Home > Mobile >  Unable to Repeat Template in Azure Pipelines
Unable to Repeat Template in Azure Pipelines

Time:10-05

I have a shared template that I am referencing in my azure pipeline to Build, Test, Pack, and Publish a C# nuget package.

DotNet-BuildTestPackPublish.yml

parameters:
- name: project
  type: string
  default: ''
- name: dotnetVersion
  type: string
  default: '5.0.x'
- name: isNugetPackage
  type: boolean
  default: false
- name: isFirstProjectInRepo
  type: boolean
  default: true

steps: 
- task: UseDotNet@2
  displayName: 'Add .NET ${{parameters.dotnetVersion}}' 
  condition: and(succeeded(), eq(${{parameters.isFirstProjectInRepo}}, true))
  inputs:
    packageType: 'sdk'
    version: ${{parameters.dotnetVersion}}

- task: NuGetAuthenticate@0
  displayName: 'NuGet Auth'
  condition: and(succeeded(), eq(${{parameters.isFirstProjectInRepo}}, true))

- checkout: self
  persistCredentials: true
  displayName: "Git Checkout"
  condition: and(succeeded(), eq(${{parameters.isFirstProjectInRepo}}, true))

- task: DotNetCoreCLI@2
  displayName: "Build"
  inputs:
    command: 'build'
    projects: '**/*.sln'

- task: DotNetCoreCLI@2
  displayName: Unit Test
  inputs:
    projects: '**/*.sln'
    command: 'test'

- task: PowerShell@2 
  displayName: "Extract Version" 
  condition: and(succeeded(), eq(${{parameters.isNugetPackage}}, true), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  inputs: 
    targetType: 'inline' 
    script: | 
      Write-Host "Locating Project Path..."
      $input_path = (Get-ChildItem -Include ${{parameters.project}}.csproj -File -Recurse) 
      Write-Host "Project Path = $input_path"      
      Write-Host "Getting version from csproj..."
      $regex = '(?<=<Version>).*?(?=<\/Version>)' 
      $version = Select-String -Path $input_path -Pattern $regex -AllMatches | % { $_.Matches } | % { $_.Value }       
      Write-Host "Version = $version"
      if([string]::IsNullOrWhiteSpace($version))
      {
          Write-Host "Version not in csproj. Defaulting to 1.0.0"
          $version = "1.0.0"
      }      
      Write-Host "Getting Build Number from Environment"
      $buildNumber = '$(Build.BuildId)' 
      Write-Host "Build Number = $buildNumber" 
      $versionAndBuildNumber = "$version $buildNumber"
      Write-Host "Package Version = $versionAndBuildNumber" 
      $tagText = "${{parameters.project}} $version $buildNumber"
      Write-Host "Tag Text = $tagText" 
      Write-Output "##vso[task.setvariable variable=gitTag]$tagText" 
      Write-Output "##vso[task.setvariable variable=versionNumber]$versionAndBuildNumber" 
      
- task: PublishSymbols@2
  inputs:
    searchPattern: '**/bin/**/${{parameters.project}}.pdb' 
    symbolServerType: "teamServices"

- task: DotNetCoreCLI@2
  displayName: "Nuget Pack"
  condition: and(succeeded(), eq(${{parameters.isNugetPackage}}, true), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  inputs:
    command: 'pack'
    packagesToPack: '**/${{parameters.project}}.csproj'
    versioningScheme: byEnvVar 
    versionEnvVar: versionNumber 
    includesymbols: true
    includesource: true

- task: NuGetCommand@2
  displayName: "Nuget Push"
  condition: and(succeeded(), eq(${{parameters.isNugetPackage}}, true), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  inputs:
    command: 'push'
    packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg'
    nuGetFeedType: 'internal'
    publishVstsFeed: 'Internal'
    allowPackageConflicts: true

- script: |
    echo Current Directory:
    cd
    dir /s
    git tag $(gitTag)
    git push --tags origin $(gitTag)
  workingDirectory: $(Build.SourcesDirectory)
  displayName: "Git Tag Repository"
  condition: and(succeeded(), eq(${{parameters.isNugetPackage}}, true), eq(variables['Build.SourceBranch'], 'refs/heads/main'))

This works well if there is only one project in my repository:

azure-pipelines.yml (only one project)

trigger:
  branches:
    include:
    - '*'

pool:
  vmImage: 'windows-latest'

resources: 
  repositories: 
  - repository: BuildScripts 
    name: Feldryn/BuildScripts 
    type: git 
    ref: main
    trigger:
      - main

variables:
- group: 'Pipeline Shared Variables'

steps:
- template: DotNet-BuildTestPackPublish.yml@BuildScripts
  parameters:
    project: 'Daemon.Domain.RumbleRunners.Values'
    isNugetPackage: true

# the following step is superfluous for this example, but it DOES work
- task: PowerShell@2 
  displayName: "Replace Project Reference with Nuget" 
  inputs: 
    targetType: 'inline' 
    script: | 
      cd Daemon.Domain.RumbleRunners
      dotnet remove reference ..\Daemon.Domain.RumbleRunners.Values\Daemon.Domain.RumbleRunners.Values.csproj 
      dotnet add package Daemon.Domain.RumbleRunners.Values
      cd..

As soon as I attempt to call the template again in the same pipeline for another project, the first will start failing.

This does not work: azure-pipelines.yml (two projects)

trigger:
  branches:
    include:
    - '*'

pool:
  vmImage: 'windows-latest'

resources: 
  repositories: 
  - repository: BuildScripts 
    name: Feldryn/BuildScripts 
    type: git 
    ref: main
    trigger:
      - main

variables:
- group: 'Pipeline Shared Variables'

steps:
- template: DotNet-BuildTestPackPublish.yml@BuildScripts
  parameters:
    project: 'Daemon.Domain.RumbleRunners.Values'
    isNugetPackage: true

- task: PowerShell@2 
  displayName: "Replace Project Reference with Nuget" 
  inputs: 
    targetType: 'inline' 
    script: | 
      cd Daemon.Domain.RumbleRunners
      dotnet remove reference ..\Daemon.Domain.RumbleRunners.Values\Daemon.Domain.RumbleRunners.Values.csproj 
      dotnet add package Daemon.Domain.RumbleRunners.Values
      cd..

# the inclusion of following step is the only change
- template: DotNet-BuildTestPackPublish.yml@BuildScripts
  parameters:
    project: 'Daemon.Domain.RumbleRunners'
    isNugetPackage: true
    isFirstProjectInRepo: false

It fails with 'fatal: not a git repository (or any of the parent directories): .git' when attempting to git tag the first project.

I've done some troubleshooting and determined:

  • It's not my git tag step that is at fault.
    • It works when there is one project
    • The failure moves to the following step if I comment the git tag step.
      • New error: Could not find any project in D:\a\1\s\Daemon.Domain.RumbleRunners\.
  • I've outputted the contents of my working directory and can see all expected files are present, including the .git folder
  • The working directory is not different between the working and non-working approaches.

I'm at a loss for how to troubleshoot further.

Why can't I call my template twice? What is happening here?

CodePudding user response:

checkout task behaves differently when there are multiple checkouts:

  1. When there's only a single checkout: self step, it will check out the repository to /home/vsts/work/1/s/.
  2. When there are multiple checkout steps (even if they refer to the same repository), it will check out to /home/vsts/work/1/s/{repository_name}.

Even though you have a condition on the second checkout, the step still counts, thus point 2. applies.

To validate this, check logs of checkout task for both scenarios. You can also try a minimal repro pipeline:

steps:
  - checkout: self # <-- /home/vsts/work/1/s/ 

vs

steps:
  - checkout: self # <-- /home/vsts/work/1/s/{repo_name}/
  - checkout: self # <-- /home/vsts/work/1/s/{repo_name}/
    condition: false
  • Related