lukaszraczylo 85900e7304 fix(autoupdate): give Renovate the pnpm version the tests use
Renovate wrote the lockfile with its own pnpm, in a form the pinned pnpm
rejected as an overrides mismatch, so every branch failed to install. Pass
pnpm-version to Renovate as a constraint.
2026-10-03 21:31:19 +01:00

Shared GitHub Actions

Reusable workflows and composite actions for Go projects.

Reusable Workflows

Runner selection

Every reusable workflow accepts runner (label, or a JSON object to pick a runner group):

with:
  runner: self-hosted
  # or
  runner: '{"group":"ci-linux","labels":["x64"]}'

Resolution order: inputs.runner, repository/org variable SHARED_ACTIONS_RUNNER, ubuntu-latest. Set the variable once to move every consumer. In go-release-cgo.yaml the build matrix keeps its per-platform os; runner covers the other jobs. Runner groups exist only for organisations and enterprises.

go-release.yaml

Standard Go release workflow using GoReleaser.

jobs:
  release:
    uses: lukaszraczylo/shared-actions/.github/workflows/go-release.yaml@main
    with:
      go-version: ">=1.24"
      docker-enabled: true  # optional
    secrets: inherit

Inputs:

Input Default Description
go-version >=1.24 Go version
semver-config semver.yaml Path to semver config
docker-enabled false Enable Docker builds
docker-registry ghcr.io Docker registry
rolling-release-tag "" Rolling release tag (e.g., v1)

go-release-cgo.yaml

Go release workflow for CGO-enabled projects. Builds natively on each platform.

jobs:
  release:
    uses: lukaszraczylo/shared-actions/.github/workflows/go-release-cgo.yaml@main
    with:
      go-version: ">=1.24"
      node-enabled: true
      node-build-script: "cd ui && npm ci && npm run build"
    secrets: inherit

Inputs:

Input Default Description
go-version >=1.24 Go version
semver-config semver.yaml Path to semver config
rolling-release-tag "" Rolling release tag
node-enabled false Enable Node.js
node-version 20 Node.js version
node-build-script "" Frontend build script
platforms (all 4) JSON array of platforms

go-pr.yaml

Pull request checks: tests, linting, security scans.

  • go vet / staticcheck findings show as inline annotations on the PR diff; gosec and CodeQL post to code scanning.
  • The report job posts one sticky comment with every check's result and coverage, and fails if any check fails or coverage is below coverage-threshold. Require PR Checks Report in branch protection.
  • A push to a branch with an open PR skips the duplicate run; stale runs on the same branch are cancelled.
  • Fork PRs cannot receive the comment; the report still lands in the job summary.
jobs:
  pr-checks:
    uses: lukaszraczylo/shared-actions/.github/workflows/go-pr.yaml@main
    with:
      go-version: ">=1.24"
    secrets: inherit

node-pr.yaml

Pull request checks for a Node, Vue or Astro project. It installs without changing the lockfile, then runs lint, typecheck, test and build. A script that does not exist is skipped. A push to a branch with an open PR skips the duplicate run, and stale runs on the same branch are cancelled. Call it once per project directory.

name: Pull Request

on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - "**"
      - "!main"

permissions:
  contents: read
  pull-requests: read

jobs:
  frontend:
    uses: lukaszraczylo/shared-actions/.github/workflows/node-pr.yaml@main
    with:
      working-directory: web

Inputs:

Input Default Description
node-version 22 Node.js version
working-directory . Directory that holds package.json
scripts lint,typecheck,test,build Scripts to run in order. A missing script is skipped.
pnpm-version pnpm version for a repo with no packageManager field. Empty uses the field, or the newest pnpm.
require-tests false Fail when there is no test script
lfs false Git LFS checkout
runner Runner label or runner group, as in the other workflows

pnpm is used when pnpm-lock.yaml exists, yarn for yarn.lock, otherwise npm. pnpm and yarn run through Corepack, so set packageManager in package.json.

go-autoupdate.yaml

Automatic dependency updates for Go. See renovate-autoupdate.yaml for the Renovate-based replacement that also covers npm, pnpm and yarn.

jobs:
  autoupdate:
    uses: lukaszraczylo/shared-actions/.github/workflows/go-autoupdate.yaml@main
    with:
      go-version: ">=1.24"
      release-workflow: "release.yaml"
    secrets: inherit

renovate-autoupdate.yaml

Daily dependency updates for Go and npm/pnpm/yarn projects, built on Renovate. It replaces go-autoupdate.yaml.

  1. Renovate upgrades everything that can be upgraded on branches named deps-autoupdate/* and opens no PR. All minor and patch updates (direct and indirect Go modules, npm, pnpm and yarn packages) go on deps-autoupdate/batch. Each major update gets its own branch.
  2. For each branch, one at a time, the workflow merges it into the default branch locally and runs the tests on that result: go build and go test -race -cover for Go, the package.json scripts for Node.
  3. If the tests pass, it opens a PR and squash-merges it. If they fail, no PR is opened. The test output goes into a comment on one sticky issue (see below), and Renovate retries on the next run.
  4. If anything merged and release-workflow is set, it dispatches the release once.
name: Update dependencies

on:
  workflow_dispatch:
  schedule:
    - cron: "0 3 * * *"

permissions:
  actions: write       # only to dispatch release-workflow
  contents: write
  issues: write        # only to report failing updates
  pull-requests: write

jobs:
  update:
    uses: lukaszraczylo/shared-actions/.github/workflows/renovate-autoupdate.yaml@main
    with:
      go-version: ">=1.24"
      release-workflow: release.yaml

The workflow finds go.mod and package.json itself and tests what exists. A repo with both, such as a Go backend with a Vue frontend, gets both tested for every branch.

Inputs:

Input Default Description
go-version >=1.24 Go version
go true Update and test the Go module. Turn off for a repo with no Go code.
go-working-directory . Directory that holds go.mod. Only this module is updated and tested.
go-prepare-command Shell commands to run before the Go tests, for example installing a CLI. Append a tool directory to $GITHUB_PATH to put it on PATH.
go-test-command Replaces the default go build and go test, for example encore test ./... for an Encore app.
node-version 22 Node.js version
node true Update and test the Node project. Turn off for a repo with no frontend to test.
node-working-directory . Directory that holds package.json. Only this project is updated and tested.
node-scripts lint,typecheck,test,build Scripts to run in order. A missing script is skipped.
pnpm-version pnpm version for a repo with no packageManager field. Empty uses the field, or the newest pnpm.
require-node-tests true Fail when there is no test script, so an untested update never merges
major-updates separate separate: each major gets its own branch, tested and merged on its own. batch: majors join the batch. ignore: skip majors.
minimum-release-age 2 days Skip releases younger than this
renovate-version 44 Renovate version
release-workflow Workflow file to dispatch after a merge, for example release.yaml. Give several as a comma-separated list. Each needs a workflow_dispatch trigger. Empty means no dispatch.
admin-merge false Merge with --admin. The workflow token cannot bypass branch protection.
lfs false Git LFS checkout
runner Runner label or runner group, as in the other workflows

Failing updates. The last 50 KB of the test output goes into a comment on one issue titled "Dependency updates failing tests". Each failing branch has its own comment, updated on every run, and a header with the commit and the run link. When a branch passes and merges, its comment is removed. When no failing branch is left, the issue closes. The output is also in the run summary. Without issues: write the run still works, but the issue is skipped.

Only what is tested is updated. Renovate manages one Go module and one Node project: the ones in go-working-directory and node-working-directory. A second package.json (docs, e2e tests, another frontend) or a second go.mod is left alone, because nothing would test its updates.

Branches run one at a time, so each one is tested on top of the ones merged before it. A branch that conflicts with the default branch is skipped, and Renovate rebases it on the next run.

Package manager. pnpm is used when pnpm-lock.yaml exists, yarn for yarn.lock, otherwise npm. The install step never changes the lockfile (--frozen-lockfile, --immutable, npm ci), so a lockfile that does not match package.json fails the run. pnpm and yarn run through Corepack, so set packageManager in package.json.

Per-project rules. Put a renovate.json in the calling repository. Renovate reads it and merges it with the defaults, so no extra input is needed:

{
  "ignoreDeps": ["some/package"],
  "packageRules": [{ "matchPackageNames": ["vite"], "enabled": false }]
}

The defaults already cap typescript below 7, which breaks vue-tsc.

Token. No secret is needed. Everything runs inside the calling repository with the workflow's own token, which needs contents: write and pull-requests: write. Two repository settings matter:

  • Settings, Actions, General: tick "Allow GitHub Actions to create and approve pull requests". Without it the workflow cannot open the PR.
  • A push made with the workflow token does not trigger other workflows, so a release workflow that runs on push will not start after a merge. Set release-workflow to dispatch it, and grant actions: write.

Commit message. The squash commit subject is the Renovate commit message, for example chore(deps): update dependencies, and the body is fixed text. Neither contains major or breaking, which semver-generator matches in commit messages.

Composite Actions

actions/go-test

Run Go tests.

- uses: lukaszraczylo/shared-actions/.github/actions/go-test@main
  with:
    go-version: ">=1.24"
    cgo-enabled: "1"  # optional, default "0"

actions/semver

Calculate semantic version.

- id: semver
  uses: lukaszraczylo/shared-actions/.github/actions/semver@main
  with:
    config-file: semver.yaml

- run: echo "Version: ${{ steps.semver.outputs.version_tag }}"

actions/goreleaser

Run GoReleaser with mode support.

# Full release (single runner)
- uses: lukaszraczylo/shared-actions/.github/actions/goreleaser@main
  with:
    version-tag: v1.0.0
    mode: full
    github-token: ${{ secrets.GITHUB_TOKEN }}

# Split build (matrix)
- uses: lukaszraczylo/shared-actions/.github/actions/goreleaser@main
  with:
    version-tag: v1.0.0
    mode: split
    cgo-enabled: "1"
    github-token: ${{ secrets.GITHUB_TOKEN }}

# Merge artifacts
- uses: lukaszraczylo/shared-actions/.github/actions/goreleaser@main
  with:
    version-tag: v1.0.0
    mode: merge
    github-token: ${{ secrets.GITHUB_TOKEN }}

actions/preflight

Fail in seconds when a prerequisite is missing, instead of at the end of a long run. Reads names from the step env, so map secrets there.

- uses: lukaszraczylo/shared-actions/.github/actions/preflight@main
  with:
    require: GITHUB_TOKEN,NPM_TOKEN          # must be non-empty
    repo-access: lukaszraczylo/helm-charts   # token needs push access
    repo-token-env: HOMEBREW_TAP_TOKEN
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
    HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}

Optional probes use the real token, so they catch caller permissions: that are too narrow:

  • release-write: "true" runs git push --dry-run, which fails when the token cannot push (no tag or release possible).
  • ghcr-push: true|auto asks ghcr.io for a push token and opens a blob upload session (no package is created). auto probes only when the config has dockers/dockers_v2/docker_manifests and mentions ghcr.io. The image is the first ghcr.io/... path in the config, else the repository (ghcr-image overrides).
  • A probe that cannot reach a verdict (network error, odd status) warns and does not fail.

It also scans .goreleaser.y*ml and requires every {{ .Env.NAME }} (comment lines ignored) to be set. All problems are listed in one run.

go-release.yaml and go-release-cgo.yaml run it in a first preflight job before tests. Set preflight: false to skip it, and preflight-repos to check access to a tap or helm-charts repo. An empty secret usually means the caller omitted secrets: inherit.

actions/rolling-release

Create/update a rolling release tag.

- uses: lukaszraczylo/shared-actions/.github/actions/rolling-release@main
  with:
    tag: v1
    version-tag: v1.2.3
    github-token: ${{ secrets.GITHUB_TOKEN }}

actions/node-build

Setup Node.js and run build script.

- uses: lukaszraczylo/shared-actions/.github/actions/node-build@main
  with:
    node-version: "20"
    build-script: "cd ui && npm ci && npm run build"

Outputs

Both release workflows output:

  • version - Calculated version without v prefix (e.g., 1.2.3)
  • version_tag - Version with v prefix (e.g., v1.2.3)
S
Description
Mirror of github.com/lukaszraczylo/shared-actions
Readme
308 KiB
Languages
Shell 100%