GitHub Actions Workflows - CodeSwordsman

GitHub Actions workflow templates: triggers and job structure, Node build and test with caching, Docker image push, artifacts and SSH deploy, matrix builds, least privilege and secrets.

actions/checkout@v4 / setup-node@v4Updated 2026-10-3022 commands

Structure

Triggers for branch pushes, pull requests and manual runs; files live in .github/workflows

name: ci
on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

Minimal job and step structure; a failing step aborts the job

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "hello"

Workflow-level and job-level env vars; job values override duplicates

env:
  NODE_ENV: test
jobs:
  build:
    env:
      CI: true

Pin the Node version and enable caching keyed on the lockfile

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

Use npm ci in CI for reproducible installs from the lockfile

      - run: npm ci
      - run: npm run lint
      - run: npm test

Build & Test

Read the version from .nvmrc so CI matches local Node

      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version-file: .nvmrc
          cache: npm
      - run: npm ci
      - run: npm run build

Matrix builds test several versions in parallel; fail-fast: false reports all failures

    strategy:
      fail-fast: false
      matrix:
        node: [18, 20, 22]

Run tests non-interactively; vitest uses --run and jest uses --ci

      - run: npm test -- --run
        env:
          CI: true

Upload reports even on failure to inspect what went wrong

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-report
          path: coverage/

Scan for high-severity dependency issues; relax with continue-on-error if needed

      - run: npm audit --audit-level=high

Docker Build & Push

Log in to the registry; GITHUB_TOKEN requires packages: write

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

Tag with the commit SHA for traceability without overwriting history

      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

Enable BuildKit for multi-platform builds before pushing

      - uses: docker/setup-buildx-action@v3

Declare least privilege explicitly so tightened defaults do not break the workflow

permissions:
  contents: read
  packages: write

Artifacts & Deploy

Store build output for later jobs or manual download; v4 forbids duplicate names

      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
          retention-days: 7

Fetch the artifact in the deploy job instead of rebuilding

      - uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist

Sync over SSH; keep the private key in secrets and load it at runtime

      - name: Deploy
        run: rsync -avz --delete dist/ deploy@10.0.0.12:/opt/app/
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}

Environments can require approval; concurrency prevents overlapping deploys

    environment:
      name: production
      url: https://app.example.com
    concurrency:
      group: production
      cancel-in-progress: false

Cache & Security

Cache keyed on the dependency file hash so changes invalidate it

      - uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: pip-${{ hashFiles('requirements.txt') }}

Checkout fetches depth 1 by default; set fetch-depth: 0 for tags or diffs

        with:
          fetch-depth: 0

Secrets are masked; check length to confirm injection

      - run: echo "token length ${#TOKEN}"
        env:
          TOKEN: ${{ secrets.API_TOKEN }}

Set job and step timeouts to avoid hanging runs burning minutes

    timeout-minutes: 15
    steps:
      - run: npm run test:e2e
        timeout-minutes: 10

This website uses cookies to ensure you get the best experience on our website. Privacy Policy.