Hi everyone,
I’d like some advice on structuring build vs. promotion in GitLab CI/CD.
-
Current idea:
-
On Merge Request (MR) pipelines, I build and push a test container image.
-
The image is tagged with the MR branch name (e.g.,
feature/foo). -
This gives me a preview/test image for reviewers.
-
-
Promotion question:
-
When the MR is merged to
main, I’d like to promote the same container image (built during the MR pipeline) into my production repository, instead of rebuilding. -
However, once on
main, I’m not sure what’s the best way to reliably know which branch was merged, so I can pick the right test image to promote.
-
-
Current setup:
-
I use merge-commit with semi-linear history to avoid race conditions and ensure the promoted image includes all changes.
-
To check the branch that was merged, I currently run:
git log --merges -n 1 --pretty=format:"%s" | awk -F"'" '/Merge branch/{print $2}'
-
Questions:
-
Is tagging MR images with the branch name a good approach for this?
-
How do others solve the “promotion” problem when moving from MR → main?
-
Do you usually rebuild on
main, or reuse the MR-built image? -
Is there a recommended way in GitLab to track the branch/tag that got merged, so I can promote the correct image?
I’d love to hear how others are handling this.
Thanks!
Example of pipeline:
variables:
IMAGE_REGISTRY: registry.example.com
IMAGE_NAME: ${IMAGE_REGISTRY}/my-project/app
IMAGE_NAME_TEST: ${IMAGE_NAME}-test
IMAGE_TAG: ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}
stages:
- build-and-push
- test
- promote
# Rules
.rules:mr:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
.rules:main:
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
# Jobs
build-and-push:
stage: build-and-push
image: quay.io/buildah/stable:v1.41.4
extends: [.rules:mr]
script:
- echo "Building and pushing test image..."
- buildah bud -t ${IMAGE_NAME_TEST}:${IMAGE_TAG} .
- buildah push ${IMAGE_NAME_TEST}:${IMAGE_TAG}
test:
stage: test
extends: [.rules:mr]
image: ${IMAGE_NAME_TEST}:${IMAGE_TAG}
needs: [build-and-push]
script:
- echo "Run integration tests here"
- echo "Tests passed!"
promote:
stage: promote
image: registry.redhat.io/ubi9/skopeo:9.6
extends: [.rules:main]
variables:
IMAGE_TAG: latest
script:
- echo "Promoting image with skopeo..."
# Extract merged branch tag
- BRANCH_TAG=$(git log --merges -n 1 --pretty=format:"%s" | awk -F"'" '/Merge branch/{print $2}')
# Copy from test repo to prod repo
- skopeo copy docker://${IMAGE_NAME_TEST}:${BRANCH_TAG} docker://${IMAGE_NAME}:${IMAGE_TAG}
- echo "Promoted ${IMAGE_NAME_TEST}:${BRANCH_TAG} -> ${IMAGE_NAME}:${IMAGE_TAG}"
- skopeo delete docker://${IMAGE_NAME_TEST}:${BRANCH_TAG}