Azure Pipeline从Bitbucket拉取代码时CI任务工作目录不一致问题问询
背景
我有一个Azure DevOps(ADO)流水线,包含名为option的运行时参数,可选值为ci、cd、release-test、release-build。流水线会根据option的取值调用对应模板,四个模板都会先调用同一个setup_tasks.yml模板,该模板会执行从Bitbucket Cloud拉取源代码的checkout操作。
全局仅存在一份setup_tasks.yml,供四个模板共用。
核心配置文件
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
- CI模板
pipelines/ci-build.yml内容如下,另外三个模板除了作业名称和专属业务逻辑外完全一致:
# 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
- 公共检出模板
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
问题现象
四个模板中,三个执行checkout任务的行为一致且符合预期,仅ci对应的模板执行checkout时行为异常:
- 正常任务的checkout输出示例:
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
- CI任务的checkout输出示例:
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
待解答问题
- 为什么ADO
checkout任务在ci选项下会使用不同的目标目录拉取代码? - 相关配置存储在ADO虚拟机还是代码仓库中,要如何访问并修改这些配置?
参考信息
- 所有代理均为运行在Azure虚拟机上的自托管代理。
- 目前所有构建均为手动触发,手动设置
option运行时变量。 ci选项为最早开发的功能,其余三个选项为后续新增,该异常行为可能从ci功能上线起就存在。
已完成的排查操作
手动复制原ci-build.yml的文本内容新建了pipelines\ci-build2.yml模板,同时在ADO上新建了指向同一个Bitbucket仓库的流水线。在新流水线触发ci构建时,虽然拉取的仓库名仍有差异,但目标目录已经恢复正常。无法判断是模板修改还是新建流水线修复了目录异常问题,不清楚底层相关参数或配置的变动逻辑。
问题1解答
该异常由旧流水线的UI层残留配置导致,和代码中的YAML模板无关:
CI是最早开发的功能,早期配置流水线时,大概率在ADO流水线UI中设置过自定义检出路径、或者配置过多仓库资源,即使后续YAML模板已经统一为使用checkout: self,旧流水线的UI配置不会自动同步更新,会强制将代码检出到以仓库名命名的子目录下。其余三个选项是后续新增的,没有修改过UI层面的配置,所以沿用默认的检出路径$(Pipeline.Workspace)/s。
你新建流水线后目录恢复正常,也验证了这一点:新流水线没有历史UI配置残留,会完全按照YAML内容执行检出逻辑。
问题2解答
相关配置分为两类,存储位置和修改方式如下:
- YAML格式的流水线配置:存储在Bitbucket代码仓库中,直接修改对应文件提交即可生效。
- 流水线UI层面的自定义配置:存储在Azure DevOps服务端,既不在代码仓库也不在代理虚拟机中。修改方式为:打开旧的目标流水线,点击「编辑」→ 右上角三个点的更多按钮→ 「触发器」,先查看「变量」页签,删除自定义的
Build.SourcesDirectory、CheckoutPath等和路径相关的变量;再查看「资源」→「仓库」页签,删除多余的仓库配置,仅保留当前使用的主仓库即可。
如果要彻底避免该类问题,可以直接在setup_tasks.yml的checkout步骤中强制指定检出路径:
- checkout: self clean: true path: s # 强制检出到$(Pipeline.Workspace)/s目录 displayName: Checkout source
内容的提问来源于stack exchange,提问作者Ray Depew

