Saturday, November 30, 2019

Reusing Steps in Azure DevOps Build Pipelines with YAML Templates

Azure DevOps allows us to create yaml build pipelines. If you use yaml build pipelines you may have realized, there are repetitive steps which can be reused in multiple build pipelines. You can create a yaml template with include all the repetitive steps and reuse that template with in other yaml file which defines a build pipelines. This post will explain how to create a yaml template and use it in a pipeline.

Following is the yaml script which doesn't use templates. It has all the steps in the same yaml file which makes a script not manageable.
pool:
  name: Hosted Windows 2019 with VS2019
  demands:
  - msbuild
  - visualstudio
  - vstest


variables:
  BuildPlatform: 'Any CPU'
  BuildConfiguration: 'Release'

steps:

- task: NuGetToolInstaller@1
  displayName: 'Use NuGet 4.7.1'
  inputs:
    versionSpec: 4.7.1

- task: DotNetCoreCLI@2
  displayName: 'dotnet restore'
  inputs:
    command: restore
    projects: '**/Test.sln'
    feedsToUse: config
    nugetConfigPath: Nuget.config

- task: NuGetCommand@2
  displayName: 'NuGet restore'
  inputs:
    restoreSolution: '**/Test.sln'

- task: VSBuild@1
  displayName: 'Build solution **/Test.sln'
  inputs:
    solution: '**/Test.sln'
    vsVersion: 16.0
    msbuildArgs: '/p:JavaSdkDirectory="$(JAVA_HOME_8_X64)"'
    platform: '$(BuildPlatform)'
    configuration: '$(BuildConfiguration)'
    clean: true

- task: VSTest@2
  displayName: 'VsTest - testAssemblies'
  inputs:
    testAssemblyVer2: |
     **\*test*.dll
     !**\*TestAdapter.dll
     !**\*Test.UnitTest.dll
     !**\obj\**
    diagnosticsEnabled: true
    rerunFailedTests: true

We can put common script to template yaml file with parameters as follows(Template.yml). There are three parameters use in this template.

parameters:
  BuildConfiguration: ''
  FunctionPath: ''
  NuspecName: ''  

steps:

- task: DotNetCoreCLI@2
  displayName: 'Build Project'
  inputs:
    command: publish
    publishWebProjects: false
    projects: '${{ parameters.FunctionPath }}/**/*.csproj'
    arguments: '--output $(Build.ArtifactStagingDirectory)/publish_output --configuration $(BuildConfiguration)'
    zipAfterPublish: false
    modifyOutputPath: false

- task: DotNetCoreCLI@2
  displayName: 'dotnet test'
  inputs:
    command: test
    projects: |
     ${{ parameters.FunctionPath }}/**/*test*.csproj
     !**\*TestAdapter*.dll
     !\obj\

- task: NuGetCommand@2
  displayName: 'NuGet pack'
  inputs:
    command: pack
    packagesToPack: '${{ parameters.FunctionPath }}/${{ parameters.NuspecName }}'
    versioningScheme: byBuildNumber
    basePath: '$(Build.ArtifactStagingDirectory)/publish_output'

- task: NuGetCommand@2
  displayName: 'NuGet push'
  inputs:
    command: push
    publishVstsFeed: '8d31bac5-d81b-409f-84d9-b7dab544a29e'
    allowPackageConflicts: true

We have a template yaml script which has the all common steps with parameters. Let's see how we can use this template with in another yaml file, which defines the build template. As shown in the following code segment you can call the template yaml  and pass the parameter values.

steps: 
- template: Template.yml 
  parameters:
    BuildConfiguration: 'Release'
    FunctionPath: 'Functions/MyApp’
    NuspecName: 'MyApp.nuspec'

Following yaml script shows the complete build pipeline which is a good example of,  how you can use the yaml template with in another yaml based build pipeline.

trigger:
  branches:
    include:
    - master
    - develop
    - version/*
    exclude:
    - feature/*
  paths:
    include:
    - Functions/MyApp
variables:
  BuildConfiguration: 'Release'
  FunctionPath: 'Functions/MyApp'
  NuspecName: 'MyApp.nuspec'
pool:
  vmImage: 'windows-latest'
name: $(Build.SourceBranchName).$(Build.BuildId)
steps: 
- template: Template.yml 
  parameters:
    BuildConfiguration: $(BuildConfiguration)
    FunctionPath: $(FunctionPath)
    NuspecName: $(NuspecName) 

You can see it has variable section which have the values of the parameters. Under step section we can call the template and pass the values to the template parameters as shown in the yaml file above.

No comments:

Post a Comment