background

Continuous intégration of serverless project in Gitlab

JWaws
JWgitlab
JWcicd
JWserverless
JWlambda

Benefits of Continuous Integration

The key advantages of Continuous Integration (CI) include:

  • Increased Code Quality
  • Faster Development Cycle
  • Improved Collaboration
  • Visibility

There's no need to elaborate further on these well-known benefits. This project focuses on setting up a CI pipeline for a Serverless application, which automatically runs tests and reports code coverage within GitLab.

Project Creation

Comprehensive information about project creation can be found here in a dedicated post.

You now have a template.yml file in the sam-project folder.

This TypeScript project includes a basic example of a Lambda function tested using the Jest framework.

Running tests locally

Navigate to the hello-world folder and run the tests locally:

1cd hello-world 2npm i 3npm run test

This runs the test-handler.test.ts file, producing the following test report:

1 PASS tests/unit/test-handler.test.ts 2 Unit test for app handler 3 ✓ verifies successful response (3 ms) 4 5----------|---------|----------|---------|---------|------------------- 6File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 7----------|---------|----------|---------|---------|------------------- 8All files | 76.66 | 75 | 100 | 76.66 | 9 app.ts | 76.66 | 75 | 100 | 76.66 | 20-26 10----------|---------|----------|---------|---------|------------------- 11Test Suites: 1 passed, 1 total 12Tests: 1 passed, 1 total 13Snapshots: 0 total 14Time: 2.093 s

This report provides basic code coverage information, but we can extend it with a JUnit report.

JUnit reporting

To generate a JUnit report, we’ll use jest-junit, which converts test results to JUnit XML format. This will be crucial for GitLab CI later.

installation

1npm i jest-junit -D

Configuration

Update the jest.config.ts file to generate the JUnit report:

1export default { 2 transform: { 3 '^.+\\.ts?$': 'ts-jest', 4 }, 5 clearMocks: true, 6 collectCoverage: true, 7 coverageDirectory: 'coverage', 8 coverageProvider: 'v8', 9 testMatch: ['**/tests/unit/*.test.ts'], 10 coverageReporters: ['html', 'text', 'text-summary', 'cobertura'], 11 reporters: [ 12 'default', 13 [ 14 'jest-junit', 15 { 16 outputDirectory: 'junit', 17 outputName: 'jest-junit.xml', 18 }, 19 ], 20 ], 21};

Running

Re-run the tests and observe the newly generated coverage and junit folders:

1npm run test

In the coverage folder, you’ll find detailed information on the tested lines.

Cobertura coverage

The junit folder contains the jest-junit.xml file, structured like this:

1<?xml version="1.0" encoding="UTF-8"?> 2<testsuites name="jest tests" tests="1" failures="0" errors="0" time="1.117"> 3 <testsuite name="Unit test for app handler" errors="0" failures="0" skipped="0" timestamp="2024-10-09T15:29:17" time="1.061" tests="1"> 4 <testcase classname="Unit test for app handler verifies successful response" name="Unit test for app handler verifies successful response" time="0.004"> 5 </testcase> 6 </testsuite> 7</testsuites>

Running in GitLab CI

Now that we have local test coverage, we will integrate it with GitLab to automate Continuous Integration.

Configuration

Create a .gitlab-ci.yml file with the following content:

1 2stages: 3 - build 4 - test 5 6"Build": 7 image: public.ecr.aws/sam/build-nodejs18.x 8 stage: build 9 script: 10 - cd hello-world 11 - npm install 12 cache: 13 paths: 14 - hello-world/node_modules/ 15 only: 16 - main 17 artifacts: 18 expire_in: 1 days 19 when: on_success 20 paths: 21 - hello-world/node_modules/ 22 23"Test": 24 image: public.ecr.aws/sam/build-nodejs18.x 25 stage: test 26 only: 27 - merge_requests 28 - main 29 coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/ 30 dependencies: 31 - "Build" 32 script: 33 - node --version 34 - npm --version 35 - cd hello-world 36 - npm install 37 - npm run test 38 artifacts: 39 when: always 40 reports: 41 junit: 42 - hello-world/junit/jest-junit.xml 43 coverage_report: 44 coverage_format: cobertura 45 path: hello-world/coverage/cobertura-coverage.xml

This pipeline contains two stages:

  • Build: Installs dependencies.
  • Test: Runs tests, calculates coverage, and stores reports.

The coverage parameter of the Test job extracts code coverage from the job’s output using this regex pattern:

1coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/

Reporting

GitLab captures coverage data and displays it in various places (badges, pipelines, merge requests, statistics).

Code coverage job

JUnit test summaries are also stored and accessible through the GitLab pipeline interface.

Code test details

Badge

GitLab automatically generates a badge for code coverage, which can be displayed on the project’s homepage by updating the configuration project in General Settings > Badges.

Configure badge

Configure badge

Summary

In this tutorial, we implemented Continuous Integration for an AWS Serverless application. The code coverage indicator enhances code reviews by providing insights directly within GitLab merge requests.

WARNING: If you deploy this app to AWS, remember to clean up AWS resources

1sam delete

Comments