Skip to content

feat(cache): add top-level refresh subcommand (#146) #36

feat(cache): add top-level refresh subcommand (#146)

feat(cache): add top-level refresh subcommand (#146) #36

Workflow file for this run

name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to build (e.g., v1.0.0)'
required: true
type: string
permissions:
contents: write
jobs:
goreleaser:
# INT-449: darwin must build with cgo (Keychain backend). cgo+darwin
# cannot cross-compile from Linux, so this job runs on macOS. Pinned
# image (not the moving macos-latest label) for a reproducible release.
runs-on: macos-15
env:
TAG: ${{ github.ref_name || inputs.tag }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.TAG }}
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: "1.26"
- name: Install GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: "~> v2"
install-only: true
- name: GoReleaser check
run: goreleaser check
- name: Build (snapshot, no publish)
run: goreleaser release --snapshot --clean
# INT-449 pre-publish gate: prove the darwin binaries actually carry
# the Keychain backend BEFORE anything is published. A CGO_ENABLED=0
# darwin build links no Security.framework and fails closed at
# runtime; this gate makes that impossible to ship silently.
- name: Pre-publish gate — darwin Keychain backend present
run: |
set -euo pipefail
art=dist/artifacts.json
arm_bin=$(jq -r '.[]|select(.type=="Binary" and .goos=="darwin" and .goarch=="arm64")|.path' "$art")
amd_bin=$(jq -r '.[]|select(.type=="Binary" and .goos=="darwin" and .goarch=="amd64")|.path' "$art")
[ -n "$arm_bin" ] && [ -n "$amd_bin" ] || { echo "missing a darwin binary in artifacts.json"; exit 1; }
# darwin archives: exactly one per arch, no duplicate names
tot=$(jq '[.[]|select(.type=="Archive" and .goos=="darwin")|.name]|length' "$art")
uniq=$(jq '[.[]|select(.type=="Archive" and .goos=="darwin")|.name]|unique|length' "$art")
[ "$tot" = "$uniq" ] || { echo "duplicate darwin archive names"; exit 1; }
[ "$(jq '[.[]|select(.type=="Archive" and .goos=="darwin" and .goarch=="arm64")]|length' "$art")" = 1 ] || { echo "expected exactly one darwin/arm64 archive"; exit 1; }
[ "$(jq '[.[]|select(.type=="Archive" and .goos=="darwin" and .goarch=="amd64")]|length' "$art")" = 1 ] || { echo "expected exactly one darwin/amd64 archive"; exit 1; }
# Mach-O arch sanity (both slices)
file "$arm_bin" | grep -q 'arm64' || { echo "arm64 binary is not arm64 Mach-O"; exit 1; }
file "$amd_bin" | grep -q 'x86_64' || { echo "amd64 binary is not x86_64 Mach-O"; exit 1; }
lipo -archs "$arm_bin" | grep -qw arm64 || { echo "lipo: arm64 slice missing"; exit 1; }
lipo -archs "$amd_bin" | grep -qw x86_64 || { echo "lipo: x86_64 slice missing"; exit 1; }
# amd64 cannot run on the arm64 runner: assert Security.framework
# is linked. CGO_ENABLED=0 omits it entirely, so its presence is a
# sound *necessary* cgo signal for the slice we can't execute.
otool -L "$amd_bin" | grep -q '/System/Library/Frameworks/Security.framework' \
|| { echo "amd64 binary not linked against Security.framework (cgo missing)"; exit 1; }
# arm64 authoritative functional check: with no backend override
# and a seeded config, credstore must auto-select the Keychain.
# config.yml lives under $XDG_CONFIG_HOME/google-readonly/config.yml.
# -u GOOGLE_READONLY_KEYRING_BACKEND: derived from DirName
# "google-readonly" upper-snake-cased.
tmp=$(mktemp -d)
mkdir -p "$tmp/xdg/google-readonly"
printf 'credential_ref: google-readonly/default\n' > "$tmp/xdg/google-readonly/config.yml"
out=$(env -u GOOGLE_READONLY_KEYRING_BACKEND HOME="$tmp" XDG_CONFIG_HOME="$tmp/xdg" "$arm_bin" config show -j)
echo "$out"
b=$(echo "$out" | jq -r '.backend'); s=$(echo "$out" | jq -r '.backend_source'); r=$(echo "$out" | jq -r '.credential_ref')
[ "$b" = "keychain" ] && [ "$s" = "auto" ] && [ "$r" = "google-readonly/default" ] \
|| { echo "GATE FAIL: backend=$b source=$s ref=$r (want keychain/auto/google-readonly/default)"; exit 1; }
echo "GATE OK: darwin/arm64 backend=keychain source=auto; darwin/amd64 Security.framework linked"
- name: Release notes
run: |
set -euo pipefail
cat > "$RUNNER_TEMP/release-notes.md" <<'EOF'
### macOS Keychain storage restored
Builds since the credential-store migration were compiled without
cgo and failed closed on macOS (no Keychain backend). This release
builds the darwin binaries with cgo enabled, restoring native
macOS Keychain storage. Upgrade and re-run your normal commands;
no other action is required.
EOF
- name: Release (publish)
run: goreleaser release --clean --release-notes="$RUNNER_TEMP/release-notes.md"
env:
# TAP_GITHUB_TOKEN (PAT) is required here instead of the default
# GITHUB_TOKEN because releases created with GITHUB_TOKEN do not fire
# downstream workflow triggers (release: published). Using the PAT
# lets chocolatey-publish.yml and winget-publish.yml auto-trigger.
GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
- name: Verify release notes published
env:
GH_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
run: |
set -euo pipefail
body=$(gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json body -q .body)
if ! printf '%s' "$body" | grep -q 'macOS Keychain'; then
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --notes-file "$RUNNER_TEMP/release-notes.md"
fi
# Snap is temporarily disabled — waiting for personal-files interface approval.
snap:
if: false
needs: goreleaser
runs-on: ubuntu-latest
env:
TAG: ${{ github.ref_name || inputs.tag }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.TAG }}
fetch-depth: 0
- name: Set snap version from tag
run: |
VERSION="${TAG#v}"
sed -i "s/^version: git$/version: '${VERSION}'/" snap/snapcraft.yaml
echo "Snap version: ${VERSION}"
grep '^version:' snap/snapcraft.yaml
- name: Build snap
uses: snapcore/action-build@v1
id: build
- name: Publish to Snapcraft Store
uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
with:
snap: ${{ steps.build.outputs.snap }}
release: stable
linux-packages:
needs: goreleaser
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Trigger linux-packages repo update
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.LINUX_PACKAGES_DISPATCH_TOKEN }}
repository: open-cli-collective/linux-packages
event-type: package-release
client-payload: |-
{
"package": "google-readonly",
"version": "${{ github.ref_name }}",
"repo": "open-cli-collective/google-readonly"
}