fix(identity-check): resolve goreleaser_config repo-root-relative for monorepos - #15
Conversation
For a monorepo (atlassian-cli), each tool's packaging lives at tools/<tool>/packaging/, so identity-check must run with --working-dir tools/<tool>. But the goreleaser configs live at the repo root (.goreleaser-cfl.yml, with per-build `dir: tools/cfl`) and the reusable release.yml runs goreleaser from the repo root. Previously identity-check resolved goreleaser_config relative to --working-dir, so no single value satisfied both the working-dir packaging checks and the root-run release goreleaser — blocking the monorepo migration (#397). Make the resolution asymmetric (distribution.md §8.3): goreleaser_config resolves relative to a new --repo-root (default "."), while the tool-local identity (manifest, packaging/, version_file) stays working-dir-relative. Flat repos are unchanged (working-dir "." == repo root). The action gains a repo-root input (default "."). Adds two monorepo tests (root-relative goreleaser passes; a wrong working-dir-relative resolution is caught) and threads repo_root through the existing flat-repo tests. Closes #14
Add an action-level monorepo fixture (root .goreleaser-cfl.yml + tool-local tools/cfl/packaging) and an identity-monorepo CI job that runs the action with working-directory=tools/cfl and repo-root=root, proving the repo-root plumbing end-to-end. The existing self-contained golden fixtures (slck/gro/ nrq/jtk) are flat — pass repo-root == working-directory so their co-located goreleaser config still resolves after the resolution change.
|
Findings No blocking findings. The shape is correct and minimal:
I would not require After merge, moving |
TDD coverage assessmentOverall: strong. The core behavior change is well-exercised at both the unit and integration layers. Here is the breakdown: What is coveredAsymmetric resolution — the central change is guarded by two dedicated unit tests:
Flat-repo backward compatibility is proven implicitly by the 19 existing tests, all of which now pass Action-level plumbing (
Gaps worth naming
None of these gaps block the immediate use case (monorepo |
monit-reviewer
left a comment
There was a problem hiding this comment.
Automated PR Review
Reviewed commit: d49249e
Approved with 2 non-blocking suggestions below. Address at your discretion.
Summary
| Reviewer | Findings |
|---|---|
| harness-engineering:harness-architecture-reviewer | 1 |
| harness-engineering:harness-enforcement-reviewer | 1 |
harness-engineering:harness-architecture-reviewer (1 findings)
💡 Suggestion - actions/identity-check/identity.py:257
--repo-root is registered only under the validate subparser. If dispatch logic ever changes, cmd_validate will raise AttributeError on args.repo_root; and callers who try to pass --repo-root to export-json will receive an unrecognized-argument error rather than a clear diagnostic. A brief comment at the subparser registration explaining why export-json intentionally omits --repo-root (goreleaser is a validate-only concern) would prevent both surprises without changing the interface.
harness-engineering:harness-enforcement-reviewer (1 findings)
💡 Suggestion - tests/fixtures/identity/monorepo/tools/cfl/packaging/winget/OpenCLICollective.cfl.installer.yaml:1
Winget installer manifest is a minimal stub (PackageIdentifier only). This is sufficient for identity-check's current validation scope, but if identity-check ever validates additional required winget fields (PackageVersion, Installers, ManifestType, ManifestVersion), the fixture will generate false negatives. Worth noting for future fixture maintainers.
3 info-level observations excluded. Run with --verbose to include.
2 PR discussion threads considered.
Completed in 1m 42s | $0.46 | sonnet | daemon 0.2.121 | Glorfindel
| Field | Value |
|---|---|
| Model | sonnet |
| Reviewers | hybrid-synthesis, database:database-reviewer, harness-engineering:harness-architecture-reviewer, harness-engineering:harness-enforcement-reviewer, harness-engineering:harness-knowledge-reviewer, harness-engineering:harness-self-documenting-code-reviewer, security:security-code-auditor |
| Engine | claude · sonnet |
| Reviewed by | pr-review-daemon · monit-pr-reviewer |
| Duration | 1m 42s wall · 2m 29s compute (Reviewers: 39s · Synthesis: 1m 01s) |
| Cost | $0.46 |
| Tokens | 118.0k in / 10.2k out |
| Turns | 7 |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost |
|---|---|---|---|---|---|---|
| hybrid-synthesis | sonnet | 31.7k | 3.9k | 18.6k | 13.1k (1h) | $0.12 |
| database:database-reviewer | sonnet | 10.7k | 111 | 2.1k | 8.6k (1h) | $0.04 |
| harness-engineering:harness-architecture-reviewer | sonnet | 16.8k | 536 | 2.1k | 14.6k (1h) | $0.07 |
| harness-engineering:harness-enforcement-reviewer | sonnet | 16.8k | 363 | 2.1k | 14.6k (1h) | $0.07 |
| harness-engineering:harness-knowledge-reviewer | sonnet | 16.8k | 601 | 2.1k | 14.6k (1h) | $0.07 |
| harness-engineering:harness-self-documenting-code-reviewer | sonnet | 10.7k | 471 | 2.1k | 8.6k (1h) | $0.04 |
| security:security-code-auditor | haiku | 14.6k | 4.2k | 0 | 14.6k (1h) | $0.05 |
Re-reviews only run when @monit-reviewer is re-requested as a reviewer — push as many commits as you need, then re-request when ready. PRs targeting branches other than main, master are skipped, even when @monit-reviewer is re-requested.
| @@ -244,6 +257,11 @@ def main(argv: list[str] | None = None) -> int: | |||
| sp.add_argument("--manifest", default="packaging/identity.yml") | |||
There was a problem hiding this comment.
🔵 Low (harness-engineering:harness-architecture-reviewer): --repo-root is registered only under the validate subparser. If dispatch logic ever changes, cmd_validate will raise AttributeError on args.repo_root; and callers who try to pass --repo-root to export-json will receive an unrecognized-argument error rather than a clear diagnostic. A brief comment at the subparser registration explaining why export-json intentionally omits --repo-root (goreleaser is a validate-only concern) would prevent both surprises without changing the interface.
Reply to this thread when addressed.
| @@ -0,0 +1 @@ | |||
| PackageIdentifier: OpenCLICollective.cfl | |||
There was a problem hiding this comment.
🔵 Low (harness-engineering:harness-enforcement-reviewer): Winget installer manifest is a minimal stub (PackageIdentifier only). This is sufficient for identity-check's current validation scope, but if identity-check ever validates additional required winget fields (PackageVersion, Installers, ManifestType, ManifestVersion), the fixture will generate false negatives. Worth noting for future fixture maintainers.
Reply to this thread when addressed.
…§8.3) (#42) Document the asymmetric path resolution from open-cli-collective/.github#15.
The reusable release.yml chocolatey job hardcoded repo-root-relative
packaging/chocolatey paths, so a monorepo tool's
tools/<tool>/packaging/chocolatey could not be found. Add
working-directory: ${{ inputs.working-directory }} to the two steps that
reference those paths (the checksum-download step is path-agnostic and is
left alone). Flat repos pass ".", so resolution is unchanged.
Second monorepo gap surfaced during the atlassian-cli#397 survey, sibling
to the identity-check repo-root fix (#14/#15).
Closes #16
What
Makes
identity-checkresolvegoreleaser_configrelative to the repo root instead of--working-dir, unblocking the monorepo release migration (atlassian-cli#397). Implements the architect-recommended Option B.Closes #14.
Why
For a monorepo, each tool's packaging lives at
tools/<tool>/packaging/, soidentity-checkmust run with--working-dir tools/<tool>. But the goreleaser configs live at the repo root (.goreleaser-cfl.yml, with per-builddir: tools/cfl), and the reusablerelease.ymlruns goreleaser from the repo root. Previouslygoreleaser_configresolved relative to--working-dir, so no single value satisfied both the working-dir packaging checks and the root-run release goreleaser. Flat repos were unaffected, which is why slck/nrq/codereview migrated fine.Change (Option B)
Resolution is now asymmetric (distribution.md §8.3):
goreleaser_config→ relative to a new--repo-root(default.) — goreleaser is a repo-root release operation even in a monorepo (go.work, shared modules, root tags/dist).packaging/*,manifest-path,version_file→ stay--working-dir-relative (tool-local identity).Flat repos are unchanged (
working-dir.== repo root). A monorepo caller passesworking-directory: tools/cfland leavesrepo-rootat the default..identity.py:validate()gainsrepo_root;--repo-rootCLI arg (default.); docstring documents the split.action.yml: newrepo-rootinput (default.).test_identity.py: 2 new monorepo tests (root-relative goreleaser passes; a wrong working-dir-relative resolution is caught); existing flat-repo tests threadrepo_root.tests/fixtures/identity/monorepo/+identity-monorepoCI job exercising the action'srepo-rootplumbing end-to-end. Golden fixtures (slck/gro/nrq/jtk) passrepo-root == working-directory(they're flat/self-contained).cli-commondistribution.md§8.3 documents the asymmetry (companion doc PR).Proof
pytest -q: 21 passed (19 existing + 2 monorepo)..goreleaser-cfl.yml+tools/cfl/packaging:--working-dir tools/cfl --repo-root .→identity-check ok.Follow-up
After merge: cut
v1.1.0and re-point the moving@v1tag (backward-compatible — flat-repo behavior unchanged), then atlassian-cli#397 can migrate.