Azure Devops

Qu’est ce qu’Azure Devops ? A quoi ça sert ? Comment l’utiliser ?  Je vais tenter d’expliquer par l’exemple et l’expérience ce que l’on peut faire avec Azure Devops Un bref historique Il est l’héritier de plusieurs anciens outils. Si je remonte loin on a VSS (visual source safe) qui était le svn de Microsoft, un gestionnaire de code source. Ensuite on a eu Team Foundation Server qui était un peu plus sérieux, on commençait à voir des outils annexes comme un board avec des work items. Git étant devenu une référence, Microsoft s’est adapté et a la intégré sur toutes ses plateformes. On a eu aussi VS Online (Visual Studio Online) et dans le même temps Microsoft rachetait HockeyApp qui deviendra App Center (spécialisé dans l’application mobile). C’est indépendant, mais j’imagine que demain tout ne fera qu’un. Et puis est né Azure Devops. Tout ça pour dire qu’il est pas arrivé comme ça. C’est le fruit d’années d’évolution et de savoir faire.   Azure Devops est gratuit.  Azure Devops est multi projets, multi utilisateurs, … voir ici pour le limites A quoi ça sert ? Alors qu’on soit bien clair, Azure Devops n’est pas indispenable… jusqu’à ce qu’on s’en serve… Azure Devops c’est une plateforme web qui regroupe plusieurs gros services : Board : un outil qui permet de créer des work items et de les organiser suivant des méthodes agile (scrum, kanban) Repos : un repo git, où l’on peut y voir les commits, pushes, branches, tags, pull requests Pipelines : orchestrateur automatique. Permet de lancer des « scripts » yaml et d’automatiser notre chaine de livraison continue.  Test Plans : La section test. Artefacts : ce que vous aller produire se retrouve ici.  Les deux derniers, j’en parlerai pas, je connais pas bien. Les 3 premiers sont des supers outils, ils sont liés.  En premier lieux on va utiliser Board pour s’organiser, créer des tâches et les répartir aux membres de l’équipe. Bien entendu il nous faut un repos Git. Ils nous permet de gérer notre code source. Enfin, quand le projet avance, on ajoute de l’automatisation pour que notre chaine de livraison continue fonctionne toute seule.  Comment l’utiliser ? Pour cela j’ai écris 9 articles qui se focalise sur la chaine de livraison/déploement continue CI/CD 1 – Première pipeline, On y apprend à faire un build tout simple : Azure Devops Pipeline (CI/CD) – First Build 2 – Deploiement via SSH Azure Devops Pipeline (CI/CD) – Deploy 3- Versioning Azure Devops Pipeline (CI/CD) – Versioning 4- Gestion des environnements Azure Devops Pipeline (CI/CD) – Environnement Azure Devops Pipeline (CI/CD) – Relancer les services 5- Git Flow Azure Devops – Git Flow intro 6- Pull Request Azure Devops – Pull Request Azure Devops – Pull Request (part 2) Voilà, j’espère que ça pourra servir à quelqu’un 🙂 

Azure Devops – Pull Request (part 2)

Cet article est la suite de https://reactor.fr/azure-devops-pull-request/ On avait créé des règles de branche sur la master : interdiction d’effacer cette branche pas de git push direct sur cette branche règle de Pull Request (light) Ceci nous permet de sécuriser la branche master. Faisons de même avec la branche develop. Rappels Git Flow On a vu la PR develop –> master.  Maintenant, on va ajouter une PR sur chaque commit vers la branche develop. Si on applique Git Flow, on aura une branche feature qui devra à un moment livrer son contenu sur la develop.  La PR intervient à ce moment.  Règle de branche develop sur Azure Devops On va donc fairre un clic sur le menu de la ligne représentant la branche develop dans Repos – Branches, puis on sélection "Branch Policies" Pour la branch dévelop, j’ai rajouté plus de contraintes que la master. En effet je veux qu’en premier lieu chaque commit sur la branch dévelop corresponde à un work item. Ensuite si il y a une intervention d’un reviewer, celle ci doit être résolut par un commentaire. Dans la pratique ça peut simplement être une question qui ne demande pas vraiment d’intervention. Mais ça peut aller jusqu’à ce que le reviewer demande un refacto voir refuse carrément le code (c’est rare…) Je limite aussi le type de merge afin d’avoir un historique lisible et en cohérence avec la branche master. Ensuite j’ajoute une règle de build. Je sélectionne une nouvelle Pipeline que je viens de juste de crée : pool: vmImage: ubuntu-latest variables: buildConfiguration: ‘Release’ projectBlazorWasmServer: ‘src/BlazorDemo/BlazorDemo/Server/BlazorDemo.Server.csproj’ steps: # Publish Blazor Demo Server – task: DotNetCoreCLI@2 displayName: Publish inputs: command: publish publishWebProjects: false projects: ‘$(projectBlazorWasmServer)’ arguments: ‘–configuration $(buildConfiguration) –output $(build.artifactstagingdirectory)’ zipAfterPublish: false modifyOutputPath: false La seule différence avec l’autre pipeline de build, c’est que je ne précise pas le trigger. En effet, je ne connais pas le nom de la branche feature. Donc par défault ce sera la source de la PR concernée. Mise en situation Mon tech lead m’a affecté une tâche. On va aller la créer pour la simuler, normalement elle est déjà existante : Je suis développeur, je dois donc créer une branche si elle n’existe pas déjà. Sut mon terminal je tape : git checkout -b feat/LoginPage Je développe, quand j’ai fini : git add . git commit -m « mon travail sur la page login » git push –set-upstream origin feat/LoginPage Je peux bien évidement avoir plusieurs commit et/ou avoir d’autre commit d’autre développeurs. D’ailleurs (si vous avez les droits) n’importe qui peut aller voir ce qu’il se passe sur cette branche depuis Azure Devops : La Pull Request feat -> develop Azure Devops sait qu’une branche feat/LoginPage est en cours et vous propose directement de choisir celle ci et de créer une pull request à partir de celle ci. Dans mon cas j’ai eu ceci : C’était pas voulu, mais j’ai eu la surprise de voir que j’ai un conflit de merge. Et c’est finalement un point intéressant à montrer.  J’ai pas récupéré la branche develop dans mon dev sur ma branche feature. Et honnetement ça arrive TOUT LE TEMPS.  Normal, qq a pu entre temps livrer qq chose sur la branche develop. Il faut donc s’assurer que ce nouveau code s’intègre au mien. Il faut alors lancer toute une série de commandes git: git checkout develop git pull git checkout feat/LoginPage git rebase develop git pull git push Explication : on change de branche pour aller sur develop. On récupère la dernière version de cette branche. On re bascule sur notre branche feat. On applique ces nouveautés (rebase permet de garder un historique chronlogique en mettant nos modifs après celle de develop). A ce stade on est iso en local. Faut faire un pull pour que ça lance un merge automatique (ca met au carré le repo local et le distant et prépare au push) Et enfin on push sur le repo distant.   Maintenant on retourne sur Azure devops : Ya plus de conflit ! 🙂 si on regarde de plus prêt Il ne reste plus qu’à associer notre PR à un Work Item : Ce qui résoud le problème : On peut valider le PR : Ceci effacera la branche feat/LoginPage Au final : Conclusion Pourquoi c’est génial ? C’est vrai qu’avant on publiait directement sur develop et tout allait bien. Et vous avez pas tort. Chacun travail comme il le souhaite.  Avec cette façon de faire, vous allez prendre un petit plus de temps à faire un "peu de paprasse". Mais on a un suivi très intéressant sur chaque étape de la construction de morceau d’application. Tout est lié, et tout le monde peu savoir ce qu’il se passe. Qui travaille sur quoi et quand. Attention, faut pas le voir comme un outil de flicage, mais plutot un outil d’orchestration dans une équipe logiciel.  L’élément que j’ai peu évoqué ici, et qui est relié à a chaque PR c’est le board. Le Board permet de suivre des work items de plusieurs types : Chacun s’organise comme il veut. On peut créer autant de work item que l’on veut et utiliser scrum ou kanban Le développeur se focalise sur sa feature et traite de bout en bout celle ci (jusqu’à la branche develop) Le tech lead suit tout ça. A chaque fin de sprint, ou quand il le souhaite, il peut faire une release. Le product owner est au courant des évolutions de son app.  Azure Devops est vraiment un super outil.  Et j’ai pas fait le tour de toutes ses possibilités.

Azure Devops – Git Flow intro

Intro Git Flow tu connais ? non ? Et Git tu connais ? non…ouais faut faire un effort la monsieur (ou madame). Alors git j’explique pas. Si tu connais pas reviens me voir, mais va tout de suite apprendre qq commandes car c’est juste une tuerie ce truc. Quand t’as connus vss, svn ou team foundation server, tu sais que git te sauve la vie. Il est juste incontournable aujourd’hui. Ho tu pourras faire semblant qq heures, mais tu vas vite te retrouver dans l’impasse. Un conseil, tarde pas trop, apprends git ! Et en ligne de commande, pas avec un outil (quoi qu’un outil peut éventuellement t’aider, mais crois moi, fait tout en ligne de commande…) J’ai personnellement tardé à y passer. Trop. Et j’ai aussi utilisé des outils graphiques. Personne n’est parfait ! Alors si tu es encore la, tu sais ce qu’est une branche, un merge ou un rebase, un commit…   C’est quoi Git Flow ? A lire, surtout le premier : voici 3 liens : https://danielkummer.github.io/git-flow-cheatsheet/index.fr_FR.html https://grafikart.fr/tutoriels/git-flow-742 https://git-flow.readthedocs.io/fr/latest/presentation.html Ca cause Git Flow mieux que moi. Je suis ici pour vulgariser. Alors Git Flow c’est un ensemble de commandes git qui permettent de s’organiser autour du code source d’une application. Git Flow propose une stratégie pour gérer le cycle de vie d’une application coté code source, du développement locale jusqu’aux versions releases finale en passant par des branches qui auront un but précis.  En vrai, c’est juste des commandes git ! C’est une surcouche qui facilite la vie. Enfin en théorie. Perso j’utilise les principes de Git Flow mais pas ses commandes.  Pour expliquer Git Flow, on va se mettre dans un contexte, imaginons la vie d’une application, par exemple Tonder, une app web pour flirter.   V0.0.1 alpha – naissance d’une app Il était une fois un développeur en recherche d’amour (il veut ken à donf) et il lui vient une idée d’application qu’il nomma Tonder. Le dev est tout seul sur son projet. Il bosse dessus comme un ouf et sort sa premiere app Tonder Alpha 0.0.1 Il est content, mais c’est une version alpha. Elle tourne sur un serveur à lui dans sa piaule, bancale, comme son code.  V0.1.0 bêta Arpès quelques jours de discussion avec son hamster, son app ressemble à quelque chose, il veut faire tester son app et la rend disponible en version bêta privé. Il a donc une « prod » (toujours dans sa piaule) et il s’appercoit qu’il devient difficile de travailler directement sur sa prod sans prendre le risque de tout péter. Alors il crée une version « staging » sur laquelle il bosse.  Mais pour le moment, il existe qu’une « version » de son code. Aucun historique, tout est en local sur un disque dur de sa machine. Un virus, un feu domestique, un coup de foudre, pire trouver une meuf et avoir des gosses… il peut tout perdre.  Notre dev se dit qu’il serait bien d’avoir un controleur de code source qui lui permettra de  sauvegarder son code sur un cloud le rendre accessible à d’autre dev via ce cloud pouvoir gérer l’historique de son code  Alors il crée son repo Git, qq part où il sait qu’il sera accessible et disponible.  V1.0.0 Première release officielle Ca y est, notre dev sort enfin au grand publique sa super App. Il est fiert. Il est content. Son poil brille (il a pas pris de douche depuis 72h, 15 cannettes de coca trainent sur le bureau, il ne sait même plus quel jour on est, et si d’ailleurs c’est le jour ou la nuit …) Les retours utilisateurs arrivent. Il les traite comme il peut, avec le mécanisme suivant : « je code en dev locale, puis si ca marche je passe sur staging puis si ca plante pas je balance sur la production ». Il fait tout à la main, pas d’automatisation, il se dit qu’il a pas le temps pour ça et que c’est qu’une petite release de plus, ça prendra 5 min… Ils se dit qu’il aimerait bien un peu d’aide… et prendre l’air… V1.0.547 Ca build à donf Notre développeur ne compte plus le nombre de build qu’il a fait. Toujours à la main. Ce coup ci il décide d’automatiser sa chaine de livraison/deploiement continue. Il passe par : son premier build automatisé : https://reactor.fr/azure-devops-pipeline-ci-cd-first-build son premier deploiement automatisé : https://reactor.fr/azure-devops-pipeline-ci-cd-deploy ses versions automatisées : https://reactor.fr/azure-devops-pipeline-ci-cd-versioning multi environnement : https://reactor.fr/azure-devops-pipeline-ci-cd-environnement Il est vraiment satisfait. Certe il vient d’y passé quelques heures. Mais a présent il ne s’occupe ni de son staging, ni de sa prod. Tout est fait automatiquement. Et du coup il peut prendre l’air… ça lui rappel d’ailleurs qu’il a un chien… mais il est où son chien ? V1.1.41 1er co développeur Enfin un peu d’aide ! Un nouveau dev arrive en renfort. Git devient indispensable.  Jusque là, le repo git contient 2 branches, une master et une develop.  La branche develop est celle que les développeurs utilisent.  La master sert de branche « release ». Quand on estime que l’on a quelque chose, on pousse du code depuis la branche develop vers la master.  Une pipeline s’occupe de mettre à jour le staging dès que la branche develop reçoit un commit. Une pipeline s’occupe de mettre à jour la prod dès que la branche master reçoit un commit. Nos deux devs travaillent en simultané sur la branche dev. A chaque commit, on a run de pipeline, ca fait bcp de deploiement pour parfois pas grand chose. Alors nos deux devs décident de travailler en branche.  Chacun aura sa branche au départ. Mais nos développeurs se rendront compte qu’avoir une branche chacun revient à avoir deux versions de la branche develop (en plus de celle ci). Il ne profite pas des avancés de chacun et attendent que la branche develop soit à jour pour récupérer le travail de l’autre, via des cherry-pick ou des rebases hasardeux. C’est un peu confu, et nos deux devs décident d’appliquer Git Flow avec des branches feature (fonctionalités).  Ainsi, ils peuvent travailler tous les deux sur une feature si il…

Azure Devops Pipeline (CI/CD) – Relancer les services

Services Debian systemctl Suite à mon dernier article, j’ai été confronté à un problème que j’ai mis longtemps à identifier. Lorsque je mets à jour mon site web, mettons celui du staging avec une nouvelle publication, je modifie les fichiers à la racine du projet, c’est à dire var/etc/www/staging.blazordemo.reactor.fr/ dans mon cas. Pour ma part j’applique une politique du "j’effface tout" et "j’upload tout". Pas de remplacement de fichier. C’est plus long mais je suis certain qu’il y a pas un mauvais fichier en ligne.  Hormis des pb de cache ou de rafraichissement, mon site web est bien à jour.  Mais pas mon service Kernel. En tout cas sur linux Nginx, lorsque je rajoute par exemple un controler "api/plateform" coté serveur, si je ne relance pas mon service avec les commandes suivantes : sudo systemctl stop kestrel-staging.blazordemo.reactor.fr.service sudo systemctl start kestrel-staging.blazordemo.reactor.fr.service sudo systemctl status kestrel-staging.blazordemo.reactor.fr.service mon api « plateform » ne sera pas accessible. En tapant ces commandes, l’api est accessible. Il serait bon d’inclure cela dans la pipeline, histoire qu’on est rien à faire à la main à chaque run de pipeline si le code c# est modifié coté serveur. Pour cela, il suffit de rajouter ces lignes : – task: SSH@0 displayName: ‘Restart Kestrel Service’ inputs: sshEndpoint: ‘SSH to Ikoula’ runOptions: ‘commands’ commands: | sudo systemctl stop kestrel-staging.blazordemo.reactor.fr.service sudo systemctl start kestrel-staging.blazordemo.reactor.fr.service sudo systemctl status kestrel-staging.blazordemo.reactor.fr.service readyTimeout: ‘20000’ Ca donne ça dans les ‘logs’ des jobs de l’execution du pipeline :

Azure Devops Pipeline (CI/CD) – Environnement

Problème du dernier post Je me suis bien pris la tête sur le dernier billet au sujet d’un nouveau problème qui est apparu lorsque j’ai voulu diviser mon site web en 2, une partie staging et une partie prod. Ca pourrait tout aussi bien être "preprod", "recette" etc… Avant j’avais qu’un seul site web: blazordemo.reactor.fr. Celui ci a sa config Nginx et son service systemd qui fait tourner Kernel via un proxy sur le port 7777. (voir article ) J’en ai créé un nouveau "staging.blazordemo.reactor.fr".  L’idée est de faire comme les pros, un site web de "staging" et un de "prod".  dev : locale, tambouille de developeur, avec une base de données crado, des machins bricolés, des trucs à jours ou pas… staging:  distante, même environnement que la prod (meme serveur de base de données, même OS, même TOUT, sauf les données qui sont normalement copiés et anonymisés dans le meilleurs des mondes) prod: distante, le site qu’on update le vendredi soir 🙂 Donc j’ai crée "staging.blazordemo.reactor.fr". Sauf que j’ai pas modifié mon service qui fait tourner Kestrel via proxy sur port 7777.  Et j’ai mis un temps fou à m’en apercevoir. (j’ai été jusqu’a faire un gros delete de mon repertoire www. Nginx continuait à me servir un beau site web… même après un reboot. car le service était le meme…) Donc il me faut 2 services… Un de staging, l’autre de prod. Le tout sur un port proxy différent bien évidement.  Bien entendu, ce problème n’existe pas si le staging et la prod ne sont pas sur le meme serveur, ce qui est TRES recommandé. Cependant, je trouve l’exercice intéressant car il pousse dans les retranchements et force à de bonnes pratiques. Mon ancienne technique Dans le projet Blazor Server, dans Program.cs j’ajoutais ceci  Une ligne de compilation conditionnelle qui me changait le port si on était en release (ce que je considèrais comme mon unique prod).  Je pourrais ajouter une condition STAGING avec un port 7776 et m’en servir pour la version staging. A mon sens une directive de compilation n’a rien a voir avec les environnements, je veux dire c’est liés, mais c’est pas son but de définir du paramétrage de port…  Je pense qu’on peut faire mieux, avec les fichiers de conf appsettings.js. Créeons deux autres fichiers de config, un pour la prod et l’autre pour le staging. Normalement vous avez déjà par défaut un fichier appsettings.Development.json launchSettings.json Si vous travaillez avec Visual Studio ou VS Code vous devez savoir que vous avez des options de lancement de votre app qui sont configurable dans le fichier Properties/launchSettings.json Encore un fichier de config qui sème le doute… { « iisSettings »: { « windowsAuthentication »: false, « anonymousAuthentication »: true, « iisExpress »: { « applicationUrl »: « http://localhost:54778 », « sslPort »: 44382 } }, « profiles »: { « BlazorDemo.Server »: { « commandName »: « Project », « dotnetRunMessages »: true, « launchBrowser »: true, « inspectUri »: « {wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri} », « applicationUrl »: « https://localhost:7249;http://localhost:5249 », « environmentVariables »: { « ASPNETCORE_ENVIRONMENT »: « Development » } }, « IIS Express »: { « commandName »: « IISExpress », « launchBrowser »: true, « inspectUri »: « {wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri} », « environmentVariables »: { « ASPNETCORE_ENVIRONMENT »: « Development » } } } } Comme on peut le voir dans la section "profiles", je peux lancer mon app soit : Via IIS Express  Via la commande dotnet run La première est historique, je pense qu’on en parlera plus dans qq temps. Avant .net core on était obliger de lancer un server utilisant le .net Framework sous IIS qui est le serveur de Windows. La version Express est la version de dévelopement. Pour moi c’est voué à mourrir, mais certains ont des habitudes et Microsoft les forces pas à les changers.  Depuis .net Core (et donc .net 5 et 6), on peut executer nos app sur n’importe quel OS et serveur web comme apache ou nginx sous linux. On a un serveur web intermédiaire appelé Kestrel qui fait le job. D’ailleurs c’est lui que l’on utilise en dévelopement.  En executant une commande dotnet run sur notre projet serveur, on lance un Kestrel. C’est lui que l’on veut paramétrer pour avoir une config dev, staging, prod.  C’est possible d’éditer en développement ce fichier pour changer de port. Mais c’est uniquement un fichier de conf pour une execution en dev local. C’est pas un fichier de configuration plateforme de prod.  Je place ça là car c’est un fichier qui peut vous semer le doute lors de vos devops et test local. AppSettings.{ENV}.json On va modifier le fichier appSettings.Developement.json et lui rajouter ceci  { « Plateform »: « Dev », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:1234 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } Perso je rajoute une ligne "Environment" qui me permet de voir dans sur quel type d’environement je suis (et plus tard de l’afficher dans l’app).  Ce qui nous intéresse c’est la section Kestrel. On ajoute un EndPoints et on lui précise un port.  Faites un dotnet run sur votre projet à présent : On a un warning qui nous dit que l’adresse utilisé va écrasé celle du launchsetting.json. C’est ce qu’on veut. On voit bien la nouvelle adresse http://localhost:1234.  C’était pour la démo, en dev ça sert a rien de faire cela, autant utiliser le launchSettings.json qui est la pour ça. Donc enlever la ligne Kestrel, c’était pour la démo. Par contre on va mettre ces configs pour appsettings.staging.json  { « Plateform »: « Staging », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:7776 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } et appsettings.prod.json { « Plateform »: « Prod », « Kestrel »: { « EndPoints »: { « Http »: { « Url »: « http://localhost:7777 » } } }, « Logging »: { « LogLevel »: { « Default »: « Information », « Microsoft.AspNetCore »: « Warning » } } } ASPNETCORE_ENVIRONMENT Encore une chose à savoir. Pour déterminer sur quel environement .net se trouve, il utilise une variable d’environement ASPNETCORE_ENVIRONMENT Elle est d’ailleurs clairement définie dans le fichier launchSettings.json à "Development". Donc en dev, le fichier de config appsettings utilisé sera appsettings.development.json Pour que ce mécanisme fonctionne en prod, soit on définie la variable ASPNETCORE_ENVIRONMENT à "Production" soit par défaut, si elle n’existe pas, c’est déjà le cas (attention moi j’ai nommé mon appsettings prod et non production). Le problème c’est que une variable d’environement est définie pour tout…

Azure Devops Pipeline (CI/CD) – Versioning

C’est quoi une version ? Je vais faire quelque chose de très basique et qui ne sera probablement pas appliqué tel quel dans un cas plus professionnel. D’ailleurs, chacun ayant ses méthodes de travail, ce post reste un example de "comment on pourrait faire" pour versionner une app.  C’est quoi une version ? La encore, je suis pas sûr que tout le monde utilise la même façon de versionner.  Par exemple les versions du navigateur Firefox utilise simplement un chiffre (https://blog.mozfr.org/pages/Calendrier-versions-Firefox). Mais si on regarde de plus prêt on a quand meme 98.0.1 et donc des points de séparations.  En fait, Pour le grand public on va utiliser "Firefox 98". Mais il faut savoir qu’il existe de nombreuses versions de la 98 ! Du moins en interne. Avant de livrer une version patché 98.0.1 qui va corrigé des bugs mineures.  D’après ce que j’ai pu voir, on utilise principalement ce style de nommage de version X.Y.Z X : Version Majeure (non rétro compatible) (nouvelles fonctionalités, gros correctif, ajout de techno, changement de look…) Y : Version Mineure (rétro compatible) (correctifs, patchs, en gros pas de grosse modif, mais qui répare) Z : Révisions.  (rétro compatible) Sert plutot au dev et product owner pour savoir de quelle version on parle en pre prod pour basculer vers la prod. Quelque part, ce dernier numéro ne devrait à mon sens pas être communiqué officiellement (un peu comme Firefox qq part) Sur la version X, on a je pense tous la même idée. On sort une version X rarement. Par contre, je suis pas certain qu’on utilise tous Y et Z de la même manière. Franchement, c’est freestyle, dans les versions mineures on peut voir de nouvelles (petites) fonctionalités. C’est vraiment selon vos préférences et ceux avec qui vous bosser.  Pour le coté retro compatible, c’est ce que j’ai lu sur le net. Intéressant mais pas du tout respecté par tous.  Autre style, voici un format intéressant ou l’on cumule en plus une date : V 2020.10.23.1629 Je trouve ce format particulièrement intéressant car on sait tout de suite de quand date la version. Mais ca fait bcp de chiffre.  Ce format est utilisé par Larsen Lance avec un scipt powershell qui "incrémente" ce format à chaque build en automatique (http://www.lancelarsen.com/blazor-tips-n-tricks-auto-increment-your-version-tag-with-powershell/) Pourquoi versionner ? La version d’une app sert tout simplement de référenciel. De quoi on parle ? De la version 1.12.665 ou ya un bug qui est corrigé dans la V1.13.005. C’est quand même plus pratique.  Le product owner sera aussi attentif à ces versions concernant l’ajout de nouvelles fonctionalités et communiquer dessus.  Ca permet de prévoir une roadmap large et dire par exemple, cette fonctionalité sera attendu pour la V2.3, pas avant.  En parlant de roadmap, je cite souvent Star Citizen qui est un jeux vidéo en béta depuis des années, et qui affiche ses avancés https://robertsspaceindustries.com/roadmap/release-view Il fixe des objectifs par trimestres sous forme de version avec une majeure et une mineure. C’est clair. Mais bon il sort quand ce jeu !!!! C’est une alpha. Et certain ajoute ce terme dans la version.  Alpha, Beta, Rc (Release Candidate), Nightly Build… On peut préciser le contexte de la version.  Versionner une app .net Core avec une Pipeline automatique Tout l’enjeu de cet article. Comment je peux modifier ma pipeline pour inclure un nouveau numéro de build par exemple à ma version et l’afficher en prod. (comme sur Firefox dans la rubrique aide ou a propos) ? Afficher la version dans l’app Pour que l’on voit directement la version dans mon app Blazor, je vais carrément l’afficher en haut a droite : Une page about avec ce numéro aurait été plus propre sur une vraie App. L’idée ici c’est de l’avoir en permanence sous les yeux.  Pour cela on va modifier MainLayout.razor comme ceci La ligne importante est celle ci : Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion; La version par défaut qui s’affiche est 1.0.0. Si vous faites (sous Visual Studio) un clic droit sur le projet client de Blazor, puis propriété et enfin dans la section Package vous verrez ce numéro. Par contre il n’est pas modifiable.  Pour le modifier, il suffit de rajouter dans le .csproj une ligne version. Easy. Bingo YAML comment gérer une version Je veux une version sous cette forme yyyy.mm.dd.xx, donc date + un numéro auto incrémenté. On commence par ajouter un compteur à une variable. Ce compteur sera automatiquement incrémenté à chaque execution de la pipeline. revision: $[counter(format(‘{0:dd}’, pipeline.startTime), 1)] Pour s’en assurer, on va afficher la valeur de notre variable : #display value – script: echo $(revision) displayName: ‘revision display’ Executez plusieurs fois votre pipeline et aller voir ce que ça donne. Par exemple chez moi : J’en suis à mon 24ième run. Il me faut aussi une date du jour. pour cela on va aussi utiliser une variable dateToday ainsi qu’une derniere variable  »versionString"  qui va concaténer ces deux dernières. (1 h pour trouver comment faire… le ‘>’ magique). Ce qui donne : dateToday: ‘Will be set dynamically’ revision: $[counter(format(‘{0:dd}’, pipeline.startTime), 1)] versionString: > $(dateToday).$(revision) Il suffit à présent de générer dateToday. On va utiliser un script PowerShell (pompé et adapté sur ce site) #Preparing Build Number – task: PowerShell@2 displayName: ‘Preparing Build Number’ inputs: targetType: ‘inline’ script: | $currentDate = $(Get-Date) $year = $currentDate.Year $month = $currentDate.Month $day = $currentDate.Day Write-Host $currentDate Write-Host $day Write-Host $env:revision Write-Host « ##vso[task.setvariable variable=dateToday]$year.$month.$day » On vérifie les données : #display value – script: echo $(revision) displayName: ‘revision display’ – script: echo $(dateToday) displayName: ‘dateToday display’ – script: echo $(versionString) displayName: ‘versionString display’ Normalement on a ce résulat : 2022.3.21.29, version numéro 29 faite le 3 mars 2022, elle est pas belle la vie ?  Publication avec la version J’ai légérement adapté mon script de publication qui était anciennement ceci : # Publish Blazor Demo Server – script: dotnet publish –configuration $(buildConfiguration) src/BlazorDemo/BlazorDemo/Server/BlazorDemo.Server.csproj displayName: ‘dotnet publish $(buildConfiguration)’ Remplacé par : # Publish Blazor Demo Server – task: DotNetCoreCLI@2 displayName: Publish inputs: command: publish publishWebProjects: false projects: ‘$(projectBlazorWasmServer)’ arguments: ‘–configuration $(buildConfiguration) –output $(build.artifactstagingdirectory) /p:Version=$(versionString)’ zipAfterPublish: false modifyOutputPath: false…