Skip to content

feat: add a reusable render-module-rmd.yaml workflow - #37

Merged
eliotmcintire merged 1 commit into
mainfrom
feat/render-module-rmd-reusable
Sep 4, 2026
Merged

feat: add a reusable render-module-rmd.yaml workflow#37
eliotmcintire merged 1 commit into
mainfrom
feat/render-module-rmd-reusable

Conversation

@eliotmcintire

Copy link
Copy Markdown
Contributor

Implements step 1 of #36.

Adds .github/workflows/render-module-rmd.yaml, so the module render job stops being a file that each module repository owns a frozen copy of.

The problem this solves

From the survey in #36: 74 module repositories carry a hand-generated copy of this job, across 96 repository/branch combinations. Nobody writes it — SpaDES.core::use_gha() writes it once, and it is never regenerated. So the file has frozen into two generations:

combinations shape
older 46 ubuntu-20.04, checkout@v2, setup-r@v1, hand-written apt block, nothing from this repo
newer 50 ubuntu-latest, checkout@v4, five actions from this repo at @v0.2 / @v0 / @v0.0.1

Those pins are the main reason v0.1v0.5 cannot be retired. After this, a caller names one ref and the five pins live here.

Bugs fixed by the move

These were all in the generated file, in every copy of it:

  • [skip-ci] worked on neither event. It tested github.event.commits[0].messagecommits[0] is the oldest commit in a push, so [skip-ci] on the tip was ignored; and pull_request payloads have no commits field at all, so it never applied there. Now uses head_commit, matching feat: honour [skip-ci] org-wide; add a reusable revdeps workflow #34.
  • No concurrency group, so superseded runs were never cancelled — 74 repositories outside the protection feat: cancel superseded runs to stop burning the shared concurrency budget #30 gave the packages.
  • The apt block had no apt-get update, no retries and no timeout. That is the exact shape that left two LandWebUtils jobs sitting for 6h0m on 2026-08-19 before being killed. Now uses the same retry wrapper as install-spatial-deps.
  • The commit step ran on pull_request too, where github.ref is refs/pull/N/merge and the push cannot succeed. It failed silently every time, swallowed by || echo "No changes to commit". Now push-only.

Privilege split

Same as citation.yaml (#35), and the argument is stronger here: rendering installs the module's whole dependency tree and then executes the module's own .Rmd. That must not share a job with a token that can push. render gets contents: read and uploads an artifact; commit gets contents: write and runs nothing but git.

Callers grant contents: write on the calling job — a called workflow can only reduce permissions, never widen them.

Inputs

input default why
module required the <module>.R / <module>.Rmd basename
r-version release
system-deps true a module that needs no geospatial stack sets false
extra-apt "" modules have no DESCRIPTION, so nothing can derive their system requirements — this is the escape hatch

Two deliberate deviations from #36, worth review

setup-r-deps is not used. #36 proposed folding it in. It can't be: it delegates to r-lib/actions/setup-r-dependencies, which resolves from a DESCRIPTION, and modules have none — their dependencies come from SpaDES.core::packages() + Require::Require(). The apt hardening is reproduced inline instead. Worth revisiting if setup-r-deps ever grows a packages: passthrough.

The second install-Rmd-pkgs call is kept. The generated file calls it twice, once before install-Require and once after install-SpaDES. #36 flagged this as possibly deliberate — installing SpaDES can move versions the first call settled — so it is preserved rather than silently dropped. If someone knows the history and it is vestigial, say so and I will remove it.

One assumption made explicit

The module name must equal the repository name. This is already baked into the generated file: it calls SpaDES.core::packages(modules = "<name>", paths = ".."), which only resolves because actions/checkout puts the repo at /home/runner/work/<repo>/<repo> — so .. is the module directory. It held for every module surveyed, but it is now stated in a comment rather than implied.

Not in this PR

Steps 2–4 of #36: changing the generator in SpaDES.core, updating the 74 existing repositories, and deleting the tags. This is just the piece they depend on.

examples/render-module-rmd.caller.yaml shows the ~20-line caller the generator will emit.

Testing

self-test.yaml still cannot exercise a reusable workflow — it checks out the caller and runs at its root, and this repo has no module. So this lands with the same verification gap as the other six templates; the first real test is a module repository calling it, which is step 3.

🤖 Generated with Claude Code

https://claude.ai/code/session_015ZoicL7829pkb5ZbS5Ciww

Every SpaDES module repository carries a hand-generated copy of this job,
written once by SpaDES.core::use_gha() and never regenerated. The survey in
#36 found 74 repositories carrying it across 96 repository/branch
combinations, in two generations that had drifted apart: 46 combinations
still on ubuntu-20.04 with checkout@v2 and setup-r@v1, and 50 on the newer
shape pinning five actions from this repository at @v0.2, @v0 or @v0.0.1.

Those pins are the main thing blocking retirement of v0.1-v0.5. A caller now
supplies its triggers and the module name; the pins live here and move once.

Fixes carried in by the move:

- [skip-ci] tested commits[0], the OLDEST commit in a push, and there is no
  commits field at all on pull_request -- so it worked on neither. Now uses
  head_commit, as in #34.
- No concurrency group, so superseded runs were never cancelled (#30).
- The hand-written apt-get install had no apt-get update, no retries and no
  timeout. That is the shape that left two LandWebUtils jobs sitting 6h on
  2026-08-19. Now uses the same retry wrapper as install-spatial-deps.
- The commit step ran on pull_request too, where github.ref is
  refs/pull/N/merge and the push cannot succeed; it failed silently every
  time, swallowed by `|| echo "No changes to commit"`. Now push-only.

Rendering and committing are separate jobs, as in citation.yaml (#35):
rendering installs the module's dependency tree and then executes the
module's own .Rmd, which must not share a job with a write-scoped token.

setup-r-deps is deliberately not used here. It delegates to
r-lib/actions/setup-r-dependencies, which resolves from a DESCRIPTION, and
modules have none -- their dependencies come from SpaDES.core::packages().
The apt hardening is reproduced instead.

The second install-Rmd-pkgs call is preserved rather than dropped: the
generated file had it, installing SpaDES can move versions the first call
settled, and #36 flags it for someone with the history to confirm or remove.

Refs #36.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZoicL7829pkb5ZbS5Ciww
@eliotmcintire
eliotmcintire merged commit 12bfc0f into main Sep 4, 2026
1 check passed
@eliotmcintire

Copy link
Copy Markdown
Contributor Author

Merging as this has no effect yet; but it is needed to proceed to following steps in the #36

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant