Skip to content
Snippets Groups Projects
README.md 14.1 KiB
Newer Older
Pierre Smeyers's avatar
Pierre Smeyers committed
# GitLab CI template for semantic-release

Pierre Smeyers's avatar
Pierre Smeyers committed
This project implements a GitLab CI/CD template to automate your versioning and release management with [semantic-release](https://github.com/semantic-release/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](https://docs.gitlab.com/ee/user/project/releases/index.html) or any other package repository of your choice),
* any additional custom behavior you are able to script, triggered on the [release steps](https://semantic-release.gitbook.io/semantic-release/#release-steps).

Pierre Smeyers's avatar
Pierre Smeyers committed
## Usage

This template can be used both as a [CI/CD component](https://docs.gitlab.com/ee/ci/components/#use-a-component-in-a-cicd-configuration) or using the legacy [`include:project`](https://docs.gitlab.com/ee/ci/yaml/index.html#includeproject) syntax.

### Use as a CI/CD component

Add the following to your `gitlab-ci.yml`:

```yaml
include:
  # 1: include the component
  - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel@3.8.3
    # 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`:
Pierre Smeyers's avatar
Pierre Smeyers committed

```yaml
include:
  # 1: include the template
Pierre Smeyers's avatar
Pierre Smeyers committed
  - project: 'to-be-continuous/semantic-release'
    ref: '3.8.3'
Pierre Smeyers's avatar
Pierre Smeyers committed
    file: '/templates/gitlab-ci-semrel.yml'

variables:
  # 2: set/override template variables
  SEMREL_CHANGELOG_ENABLED: "true" # ⚠ this is only an example
Pierre Smeyers's avatar
Pierre Smeyers committed
```

## Global configuration

The semantic-release template uses some global configuration used throughout all jobs.

| Input / Variable | Description                                   | Default value     |
Pierre Smeyers's avatar
Pierre Smeyers committed
| --------------------- | --------------------------------------------- | ----------------- |
| `image` / `SEMREL_IMAGE` | The Docker image used to run semantic-release | `registry.hub.docker.com/library/node:latest` |
| `version` / `SEMREL_VERSION` | The [semantic-release](https://www.npmjs.com/package/semantic-release) version to use | `latest` |
| `exec-version` / `SEMREL_EXEC_VERSION` | The [@semantic-release/exec](https://www.npmjs.com/package/@semantic-release/exec) version to use | `latest` |
| :lock: `GITLAB_TOKEN` | A GitLab [project access token](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) or [personal access token](https://docs.gitlab.com/ce/user/profile/personal_access_tokens.html) with `api`, `read_repository` and `write repository` scopes. :warning: This variable is **mandatory** and [defined by `semantic-release`](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#push-access-to-the-remote-repository) itself. | _none_ |
| :lock: `GIT_AUTHOR_EMAIL` | A Git author email address associated with the `GITLAB_TOKEN` [bot user](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html#bot-users-for-projects). This is [defined by `semantic-release`](https://semantic-release.gitbook.io/semantic-release/usage/configuration#git-environment-variables) itself, and **required if** the [verify-user push rules](https://docs.gitlab.com/ee/user/project/repository/push_rules.html#verify-users) enabled for the project | _none_ |
| :lock: `GIT_COMMITTER_EMAIL` | A Git committer email address associated with the `GITLAB_TOKEN` [bot user](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html#bot-users-for-projects). This is [defined by `semantic-release`](https://semantic-release.gitbook.io/semantic-release/usage/configuration#git-environment-variables) itself, and **required if** the [verify-user push rules](https://docs.gitlab.com/ee/user/project/repository/push_rules.html#verify-users) enabled for the project | _none_ |
| `config-dir` / `SEMREL_CONFIG_DIR` |  directory containing your [semantic-release configuration](https://semantic-release.gitbook.io/semantic-release/usage/configuration#configuration-file) | `.` |
| `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.
Pierre Smeyers's avatar
Pierre Smeyers committed

## Jobs

### `semantic-release` job

This job runs `semantic-release` in `ci` mode.

:warning: This template supports all [semantic-release configuration files](https://semantic-release.gitbook.io/semantic-release/usage/configuration#configuration-file) __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` otherwise
* `dryRun`: `true` if the `$SEMREL_DRY_RUN` variable is set, `false` otherwise
* `tagFormat`: see `$SEMREL_TAG_FORMAT` variable
* `plugins`:
    * [@semantic-release/commit-analyzer](https://github.com/semantic-release/commit-analyzer)
    * [@semantic-release/release-notes-generator](https://github.com/semantic-release/release-notes-generator)
    * [@semantic-release/gitlab](https://github.com/semantic-release/gitlab)
    * [@semantic-release/git](https://github.com/semantic-release/git)
    * optional [@semantic-release/changelog](https://github.com/semantic-release/changelog) if `SEMREL_CHANGELOG_ENABLED` is set to `true`
    * optional [@semantic-release/exec](https://github.com/semantic-release/exec) if any hook script is found (see [hook scripts](#hook_scripts))
Pierre Smeyers's avatar
Pierre Smeyers committed
* `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 |
Pierre Smeyers's avatar
Pierre Smeyers committed
| ------------------------------| ------------------------------------------------------ | ------------- |
| `changelog-enabled` / `SEMREL_CHANGELOG_ENABLED` | Add the [@semantic-release/changelog](https://github.com/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](https://github.com/semantic-release/changelog#options). | _none_ (use the plugin default value which is `CHANGELOG.md`). |
| `changelog-title` / `SEMREL_CHANGELOG_TITLE` | [changelogTitle @semantic-release/changelog option](https://github.com/semantic-release/changelog#options). You might want to use markdown format (for example `# MyApp Changelog`). | _none_ |
| `dry-run` / `SEMREL_DRY_RUN` | Activate the [dryRun semantic-release option](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#dryrun) 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_ |
| `tag-format` / `SEMREL_TAG_FORMAT` | [tagFormat semantic-release option](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#tagformat). :warning: don't forget to double the `$` character so it is not interpreted by GitLab.                   | `$${version}` |
| `hooks-dir` / `SEMREL_HOOKS_DIR` | [Hook scripts](#hook_scripts) folder. | `.` |
| `commit-message` / `SEMREL_COMMIT_MESSAGE` | Add a custom commit message based on [semantic-release/git option](https://github.com/semantic-release/git#message). | _none_ (uses semantic-release default commit message) |
| `release-disabled` / `SEMREL_RELEASE_DISABLED` | Disable this job. | _none_ |
Pierre Smeyers's avatar
Pierre Smeyers committed

#### Hook scripts

The generated `.releaserc` will include the [@semantic-release/exec](https://github.com/semantic-release/exec) plugin if any of the following scripts is found in the `$SEMREL_HOOKS_DIR` folder:

##### verify-conditions.sh

See [exec verifyConditionsCmd](https://github.com/semantic-release/exec#verifyconditionscmd).

Parameters: _none_

##### verify-release.sh

See [exec verifyReleaseCmd](https://github.com/semantic-release/exec#verifyreleasecmd).

Parameters:

1. Last release version
2. next release version
3. next release type

##### prepare.sh

See [exec prepareCmd](https://github.com/semantic-release/exec#preparecmd).

Parameters:

1. Last release version
2. next release version
3. next release type

##### publish.sh

See [exec publishCmd](https://github.com/semantic-release/exec#publishcmd).

Parameters:

1. Last release version
2. next release version
3. release branch
4. commits count
5. current date

##### success.sh

See [exec successCmd](https://github.com/semantic-release/exec#successcmd).

Parameters:

1. Last release version
2. next release version

##### fail.sh

See [exec failcmd](https://github.com/semantic-release/exec#failcmd).

Parameters:

1. Last release version
2. next release version

#### Signing release commits with GPG

For an introduction on commit signing, see [GitLab documentation](https://docs.gitlab.com/ee/user/project/repository/gpg_signed_commits/).

To make semantic-release sign its commits, use the following variable.

| Input / Variable | Description                                                              | Default value |
| ---------------------| ------------------------------------------------------------------------ | ------------- |
| :lock: `SEMREL_GPG_SIGNKEY` | Path to the GPG signkey exported with `gpg --armor --export-secret-key`<br/>:warning: Declare as a masked [project variable of File type](https://docs.gitlab.com/ee/ci/variables/#cicd-variable-types). | _none_        |

Pierre Smeyers's avatar
Pierre Smeyers committed
### `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](https://docs.gitlab.com/ee/ci/pipelines/job_artifacts.html#artifactsreportsdotenv) making them available for the next pipeline stages:

* `SEMREL_INFO_LAST_VERSION`: latest released version
* `SEMREL_INFO_NEXT_VERSION`: next release version (based on actual commits and comments)
* `SEMREL_INFO_NEXT_VERSION_TYPE`: next release type (`major`|`minor`|`patch`)

:warning: `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` or `master` by default)
Pierre Smeyers's avatar
Pierre Smeyers committed
* `protected` to enable on protected references
* `all` to enable on all Git references. :warning: Beware that this job requires the `GITLAB_TOKEN` variable so you must unprotect it (this will make privilege escalation possible from developer to maintainer).

## Secrets management

Here are some advices about your **secrets** (variables marked with a :lock:):

Pierre Smeyers's avatar
Pierre Smeyers committed
1. Manage them as [project or group CI/CD variables](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project):
    * [**masked**](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable) to prevent them from being inadvertently
Pierre Smeyers's avatar
Pierre Smeyers committed
      displayed in your job logs,
Pierre Smeyers's avatar
Pierre Smeyers committed
    * [**protected**](https://docs.gitlab.com/ee/ci/variables/#protected-cicd-variables) if you want to secure some secrets
Pierre Smeyers's avatar
Pierre Smeyers committed
      you don't want everyone in the project to have access to (for instance production secrets).
Pierre Smeyers's avatar
Pierre Smeyers committed
2. In case a secret contains [characters that prevent it from being masked](https://docs.gitlab.com/ee/ci/variables/#mask-a-cicd-variable),
Pierre Smeyers's avatar
Pierre Smeyers committed
  simply define its value as the [Base64](https://en.wikipedia.org/wiki/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.
3. Don't forget to escape special characters (ex: `$` -> `$$`).
4. You can also manage secrets using Vault variant

## Variants

The Docker 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](https://www.vaultproject.io/) 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](https://gitlab.com/to-be-continuous/tools/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` |
| :lock: `VAULT_ROLE_ID`   | The [AppRole](https://www.vaultproject.io/docs/auth/approle) RoleID | **must be defined** |
| :lock: `VAULT_SECRET_ID` | The [AppRole](https://www.vaultproject.io/docs/auth/approle) SecretID | **must be defined** |

#### Usage

Then you may retrieve any of your secret(s) from Vault using the following syntax:

```text
@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

```yaml
include:
  # main template
  - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel@3.8.3
  # Vault variant
  - component: gitlab.com/to-be-continuous/semantic-release/gitlab-ci-semrel-vault@3.8.3
    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