Reusable GitHub Actions workflows shared across my repos.
This repo is public by necessity. GitHub resolves a reusable workflow using
the caller's token, so a public repo cannot call a reusable workflow that
lives in a private one. These workflows were originally in the private
ajmarkow/utilities, which worked for the private config repos but failed at
parse time from public nix-components:
failed to parse workflow: error parsing called workflow
"ajmarkow/utilities/.github/workflows/telegram-notify.yml@main"
: workflow was not found
Nothing here is sensitive. Secrets are always passed in by the caller.
Sends a Telegram message with a success/failure GIF.
notify:
needs: build
if: always()
uses: ajmarkow/ci-workflows/.github/workflows/telegram-notify.yml@main
with:
status: ${{ needs.build.result }}
secrets:
TELEGRAM_TOKEN: ${{ secrets.INFISICAL_AJ_ALERTS_TELEGRAM_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.INFISICAL_TELEGRAM_CHAT_ID }}status takes needs.<job>.result. With a matrix, that aggregates — it is
success only when every leg passed.
Both secrets are required. If either is empty the job fails early and names the
cause, rather than emitting a bare Can't add secret mask for empty string
annotation and failing further down.
nix-server—.github/workflows/deploy.ymlnix-check.yml(this repo) — its ownnotifyjob, when a caller opts in
Shared nix flake check + build matrix for the four Nix flake repos
(nix-components, nix-mac, nix-pixelbook, nix-server). Each of those
keeps a thin check.yml that supplies only what genuinely differs between
them; everything else lives here.
name: Check # keep this literal name — see gotchas below
on:
push:
pull_request:
jobs:
check:
uses: ajmarkow/ci-workflows/.github/workflows/nix-check.yml@v1
with:
systems: |
[{"system": "x86_64-linux", "runner": "ubuntu-latest"},
{"system": "aarch64-darwin", "runner": "macos-latest"}]
check-flags: --impure
build-attrs: |
nixosConfigurations.foo.config.system.build.toplevel
build-all-packages: true
cachix-cache: my-cache
notify: true
secrets:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
TELEGRAM_TOKEN: ${{ secrets.INFISICAL_AJ_ALERTS_TELEGRAM_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.INFISICAL_TELEGRAM_CHAT_ID }}Inputs:
| Input | Type | Default | Purpose |
|---|---|---|---|
systems |
string (JSON) | required | Array of {"system","runner"} objects, consumed as the job matrix. Both keys are required on every entry. Must be non-empty. |
check-flags |
string | '' |
Appended to nix flake check. |
build-attrs |
string | '' |
Newline-separated flake attributes to build. |
build-flags |
string | '' |
Appended to every nix build. |
build-all-packages |
boolean | false |
Enumerate .#packages.<system> and build every attribute, since nix flake check only evaluates (doesn't build) packages. |
accept-flake-config |
boolean | false |
Honour the flake's own nixConfig (e.g. extra-substituters). |
nix-path |
string | '' |
Passed through to install-nix-action's nix_path. |
cachix-cache |
string | '' |
Cachix cache name to push to. Empty disables the cachix step entirely. |
extra-env |
string | '' |
Single-line KEY=VALUE entries appended to $GITHUB_ENV, for configs that read builtins.getEnv. |
notify |
boolean | false |
Send a Telegram notification via telegram-notify.yml. See gotchas. |
Secrets CACHIX_AUTH_TOKEN, TELEGRAM_TOKEN, TELEGRAM_CHAT_ID are all
optional at the schema level, but each becomes required in practice the moment
you set the input that needs it (cachix-cache, notify).
Three things here are counter-intuitive, on purpose:
notifydefaults tofalse.secretsisn't readable from a job-levelif:, and a called reusable workflow doesn't supportcontinue-on-error, so this workflow has no way to soft-skip notify when a caller forgets to wire the Telegram secrets.telegram-notify.ymlexits 1 on an empty token or chat ID. Defaulting totruewould mean one missing secret turns every green flake check red. Opting in is the caller's job.build-attrsentries omit the.#. WritenixosConfigurations.foo.config.system.build.toplevel, not.#nixosConfigurations...— the workflow prepends the.#itself.- The check name is
<caller job id> / nix flake check (<system>). If your caller job is namedcheck, GitHub reportscheck / nix flake check (x86_64-linux). That's a different string than the pre-consolidation per-repo check names — matters only if something is pinned to the old name (nothing currently is; none of the four repos enforces required status checks).
The caller must keep its own workflow named Check (the top-level
name:, not the job id). nix-server's deploy.yml triggers on
workflow_run: workflows: ["Check"], which matches the caller's workflow
name — rename it and deploys stop firing, silently.
On a pull request from a fork, the cachix push and the Telegram notification
are both skipped, because fork PRs receive no secrets. nix flake check and
the builds still run.
nix-components—.github/workflows/check.ymlnix-mac—.github/workflows/check.ymlnix-pixelbook—.github/workflows/check.ymlnix-server—.github/workflows/check.yml
Lints this repo's own workflow files on every push to main and every pull
request. Not a reusable workflow — nothing else calls it. It exists because
this repo had zero CI before it: a YAML or expression error in a reusable
workflow here was previously only discoverable when a downstream caller next
ran it.