Exercice : Générer plusieurs configurations à l’aide de modèles

Effectué

Dans les exercices précédents, vous avez implémenté un pipeline qui génère le site web Space Game. Vous avez commencé avec un script qui exécutait chaque action de génération et mappait chaque action à sa tâche de pipeline correspondante. La sortie du pipeline est un fichier .zip qui contient l’application web compilée.

Dans cet exercice, vous allez utiliser un modèle pour définir les tâches de génération capables de générer n’importe quelle configuration définie dans le fichier projet. Les modèles vous permettent de définir votre logique une seule fois, puis de la réutiliser plusieurs fois. Ils combinent le contenu de plusieurs fichiers YAML dans un pipeline unique.

Conseil

Cette étape du module est facultative. Si vous ne souhaitez pas en savoir plus sur les modèles pour l’instant, passez à l’étape suivante, Nettoyer votre environnement Azure DevOps. Pour plus d’informations sur les modèles, consultez Types de modèles et utilisation.

Commençons par retrouver Mara et Amita.

La démo

Mara, impatiente de partager ses résultats, finit par retrouver Amita pour lui montrer le pipeline de build.

Amita : Je suis impressionnée, car vous avez réussi à faire ce que vous vouliez en très peu de temps ! En fait, je venais justement vous voir parce que j’ai reçu un e-mail me prévenant que la build était prête. Merci ! Je vois que le pipeline génère uniquement la configuration Release. Or, nous utilisons également des builds Debug pour pouvoir capturer d’autres informations si l’application plante. Est-ce que nous pouvons en ajouter une ?

Mara : Bien sûr. J’ai oublié de considérer les builds Debug quand j’ai configuré tout ça. Que diriez-vous de l’ajouter ensemble ?

Amita : Vous m’avez montré le fichier YAML qui définit les étapes de génération, mais je ne sais pas vraiment comment le modifier.

Mara : C’est normal. Vous pouvez me regarder taper. Nous allons y réfléchir ensemble.

Comment pouvez-vous définir les deux configurations de build ?

Considérez les tâches suivantes qui génèrent et publient la configuration Release du projet web Space Game. (N’ajoutez pas ce code à votre fichier azure-pipelines.yml.)

- task: DotNetCoreCLI@2
  displayName: 'Build the project - Release'
  inputs:
    command: 'build'
    arguments: '--no-restore --configuration Release'
    projects: '**/*.csproj'

- task: DotNetCoreCLI@2
  displayName: 'Publish the project - Release'
  inputs:
    command: 'publish'
    projects: '**/*.csproj'
    publishWebProjects: false
    arguments: '--no-build --configuration Release --output $(Build.ArtifactStagingDirectory)/Release'
    zipAfterPublish: true

Pour générer la configuration Debug, vous pouvez répéter ces deux tâches, en remplaçant Release par Debug.

Vous obtenez ainsi le résultat escompté pour le moment, mais que se passera-t-il quand votre build deviendra plus complexe ou que vos besoins évolueront ? Vous devrez alors rechercher et changer manuellement les deux variantes de chaque tâche de génération. Une fois que vous aurez ajouté les exigences de build supplémentaires, vous devrez également créer deux tâches, une pour la configuration Debug et une pour la configuration Release, afin de satisfaire à ces exigences.

Une meilleure solution consiste à utiliser un modèle.

Que sont les modèles ?

Un modèle vous permet de définir des tâches de génération courantes une seule fois pour les réutiliser plusieurs fois.

Vous allez appeler un modèle à partir du pipeline parent en tant qu’étape de génération. Vous pouvez passer des paramètres dans un modèle à partir du pipeline parent.

Mara peut définir des tâches pour générer et publier l’application en tant que modèle, puis appliquer ce modèle à chaque configuration dont elle a besoin.

Définir le modèle

Pour rappel, un modèle vous permet de définir des tâches de génération courantes une seule fois pour les réutiliser plusieurs fois. Vous appelez un modèle à partir de son modèle parent en tant qu’étape de génération, puis vous passez des paramètres dans un modèle à partir du pipeline parent.

Vous allez maintenant créer un modèle capable de générer n’importe quelle configuration définie dans le fichier projet.

  1. À partir de la console intégrée de Visual Studio Code, à la racine de votre projet, créez un répertoire nommé templates.

    mkdir templates
    

    Dans la pratique, vous pouvez choisir tout autre emplacement pour votre fichier de modèle. Vous n’êtes pas obligé de le placer dans le répertoire templates.

  2. Dans Visual Studio Code, sélectionnez Fichier > Nouveau fichier. Ensuite, pour enregistrer le fichier vide sous le nom build.yml dans le répertoire templates de votre projet, sélectionnez Fichier > Enregistrer. Voici un exemple : ~/mslearn-tailspin-spacegame-web/templates.

    Important

    Comme précédemment, dans Windows, dans la liste Enregistrer sous le type, sélectionnez YAML.

  3. Dans Visual Studio Code, ajoutez ce code à build.yml :

    parameters:
      buildConfiguration: 'Release'
    
    steps:
    - task: DotNetCoreCLI@2
      displayName: 'Build the project - ${{ parameters.buildConfiguration }}'
      inputs:
        command: 'build'
        arguments: '--no-restore --configuration ${{ parameters.buildConfiguration }}'
        projects: '**/*.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Publish the project - ${{ parameters.buildConfiguration }}'
      inputs:
        command: 'publish'
        projects: '**/*.csproj'
        publishWebProjects: false
        arguments: '--no-build --configuration ${{ parameters.buildConfiguration }} --output $(Build.ArtifactStagingDirectory)/${{ parameters.buildConfiguration }}'
        zipAfterPublish: true
    

    Ces tâches sont similaires à celles que vous avez définies précédemment pour générer et publier l’application. Toutefois, dans un modèle, vous utilisez les paramètres d’entrée de manière différente des variables standard. Deux différences sont à noter :

    • Dans un fichier de modèle, utilisez la section parameters au lieu de variables pour définir des entrées.
    • Dans un fichier de modèle, utilisez la syntaxe ${{ }} au lieu de la syntaxe $() pour lire la valeur d’un paramètre. Quand vous lisez la valeur d’un paramètre, vous incluez la section parameters dans son nom. Par exemple : ${{ parameters.buildConfiguration }}.

Appeler le modèle à partir du pipeline

Vous allez maintenant appeler le nouveau modèle à partir du pipeline. Vous le faites une fois pour la configuration Debug, puis vous répétez le processus pour la configuration Release.

  1. Dans Visual Studio Code, modifiez azure-pipelines.yml comme ceci :

    trigger:
    - '*'
    
    pool:
      vmImage: ubuntu-latest
    
    variables:
      buildConfiguration: 'Release'
      wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
      dotnetSdkVersion: '6.x'
    
    steps:
    - task: UseDotNet@2
      displayName: 'Use .NET SDK $(dotnetSdkVersion)'
      inputs:
        version: '$(dotnetSdkVersion)'
    
    - task: Npm@1
      displayName: 'Run npm install'
      inputs:
        verbose: false
    
    - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
      displayName: 'Compile Sass assets'
    
    - task: gulp@1
      displayName: 'Run gulp tasks'
    
    - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
      displayName: 'Write build info'
      workingDirectory: $(wwwrootDir)
    
    - task: DotNetCoreCLI@2
      displayName: 'Restore project dependencies'
      inputs:
        command: 'restore'
        projects: '**/*.csproj'
    
    - template: templates/build.yml
      parameters:
        buildConfiguration: 'Debug'
    
    - template: templates/build.yml
      parameters:
        buildConfiguration: 'Release'
    
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact: drop'
      condition: succeeded()
    
    trigger:
    - '*'
    
    pool:
      name: 'Default' #replace if needed with name of your agent pool
    
    variables:
      buildConfiguration: 'Release'
      wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
      dotnetSdkVersion: '6.x'
    
    steps:
    - task: UseDotNet@2
      displayName: 'Use .NET SDK $(dotnetSdkVersion)'
      inputs:
        version: '$(dotnetSdkVersion)'
    
    - task: Npm@1
      displayName: 'Run npm install'
      inputs:
        verbose: false
    
    - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
      displayName: 'Compile Sass assets'
    
    - task: gulp@1
      displayName: 'Run gulp tasks'
    
    - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
      displayName: 'Write build info'
      workingDirectory: $(wwwrootDir)
    
    - task: DotNetCoreCLI@2
      displayName: 'Restore project dependencies'
      inputs:
        command: 'restore'
        projects: '**/*.csproj'
    
    - template: templates/build.yml
      parameters:
        buildConfiguration: 'Debug'
    
    - template: templates/build.yml
      parameters:
        buildConfiguration: 'Release'
    
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact: drop'
      condition: succeeded()
    

    Ce fichier ressemble au fichier initial, sauf qu’il remplace les tâches de génération et de publication par des appels au modèle qui effectue les mêmes tâches.

    Vous voyez que le modèle est appelé une seule fois pour chaque configuration. Pour passer le nom de la configuration au modèle, chaque tâche template utilise l’argument parameters.

Exécuter le pipeline

Vous allez maintenant pousser vos modifications vers GitHub et regarder le pipeline s’exécuter.

  1. Dans le terminal intégré, ajoutez azure-pipelines.yml et templates/build.yml à l’index, validez les modifications, puis poussez-les (push) vers GitHub.

    git add azure-pipelines.yml templates/build.yml
    git commit -m "Support build configurations"
    git push origin build-pipeline
    
  2. Depuis Azure Pipelines, tracez la build tout au long des étapes de génération, comme vous l’avez déjà fait précédemment.

    À mesure que le pipeline s’exécute, vous voyez que le processus développe les tâches incluses dans le modèle. Les tâches qui génèrent et publient le projet sont exécutées deux fois (une fois pour chaque configuration de build).

    Screenshot of Azure Pipelines showing the expanded template tasks. Included are build and publish tasks for both the Debug and Release configurations.

  3. Une fois la build terminée, revenez à la page du récapitulatif, puis sélectionnez l’artefact publié comme vous l’avez fait précédemment. Développez le dossier de dépôt (drop).

    Vous voyez que le pipeline produit un fichier .zip pour chacune des deux configurations, Debug et Release.

    Screenshot of Azure Pipelines showing the packaged application for both Debug and Release configurations.

Fusionner la branche dans main

À ce stade, vous avez un pipeline de build opérationnel qui réalise tout ce dont Mara a besoin pour le moment.

Dans la pratique, vous envoyez une demande de tirage (pull request) qui fusionne votre branche build-pipeline dans la branche main.

Nous allons ignorer cette étape pour l’instant. Dans le prochain module, vous allez découvrir des moyens de collaborer avec votre équipe sur GitHub, notamment comment envoyer, vérifier et fusionner des demandes de tirage.