Gitlab CI/CD跨流水线传递工件与变量问题咨询:如何将BUILD_VERSION从合并请求流水线传递至合并后部署流水线
Hey there, I've tackled this exact scenario before—passing build variables from a merge request pipeline to a post-merge deployment pipeline in GitLab CI. Let's walk through tested, working solutions since your previous attempts hit GitLab's artifact scope limitations:
Solution 1: Write BUILD_VERSION to a repo file and push to the MR branch
The simplest approach is to commit your generated version number directly to a file in your merge request branch. Once the MR merges into staging, the deployment pipeline can read this file directly.
CI Config Example
First, update your building job to generate and commit the version:
staging: stage: staging rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' script: # Generate your BUILD_VERSION (customize this to your logic) - export BUILD_VERSION="v1.0.0-${CI_COMMIT_SHORT_SHA}-$(date +%Y%m%d%H%M)" - echo "$BUILD_VERSION" > VERSION # Configure Git for CI commits - git config --global user.name "GitLab CI Bot" - git config --global user.email "ci-bot@your-domain.com" # Commit and push the VERSION file to the MR source branch - git add VERSION - git commit -m "chore: record build version $BUILD_VERSION" - git push origin "${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}" artifacts: reports: dotenv: build.env paths: - VERSION
Then, in your deploying job, just read the file:
deploy: stage: deploy rules: - if: '$CI_COMMIT_BRANCH == $STAGING_BRANCH' script: - export BUILD_VERSION=$(cat VERSION) - echo "Starting deployment for version $BUILD_VERSION" # Add your deployment logic here (e.g., GitLab API calls)
Notes
- If you don't want the
VERSIONfile sticking around, add it to.gitignoreand usegit add -f VERSIONto force commit it. You can also delete it in the deploy job and push the change (just watch out for pipeline loops). - Make sure your CI runner has permission to push to the MR branch—check your project's Settings > Repository > Protected Branches to allow pushes from CI for your source branches.
Solution 2: Store BUILD_VERSION as a temporary project CI/CD variable via GitLab API
Use GitLab's API to create a temporary CI/CD variable in your project during the MR pipeline. The post-merge pipeline can then access this variable directly.
CI Config Example
First, create a Project Access Token in your project's Settings > Access Tokens with
apiandwrite_repositorypermissions. Add this token as a masked/protected CI variable namedPROJECT_ACCESS_TOKEN.Update your
buildingjob to set the variable:
staging: stage: staging rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' script: - export BUILD_VERSION="v1.0.0-${CI_COMMIT_SHORT_SHA}-$(date +%Y%m%d%H%M)" - echo "BUILD_VERSION=$BUILD_VERSION" > build.env # Create a temporary variable that expires in 1 day - curl --request POST \ --header "PRIVATE-TOKEN: $PROJECT_ACCESS_TOKEN" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/variables" \ --form "key=BUILD_VERSION" \ --form "value=$BUILD_VERSION" \ --form "protected=true" \ --form "environment_scope=*" \ --form "expires_at=$(date -d '+1 day' +%Y-%m-%d)" artifacts: reports: dotenv: build.env
- Use the variable in your
deployingjob (and optionally clean it up):
deploy: stage: deploy rules: - if: '$CI_COMMIT_BRANCH == $STAGING_BRANCH' script: - echo "Deploying version $BUILD_VERSION" # Your deployment logic here # Optional: Delete the temporary variable after deployment - curl --request DELETE \ --header "PRIVATE-TOKEN: $PROJECT_ACCESS_TOKEN" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/variables/BUILD_VERSION"
Notes
- The
expires_atparameter ensures old versions don't linger and cause conflicts in future pipelines. - Ensure the variable is marked as protected if your
stagingbranch is protected (matches GitLab's variable scope rules).
Solution 3: Create a Git Tag for the BUILD_VERSION
Generate a Git tag with your version number during the MR pipeline, then fetch that tag in the post-merge deployment pipeline.
CI Config Example
- Update the
buildingjob to create and push the tag:
staging: stage: staging rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' script: - export BUILD_VERSION="v1.0.0-${CI_COMMIT_SHORT_SHA}-$(date +%Y%m%d%H%M)" - echo "BUILD_VERSION=$BUILD_VERSION" > build.env # Configure Git for CI tagging - git config --global user.name "GitLab CI Bot" - git config --global user.email "ci-bot@your-domain.com" # Create and push the tag - git tag "$BUILD_VERSION" - git push origin "$BUILD_VERSION" artifacts: reports: dotenv: build.env
- Fetch the tag in your
deployingjob:
deploy: stage: deploy rules: - if: '$CI_COMMIT_BRANCH == $STAGING_BRANCH' script: # Fetch all tags to ensure we have the latest - git fetch --tags # Find the tag tied to the current merge commit (using the short SHA) - export BUILD_VERSION=$(git tag --list "*${CI_COMMIT_SHORT_SHA}*" | head -n 1) - echo "Deploying tagged version $BUILD_VERSION" # Your deployment logic here # Optional: Delete the temporary tag - git tag -d "$BUILD_VERSION" - git push origin :refs/tags/"$BUILD_VERSION"
Notes
- This works well if your version numbers are unique (the commit SHA ensures that). Adjust the tag pattern if you have a different versioning strategy.
- Make sure your CI runner has permission to create and push tags.
Why your previous attempts failed:
- dotenv/artifacts: GitLab artifacts are scoped to the specific pipeline that creates them. Post-merge pipelines are separate, so you can't directly pull artifacts from an MR pipeline unless you use cross-pipeline
needswith exact pipeline IDs (which isn't feasible here since you don't know the MR pipeline ID upfront). - API artifact download: MR pipelines run on a ref like
merge-requests/XXX/head, not the branch name. UsingCI_COMMIT_REF_NAMEin the post-merge pipeline won't find the MR pipeline's artifacts because that ref no longer exists after merging.
内容的提问来源于stack exchange,提问作者miile7

