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
4 changes: 4 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ jobs:

A library that bundles a small CLI keeps it in its own module (`cmd/<tool>/go.mod`), so library consumers do not inherit its dependencies. Pass `module-dir: cmd/<tool>` and `main-path: .` to `go-binary-release.yml`. No `go.work` is needed.

## Go version of release builds

`go-binary-release.yml` builds with the newest patch release of the Go minor version the module declares: `go 1.26.0` (or `go 1.26`) builds with the latest 1.26.x. A `toolchain` line counts when its minor version is newer. The `go` directive stays the floor for users; it does not pin the compiler of the shipped binaries, so a patch release of Go reaches them on the next release.

## Release notes via RELEASE.md

Both release workflows support an optional `RELEASE.md` file in the repo root. When a section matching the new tag is found, its content is used as the GitHub Release body. Otherwise a commit-log changelog is generated automatically.
Expand Down
42 changes: 40 additions & 2 deletions .github/workflows/go-binary-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,29 @@ jobs:
exit 1
fi

- name: Resolve Go version
id: go-version
shell: bash
env:
GO_MOD: go.mod
run: |
set -euo pipefail
# The newest patch of the Go minor the module declares (go 1.26.0 -> 1.26,
# built with the latest 1.26.x), or of its toolchain line if that is newer.
# Building with go.mod's exact version would ship old patch releases.
[ -f "$GO_MOD" ] || { echo "::error::$GO_MOD not found"; exit 1; }
minor() { sed -nE "s/^$1[[:space:]]+(go)?([0-9]+\.[0-9]+).*/\2/p" "$GO_MOD" | head -1; }
go=$(minor go); toolchain=$(minor toolchain)
[ -n "$go" ] || { echo "::error::no go directive in $GO_MOD"; exit 1; }
version=$(printf '%s\n%s\n' "$go" "$toolchain" | sed '/^$/d' | sort -t. -k1,1n -k2,2n | tail -1)
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Go $version (latest patch) from $GO_MOD"

- name: Set up Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod
go-version: ${{ steps.go-version.outputs.version }}
check-latest: true
cache: true
cache-dependency-path: |
go.sum
Expand Down Expand Up @@ -397,10 +416,29 @@ jobs:
- name: Checkout
uses: actions/checkout@v7

- name: Resolve Go version
id: go-version
shell: bash
env:
GO_MOD: ${{ inputs.module-dir }}/go.mod
run: |
set -euo pipefail
# The newest patch of the Go minor the module declares (go 1.26.0 -> 1.26,
# built with the latest 1.26.x), or of its toolchain line if that is newer.
# Building with go.mod's exact version would ship old patch releases.
[ -f "$GO_MOD" ] || { echo "::error::$GO_MOD not found"; exit 1; }
minor() { sed -nE "s/^$1[[:space:]]+(go)?([0-9]+\.[0-9]+).*/\2/p" "$GO_MOD" | head -1; }
go=$(minor go); toolchain=$(minor toolchain)
[ -n "$go" ] || { echo "::error::no go directive in $GO_MOD"; exit 1; }
version=$(printf '%s\n%s\n' "$go" "$toolchain" | sed '/^$/d' | sort -t. -k1,1n -k2,2n | tail -1)
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Go $version (latest patch) from $GO_MOD"

- name: Set up Go
uses: actions/setup-go@v7
with:
go-version-file: ${{ inputs.module-dir }}/go.mod
go-version: ${{ steps.go-version.outputs.version }}
check-latest: true
cache: true
cache-dependency-path: |
go.sum
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/selftest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,11 @@ jobs:
steps:
- uses: actions/checkout@v7
- run: scripts/selftest/release-notes.sh

go-version:
name: Release Go version resolution
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v7
- run: scripts/selftest/go-version.sh
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ This repository follows **otfabric/engineering policy 1.2**, profile **infrastru
| anything | `go run ./cmd/otfabric-policy check <this repository>` from otfabric/engineering |
| `go-ci.yml` policy steps | `scripts/selftest/policy.sh` |
| release notes extraction | `scripts/selftest/release-notes.sh` |
| the Go version of release builds | `scripts/selftest/go-version.sh` |
| `docs-check.yml` docsync step | `scripts/selftest/docs-check.sh` |
| a workflow | the Selftest workflow, on the pull request |

Expand Down
56 changes: 56 additions & 0 deletions scripts/selftest/go-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Cases of the "Resolve Go version" step of go-binary-release.yml, run on the
# go.mod fixtures with the exact step script. Both copies of the step (the
# prepare job and the build job) must be the same script.
set -euo pipefail

root=$(cd "$(dirname "$0")/../.." && pwd)
wf="$root/.github/workflows/go-binary-release.yml"
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

python3 "$root/scripts/selftest/extract-step.py" "$wf" "Resolve Go version" > "$work/step.sh"
count=$(grep -c -- '- name: Resolve Go version' "$wf")
[ "$count" = 2 ] || { echo "FAIL want 2 Resolve Go version steps, got $count"; exit 1; }
# extract-step.py prints the first step; check the second has the same run block.
python3 - "$wf" "$work/step.sh" <<'EOF'
import sys
lines = open(sys.argv[1]).read().split("\n")
first = open(sys.argv[2]).read().strip()
starts = [i for i, l in enumerate(lines) if l.strip() == "- name: Resolve Go version"]
blocks = []
for i in starts:
j = next(k for k in range(i, len(lines)) if lines[k].strip() == "run: |")
ind = len(lines[j]) - len(lines[j].lstrip())
body = []
for l in lines[j + 1:]:
if l.strip() and len(l) - len(l.lstrip()) <= ind:
break
body.append(l[ind + 2:] if l.strip() else "")
blocks.append("\n".join(body).strip())
if len(set(blocks)) != 1 or blocks[0] != first:
sys.exit("FAIL the two Resolve Go version steps differ")
EOF

fail=0
check() { # fixture want-exit want-version
local got=0 out="$work/out"
: > "$work/output"
GO_MOD="$root/testdata/go-version/$1.go.mod" GITHUB_OUTPUT="$work/output" bash -e "$work/step.sh" > "$out" 2>&1 || got=$?
local version
version=$(sed -n 's/^version=//p' "$work/output")
if [ "$got" = "$2" ] && [ "$version" = "$3" ]; then
echo "ok $1: exit $got, version '${version}'"
else
echo "FAIL $1: exit $got version '${version}', want exit $2 version '$3'"; cat "$out"; fail=1
fi
}

check patch 0 1.26
check minor 0 1.26
check toolchain-newer 0 1.27
check toolchain-same 0 1.27
check two-digit 0 1.10
check no-go 1 ""
check missing 1 ""
exit $fail
3 changes: 3 additions & 0 deletions testdata/go-version/minor.go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module example.com/a

go 1.26
1 change: 1 addition & 0 deletions testdata/go-version/no-go.go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module example.com/a
3 changes: 3 additions & 0 deletions testdata/go-version/patch.go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module example.com/a

go 1.26.0
5 changes: 5 additions & 0 deletions testdata/go-version/toolchain-newer.go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module example.com/a

go 1.26.0

toolchain go1.27.3
5 changes: 5 additions & 0 deletions testdata/go-version/toolchain-same.go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module example.com/a

go 1.27.1

toolchain go1.27.3
5 changes: 5 additions & 0 deletions testdata/go-version/two-digit.go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module example.com/a

go 1.9

toolchain go1.10.2
Loading