Problem to solve
I have a Node app that I would like to check/test in CI. I have 3 jobs split across 2 stages:
- One
prepare_images
stage that creates a Docker image that will be my CI environment to check/test my Node app - One
tests
stage that triggers 2 specific jobs:unit_tests
to trigger unit testing of my Node app andintegration_tests
to launch integration tests with other components
The CI image created consists of a debian image with additional packages + the npm packages of my Node app.
This idea is to generate the CI image only upon specific changes (see the changes
variable in gitlab-ci/yml below), so that I don’t have to re-install my dependencies if only the source code has changed for instance.
I would like to install my Node app’s dependencies globally in my CI image but I couldn’t achieve it.
So far, I’ve found a workaround which consists of making a symlink to the node_modules
generated into my Node project’s folder like using ln -s /usr/src/app/node_modules node_modules
.
I’m wondering if creating a CI image that will be used across multiple stages/jobs is a good practice in general ? Also, I’m wondering if there is a proper way to install npm dependencies globally in a docker image so that it can be used in further stages/jobs in the CI?
Configuration
This is the job that builds the CI image:
prepare:docker:api-node:
extends: [.prepare-common]
stage: prepare_images
variables:
IMAGE_NAME: api-node
rules:
- !reference [.prepare-common, rules]
- if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH
changes:
- package-lock.json
- api/package.json
- api/docker/ci/*
- api/scripts/install-deps.sh
This is the docker-compose used to build the CI image:
services:
api-node:
build:
# context is at root since package-lock.json is global to multiple npm workspaces (including api)
context: ../
dockerfile: ./api/docker/ci/Dockerfile
cache_from:
- $CI_REGISTRY_IMAGE/ci-images/api-node:latest
image: $CI_REGISTRY_IMAGE/ci-images/api-node:${BUILD_VERSION:-latest}
container_name: api-node
This is the Dockerfile I’m using to build the CI image:
FROM library/node:20.10-bookworm-slim
# Set working directory to install node modules
WORKDIR /usr/src/app
# Update lists of packages and install required dependencies
COPY ./api/scripts/install-deps.sh ./install-deps.sh
RUN ./install-deps.sh
# Copy list of production dependencies
COPY ["api/package.json", "package-lock.json", "./"]
# Clean install dependencies (production and development)
RUN npm ci
# Clean up installation files and cache
RUN rm install-deps.sh package.json package-lock.json && npm cache clean --force
And finally, this is the unit_tests
job of my Node app:
api:unit_tests:
image: ${DOCKER_API_NODE_IMAGE}
tags: [amd64-build]
stage: build_and_test
before_script:
- ln -s /usr/src/app/node_modules node_modules
script:
- npm run lint
- npm run test:unit:ci
- npm run build
coverage: '/Branches\s*: \d+(?:\.\d+)?/'
artifacts:
reports:
junit:
- api/coverage/junit.xml
coverage_report:
coverage_format: cobertura
path: api/coverage/cobertura-coverage.xml
paths:
- api/dist/*
Versions
Please select whether options apply, and add the version information.
- Self-managed
- GitLab.com SaaS
- Self-hosted Runners
Versions
- GitLab (Web:
/help
or self-managed system information): - GitLab Runner, if self-hosted (Web
/admin/runners
or CLIgitlab-runner --version
):