Merge pull request #122 from speakeasy-api/walker/guide-formatting-le… #5
Workflow file for this run
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 consumer bump | |
| # After a go/vX.Y.Z tag lands, open (or refresh) a PR on the consumer repo that | |
| # pins the new module version in its go.mod. The bump branch on the consumer is | |
| # machine-owned: every release rebuilds it from the consumer default branch and | |
| # force-pushes, so a single PR always shows the newest version. | |
| on: | |
| push: | |
| tags: | |
| - 'go/v*' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: Module version to pin (for example v0.1.4). Empty uses the latest go/v* tag. | |
| required: false | |
| type: string | |
| concurrency: | |
| group: go-module-consumer-bump | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| env: | |
| CONSUMER_REPO: speakeasy-api/gram | |
| MODULE_PATH: github.com/speakeasy-api/mcp-setup-docs/go | |
| BUMP_BRANCH: chore/bump-mcp-setup-docs-go | |
| jobs: | |
| bump: | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Scoped to the consumer repo and valid for an hour, unlike a PAT. | |
| - name: Mint a gram-bot token | |
| id: app-token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| app-id: ${{ secrets.GRAM_BOT_APP_ID }} | |
| private-key: ${{ secrets.GRAM_BOT_PRIVATE_KEY }} | |
| owner: speakeasy-api | |
| repositories: gram | |
| permission-contents: write | |
| permission-pull-requests: write | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Resolve module version | |
| id: ver | |
| env: | |
| INPUT_VERSION: ${{ github.event.inputs.version }} | |
| run: | | |
| set -euo pipefail | |
| if [ -n "${INPUT_VERSION:-}" ]; then | |
| ver="${INPUT_VERSION}" | |
| elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then | |
| ver="${GITHUB_REF_NAME}" | |
| else | |
| ver="$(git tag -l 'go/v*' --sort=-v:refname | head -1)" | |
| fi | |
| ver="${ver#go/}" | |
| ver="v${ver#v}" | |
| if ! printf '%s' "$ver" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "not a release version: '$ver'" | |
| exit 1 | |
| fi | |
| echo "version=$ver" >> "$GITHUB_OUTPUT" | |
| echo "tag=go/$ver" >> "$GITHUB_OUTPUT" | |
| echo "Pinning ${MODULE_PATH}@${ver}" | |
| - name: Checkout consumer | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.CONSUMER_REPO }} | |
| token: ${{ steps.app-token.outputs.token }} | |
| path: consumer | |
| fetch-depth: 1 | |
| - uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: consumer/go.mod | |
| cache-dependency-path: consumer/go.sum | |
| - name: Bump the module version | |
| id: bump | |
| working-directory: consumer | |
| env: | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| current="$(awk -v m="$MODULE_PATH" '$1 == m {print $2; exit}' go.mod)" | |
| if [ -z "$current" ]; then | |
| echo "${CONSUMER_REPO} go.mod does not require ${MODULE_PATH}; nothing to bump." | |
| exit 1 | |
| fi | |
| echo "previous=$current" >> "$GITHUB_OUTPUT" | |
| if [ "$current" = "$VERSION" ]; then | |
| echo "${CONSUMER_REPO} already pins ${VERSION}." | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # Proxy indexing lags the tag push; retry until the version resolves. | |
| attempts=12 | |
| for i in $(seq 1 "$attempts"); do | |
| if go get "${MODULE_PATH}@${VERSION}"; then | |
| break | |
| fi | |
| if [ "$i" -eq "$attempts" ]; then | |
| echo "${MODULE_PATH}@${VERSION} never resolved; re-run this workflow later." | |
| exit 1 | |
| fi | |
| echo "attempt ${i}: ${MODULE_PATH}@${VERSION} not on the proxy yet; retry in 20s" | |
| sleep 20 | |
| done | |
| # The consumer CI runs `go mod tidy` and fails on a dirty tree. | |
| go mod tidy | |
| if [ -z "$(git status --porcelain -- go.mod go.sum)" ]; then | |
| echo "go get produced no change; nothing to open." | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [ -n "$(git status --porcelain | grep -v -E '^ M go\.(mod|sum)$' || true)" ]; then | |
| echo "unexpected files changed; refusing to open a PR:" | |
| git status --porcelain | |
| exit 1 | |
| fi | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| - name: Collect release notes | |
| id: notes | |
| if: steps.bump.outputs.changed == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAG: ${{ steps.ver.outputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| notes_file="${RUNNER_TEMP:-/tmp}/consumer-bump-notes.md" | |
| gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json body --jq .body \ | |
| > "$notes_file" 2>/dev/null || : > "$notes_file" | |
| echo "file=$notes_file" >> "$GITHUB_OUTPUT" | |
| - name: Open or update the bump PR | |
| if: steps.bump.outputs.changed == 'true' | |
| working-directory: consumer | |
| env: | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| VERSION: ${{ steps.ver.outputs.version }} | |
| PREVIOUS: ${{ steps.bump.outputs.previous }} | |
| TAG: ${{ steps.ver.outputs.tag }} | |
| NOTES_FILE: ${{ steps.notes.outputs.file }} | |
| run: | | |
| set -euo pipefail | |
| # Commit as the app, so the consumer CI runs on the pushed branch. | |
| git config user.name "gram-bot[bot]" | |
| git config user.email "gram-bot[bot]@users.noreply.github.com" | |
| title="chore(deps): bump ${MODULE_PATH} from ${PREVIOUS} to ${VERSION}" | |
| git checkout -B "$BUMP_BRANCH" | |
| git add -- go.mod go.sum | |
| git commit -m "$title" | |
| # Machine-owned branch: the lease fails loudly if the remote moved. | |
| git fetch --depth=1 origin "+refs/heads/${BUMP_BRANCH}:refs/remotes/origin/${BUMP_BRANCH}" 2>/dev/null || true | |
| git push -u origin "HEAD:refs/heads/${BUMP_BRANCH}" --force-with-lease | |
| release_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${TAG}" | |
| body_file="${RUNNER_TEMP:-/tmp}/consumer-bump-pr.md" | |
| { | |
| echo "## Summary" | |
| echo "- Pin \`${MODULE_PATH}\` to \`${VERSION}\` (was \`${PREVIOUS}\`)" | |
| echo "- Opened by \`go-module-consumer-bump\` in ${GITHUB_REPOSITORY} after the \`${TAG}\` release" | |
| echo "- Branch is machine-owned — the next release force-pushes over it" | |
| echo "- If this bump breaks CI, branch off \`${BUMP_BRANCH}\`, fix it there, and close this PR." | |
| echo " Commits pushed onto this branch are lost on the next release." | |
| echo | |
| echo "## Release notes" | |
| echo "[\`${TAG}\`](${release_url})" | |
| if [ -s "${NOTES_FILE:-}" ]; then | |
| echo | |
| cat "$NOTES_FILE" | |
| fi | |
| echo | |
| echo "## Test plan" | |
| echo "- [ ] Consumer CI is green (\`go mod tidy\` leaves the tree clean)" | |
| echo "- [ ] Setup docs lookups still resolve the guides the release changed" | |
| } > "$body_file" | |
| existing="$(gh pr list --repo "$CONSUMER_REPO" --head "$BUMP_BRANCH" --state open \ | |
| --json number --jq '.[0].number // empty')" | |
| if [ -n "$existing" ]; then | |
| echo "Updated existing PR #${existing} on ${CONSUMER_REPO}" | |
| gh pr edit "$existing" --repo "$CONSUMER_REPO" --title "$title" --body-file "$body_file" | |
| else | |
| gh pr create --repo "$CONSUMER_REPO" \ | |
| --head "$BUMP_BRANCH" \ | |
| --title "$title" \ | |
| --body-file "$body_file" | |
| gh pr edit "$BUMP_BRANCH" --repo "$CONSUMER_REPO" \ | |
| --add-label dependencies --add-label go --add-label automation || true | |
| fi |