feat: add reusable lint.yml workflow (SK-415)#6
Conversation
Author the Layer-2 lint bundle: reusable-lint.yml (`on: workflow_call`) composes the shared Layer-1 lint composite actions (eslint, lint-markdown, lint-yaml, changelog-validate) in one job that pays `setup-project` once, per ADR 0001 §5.7. Each sub-check has a boolean opt-out input so a consumer drops a check without leaving the bundle. Prettier is deferred (no `prettier` composite action exists; not in §5.7's canonical bundle). The composite actions are referenced by full cross-repo path, SHA-pinned to their commit on main — a `workflow_call` job's local `./` paths resolve against the caller's workspace, and the full-path form is also what populates `github.action_path` for lint-yaml's centralised `.yamllint.yml` injection.
|
Claude finished @RobEasthope's task in 1m 58s —— View job Code Review
CI: passing ✅ — the This is a clean, well-structured PR. The main deliverable ( Open finding: mutable tag in local install hintsThe one outstanding CodeRabbit finding is technically valid but warrants nuance. CI and the composite action use the commit-pinned SHA ( The counterargument — which I find reasonable — is that these are human-facing hints printed when a developer doesn't have actionlint installed locally. The developer runs the command manually; it isn't automated. More importantly, Given that, this is genuinely minor. Two sensible paths forward:
Either is fine. This shouldn't block the merge. Fix this → Minor observations (non-blocking)Bootstrap pin maintenance — all five action
Boolean→string bridge on What's correct
The PR looks ready to merge once the CodeRabbit finding is acknowledged (either way). |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a reusable lint workflow with configurable ESLint, markdown, YAML, and changelog checks, updates repository guidance for Layer-2 workflow composition, and bumps actionlint pins across workflow and local hook entry points. ChangesReusable lint workflow
actionlint version pins
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/reusable-lint.yml:
- Around line 139-166: Update the reusable lint workflow to use bracket notation
for every hyphenated input reference in the job steps, since expressions like
inputs.foo-bar are invalid. In the YAML step definitions for node-version-file,
eslint-args, markdown-globs, yaml-paths, yamllint-version, actionlint-version,
and changelog-script, switch to the corresponding inputs['...'] form so the
workflow parses and validates correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9f88dc4e-3ecc-447b-a09f-356097d38b79
📒 Files selected for processing (2)
.github/workflows/reusable-lint.ymlCLAUDE.md
actionlint 1.7.5 has a false positive — it reports `context "inputs" is not allowed here` for expressions under a step's `with: args:` (and `entrypoint:`), the Docker-action reserved inputs. Upstream fixed it in v1.7.6. The new reusable-lint.yml forwards the `eslint` composite action's `args` input dynamically, so it tripped the bug in CI. Bump deliberately in lockstep (SK-422) across every pin: ci.yml, the lint-yaml composite action default + installer SHA, reusable-lint.yml's default, and the lint-staged / pre-push install hints. Re-pinned the installer to the v1.7.12 commit (914e7df). Aligns CI with the version local dev already runs (Homebrew 1.7.12).
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@package.json`:
- Line 48: The local actionlint install hints in package.json and the pre-push
hook still point to the mutable v1.7.12 tag, which should be aligned with the
commit-pinned URL used elsewhere. Update the actionlint fallback message in
package.json and the matching hint in pre-push to reference the same pinned
download-actionlint.bash URL as .github/workflows/ci.yml and
.github/actions/lint-yaml/action.yml so all guidance stays consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: a938159c-f017-481c-a4eb-ed89ae95ffb7
📒 Files selected for processing (5)
.github/actions/lint-yaml/action.yml.github/workflows/ci.yml.github/workflows/reusable-lint.yml.husky/pre-pushpackage.json
Clarify the `changelog` input contract (flagged in review): a consumer without a dated changelog must set `changelog: false`, otherwise the default `pnpm changelog:validate` step fails on first adoption.
## What Reconstructs `shared-workflows`' **entire release history** and graduates the current code to a stable **`v1.0.0`** (A-585). The repo publishes no npm package, so a "release" here is a **git tag (`vX.Y.Z`) + GitHub release** over the reusable workflows and composite actions. ## Versioning methodology The merged PR **titles are not reliable** — Conventional-Commit discipline was loose when the repo was stood up (the GO/NO GO gate shipped as `ci:`, the versioned ruleset as `chore:`). So every PR was re-classified by **what it actually changed to the product surface** (the `reusable-*.yml` workflows + `.github/actions/*` consumers use, and their reference docs), read from the diff. Pre-1.0 rules: `feature` → minor, `fix` → patch, breaking → minor (stay in `0.x`), and `1.0.0` is a deliberate "graduate to stable" milestone. | Version | PR | True category | Headline | |---|---|---|---| | 0.1.0 | #1 | feature | bootstrap: 3 reusable workflows | | 0.2.0 | #5 | feature | Layer-1 composite-action layer | | 0.3.0 | #6 | feature | reusable-lint bundle | | 0.4.0 | #7 | feature | reusable build-test bundle + `build` action | | 0.4.1 | #8 | fix | repoint build-test pins so the build lane resolves | | 0.5.0 | #9 | feature | reusable pkg-release workflow | | 0.6.0 | #15 | refactor **(breaking)** | rename release → pkg-release | | 0.7.0 | #16 | **feature** *(titled `ci:`)* | GO/NO GO aggregator gate + docs | | 0.8.0 | #17 | **feature** *(titled `chore:`)* | versioned canonical estate ruleset | | 1.0.0 | HEAD | milestone | graduate to stable public surface | Non-release PRs (self-host CI, ADR, dep bump, SK→A rename, skill adoptions/re-syncs, check-run rename) are folded into the body of the release window they merged in — the way a release-please changelog aggregates. ## Changes - **`changelog/`** — hand-authored dated entries (one per release) + the schema doc (`changelog/README.md`), adapted from the estate's `eslint-config`/`agent-skills` convention. - **`package.json`** — `0.0.0` → `1.0.0` (stays `private`; the version is the release anchor, not an npm publish). - **`reusable-lint.yml`** — pin the five sibling Layer-1 actions to the **`v0.8.0`** tag (`@7f543be`) instead of the bare pre-release commit, so Dependabot can track them (`v0.8.0` is the latest backfilled tag that carries every action and predates this commit, avoiding a self-reference to `v1.0.0`). - **`CLAUDE.md` / `README`** — replace the "no release tag exists yet" wording. ## After merge The git tags + GitHub releases are cut once this lands: `v0.1.0`–`v0.8.0` at their historical merge commits, `v1.0.0` at this PR's squash-merge commit, with notes sourced from each `changelog/` entry. This unblocks consumers pinning a tag (+ Dependabot) instead of a moving SHA (A-420 / A-446). ## Deferred (follow-up) - **release-please automation** + a tag-only release workflow — the forward release process is a separate decision now the backfill exists. ## Note for review > Backfilling git tags at historical commits is a deliberate divergence from the estate precedent (`eslint-config`/`agent-skills` backfilled changelog *entries* but tagged only going forward) — chosen here because A-585 explicitly wants the *full tag history* reconstructed. The pre-existing Prettier drift on the vendored `.claude`/`.agents` skill bundles is untouched (out of scope). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Marked the reusable workflows and composite actions as stable at **v1.0.0**. * Updated workflow references to use the newer version tags. * **Documentation** * Clarified release and versioning guidance across the repository. * Added and expanded changelog documentation and release notes structure. * **Chores** * Updated internal workflow pins to the latest approved release. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
What
Authors the Layer-2 lint bundle:
reusable-lint.yml(on: workflow_call) — one job that payssetup-projectonce, then composes the shared Layer-1 lint composite actions:eslintlint-markdownlint-yaml(yamllint + actionlint)changelog-validateper ADR 0001 §5.7. Consumer repos drop their per-repo lint jobs and call this instead (SHA-pinned + Dependabot).
Why these decisions
eslint: false,markdown: false,yaml: false,changelog: false) — §5.7's first opt-out rung: drop a sub-check without leaving the bundle (e.g.agent-skillsrunseslint: falseuntil SK-394). The remaining inputs are thin pass-throughs to each composite action, fed in a caller stub from the consumer'srepo-config.yaml.prettiercomposite action to compose and it is not in §5.7's canonical bundle. Added later when an action exists../.github/actions/…: inside aworkflow_calljob a./path resolves against the caller's workspace, not this repo (community #18601), andsha_pinning_requiredrejects an unpinned local ref. The full-path form is also what populatesgithub.action_pathsolint-yaml's centralised.yamllint.ymlinjection resolves (SK-438).mainat132d746; there are no release tags yet, so eachuses:pins to that commit. Documented inCLAUDE.md; the release process maintains it once tags land.HUSKY: 0,persist-credentials: false, rootpermissions: {}+ least-privilege job — mirrors the existing reusable workflows andci.yml.Verification
This repo deliberately does not dogfood the reusable workflow (same
sha_pinning_requiredcircularity that inlinesci.yml/claude.yml), so it is validated statically here; true end-to-end exercise is deferred to a consumer (npm-package-template, SK-413/424):actionlint(schema + expressions)yamllint(centralised config; only unavoidable line-length warnings on the SHA-pinneduses:lines, same as the existing Claude workflows)prettier --checkmarkdownlintCloses SK-415.
Summary by CodeRabbit
actionlintto v1.7.12 across CI, composite action defaults, and developer tooling (including pre-push and lint-staged fallbacks).