Aperçu du nouveau PowerShell Cross Platform

Microsoft annonce depuis 2014 s’ouvrir aux autres systèmes, et en ce moment nombre de leurs nouveautés vont dans ce sens. Après l’arrivée entre autres de SQL Server sur Linux et Bash sous Windows, le dernier élément en date est : PowerShell 6 en OpenSource compatible Linux et MacOs. Plus précisément Microsoft déclare actuellement PowerShell 6 Alpha 9 compatible avec :

  • Windows 10 / Server 2016
  • Windows 8.1 / Server 2012 R2
  • Ubuntu 16.04
  • Ubuntu 14.04
  • CentOS 7
  • OS X 10.11

Microsoft a réussi à réaliser ce tour de force en se basant sur .NET Core, Framework .NET en open source et Cross Platform (note : baser un outil aussi crucial et important que PowerShell sur .NET Core montre bien la détermination qu’a Microsoft à s’ouvrir aux autres produits/plateformes).

Comment puis-je tester ?

Simplement en installant le package approprié à la plateforme : https://github.com/PowerShell/PowerShell/releases/. Une fois installé PowerShell 6 est accessible via la commande

Powershell

Ou en passant par la console de commande dédiée à PowerShell 6 présente sous Windows (nommée PowerShell 6).

Ça marche comment ?

De la même façon qu’un PowerShell normal. En testant les commandes de base tout semble fonctionner correctement. Néanmoins on remarque rapidement que la version actuelle est encore en Alpha, de ce fait quelques différences apparaissent rapidement comme par exemple la vérification de l’environnement via la commande [environment]::OSVersion.Version retourne sous Windows 10 :

  • 10.0.10536.0 (=Windows 10) avec PowerShell 5
  • 6.2.9200.0 (=Windows 8) avec PowerShell 6

Cela prouve qu’il faut garder en mémoire que la majorité du code a dû être réécrit, des problèmes peuvent donc survenir ou des adaptations sont à prévoir…

Avec l’ouverture quelques adaptations apparaissent

PowerShell 6 est actuellement en Alpha et cela implique nécessairement quelques limitations ou adaptations pour la réutilisation d’anciens scripts :

  • .NET Core != .NET:  évident, mais cela à de grosse conséquence sur PowerShell, en effet les versions antérieurs à PowerShell 6 sont basées sur le Framework .NET : comme les bases ne sont pas les mêmes rien ne garantit à 100% qu’un script PowerShell (version inférieur à 6) fonctionnera en PowerShell 6.
  • PowerShell exécute la plupart des commandes en mémoire : donc pas de :
    • sudo ma_commande

    • mais plutôt
    • sudo powershell ma_commande

  • Windows != Linux/MaxOs: c’est une évidence, mais cela implique quelques nouveaux paramètres à prendre en compte :

En bref cela impliquera obligatoirement du développement spécifique par script, mais pour tout ceux ayant déjà touché à .NET Core ou au développement mobile Cross Platform cela devrait être naturel.

C’est quand même utilisable ?

Comme toute alpha, PowerShell 6 est intéressant pour les tests et la découverte, mais il ne faut surtout pas l’utiliser en production, le nombre important de problème (+ de 300 sur GitHub) et le nombre de fonctionnalités vitales encore non implémentées/bancales (gestion des services, remote, manipulation XML…) ne permettent pas d’utiliser PowerShell 6 comme outil de gestion ou de scripting principal.

Finalement…

PowerShell 6 s’annonce être une excellente version, même si celle-ci est encore en alpha et que le travail est encore conséquent pour fournir une expérience parfaite côté Linux et MacOs ! Si le pari est tenu, PowerShell sous Linux et MacOs pourra permettre d’avoir une gestion des scripts unifiée et ainsi qu’une centralisation des compétences, ce qui est loin d’être anodin dans un monde ou se battent principalement Windows, Linux et MacOs.

TFS 2015: Customisation des activités de build (part2)

Auteur original, de notre ancien blog : Laurent Jacques

tfs1

Aujourd’hui nous allons discuter de la customisation des activités de build avec TFS 2015.En effet, alors que dans un prochain billet j’aborderai le tout nouveau système de build vNext ; il me semblait important de souligner une des (nombreuses) possibilités de customisation du mécanisme existant.

Etant donné le nombre d’étapes, j’ai scindé cette présentation en 2 parties : 

  1. la création d’un nouvelle activité (voir TFS 2015: Customisation des activités de build (part1))
  2. l’intégration du workflow dans la définition de la build.
 

PART2 : Intégration du workflow dans la définition de build.

Lire la suite

[ALM] TFS 2015 est RTM

Auteur original, de notre ancien blog : Laurent Jacques

tfs2015_1

Microsoft a publié hier la release finale de Team Foundation Server 2015.

Parmi les nouveautés notables par rapport à la version précédente, on peut noter:

  • Nouveau système de build : vNext
  • Nouveau pipeline de déploiement (countinuous delivery),
  • Amélioration agile & planning,
  • Modification du licensing (basic user).

Lire la suite

TFS 2015 : automatiser la création d’une définition de build XAML.

Auteur original, de notre ancien blog : Laurent Jacques

xaml1

xaml2

Aujourd’hui nous étudierons un cas pratique d’utilisation avancée de TFS  (2012,2013 et 2015) et de ses mécanismes de build.

Nous chercherons à automatiser la création et la suppression des définitions de builds avec l’utilisation de l’API de Team Foundation Server avec Visual Studio 2013.

Pour le cas d’étude de ce billet, l’organisation du code source se présente ainsi :

  • une branche dev : le travail courant des développeurs, tous check-in leurs modificationdedans au jour le jour.
  • plusieurs branches uat : en fin de cycle de développement, une nouvelle branche uat_X.Y.Z est créée à partir du dev pour partir en validation (test d’intégration)
  • une branche master : une fois validée la branche uat_X.Y.Z devient la nouvelle branche master : version référence pour les développements.

Ce qui donne par exemple l’arborescence suivante :

[code light= »true »]/Projet/
/dev
/Appli1
/Appli2
/master
/Appli1
/Appli2
/uat_1.2.3
/Appli1
/Appli2
/uat_1.3.0
/Appli1
/Appli2[/code]

 

L’équipe de développement a mis au point deux définitions de build basées sur la branche DEV :

  • une intégration continue, tournant les tests unitaires automatiques, générant la doc, fournissant les livrables dans un répertoire dépôt;
  • une nightly : déployant les applications sur l’environnement de test tous les jours à 23h.

Problématique 

Une fois validée en interne, le DEV est branché en UAT_X.Y.Z : les définitions de builds ne fonctionnent donc pas sur cette branche.

Actuellement : pour chaque nouvelle branche UAT le lead technique vient créer une nouvelle définition de build UAT et ajouter les différents paramètres.

Besoin 

Automatiser le processus.

Mise en oeuvre

Pour cette première version nous visons la mise en place d’une app console en c# qui ira, à intervalles réguliers, vérifier l’état des branches et gérer les définitions de builds.[…]

Avant toute chose: ajouter les références (v12) dans le projet :

xaml3

1ière étape:  récupérer la listes des branches UAT existantes.:

[code language= »csharp »]
List<Branch> branchList = new List<Branch>();
using (var tfs = new TfsTeamProjectCollection(_TFSserver))
{
VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
var items = vcs.GetItems(sourceCodeArea, VersionSpec.Latest, RecursionType.OneLevel,
DeletedState.NonDeleted, ItemType.Folder).Items;
foreach (Item item in items)
{
// skip self
if (!item.ServerItem.Equals(sourceCodeArea))
{
if (item.ServerItem.ToLower().Contains(filter.ToLower()))
branchList.Add(new Branch(item.ServerItem, item.CheckinDate, project));
}
}
}
[/code]

Dans le code présent la logique est la suivante:

  1. on fournit comme paramètres :
  • l’url d’accès au serveur TFS ,
  • la zone de départ dans le source (sourceCodeArea) , 
  • un fitre est indiqué qui va permettre de ne ressortir que les branches qui nous intéressent (filter) 
     2. on récupère la liste des folders (branche) ;

[code language= »csharp » light= »true »]
var items = vcs.GetItems(sourceCodeArea, VersionSpec.Latest, RecursionType.OneLevel, DeletedState.NonDeleted, ItemType.Folder).Items;
[/code]

3. pour chacun de ses folders, on vérifie la cohérence du nom par rapport au filtre précisé :

[code language= »csharp » light= »true »]
if (item.ServerItem.ToLower().Contains(filter.ToLower()))
[/code]

4. une fois récupérées, les branches seront ajoutées dans une liste d’objets maisons pour être gérées plus tard.

 

2ième étape:  récupérer les définitions de build existantes:

[code language= »csharp »]
var tfs = new TfsTeamProjectCollection(_TFSserver);
tfs.Authenticate();
var buildServer = (IBuildServer)tfs.GetService(typeof(IBuildServer));
var buildDefinitionList = new List<IBuildDefinition>(buildServer.QueryBuildDefinitions(TEAM_PROJECT));
[/code]

Afin de déterminer si les builds n’existent pas déjà, il faut en premier lieu récupérer la liste des builds existantes.

Les instructions ci-dessus permettent d’interroger le serveur TFS pour cela.

Ici, le TEAM_PROJECT  est simplement une constante représentant le nom du projet d’équipe.

L’appel à  buildServer.QueryBuildDefinitions va fournir l’ensemble des builds existantes pour le projet.

 

3ème étape:  parcourir la liste des branches et créer les builds inexistantes:

[code language= »csharp »]
if (!buildDefinitionList.Exists(x => x.Name == TfsBuildServices.BuildName(projectName, branch)))
                {
                    IBuildDefinition CIBuild = buildDefinitionList.Where(x => x.Name == projectName + "_CI").First();
                    if (CIBuild != null)
                    {
                        var newbuild = buildServer.CreateBuildDefinition(TEAM_PROJECT);
                        newbuild.CopyFrom(CIBuild);
                        newbuild.Name = TfsBuildServices.BuildName(projectName, branch);
                        BuildSettings settings = new BuildSettings();
                        var process = WorkflowHelpers.DeserializeProcessParameters(newbuild.ProcessParameters);
                        settings.ProjectsToBuild = new StringList(((BuildSettings)process["BuildSettings"]).ProjectsToBuild.ToString().Replace("DEV",branch));
                        process.Remove("BuildSettings");
                        process.Remove("ProjectsToBuild");
                        process.Add("BuildSettings", settings);
                        process.Add("ProjectsToBuild", new string[] { settings.ProjectsToBuild.ToString() });
                        newbuild.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);
                        newbuild.DefaultDropLocation += @"" + projectName;
                        newbuild.Workspace.Mappings[0].ServerItem = newbuild.Workspace.Mappings[0].ServerItem.Replace("DEV", branch);
                        newbuild.Save();
                    }
                }
[/code]

1. une simple requête linq sur le nom de la build permet de passer la création si la build existe déjà

[code language= »csharp » light= »true »]
if (!buildDefinitionList.Exists(x => x.Name == TfsBuildServices.BuildName(projectName, branch)))
[/code]

L’appel  à TfsBuildServices.BuildName  permet de centraliser et de formaliser  la création du nom de la build 

2. on récupère la build d’intégration continue qui va nous servir de modèle pour la nouvelle définition 

[code language= »csharp » light= »true »]
IBuildDefinition CIBuild = buildDefinitionList.Where(x => x.Name == projectName + "_CI").First();
[/code]

3. on initialise la nouvelle build avec le modèle

[code language= »csharp » light= »true »]
var newbuild = buildServer.CreateBuildDefinition(TEAM_PROJECT);
  newbuild.CopyFrom(CIBuild);
[/code]

4. la modification des paramètres

La build definition utilise des BuildSettings pour enregistrer ses paramètres :

[code language= »csharp »]
BuildSettings settings = new BuildSettings();
                        var process = WorkflowHelpers.DeserializeProcessParameters(newbuild.ProcessParameters);
                        settings.ProjectsToBuild = new StringList(((BuildSettings)process["BuildSettings"]).ProjectsToBuild.ToString().Replace("DEV",branch));
                        process.Remove("BuildSettings");
                        process.Remove("ProjectsToBuild");
                        process.Add("BuildSettings", settings);
                        process.Add("ProjectsToBuild", new string[] { settings.ProjectsToBuild.ToString() });
                        newbuild.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(process);
                        newbuild.DefaultDropLocation += @"" + projectName;
                        newbuild.Workspace.Mappings[0].ServerItem = newbuild.Workspace.Mappings[0].ServerItem.Replace("DEV", branch);
[/code]

Ces settings sont sérialisés sous forme de dictionnaires et doivent donc être réédités pour cadrer avec le besoin spécifique UAT:

  • la copie de la build CI pointe par exemple vers la solution à compiler $/Project/dev/Appli1/Appli1.sln . il faut donc modifier ce répertoire pour celui UAT : 

[code language= »csharp » light= »true »]
settings.ProjectsToBuild = new StringList(((BuildSettings)process["BuildSettings"]).ProjectsToBuild.ToString().Replace("DEV",branch));
[/code]

  • de la même manière le default drop location contient celle de la build CI et doit être modifié : 

[code language= »csharp » light= »true »]
newbuild.DefaultDropLocation += @"" + projectName;
[/code]

  • et enfin le modèle objet de la définition de build contient aussi le mapping vers le répertoire source controle mappé qui doit lui aussi être remplacé : 

[code language= »csharp » light= »true »]
newbuild.Workspace.Mappings[0].ServerItem = newbuild.Workspace.Mappings[0].ServerItem.Replace("DEV", branch);
[/code]

5. on sauvegarde, laisse 15 min au four : et hop. la build est créée !

[code language= »csharp » light= »true »]
newbuild.Save();
[/code]

 

4ième étape:  supprimer les builds des anciennes branches :

Récupération de la liste des branches supprimées :

[code language= »csharp » highlight= »2″]
var items = vcs.GetItems(area, VersionSpec.Latest, RecursionType.OneLevel,
DeletedState.Deleted,
ItemType.Folder).Items;
[/code]

Pour chacune des anciennes branches on récupère la définition de la build associée (si elle existe)

[code language= »csharp » highlight= »4″]
IBuildDefinition UAT_CIBuild = buildDefinitionList.Where(x => x.Name == TfsBuildServices.BuildName(projectName, branch)).FirstOrDefault();
if (UAT_CIBuild != null)
{
buildServer.DeleteBuilds(UAT_CIBuild.QueryBuilds());
}
[/code]

A noter: pour pouvoir supprimer une définition de builds il faut que les historiques de run soient eux-aussi supprimés, c’est pourquoi l’appel buildServer.DeleteBuilds(UAT_CIBuild.QueryBuilds());  est fait ainsi  : cela supprime l’ensemble.

 

5ième étape:  emballer dans une petite application :

Je ne rentrerai pas dans les détails sur ce point, mais avec les éléments fournis rien de plus simple que de réunir tout cela dans une application qui tourne à intervalle régulier et exécute ces appels afin de synchroniser les définitions de builds et les branches.

 

Pour aller plus loin 

http://nakedalm.com/

https://msdn.microsoft.com/fr-fr/vstudio/ff637362.aspx

ALM ranger’s site

Prochaine étape 

Dans le prochain billet j’expliquerai comment se passer de l’application console en intégrant ce code au sein d’activités de build maisons et comment créer notre propre template de build avec tout ceci.

 

Laurent.

 

Introduction à la gestion des cycles de vie des applications (ALM)

Introduction à la gestion des cycles de vie des applications

(Application Lifecycle Management – ALM)

       ….

Evidemment, dit comme cela, cela peut paraître un peu abrupte voire déconcertant … Cycles de vie des applications  – Application Lifecycle Management. Mais sous ce nom se cache en réalité l’une des meilleures pratiques logicielles dont l’objectif est de fournir un logiciel de haute valeur et de haute qualité, et ce d’une manière très efficace, rapide et fiable

Quelles sont les différentes étapes de l’ALM ? 

D’un point de vue du développeur, il est courant de penser que le cycle de vie d’un logiciel commence et s’arrête lors du checkout et du commit des modifications du code. 

La réalité est tout autre, comme nous le voyons tous les jours, et couvre beaucoup plus. 

Le cycle de vie des applications commence à partir de la création du projet jusqu’à la livraison en production, comprenant plusieurs étapes dont le développement n’est qu’une petite partie parmi, entre autres, les tests, les documentations et la génération d’installateurs. 

L’ensemble de ces opérations permet de livrer un logiciel de haute valeur et de haute qualité pour le client.

Ce schéma montre le pipeline de déploiement idéal. On y retrouve l’ensemble des opérations automatisées à mettre en place lorsqu’on parle d’ALM.
Le processus est entièrement automatisé, capable de fournir un feedback détaillé de son statut et de celui de ses opérations, et de s’interrompre à chaque étape en cas de détection d’anomalies.
Bien loin de ce déroulement idéal, le plus souvent, il est fréquent que la plupart de ces opérations soient manuelles, partielles et sans fournir de réel feedback.
Même si maintenant il est largement admis que le code source doit être hébergé dans un outil de contrôle de version, et que chaque développeur doit faire des check-out et commit réguliers, il est encore très rare de trouver une plateforme d’intégration continue réelle automatisée, qui gère ne serait-ce que la compilation automatique et le déroulement des tests unitaires. 
A la place, il est fréquent qu’il y ait des flux allant dans toutes les directions, sources de risques et de problèmes à venir, comme le montre le schéma ci-dessous  : 

Quel est le problème avec la livraison de logiciels ? 


  1. Les opérations sont nombreuses, souvent manuelles et sur différents environnements techniques mal maitrisés,
    • Le corollaire est que ces opérations dépendent de quelqu’un (responsable déploiement, chef de projet, expert quelconque). La question est donc : que se passe t’il lorsque cette personne est absente
    • extrêmement répétitives, ces tâches sont une plaie sur le long terme,
    • la réalisation d’une documentation souvent lourde est nécessaire,
    • une courbe d’apprentissage lente pour l’ajout de nouveaux membres à l’équipe,
    • des besoins humains supplémentaires sont nécessaires à l’équipe

  2. Le code source et les paramétrages ne sont pas nécessairement stockés dans le même endroit, mais peuvent être générés à partir de partout et par n’importe qui, n’importe quand : qui contrôle quoi ?
  3. Aucune vraie traçabilité,
  4. Des délais de livraison très long : il peut se passer des jours entre la validation et le déploiement,
  5. Des erreurs sont plus enclines à apparaître. 
En bref : lorsqu’il y a des opérations manuelles, il devient vraiment difficile de répéter, de cadencer et de mesurer la livraison. 

Quels sont les objectifs de l’ALM ? 

Comme vous l’aurez compris maintenant : implémenter l’ALM c’est principalement se concentrer sur l’automatisation de la grande majorité (sinon la totalité) des opérations ; afin d’assurer la création de valeur et des livraisons fiables, rapides et cadencées.
L’idée maîtresse est de réduire les temps de cycle.
Plus le temps de cycle est court, plus le client pourra être satisfait (par plus de fonctionnalités ou même par des corrections de bugs). L’objectif est de favoriser les feedbacks rapides.

Comment? 

Etant donné que cet article est seulement une (très) courte introduction, nous ne plongerons pas plus à fond dans les détails ici. 
Nous énumérerons simplement les différents sujets à couvrir. Ceux-ci seront expliqués plus en détails dans de prochains articles :
  1. Configuration et installation d’un outil d’intégration continue (TFS, Hudson, CruiseControl), 
  2. Mettre au cœur de l’outil l’analyse de qualité (règles de gestion, Sonar, FxCop) ainsi que les tests, le tout avec de l’automatisation, 
  3. Mettre sous contrôle de source tous les paramètres ou fichiers de configuration pour tous les hôtes cibles, 
  4. Lister toutes les autres opérations manuelles, les automatiser et les chaîner entre elles,
  5. Modifier le processus de développement pour s’appuyer davantage sur les tests d’acceptation,
  6. Réduire les délais de feedback (testeurs, clients ….). 

Conclusion 

Cet article n’est que le premier d’une série d’articles introduisant les principes de ALM (intégration continue, déploiement continu…etc). Il vise à présenter simplement ce qui est en jeu tout en abordant les grands principes du cycle de vie des applications.
Dans les prochains articles, nous expliquerons plus en détail avec de cas concrets d’utilisation et d’implémentation, les scénarios de mise en place de l’ALM.

Liens utiles

ALM (sur wikipedia) : pour une explication simplifiée.
Intégration Continuela définition par M. Martin Fowler
Déploiement Continu : la définition par M. Martin Fowler