Skip to main content

NPM Release

The npm-release jobs are used to prepare and create GitLab releases. They download build artifacts, tag Docker images with release versions, and create GitLab releases.

Overview

The npm-release jobs include:

  • .prepare_job: Prepares the release by downloading artifacts, tagging Docker images, and exporting release variables
  • .release_job: Creates a GitLab release using the release-cli

Variables

The following variables can be configured:

VariableDescriptionDefaultRequired
CONTAINER_REGISTRY_IDContainer registry project ID4495833No
DOCKER_BUILD_IMAGEDocker image for Docker-in-Docker'docker:19.03.11'No
DOCKER_BUILD_SERVICEDocker-in-Docker service version'19.03.11-dind'No
NODE_IMAGENode.js image (not used in current jobs)'node:16.3.0-alpine'No
CI_TOKENGitLab CI token for API access''Yes

Variable Details

  • CONTAINER_REGISTRY_ID: Container registry project ID (used for registry operations)
  • DOCKER_BUILD_IMAGE: Docker image version for Docker-in-Docker service
  • DOCKER_BUILD_SERVICE: Docker-in-Docker service version
  • NODE_IMAGE: Node.js image (defined but not currently used in the jobs)
  • CI_TOKEN: GitLab CI token for downloading artifacts via API

GitLab CI/CD Variables

The jobs use the following built-in GitLab CI/CD variables:

  • CI_REGISTRY_USER: GitLab registry username
  • CI_REGISTRY_PASSWORD: GitLab registry password
  • CI_REGISTRY: GitLab container registry URL
  • CI_REGISTRY_IMAGE: The address of the container registry tied to the project
  • CI_PROJECT_ID: Project ID
  • CI_MERGE_REQUEST_SOURCE_BRANCH_NAME: Source branch name of the merge request
  • CI_COMMIT_SHA: Commit SHA for the release

Job Types

.prepare_job

Prepares the release by downloading build artifacts, extracting Docker image information, and tagging images with release versions.

Usage

variables:
CONTAINER_REGISTRY_ID: 4495833
DOCKER_BUILD_IMAGE: 'docker:19.03.11'
DOCKER_BUILD_SERVICE: '19.03.11-dind'
CI_TOKEN: ''

.prepare_job:
image: $DOCKER_BUILD_IMAGE
services:
- docker:$DOCKER_BUILD_SERVICE
variables:
REGISTRY_ID: $CONTAINER_REGISTRY_ID
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- apk update
- apk --no-cache add curl
script:
- |
BRANCH_NAME=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME/\//_}
VERSION=${BRANCH_NAME}
echo VERSION = $VERSION
echo "URL=https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/jobs/artifacts/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}/download?job=docker-build_job"
curl --location --output artifacts.zip --header "Private-Token: ${CI_TOKEN}" "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/jobs/artifacts/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}/download?job=docker-build_job"
unzip -o artifacts.zip
DOCKER_IMAGE=$(cat pipeline.env)
TAG=$(cat pipeline.env| awk -F "_" '{print $2}')
echo "releasing TAG = $TAG"

echo "pulling image: ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE}"
docker pull ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE}

echo "tagging image: ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE} ${CI_REGISTRY_IMAGE}:${TAG}"
docker tag ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE} ${CI_REGISTRY_IMAGE}:${TAG}

echo "pushing image: ${CI_REGISTRY_IMAGE}:${TAG}"
docker push ${CI_REGISTRY_IMAGE}:${TAG}

- echo "EXTRA_DESCRIPTION=RELEASE=v${TAG} | DATE=$(date +%Y-%m-%d)" >> variables.env
- echo "TAG=v${TAG}" >> variables.env
artifacts:
reports:
dotenv: variables.env

Job Details

Before Script:

  1. Docker login:

    docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  2. Install curl:

    apk update 
    apk --no-cache add curl

Script:

  1. Extract version from branch name:

    BRANCH_NAME=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME/\//_}
    VERSION=${BRANCH_NAME}
    • Replaces / with _ in branch name (e.g., release/1.0.0release_1.0.0)
  2. Download build artifacts:

    curl --location --output artifacts.zip \
    --header "Private-Token: ${CI_TOKEN}" \
    "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/jobs/artifacts/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}/download?job=docker-build_job"
    unzip -o artifacts.zip
    • Downloads artifacts from the docker-build_job in the source branch
    • Extracts the artifacts (should contain pipeline.env)
  3. Extract Docker image information:

    DOCKER_IMAGE=$(cat pipeline.env)
    TAG=$(cat pipeline.env| awk -F "_" '{print $2}')
    • Reads Docker image tag from pipeline.env
    • Extracts release tag (assumes format: {prefix}_{tag})
  4. Tag and push Docker image:

    docker pull ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE}
    docker tag ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE} ${CI_REGISTRY_IMAGE}:${TAG}
    docker push ${CI_REGISTRY_IMAGE}:${TAG}
    • Pulls the build image
    • Tags it with the release tag
    • Pushes the tagged image
  5. Generate release variables:

    echo "EXTRA_DESCRIPTION=RELEASE=v${TAG} | DATE=$(date +%Y-%m-%d)" >> variables.env
    echo "TAG=v${TAG}" >> variables.env

Artifacts:

Exports variables via dotenv artifact for use in subsequent jobs.

.release_job

Creates a GitLab release using the release-cli.

Usage

.release_job:
image: registry.gitlab.com/gitlab-org/release-cli:latest
script:
- echo "running release_job for $TAG"
release:
name: 'Release $TAG'
description: '$EXTRA_DESCRIPTION'
tag_name: '$TAG'
ref: '$CI_COMMIT_SHA'

Job Details

Image: Uses the official GitLab release-cli image

Script: Simple echo statement (the actual release is created via the release: block)

Release Configuration:

  • name: Release name (e.g., Release v1.0.0)
  • description: Release description with version and date
  • tag_name: Git tag name (e.g., v1.0.0)
  • ref: Commit SHA to tag

Complete Pipeline Example

variables:
CONTAINER_REGISTRY_ID: 4495833
DOCKER_BUILD_IMAGE: 'docker:19.03.11'
DOCKER_BUILD_SERVICE: '19.03.11-dind'
CI_TOKEN: '${CI_JOB_TOKEN}'

stages:
- build
- release

# Build job creates pipeline.env
docker-build_job:
stage: build
script:
- docker build -t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}_${CI_COMMIT_SHORT_SHA} .
- docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_NAME}_${CI_COMMIT_SHORT_SHA}
- echo "${CI_COMMIT_REF_NAME}_${CI_COMMIT_SHORT_SHA}" > pipeline.env
artifacts:
paths:
- pipeline.env
expire_in: 1 hour

.prepare_job:
image: $DOCKER_BUILD_IMAGE
services:
- docker:$DOCKER_BUILD_SERVICE
variables:
REGISTRY_ID: $CONTAINER_REGISTRY_ID
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- apk update
- apk --no-cache add curl
script:
- |
BRANCH_NAME=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME/\//_}
VERSION=${BRANCH_NAME}
echo VERSION = $VERSION
curl --location --output artifacts.zip --header "Private-Token: ${CI_TOKEN}" "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/jobs/artifacts/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}/download?job=docker-build_job"
unzip -o artifacts.zip
DOCKER_IMAGE=$(cat pipeline.env)
TAG=$(cat pipeline.env| awk -F "_" '{print $2}')
echo "releasing TAG = $TAG"

docker pull ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE}
docker tag ${CI_REGISTRY_IMAGE}:${DOCKER_IMAGE} ${CI_REGISTRY_IMAGE}:${TAG}
docker push ${CI_REGISTRY_IMAGE}:${TAG}

- echo "EXTRA_DESCRIPTION=RELEASE=v${TAG} | DATE=$(date +%Y-%m-%d)" >> variables.env
- echo "TAG=v${TAG}" >> variables.env
artifacts:
reports:
dotenv: variables.env
dependencies:
- docker-build_job

.release_job:
image: registry.gitlab.com/gitlab-org/release-cli:latest
script:
- echo "running release_job for $TAG"
release:
name: 'Release $TAG'
description: '$EXTRA_DESCRIPTION'
tag_name: '$TAG'
ref: '$CI_COMMIT_SHA'

prepare-release:
extends: .prepare_job
stage: release
only:
- merge_requests

create-release:
extends: .release_job
stage: release
dependencies:
- prepare-release
only:
- merge_requests

Workflow

The release process follows this workflow:

  1. Build Stage: Docker image is built and pipeline.env is created with image tag
  2. Prepare Stage:
    • Downloads artifacts from build job
    • Extracts Docker image tag from pipeline.env
    • Tags Docker image with release version
    • Pushes tagged image
    • Exports release variables
  3. Release Stage: Creates GitLab release with tag and description

Pipeline.env Format

The pipeline.env file should contain the Docker image tag in this format:

{prefix}_{tag}

Example:

release_1.0.0
main_abc12345

The tag extraction uses awk -F "_" '{print $2}' to get the second part after splitting by _.

Prerequisites

  • Docker Build Job: A job named docker-build_job must exist and create pipeline.env
  • Artifacts: The build job must create artifacts containing pipeline.env
  • GitLab Token: CI_TOKEN must have permissions to download artifacts
  • Docker Registry Access: Registry credentials must be configured
  • Docker-in-Docker: Runner must support Docker-in-Docker for image operations

Security Considerations

  • CI Token: Store CI_TOKEN as a masked CI/CD variable
  • Registry Credentials: Store CI_REGISTRY_USER and CI_REGISTRY_PASSWORD as masked variables
  • Token Permissions: Ensure the token has read access to artifacts
  • Image Tags: Release tags should follow semantic versioning

Notes

  • The job downloads artifacts from a specific job (docker-build_job) in the source branch
  • Docker image tagging creates a release tag from the build tag
  • The release tag format assumes pipeline.env contains {prefix}_{tag}
  • Variables are exported via dotenv artifact for the release job
  • The release job uses GitLab's official release-cli
  • The job should typically run on merge request pipelines
  • Branch names with / are converted to _ for version extraction
  • The release is created at the commit SHA, not at the branch tip