GitLab CI/CD is a powerful tool that can be used to automate the build, test, and deployment of software applications. With GitLab CI/CD, you can define a set of rules that govern how your application is built, tested, and deployed, and then let GitLab take care of the rest.
In this tutorial, we will be looking at a GitLab CI/CD pipeline configuration file and explaining what each section does.
Let's start by taking a look at the default
section:
default:
interruptible: true
image: node:lts-alpine
This section defines the default settings for the entire pipeline. In this case, we have set the interruptible flag to true, which means that the pipeline can be interrupted by a user or by another job. We have also set the image to node:lts-alpine, which means that each job in the pipeline will be run in a Docker container based on the node:lts-alpine image.
Next, we have the stages
section:
stages:
- dependencies
- quality
- assemble
- deploy
This section defines the stages that the pipeline will go through. Each stage represents a different step in the process of building, testing, and deploying the application. In this case, we have defined four stages: dependencies, quality, assemble, and deploy.
Now, let's look at the install
job:
install:
stage: dependencies
script:
# Install dependencies
- npm install --prefer-offline
cache:
key:
files:
- package.json
paths:
- node_modules
This job is part of the dependencies stage and is responsible for installing the application's dependencies. We use the npm command to install the dependencies and use the --prefer-offline flag to ensure that cached versions of dependencies are used if available. We also define a cache for the node_modules directory based on the package.json file.
Next, we have the lint
job:
lint:
stage: quality
needs: ["install"]
script:
- npm run lint
cache:
key:
files:
- package.json
paths:
- node_modules
policy: pull
This job is part of the quality stage and is responsible for running the application's linter. We define a dependency on the install job using the needs keyword. We use the npm run lint command to run the linter and define a cache for the node_modules directory based on the package.json file. We also set the cache policy to pull, which means that GitLab will attempt to pull the cache from a remote cache server before running the job.
Next, we have the test
job:
test:
stage: quality
needs: ["install"]
before_script:
# Download Chrome
- apk add chromium
- export CHROME_BIN=/usr/bin/chromium-browser
- export CHROME_PATH=/usr/lib/chromium/
# Download Firefox
- apk add firefox-esr
- export FIREFOX_BIN=/usr/bin/firefox
- export FIREFOX_PATH=/usr/lib/firefox/
# X Server
- apk add xvfb
- export DISPLAY=:99
- Xvfb :99 -screen 0 1024x768x24 > /dev/null
script:
- npm run test -- --browsers=Headless_Chrome --no-watch
This was the stage that was the most difficult to solve, this is responsible for running automated tests for the project. This stage has a before_script section where we download and configure web browsers (Chrome and Firefox) as well as an X Server for headless testing. The script section runs the automated tests using the npm run test command with the --browsers=Headless_Chrome --no-watch
options. The cache configuration is similar to the previous stages.
The config for the Headless browser is like
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
...
browsers: ["Chrome"],
customLaunchers: {
Headless_Chrome: {
base: "Chrome",
flags: ["--no-sandbox", "--disable-gpu"],
},
}
});
};
The assemble stage is responsible for building the project. It depends on the test and lint stages and has a script section that runs the npm run build command. The artifacts section specifies that the resulting dist directory should be stored as a build artifact. The cache configuration is similar to the previous stages.
Finally, we have the deploy stage, which is responsible for deploying the project. It depends on the assemble stage and has a variables section that sets the NODE_ENV environment variable to "production". The before_script section simply echoes the name of the environment that we're deploying to.
We also have two different deploy-* jobs that extend the deploy stage with specific configuration for different environments. These jobs are triggered manually and have a variables section that sets the NODE_ENV environment variable to "development" or "staging". The script section for each of these jobs echoes the name of the environment that we're deploying to and runs any additional deployment actions that are required.
Complete file
default:
interruptible: true
image: node:lts-alpine
stages:
- dependencies
- quality
- assemble
- deploy
install:
stage: dependencies
script:
# Install dependencies
- npm install --prefer-offline
cache:
key:
files:
- package.json
paths:
- node_modules
lint:
stage: quality
needs: ["install"]
script:
- npm run lint
cache:
key:
files:
- package.json
paths:
- node_modules
policy: pull
test:
stage: quality
needs: ["install"]
before_script:
# Download Chrome
- apk add chromium
- export CHROME_BIN=/usr/bin/chromium-browser
- export CHROME_PATH=/usr/lib/chromium/
# Download Firefox
- apk add firefox-esr
- export FIREFOX_BIN=/usr/bin/firefox
- export FIREFOX_PATH=/usr/lib/firefox/
# X Server
- apk add xvfb
- export DISPLAY=:99
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
script:
- npm run test -- --browsers=Headless_Chrome --no-watch
cache:
key:
files:
- package.json
paths:
- node_modules
policy: pull
assemble:
stage: assemble
needs: ["test", "lint"]
script:
- npm run build
artifacts:
paths:
- $CI_PROJECT_DIR/dist
cache:
key:
files:
- package.json
paths:
- node_modules
policy: pull
.deploy:
stage: deploy
variables:
NODE_ENV: production
needs: ["assemble"]
before_script:
- echo "Deploying to $CI_ENVIRONMENT_NAME"
deploy-dev:
extends: .deploy
variables:
NODE_ENV: development
script:
- echo "Deploying to $CI_ENVIRONMENT_NAME"
- echo "Making actions to deploy to dev"
- echo "Deployed to $CI_ENVIRONMENT_NAME"
deploy-staging:
extends: .deploy
rules:
- when: manual
allow_failure: true
variables:
NODE_ENV: staging
script:
- echo "Deploying to $CI_ENVIRONMENT_NAME"
- echo "Making actions to deploy to staging"
- echo "Deployed to $CI_ENVIRONMENT_NAME"
Overall, this CI/CD configuration is a solid foundation for building, testing, and deploying a Node.js project. The use of caching and artifacts can help speed up the build process, and the separation of stages allows for greater control over the entire pipeline.
Top comments (2)
For running unit tests, with the right container, the setup can be simplified to:
Where "test-ci" is defined in the package.json as the following script:
If you cache node_modules you should guarantee that every job will install it if not present, if you don't want that install every job you should use artifacts instead.
"Cache is here to speed up your job but it may not exist, so don't rely on it." about.gitlab.com/blog/2022/09/12/a...