Skip to content

Release Please

Release Please #643

name: Release Please
on:
push:
branches: [main]
schedule:
- cron: '0 0 * * *' # runs daily at midnight UTC
workflow_dispatch: # Allow manual triggering for testing
jobs:
release-please:
runs-on: ubuntu-latest
permissions:
contents: write # needed to create tags and releases
pull-requests: write # needed to create/update the release PR
issues: write # needed for release-please to function properly
repository-projects: write # needed for release-please to function properly
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- name: Checkout repo
uses: actions/checkout@v5
with:
fetch-depth: 0 # Needed for release-please to analyze commit history
- name: Run release-please
id: release
uses: googleapis/release-please-action@v4
with:
# Use PAT instead of GITHUB_TOKEN to bypass repository restrictions
token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
# The release-please action creates the git tag when a release PR is merged
# This tag will automatically trigger the existing release.yml workflow
# No additional workflow dispatch needed since release.yml triggers on tags matching 'v*.*.*'
upload-cli-binaries:
name: Upload CLI binaries to release 📦
# Only run when release-please creates a release
if: ${{ needs.release-please.outputs.release_created }}
needs: [release-please]
runs-on: ubuntu-latest
permissions:
contents: write # Required to upload release assets
actions: read # Required to download artifacts from other workflows
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Wait for release workflow to complete
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${{ needs.release-please.outputs.tag_name }}"
echo "Waiting for release workflow to complete for tag: $TAG_NAME"
# Wait for the release workflow to finish
# The release workflow is triggered by the tag creation
max_attempts=60 # Wait up to 30 minutes (60 * 30s)
attempt=0
while [ $attempt -lt $max_attempts ]; do
echo "Checking for release workflow run... (attempt $((attempt + 1))/$max_attempts)"
# Find workflow runs for the tag
WORKFLOW_ID=$(gh api repos/${{ github.repository }}/actions/workflows --jq '.workflows[] | select(.name == "Release") | .id')
if [ -n "$WORKFLOW_ID" ]; then
# Check for completed runs
COMPLETED_RUNS=$(gh api "repos/${{ github.repository }}/actions/workflows/$WORKFLOW_ID/runs" \
--jq "[.workflow_runs[] | select(.head_sha == \"$(git rev-parse $TAG_NAME)\") | select(.status == \"completed\")] | length")
if [ "$COMPLETED_RUNS" -gt 0 ]; then
echo "✅ Release workflow completed!"
break
fi
fi
echo "Release workflow still running, waiting 30 seconds..."
sleep 30
attempt=$((attempt + 1))
done
if [ $attempt -eq $max_attempts ]; then
echo "❌ Timeout waiting for release workflow to complete"
exit 1
fi
- name: Download CLI archives from release workflow
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${{ needs.release-please.outputs.tag_name }}"
# Find the workflow run for this tag
WORKFLOW_ID=$(gh api repos/${{ github.repository }}/actions/workflows --jq '.workflows[] | select(.name == "Release") | .id')
RUN_ID=$(gh api "repos/${{ github.repository }}/actions/workflows/$WORKFLOW_ID/runs" \
--jq ".workflow_runs[] | select(.head_sha == \"$(git rev-parse $TAG_NAME)\") | select(.status == \"completed\") | .id" | head -1)
echo "Found release workflow run ID: $RUN_ID"
# Create directory for archives
mkdir -p cli-archives
# Download all CLI archive artifacts
gh run download "$RUN_ID" --pattern "cli-archive-*" --dir cli-archives-temp/
# Organize the downloaded archives
find cli-archives-temp -name "*.tar.gz" -o -name "*.zip" -o -name "*.sha256" | while read file; do
cp "$file" cli-archives/
done
echo "Downloaded CLI archives:"
ls -la cli-archives/
- name: Upload CLI archives to GitHub Release
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${{ needs.release-please.outputs.tag_name }}"
# Upload each archive and checksum to the release
for file in cli-archives/*; do
if [[ -f "$file" ]]; then
filename=$(basename "$file")
echo "Uploading: $filename"
gh release upload "$TAG_NAME" "$file" --clobber
echo "✅ Uploaded: $filename"
fi
done
echo "All CLI binaries uploaded to release: $TAG_NAME"
generate-changelog-summary:
name: Generate human-readable release summary
runs-on: ubuntu-latest
needs: [release-please]
if: needs.release-please.outputs.release_created == 'true'
permissions:
contents: write
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ needs.release-please.outputs.tag_name }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Generate changelog summary with OpenAI API
id: summary
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
SYSTEM_PROMPT: |
You are a release note summarizer and reviewing release notes for Cribo project.
Cribo is a Python source bundler written in Rust that produces a single .py file
from a multi-module Python project by inlining first-party source files. It's available as a CLI tool.
1. Exclude any commits whose *only* change is bumping **this project’s** own version number
(e.g. “chore(main): release 0.4.17”).
2. However, **do include** commits that update dependency versions
(e.g. “chore(deps): bump lodash from 4.17.20 to 4.17.21”).
3. From the remaining commits (including bodies), produce a concise, human-readable
summary of what changed in this release.
4. Organize your summary under headings like “✨ Features,” “🐛 Bug Fixes,” “📦 Dependencies,”
and “🚀 Performance,” using bullet points or short paragraphs. Feel free to use emojis in the headings to make them more engaging.
run: |
gh release view "$TAG" --json body --jq .body > raw_changelog.md
PREV_TAG=$(
git tag --sort=-v:refname \
| awk -v tag="$TAG" '$0 == tag { getline; print; exit }'
)
REQUEST_PAYLOAD=$(
jq -n \
--arg system "$SYSTEM_PROMPT" \
--arg prev "$PREV_TAG" \
--arg tag "$TAG" \
--rawfile body <(gh release view "$TAG" --json body --jq .body) \
--rawfile log <(git log "$PREV_TAG..$TAG" --pretty=format:'%s%n%b%n') \
'{
model: "gpt-4",
temperature: 0.2,
max_tokens: 800,
messages: [
{ role: "system", content: $system },
{
role: "user",
content: (
($body + "\n\n## Full commit messages between " + $prev
+ " and " + $tag + "\n\n")
+ $log
)
}
]
}'
)
echo "Request payload for OpenAI API:"
echo "$REQUEST_PAYLOAD"
echo "Generating summary for release $TAG..."
SUMMARY_JSON=$(curl -s https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" --json "$REQUEST_PAYLOAD")
echo "OpenAI API response:"
echo "$SUMMARY_JSON"
SUMMARY=$(echo "$SUMMARY_JSON" | jq -r '.choices[0].message.content')
echo "$SUMMARY" > changelog_summary.md
echo $SUMMARY
- name: Update GitHub Release
run: gh release edit "$TAG" --notes-file changelog_summary.md