Merge branch 'main' into feat/node-registry-workspace

This commit is contained in:
2026-10-03 23:18:26 +01:00
17 changed files with 361 additions and 37 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ runs:
using: "composite"
steps:
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
+1 -1
View File
@@ -18,7 +18,7 @@ runs:
using: "composite"
steps:
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: ${{ inputs.node-version }}
cache: "npm"
+2 -2
View File
@@ -37,7 +37,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -51,7 +51,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
check-latest: true
+12 -12
View File
@@ -78,7 +78,7 @@ jobs:
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -92,7 +92,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
cache: true
@@ -122,7 +122,7 @@ jobs:
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -136,7 +136,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
cache: true
@@ -185,7 +185,7 @@ jobs:
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -199,7 +199,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
cache: true
@@ -226,7 +226,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -240,7 +240,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
cache: true
@@ -264,7 +264,7 @@ jobs:
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
lfs: ${{ inputs.lfs }}
@@ -277,7 +277,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
cache: true
@@ -303,7 +303,7 @@ jobs:
coverage: ${{ steps.coverage.outputs.coverage }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -317,7 +317,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
cache: true
+9 -9
View File
@@ -103,7 +103,7 @@ jobs:
steps:
- name: Checkout
if: inputs.preflight
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
lfs: false
@@ -127,7 +127,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -154,7 +154,7 @@ jobs:
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
lfs: ${{ inputs.lfs }}
@@ -167,7 +167,7 @@ jobs:
fi
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: ${{ inputs.node-version }}
cache: "npm"
@@ -194,7 +194,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -229,7 +229,7 @@ jobs:
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -246,7 +246,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
cache: true
@@ -308,7 +308,7 @@ jobs:
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -322,7 +322,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
+5 -5
View File
@@ -81,7 +81,7 @@ jobs:
steps:
- name: Checkout
if: inputs.preflight
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
lfs: false
@@ -104,7 +104,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
lfs: ${{ inputs.lfs }}
@@ -131,7 +131,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -162,7 +162,7 @@ jobs:
timeout-minutes: 60
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
lfs: ${{ inputs.lfs }}
@@ -184,7 +184,7 @@ jobs:
fi
- name: Setup Go
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
+2 -2
View File
@@ -113,7 +113,7 @@ jobs:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
lfs: ${{ inputs.lfs }}
@@ -166,7 +166,7 @@ jobs:
echo "pm=$pm" >> "$GITHUB_OUTPUT"
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: ${{ inputs.node-version }}
+5 -5
View File
@@ -319,7 +319,7 @@ jobs:
# Not the triggering ref: a push or a manual run from another branch must still test the default branch.
- name: Checkout the default branch
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
ref: ${{ steps.default.outputs.branch }}
fetch-depth: 0
@@ -328,8 +328,8 @@ jobs:
- name: Merge the update branch locally
id: merge
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config user.name "Lukasz Raczylo"
git config user.email "lukasz@raczylo.com"
git fetch origin "$BRANCH"
echo "head=$(git rev-parse FETCH_HEAD)" >> "$GITHUB_OUTPUT"
echo "subject=$(git log -1 --format=%s FETCH_HEAD)" >> "$GITHUB_OUTPUT"
@@ -408,7 +408,7 @@ jobs:
- name: Setup Go
if: steps.merge.outputs.skip != 'true' && steps.detect.outputs.go == 'true'
uses: actions/setup-go@v6
uses: actions/setup-go@v7
with:
go-version: ${{ inputs.go-version }}
check-latest: true
@@ -443,7 +443,7 @@ jobs:
- name: Setup Node.js
if: steps.merge.outputs.skip != 'true' && steps.detect.outputs.node == 'true'
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version: ${{ inputs.node-version }}
+89
View File
@@ -0,0 +1,89 @@
name: Validate
# Checks that a change to the workflows or composite actions still works. Renovate
# opens a PR for each action bump; this workflow is the gate those PRs must pass.
# The aggregate job "validate" is the one required status check.
# No paths filter: "validate" is a required status check, and a required check
# that never runs blocks a PR that touches only other files.
on:
pull_request:
workflow_dispatch:
permissions:
contents: read
pull-requests: read
concurrency:
group: validate-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
jobs:
static:
name: Static checks
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v7
# actionlint, then every external `uses:` reference must resolve.
- name: Check workflows and action references
run: scripts/check-actions.sh --ci
selftest-go:
name: Self-test go-test action
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v7
# The local path runs the action as it is on this branch, not at @main.
- name: Run the go-test action on the fixture module
uses: ./.github/actions/go-test
with:
working-directory: testdata/selftest/go
selftest-node-build:
name: Self-test node-build action
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Run the node-build action on the fixture project
uses: ./.github/actions/node-build
with:
build-script: cd testdata/selftest/node && npm ci && npm run build
cache-dependency-path: testdata/selftest/node/package-lock.json
selftest-node-pr:
name: Self-test node-pr workflow
uses: ./.github/workflows/node-pr.yaml
permissions:
contents: read
pull-requests: read
with:
working-directory: testdata/selftest/node
require-tests: true
validate:
name: validate
if: always()
needs: [static, selftest-go, selftest-node-build, selftest-node-pr]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Require every check to pass
env:
RESULTS: ${{ join(needs.*.result, ' ') }}
run: |
echo "results: $RESULTS"
for r in $RESULTS; do
if [ "$r" != success ]; then
echo "::error::a validation job finished as '$r'"
exit 1
fi
done
+75
View File
@@ -0,0 +1,75 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"timezone": "Europe/London",
"enabledManagers": [
"github-actions"
],
"semanticCommits": "enabled",
"semanticCommitType": "chore",
"semanticCommitScope": "deps",
"dependencyDashboard": false,
"prConcurrentLimit": 0,
"prHourlyLimit": 0,
"minimumReleaseAge": "3 days",
"postUpgradeTasks": {
"commands": [
"scripts/check-actions.sh --renovate"
],
"fileFilters": [
".validation-failed"
],
"executionMode": "branch"
},
"packageRules": [
{
"description": "This repository's own composite actions are tracked at @main by design.",
"matchPackageNames": [
"lukaszraczylo/shared-actions"
],
"enabled": false
},
{
"description": "Tool versions in action inputs and defaults (Go, Node, GoReleaser) are policy, not pins. A bump would change what every consumer builds with.",
"matchDatasources": [
"golang-version",
"node-version"
],
"enabled": false
},
{
"description": "The GoReleaser version input is policy, not a pin.",
"matchDepNames": [
"goreleaser/goreleaser"
],
"enabled": false
},
{
"description": "Minor and patch bumps merge on their own once the validate check is green.",
"matchUpdateTypes": [
"minor",
"patch",
"digest",
"pin"
],
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
},
{
"description": "Every consumer calls these actions at @main, so a major bump waits for a human.",
"matchUpdateTypes": [
"major"
],
"automerge": false,
"addLabels": [
"major"
]
}
],
"statusCheckNames": {
"artifactError": null,
"configValidation": null,
"mergeConfidence": null,
"minimumReleaseAge": null
}
}
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env bash
# Static checks for the workflows and composite actions in this repository:
# 1. actionlint (schema, expressions, and shell steps through shellcheck when present)
# 2. every external `uses:` reference resolves to a real tag or branch
#
# Usage: scripts/check-actions.sh [--ci | --renovate]
# --ci exit 1 when a check fails (default)
# --renovate exit 0 and write .validation-failed when a check fails, so the
# Renovate runner deletes the branch before a PR can open
#
# Needs: bash, git, curl, tar, sha256sum or shasum. No other tools: actionlint is
# downloaded at a pinned version and checked against a pinned SHA-256.
set -u
mode=--ci
case "${1:-}" in
"" | --ci) mode=--ci ;;
--renovate) mode=--renovate ;;
*) echo "usage: $0 [--ci | --renovate]" >&2; exit 2 ;;
esac
ACTIONLINT_VERSION=1.7.12
ACTIONLINT_SHA256_AMD64=8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8
ACTIONLINT_SHA256_ARM64=325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6
marker=.validation-failed
cd "$(git rev-parse --show-toplevel)" || exit 2
fail=0
problem() {
echo "::error::$*" >&2
fail=1
}
sha256_of() {
if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1; else shasum -a 256 "$1" | cut -d' ' -f1; fi
}
install_actionlint() {
local os arch want url tmp
case "$(uname -s)" in Linux) os=linux ;; Darwin) os=darwin ;; *) return 1 ;; esac
case "$(uname -m)" in
x86_64 | amd64) arch=amd64; want=$ACTIONLINT_SHA256_AMD64 ;;
aarch64 | arm64) arch=arm64; want=$ACTIONLINT_SHA256_ARM64 ;;
*) return 1 ;;
esac
# The pinned checksums are for the linux builds only.
[ "$os" = linux ] || return 1
tmp=$(mktemp -d)
url="https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_${os}_${arch}.tar.gz"
curl -fsSL --retry 3 -o "$tmp/a.tgz" "$url" || return 1
[ "$(sha256_of "$tmp/a.tgz")" = "$want" ] || { echo "actionlint checksum mismatch" >&2; return 1; }
tar -xzf "$tmp/a.tgz" -C "$tmp" actionlint || return 1
echo "$tmp/actionlint"
}
run_actionlint() {
local bin
if command -v actionlint >/dev/null 2>&1; then
bin=$(command -v actionlint)
else
bin=$(install_actionlint) || { problem "cannot install actionlint ${ACTIONLINT_VERSION}"; return; }
fi
# -shellcheck= disables the shellcheck pass when the binary is missing.
local opts=()
command -v shellcheck >/dev/null 2>&1 || opts+=(-shellcheck=)
# Info and style findings from shellcheck (for example SC2086 on intentional word
# splitting) do not fail the gate. Warnings and errors do. Composite actions are
# not linted by actionlint 1.7; workflows are.
opts+=(-ignore 'shellcheck reported issue.+SC[0-9]+:(info|style):')
if ! "$bin" "${opts[@]}" -color .github/workflows/*.y*ml; then
problem "actionlint reported problems"
fi
}
# Resolves every `uses: owner/repo[/path]@ref` that points outside this repository.
check_refs() {
local files uses ref repo path checked=""
files=$(find .github -type f \( -name '*.yml' -o -name '*.yaml' \))
uses=$(grep -hoE '^[[:space:]]*(-[[:space:]]+)?uses:[[:space:]]*[^[:space:]#]+' $files | sed -E 's/^[[:space:]]*(-[[:space:]]+)?uses:[[:space:]]*//' | sort -u)
while IFS= read -r u; do
[ -n "$u" ] || continue
case "$u" in ./* | docker://*) continue ;; esac
repo=${u%%@*}
ref=${u#*@}
[ "$repo" != "$u" ] || { problem "no @ref in 'uses: $u'"; continue; }
# owner/repo/sub/path -> owner/repo
path=$(echo "$repo" | cut -d/ -f1,2)
# This repository's own composite actions are tracked at @main by design.
[ "$path" = lukaszraczylo/shared-actions ] && continue
case " $checked " in *" $path@$ref "*) continue ;; esac
checked="$checked $path@$ref"
if ! git ls-remote --exit-code "https://github.com/$path" "refs/tags/$ref" "refs/heads/$ref" >/dev/null 2>&1; then
# A full commit SHA is not listed by ls-remote; accept it when the repository answers at all.
if echo "$ref" | grep -qE '^[0-9a-f]{40}$' && git ls-remote --exit-code "https://github.com/$path" HEAD >/dev/null 2>&1; then
continue
fi
problem "'uses: $u' does not resolve: no tag or branch $ref in $path"
fi
done <<<"$uses"
}
rm -f "$marker"
run_actionlint
check_refs
if [ "$fail" -ne 0 ]; then
if [ "$mode" = --renovate ]; then
echo "validation failed; writing $marker" >&2
printf 'actions validation failed\n' >"$marker"
exit 0
fi
exit 1
fi
echo "actions validation passed"
+5
View File
@@ -0,0 +1,5 @@
// Package selftest is a fixture that the validate workflow runs the go-test action against.
package selftest
// Add returns the sum of a and b.
func Add(a, b int) int { return a + b }
+9
View File
@@ -0,0 +1,9 @@
package selftest
import "testing"
func TestAdd(t *testing.T) {
if got := Add(2, 3); got != 5 {
t.Fatalf("Add(2, 3) = %d, want 5", got)
}
}
+3
View File
@@ -0,0 +1,3 @@
module example.com/selftest
go 1.24
+12
View File
@@ -0,0 +1,12 @@
{
"name": "selftest",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "selftest",
"version": "0.0.0"
}
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"name": "selftest",
"version": "0.0.0",
"private": true,
"scripts": {
"lint": "node -e \"process.exit(0)\"",
"test": "node --test",
"build": "node -e \"console.log('built')\""
}
}
+6
View File
@@ -0,0 +1,6 @@
const test = require('node:test');
const assert = require('node:assert');
test('addition', () => {
assert.strictEqual(2 + 3, 5);
});