Skip to content

Fix: stop the pre-commit hook rewriting generator-owned files, and check the hook's glob in CI - #636

Open
AmaadMartin wants to merge 2 commits into
mainfrom
fix/prettier-ignore-generated-files
Open

Fix: stop the pre-commit hook rewriting generator-owned files, and check the hook's glob in CI#636
AmaadMartin wants to merge 2 commits into
mainfrom
fix/prettier-ignore-generated-files

Conversation

@AmaadMartin

@AmaadMartin AmaadMartin commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):
    Closes: #issue_number
    Related: #issue_number
  2. Or, if no issue exists, describe the change:

Problem:

Two related defects in the repository's formatting setup, both reproduced against
this checkout with the Prettier version that resolves from the committed lockfile
(prettier@3.8.4).

1. The pre-commit hook rewrites release-please-generated changelogs.
package.json maps **/*.{json,md} to prettier --write in its lint-staged
block, and .prettierignore listed only dist/, node_modules/ and
dev/src/browser. The three changelogs release-please owns
(release-please-config.json sets changelog-path: CHANGELOG.md for core, dev
and integrations) were therefore in scope, and none of them is Prettier-clean —
Prettier rewrites release-please's * bullets to - and strips its blank lines:

File Lines rewritten by prettier --write File length
core/CHANGELOG.md 264 341
dev/CHANGELOG.md 136 288
integrations/CHANGELOG.md 23 34

So a contributor who appends two lines to a changelog and commits gets a staged
diff of +11/-14 on integrations/CHANGELOG.md — the real change buried under
formatting noise nobody asked for.

2. Nothing enforces the formatting the hook writes. format:check was
prettier "**/*.ts" --check, and .github/workflows/validation.yaml runs it on
ubuntu/windows/macos. JSON and Markdown were never checked in CI even though the
hook formats them, so the tree had drifted: four hand-authored files were not
Prettier-clean, and any contributor who happened to stage one of them picked up an
unrelated reformat in their PR.

Solution:

.prettierignore — ignore the files a generator owns:

  • CHANGELOG.md, bare. .prettierignore uses gitignore pattern syntax, so this
    matches every package changelog at any depth and keeps matching when a new
    workspace package is added. This is the fix for defect 1. Prettier applies
    .prettierignore even to paths passed explicitly on the command line, which is
    exactly how lint-staged invokes it, so the hook now reproduces the author's
    edit byte for byte.
  • package-lock.json. To be explicit about why, since it would otherwise look like
    a bug fix it is not: Prettier does not currently reformat the lockfile.
    Prettier maps the filenames package.json and package-lock.json to its
    json-stringify parser, which emits exactly JSON.stringify(value, null, 2)
    byte-identical to what npm itself writes. Verified here: npx prettier package-lock.json is byte-identical to the file on disk, and the file is
    byte-identical to JSON.stringify(JSON.parse(src), null, 2) + "\n". The entry is
    a forward-looking guard: once format:check matches **/*.json, CI would
    start checking a 566 KB npm-generated artifact on three operating systems, and
    any future change in npm's serializer would surface as a bogus formatting
    failure. npm owns the file.

package.json — widen format and format:check from **/*.ts to
**/*.{ts,json,md}, i.e. exactly the file set the pre-commit hook formats, so the
formatting the hook writes is the formatting CI enforces and the tree cannot
silently drift again. Only those two string values changed; the lint-staged
block, .prettierrc.js, .husky/pre-commit and validation.yaml are untouched
(validation.yaml already runs npm run format:check, so it picks the wider glob
up for free).

Four hand-authored files — reformatted by running npx prettier --write on
exactly those paths, with no hand edits. This is the whole backlog the widened
check surfaces:

File Change
.github/ISSUE_TEMPLATE/bug_report.md - bullets, blank line before an ordered list, trailing newline
.github/ISSUE_TEMPLATE/feature_request.md drops a blank line inside the YAML front matter, trailing newline
.vscode/settings.json removes a trailing comma (which is not valid JSON)
dev/README.md adds the missing trailing newline

The generated changelogs are deliberately left byte-for-byte as release-please
wrote them — cleaning them up here would be the exact noise this change exists to
prevent.

Cost. The widened check is slower, measured on this machine as the mean of
three runs with a warm node_modules: **/*.ts 15.6 s → **/*.{ts,json,md}
16.9 s, i.e. +1.3 s per CI leg.

Collision check. All 535 open PRs on the fork were listed and the plausibly
adjacent ones diffed. Two touch the same files but neither lands this change:

This PR was not stacked on either, deliberately: the two of them modify
.prettierignore in mutually exclusive ways, so there is no single base that
covers both; and #552's base chain reaches into core/src TypeScript, which would
drag unrelated changes into a diff that is meant to contain no TypeScript at all.
Both overlaps are single-line textual conflicts that resolve trivially for whichever
lands second.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.

No test file is added, and that is not an oversight. This change adds zero
lines of executable code — it is two glob strings, two .prettierignore patterns,
and Prettier's own output on four documents. A *_test.ts that shells out to
Prettier to assert its own config would be testing Prettier, not ADK. The
verification below is run against the real husky + lint-staged pipeline
instead, and each check was also run in a state where it fails, so none of it is
a green light with no signal.

Unit Tests:
[ ] I have added or updated unit tests for my change. — no executable code is
added; see above.
[x] All unit tests pass locally. — unchanged by this PR (no TypeScript is
touched). npm run lint exits 0; the widened check is the gate that matters
and is covered below.

1. The widened check passes on the resulting tree.

$ npm run format:check
> prettier "**/*.{ts,json,md}" --check
Checking formatting...
All matched files use Prettier code style!    # exit 0

2. Generated files are genuinely out of scope (this is how lint-staged
invokes Prettier — explicit paths):

$ npx prettier --write core/CHANGELOG.md dev/CHANGELOG.md \
    integrations/CHANGELOG.md package-lock.json
                                              # no output, exit 0
$ git status --porcelain                      # empty

3. Package manifests are still in scope and still clean — guards against the
bare package-lock.json pattern over-matching:

$ npx prettier --check package.json core/package.json \
    dev/package.json integrations/package.json
All matched files use Prettier code style!    # exit 0

Also confirmed through the API, which needs the ignore file passed explicitly:
getFileInfo(f, {ignorePath: '.prettierignore'}) reports ignored: true for the
three changelogs and package-lock.json, and ignored: false for all four
package.json files and .release-please-manifest.json.

4. Nothing else regressed. npm run lint exits 0.

Proof the checks can fail

Regression proof for defect 1 — real git commit through .husky/pre-commit:

$ printf '\n<!-- scratch -->\n' >> integrations/CHANGELOG.md
$ git add integrations/CHANGELOG.md && git commit -m "probe"
$ git show --numstat --format= HEAD -- integrations/CHANGELOG.md
2   0   integrations/CHANGELOG.md      # with this change

The committed content still carries release-please's * bullets, unmodified. Same
sequence before this change: 11 14.

Attribution mutation — revert only the two .prettierignore entries, change
nothing else, re-run the real hook:

11  14   integrations/CHANGELOG.md

So the .prettierignore entries, and not the script change, are what fix defect 1.

Mutation proof for defect 2 — drift a Markdown file, then run both globs:

$ printf 'trailing drift   \n\n\n\n' >> dev/README.md
$ npm run format:check                  # new glob
[warn] dev/README.md
[warn] Code style issues found in the above file.     # exit 1
$ npx prettier "**/*.ts" --check        # the glob on main
All matched files use Prettier code style!            # exit 0

The old glob would have shipped that drift; the widened one catches it.

Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.

From a clean checkout of this branch:

npm ci

# A. The hook no longer rewrites a generator-owned file.
printf '\n<!-- scratch -->\n' >> integrations/CHANGELOG.md
git add integrations/CHANGELOG.md
npx lint-staged
git diff --cached --numstat -- integrations/CHANGELOG.md   # expect: 2  0
git reset --hard HEAD

# B. The hook still formats a hand-authored Markdown/JSON file.
printf 'drift   \n\n\n\n' >> dev/README.md
git add dev/README.md
npx lint-staged
git diff --cached -- dev/README.md    # Prettier normalised it
git reset --hard HEAD

# C. CI's gate is satisfied.
npm run format:check                  # exit 0

CI result. run-tests passed on all three legs (ubuntu-latest,
windows-latest, macos-latest). The Windows leg was the one worth watching, since
.prettierrc.js sets endOfLine: "auto" and the brace glob has to survive
PowerShell; its Run format check step reports All matched files use Prettier code style!, so the widened glob is fine there.

The first Windows attempt failed in the earlier Run tests and check code coverage step — tests/integration/a2a/input_required/input_required_test.ts,
Error: CLI exited prematurely with code 1 at
tests/integration/test_case_utils.ts:341 — with 0 failing tests (2677
passed, 1 failed suite). That is the known Windows spawned-server flake, not
this change: this diff contains no TypeScript and no test file, so there is no
path by which two npm script strings, two .prettierignore lines and four
reformatted documents reach a spawned CLI subprocess. It passed on re-run without
any code change.

api-reference/ was checked and is not a hazard for the widened glob: typedoc
emits zero .json/.md/.ts files (verified by generating it), and CI's
docs:check runs typedoc --emit none after format:check anyway.

Checklist

[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas. — the one
comment added is the # Generated files: owned by their generators, not Prettier. header in .prettierignore.
[x] I have added tests that prove my fix is effective or that my feature works. —
as executable verification against the real hook rather than a test file; see
"Proof the checks can fail" above for the mutations and their failure output.
[x] New and existing unit tests pass locally with my changes.

Amaad Martin added 2 commits August 4, 2026 06:47
…glob in CI

The pre-commit hook maps `**/*.{json,md}` to `prettier --write`, but
`.prettierignore` listed only build output, so the release-please-generated
`CHANGELOG.md` files were in scope. Staging a two-line note on
`integrations/CHANGELOG.md` produced a +11/-14 staged diff; `core/CHANGELOG.md`
loses 264 of its 341 lines to the same rewrite. Ignore `CHANGELOG.md` (bare, so
it matches every workspace package now and in future) so the hook reproduces the
author's edit exactly.

Widen `format`/`format:check` to the same `**/*.{ts,json,md}` glob the hook
formats, so the formatting the hook writes is the formatting CI enforces and the
tree cannot silently drift again.

`package-lock.json` is ignored as a forward-looking guard for that widened
check: Prettier does not reformat it today (it routes `package.json` and
`package-lock.json` to the `json-stringify` parser, whose output is
byte-identical to npm's own serialization), but npm owns the file and it should
not become a CI formatting failure on three operating systems.
Produced by `npx prettier --write` on exactly these four paths, with no hand
edits. They are the entire backlog the widened `format:check` surfaces: JSON and
Markdown were never checked in CI even though the pre-commit hook formats them,
so these had drifted out of the standard the hook applies. `.vscode/settings.json`
also carried a trailing comma, which is not valid JSON.
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.

1 participant