ci: conform CI/CD to the shared repo/CI-CD standard#151
Conversation
Migrate CI onto the shared composite actions and release/distribution onto the reusable workflows (open-cli-collective/.github @v1), declaring identity once in packaging/identity.yml. Published package identities (cask google-readonly, winget/chocolatey/linux google-readonly) are unchanged. - New packaging/identity.yml: binary gro, goreleaser_config .goreleaser.yaml, tag prefix v, canonical_cask google-readonly (no alias), winget/choco/linux google-readonly, and a JSON keychain_probe using gro's `config show -j` control-plane flag (verified backend=keychain/auto locally). - ci.yml on composites: build-platform matrix + required build aggregate, go-test, go-lint, identity-check, pr-title; plus preserved required gates — a tidy job (go mod tidy + git diff --exit-code, from the old `make tidy test build`), the static-release build guard, and the make test-cover-check coverage floor (ci.md §6). - auto-release/release callers replace the hand-rolled pipelines; the reusable owns the darwin keychain-probe gate and the homebrew/winget/chocolatey/linux fan-out. - goreleaser homebrew_casks: skip_upload + tap token removed (the reusable homebrew step is the single tap writer); add release.replace_existing_artifacts; fix the mutating before-hook to fail on a dirty go.mod/go.sum. - Remove the orphaned snap/ (disabled job; distribution.md §7 — Linux via apt/rpm). - Demote chocolatey-publish/winget-publish to workflow_dispatch-only manual escape hatches (drop the release: published auto-trigger; the reusable now owns the common-path publish, avoiding double-publish). Closes #148
|
Findings Nit: PR body says the before-hook is Review Notes No code-level drift found. The implementation matches the converged plan:
|
Test Coverage AssessmentChange type: CI/CD migration — no Go production-code changes. Assessment is scoped to the verification surface that matters for workflow/packaging YAML. Gates in place
AssessmentCoverage is adequate for this change type. Every preserved gate from the pre-migration CI is accounted for, and the new No actionable gaps identified. |
monit-reviewer
left a comment
There was a problem hiding this comment.
Automated PR Review
Reviewed commit: b3d36aa
Summary
| Reviewer | Findings |
|---|---|
| harness-engineering:harness-architecture-reviewer | 1 |
| harness-engineering:harness-enforcement-reviewer | 2 |
| harness-engineering:harness-knowledge-reviewer | 1 |
harness-engineering:harness-architecture-reviewer (1 findings)
💡 Suggestion - .github/workflows/ci.yml:42
The 'build' aggregate gate passes when all needs results are 'skipped'. While intentional for skipped matrix legs, if the entire build-platform matrix were somehow skipped (e.g., a future path filter added upstream), the required 'build' gate would pass vacuously. Consider documenting this invariant or adding an explicit check that at least one leg ran, if the standard mandates it.
harness-engineering:harness-enforcement-reviewer (2 findings)
💡 Suggestion - .github/workflows/ci.yml:101
The
identity-checkjob callsopen-cli-collective/.github/actions/identity-check@v1with no precedingactions/checkoutstep. Every other job that reads repo files (tidy, static-release-guard, coverage) explicitly checks out first. If the composite action does not perform its own checkout internally, it will fail to findpackaging/identity.yml. Consider adding- uses: actions/checkout@v4as the first step unless the composite action's contract explicitly promises a self-checkout.
💡 Suggestion - .github/workflows/release.yml:16
The
workflow_dispatchinput was changed from a free-texttagto a booleandry-run, removing the ability to manually re-trigger a release for an arbitrary existing tag. If a release ever needs to be re-cut from a historical tag (e.g. to recover a failed publish), the manual escape hatch no longer exists in this workflow. The chocolatey/winget dispatch files retain tag inputs as manual escape hatches, but the primary goreleaser build does not.
harness-engineering:harness-knowledge-reviewer (1 findings)
packaging/identity.yml:8
archives.name_template declares 'gro_v{{ .Version }}{{ .Os }}{{ .Arch }}' but project_name in .goreleaser.yaml is 'google-readonly'. Unless .goreleaser.yaml already has a matching archives.name_template override, GoReleaser's default would produce 'google-readonly_{{ .Version }}...' — no 'gro' prefix and no 'v' infix. If the reusable release.yml@v1 uses this field to locate or verify published artifacts, the name mismatch will cause artifact lookup failures at release time.
2 info-level observations excluded. Run with --verbose to include.
2 PR discussion threads considered.
Completed in 1m 46s | $0.50 | sonnet | daemon 0.2.121 | Glorfindel
| Field | Value |
|---|---|
| Model | sonnet |
| Reviewers | hybrid-synthesis, harness-engineering:harness-architecture-reviewer, harness-engineering:harness-enforcement-reviewer, harness-engineering:harness-knowledge-reviewer |
| Engine | claude · sonnet |
| Reviewed by | pr-review-daemon · monit-pr-reviewer |
| Duration | 1m 46s wall · 4m 02s compute (Reviewers: 1m 21s · Synthesis: 22s) |
| Cost | $0.50 |
| Tokens | 94.7k in / 13.1k out |
| Turns | 4 |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost |
|---|---|---|---|---|---|---|
| hybrid-synthesis | sonnet | 35.8k | 1.5k | 18.6k | 17.2k (1h) | $0.10 |
| harness-engineering:harness-architecture-reviewer | sonnet | 19.6k | 3.8k | 2.1k | 17.5k (1h) | $0.13 |
| harness-engineering:harness-enforcement-reviewer | sonnet | 19.6k | 3.8k | 2.1k | 17.5k (1h) | $0.13 |
| harness-engineering:harness-knowledge-reviewer | sonnet | 19.6k | 4.0k | 2.1k | 17.5k (1h) | $0.14 |
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.
| tag: | ||
| prefix: v | ||
| version_scheme: major_minor_run_patch | ||
| archives: |
There was a problem hiding this comment.
🟡 Medium (harness-engineering:harness-knowledge-reviewer): archives.name_template declares 'gro_v{{ .Version }}{{ .Os }}{{ .Arch }}' but project_name in .goreleaser.yaml is 'google-readonly'. Unless .goreleaser.yaml already has a matching archives.name_template override, GoReleaser's default would produce 'google-readonly_{{ .Version }}...' — no 'gro' prefix and no 'v' infix. If the reusable release.yml@v1 uses this field to locate or verify published artifacts, the name mismatch will cause artifact lookup failures at release time.
Reply to this thread when addressed.
There was a problem hiding this comment.
Verified false positive: .goreleaser.yaml line 70 already declares archives.name_template: "gro_v{{ .Version }}_{{ .Os }}_{{ .Arch }}", identical to the manifest. identity-check enforces that the manifest template string-equals the goreleaser one and it passed in CI; the local goreleaser release --snapshot rendered gro_v* archives. No mismatch — no change.
| # own required check so the floor stays blocking (not advisory). | ||
| coverage: | ||
| runs-on: ubuntu-latest | ||
| steps: |
There was a problem hiding this comment.
🔵 Low (harness-engineering:harness-enforcement-reviewer): The identity-check job calls open-cli-collective/.github/actions/identity-check@v1 with no preceding actions/checkout step. Every other job that reads repo files (tidy, static-release-guard, coverage) explicitly checks out first. If the composite action does not perform its own checkout internally, it will fail to find packaging/identity.yml. Consider adding - uses: actions/checkout@v4 as the first step unless the composite action's contract explicitly promises a self-checkout.
Reply to this thread when addressed.
There was a problem hiding this comment.
False positive: the job's first step is - uses: actions/checkout@v4 (ci.yml line 111), immediately before the composite. The identity-check job passed in CI, which it couldn't without the checkout finding packaging/identity.yml. No change.
| - 'v*' | ||
| - "v*" | ||
| workflow_dispatch: | ||
| inputs: |
There was a problem hiding this comment.
🔵 Low (harness-engineering:harness-enforcement-reviewer): The workflow_dispatch input was changed from a free-text tag to a boolean dry-run, removing the ability to manually re-trigger a release for an arbitrary existing tag. If a release ever needs to be re-cut from a historical tag (e.g. to recover a failed publish), the manual escape hatch no longer exists in this workflow. The chocolatey/winget dispatch files retain tag inputs as manual escape hatches, but the primary goreleaser build does not.
Reply to this thread when addressed.
There was a problem hiding this comment.
Intentional — matches the family standard (slck#176/nrq#116 release callers): the manual knob is the dry-run boolean, and re-cutting a release from a historical tag is done by re-pushing that tag (the tag-push path re-triggers the reusable, which is idempotent via replace_existing_artifacts). The free-text tag input was specific to the old inline goreleaser job that this caller replaces. No change.
| # Preserve the pre-migration `make tidy test build` tidy gate: `make tidy` runs | ||
| # `go mod tidy && git diff --exit-code go.mod go.sum`, failing a PR whose module | ||
| # files aren't tidy. The go-build/go-test composites don't tidy, so this stays. | ||
| tidy: |
There was a problem hiding this comment.
🔵 Low (harness-engineering:harness-architecture-reviewer): The 'build' aggregate gate passes when all needs results are 'skipped'. While intentional for skipped matrix legs, if the entire build-platform matrix were somehow skipped (e.g., a future path filter added upstream), the required 'build' gate would pass vacuously. Consider documenting this invariant or adding an explicit check that at least one leg ran, if the standard mandates it.
Reply to this thread when addressed.
There was a problem hiding this comment.
Intentional — this is the codified ci.md §7 'build aggregate' pattern (identical in slck/nrq). build-platform carries no gating if:/path-filter, so all three OS legs always run; the aggregate can't pass vacuously today. The skip-tolerance exists only so a genuinely failed/cancelled leg fails the gate while a skipped one doesn't. Guarding a hypothetical future path filter would be speculative. No change.
What
Brings
google-readonlyinto conformance with the repo/CI-CD standard (flat-repo sibling of the merged slck#176 / nrq#116): CI on the shared composite actions, release/distribution on the reusable workflows (open-cli-collective/.github@v1), with identity declared once inpackaging/identity.yml.Published package identities are unchanged (acceptance): cask
google-readonly, wingetOpenCLICollective.google-readonly, chocolateygoogle-readonly, linuxgoogle-readonly— verified byidentity-check.Changes
packaging/identity.yml(new) — binarygro,goreleaser_config: .goreleaser.yaml, tag prefixv, the four channel identities above, and a JSONkeychain_probeusing gro'sconfig show -jcontrol-plane flag (the short JSON flag; not the global--output json). Faithful port of the INT-449 darwin gate (seeded config, assertsbackend=keychain/backend_source=auto/credential_ref=google-readonly/default).ci.ymlon composites (ci.md §7): non-requiredbuild-platformOS matrix + requiredbuildaggregate;test(go-test@v1),lint(go-lint@v1),identity-check,pr-title. Preserved required gates: atidyjob (the oldmake tidy test buildranmake tidy=go mod tidy && git diff --exit-code), thestatic-release-guard, and thecoveragefloor (make test-cover-check, ci.md §6 — kept blocking, not advisory)..goreleaser.yaml:homebrew_casksaddskip_upload: true+ remove the tap token (the reusable homebrew step is the single tap writer); addrelease.replace_existing_artifacts: true; fix the mutating before-hook to fail on a dirtygo.mod/go.sum(sh -c "go mod tidy && git diff --exit-code go.mod go.sum"). Nourl.template— flatvrepo, no tag rename.snap/(the disabledif: falsejob; distribution.md §7 — Linux ships via apt/rpm).chocolatey-publish.yml/winget-publish.ymltoworkflow_dispatch-only manual escape hatches (drop therelease: publishedauto-trigger now that the reusable owns the common-path publish — avoids double-publish).Out of scope
test-chocolatey.yml/test-winget.ymlleft as-is (post-merge packaging validation). Themake test-cover-checktarget's output redirection is gro's pre-existing Makefile trait (the visiblemake testin thetestjob is the diagnostic signal).Proof ladder (local)
goreleaser check+goreleaser release --snapshot→ rendersdist/homebrew/Casks/google-readonly.rb(binarygro, defaultvURL),skip_upload→ no tap push.identity-check validate— clean.release-preflight check-config --homebrew --tag-prefix v— ✅.config show -jin isolated HOME + seed →backend=keychain,source=auto,credential_ref=google-readonly/default.make tidy(clean) +make lint(0 issues) +make test-cover-check(70.7% ≥ 60%) +make build.Branch protection (post-merge): require
build,tidy,test,lint,static-release-guard,coverage,identity-check,pr-title.Closes #148