GitLab父流水线部分Job失败时,子流水线无法获取工件求助
GitLab CI子流水线获取父流水线失败任务工件的解决方案
问题核心
父流水线中smoke-tests、sanity-tests、patient-api-tests等任务已配置artifacts: when: always,但子流水线的upload-patient-report任务通过needs:pipeline依赖这些父任务时,只要任意父任务失败,子任务就会因无法获取工件报错:
This job could not start because it could not retrieve the needed artifacts.
此外,通过GitLab API在本地CLI能正常下载工件,但CI环境中返回404。需要不使用needs关键字的解决方案。
根本原因
needs:pipeline的限制:GitLab跨流水线依赖时,默认要求依赖的任务必须成功才能获取工件,即使父任务配置了when: always生成工件,失败状态的任务仍会被needs判定为无法提供工件。- CI环境API调用问题:本地使用个人token有权限,但CI环境的
CI_JOB_TOKEN默认可能未开启API访问权限,且用分支名下载可能匹配到错误的commit(父流水线对应特定commit,而非分支最新)。
解决方案:通过GitLab API手动下载工件
步骤1:开启CI Job Token的API访问权限
进入项目设置→CI/CD→权限,勾选允许从CI作业访问API,确保CI_JOB_TOKEN能调用GitLab API获取工件。
步骤2:父流水线传递关键变量
修改父流水线的触发任务,直接传递父流水线的commit SHA,避免子流水线调用API获取:
patient-api-tests-trigger: stage: trigger jobs rules: - if: $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "push" when: never - if: $CI_PIPELINE_SOURCE == "web" when: always needs: ["patient-api-tests"] trigger: include: .trigger-ci.yml strategy: depend forward: yaml_variables: true pipeline_variables: true variables: PARENT_JOB_NAME: $CI_JOB_NAME PARENT_PIPELINE_ID: $CI_PIPELINE_ID PARENT_COMMIT_SHA: $CI_COMMIT_SHA # 新增:传递父流水线的commit SHA
步骤3:子流水线修改upload-patient-report任务
移除needs配置,添加手动下载工件的脚本逻辑:
upload-patient-report: extends: .upload-report stage: upload api report (always) rules: - if: $CI_PIPELINE_SOURCE == "schedule" when: never - if: $CI_PIPELINE_SOURCE == "parent_pipeline" && $PARENT_JOB_NAME == "patient-api-tests-trigger" when: always before_script: - echo "Parent Pipeline ID: $PARENT_PIPELINE_ID" - apt-get update && apt-get install -y curl jq unzip # 定义通用下载函数 - download_artifact() { local JOB_NAME=$1 echo "Downloading artifacts from job: $JOB_NAME" # 用CI_JOB_TOKEN认证,指定父流水线的commit SHA下载对应工件 curl --fail --location --header "PRIVATE-TOKEN: $CI_JOB_TOKEN" \ "https://gitlab.ru/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${PARENT_COMMIT_SHA}/download?job=${JOB_NAME}" \ -o "${JOB_NAME}_artifacts.zip" # 解压到临时目录并移动文件到当前工作区 unzip -q "${JOB_NAME}_artifacts.zip" -d "${JOB_NAME}_temp" mv "${JOB_NAME}_temp"/target* "./target_${JOB_NAME}" mv "${JOB_NAME}_temp"/mvn_log* ./ rm -rf "${JOB_NAME}_temp" "${JOB_NAME}_artifacts.zip" } # 下载所有需要的工件 - download_artifact "smoke-tests" - download_artifact "sanity-tests" - download_artifact "patient-api-tests"
关键细节说明
CI_JOB_TOKEN认证:CI环境自动生成的CI_JOB_TOKEN拥有当前项目的读取权限,无需手动配置个人token,避免安全风险。- 指定commit SHA下载:使用父流水线的
PARENT_COMMIT_SHA而非分支名,确保下载的是父流水线对应版本的工件,避免分支更新导致的404。 - 适配原有上传脚本:将每个任务的target目录重命名为
target_<job-name>,匹配原upload-report脚本中mv target_*/allure-results/*的逻辑。
替代方案:上传工件到共享存储
如果API方案不符合需求,可在父流水线的测试任务中,将artifacts上传到GitLab Package Registry或外部存储(如MinIO),子流水线从该存储下载工件。示例(上传到GitLab Generic Package):
# 父流水线测试任务新增上传步骤 .run-tests: # ... 原有配置 after_script: - curl --header "PRIVATE-TOKEN: $CI_JOB_TOKEN" \ --upload-file "${CI_PROJECT_NAME}-${CI_COMMIT_REF_SLUG}.zip" \ "https://gitlab.ru/api/v4/projects/${CI_PROJECT_ID}/packages/generic/${CI_PROJECT_NAME}/${CI_COMMIT_SHA}/${JOB_NAME}_artifacts.zip"
子流水线则通过API从Package Registry下载对应文件。
内容的提问来源于stack exchange,提问作者Zel Anastasia
相关产品推荐
相关产品推荐

