Skip to content

Latest commit

 

History

History
652 lines (545 loc) · 60.3 KB

continuous-integration.md

File metadata and controls

652 lines (545 loc) · 60.3 KB

GitHub Reusable Workflow: Node.js Continuous Integration

Node.js Continuous Integration

Release License Stars PRs Welcome GitHub Verified Creator

Overview

Workflow to performs continuous integration steps against a Node.js project:

  • CodeQL analysis
  • Linting
  • Build
  • Test

Permissions

  • contents: read
  • id-token: write
  • packages: read
  • pull-requests: write
  • security-events: write

Usage

name: Node.js Continuous Integration
on:
  push:
    branches:
      - main
permissions: {}
jobs:
  continuous-integration:
    uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@31cd29bfb95f6bc6490d6abe5d66690431b518e3 # 2.0.0
    permissions:
      contents: read
      id-token: write
      packages: read
      pull-requests: write
      security-events: write
    secrets:
      # Secrets to be used during the build step.
      # Must be a multi-line env formatted string.
      # Example:
      # ```txt
      # SECRET_EXAMPLE=$\{{ secrets.SECRET_EXAMPLE }}
      # ```
      build-secrets: ""

      # Password for container registry authentication, if required.
      # Used when the container image is hosted in a private registry.
      # See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container#defining-credentials-for-a-container-registry.
      container-password: ""

      # GitHub token to use for authentication.
      # Defaults to `GITHUB_TOKEN` if not provided.
      github-token: ""
    with:
      # Disable project and dependency lifecycle scripts during installation in build, lint and test jobs.
      # Set false to allow installation hooks, subject to the package manager's script approval settings.
      # Explicit commands are unaffected. Does not apply in container mode, which skips installation.
      #
      # Default: `true`
      ignore-scripts: true

      # JSON array of runner(s) to use.
      # See https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job.
      #
      # Default: `["ubuntu-latest"]`
      runs-on: '["ubuntu-latest"]'

      # Build parameters. Must be a string or a JSON object.
      # For string, provide a list of commands to run during the build step, one per line.
      # For JSON object, provide the following properties:
      #
      # - `commands`: Array of commands to run during the build step.
      # - `env`: Object of environment variables to set during the build step.
      # - `artifact`: String or array of strings specifying paths to artifacts to upload after the build
      #
      # Example:
      # ```json
      # {
      # "commands": [
      # "build",
      # "generate-artifacts"
      # ],
      # "env": {
      # "CUSTOM_ENV_VAR": "value"
      # },
      # "artifact": [
      # "dist/",
      # "packages/package-a/build/"
      # ]
      # }
      # ```
      #
      # Default: `build`
      build: build

      # Create and validate public npm packages from the checked-out source and build output.
      # Pass "false" (the default) to disable, "true" for automatic package discovery and default checks,
      # or a JSON object to enable packaging with specific options. Quote booleans because this input has type string.
      #
      # - `directories`: Optional array of public package directories relative to working-directory. Omit to discover workspaces or the standalone root package. Private packages are excluded.
      # - `tests`: Optional shell commands after default manifest and entry-point checks. Runs in an isolated npm consumer with lifecycle scripts disabled and installed binaries on PATH.
      # - `test-project`: Optional consumer fixture directory relative to working-directory. Its dependencies and scripts are copied without node_modules or Git metadata. Requires `tests`.
      #
      # PACKAGE_INSTALL_PATH, PACKAGE_TARBALL_PATH, PACKAGE_NAME and PACKAGE_VERSION identify the tested package.
      # The consumer is cleaned up on success or failure. Commands must not modify the tarball.
      # Requires non-container CI with the default Ubuntu artifact layout.
      # Unknown options and invalid field types are rejected before build or packaging.
      #
      # Example: `{"tests":"my-cli --help"}`
      #
      # Default: `false`
      package: "false"

      # Optional flag to enable check steps.
      # Default: `true`
      checks: true

      # Whether to enable linting.
      # Set to `null` or empty to disable.
      # Accepts a JSON object for lint options. See [lint action](../../actions/lint/README.md).
      # It should generate lint reports in standard formats.
      #
      # Example:
      #
      # ```json:package.json
      # {
      # "lint:ci": "eslint . --output-file eslint-report.json --format json"
      # }
      # ```
      #
      # Default: `true`
      lint: "true"

      # CodeQL analysis language, or a JSON object with `languages` and optional `config-file`.
      # Set to an empty string to disable CodeQL.
      # In JSON form, `languages` must be a nonempty string and `config-file` must be a string.
      # Omitting or leaving `config-file` empty keeps CodeQL's default configuration behavior.
      # Unknown JSON properties and invalid field types fail before CodeQL initialization.
      # Local configuration paths are relative to the caller repository root, not `working-directory`.
      # See https://github.com/github/codeql-action.
      #
      # Example:
      # ```json
      # {
      # "languages": "javascript-typescript",
      # "config-file": ".github/codeql/config.yml"
      # }
      # ```
      #
      # Default: `typescript`
      code-ql: typescript

      # Enable dependency review scan.
      # Works with public repositories and private repositories with a GitHub Advanced Security license.
      # See https://github.com/actions/dependency-review-action.
      #
      # Default: `true`
      dependency-review: true

      # Whether to enable testing.
      # Set to `null` or empty to disable.
      # Accepts a JSON object for test options. See [test action](../../actions/test/README.md).
      # If coverage is enabled, it should generate test and coverage reports in standard formats.
      #
      # Example:
      #
      # ```json:package.json
      # {
      # "test:ci": "vitest run --reporter=default --reporter=junit --outputFile=junit.xml --coverage.enabled --coverage.reporter=lcov --coverage.reporter=text"
      # }
      # ```
      #
      # Default: `true`
      test: "true"

      # Working directory where the dependencies are installed.
      # Default: `.`
      working-directory: .

      # Container configuration to run CI steps in.
      # Accepts either a string (container image name) or a JSON object with container options.
      #
      # String format (simple):
      #
      # ```yml
      # container: "node:18"
      # ```
      #
      # JSON object format (advanced):
      #
      # ```json
      # {
      # "image": "node:18",
      # "env": {
      # "NODE_ENV": "production"
      # },
      # "options": "--cpus 2",
      # "ports": [8080, 3000],
      # "volumes": ["/tmp:/tmp", "/cache:/cache"],
      # "credentials": {
      # "username": "myusername"
      # },
      # "pathMapping": {
      # "/app": "./relative/path/to/app"
      # }
      # }
      # ```
      #
      # Supported properties:
      #
      # - `image` (required)
      # - `env` (object)
      # - `options` (string)
      # - `ports` (array)
      # - `volumes` (array)
      # - `credentials` (object with `username`).
      # - `pathMapping` (object) path mapping from container paths to repository paths. Defaults is working directory is mapped with repository root.
      #
      # See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container.
      #
      # When specified, steps will execute inside this container instead of checking out code.
      # The container should have the project code and dependencies pre-installed.
      container: ""

Inputs

Workflow Call Inputs

Input Description Required Type Default
ignore-scripts Disable project and dependency lifecycle scripts during installation in build, lint and test jobs. false boolean true
Set false to allow installation hooks, subject to the package manager's script approval settings.
Explicit commands are unaffected. Does not apply in container mode, which skips installation.
runs-on JSON array of runner(s) to use. false string ["ubuntu-latest"]
See https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job.
build Build parameters. Must be a string or a JSON object. false string build
For string, provide a list of commands to run during the build step, one per line.
For JSON object, provide the following properties:
- commands: Array of commands to run during the build step.
- env: Object of environment variables to set during the build step.
- artifact: String or array of strings specifying paths to artifacts to upload after the build
Example:
{
 "commands": [
 "build",
 "generate-artifacts"
 ],
 "env": {
 "CUSTOM_ENV_VAR": "value"
 },
 "artifact": [
 "dist/",
 "packages/package-a/build/"
 ]
}
package Create and validate public npm packages from the checked-out source and build output. false string false
Pass "false" (the default) to disable, "true" for automatic package discovery and default checks,
or a JSON object to enable packaging with specific options. Quote booleans because this input has type string.
- directories: Optional array of public package directories relative to working-directory. Omit to discover workspaces or the standalone root package. Private packages are excluded.
- tests: Optional shell commands after default manifest and entry-point checks. Runs in an isolated npm consumer with lifecycle scripts disabled and installed binaries on PATH.
- test-project: Optional consumer fixture directory relative to working-directory. Its dependencies and scripts are copied without node_modules or Git metadata. Requires tests.
PACKAGE_INSTALL_PATH, PACKAGE_TARBALL_PATH, PACKAGE_NAME and PACKAGE_VERSION identify the tested package.
The consumer is cleaned up on success or failure. Commands must not modify the tarball.
Requires non-container CI with the default Ubuntu artifact layout.
Unknown options and invalid field types are rejected before build or packaging.
Example: {"tests":"my-cli --help"}
checks Optional flag to enable check steps. false boolean true
lint Whether to enable linting. false string true
Set to null or empty to disable.
Accepts a JSON object for lint options. See lint action.
It should generate lint reports in standard formats.
Example:
{
 "lint:ci": "eslint . --output-file eslint-report.json --format json"
}
code-ql CodeQL analysis language, or a JSON object with languages and optional config-file. false string typescript
Set to an empty string to disable CodeQL.
In JSON form, languages must be a nonempty string and config-file must be a string.
Omitting or leaving config-file empty keeps CodeQL's default configuration behavior.
Unknown JSON properties and invalid field types fail before CodeQL initialization.
Local configuration paths are relative to the caller repository root, not working-directory.
See https://github.com/github/codeql-action.
Example:
{
 "languages": "javascript-typescript",
 "config-file": ".github/codeql/config.yml"
}
dependency-review Enable dependency review scan. false boolean true
Works with public repositories and private repositories with a GitHub Advanced Security license.
See https://github.com/actions/dependency-review-action.
test Whether to enable testing. false string true
Set to null or empty to disable.
Accepts a JSON object for test options. See test action.
If coverage is enabled, it should generate test and coverage reports in standard formats.
Example:
{
 "test:ci": "vitest run --reporter=default --reporter=junit --outputFile=junit.xml --coverage.enabled --coverage.reporter=lcov --coverage.reporter=text"
}
working-directory Working directory where the dependencies are installed. false string .
container Container configuration to run CI steps in. false string -
Accepts either a string (container image name) or a JSON object with container options.
String format (simple):
container: "node:18"
JSON object format (advanced):
{
 "image": "node:18",
 "env": {
 "NODE_ENV": "production"
 },
 "options": "--cpus 2",
 "ports": [8080, 3000],
 "volumes": ["/tmp:/tmp", "/cache:/cache"],
 "credentials": {
 "username": "myusername"
 },
 "pathMapping": {
 "/app": "./relative/path/to/app"
 }
}
Supported properties:
- image (required)
- env (object)
- options (string)
- ports (array)
- volumes (array)
- credentials (object with username).
- pathMapping (object) path mapping from container paths to repository paths. Defaults is working directory is mapped with repository root.
See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container.
When specified, steps will execute inside this container instead of checking out code.
The container should have the project code and dependencies pre-installed.

Container Configuration

The container input accepts either:

Simple string format (image name only):

container: "node:18"

Advanced JSON format (with container options):

container: |
  {
    "image": "node:18",
    "env": {
      "NODE_ENV": "production"
    },
    "options": "--cpus 2",
    "ports": [8080, 3000],
    "volumes": ["/tmp:/tmp", "/cache:/cache"],
    "credentials": {
      "username": "myusername"
    }
  }

Supported properties:

  • image (string, required) - Container image name
  • env (object) - Environment variables
  • options (string) - Additional Docker options
  • ports (array) - Port mappings
  • volumes (array) - Volume mounts
  • credentials (object) - Registry credentials with username property

Container Registry Credentials

For private container images, specify the username in the container input's credentials.username property and pass the password via the container-password secret:

jobs:
  continuous-integration:
    uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@81a4bca8445b7b273455ff26a9a5c3c31c86b2a1 # 0.25.0
    secrets:
      container-password: ${{ secrets.REGISTRY_PASSWORD }}
    with:
      container: |
        {
          "image": "ghcr.io/myorg/my-private-image:latest",
          "credentials": {
            "username": "myusername"
          }
        }

See GitHub's container specification for more details.

When specified, steps will execute inside this container instead of checking out code. The container should have the project code and dependencies pre-installed.

Secrets

Secret Description Required
build-secrets Secrets to be used during the build step. false
Must be a multi-line env formatted string.
Example:
SECRET_EXAMPLE=${{ secrets.SECRET_EXAMPLE }}
container-password Password for container registry authentication, if required. false
Used when the container image is hosted in a private registry.
See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container#defining-credentials-for-a-container-registry.
github-token GitHub token to use for authentication. false
Defaults to GITHUB_TOKEN if not provided.

Outputs

Output Description
package-tarball-artifact-id Artifact ID of the package validated by the packaging job. Available when package is enabled and validation succeeds.
package-tarball-artifacts JSON object mapping package directories to validated tarball artifact IDs when packaging is enabled. Require successful CI before publication.
build-artifact-id ID of the build artifact) uploaded during the build step.

Examples

Continuous Integration, build and publish

name: Continuous Integration - Build and Publish

name: Nodejs Continuous Integration

on:
  push:
    branches: [main]

jobs:
  continuous-integration:
    uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@31cd29bfb95f6bc6490d6abe5d66690431b518e3 # 2.0.0
    permissions:
      id-token: write
      security-events: write
      contents: read
    with:
      build: |
        {
          "commands": ["build"],
          "artifact": "dist"
        }

  publish:
    needs: continuous-integration
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

      - name: Setup NodeJS
        uses: hoverkraft-tech/ci-github-nodejs/actions/setup-node@81a4bca8445b7b273455ff26a9a5c3c31c86b2a1 # 0.25.0

      - name: Download build artifact
        uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
        with:
          artifact-ids: ${{ needs.continuous-integration.outputs.build-artifact-id }}
          path: /

      - name: Publish
        run: |
          npm publish dist
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Continuous Integration in a Docker container

This example runs CI checks inside a pre-built Docker container that contains the project code and dependencies. This ensures the same environment that will be deployed to production is tested.

name: Continuous Integration - Container Mode

on:
  push:
    branches: [main]

jobs:
  # Build the Docker image with project code and dependencies
  build-image:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

      - name: Build Docker image
        run: |
          docker build -t my-app:${{ github.sha }} .

      - name: Push to registry
        run: |
          docker tag my-app:${{ github.sha }} ghcr.io/${{ github.repository }}:${{ github.sha }}
          docker push ghcr.io/${{ github.repository }}:${{ github.sha }}

  # Run CI checks inside the Docker container
  continuous-integration:
    needs: build-image
    uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@31cd29bfb95f6bc6490d6abe5d66690431b518e3 # 2.0.0
    permissions:
      id-token: write
      security-events: write
      contents: read
    with:
      container: ghcr.io/${{ github.repository }}:${{ github.sha }}
      # Specify which build/test commands to run (they should exist in package.json)
      build: "" # Skip build as it was done in the Docker image

Continuous Integration with custom container path mapping

This example shows how to use custom path mappings when running CI steps inside a container.

It is useful when the project code is not located in the root folder of the repository.

name: Continuous Integration - Custom Container Path Mapping
on:
  push:
    branches: [main]
jobs:
  continuous-integration:
    uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@31cd29bfb95f6bc6490d6abe5d66690431b518e3 # 2.0.0
    permissions:
      id-token: write
      security-events: write
      contents: read
    with:
      container: |
        {
          "image": "ghcr.io/myorg/node-image:18-alpine",
          "pathMapping": {
            "/app": "./relative/path/to/app"
          }
        }

Continuous Integration with Advanced Container Options

This example shows how to use advanced container options like environment variables, ports, volumes, credentials, and additional Docker options.

name: Continuous Integration - Advanced Container Options

on:
  push:
    branches: [main]

jobs:
  continuous-integration:
    uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@31cd29bfb95f6bc6490d6abe5d66690431b518e3 # 2.0.0
    permissions:
      id-token: write
      security-events: write
      contents: read
    secrets:
      container-password: ${{ secrets.REGISTRY_PASSWORD }}
    with:
      container: |
        {
          "image": "ghcr.io/myorg/node-image:18-alpine",
          "env": {
            "NODE_ENV": "production",
            "CI": "true"
          },
          "options": "--cpus 2 --memory 4g",
          "ports": [3000, 8080],
          "volumes": ["/tmp:/tmp", "/cache:/workspace/cache"],
          "credentials": {
            "username": "myusername"
          }          
        }

Contributing

Contributions are welcome! Please see the contributing guidelines for more details.

License

This project is licensed under the MIT License.

SPDX-License-Identifier: MIT

Copyright © 2026 hoverkraft-tech

For more details, see the license.


This documentation was automatically generated by CI Dokumentor.