mirror of
https://github.com/lukaszraczylo/shared-actions.git
synced 2026-10-14 05:23:05 +00:00
Renovate updated every go.mod and package.json in a repo, while the tests cover one module and one Node project. An update outside them would merge untested. Restrict the managers to the configured directories, and add go and node switches for a repo that has no Go code or no frontend to test.
288 lines
12 KiB
Markdown
288 lines
12 KiB
Markdown
# 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):
|
|
|
|
```yaml
|
|
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.
|
|
|
|
```yaml
|
|
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.
|
|
|
|
```yaml
|
|
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.
|
|
|
|
```yaml
|
|
jobs:
|
|
pr-checks:
|
|
uses: lukaszraczylo/shared-actions/.github/workflows/go-pr.yaml@main
|
|
with:
|
|
go-version: ">=1.24"
|
|
secrets: inherit
|
|
```
|
|
|
|
### `go-autoupdate.yaml`
|
|
|
|
Automatic dependency updates for Go. See `renovate-autoupdate.yaml` for the Renovate-based replacement that also covers npm, pnpm and yarn.
|
|
|
|
```yaml
|
|
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.
|
|
|
|
```yaml
|
|
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. |
|
|
| `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. |
|
|
| `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`. It 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:
|
|
|
|
```json
|
|
{
|
|
"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.
|
|
|
|
```yaml
|
|
- 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.
|
|
|
|
```yaml
|
|
- 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.
|
|
|
|
```yaml
|
|
# 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.
|
|
|
|
```yaml
|
|
- 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.
|
|
|
|
```yaml
|
|
- 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.
|
|
|
|
```yaml
|
|
- 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`)
|