-
Notifications
You must be signed in to change notification settings - Fork 1
ci: conform CI/CD to the shared repo/CI-CD standard #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,32 @@ | ||
| name: Auto Release | ||
|
|
||
| # On push to main, decide whether to cut a release and mint the tag. Identity | ||
| # (tag prefix + version file) comes from packaging/identity.yml. The release gate | ||
| # (Go-code paths + feat/fix commit) and the version.txt + GITHUB_RUN_NUMBER tag | ||
| # scheme are handled by the shared reusable workflow; this caller wires triggers | ||
| # and secrets. | ||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| # Gate 1: Only trigger when Go code actually changes | ||
| paths: | ||
| - '**.go' | ||
| - 'go.mod' | ||
| - 'go.sum' | ||
| branches: [main] | ||
| workflow_dispatch: | ||
| inputs: | ||
| dry-run: | ||
| description: "Compute the tag but do not push it" | ||
| type: boolean | ||
| default: true | ||
|
|
||
| # The tag push uses the dedicated TAP_GITHUB_TOKEN via a credential helper, not | ||
| # GITHUB_TOKEN — so the pushed tag retriggers release.yml. | ||
| permissions: | ||
| contents: write | ||
| contents: read | ||
|
|
||
| jobs: | ||
| create-release: | ||
| runs-on: ubuntu-latest | ||
| # Gate 2: Only release for feat: and fix: commits (actual functionality changes) | ||
| if: >- | ||
| startsWith(github.event.head_commit.message, 'feat:') || | ||
| startsWith(github.event.head_commit.message, 'feat(') || | ||
| startsWith(github.event.head_commit.message, 'fix:') || | ||
| startsWith(github.event.head_commit.message, 'fix(') | ||
| steps: | ||
| # TAP_GITHUB_TOKEN (a PAT) is required here instead of the default GITHUB_TOKEN | ||
| # because tag pushes made with GITHUB_TOKEN do not trigger other workflows. | ||
| # Without this, the Release workflow would not run when we push the tag. | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.TAP_GITHUB_TOKEN }} | ||
|
|
||
| - name: Read version | ||
| id: version | ||
| run: | | ||
| BASE_VERSION=$(cat version.txt | tr -d '\n') | ||
| VERSION="v${BASE_VERSION}.${GITHUB_RUN_NUMBER}" | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "Creating release: $VERSION" | ||
|
|
||
| - name: Create and push tag | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git tag ${{ steps.version.outputs.version }} | ||
| git push origin ${{ steps.version.outputs.version }} | ||
| auto-release: | ||
| uses: open-cli-collective/.github/.github/workflows/auto-release.yml@v1 | ||
| with: | ||
| # push is live (false); workflow_dispatch honors the checkbox. Compare | ||
| # against both true and 'true' because a workflow_dispatch boolean input | ||
| # may surface as a real boolean or the string "true" depending on context. | ||
| dry-run: ${{ github.event_name == 'workflow_dispatch' && (inputs.dry-run == true || inputs.dry-run == 'true') }} | ||
| secrets: | ||
| tag-token: ${{ secrets.TAP_GITHUB_TOKEN }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,21 +4,77 @@ on: | |
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
|
|
||
| concurrency: | ||
| group: ci-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| build-and-test: | ||
| runs-on: ubuntu-latest | ||
| build-platform: # OS matrix — NOT a required check | ||
| name: build (${{ matrix.os }}) | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: [ubuntu-latest, macos-latest, windows-latest] | ||
| runs-on: ${{ matrix.os }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: open-cli-collective/.github/actions/go-build@v1 | ||
| with: | ||
| go-version-file: go.mod | ||
|
|
||
| build: # required aggregate — stable bare name | ||
| needs: [build-platform] | ||
| if: ${{ always() }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| # Fail only on a real failure/cancellation; a skipped leg must NOT fail | ||
| # the gate (which `== 'success'` would do). | ||
| - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} | ||
| run: echo "::error::a build-platform leg failed or was cancelled" && exit 1 | ||
|
|
||
| # 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: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: '1.26' | ||
| go-version-file: go.mod | ||
| - run: make tidy | ||
|
|
||
| - name: Tidy, test, and build | ||
| run: make tidy test build | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: open-cli-collective/.github/actions/go-test@v1 | ||
| with: | ||
| go-version-file: go.mod | ||
|
|
||
| lint: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: open-cli-collective/.github/actions/go-lint@v1 | ||
| with: | ||
| go-version-file: go.mod | ||
|
|
||
| # Regression sentinel (preserved): the shared go-build@v1 matrix legs build with | ||
| # default CGO and would NOT catch a static-linux regression. This cross-compiles | ||
| # the release targets CGO-off and asserts the static build graph never pulls in | ||
| # the 1Password/keyring stack. Kept required to preserve its blocking semantics. | ||
| static-release-guard: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-go@v5 | ||
| with: | ||
| go-version-file: go.mod | ||
| - name: Static release build guard | ||
| run: | | ||
| set -euo pipefail | ||
|
|
@@ -32,24 +88,33 @@ jobs: | |
| for goarch in amd64 arm64; do | ||
| deps=$(CGO_ENABLED=0 GOOS=linux GOARCH="$goarch" go list -deps ./cmd/gro) | ||
| if printf '%s\n' "$deps" | grep -E '^(github.com/byteness/keyring|github.com/1password/onepassword-sdk-go)(/|$)'; then | ||
| echo "static Linux $goarch build graph must not include byteness/keyring or onepassword-sdk-go" | ||
| echo "static Linux gro $goarch build graph must not include byteness/keyring or onepassword-sdk-go" | ||
| exit 1 | ||
| fi | ||
| done | ||
|
|
||
| - name: Coverage gate | ||
| run: make test-cover-check | ||
|
|
||
| lint: | ||
| # Preserve gro's opt-in coverage floor (ci.md §6): `make test-cover-check` runs | ||
| # the suite with -race + coverage and fails below the 60% threshold. Kept as its | ||
| # own required check so the floor stays blocking (not advisory). | ||
| coverage: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 Low (harness-engineering:harness-enforcement-reviewer): The Reply to this thread when addressed.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. False positive: the job's first step is |
||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: '1.26' | ||
| go-version-file: go.mod | ||
| - run: make test-cover-check | ||
|
|
||
| identity-check: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: open-cli-collective/.github/actions/identity-check@v1 # distribution.md §8.2 | ||
|
|
||
| - name: golangci-lint | ||
| uses: golangci/golangci-lint-action@v7 | ||
| pr-title: | ||
| if: github.event_name == 'pull_request' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: open-cli-collective/.github/actions/pr-title@v1 | ||
| with: | ||
| version: v2.12.2 | ||
| title: ${{ github.event.pull_request.title }} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intentional — this is the codified ci.md §7 'build aggregate' pattern (identical in slck/nrq).
build-platformcarries no gatingif:/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.