• Teambuild

    En cours de test pour un partenaire, Visual Studio Team Server a pour l'instant réussi un quasi-sans-fautes quant à la simplicité d'utilisation (mais pas d'installation), la performance, les possibilités et d'accessibilité par des bureaux déportés. Le prochain test se situe au niveau de la machine de build et, pour l'instant, c'est encore une bonne impression qui domine.

    Utilisant depuis quelques temps CruiseControl.NET, accompagné d'une tonne et demie de plug-ins fait maison, la migration vers un autre système de build ne se fera que si le jeu en vaut la chandelle. Voici déjà quelques remarques concernant TeamBuild :

    • il ne s'agit pas d'une solution d'intégration continue, c'est assez simple de le transformer pour cela (voir ce post et celui-ci) mais il ne s'agit pas de son utilisation première qui reste le build "à la demande"
    • il est basé sur MSBuild, ce qui est plutôt un bon point : les tâches créées pour l'un fonctionne pour l'autre
    • Le resultat des builds est intégré (en cas d'erreur) dans les tâches du projet, avec les logs
    • Il est (assez) facile de déplacer le build entre plusieurs machines.
    • Le reporting de TFS reprends les infos des builds

    Cela étant dit, il me manque encore un certain nombre d'outils et/ou tâches à créer (à moins que ce soit des fonctionnalités qui m'ont échapée) :

    • Une solution simple pour gérer le versionning des assemblies (la solution est un peu pénible à mettre en place : une interface graphique serait vraiment la bienvenue)
    • Un outil permettant de déclencher un build sur le même jeu de changeset qu'un autre (par exemple construire le build "Release" correspondant à un build "Debug" réalisé il y a quelques jours, avant les tests de recette)
    • Des tâches permettant un retour plus intuitif de l'information - un petit post sur un blog privé par exemple serait impeccable -, une meilleure gestion des fichiers, etc.
    • La possibilité de gérer facilement les dossiers de sortie de chacun des projets : la configuration standard copiant toutes les assemblies compilées dans un seul et unique dossier de release

     

  • Foreach sous Powershell

    Powershell, comme nous l'avons déjà entr'aperçu, est un shell très orienté développeurs. On y retrouve en effet un nombre de paradigmes de la programmation "objets". Parmis ceux-ci, la notion d'itération (c'est à dire la possibilité d'executer un traitement plusieurs fois) est representée par 3 commandes : forwhile et foreach. C'est sur cette derniere - qui est la plus intéressante - que nous allons un peu nous attarder.

    Commençons par un petit exemple très simple : imaginons que vous souhaitiez obtenir la liste des fichiers de sauvegarde SQL dans un dossier. La commande suivante devrait parfaitement vous satisfaire :

    gci *.bak

    Nous allons donc un peu complexifier cet exemple et imaginer que nous allons restaurer (dans un environnement de developpement, de pré-prod ou tout ce que vous voudrez) tous ces fichiers sur l'instance locale de SqlServer (nous utiliserons pour cela la fonction restore-database que vous trouverez ici - Attention, cette fonction est juste un exemple de ce que l'on peut faire pour restaurer une base de données SQL, elle n'est pas destinée à être utilisée en production).Pour ne pas trop chercher à rendre incompréhensible le script , les fichiers de sauvegardes seront supposés être nommés nom_de_la_base-date_de_la_sauvegarde.

    gci *.bak | foreach 
    {
    restore-database ...
    $_.Name.SubString($_.Name.IndexOf("-")) ...
    $_.Name }

    Expliquons un peu cette ligne de commande : l'instruction foreach va executer le block entre accolades pour chacun des objets qu'elle obtiendra de la pipeline. Pour savoir l'objet courant de l'itération (sur quel objet on se trouve actuellement...), nous avons à disposition la variable reservée $_. $_.Name va donc énumérer successivement tous les noms de fichiers récupérés par le gci.

    Ce qui est interessant de savoir, c'est que le contenu d'un foreach n'a pas besoin de se limiter à une seule instruction. Le script suivant est parfaitement valable :

    gci *.bak | foreach 
    {
    restore-database ...
    $_.Name.SubString($_.Name.IndexOf("-")) ...
    $_.Name move $_ ..\done }

    Pour savoir si vous avez bien compris, je vous invite a essayer d'ecrire :

    • un script qui modifie les dates de dernieres modifications de tous les fichiers bak pour simuler la commande touch.
    • un script qui vous donne l'état des services MSSQLSERVER et IISADMIN ainsi que leurs "enfants" (l'agent Sql, les services http, https, etc.). Pour cela, je vous donne une petite aide : pour obtenir les 2 services "racines", vous pouvez faire
    "mssqlserver","isadmin" | get-service
    • un script qui retire tous les fichiers de sauvegarde de toutes les bases sauf le plus récent (et pas question de tricher avec une comparaison par rapport à la date du jour : vous pourriez avoir plusieurs sauvegardes le même jour)

  • Ajouter une commande à Powershell

    Voyons un peu comment faire pour intégrer vos propres commandes dans Powershell, vous allez voir cela n'a rien de sorcier.

    1) Création d'une Cmdet

    Une Cmdlet (prononcez «Commande-lète») est tout simplement une classe .net représentant une commande sous Powershell comme par exemple Get-ChildItem (la cmdlet standard utilisée - ou plutôt aliasée - pour faire un bon vieux dir).

    Comment crée-t-on une Cmdlet donc ? Eh bien, c'est assez simple :

    • créez un nouveau projet «bibilothèque de classe» sous VS2005
    • ajoutez comme référence la dll «System.Management.Automation» (vous la trouverez dans Program Files\Windows PowerShell\v1.0 [update] il vous faudra la récupérer du SDK)
    • créez une nouvelle classe et faites la dériver de System.Management.Automation.Cmdlet
    • ajoutez lui un attribut System.Management.Automation.CmdletAttribute. Ce parametre vous permet de définir le type d'action (paramètre verb) et l'objet (paramètre nounName) sur lequel celui-ci se réalise - pour en savoir plus sur les verbes autorisés, reportez vous à la table suivante : http://blogs.msdn.com/powershell/archive/2006/04/25/583257.aspx)
    • surchargez la méthode BeginProcessing() si vous souhaitez réaliser un traitement avant de traiter les éventuels éléments de la PipeLine
    • et/ou surchargez la méthode EndProcessing() si vous souhaitez réaliser un traitement après de traiter les éventuels éléments de la PipeLine (c'est aussi ici que se font habituellement les traitements de commandes qui ne gèrent pas la Pipeline)
    [Cmdlet("Get","MyUser")]
    public class GetMyUsersCmdlet : Cmdlet
    {
      protected override void< EndProcessing()
      {
        // effectuer le traitement
      }
    }

    Voila, vous avez déjà une Cmdlet qui peut fonctionner. Bon, évidemment, pour l'instant il n'est pas vraiment question d'une commande intéressante, puisque vous ne pouvez pas lui passer de paramètres ni obtenir de résultat. Cela pourrait être suffisant si vous réalisez une commande destinée à rebooter la machine, mais pour le reste c'est un peu juste.

    Voyons donc comment on peut passer des paramètres, mais nous ne nous occuperons pas encore de la Pipeline - cela sera pour un prochain post :

    • pour chacun, ajoutez une propriété en lecture/ecriture (ou un champ) dans votre classe - en faisant bien attention au type que vous utilisez : pas question d'utiliser des types bizarres - mais vous pouvez très bien utiliser une enum.
    • ajoutez sur chacun de ces éléments un System.Management.Automation.ParameterAttribute. Celui-ci vous permettra, après quelques essais, de mieux contrôler la façon dont s'enchainent ou sont obligatoires ou non tous les paramètres.
    • dans votre traitement, utilisez la propriété normalement : elle aura été «remplie» automatiquement par le moteur de PowerShell

    public enum TypeUser
    {
      Administrateurs,
      Utilisateurs
    }

    [Cmdlet("Get","MyUser")]
    public class GetMyUsersCmdlet : Cmdlet
    {
     private TypeUser _typeUser
                = TypeUser.Utilisateurs;
      [Parameter(Mandatory=true)]
      public TypeUser TypeUser
      {
     get { return _typeUser; }
       set { _typeUser = value; }
      }

      protected override void EndProcessing()
      {
       if (_typeUser == TypeUser.Administrateurs)
       {
          // faire le traitement pour les
          // administrateurs
       }
       else
       {
          // faire le traitement pour les
          // utilisateurs normaux
       }
      }
    }

    Il reste encore une chose à faire pour avoir une Cmdlet digne de ce nom : renvoyer des données. Cela est très simple : il suffit d'appeler la méthode WriteObject pour chacunes des «lignes» de résultats. (Rappelons au passage que les Cmdlets ne renvoie pas forcément du texte, mais peuvent renvoyer n'importe quel type d'objet, dans la limite du raisonnable)

    public enum TypeUser
    {
      Administrateurs,
      Utilisateurs
    }

    public class MyUser
    {
         ...
    }

    [Cmdlet("Get","MyUser")]
    public class GetMyUsersCmdlet : Cmdlet
    {
      private TypeUser _typeUser 
                = TypeUser.Utilisateurs;
      [Parameter(Mandatory=true)]
      public TypeUser TypeUser
      {
       get { return _typeUser; }
       set { _typeUser = value; }
      }

      protected override void EndProcessing()
      {
       if (_typeUser == TypeUser.Administrateurs)
       {
          foreach( ... )
          {
             MyUser usr = new MyUser( ...);
             WriteObject(usr);
          }
       }
       else
       {
          ...

       }
      }
    }

    Dans le prochain post, nous verrons comment ajouter votre toute nouvelle Cmdlet dans Powershell.

  • SQL/e CTP

    Cela faisait un moment que j'attendais une CTP de SQL/e (le nouvel élément de la gamme SQL Server/SQL Mobile de Microsoft), et voila qui est fait !

    2007 sera une année faste pour les amateurs de MS - en tout cas beaucoup plus que la précédente - : Vista, IE7,Office, Exchange, Powershell, .net 3.0, SQL/e, ForeFront, live.com, etc.

    Revenons à nous moutons : qu'est ce que SQL/e ? Eh bien il s'agit (grosso modo) du portage - en terme de fonctionnalités, je ne m'hasarderai pas à parler de la façon dont le code à été fait - de SQL Mobile sur les plateformes Windows «complètes». SQL/e permettra par exemple d'embarquer un mini moteur de base de données dans vos applications, à la manière d'un Firebird Embedded. Enfin !
    Bon, je le télécharge, je teste et - si j'y pense - je vous fait part de ce que ça donne