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
46 changes: 46 additions & 0 deletions .github/workflows/publish-gem-prerelease.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#
# This workflow is used to publish the Ruby SDK to RubyGems as a prerelease.
# The version number is automatically modified to append an "alpha" suffix with
# the GitHub run number, so you can push multiple prereleases from any branch.
#

name: Publish Ruby SDK Prerelease

on:
workflow_dispatch:
inputs:
ref:
description: "Publish the given Git ref as a prerelease (branch, tag, or commit SHA)"
required: true
type: string
default: "main"

jobs:
build-and-publish-prerelease:
runs-on: ubuntu-latest

permissions:
contents: write
id-token: write

steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.ref }}

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4'
bundler-cache: true

- name: Run linter
run: bundle exec rake lint

- name: Configure RubyGems credentials
uses: rubygems/configure-rubygems-credentials@main

- name: Build and publish prerelease
run: bundle exec rake release:prerelease
env:
GITHUB_RUN_NUMBER: ${{ github.run_number }}
61 changes: 61 additions & 0 deletions .github/workflows/publish-gem.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#
# This workflow publishes the Ruby SDK to RubyGems when a release tag is pushed.
# It validates the tag, ensures the commit is on main, runs tests, and publishes.
#

name: Publish Ruby SDK

on:
push:
tags:
- 'v*.*.*'

jobs:
validate:
runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.get-tag.outputs.tag }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get release tag
id: get-tag
run: echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4'
bundler-cache: true

- name: Validate release tag
run: bash scripts/validate-release-tag.sh

publish:
needs: validate
runs-on: ubuntu-latest

permissions:
contents: write
id-token: write

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4'
bundler-cache: true

- name: Configure RubyGems credentials
uses: rubygems/configure-rubygems-credentials@main

- name: Release
run: bundle exec rake release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@
# Ignore mise local settings
.mise.local.toml
.claude

# Release artifacts
changelog.md
83 changes: 83 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,86 @@ desc "Verify CI (lint + test)"
task ci: [:lint, :test]

task default: :ci

# Release tasks
namespace :release do
desc "Validate release tag and version"
task :validate do
sh "bash scripts/validate-release-tag.sh"
end

desc "Build the gem"
task build: [:clean] do
sh "gem build braintrust.gemspec"
end

desc "Publish gem to RubyGems (requires authentication)"
task :publish do
gem_file = FileList["braintrust-*.gem"].first
unless gem_file
puts "Error: No gem file found. Run 'rake release:build' first."
exit 1
end
sh "gem push #{gem_file}"
end

desc "Generate changelog for release"
task :changelog do
sh "bash scripts/generate-release-notes.sh > changelog.md"
puts "✓ Changelog generated: changelog.md"
end

desc "Create GitHub release"
task :github do
unless File.exist?("changelog.md")
puts "Error: changelog.md not found. Run 'rake release:changelog' first."
exit 1
end

require_relative "lib/braintrust/version"
tag = "v#{Braintrust::VERSION}"

sh "gh release create #{tag} --title 'Release #{tag}' --notes-file changelog.md"
puts "✓ GitHub release created: #{tag}"
end

desc "Build and publish prerelease (modifies version with alpha suffix)"
task :prerelease do
# Get current version
require_relative "lib/braintrust/version"
original_version = Braintrust::VERSION

# Generate prerelease version with GitHub run number or timestamp
run_number = ENV["GITHUB_RUN_NUMBER"] || Time.now.to_i.to_s
prerelease_version = "#{original_version}.alpha.#{run_number}"

puts "Original version: #{original_version}"
puts "Prerelease version: #{prerelease_version}"

# Temporarily modify version.rb
version_file = "lib/braintrust/version.rb"
content = File.read(version_file)
modified_content = content.gsub(
/VERSION = "#{Regexp.escape(original_version)}"/,
"VERSION = \"#{prerelease_version}\""
)

File.write(version_file, modified_content)

begin
# Build and publish
Rake::Task["release:build"].invoke
Rake::Task["release:publish"].invoke
puts "✓ Prerelease #{prerelease_version} published successfully!"
ensure
# Restore original version
File.write(version_file, content)
puts "Restored original version.rb"
end
end
end

desc "Full release: validate, lint, generate changelog, build, publish, and create GitHub release"
task release: ["release:validate", :lint, "release:changelog", "release:build", "release:publish", "release:github"] do
puts "✓ Release completed successfully!"
end
31 changes: 31 additions & 0 deletions scripts/generate-release-notes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Script to generate release notes for GitHub Release
# Compares current tag with previous tag

set -euo pipefail

# Get the repository root
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"

# Get current tag
CURRENT_TAG="${GITHUB_REF_NAME:-$(git describe --tags --exact-match 2>/dev/null || echo "")}"

if [ -z "$CURRENT_TAG" ]; then
echo "Error: No tag found. This script should be run on a tagged commit."
exit 1
fi

# Get previous tag
PREVIOUS_TAG=$(git describe --tags --abbrev=0 "${CURRENT_TAG}^" 2>/dev/null || echo "")

# Generate release notes
if [ -n "$PREVIOUS_TAG" ]; then
echo "## Changes since $PREVIOUS_TAG"
echo ""
git log "${PREVIOUS_TAG}..${CURRENT_TAG}" --pretty=format:"- %s (%h)" --no-merges
else
echo "## Initial Release"
echo ""
echo "First release of the Braintrust Ruby SDK"
fi
91 changes: 91 additions & 0 deletions scripts/push-release-tag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env bash
# Script to push a release tag for the Ruby SDK
# Inspired by py/scripts/push-release-tag.sh

set -euo pipefail

# Parse arguments
DRY_RUN=false
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
DRY_RUN=true
shift
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [--dry-run]"
exit 1
;;
esac
done

# Get the repository root
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"

# Fetch latest tags
echo "Fetching latest tags..."
git fetch --tags

# Get version from version.rb
VERSION=$(ruby -r "./lib/braintrust/version.rb" -e "puts Braintrust::VERSION")
TAG="v${VERSION}"

# Check if tag already exists
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Error: Tag $TAG already exists"
exit 1
fi

# Get current commit info
COMMIT_SHA=$(git rev-parse HEAD)
COMMIT_SHORT_SHA=$(git rev-parse --short HEAD)
REPO_URL=$(git config --get remote.origin.url | sed 's/\.git$//' | sed 's/git@github.com:/https:\/\/github.com\//')

# Get the previous tag for comparison
PREVIOUS_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")

echo ""
echo "========================================"
echo "Release Information"
echo "========================================"
echo "New version tag: $TAG"
echo "Current commit: $COMMIT_SHA"
echo "Commit URL: ${REPO_URL}/commit/${COMMIT_SHA}"
if [ -n "$PREVIOUS_TAG" ]; then
echo "Previous tag: $PREVIOUS_TAG"
echo "Changelog: ${REPO_URL}/compare/${PREVIOUS_TAG}...${COMMIT_SHORT_SHA}"
fi
echo "========================================"
echo ""

if [ "$DRY_RUN" = true ]; then
echo "DRY RUN: Would create and push tag $TAG"
echo "Exiting without making changes."
exit 0
fi

# Require confirmation
echo "This will create and push tag $TAG to trigger the production release."
echo "Type 'YOLO' to confirm:"
read -r CONFIRMATION

if [ "$CONFIRMATION" != "YOLO" ]; then
echo "Confirmation failed. Aborting."
exit 1
fi

# Create and push the tag
echo ""
echo "Creating tag $TAG..."
git tag "$TAG"

echo "Pushing tag $TAG..."
git push origin "$TAG"

echo ""
echo "✓ Tag $TAG has been pushed successfully!"
echo ""
echo "Monitor the release workflow at:"
echo "${REPO_URL}/actions"
62 changes: 62 additions & 0 deletions scripts/validate-release-tag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Script to validate a release tag for the Ruby SDK
# Ensures the tag matches the version in version.rb and is on the main branch

set -euo pipefail

# Get the repository root
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"

# Get the current tag (should be set in CI environment)
RELEASE_TAG="${GITHUB_REF_NAME:-}"

if [ -z "$RELEASE_TAG" ]; then
echo "Error: GITHUB_REF_NAME is not set"
echo "This script should be run in a GitHub Actions environment"
exit 1
fi

echo "Validating release tag: $RELEASE_TAG"

# Extract version from tag (remove 'v' prefix)
TAG_VERSION="${RELEASE_TAG#v}"

# Get version from version.rb
VERSION=$(ruby -r "./lib/braintrust/version.rb" -e "puts Braintrust::VERSION")

echo "Tag version: $TAG_VERSION"
echo "version.rb: $VERSION"

# Validate version matches
if [ "$TAG_VERSION" != "$VERSION" ]; then
echo ""
echo "Error: Tag version does not match version.rb"
echo " Tag: $TAG_VERSION"
echo " version.rb: $VERSION"
exit 1
fi

echo "✓ Version matches"

# Validate the tag is on the main branch
MAIN_BRANCH="main"
TAG_COMMIT=$(git rev-parse "$RELEASE_TAG")
MAIN_COMMIT=$(git rev-parse "origin/$MAIN_BRANCH")

# Check if the tag commit is an ancestor of main or is main
if ! git merge-base --is-ancestor "$TAG_COMMIT" "$MAIN_COMMIT" && [ "$TAG_COMMIT" != "$MAIN_COMMIT" ]; then
echo ""
echo "Error: Tag $RELEASE_TAG is not on the $MAIN_BRANCH branch"
echo " Tag commit: $TAG_COMMIT"
echo " Main commit: $MAIN_COMMIT"
exit 1
fi

echo "✓ Tag is on the $MAIN_BRANCH branch"

echo ""
echo "✓ Release tag validation successful"
echo " Tag: $RELEASE_TAG"
echo " Version: $VERSION"
echo " Commit: $TAG_COMMIT"
Loading