GitLab CI template for semantic-release¶
This project implements a GitLab CI/CD template to automate your versioning and release management with semantic-release, supporting one or several of the following features:
- determine the next release version number,
- generate the changelog,
- commit any changed resource to the Git repository,
- create and push the Git tag,
- publish the packages (in GitLab or any other package repository of your choice),
- any additional custom behavior you are able to script, triggered on the release steps.
Usage¶
This template can be used both as a CI/CD component or using the legacy include:project
syntax.
Use as a CI/CD component¶
Add the following to your .gitlab-ci.yml
:
include:
# 1: include the component
- component: $CI_SERVER_FQDN/to-be-continuous/semantic-release/gitlab-ci-semrel@3.11.5
# 2: set/override component inputs
inputs:
changelog-enabled: true # ⚠ this is only an example
Use as a CI/CD template (legacy)¶
Add the following to your .gitlab-ci.yml
:
include:
# 1: include the template
- project: 'to-be-continuous/semantic-release'
ref: '3.11.5'
file: '/templates/gitlab-ci-semrel.yml'
variables:
# 2: set/override template variables
SEMREL_CHANGELOG_ENABLED: "true" # ⚠ this is only an example
Global configuration¶
The semantic-release template uses some global configuration used throughout all jobs.
Input / Variable | Description | Default value |
---|---|---|
image / SEMREL_IMAGE |
The Docker image used to run semantic-release | registry.hub.docker.com/library/node:lts-slim |
version / SEMREL_VERSION |
The semantic-release version to use | latest |
exec-version / SEMREL_EXEC_VERSION |
The @semantic-release/exec version to use | latest |
GITLAB_TOKEN |
A GitLab project access token or personal access token with api , read_repository and write repository scopes. This variable is mandatory and defined by semantic-release itself. |
none |
GIT_AUTHOR_EMAIL |
A Git author email address associated with the GITLAB_TOKEN bot user. This is defined by semantic-release itself, and required if the verify-user push rules enabled for the project |
none |
GIT_COMMITTER_EMAIL |
A Git committer email address associated with the GITLAB_TOKEN bot user. This is defined by semantic-release itself, and required if the verify-user push rules enabled for the project |
none |
config-dir / SEMREL_CONFIG_DIR |
directory containing your semantic-release configuration | . |
required-plugins-file / SEMREL_REQUIRED_PLUGINS_FILE |
An optional file for additional npm packages to install | semrel-required-plugins.txt |
Jobs will extract required plugin packages from discovered configuration. If your configuration needs additional packages, add them, one per line, to SEMREL_REQUIRED_PLUGINS_FILE
file. Each line must be a valid npm install
package argument.
Jobs¶
semantic-release
job¶
This job runs semantic-release
in ci
mode.
This template supports all semantic-release configuration files except for release.config.js
and custom CLI arguments.
If no configuration is found, the template will generate one with the following options:
debug
:true
if the$TRACE
variable is set,false
otherwisedryRun
:true
if the$SEMREL_DRY_RUN
variable is set,false
otherwisetagFormat
: see$SEMREL_TAG_FORMAT
variableplugins
:- @semantic-release/commit-analyzer
- @semantic-release/release-notes-generator
- @semantic-release/gitlab
- @semantic-release/git
- optional @semantic-release/changelog if
SEMREL_CHANGELOG_ENABLED
is set totrue
- optional @semantic-release/exec if any hook script is found (see hook scripts)
branches
:master
Variables¶
As specified in the previous chapter, these variables are only used to generated a .releaserc
when no configuration is found in the repository.
Input / Variable | Description | Default value |
---|---|---|
changelog-enabled / SEMREL_CHANGELOG_ENABLED |
Add the @semantic-release/changelog plugin which will commit a changelog file in the repository if set to true . |
none |
changelog-file / SEMREL_CHANGELOG_FILE |
changelogFile @semantic-release/changelog option. | none (use the plugin default value which is CHANGELOG.md ). |
changelog-title / SEMREL_CHANGELOG_TITLE |
changelogTitle @semantic-release/changelog option. You might want to use markdown format (for example # MyApp Changelog ). |
none |
dry-run / SEMREL_DRY_RUN |
Activate the dryRun semantic-release option if present. | none |
auto-release-enabled / SEMREL_AUTO_RELEASE_ENABLED |
When set to true the job start automatically. When not set (default), the job is manual. |
none |
branches-ref / SEMREL_BRANCHES_REF |
Regular expression pattern matching branches from which releases should happen (should match your semantic-release configuration) | /^(master|main)$/ |
tag-format / SEMREL_TAG_FORMAT |
tagFormat semantic-release option. don't forget to double the $ character so it is not interpreted by GitLab. |
$${version} |
hooks-dir / SEMREL_HOOKS_DIR |
Hook scripts folder. | . |
commit-message / SEMREL_COMMIT_MESSAGE |
Add a custom commit message based on semantic-release/git option. | none (uses semantic-release default commit message) |
release-disabled / SEMREL_RELEASE_DISABLED |
Disable this job. | none |
Hook scripts¶
The generated .releaserc
will include the @semantic-release/exec plugin if any of the following scripts is found in the $SEMREL_HOOKS_DIR
folder:
verify-conditions.sh¶
Parameters: none
verify-release.sh¶
Parameters:
- Last release version
- next release version
- next release type
prepare.sh¶
See exec prepareCmd.
Parameters:
- Last release version
- next release version
- next release type
publish.sh¶
See exec publishCmd.
Parameters:
- Last release version
- next release version
- release branch
- commits count
- current date
success.sh¶
See exec successCmd.
Parameters:
- Last release version
- next release version
fail.sh¶
See exec failcmd.
Parameters:
- Last release version
- next release version
Signing release commits with GPG¶
For an introduction on commit signing, see GitLab documentation.
To make semantic-release sign its commits, use the following variable.
Input / Variable | Description | Default value |
---|---|---|
SEMREL_GPG_SIGNKEY |
Path to the GPG signkey exported with gpg --armor --export-secret-key Declare as a masked project variable of File type. |
none |
semantic-release-info
job¶
This job (disabled by default) runs semantic-release
with dry-run
mode in .pre
stage to save the following variables as dotenv artifact making them available for the next pipeline stages:
SEMREL_INFO_LAST_VERSION
: latest released versionSEMREL_INFO_NEXT_VERSION
: next release version (based on actual commits and comments)SEMREL_INFO_NEXT_VERSION_TYPE
: next release type (major
|minor
|patch
)
SEMREL_INFO_NEXT_VERSION
and SEMREL_INFO_NEXT_VERSION_TYPE
wont be available when semantic-release commits analysis determine that no release will be performed.
This job can be enabled by defining the SEMREL_INFO_ON
variable:
prod
to enable on production branch only (main
ormaster
by default withPROD_REF
environment variable)branches-ref
to enable on branches associated withbranches-ref
component configuration orSEMREL_BRANCHES_REF
environment variable (main
ormaster
by default as it fallbacks onPROD_REF
environment variable).protected
to enable on protected referencesall
to enable on all Git references. Beware that this job requires theGITLAB_TOKEN
variable so you must unprotect it (this will make privilege escalation possible from developer to maintainer).
Semantic Release Commit Analyzer and Release Notes Configuration¶
Semantic Release determines the semantic version, major.minor.patch, with the use of @semantic-release/commit-analyzer
and @semantic-release/release-notes-generator
presets
. The default preset is angular
.
The default may lead to unexpected versioning or release notes, especially when not in an Angular project nor using the Angular standard.
The commit message parser may be changed by defining the commit-spec
/ SEMREL_COMMIT_SPEC
variable:
Input / Variable | Description | Default |
---|---|---|
commit-spec / SEMREL_COMMIT_SPEC |
commit specification preset (possible values: angular , codemirror , ember , eslint , express , jquery , jshint , conventionalcommits (cc short form supported)) |
angular |
Conventional Commit Specification
The preset
of conventionalcommits
(or cc
) is a good option for most users. The specification is well defined and documented and compatible with tools like Husky and commitlint. Semantic Release has plans to make conventionalcommits
the default in the future.
Commit Message Controls
The commit-spec
/ SEMREL_COMMIT_SPEC
value installs the parser requirement for Semantic Release only. Adherence to a specification with commit message controls is not provided. Angular and Conventional Commits are widely supported by commitlint and commitizen, though additional devDependencies
and configuration files may be required, please review the tooling documentation for more information.
Note on supporting Semantic Release versions
If the version of Semantic Release is pinned using SEMREL_VERSION
prior to v24, automated versioning via commit messaging may fail in unexpected ways. See conventional-changelog-conventionalcommits v8.0.0 breaks semantic release or consider upgrading the pinned version to v24 or better to restore behaviors.
Secrets management¶
Here are some advices about your secrets (variables marked with a ):
- Manage them as project or group CI/CD variables:
- In case a secret contains characters that prevent it from being masked,
simply define its value as the Base64 encoded value prefixed with
@b64@
: it will then be possible to mask it and the template will automatically decode it prior to using it. - Don't forget to escape special characters (ex:
$
->$$
). - You can also manage secrets using Vault variant
Using semantic-release with other to-be-continuous templates¶
The semantic-release template has been designed to interoperate gracefully with release-capable to-be-continuous templates.
Unfortunaltely, there isn't one single configuration that fits all needs. Instead, the semantic-release template configuration will have to be adapted to your case.
There are actually 2 questions that will determine the required configuration:
- which Delivery Mode are you using in your project?
- Application Deployment mode should trigger the release directly from your production branch (
main
ormaster
by default), - Software Distribution mode should trigger the release through a tag pipeline.
- Application Deployment mode should trigger the release directly from your production branch (
- does the release involve changing files in your repository (and therefore creating a Git commit)?
- that will be the case if you use plugins such as @semantic-release/changelog or semantic-release-replace
Case 1: Application Deployment mode¶
When using the Application Deployment delivery mode in your project, the release should be triggered directly from the production branch (main
or master
by default).
In that case you'll need to:
- enable the semantic-release info job,
this is the job that will provide next release information to the other template(s) - by setting
info-on
input /SEMREL_INFO_ON
variable toprod
(or any suitable non-empty value) - disable the semantic-release job,
the release will be handled by other template(s) directly from the production branch - by setting
release-disabled
input /SEMREL_RELEASE_DISABLED
variable totrue
- make sure the other template(s) provide a semantic-release integration to perform the release from the semantic-release info job.
Templates supporting it:
- Docker,
- Helm,
- Maven,
- Python,
- S2I.
Case 2: Software Distribution mode without any Git commit¶
This is the easiest case as nothing specific has to be done to address it:
- by default the semantic-release will analyse each commit on your production branch, and will possibly create a Git tag (but no Git commit) if it determined a release has to be performed,
- the Git tag will trigger a tag pipeline during which every to-be-continuous template will take care of publishing its versioned package (using the Git tag as the version) to an appropriate packages repository.
Case 3: Software Distribution mode with a Git commit¶
This case will occur if you configure semantic-release to modify one or several files in your Git repository (ex: pom.xml
, pyproject.toml
, CHANGELOG.md
, README.md
...)
In that case, when semantic-release determines a release is required, it will:
- modify the files,
- create a Git commit with the changes,
- create a Git tag with the next release version,
- push the commit + the tag.
Problem: by default, semantic-release creates a Git commit with comment chore(release): ${nextRelease.version} [skip ci]
.\
The [skip ci]
part is problematic as it prevents GitLab from triggering the tag pipeline, therefore preventing other to-be-continuous templates from publishing their versioned packages.
To fix this, you'll have to override the default semantic-release Git commit comment in order not to prevent the tag pipeline from being triggered. With this done:
- the semantic-release will analyse each commit on your production branch, and will possibly create a Git tag if it determined a release has to be performed,
- the Git tag will trigger a tag pipeline during which every to-be-continuous template will take care of publishing its versioned package (using the Git tag as the version) to an appropriate packages repository.
How to override the Git commit comment¶
In most cases it is recommended to use chore(release): ${nextRelease.version} [skip ci on prod]
as message template.\
the important part is [skip ci on prod]
that prevents GitLab from triggering the pipeline on your production branch only, but not the tag pipeline.
Using a configuration file¶
If you're configuring semantic-release with a configuration file in your repository, then the Git commit message has to be configured in the @semantic-release/git plugin section.
Here is a .releaserc.yaml
configuration example that auto-generates the changelog file, and also replaces the project version in the pyproject.toml
using the semantic-release-replace plugin:
plugins:
# GitLab support
- '@semantic-release/gitlab'
# analyses the Git commits
- '@semantic-release/commit-analyzer'
# generates the release note from the Git commit messages
- '@semantic-release/release-notes-generator'
# generates the CHANGELOG.md file
- '@semantic-release/changelog'
# emulates bumpversion (replaces 'version' in pyproject.toml)
- - semantic-release-replace-plugin
- replacements:
- files:
- pyproject.toml
from:
- ^version *= *"\d+\.\d+\.\d+"
to: 'version = "${nextRelease.version}"'
countMatches: true
# git commit/push modified files
- - '@semantic-release/git'
- assets:
- 'CHANGELOG.md'
- 'pyproject.toml'
# the commit MUST trigger a pipeline on tag (to perform publish jobs)
# can be skipped on prod branch
message: 'chore(release): ${nextRelease.version} [skip ci on prod]'
branches:
- main
- master
tagFormat: '${version}'
Using implicit configuration¶
If you're not configuring semantic-release with a configuration file (but using implicit configuration provided by the template), then the Git commit message can be configured with the commit-message
input / SEMREL_COMMIT_MESSAGE
variable:
variables:
# the '$' has to be doubled to prevent GitLab from expanding it as a variable
SEMREL_COMMIT_MESSAGE: 'chore(release): $${nextRelease.version} [skip ci on prod]'
Variants¶
The semantic-release template can be used in conjunction with template variants to cover specific cases.
Vault variant¶
This variant allows delegating your secrets management to a Vault server.
Configuration¶
In order to be able to communicate with the Vault server, the variant requires the additional configuration parameters:
Input / Variable | Description | Default value |
---|---|---|
TBC_VAULT_IMAGE |
The Vault Secrets Provider image to use (can be overridden) | registry.gitlab.com/to-be-continuous/tools/vault-secrets-provider:latest |
vault-base-url / VAULT_BASE_URL |
The Vault server base API url | none |
vault-oidc-aud / VAULT_OIDC_AUD |
The aud claim for the JWT |
$CI_SERVER_URL |
VAULT_ROLE_ID |
The AppRole RoleID | must be defined |
VAULT_SECRET_ID |
The AppRole SecretID | must be defined |
Usage¶
Then you may retrieve any of your secret(s) from Vault using the following syntax:
@url@http://vault-secrets-provider/api/secrets/{secret_path}?field={field}
With:
Parameter | Description |
---|---|
secret_path (path parameter) |
this is your secret location in the Vault server |
field (query parameter) |
parameter to access a single basic field from the secret JSON payload |
Example¶
include:
# main template
- component: $CI_SERVER_FQDN/to-be-continuous/semantic-release/gitlab-ci-semrel@3.11.5
# Vault variant
- component: $CI_SERVER_FQDN/to-be-continuous/semantic-release/gitlab-ci-semrel-vault@3.11.5
inputs:
vault-base-url: "https://vault.acme.host/v1"
# audience claim for JWT
vault-oidc-aud: "https://vault.acme.host"
variables:
# Secrets managed by Vault
GITLAB_TOKEN: "@url@http://vault-secrets-provider/api/secrets/b7ecb6ebabc231/semantic-release/token?field=group-access-token"
# $VAULT_ROLE_ID and $VAULT_SECRET_ID defined as a secret CI/CD variable