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
48 changes: 48 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: release

# Cutting a release is just pushing a tag (see CHANGELOG.md "Release
# workflow"):
# git tag v0.2.0 && git push origin main --tags
# This workflow verifies the tagged commit still builds, then publishes a
# GitHub Release whose body lists every change since the previous v* tag
# plus a compare link.
on:
push:
tags: ['v*']

permissions:
contents: write # required to create the GitHub Release

jobs:
release:
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Full history + tags so release-notes.sh can find the previous tag
# and diff against it.
fetch-depth: 0

- uses: actions/setup-go@v5
with:
go-version: '1.26.x'
check-latest: true

# Gate: never publish a release from a tag that doesn't build/pass.
- run: go vet ./...
- run: go test -race ./...

- name: Generate release notes
run: bash scripts/release-notes.sh "$GITHUB_REF_NAME" > release-notes.md
env:
GITHUB_REPOSITORY: ${{ github.repository }}

- name: Publish GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$GITHUB_REF_NAME" \
--title "$GITHUB_REF_NAME" \
--notes-file release-notes.md \
--verify-tag
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ When cutting a release:
6. `git add spec/ internal/ VERSION CHANGELOG.md && git commit -m "release vX.Y.Z"`.
7. `git tag vX.Y.Z && git push origin main --tags`.

Pushing the `vX.Y.Z` tag triggers `.github/workflows/release.yml`, which
re-runs `go vet`/`go test -race` against the tagged commit and then
publishes a GitHub Release. Its notes list every non-merge commit since the
previous `v*` tag plus a `compare/<prev>...<new>` link. Preview the body
locally before tagging with `bash scripts/release-notes.sh vX.Y.Z`.

Once aligned with upstream, the Go module tag (`vX.Y.Z`) matches the
`e2b@X.Y.Z` tag it was generated from so consumers can pin
`github.com/eric642/e2b-go-sdk@vX.Y.Z` and know exactly which upstream
Expand Down
90 changes: 90 additions & 0 deletions scripts/release-notes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
# Generate GitHub Release notes for a tag by diffing it against the
# previous release tag.
#
# Usage:
# scripts/release-notes.sh v0.2.0 # notes for an explicit tag
# scripts/release-notes.sh # notes for $GITHUB_REF_NAME, else the
# # tag pointing at HEAD, else newest v*
#
# Prints Markdown to stdout: a "What's Changed" commit list (the changes
# between the previous release tag and this one) plus a "Full Changelog"
# compare link. Designed to feed `gh release create --notes-file -`.
#
# Requires full git history with tags (clone with fetch-depth: 0 in CI).
#
# Environment:
# GITHUB_REPOSITORY owner/repo for compare + commit links. Falls back to
# parsing `git config remote.origin.url`.

set -euo pipefail

die() { printf 'error: %s\n' "$*" >&2; exit 1; }

# --- resolve the tag we're cutting notes for ---------------------------------

TAG="${1:-${GITHUB_REF_NAME:-}}"
if [[ -z "$TAG" ]]; then
# Tag pointing exactly at HEAD, else the newest v* tag.
TAG="$(git describe --tags --exact-match 2>/dev/null \
|| git tag --list 'v*' --sort=-v:refname | head -n1)"
fi
[[ -n "$TAG" ]] || die "could not determine a tag; pass one explicitly"

git rev-parse -q --verify "refs/tags/$TAG" >/dev/null \
|| die "tag not found: $TAG (is the full history fetched?)"

# --- resolve the previous release tag in this line of history ----------------
# `git describe` walks commit topology, so PREV is the most recent v* tag
# reachable from the commit before TAG — i.e. the previous release, even when
# tags aren't strictly version-ordered.
PREV="$(git describe --tags --abbrev=0 --match 'v*' "${TAG}^" 2>/dev/null || true)"

# --- derive owner/repo for links ---------------------------------------------

repo_slug() {
if [[ -n "${GITHUB_REPOSITORY:-}" ]]; then
printf '%s' "$GITHUB_REPOSITORY"
return
fi
local url
url="$(git config --get remote.origin.url 2>/dev/null || true)"
url="${url%.git}"
url="${url#git@github.com:}"
url="${url#ssh://git@github.com/}"
url="${url#https://github.com/}"
url="${url#http://github.com/}"
printf '%s' "$url"
}
SLUG="$(repo_slug)"

# --- build the body ----------------------------------------------------------

printf '## What'\''s Changed\n\n'

if [[ -n "$PREV" ]]; then
RANGE="${PREV}..${TAG}"
else
# First release: everything reachable from the tag.
RANGE="$TAG"
fi

# Newest first, drop merge commits so the list reads as real changes rather
# than "Merge pull request #N …" noise. Subjects and the short SHA are
# auto-linkified by GitHub in release bodies.
COMMITS="$(git log --no-merges --pretty=format:'- %s (%h)' "$RANGE" || true)"
if [[ -n "$COMMITS" ]]; then
printf '%s\n' "$COMMITS"
else
printf '_No code changes since %s._\n' "${PREV:-the start of history}"
fi

printf '\n'

if [[ -n "$SLUG" ]]; then
if [[ -n "$PREV" ]]; then
printf '**Full Changelog**: https://github.com/%s/compare/%s...%s\n' "$SLUG" "$PREV" "$TAG"
else
printf '**Full Changelog**: https://github.com/%s/commits/%s\n' "$SLUG" "$TAG"
fi
fi
Loading