Shared, reusable GitHub Actions workflows for ucgmsim Python repos:
ci.yml—ruff(check + format),deptry,numpydoclint,pytest, andty(type checking) as five parallel jobs.claude-review.yml— an on-demand Claude PR review, triggered by a@claude reviewcomment (never automatically on PR open/push).
In the consuming repo, replace the repo's own ruff.yml, deptry.yml,
numpydoc.yml, pytest.yml, and types.yml workflows with a single file,
e.g. .github/workflows/ci.yml:
name: CI
on: [pull_request]
jobs:
ci:
uses: ucgmsim/meta-ci-action/.github/workflows/ci.yml@v1
with:
package-dir: qcore
# system-packages: "gmt libgmt-dev ghostscript"
# uv-extra-args: "--all-groups --all-extras"
# numpydoc-extra-excludes: "-E ccldpy.py"
# enable-coverage: true
# cov-package: qcore
# cov-fail-under: 95| Input | Default | Purpose |
|---|---|---|
python-version |
"3.13" |
Interpreter version for the numpydoc job's setup-python step. |
package-dir |
(required) | Top-level package directory numpydoc lints, e.g. qcore, workflow, IM. |
system-packages |
"" |
Space-separated apt packages installed before the deptry/pytest/typecheck jobs (e.g. native libs like GMT or GDAL). |
uv-extra-args |
"--all-extras --dev" |
Extra flags passed to uv sync in the deptry/pytest/typecheck jobs. |
numpydoc-extra-excludes |
"" |
Extra -E fdfind exclude fragments for numpydoc, e.g. -E ccldpy.py. __init__.py is always excluded. |
enable-coverage |
false |
When true, runs pytest with --cov=<cov-package> and gates on cov-fail-under. |
cov-package |
"" |
Package name passed to --cov=. Required when enable-coverage is true. |
cov-fail-under |
95 |
Coverage percentage threshold passed to coverage report --fail-under=. |
claude-review.yml is a workflow_call-only reusable workflow — it has no
trigger of its own. Each consuming repo needs its own thin wrapper carrying
the actual issue_comment trigger, e.g. .github/workflows/claude-review.yml:
name: Claude PR Review
on:
issue_comment:
types: [created]
jobs:
review:
uses: ucgmsim/meta-ci-action/.github/workflows/claude-review.yml@v1
secrets:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}The reusable workflow itself gates on contains(github.event.comment.body, '@claude review') and only runs on PR comments — it does not run on PR
creation, push, or any other event. CLAUDE_CODE_OAUTH_TOKEN must be set as
a secret in the consuming repo (or its org) and passed through explicitly,
since reusable workflows don't inherit secrets automatically unless declared.
- Args live in
pyproject.toml, not the workflow. Tool behavior (ruff rules, deptry dev-dependency groups,tyexcludes) should be configured via each repo's own[tool.*]sections, so this workflow stays argument-free where possible. The two exceptions —package-dirandnumpydoc-extra-excludes— exist becausenumpydoc's CLI has no path-exclude equivalent expressible inpyproject.toml. - Coverage is opt-in. Set
enable-coverage: true(pluscov-package) to add a--covrun and acoverage report --fail-under=gate to the pytest job. Leftfalse, pytest just runspytest testswith no coverage instrumentation at all — matches repos that don't want the extra CI time or don't have a coverage target yet.
- Move hardcoded CLI args into
pyproject.toml. Check the repo's existingruff.yml/deptry.yml/types.yml/etc. for flags baked into therun:steps (e.g.ty --exclude,deptry's dev-dependency groups) and move them into the matching[tool.*]section instead, so the shared workflow can invoke each tool without repo-specific arguments. - Identify what can't move to config. A few things (like numpydoc's
path excludes) have no
pyproject.tomlequivalent — these stay aswith:inputs on theci.ymlcall. - Add the caller workflow. Create
.github/workflows/ci.ymlin the consuming repo per the Usage example above, setting only the inputs that differ from the defaults. - Delete the superseded workflows (whichever of
ruff.yml,deptry.yml,numpydoc.yml,pytest.yml,types.ymlthe repo has). Leave anything unrelated to these five tools untouched. - Validate before merging. Open a draft PR and confirm each job passes (or fails the same way the old workflow did) before relying on it.
Adopting claude-review.yml is independent of the above — it's a separate
opt-in workflow, not part of the ci.yml migration.