test(go): resolve Box provenance by name (#195) #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Go module release | |
| # After a go/ sync (or API change) merges to main, cut the next go/vX.Y.Z tag | |
| # and GitHub Release. Requires an initial manual go/v0.1.0 tag first. | |
| on: | |
| push: | |
| branches: [main] | |
| # Everything the module publishes, minus what it does not. Stated as | |
| # subtraction so a new source file releases by default; an allowlist of | |
| # filenames silently stops releasing the day someone adds one. Later | |
| # patterns win, so the negations must stay below 'go/**'. | |
| paths: | |
| - 'go/**' | |
| - '!go/*_test.go' | |
| - '!go/**/*_test.go' | |
| - '!go/internal/**' | |
| - '!go/README.md' | |
| - '!go/check.sh' | |
| workflow_dispatch: | |
| inputs: | |
| bump: | |
| description: Semver bump (patch, minor, major) | |
| required: true | |
| default: patch | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| concurrency: | |
| group: go-module-release | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.AGENT_PAT || secrets.GITHUB_TOKEN }} | |
| - uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: go/go.mod | |
| cache-dependency-path: | | |
| go/go.mod | |
| go/internal/gen/go.sum | |
| - name: Resolve next version | |
| id: ver | |
| env: | |
| BUMP_INPUT: ${{ github.event.inputs.bump }} | |
| run: | | |
| set -euo pipefail | |
| # workflow_dispatch wins. On push, a [minor] or [major] marker in the | |
| # merge commit message picks the bump, so an API change ships as one | |
| # tag instead of a throwaway patch followed by a dispatched bump. | |
| bump="${BUMP_INPUT:-}" | |
| if [ -z "$bump" ]; then | |
| msg="$(git log -1 --pretty=%B)" | |
| case "$msg" in | |
| *'[major]'*) bump="major" ;; | |
| *'[minor]'*) bump="minor" ;; | |
| *) bump="patch" ;; | |
| esac | |
| fi | |
| echo "Bump: $bump" | |
| latest="$(git tag -l 'go/v*' --sort=-v:refname | grep -E '^go/v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 || true)" | |
| if [ -z "$latest" ]; then | |
| echo "No go/v* tags yet. Cut go/v0.1.0 manually once, then re-run." | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| echo "latest=$latest" >> "$GITHUB_OUTPUT" | |
| ver="${latest#go/v}" | |
| IFS=. read -r major minor patch <<<"$ver" | |
| case "$bump" in | |
| major) major=$((major + 1)); minor=0; patch=0 ;; | |
| minor) minor=$((minor + 1)); patch=0 ;; | |
| patch) patch=$((patch + 1)) ;; | |
| *) echo "unknown bump: $bump"; exit 1 ;; | |
| esac | |
| next="go/v${major}.${minor}.${patch}" | |
| module_ver="v${major}.${minor}.${patch}" | |
| echo "tag=$next" >> "$GITHUB_OUTPUT" | |
| echo "module_ver=$module_ver" >> "$GITHUB_OUTPUT" | |
| echo "Next tag: $next (module @${module_ver})" | |
| - name: Verify module before tagging | |
| if: steps.ver.outputs.skip != 'true' | |
| run: | | |
| set -euo pipefail | |
| (cd go/internal/gen && go run .) | |
| if [ -n "$(git status --porcelain -- go/)" ]; then | |
| echo "go/ drift on main; refusing to tag:" | |
| git status --porcelain -- go/ | |
| exit 1 | |
| fi | |
| (cd go && gofmt -l . | tee /tmp/gofmt.out) | |
| if [ -s /tmp/gofmt.out ]; then | |
| echo "gofmt needed before release" | |
| exit 1 | |
| fi | |
| (cd go && go vet . && go test .) | |
| (cd go/internal/gen && go test .) | |
| - name: Create tag and GitHub Release | |
| if: steps.ver.outputs.skip != 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.AGENT_PAT || secrets.GITHUB_TOKEN }} | |
| TAG: ${{ steps.ver.outputs.tag }} | |
| MODULE_VER: ${{ steps.ver.outputs.module_ver }} | |
| PREV: ${{ steps.ver.outputs.latest }} | |
| run: | | |
| set -euo pipefail | |
| if git rev-parse "$TAG" >/dev/null 2>&1; then | |
| echo "Tag $TAG already exists; nothing to do" | |
| exit 0 | |
| fi | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag -a "$TAG" -m "mcp-setup-docs Go module ${MODULE_VER}" | |
| git push origin "$TAG" | |
| notes_file="${RUNNER_TEMP:-/tmp}/go-module-release-notes.md" | |
| base_guides="${RUNNER_TEMP:-/tmp}/go-module-release-guides-base.txt" | |
| head_guides="${RUNNER_TEMP:-/tmp}/go-module-release-guides-head.txt" | |
| git ls-tree -d --name-only "${PREV}:go/generated/guides" 2>/dev/null \ | |
| | sort -u > "$base_guides" || : > "$base_guides" | |
| git ls-tree -d --name-only "HEAD:go/generated/guides" 2>/dev/null \ | |
| | sort -u > "$head_guides" || : > "$head_guides" | |
| mapfile -t added_guides < <(comm -13 "$base_guides" "$head_guides") | |
| mapfile -t removed_guides < <(comm -23 "$base_guides" "$head_guides") | |
| updated_guides=() | |
| while IFS= read -r slug; do | |
| [ -z "$slug" ] && continue | |
| if ! git diff --quiet "$PREV" -- "go/generated/guides/${slug}"; then | |
| updated_guides+=("$slug") | |
| fi | |
| done < <(comm -12 "$base_guides" "$head_guides") | |
| mapfile -t other_files < <( | |
| git diff --name-only "$PREV" -- go/ \ | |
| | grep -v '^go/generated/guides/' \ | |
| | sort -u || true | |
| ) | |
| fmt_backticks() { | |
| local out="" s | |
| for s in "$@"; do | |
| [ -z "$s" ] && continue | |
| if [ -n "$out" ]; then out+=", "; fi | |
| out+="\`${s}\`" | |
| done | |
| printf '%s' "$out" | |
| } | |
| { | |
| echo "Go module \`github.com/speakeasy-api/mcp-setup-docs/go@${MODULE_VER}\`" | |
| echo | |
| echo '```bash' | |
| echo "go get github.com/speakeasy-api/mcp-setup-docs/go@${MODULE_VER}" | |
| echo '```' | |
| echo | |
| echo "### Changes since ${PREV}" | |
| if [ "${#added_guides[@]}" -gt 0 ]; then | |
| echo "- **Added guides:** $(fmt_backticks "${added_guides[@]}")" | |
| fi | |
| if [ "${#updated_guides[@]}" -gt 0 ]; then | |
| echo "- **Updated guides:** $(fmt_backticks "${updated_guides[@]}")" | |
| fi | |
| if [ "${#removed_guides[@]}" -gt 0 ]; then | |
| echo "- **Removed guides:** $(fmt_backticks "${removed_guides[@]}")" | |
| fi | |
| if [ "${#other_files[@]}" -gt 0 ]; then | |
| echo "- **Other:** $(fmt_backticks "${other_files[@]}")" | |
| fi | |
| if [ "${#added_guides[@]}" -eq 0 ] \ | |
| && [ "${#updated_guides[@]}" -eq 0 ] \ | |
| && [ "${#removed_guides[@]}" -eq 0 ] \ | |
| && [ "${#other_files[@]}" -eq 0 ]; then | |
| echo "- Sync publishable guides into the Go module embed" | |
| fi | |
| } > "$notes_file" | |
| gh release create "$TAG" --title "$TAG" --notes-file "$notes_file" | |
| - name: Prime module proxy | |
| if: steps.ver.outputs.skip != 'true' | |
| env: | |
| MODULE_VER: ${{ steps.ver.outputs.module_ver }} | |
| run: | | |
| set -euo pipefail | |
| # Best-effort: proxy indexing can lag; don't fail the release on it. | |
| GOPROXY=https://proxy.golang.org go list -m "github.com/speakeasy-api/mcp-setup-docs/go@${MODULE_VER}" \ | |
| || echo "proxy prime not ready yet for @${MODULE_VER}" |