GitLab CI can automatically build and publish releases from Git tags, transforming your tagging workflow into a streamlined release process.
Let’s see this in action. Imagine you’ve just tagged a new version of your software: v1.2.0. Your .gitlab-ci.yml file can be configured to detect this tag and trigger a specific job.
stages:
- build
- release
variables:
APP_VERSION: ${CI_COMMIT_TAG#v} # Removes 'v' prefix if present
build_app:
stage: build
script:
- echo "Building application version ${APP_VERSION}..."
- # Your build commands here (e.g., docker build, make, npm install)
- echo "Build complete."
only:
- tags # This job runs only for tags
publish_release:
stage: release
script:
- echo "Publishing release for tag ${CI_COMMIT_TAG}..."
- echo "Version: ${APP_VERSION}"
- # Commands to publish your release (e.g., push to Docker Hub, upload to S3, create GitHub release)
- echo "Release published successfully."
only:
- tags # This job runs only for tags
when: on_success # Only run if the 'build_app' job succeeds
In this example:
- The
build_appjob runs as part of thebuildstage. It usesonly: - tagsto ensure it only executes when a Git tag is pushed. TheAPP_VERSIONvariable is defined to automatically extract the version number from the tag, stripping a leadingvif it exists (e.g.,v1.2.0becomes1.2.0). - The
publish_releasejob, in thereleasestage, also runsonly: - tags. Thewhen: on_successclause ensures it only runs if the precedingbuild_appjob completed without errors. This job contains the logic for actually publishing your release artifacts.
The core problem this solves is manual release management. Without automation, you’d be pushing code, manually creating tags, then manually building artifacts, uploading them, and updating release notes. GitLab CI automates this entire sequence, reducing human error and saving significant time.
Internally, GitLab CI uses predefined CI/CD variables to provide context about the pipeline. CI_COMMIT_TAG is crucial here; it holds the name of the tag that triggered the pipeline. When you push a tag, GitLab recognizes it as a special type of commit and can be instructed to run specific jobs based on it. The only: - tags directive tells the CI system to filter jobs and only execute them when the pipeline is triggered by a tag push.
The APP_VERSION: ${CI_COMMIT_TAG#v} syntax is a shell parameter expansion. It takes the value of CI_COMMIT_TAG and removes the shortest match of v from the beginning of the string. This is incredibly useful for standardizing versioning in your build artifacts, regardless of whether you tag as v1.0.0 or 1.0.0.
The when: on_success keyword is powerful for creating sequential release steps. It guarantees that your release publishing logic only executes if the preceding build steps have successfully completed. This prevents partial or broken releases from being published.
A common misconception is that you need complex scripting to handle different tag patterns. However, GitLab’s predefined variables and simple shell expansions are often sufficient. For instance, if you consistently tag with semantic versioning (e.g., vMAJOR.MINOR.PATCH), you can easily extract these components. If you needed to publish to a specific registry based on the tag, you could use if [[ "${CI_COMMIT_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] within your script to conditionally execute publishing commands, targeting only valid version tags.
The next concept you’ll likely explore is using GitLab’s Release feature itself, where you can create official release objects directly within GitLab, often populated automatically by these CI jobs.