Skip config-distributed files in consumer repos when updating copyright#31
Conversation
In repositories that consume the shared `config` submodule, the PostToolUse copyright hook re-stamped headers of files that `./config/pull` distributes and overwrites — e.g. repeatedly stamping TeamDev's proprietary header over the Apache header of a `buildSrc` source in `delivery-server`. `update_copyright.py` now detects a consumer repo (its `.gitmodules` declares a submodule at `config`) and excludes what `config`'s `migrate` script distributes: `buildSrc/**` except the consumer-owned `module.gradle.kts`; the root `gradle.properties`, `.codecov.yml`, and `lychee.toml`; and workflows whose basename the submodule carries in `.github/workflows/` or `.github-workflows/`. When the submodule is not checked out, the comparison is impossible and workflow files keep being stamped. The `config` and `agents` source repositories declare no such submodule, so their behavior is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the update-copyright skill’s script to detect “consumer” repositories (those with a config submodule) and avoid re-stamping copyright headers on files that are distributed/overwritten by that shared config repo.
Changes:
- Add consumer-repo detection via
.gitmodulesand skip config-distributed paths (root files,buildSrc/**with a single exception, and certain.github/workflows/*when matched by basename in the submodule). - Add unit tests covering consumer vs. source repo behavior, workflow matching, unchecked-out submodule fallback, and bulk tracked-files mode.
- Update the skill documentation to describe the new exclusion behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| skills/update-copyright/scripts/update_copyright.py | Adds consumer-repo detection and applies config-distribution exclusions in the path expansion chokepoint. |
| skills/update-copyright/tests/test_update_copyright.py | Adds coverage for the new consumer-repo exclusion rules and workflow matching behavior. |
| skills/update-copyright/SKILL.md | Documents the new behavior for consumer repositories and the distributed-file skip set. |
| credentials.properties | Removes the file from the repository. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Skill bodies must read the same for any agent runtime (Claude, Codex, Junie); "PostToolUse hook" is Claude Code vocabulary. Use the skill's own step-1 phrasing — the automatic follow-up run after edits — as requested in the Copilot review of PR #31. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 371f71932d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
What
skills/update-copyright/scripts/update_copyright.pynow detects a consumer repository — one whose root.gitmodulesdeclares a submodule withpath = config— and excludes the files thatconfig'smigratescript distributes into it:buildSrc/**, except exactlybuildSrc/src/main/kotlin/module.gradle.kts(consumer-owned;migratepreserves/restores it). Siblings such asjvm-module.gradle.ktsstay skipped.gradle.properties,.codecov.yml, andlychee.toml..github/workflows/<name>when theconfigsubmodule carries a workflow of the same basename in.github/workflows/or.github-workflows/. Repo-specific workflows (includingconfig:replacesvariants, which use a different basename) keep being stamped. When the submodule is not checked out, the comparison is impossible and workflow files are treated as consumer-owned (stamped) — the same fallbackwhich-fixerdocuments forCONTRIBUTING.md.The check is wired into
is_excluded()and applied inexpand_requested_paths(), the chokepoint both invocation modes flow through — the automatic follow-up run after edits (single-file paths) and the bulktracked_filesmode. In theconfigandagentssource repositories (noconfigsubmodule) behavior is unchanged: theirbuildSrc/etc. are project-owned and keep being stamped.Why
In consumer repos, the copyright follow-up re-stamped headers of config-distributed files using the consumer's default IntelliJ copyright profile. Concrete incident: in the proprietary
delivery-serverrepo, fixing a Gradle 9 deprecation inbuildSrc/.../KoverConfig.ktcaused the automation to repeatedly stamp TeamDev's proprietary header over the file's Apache header; it had to be bypassed to finish the fix. Those files are Apache-licensed, config-owned, and overwritten on every./config/pull.The skip-set mirrors the authoritative distribution list in
config'smigratescript and the identical set already documented inskills/which-fixer/SKILL.mdstep 2, including its warning: paths are never skipped merely because a same-named file exists somewhere under theconfig/submodule.Also in this branch
The branch carries a pre-existing cleanup commit (4a85b32) removing
credentials.propertiesfrom the repository root. The file was a leftover secret-scanner test fixture with placeholder content (FAKEprivate key) — nothing sensitive, in the file or in history.Verification
python3 -m unittest discover -s skills/update-copyright/tests: 8/8 pass (3 pre-existing + 5 new). New cases cover: consumer repo skips abuildSrcsibling but updatesmodule.gradle.kts; a repo without the submodule updatesbuildSrcas before; distributed vs. repo-specific workflows (both submodule source dirs); the not-checked-out fallback; and a bulk run skippingbuildSrc+ rootgradle.properties. Skipped fixtures carry stale headers so an "unchanged" assertion proves exclusion, not a no-op.delivery-serverincident (consumer fixture, TeamDev profile, Apache-headeredbuildSrc/.../KoverConfig.kt, single-file invocation with an absolute path) → "Updated 0 file(s)", header preserved.version.gradle.kts); no Gradle build in this repo.review-docsapproved with changes; its wording items were applied in 1346b23 together with the matching Copilot review comment (agent-neutral phrasing instead of runtime-specific hook vocabulary).🤖 Generated with Claude Code