diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7c19319..39daf62 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,7 +1,7 @@ name: Lint -# actionlint over this repo's workflows and the caller templates (the templates aren't under -# .github/workflows, so they're named explicitly). +# actionlint over this repo's workflows and the caller templates. The templates are linted as an +# app holds them (in a git repo's .github/workflows), so build.yml's call to ./ci.yml resolves. on: pull_request: push: @@ -20,4 +20,9 @@ jobs: - name: actionlint run: | docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:1.7.12 -color - docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:1.7.12 -color templates/*.yml + app=$(mktemp -d) + chmod 755 "$app" # the actionlint image runs as an unprivileged user; mktemp makes it 0700 + mkdir -p "$app/.github/workflows" + cp templates/*.yml "$app/.github/workflows/" + git -C "$app" init -q + docker run --rm -v "$app:/repo" -w /repo rhysd/actionlint:1.7.12 -color diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index fc1da0d..73e3020 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -1,8 +1,8 @@ name: Node CI # Installs a Node repo's dependencies (npm ci, with the npm cache) and runs its checks. -# Called from a repo's ci.yml on pull requests and from the test job of its build.yml; -# see templates/ for both callers. With docker-template set, it first runs this repo's +# Called from a repo's ci.yml, which runs on pull requests and as the test job of its build.yml; +# see templates/. With docker-template set, it first runs this repo's # templates//check-drift, from the same commit as this workflow, on the caller. on: workflow_call: diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 7657f9c..68cc609 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -3,7 +3,8 @@ name: Python CI # Runs a uv project's checks: by default ruff with the shared rule set, then pytest. # The shared ruff.toml (this repo's root) is copied into the caller's checkout from the same # commit as this workflow, since ruff can't extend a remote config. A repo keeps no ruff.toml -# of its own. Called from a repo's ci.yml and from the test job of its build.yml. +# of its own. Called from a repo's ci.yml, which runs on pull requests and as the test job of its +# build.yml. on: workflow_call: inputs: diff --git a/README.md b/README.md index cbdca58..6650427 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,14 @@ their Next+Prisma Dockerfile. Public so that public and private repos can both c is nothing secret here. Not accepting contributions. App repos hold only thin callers. Start from [`templates/`](templates): `ci.yml` runs the checks -on pull requests (skipped when only docs change), and `build.yml` runs the same checks on a `v*` -tag before building the image. Every workflow's inputs and defaults are documented at the top of -its file, and every one takes `runs-on` as JSON (`'"ubuntu-latest"'` or a list of labels), so a -repo can move to a self-hosted runner without forking anything. +on pull requests (skipped when only docs change) and holds the repo's one copy of its CI inputs +(its `with:`). `build.yml`'s `test` job calls that `ci.yml` (`uses: ./.github/workflows/ci.yml`) +on a `v*` tag before building the image, so a tag runs exactly the PR checks. A called run has +no path filter, and it takes its caller's `github` context (event `push`, the tag's ref), so it +never shares a concurrency group with a PR run and is never cancelled. Every workflow's inputs +and defaults are documented at the top of its file, and every one takes `runs-on` as JSON +(`'"ubuntu-latest"'` or a list of labels), so a repo can move to a self-hosted runner without +forking anything. Callers pin `@main`, so a push here changes every app's CI and builds at once. @@ -47,10 +51,11 @@ base image, so a per-app tweak stays one line. Anything app-only is marked with `check-drift ` diffs an app's copy against the template, ignoring the marked lines, and exits nonzero on drift. `check-drift --help` gives the marker rules. -Every app built from it is held to it in CI: its `ci.yml` and `build.yml`'s `test` job pass -`docker-template: next-prisma` to `node-ci.yml`. A template change here therefore fails every -app's next PR and tag build until the app copies it in (run -`~/Projects/workflows/templates/next-prisma/check-drift .` in the app to see the diff). +Every app built from it is held to it in CI: its `ci.yml` passes `docker-template: next-prisma` +to `node-ci.yml`. A template change here therefore fails every app's next PR and tag build until +the app copies it in (run `~/Projects/workflows/templates/next-prisma/check-drift .` in the app to +see the diff). A Node major bump lands here first (the `FROM` lines, and `node-ci.yml`'s +`node-version` default), then in each app; an app that bumps first fails its drift check. - The image builds without the optional `npm_token` secret; pass it (`npm-token: true` in the caller of `build-image.yml`) when the app installs `@basmith7` packages from GitHub Packages. diff --git a/templates/build.yml b/templates/build.yml index 26a8b97..3a24fa6 100644 --- a/templates/build.yml +++ b/templates/build.yml @@ -1,18 +1,16 @@ name: Build -# A v* tag tests the commit, then builds ghcr.io/basmith7/: and :latest; nothing -# deploys on its own. Deploy with `deploy-now ` (tower-deploy). Both jobs are shared: -# https://github.com/basmith7/workflows -# Give `test` the same `with:` as ci.yml (docker-template included, so a tag can't ship a -# drifted Dockerfile). For @basmith7 packages, set packages-read: true there and npm-token: true -# on `image`. +# A v* tag tests the commit with this repo's ci.yml, then builds ghcr.io/basmith7/: +# and :latest; nothing deploys on its own. Deploy with `deploy-now ` (tower-deploy). The +# image job is shared: https://github.com/basmith7/workflows +# For @basmith7 packages, set npm-token: true on `image`. on: push: tags: ["v*"] jobs: test: - uses: basmith7/workflows/.github/workflows/node-ci.yml@main + uses: ./.github/workflows/ci.yml permissions: contents: read packages: read diff --git a/templates/ci.yml b/templates/ci.yml index 621fb7e..57fd2fe 100644 --- a/templates/ci.yml +++ b/templates/ci.yml @@ -1,19 +1,21 @@ name: CI -# Pull-request checks, shared: https://github.com/basmith7/workflows +# Checks for pull requests, and build.yml's test job through workflow_call: this file's `with:` +# is the repo's one copy of its CI inputs. Shared: https://github.com/basmith7/workflows # Inputs (packages-read, prisma, docker-template, commands, ...) are documented at the top of # node-ci.yml. An app whose Dockerfile copies templates/next-prisma sets docker-template. -# A repo that commits straight to main also adds `push: { branches: [main], paths-ignore: ... }`. on: pull_request: paths-ignore: - "**.md" - "docs/**" - "specs/**" + workflow_call: concurrency: + # Only PR runs cancel; a call from build.yml has the tag's ref and event (workflows README). group: ci-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: check: