Skip to content

Consolidate shared workflows into a single generated automation.yml entry point#88

Open
akolson wants to merge 1 commit into
mainfrom
consolidate-automation-entrypoint
Open

Consolidate shared workflows into a single generated automation.yml entry point#88
akolson wants to merge 1 commit into
mainfrom
consolidate-automation-entrypoint

Conversation

@akolson

@akolson akolson commented Jun 24, 2026

Copy link
Copy Markdown
Member

Summary

Replaces the ~7 per-feature call-*.yml callers (and the pull-request-target.yml dispatcher) that every consumer repo copies with a single reusable automation.yml, driven by automation-registry.yml as the source of truth, plus one generated automation-template.yml every consumer copies once.

  • automation-registry.yml declares each automation's leaf workflow, trigger events/types (or schedule), dispatch if: condition, and required/optional secrets.
  • scripts/generate-automation.js regenerates .github/workflows/automation.yml (the reusable workflow, one job per automation), automation-template.yml (the file consumers copy, with the exhaustive union on: block), and .github/workflows/automation-caller.yml (this repo dogfooding the same template against itself).
  • pull-request-label/review-requested/dependabot-reviewer routing, previously done by pull-request-target.yml, is now direct jobs in automation.yml - keeping the deepest chain (caller → automation.yml → leaf → is-contributor.yml) at exactly GitHub's 4-level nesting cap.
  • resolve-bot-pr-threads and holiday-message get their first-ever caller wiring here (previously undeployed anywhere).
  • A pre-commit hook (generate-automation) fails the commit if the registry and generated files drift; a new .github/workflows/pre-commit.yml CI workflow runs prek (the repo had .pre-commit-config.yaml but no CI lint check before).

resolve-bot-pr-threads's leaf job needs contents: write + pull-requests: write via the default GITHUB_TOKEN (every other automation uses its own scoped bot-app token instead). Since reusable-workflow permissions can only be narrowed downstream of the root caller, automation-template.yml grants contents: write/pull-requests: write at the top level, and every job in automation.yml other than resolve-bot-pr-threads explicitly narrows back to contents: read - so only that one job actually gets write capability, matching today's read-only default everywhere else.

No leaf workflow's internal logic changed - this is a routing/packaging consolidation only.

References

Closes #86

Reviewer guidance

  • Manually traced every job's if: in automation.yml against the on:/types: of the call-*.yml file it replaces (and pull-request-target.yml's action routing) - functional parity confirmed, see the registry comments for the mapping.
  • Ran node scripts/generate-automation.js --check and the full pre-commit run --all-files suite locally (via pre-commit, prek's predecessor, since prek isn't installable in this sandbox) - all hooks pass, including drift detection (verified it fails when the registry is edited without regenerating, then passes again after regenerating).
  • Confirmed actionlint passes on automation.yml and automation-template.yml (tested the template in a scratch .github/workflows/ dir since it lives at repo root here, pending each consumer copying it into their own .github/workflows/).
  • Permissions narrowing in automation.yml (contents: read job-level override on every job except resolve-bot-pr-threads) is the one piece of new authorization logic in this PR - worth a careful look.
  • This is the central half of Consolidate shared workflows into a single generated automation.yml entry point #86; the per-repo migration PRs (kolibri, studio, ricecooker, kolibri-design-system, le-utils, kolibri-installer-android, kolibri-app, kolibri-installer-debian, kolibri-image-pi, kolibri-data-portal) are tracked separately and won't be merged until this lands.

AI usage

Implemented end-to-end with Claude Code (Sonnet 4.6) from the architecture already laid out in issue #86 (which was itself drafted with Claude Code per its own AI-usage note). I directed the registry/generator design, reviewed the generated automation.yml/automation-template.yml output, and specifically caught and directed the fix for a permissions-scoping gap (resolve-bot-pr-threads needing write access that the rest of the automations shouldn't inherit) before it became a security issue. Claude traced trigger parity against the original call-*.yml files, ran the pre-commit/actionlint validation, and verified the generator's drift detection actually works rather than just asserting it does.

…ntry point

Replace the per-feature call-*.yml callers and the pull-request-target.yml
dispatcher with one reusable automation.yml plus a single generated caller
template, driven by automation-registry.yml as the source of truth. A
pre-commit hook regenerates and fails on drift between the registry and the
generated files.

Closes #86

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rtibbles rtibbles requested a review from rtibblesbot July 5, 2026 05:03
@rtibblesbot

rtibblesbot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🔵 Review posted

Last updated: 2026-07-05 05:15 UTC

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid generator/registry design and correctly-scoped permission narrowing, but the branch was forked before recent changes landed on main that this registry doesn't account for.

CI passing. No UI files in scope, Phase 3 skipped.

Blocking:

  • automation-registry.yml:79 — stale/too-broad manage-issue-header dispatch condition, and a whole new automation (good-first-issue-comment) missing from the registry entirely (inline comment).

Suggestion:

  • PR body — Closes #86 will auto-close the tracking issue despite the acknowledged-incomplete migration checklist; consider Part of #86 instead, or open a follow-up tracking issue for the remaining per-repo migrations.

Nitpick:

  • package.json:10js-yaml is only used by the build-time codegen script; consider devDependencies instead.

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Ran a phased review pipeline over the pull request diff:

  • Classified the diff to select review passes (core, frontend, backend) and whether manual QA was required
  • Core review pass checked correctness, design, architecture, testing, completeness, and DRY/SRP/Rule-of-Three principles
  • Specialized frontend/backend review passes applied framework-specific lenses where those files changed
  • For UI changes: manual QA and an accessibility audit against a live dev server, when available
  • Checked CI status and linked issue acceptance criteria
  • Synthesized one review from those passes and chose the verdict from the findings, CI status, and QA evidence

Comment thread automation-registry.yml
on:
issues:
types: [opened, reopened, labeled, unlabeled]
if: "github.event_name == 'issues' && contains(fromJSON('[\"opened\",\"reopened\",\"labeled\",\"unlabeled\"]'), github.event.action)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking: This branch's merge-base with upstream/main (5512260) is stale — main has since merged #62/#90, which refactored issue-header dispatch:

  • manage-issue-header.yml's own leaf-level if: filter (opened/reopened/labeled+help wanted/unlabeled+help wanted) was removed and pushed up into two new callers, issue-open.yml (unconditional for opened/reopened) and issue-label.yml (labeled/unlabeled gated to label.name == 'help wanted' only).
  • This registry entry's if: fires on any labeled/unlabeled action regardless of label name, and since the leaf no longer self-filters, merging as-is means manage-issue-header.js runs on every label add/remove on every issue — a real behavior regression, not just missed parity.
  • issue-label.yml also adds a second job, good-first-issue-comment (gated on label.name in ['good first issue', 'help wanted']), calling a brand-new leaf good-first-issue-comment.yml. This automation has no entry anywhere in the registry, so it's silently dropped from the generated automation.yml.

Please rebase onto current upstream/main, add a good-first-issue-comment registry entry, and split this entry's if: to match issue-label.yml's help wanted-only gating.

Comment thread package.json
"axios": "^1.13.6",
"dotenv": "^17.3.1",
"googleapis": "^142.0.0",
"js-yaml": "^4.1.0",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: js-yaml is only consumed by scripts/generate-automation.js (a build-time tool), not by any runtime workflow script — consider moving it to devDependencies.

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.

Consolidate shared workflows into a single generated automation.yml entry point

2 participants