feat: actionlint and check-jsonschema composite actions - #13
Merged
Conversation
Phase 2 of the CI de-duplication program, first pair: the two single-tool step lanes that lift as composite actions (D1). - actionlint: self-contained curl + sha256 install (v1.7.12), the repo's single-binary idiom; auto-discovers .github/workflows and lints embedded run: scripts via the runner's shellcheck. Optional color/config-file/ version/sha256 inputs (D4 open-closed). - check-jsonschema: ephemeral uvx run (v0.37.3) like ruff/pyright. One invocation = one schema source (builtin-schema | schemafile) + N files; callers invoke once per schema group. Config-light — the tool reads no config file, so no standards module (research note records this). Dogfooded behind ci-status: actionlint lints this repo's own workflows; check-jsonschema validates dependabot.yml (vendor.dependabot) and the workflow files (vendor.github-workflows). The ci-status aggregation loop is rewritten with read -ra so it passes actionlint's shellcheck integration. Both verified locally with the exact CI invocations (actionlint+shellcheck 0.11.0 clean; uvx check-jsonschema validations pass). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kyle-sexton
added a commit
that referenced
this pull request
Jul 16, 2026
## Summary Step 1 of 3 for decision #13 (`metadata-do-not-merge-wire-or-walk-back`, Decisions Log: https://claude.ai/code/artifact/232ecdce-8316-4880-8c0a-dc3c7dcf3a63). - `do-not-merge-gate.yml`: a new reusable workflow mirroring `semantic-pr.yml`'s shape exactly (same `prerequisite-result` fail-closed pattern, same runner-selection input). Fails the job while the calling PR carries a configured label (default `do-not-merge`). - README: documents the canonical caller block, matching the existing `semantic-pr` doc entry's format. ## Why a new reusable workflow, not a ruleset rule `github-iac`'s `Labels.cs` has declared `do-not-merge` as a "Hard merge gate" since it was introduced, but nothing has ever enforced it. GitHub Rulesets have **no native label-condition rule type** — confirmed empirically by enumerating every `OrganizationRulesetRules*` type in the `pulumi-github` v6.14.0 provider assembly. A required-status-check is the only real mechanism, so this follows the exact precedent `pr-title`/`semantic-pr` already established in this repo. ## Re-evaluation on label change A status check binds to a SHA. If it runs once (no label) and passes, then someone adds `do-not-merge`, nothing re-runs and the merge isn't actually blocked. The canonical caller block triggers on `labeled`/`unlabeled` (in addition to `opened`/`reopened`/`synchronize`/`merge_group`) specifically so the gate re-fires when the label is toggled. ## Rollout sequencing (this PR is step 1 only) 1. **This PR** — land the reusable workflow. 2. Once merged, add the canonical caller to every `requires-ci` repo (9 repos: `.github`, `ci-runner`, `ci-workflows`, `claude-code-plugins`, `github-iac`, `medley`, `standards`, `dotfiles`, `provisioning`), pinned to this PR's merge commit SHA. 3. Only after all 9 callers are merged and emitting the check: add `do-not-merge / do-not-merge` to `github-iac`'s `ci-gate` `RequiredStatusChecks` (OrgRulesets.cs) — never before, per this repo's own documented rule ("open PRs block on a check that never runs"). Scope confirmed with the repo owner: `requires-ci` repos only (not the 6 `RequiresCi: false` archived/content repos), caller-workflow mechanism (not `required_workflows`, since that ruleset primitive's re-evaluation-on-label-toggle behavior is unverified). ## Verification - `actionlint .github/workflows/do-not-merge-gate.yml` — clean. - `zizmor .github/workflows/do-not-merge-gate.yml` — no findings. - Repo's own lefthook pre-commit hooks passed at commit time. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 2 of the CI de-duplication program — first pair: the two single-tool step lanes that lift as composite actions (architecture D1).
What
actionlint— GitHub Actions workflow linter. Self-containedcurl+sha256install (v1.7.12, hash corroborated by the upstreamchecksums.txtand an independent local compute), the repo's established single-binary idiom (shellcheck/editorconfig/lychee-offline). Bare run auto-discovers.github/workflows; the runner's shellcheck lints embeddedrun:scripts. Optionalcolor/config-file/version/sha256inputs (D4 open-closed).check-jsonschema— JSON/YAML schema validator. Ephemeraluvx check-jsonschema@0.37.3(theruff/pyrightidiom). One invocation = one schema source (builtin-schemaorschemafile) + N files; a caller validates several schema groups by invoking once per group. Config-light — the tool reads no config file of its own, so nostandardsmodule is created (recorded in the research note).Lift source & posture
Lifted from medley's
yaml-ci.yml(actionlint1.7.12; check-jsonschema multi-invocation pattern). Behavior preserved; backfilled optional inputs.Config boundary
Neither tool needs upstream config. Both run config-light in their lifted form — no new
standardsmodule required for either (flagged per the program's config-boundary rule).Dogfood (behind
ci-status)actionlintlints this repo's own workflows (strong dogfood).check-jsonschemavalidatesdependabot.yml(vendor.dependabot) and the workflow files (vendor.github-workflows).ci-statusaggregation loop is rewritten withread -raso it passes actionlint's shellcheck integration (root-cause fix, no suppression).Verification
Both verified locally with the exact CI invocations:
actionlint -color+ shellcheck 0.11.0 (the runner's version) clean; bothuvx check-jsonschemavalidations pass.Research
docs/dedup-program/research/actionlint.md,docs/dedup-program/research/check-jsonschema.md(versions/assets/checksums/invocation, all verified against official sources 2026-06-23).🤖 Generated with Claude Code