From 270739b96208e4560baa410b91f88f9db4b1b848 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sat, 22 Aug 2026 18:03:59 -0700 Subject: [PATCH 1/3] Add markdown-exclude-globs Input to validate-task.yml validate-task.yml's Lint Markdown step hardcoded '**/*.md' with no workflow_call input to narrow it, and .markdownlint-cli2.jsonc is verbatim/whole per spec/files.json, so a repo that vendors a theme or imports content it does not author (Blog's PaperMod theme and WordPress archive) had no way to keep the gate from linting prose it cannot fix. Adds an optional markdown-exclude-globs input, appended after '**/*.md' in the globs: block. Empty by default: the action's own globs.split(separator).filter(String) drops the resulting blank line, verified locally against markdownlint-cli2-action's dist source and against a live run. Fixes #924 Co-Authored-By: Claude Sonnet 5 --- .github/workflows/validate-task.yml | 15 +++++++++++++-- docs/reusable-workflows.md | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index 7b00aeb0..b0a57d79 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -3,10 +3,18 @@ name: Validate task # The fleet validation gate, hosted here once and reached by every repo's test-pull-request stub and its own publish-release stub. # Three jobs: lint (the fleet doc-lint block plus language lint by tree detection, the prose gate, and the repo gate), unit-test (a generic dotnet test or uv run pytest, skipped where the caller has no test project), and validate (the validate hook, a repo's own domain checks such as an ESPHome compile, a Hugo build, a KiCad ERC, a codegen-drift check, or PowerShell tests). # No permissions beyond contents: read where a job needs one, since every job here only checks out and reads. -# No required inputs, and CODECOV_TOKEN is the one optional secret, since coverage upload is best-effort. +# No required inputs, markdown-exclude-globs is the one optional input, and CODECOV_TOKEN is the one optional secret, since coverage upload is best-effort. # Hub-owned gates and default hooks resolve through $/ at the reusable workflow's commit, so each implementation is reproducible against the caller's released pin without a second checkout. on: workflow_call: + inputs: + # Appended after '**/*.md' rather than replacing it, so a caller only ever narrows the default rather than restating it. + # A repo that vendors a theme or imports content it does not author excludes that tree here instead of failing the gate on prose it cannot fix. + markdown-exclude-globs: + description: Extra globs for the Lint Markdown step, one per line (for example '!content/**'), appended after '**/*.md'. + required: false + type: string + default: '' secrets: CODECOV_TOKEN: required: false @@ -29,10 +37,13 @@ jobs: fetch-depth: 0 # The fleet doc-lint block, hosted once rather than carried by every repo of every type. + # An empty markdown-exclude-globs leaves a blank line here, which the action's own globs.split(separator).filter(String) drops, so the default caller passes nothing extra. - name: Lint Markdown step uses: DavidAnson/markdownlint-cli2-action@21c1be1b93ad9ed58fa840aacc3f279cde2a72ff # v24.2.0 with: - globs: '**/*.md' + globs: | + **/*.md + ${{ inputs.markdown-exclude-globs }} # The spell check covers README + HISTORY only, per CODESTYLE.md "Markdown and Spelling". - name: Spell check step diff --git a/docs/reusable-workflows.md b/docs/reusable-workflows.md index 1154588d..f0c900c9 100644 --- a/docs/reusable-workflows.md +++ b/docs/reusable-workflows.md @@ -349,6 +349,22 @@ jobs: done ``` +A repo that vendors a theme or imports content it does not author narrows the Lint Markdown step's glob instead. Blog carries a WordPress archive and the PaperMod theme, for instance. `.markdownlint-cli2.jsonc` is declared `"fidelity": "verbatim", "whole": true` in `spec/files.json`, so it is not locally editable: + +```yaml + validate: + name: Validate sources job + uses: ptr727/ProjectTemplate/.github/workflows/validate-task.yml@ # + permissions: + contents: read + with: + markdown-exclude-globs: | + !content/** + !themes/*/** +``` + +`validate-task.yml` appends each line after `**/*.md` in the Lint Markdown step's own `globs:` block. A caller only ever narrows the default this way, never restates or replaces it. + ## Adopting the Pure Functions Neither `get-version-task.yml` nor `publish-plan-task.yml` has a caller-stub snippet of its own, since a caller reaching either one is a job inside a repo's own `publish-release.yml` or a future `build-release-task.yml`, not a standalone top-level workflow. A repo whose publisher reads NBGV's version outputs directly, without carrying the whole release orchestrator, reaches `get-version-task.yml` by pin in place of its own copy: From dfbc99d108f5e4dd3d9199b0861e8a42014e4953 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sat, 22 Aug 2026 18:10:25 -0700 Subject: [PATCH 2/3] Fix Review Findings: markdown-exclude-globs Overclaims Only-Narrows Copilot review, confirmed on both threads: the input and doc wording said a caller 'only ever narrows' the default glob, but the mechanism is unvalidated string concatenation, so a non-negated line adds to what is linted instead of excluding it. Reworded the input description and the doc prose to state that plainly rather than the narrower, inaccurate claim. Also trims the input's own comment to one line per the repository's default. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/validate-task.yml | 5 ++--- docs/reusable-workflows.md | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index b0a57d79..41a6dbbf 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -8,10 +8,9 @@ name: Validate task on: workflow_call: inputs: - # Appended after '**/*.md' rather than replacing it, so a caller only ever narrows the default rather than restating it. - # A repo that vendors a theme or imports content it does not author excludes that tree here instead of failing the gate on prose it cannot fix. + # Appended after '**/*.md', not validated: a negated glob excludes, a non-negated one adds to what is linted. markdown-exclude-globs: - description: Extra globs for the Lint Markdown step, one per line (for example '!content/**'), appended after '**/*.md'. + description: Negated globs to exclude, one per line (for example '!content/**'), appended after '**/*.md'. A non-negated line adds to what is linted rather than narrowing it. required: false type: string default: '' diff --git a/docs/reusable-workflows.md b/docs/reusable-workflows.md index f0c900c9..bd269976 100644 --- a/docs/reusable-workflows.md +++ b/docs/reusable-workflows.md @@ -363,7 +363,7 @@ A repo that vendors a theme or imports content it does not author narrows the Li !themes/*/** ``` -`validate-task.yml` appends each line after `**/*.md` in the Lint Markdown step's own `globs:` block. A caller only ever narrows the default this way, never restates or replaces it. +`validate-task.yml` appends each line after `**/*.md` in the Lint Markdown step's own `globs:` block, unvalidated. A negated glob excludes, the intended use, but a non-negated one adds to what is linted rather than narrowing it. ## Adopting the Pure Functions From f3fdd7c01db410e85078b326a1d0cb9882e73334 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sat, 22 Aug 2026 18:14:13 -0700 Subject: [PATCH 3/3] Describe Observable Behavior Instead of Action Internals in Comment A suppressed CodeRabbit finding on the pushed diff: the comment named the action's internal split/filter call chain rather than the behavior a reader actually needs, blank lines are ignored, which stays true even if the action's internals change. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/validate-task.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/validate-task.yml b/.github/workflows/validate-task.yml index 41a6dbbf..7acc3260 100644 --- a/.github/workflows/validate-task.yml +++ b/.github/workflows/validate-task.yml @@ -36,7 +36,7 @@ jobs: fetch-depth: 0 # The fleet doc-lint block, hosted once rather than carried by every repo of every type. - # An empty markdown-exclude-globs leaves a blank line here, which the action's own globs.split(separator).filter(String) drops, so the default caller passes nothing extra. + # An empty markdown-exclude-globs leaves a blank line here, which the action ignores, so the default caller passes nothing extra. - name: Lint Markdown step uses: DavidAnson/markdownlint-cli2-action@21c1be1b93ad9ed58fa840aacc3f279cde2a72ff # v24.2.0 with: