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
7 changes: 5 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"

Expand All @@ -40,6 +40,8 @@ jobs:

- name: Upload Pages artifact
if: github.ref == 'refs/heads/main'
# Pinned: no node24 major published yet (upload-pages-artifact internally
# pins node20 upload-artifact). Not on the flip-cut path. Bump when released.
uses: actions/upload-pages-artifact@v3
with:
path: site
Expand All @@ -59,4 +61,5 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
# Pinned: no node24 major published yet. Not on the flip-cut path. Bump when released.
uses: actions/deploy-pages@v4
6 changes: 3 additions & 3 deletions .github/workflows/install-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ jobs:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
fetch-depth: 0

- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: "1.22"

# Build the release tarballs + checksums.txt locally without publishing.
# The runner's native-OS tarball is what install.sh below consumes.
- name: Snapshot release tarballs
uses: goreleaser/goreleaser-action@v6
uses: goreleaser/goreleaser-action@v7
with:
version: "~> v2"
args: release --snapshot --clean --skip=publish,homebrew
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/next-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "1.22"

Expand Down
26 changes: 13 additions & 13 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Cuts a GitHub Release on every v* tag: goreleaser cross-builds the darwin
# arm64+amd64 tarballs, writes checksums.txt, publishes the release, and bumps
# the homebrew-tap formula. Runs on macOS so the released darwin binaries are
# built natively.
# Cuts a GitHub Release on every v* tag: goreleaser cross-builds the darwin and
# linux arm64+amd64 tarballs, writes checksums.txt, publishes the release, and
# bumps the homebrew-tap formula. Runs on macOS so the darwin binaries are built
# natively (CGO_ENABLED=0, so the linux tarballs cross-compile on the same host).
name: release

on:
Expand All @@ -26,12 +26,12 @@ jobs:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "1.22"

Expand Down Expand Up @@ -100,15 +100,15 @@ jobs:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
# Full history + tags so `git rev-list -1 "$GITHUB_REF_NAME"` resolves
# the tagged commit SHA the gate binds the green-run match to.
fetch-depth: 0
fetch-tags: true

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "1.22"

Expand All @@ -129,19 +129,19 @@ jobs:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
# Full history + tags so `git describe --tags` resolves the version
# goreleaser stamps into internal/cli.Version. fetch-tags: true is
# required so annotated-tag bodies (the release notes consumed by the
# next step's `git tag -l --format='%(contents:body)'`) reach the
# runner — actions/checkout@v4's default is false, which leaves the
# runner — actions/checkout@v5's default is false, which leaves the
# tag ref but drops the tag object.
fetch-depth: 0
fetch-tags: true

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: "1.22"

Expand All @@ -155,7 +155,7 @@ jobs:
- name: Extract release notes from the tag body
run: |
set -euo pipefail
# Re-fetch the tag annotation explicitly — actions/checkout@v4 sometimes
# Re-fetch the tag annotation explicitly — actions/checkout@v5 sometimes
# drops the tag object even with fetch-tags: true, leaving %(contents:body)
# empty. A bare git fetch of the ref forces the annotation through.
git fetch origin "+refs/tags/${GITHUB_REF_NAME}:refs/tags/${GITHUB_REF_NAME}" --force
Expand All @@ -172,7 +172,7 @@ jobs:
fi

- name: Run goreleaser
uses: goreleaser/goreleaser-action@v6
uses: goreleaser/goreleaser-action@v7
with:
version: "~> v2"
args: release --clean --release-notes ${{ runner.temp }}/release-notes.txt
Expand Down
28 changes: 14 additions & 14 deletions .github/workflows/runtime-live-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ jobs:
offline:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: "1.22"

Expand Down Expand Up @@ -108,13 +108,13 @@ jobs:
exit 1
fi

- uses: actions/checkout@v4
- uses: actions/checkout@v5

- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: "1.22"

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: "20"

Expand Down Expand Up @@ -194,7 +194,7 @@ jobs:

- name: Upload live artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: runtime-live-e2e-claude-live-${{ matrix.model }}
path: |
Expand Down Expand Up @@ -225,13 +225,13 @@ jobs:
exit 1
fi

- uses: actions/checkout@v4
- uses: actions/checkout@v5

- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: "1.22"

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: "20"

Expand Down Expand Up @@ -315,7 +315,7 @@ jobs:

- name: Upload live artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: runtime-live-e2e-codex-live
path: |
Expand Down Expand Up @@ -343,13 +343,13 @@ jobs:
exit 1
fi

- uses: actions/checkout@v4
- uses: actions/checkout@v5

- uses: actions/setup-go@v5
- uses: actions/setup-go@v6
with:
go-version: "1.22"

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: "20"

Expand Down Expand Up @@ -422,7 +422,7 @@ jobs:

- name: Upload live artifacts
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: runtime-live-e2e-pi-live
path: |
Expand Down
83 changes: 83 additions & 0 deletions internal/release/goreleaser_guard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,86 @@ func readGoreleaserConfig(t *testing.T) string {
}
return string(data)
}

// goosOf returns the distinct goos tokens .goreleaser.yaml builds — the
// independent oracle the release.yml header must not contradict.
func goosOf(targets map[buildTarget]bool) []string {
seen := map[string]bool{}
for tgt := range targets {
seen[tgt.os] = true
}
var oses []string
for o := range seen {
oses = append(oses, o)
}
sort.Strings(oses)
return oses
}

// leadingCommentBlock returns the file's leading `#` comment lines (up to the
// first non-comment, non-blank line) joined into one string — the workflow
// header the doc-accuracy check inspects.
func leadingCommentBlock(content string) string {
var header []string
for _, line := range strings.Split(content, "\n") {
trimmed := strings.TrimSpace(line)
if strings.HasPrefix(trimmed, "#") {
header = append(header, line)
continue
}
if trimmed == "" {
continue
}
break
}
return strings.Join(header, "\n")
}

// goosMissingFromHeader returns the build OSes that the header text fails to
// name — the doc-vs-config drift the guard catches.
func goosMissingFromHeader(header string, oses []string) []string {
var missing []string
for _, o := range oses {
if !strings.Contains(header, o) {
missing = append(missing, o)
}
}
return missing
}

// TestReleaseHeaderNamesEveryBuildOS locks AC-2: release.yml's file-header comment
// names every goos .goreleaser.yaml actually builds, so the header cannot claim a
// darwin-only build while the config cross-builds linux too. The oracle is the
// parsed build set (not header prose), so a header that drops `linux` reds even
// though the file still mentions `darwin`.
func TestReleaseHeaderNamesEveryBuildOS(t *testing.T) {
oses := goosOf(parseGoreleaserBuildTargets(readGoreleaserConfig(t)))
if len(oses) == 0 {
t.Fatal("parsed no goos from .goreleaser.yaml; the header check has no oracle to bind")
}
header := leadingCommentBlock(readReleaseWorkflow(t))
if header == "" {
t.Fatal("release.yml has no leading comment header to check")
}
if missing := goosMissingFromHeader(header, oses); len(missing) > 0 {
t.Errorf("release.yml header omits build OS %s while .goreleaser.yaml builds %s; header:\n%s",
strings.Join(missing, ", "), strings.Join(oses, ", "), header)
}
}

// TestReleaseHeaderGuardRejectsDarwinOnly proves the guard is load-bearing: a
// header with `linux` removed (the pre-task darwin-only shape) must fail the
// name-every-OS check against a config that still builds linux.
func TestReleaseHeaderGuardRejectsDarwinOnly(t *testing.T) {
oses := goosOf(parseGoreleaserBuildTargets(readGoreleaserConfig(t)))
header := leadingCommentBlock(readReleaseWorkflow(t))

darwinOnly := strings.ReplaceAll(header, "linux", "")
if darwinOnly == header {
t.Fatal("release.yml header has no `linux` token to strip; the load-bearing check cannot bind")
}
if missing := goosMissingFromHeader(darwinOnly, oses); len(missing) == 0 {
t.Fatalf("stripping `linux` from the header did not trip the guard; it is not load-bearing (oses=%s)",
strings.Join(oses, ", "))
}
}
Loading
Loading