Give new-version an MSI's new ProductCode, and refuse to copy a stale one #19

Merged
jeff merged 1 commit from product-code into main 2026-10-14 03:15:13 -05:00
Owner

Closes #18.

  • Refusal: if an installer being copied has a ProductCode and no new one is given for its architecture, new-version fails and writes nothing. The check runs before any installer is downloaded. It refuses in the same way for any DisplayVersion in the installer file, which there's no way to give, and for a ProductCode at the top that applies to every installer.
  • --product-code ARCHITECTURE={GUID}: repeatable. It replaces that installer's code, written in single quotes like the hand-written manifest, because an unquoted {...} is a YAML mapping. It's checked to be a GUID in braces, and it's refused for an architecture with no --installer or whose installer has no ProductCode.
  • Compatibility: --json output and every existing option are unchanged (ADR 0004). The refusal changes behavior only for a package with a ProductCode, which today means only Harrier, where copying it was wrong.
  • Docs: CONTRIBUTING describes both.

Why now

Harrier's release.yaml already submits, and JCOllie.Harrier 0.1.0 is published. Without this, Harrier's next release would open a submission carrying 0.1.0's ProductCode, and it would pass its check. With this merged, that release's winget job fails at new-version instead, until jeff/winget-submit#6 passes the code through.

Tested

  • 9 new unit tests. The test that copies every package in the repository now covers Harrier, passing a code.
  • End to end on a copy of the tree, with Harrier's published 0.1.0 MSI standing in for a new release:
    • without --product-code, it refuses, exit 1;
    • with nope, it refuses, exit 1;
    • with a GUID, it writes 0.1.1 from 0.1.0, changing only PackageVersion and ProductCode. The stand-in MSI and today's date match 0.1.0's, so the URL, hash and date don't show in the diff. check --changed-since reports 0 problems.
    • Clipwatch, which has no ProductCode, still writes as before.

🤖 Generated with Claude Code

https://claude.ai/code/session_01D31MsLkM9DkCauP1EB2zgw

Closes #18. - **Refusal:** if an installer being copied has a `ProductCode` and no new one is given for its architecture, `new-version` fails and writes nothing. The check runs before any installer is downloaded. It refuses in the same way for any `DisplayVersion` in the installer file, which there's no way to give, and for a `ProductCode` at the top that applies to every installer. - **`--product-code ARCHITECTURE={GUID}`:** repeatable. It replaces that installer's code, written in single quotes like the hand-written manifest, because an unquoted `{...}` is a YAML mapping. It's checked to be a GUID in braces, and it's refused for an architecture with no `--installer` or whose installer has no `ProductCode`. - **Compatibility:** `--json` output and every existing option are unchanged (ADR 0004). The refusal changes behavior only for a package with a `ProductCode`, which today means only Harrier, where copying it was wrong. - **Docs:** CONTRIBUTING describes both. ## Why now Harrier's `release.yaml` already submits, and `JCOllie.Harrier` 0.1.0 is published. Without this, Harrier's next release would open a submission carrying 0.1.0's `ProductCode`, and it would pass its check. With this merged, that release's `winget` job fails at `new-version` instead, until jeff/winget-submit#6 passes the code through. ## Tested - 9 new unit tests. The test that copies every package in the repository now covers Harrier, passing a code. - End to end on a copy of the tree, with Harrier's published 0.1.0 MSI standing in for a new release: - without `--product-code`, it refuses, exit 1; - with `nope`, it refuses, exit 1; - with a GUID, it writes 0.1.1 from 0.1.0, changing only `PackageVersion` and `ProductCode`. The stand-in MSI and today's date match 0.1.0's, so the URL, hash and date don't show in the diff. `check --changed-since` reports 0 problems. - Clipwatch, which has no `ProductCode`, still writes as before. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01D31MsLkM9DkCauP1EB2zgw
give new-version an MSI's new ProductCode, and refuse to copy a stale one
All checks were successful
test / test (pull_request) Successful in 1m45s
test / publish (pull_request) Has been skipped
ee62b15f81
An MSI built with Product Id="*" has a new ProductCode every release, so
copying it made the new version claim the old one's product, and check
did not notice. `--product-code ARCHITECTURE={GUID}` now replaces it,
and an installer with a ProductCode and none given is refused before
anything is downloaded or written. So is a DisplayVersion, which there
is no way to give, and a ProductCode at the top for every installer.

Closes #18

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01D31MsLkM9DkCauP1EB2zgw
jeff scheduled this pull request to auto merge when all checks succeed 2026-10-14 03:13:38 -05:00
jeff merged commit 509ec1ca2e into main 2026-10-14 03:15:13 -05:00
jeff deleted branch product-code 2026-10-14 03:15:13 -05:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jeff/winget-pkgs!19
No description provided.