Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 24 additions & 39 deletions .github/workflows/auto-release.yml
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 }}
5 changes: 3 additions & 2 deletions .github/workflows/chocolatey-publish.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: Publish to Chocolatey

on:
release:
types: [published]
# Manual escape hatch only. The common-path Chocolatey publish is now handled by
# the reusable release.yml@v1's own manifest-driven channel job; the old
# `release: published` auto-trigger is removed to avoid double-publishing.
workflow_dispatch:
inputs:
version:
Expand Down
97 changes: 81 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Copy link
Copy Markdown

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.

Copy link
Copy Markdown
Contributor Author

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-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.

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
Expand All @@ -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:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

- 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 }}
Loading
Loading