GitLab offers a private NPM registry for each project with the GitLab Packages feature.

We will see in this article how to use it to publish modules then how to automate the releases and the changelog generation on a project.

Requirements

You will need an existing NPM module project.

First step : package.json update

Add a main entry in the package.json to declare the module entry point.

"main": "src/index.js"

Then, add a publishConfig object.

"publishConfig": {
  "access": "public"
}

⚠️ Important : You can also need to update the project name if the scope (GitLab group) is missing.

Why ? GitLab Packages use the project GitLab group as NPM scope.

Example :

The project module ziggornif/awesome-project project will be declared as @ziggornif/awesome-package

Your project is now well configured to be published in the GitLab NPM project registry.

Configure CI

Now, we can set up a CI pipeline which will publish the module versions.

In this example, we will create only one release stage that will be triggered on the main branch.

Create a .gitlab-ci.yml file in the project.

default:
  image: node:16
  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 --append .npmrc      
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - .npm/

workflow:
  rules:
    - if: $CI_COMMIT_BRANCH

stages:
  - release

publish:
  stage: release
  script:
    - npm publish
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Explanations :

  • The default part install node modules from cache (if exists) and setup .npmrc file to publish module
  • The publish job declared on the release stage run the publish module action
  • The pipeline is only triggered on main branch commits.

Let’s publish a version !

With this configuration, every commit on the main branch will trigger a pipeline like the following :

pipeline

We can see that the publish job works well. The version is published in the GitLab project package registry.

publish

Retrieve published versions in GitLab

Now, go to the package registry page (left side bar).

package-menu

You should now have a new entry in the package page.

package-page

If you click on the version entry, you will retrieve the build informations and the registry setup to use the module in your projects.

version-details

Releases and Changelog automation with semantic-release

Our project can now publish its versions to the GitLab package registry, but we still need to set the version by hand.

Let’s automate this with the semantic-release module.

Reminder on conventional commits and semantic versioning

The semantic-release module automates the package releases and apply semantic versioning based on conventional commits.

The semantic versioning (SemVer) rules permit to define the next software version.

  • A fix will be a patch version 0.0.x
  • A feature will be a minor version 0.x.0
  • A breaking change will be a major version x.0.0

Conventional commits specification permit to associate a commit type to a semantic versioning rule.

  • fix: commit will produce a patch version
  • feat: commit will produce a minor version
  • BREAKING CHANGE: commit will produce a major version

Install semantic-release and dependencies

Run the following command to add semantic-release dependencies :

npm install semantic-release @semantic-release/git @semantic-release/gitlab \
@semantic-release/npm @semantic-release/changelog --save-dev

Theses dependencies are needed to configure semantic-release with Gitlab and generate the changelog file.

Configuration

Create a .releaserc in the project with the following content :

{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    [
      "@semantic-release/changelog",
      {
        "changelogFile": "CHANGELOG.md"
      }
    ],
    "@semantic-release/gitlab",
    "@semantic-release/npm",
    [
      "@semantic-release/git",
      {
        "assets": ["package.json", "CHANGELOG.md"],
        "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ]
  ]
}

Update package.json

In the package.json file, add a semantic-release script :

"scripts": {
  "semantic-release": "semantic-release"
}

Update CI Pipeline

In the .gitlab-ci.yml add a NPM_TOKEN variable.

variables:
  NPM_TOKEN: ${CI_JOB_TOKEN}

Then, update the publish job command.

script:
-    - npm publish
+    - npm run semantic-release

Setup CI/CD variables

Create a personal access token with API scope from your profile page (see GitLab documentation : https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html).

Go to Settings -> CI/CD pages to define a private variable.

ci-cd-variables

In the Variables section, create a variable named GITLAB_TOKEN with the previous generated token.

add-variable

updated-variables

This variable will be used by the semantic-release module.

Release time !

Add a feat commit on the project and let the magic happens.

We can the that the semantic-release module pushed a release commit and a new tag.

pipeline-view

The generated tag contains the version changelog.

generated-tag

And the CHANGELOG.md file has also been updated with the version content.

changelog-file

Thats it !!! πŸ“¦ πŸš€

Project example

You can retrieve and fork the complete project here : https://gitlab.com/ziggornif/awesome-package

Useful resources

GitLab documentation :

Semantic release project : https://github.com/semantic-release/semantic-release

Changelog module : https://github.com/semantic-release/changelog

Semantic versioning : https://semver.org/

Conventional commits : https://www.conventionalcommits.org/en/v1.0.0/