Azure DevOps Pipeline中Cache@2+Poetry缓存命中后poetry run失败求助
问题:缓存命中时Poetry执行
poetry run coverage失败 在Azure DevOps托管构建代理中运行以下azure-pipelines.yml配置时,Cache@2步骤缓存命中后,poetry run coverage命令报错"Command not found: coverage",但跳过缓存重新安装依赖则正常运行。
配置文件内容
- task: UsePythonVersion@0 inputs: versionSpec: $(pythonVersion) displayName: 'Use Python 3.10.8' - script: | export POETRY_VERSION=$(poetryVersion) curl -sSL https://install.python-poetry.org | python - echo "##vso[task.setvariable variable=PATH]${PATH}:$HOME/.local/bin" displayName: 'Install poetry' - ${{ if eq(parameters.usePoetryCache, true) }}: - task: Cache@2 inputs: key: 'poetry | "$(Agent.OS)" | poetry.lock' # restoreKeys: | # poetry | "$(Agent.OS)" # poetry path: $(venv) cacheHitVar: POETRY_CAHCE_RESTORED - script: | poetry config virtualenvs.in-project true poetry config virtualenvs.path $(venv) displayName: Configure Poetry - script: | poetry install displayName: Install dependencies condition: eq(variables.POETRY_CAHCE_RESTORED, 'false') - script: | poetry show coverage displayName: Check coverage installation - script: | poetry run coverage run -m pytest && poetry run coverage xml -o ${{ parameters.workingDirectory }}/${{ parameters.testResultsDir }}/coverage.xml displayName: Run tests & code coverage # THIS FAILS
关键日志详情
Cache@2 缓存命中日志
Resolving key: - poetry [string] - "Linux" [string] - poetry.lock [file] --> 7AFBEE979DA4396BFE2D0AEF57A0A6A210629F38EFE50786DF26B396ECD935E0 Resolved to: poetry|"Linux"|VHTXv4eVo2iEXIULm/6DKwpSuYJEqaI86WbrPgZ3/T4= Using default max parallelism. Max dedup parallelism: 192 Getting a pipeline cache artifact with one of the following fingerprints: Fingerprint: `poetry|"Linux"|VHTXv4eVo2iEXIULm/6DKwpSuYJEqaI86WbrPgZ3/T4=` There is a cache hit: `poetry|"Linux"|VHTXv4eVo2iEXIULm/6DKwpSuYJEqaI86WbrPgZ3/T4=` Used scope: 3012;5b97d788-43ec-45d8-836e-eaa18049b8fb;refs/heads/feature/pipeline-work;ff191ef6-ebfd-4d63-9d61-e7d1f8ceaf65 Entry found at fingerprint: `poetry|"Linux"|VHTXv4eVo2iEXIULm/6DKwpSuYJEqaI86WbrPgZ3/T4=` Expected size to be downloaded: 121.7 MB Downloaded 0.0 MB out of 121.7 MB (0%). Downloaded 121.7 MB out of 121.7 MB (100%). Download statistics: Total Content: 121.7 MB Physical Content Downloaded: 48.8 MB Compression Saved: 72.9 MB Local Caching Saved: 0.0 MB Chunks Downloaded: 1,483 Nodes Downloaded: 3
检查Coverage安装日志
name : coverage version : 6.5.0 description : Code coverage measurement for Python dependencies - tomli *
执行测试报错日志
poetry run coverage run -m pytest && poetry run coverage xml -o /agent/_work/22/s/TestResults/coverage.xml ========================== Starting Command Output =========================== /bin/bash --noprofile --norc /agent/_work/_temp/XXXXXXXXXXXXXXXXXX.sh Command not found: coverage ##[error]Bash exited with code '1'. Finishing: Run tests & code coverage
原因分析
- 虚拟环境关联失效:缓存恢复了虚拟环境目录,但Poetry未自动识别该环境,
poetry run仍尝试使用默认环境(未安装coverage)。 - 变量拼写错误:缓存步骤中
cacheHitVar写成了POETRY_CAHCE_RESTORED(多了一个C),虽然不影响条件判断,但会导致变量名不规范,增加排查难度。 - 配置时机错误:在缓存恢复后才配置Poetry虚拟环境路径,导致缓存的环境未被纳入Poetry的识别范围。
解决方法
方法1:修复拼写错误并强制关联缓存环境
- 修正
cacheHitVar的拼写为POETRY_CACHE_RESTORED,统一变量命名。 - 在缓存命中后添加步骤,让Poetry明确关联缓存的虚拟环境:
- ${{ if eq(parameters.usePoetryCache, true) }}: - task: Cache@2 inputs: key: 'poetry | "$(Agent.OS)" | poetry.lock' path: $(venv) cacheHitVar: POETRY_CACHE_RESTORED - script: | poetry env use $(venv)/bin/python displayName: Associate cached virtual environment with Poetry condition: eq(variables.POETRY_CACHE_RESTORED, 'true') - 保持
poetry install的条件判断为eq(variables.POETRY_CACHE_RESTORED, 'false'),缓存命中时跳过安装。
方法2:调整虚拟环境配置时机
将Poetry虚拟环境配置步骤移到缓存步骤之前,确保缓存恢复时配置已生效:
- script: | poetry config virtualenvs.in-project true poetry config virtualenvs.path $(venv) displayName: Configure Poetry - ${{ if eq(parameters.usePoetryCache, true) }}: - task: Cache@2 inputs: key: 'poetry | "$(Agent.OS)" | poetry.lock' path: $(venv) cacheHitVar: POETRY_CACHE_RESTORED
方法3:缓存后验证环境可用性
在缓存恢复后添加验证步骤,确认虚拟环境可正常使用:
- script: | if [ -d $(venv) ]; then echo "Virtual environment exists at $(venv)" source $(venv)/bin/activate which coverage fi displayName: Verify cached virtual environment condition: eq(variables.POETRY_CACHE_RESTORED, 'true')
若which coverage能输出有效路径,说明环境可用,后续poetry run即可正常执行。
内容的提问来源于stack exchange,提问作者bitnahian
相关产品推荐
相关产品推荐

