1

I have a Azure DevOps (ADO) pipeline with a runtime variable or parameter called option. option can have values of build, test, ci, or cd. The pipeline immediately calls a template based on the value of option. Each of these templates then immediately calls another template, setup_tasks.yml. The setup_tasks.yml template immediately checks out the source code from Bitbucket cloud.

There's only one setup_tasks.yml. It's used by all four templates.

Contents of `azure-pipelines.yml':

# Azure Pipeline for ACM builds.

trigger:
- azure-pipelines
- parallel-builds2

parameters:
- name: option
  type: string
  default: 'release-build'
  values:
  - 'ci'
  - 'cd'
  - 'release-test'
  - 'release-build'
- name: agent
  type: string
  default: 'ACMBUILD3'
  values:
  - 'ACMBUILD3'
  - 'ACMBUILD4'
  - 'ACMBUILD5'
  - 'ACMBUILD6'
  - 'ACMBUILD32'
  - 'ACMBUILD64'
- name: bits
  type: string
  default: '64'
  values:
  - '64'
  - '32'

pool:
  name: 'Default'

variables:

  - name: buildConfiguration
    ${{ if eq(parameters.option, 'cd')}}:
      value: 'CD'
    ${{ if eq(parameters.option, 'ci')}}:
      value: 'Debug'
    ${{ if eq(parameters.option, 'release-build')}}:
      value: 'Release'
    ${{ if eq(parameters.option, 'release-test')}}:
      value: 'Test'
  - name: theAgent
    value: ${{ parameters.agent }}
  - name: buildPlatform
    ${{ if eq(parameters.bits, '32') }}:
      value: 'x86'
    ${{ if eq(parameters.bits, '64') }}:
      value: 'x64'
  - name: nativePlatform
    ${{ if eq(parameters.bits, '32') }}:
      value: 'Win32'
    ${{ if eq(parameters.bits, '64') }}:
      value: 'x64'

jobs:
- ${{ if eq(parameters.option, 'cd') }}:
  - template: pipelines/cd-build.yml
- ${{ if eq(parameters.option, 'ci') }}:
  - template: pipelines/ci-build.yml
- ${{ if eq(parameters.option, 'release-build') }}:
  - template: pipelines/release-build.yml
- ${{ if eq(parameters.option, 'release-test') }}:
  - template: pipelines/release-test.yml

Contents of template pipelines/ci-build.yml. The other three templates are identical, except for the job name, down to the point that says "CI specific stuff starts here". Therefore, only one template is shown here:

# Template for CI build


jobs:
- job: ACM_CI_Build
  timeoutInMinutes: 0 # No time limit
  pool:
    name: 'Default'
    demands:
    - Agent.Name -equals $(theAgent)

  steps:
  - template: ./setup-tasks.yml

  - powershell: | 
        Copy-Item -Path "$(Pipeline.Workspace)\s\packages" -Destination "c:\users\public" -Force -Recurse 
    displayName: Save a copy of NuGet packages 

  - powershell: |
      Write-Host "CI specific stuff starts here"
    displayName: And so on

Contents of pipelines/setup_tasks.yml:

steps:
- checkout: self
  clean: true
  displayName: Checkout source 

- script: type c:\users\Public\dummy.txt
  displayName: 'Verify self-hosted agent'

- powershell: |
    Write-Host "This is where the problem becomes evident"
    Write-Host "... because the named files are not found their expected places."
    Write-Host "A CI job will exit with error."
    ForEach ( $file in (
      "$(Pipeline.Workspace)\s\Build\acm_components.targets",
      "$(Pipeline.Workspace)\s\Client\something\else.txt"
      )
    )
    {
      Write-Host "Doing stuff to $file"
    }
  displayName: The AAB hack

- script: |
    Write-Host "Rest of setup.yml is NuGet tasks, et cetera"
    Write-Host "By now, the damage is done"
  displayName: And so on

The problem is this: Of the four templates, three of them execute the checkout task the same way, and one of them (the ci one) does it differently.

Here's the relevant output from the three that are doing it the correct way.

Syncing repository: blabla/acm_source_821_azure_pipelines (Bitbucket)
Prepending Path environment variable with directory containing 'git.exe'.
...
##[command]git init "C:\acmbuild6\_work\1\s"
Initialized empty Git repository in C:/acmbuild6/_work/1/s/.git/
##[command]git remote add origin https://bitbucket.org/blabla/acm_source_821_azure_pipelines

Here's the way the ci task does it.

Syncing repository: blabla/acm_source_821_***_pipelines (Bitbucket)
Prepending Path environment variable with directory containing 'git.exe'.
##[command]git init "C:\acmbuild4\_work\2\s\acm_source_821_***_pipelines"
Initialized empty Git repository in C:/acmbuild4/_work/2/s/acm_source_821_***_pipelines/.git/
##[command]git remote add origin https://bitbucket.org/blabla/acm_source_821_***_pipelines

Why does the ADO checkout task use a different repository and a different target directory for my option ci than for my other options?

Where is this configuration info stored on my ADO VM (or perhaps in the repo), and how can I access it to edit the info?

Screenshot of the job flow, with resulting error. enter image description here

Additional information that might help

  • My agents are all self-hosted agents, running on an Azure VM.
  • At the moment, I am triggering the builds manually, and manually setting the option value as a runtime variable.
  • If I recall correctly, the ci option was the first option that I developed. That was a few months ago. The other three options came later. I only noticed this behavior recently, but it may have been there all along.

Troubleshooting work

I created a duplicate templte, called pipelines\ci-build2.yml. I copied the text from the original ci-build.yml template and pasted it into ci-build2.yml, instead of just running a command like cp ci-build.yml ci-build2.yml. That way I made sure I got only the text.

Then I created a new pipeline on ADO. This pipeline uses the same BBCloud repository as the original pipeline -- so its operation is identical to the original pipeline.

When I select a ci build on this new pipeline, it still uses the different repository, but this time it uses the correct target directory.

I don't know which of the two changes (different ci-build.yml template, different pipeline) fixed the problem, because I can't see what's happening under the hood. I don't know what parameters or config settings got changed. Can anyone give me some hints?

Ray Depew
  • 573
  • 1
  • 9
  • 22
  • What does your `repositories` section look like? That's where the service connection to the repo is used. That's where your problem is likely to be. It would be useful if you posted the entirety of your YAML, including all of the templates and the pipeline definitions that reference the templates. The problem you're describing isn't "the wrong repo is being checked out", it's "the local working directory for the repo is inconsistent". You should update your question's title to reflect the actual problem. – Daniel Mann Nov 19 '21 at 20:36
  • I don't have an explicit `repositories` section, just using the default. Per your request, I've posted the YAML and changed the title of the question. – Ray Depew Nov 19 '21 at 22:13
  • Similarly, I don't specify a path in the `checkout` task. I just take the default of `_work\\s`. – Ray Depew Nov 19 '21 at 22:49
  • Is the job that's behaving differently perhaps a `deployment` job? Or is it bringing in additional repositories? – Daniel Mann Nov 19 '21 at 23:16
  • No, all four jobs are regular build jobs. – Ray Depew Nov 19 '21 at 23:35
  • I attached a screenshot of the build output. – Ray Depew Nov 19 '21 at 23:36
  • Are any of the templates checking out additional repositories? – Daniel Mann Nov 20 '21 at 07:41
  • No, the only repository that is checked out is the `acm_source_821_azure_pipelines` repo, and it's only checked out in `setup-tasks.yml`. All four templates utilize that template to checkout the source. – Ray Depew Nov 22 '21 at 21:05
  • I added some information based on my troubleshooting work. – Ray Depew Nov 30 '21 at 14:59
  • 1
    @DanielMann I should have caught a clue from your "multiple repositories" questions. It wasn't checking out multiple repositories, but it was checking out the same repository multiple times. See the answer. – Ray Depew Dec 09 '21 at 19:24

1 Answers1

1

The issue was with a part of `pipelines/ci-build.yml' that I didn't put in the code listing in my original problem statement, because I didn't think it was relevant. It turned out to be the critical piece.

After completing the steps shown in the listing above, the next step for pipelines/ci-build.yml is to checkout the source a second time. The checkout tasks are identical in pipelines/setup-tasks.yml and pipelines/ci-build.yml.

- checkout: self
  clean: true

According to the Checkout path documentation, a pipeline can checkout a single repository or multiple repositories.

  • If a single repository, it goes in c:\acmbuild6\_work\1\s. (following my pathnames from the original problem statement)
  • If multiple repositories, each repository goes in its own subdirectory. So they go in c:\acmbuild6\_work\1\s\FirstRepoName and c:\acmbuild6\_work\1\s\SecondRepoName.

When I wrote the pipeline files, I assumed that since the same repository was being referenced in both files, it was counted as a "single repository". However, it appears that Azure Pipelines considers multiple checkout tasks to be "multiple repositories"; therefore, it checks out my code into c:\acmbuild6\_work\1\s\acm_source_821_azure_pipelines. Twice.

The simple solution to the problem is to specify the target path explicitly in the checkout task:

steps:
- checkout: self
  clean: true
  path: s

The path is defined relative to the pipeline workspace, c:\acmbuild6\_work\1 in my case, or c:\<agent>\_work\<n> in the general case. This solution has been tested, and it works.

A better solution is to rewrite either the pipeline or the project source, so that the second checkout in ci-build.yml is unnecessary.

Ray Depew
  • 573
  • 1
  • 9
  • 22
  • 1
    Glad you figured it out -- that was *exactly* what I was getting at... the inner folder structure changes if you're checking out one repo vs multiple repos because it has to disambiguate the repos. – Daniel Mann Dec 09 '21 at 20:20