Add merge_gha_workflows task and pipeline stage (#50 slice 3) - #73
Conversation
Final slice of the Renovate-resilient template machinery: refresh GHA workflow files from their baseline templates while preserving every Renovate-managed value already in the repo. Approach: the template text is canonical — structure, comments, and formatting come from it byte-for-byte — and the Renovate-managed scalar values are grafted back on using Psych's node line/column coordinates. No YAML re-serialization happens at all, so comment/ format preservation holds by construction and no new gem (psych-pure) is needed. - preserve_keys (default: uses, image, container, ruby-version, runs-on; extensible per session config) selects which mapping keys' values are Renovate's - Values pair by [mapping path, key, identity], where identity is the part Renovate never changes (action before @, image before :, none for bare versions) — so distinct versions per job survive, trailing comments (pinned-digest conventions) ride along, and steps new to the template take the template's value - The merge_github_workflows stage merges only files that exist in BOTH the repo and the template chain (same per-module override resolution as profile::github_actions); creating/removing workflow files remains the profile's job, and repo-specific workflows with no template are never touched Verified with 13 specs (several driven by the real pr_tests.yml template, including byte-identity assertions) and an e2e run against a fixture with Renovate-bumped checkout@v7 / ruby-version 3.4.9 / ubuntu-24.04 plus structural drift: the merge restored template structure, preserved all bumped values (including per-job ones), left an untemplated custom workflow untouched, and a second run reported "1 unchanged". Real-world cases from pupmod-simp-pupmod dd98340 (ruby-version) and 837fb5e (runs-on) are covered by the defaults. After this and simp#70 merge, profile::github_actions can flip to bootstrap mode per project_type in Hiera, completing simp#50. Refs simp#50 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Really like this approach — grafting managed values onto canonical template text via Psych node coordinates is clean, and using 1. Drop the 2. Make the Hiera-flip dependency explicit — the stage is inert without it. It runs after Minor: Everything else — coordinate grafting, multi-line skip, malformed/empty handling, plan scoping, template resolution — checks out. |
- Remove the `warn stdin` debug line (it echoed every workflow template to stderr on each run) - identity() now handles ported registries (registry:5000/foo:8 pairs by everything before the tag colon), with a spec - Ship the profile::github_actions::strategy: bootstrap Hiera flip for pupmod/pupmod_skeleton WITH this stage: while the profile enforces, the apply stage overwrites workflows with pure template before this stage runs, so enabling merge_github_workflows pre-flip protects nothing. The key is inert until the managed_file strategy support merges, and the stage comment now documents the coupling. rubygem and unknown_with_ci project types stay enforce, since the merge stage does not cover them Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
All addressed in 144716f:
12 examples, 0 failures. 🤖 Generated with Claude Code |
Final slice of #50: refresh GHA workflow files from their baseline templates while preserving every Renovate-managed value already in the repo. Independent of #70/#72 (disjoint files; the stage anchors next to
configure_renovate(immediately before it) specifically to avoid overlapping #72's diff) — but the three together complete the issue.Cleaner than planned: no psych-pure
The issue proposed a psych-pure comment-preserving round-trip. This implementation avoids re-serialization entirely: since downstream workflow files are stamped copies of the templates, the template text is canonical — structure, comments, formatting, byte-for-byte — and the Renovate-managed scalars are grafted back onto it using stdlib Psych's node line/column coordinates (surgical rest-of-line replacement). Comment/format preservation holds by construction, and there's no new gem to install or trust.
Semantics
preserve_keys(default:uses,image,container,ruby-version,runs-on; extensible via the session config'smerge_github_workflows.preserve_keys) selects which mapping keys carry Renovate-managed values. The defaults cover the real-world cases from pupmod-simp-pupmod: dd98340 (ruby-version: 3.2 → 3.4.9) and 837fb5e (runs-on: ubuntu-20.04 → ubuntu-24.04), plus action refs and container images.[mapping path, key, identity], where identity is the part Renovate never changes (actions/checkout@v5→actions/checkout;ghcr.io/x/y:8→ghcr.io/x/y; bare versions → none). So: distinct versions per job survive independently; trailing comments ride along (pinned-digest conventions keep the human-readable version there); steps genuinely new to — or restored by — the template take the template's value, per the policy in the issue.merge_github_workflowsstage merges only files present in both the repo and the template chain (same per-module override resolution asprofile::github_actions). Creating and removing workflow files stays the profile's job, and repo-specific workflows with no template are never touched.Verification
pr_tests.ymltemplate, including byte-identity assertions ("output equals template except the grafted lines") and cases for pinned-digest comments, per-job version divergence, restored jobs, multi-file invocations, and idempotency. 167 examples total, 0 failures.file://fixture whosepr_tests.ymlhad Renovate bumps (checkout@v7,ruby-version: 3.4.9,ubuntu-24.04) and structural drift, plus an untemplatedcustom.yml: the merge restored template structure, preserved all 6+5+6 bumped values, leftcustom.ymluntouched, and run 2 reported0 ok / 1 unchanged / 0 failed. (A deliberately bumped value inside a commented-out template job was correctly reverted to template text — comments belong to the template.)puppet parser validate --tasks,bolt plan show, stage-list dry run, CI idempotency e2e all green. No CHANGELOG edit per the freeze.Completing #50
Once this and #70 merge, the closing move is a one-line Hiera flip (
profile::github_actions::strategy: bootstrapper project_type) plus closing the issue — I'd fold that into whichever merges last, or a tiny follow-up.Refs #50
🤖 Generated with Claude Code