doc/ci/examples/semantic-release.md
{{< details >}}
{{< /details >}}
This guide demonstrates how to automatically publish npm packages to the GitLab package registry by using semantic-release.
You can also view or fork the complete example source.
Open a terminal and go to the project's repository.
Run npm init. Name the module according to the package registry's naming conventions. For example, if the project's path is gitlab-examples/semantic-release-npm, name the module @gitlab-examples/semantic-release-npm.
Install the following npm packages:
npm install semantic-release @semantic-release/git @semantic-release/gitlab @semantic-release/npm --save-dev
Add the following properties to the module's package.json:
{
"scripts": {
"semantic-release": "semantic-release"
},
"publishConfig": {
"access": "public"
},
"files": [ <path(s) to files here> ]
}
Update the files key with glob patterns that selects all files that should be included in the published module. More information about files can be found in the npm documentation.
Add a .gitignore file to the project to avoid committing node_modules:
node_modules
Create a .gitlab-ci.yml with the following content:
default:
image: node:latest
before_script:
- npm ci --cache .npm --prefer-offline
- |
{
echo "@${CI_PROJECT_ROOT_NAMESPACE}:registry=${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/npm/"
echo "${CI_API_V4_URL#https?}/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=\${CI_JOB_TOKEN}"
} | tee -a .npmrc
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm/
workflow:
rules:
- if: $CI_COMMIT_BRANCH
variables:
NPM_TOKEN: ${CI_JOB_TOKEN}
stages:
- release
publish:
stage: release
script:
- npm run semantic-release
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
This example configures the pipeline with a single job, publish, which runs semantic-release. The semantic-release library publishes new versions of the npm package and creates new GitLab releases (if necessary).
The default before_script generates a temporary .npmrc that is used to authenticate to the package registry during the publish job.
As part of publishing a package, semantic-release increases the version number in package.json. For semantic-release to commit this change and push it back to GitLab, the pipeline requires a custom CI/CD variable named GITLAB_TOKEN. To create this variable:
GITLAB_TOKEN.semantic-release pulls its configuration information from a .releaserc.json file in the project. Create a .releaserc.json at the root of the repository:
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/gitlab",
"@semantic-release/npm",
[
"@semantic-release/git",
{
"assets": ["package.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
]
]
}
In the previous semantic-release configuration example, you can change the branch name to your project's default branch.
Test the pipeline by creating a commit with a message like:
fix: testing patch releases
Push the commit to the default branch. The pipeline should create a new release (v1.0.0) on the project's Releases page and publish a new version of the package to the project's Package registry page.
To create a minor release, use a commit message like:
feat: testing minor releases
Or, for a breaking change:
feat: testing major releases
BREAKING CHANGE: This is a breaking change.
More information about how commit messages are mapped to releases can be found in semantic-releases's documentation.
To use the published module, add an .npmrc file to the project that depends on the module. For example, to use the example project's module:
@gitlab-examples:registry=https://gitlab.com/api/v4/packages/npm/
Then, install the module:
npm install --save @gitlab-examples/semantic-release-npm
A Git tag deleted from the repository
can sometimes be recreated by semantic-release when GitLab runners use a cached
version of the repository. If the job runs on a runner with a cached repository that
still has the tag, semantic-release recreates the tag in the main repository.
To avoid this behavior, you can either:
GIT_STRATEGY: clone.git fetch --prune-tags command
in your CI/CD script.