-
Notifications
You must be signed in to change notification settings - Fork 585
chore: agentic workflow for automatic version bump #1947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
01396dd
8fdea5b
8362c4e
0a4de1e
c482cc7
cec8c7c
b96551c
434fc00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,299 @@ | ||
| name: Bump Version | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| force_bump_type: | ||
| description: 'Force a specific bump type (leave empty for AI auto-detection)' | ||
| required: false | ||
| type: choice | ||
| options: | ||
| - '' | ||
| - major | ||
| - minor | ||
| - patch | ||
| ai_provider: | ||
| description: 'AI provider to use for analysis (default: gemini)' | ||
| required: false | ||
| type: choice | ||
| default: 'gemini' | ||
| options: | ||
| - gemini | ||
| - openai | ||
| - anthropic | ||
| schedule: | ||
| # Run weekly on Monday at 9:00 AM UTC | ||
| - cron: '0 9 * * 1' | ||
|
|
||
| jobs: | ||
| analyze-and-bump: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 # Need full history to analyze commits | ||
| submodules: false | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: '3.10' | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install google-generativeai openai anthropic | ||
|
|
||
| - name: Get current version | ||
| id: current-version | ||
| run: | | ||
| CURRENT_VERSION=$(cat version.txt | tr -d '[:space:]') | ||
| echo "version=${CURRENT_VERSION}" >> $GITHUB_OUTPUT | ||
| echo "Current version: ${CURRENT_VERSION}" | ||
|
|
||
| - name: Check for existing bump PR | ||
| id: check-existing-pr | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| # Check if there's already an open PR for version bump | ||
| EXISTING_PR=$(gh pr list --state open --label "version-bump" --json number --jq '.[0].number' || echo "") | ||
| if [ -n "$EXISTING_PR" ]; then | ||
| echo "has_existing_pr=true" >> $GITHUB_OUTPUT | ||
| echo "existing_pr_number=${EXISTING_PR}" >> $GITHUB_OUTPUT | ||
| echo "β οΈ Existing version bump PR found: #${EXISTING_PR}" | ||
| else | ||
| echo "has_existing_pr=false" >> $GITHUB_OUTPUT | ||
| echo "β No existing version bump PR found" | ||
| fi | ||
|
|
||
| - name: Analyze commits with AI | ||
| id: analyze | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'false' | ||
| env: | ||
| GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} | ||
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | ||
| run: | | ||
| # Determine which AI provider to use | ||
| # Priority: manual input > default (gemini) | ||
| if [ -n "${{ inputs.ai_provider }}" ]; then | ||
| AI_PROVIDER="${{ inputs.ai_provider }}" | ||
| else | ||
| AI_PROVIDER="gemini" | ||
| fi | ||
|
|
||
| echo "Using AI provider: ${AI_PROVIDER}" | ||
| echo "Analyzing commits to determine version bump..." | ||
|
|
||
| # Run AI analysis with specified provider | ||
| python scripts/ai_determine_version_bump.py \ | ||
| --provider ${AI_PROVIDER} \ | ||
|
Comment on lines
+94
to
+95
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainVerify that the Python script accepts the The workflow passes Run this script to verify the parameter is supported: π Script executed: #!/bin/bash
# Check if ai_determine_version_bump.py accepts --provider
if [ -f scripts/ai_determine_version_bump.py ]; then
python scripts/ai_determine_version_bump.py --help | grep -E '\-\-provider'
if [ $? -eq 0 ]; then
echo "β Script accepts --provider flag"
else
echo "β Script does NOT accept --provider flag"
fi
else
echo "β Script file not found"
fiLength of output: 40 Now let me examine the actual Python script and workflow file directly: π Script executed: #!/bin/bash
# Check the Python script and workflow file
echo "=== Checking Python script ==="
if [ -f scripts/ai_determine_version_bump.py ]; then
head -100 scripts/ai_determine_version_bump.py
else
echo "Script not found"
fi
echo ""
echo "=== Checking workflow context (lines 70-120) ==="
if [ -f .github/workflows/bump-version.yml ]; then
sed -n '70,120p' .github/workflows/bump-version.yml
else
echo "Workflow not found"
fiLength of output: 5241 Let me view the complete Python script to see the argparse definitions: π Script executed: #!/bin/bash
# View the full Python script to check argparse setup
cat scripts/ai_determine_version_bump.py | grep -A 50 "argparse\|ArgumentParser\|add_argument" | head -80Length of output: 2139 Remove unsupported The Python script does not accept Additionally, the π€ Prompt for AI Agents |
||
| --output-format json \ | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| --verbose > /tmp/analysis.json 2>&1 | ||
|
|
||
| # Extract results | ||
| BUMP_TYPE=$(jq -r '.bump_type' /tmp/analysis.json) | ||
| NEW_VERSION=$(jq -r '.new_version' /tmp/analysis.json) | ||
| REASONING=$(jq -r '.reasoning' /tmp/analysis.json) | ||
|
|
||
| echo "bump_type=${BUMP_TYPE}" >> $GITHUB_OUTPUT | ||
| echo "new_version=${NEW_VERSION}" >> $GITHUB_OUTPUT | ||
| echo "ai_provider=${AI_PROVIDER}" >> $GITHUB_OUTPUT | ||
|
|
||
| # Save reasoning and key changes for PR body | ||
| jq -r '.reasoning' /tmp/analysis.json > /tmp/reasoning.txt | ||
| jq -r '.key_changes[]' /tmp/analysis.json > /tmp/key_changes.txt || echo "" > /tmp/key_changes.txt | ||
|
|
||
| echo "AI Analysis Result (${AI_PROVIDER}):" | ||
| echo " Bump type: ${BUMP_TYPE}" | ||
| echo " New version: ${NEW_VERSION}" | ||
| echo " Reasoning: ${REASONING}" | ||
|
|
||
| - name: Override with manual input | ||
| id: final-decision | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'false' | ||
| run: | | ||
| # Use manual input if provided, otherwise use AI result | ||
| if [ -n "${{ inputs.force_bump_type }}" ]; then | ||
| BUMP_TYPE="${{ inputs.force_bump_type }}" | ||
| echo "Using manual bump type: ${BUMP_TYPE}" | ||
|
|
||
| # Calculate new version | ||
| CURRENT_VERSION="${{ steps.current-version.outputs.version }}" | ||
| if [ "$BUMP_TYPE" = "major" ]; then | ||
| MAJOR=$(echo $CURRENT_VERSION | cut -d'.' -f1) | ||
| NEW_VERSION="$((MAJOR + 1)).0.0" | ||
| elif [ "$BUMP_TYPE" = "minor" ]; then | ||
| MAJOR=$(echo $CURRENT_VERSION | cut -d'.' -f1) | ||
| MINOR=$(echo $CURRENT_VERSION | cut -d'.' -f2) | ||
| NEW_VERSION="${MAJOR}.$((MINOR + 1)).0" | ||
| elif [ "$BUMP_TYPE" = "patch" ]; then | ||
| MAJOR=$(echo $CURRENT_VERSION | cut -d'.' -f1) | ||
| MINOR=$(echo $CURRENT_VERSION | cut -d'.' -f2) | ||
| PATCH=$(echo $CURRENT_VERSION | cut -d'.' -f3 | sed 's/[^0-9].*//') | ||
| NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" | ||
| fi | ||
|
|
||
| echo "Manual override - reasoning" > /tmp/reasoning.txt | ||
| else | ||
| BUMP_TYPE="${{ steps.analyze.outputs.bump_type }}" | ||
| NEW_VERSION="${{ steps.analyze.outputs.new_version }}" | ||
| echo "Using AI-determined bump type: ${BUMP_TYPE}" | ||
| fi | ||
|
|
||
| echo "bump_type=${BUMP_TYPE}" >> $GITHUB_OUTPUT | ||
| echo "new_version=${NEW_VERSION}" >> $GITHUB_OUTPUT | ||
|
|
||
| echo "Final decision:" | ||
| echo " Bump type: ${BUMP_TYPE}" | ||
| echo " New version: ${NEW_VERSION}" | ||
|
|
||
| - name: Check if bump needed | ||
| id: check-bump | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'false' | ||
| run: | | ||
| BUMP_TYPE="${{ steps.final-decision.outputs.bump_type }}" | ||
|
|
||
| if [ "$BUMP_TYPE" = "none" ]; then | ||
| echo "needs_bump=false" >> $GITHUB_OUTPUT | ||
| echo "βΉοΈ No version bump needed" | ||
| else | ||
| echo "needs_bump=true" >> $GITHUB_OUTPUT | ||
| echo "β Version bump needed: ${BUMP_TYPE}" | ||
| fi | ||
|
|
||
| - name: Update version.txt | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'false' && steps.check-bump.outputs.needs_bump == 'true' | ||
| run: | | ||
| NEW_VERSION="${{ steps.final-decision.outputs.new_version }}" | ||
| echo "${NEW_VERSION}" > version.txt | ||
| echo "β Updated version.txt to ${NEW_VERSION}" | ||
|
|
||
| - name: Generate PR body | ||
| id: pr-body | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'false' && steps.check-bump.outputs.needs_bump == 'true' | ||
| run: | | ||
| BUMP_TYPE="${{ steps.final-decision.outputs.bump_type }}" | ||
| NEW_VERSION="${{ steps.final-decision.outputs.new_version }}" | ||
| CURRENT_VERSION="${{ steps.current-version.outputs.version }}" | ||
| AI_PROVIDER="${{ steps.analyze.outputs.ai_provider }}" | ||
|
|
||
| # Read AI reasoning | ||
| REASONING=$(cat /tmp/reasoning.txt || echo "Manual version bump") | ||
|
|
||
| # Read key changes | ||
| KEY_CHANGES=$(cat /tmp/key_changes.txt || echo "") | ||
|
|
||
| # Generate PR body | ||
| cat > /tmp/pr_body.md << 'EOF' | ||
| ## Version Bump: v$CURRENT_VERSION β v$NEW_VERSION | ||
|
|
||
| This PR bumps the version from **v$CURRENT_VERSION** to **v$NEW_VERSION** ($BUMP_TYPE_UPPER bump). | ||
|
|
||
| ### AI Analysis$AI_PROVIDER_TEXT | ||
|
|
||
| $REASONING | ||
|
|
||
| EOF | ||
|
|
||
| if [ -n "$KEY_CHANGES" ]; then | ||
| echo "" >> /tmp/pr_body.md | ||
| echo "### Key Changes" >> /tmp/pr_body.md | ||
| echo "" >> /tmp/pr_body.md | ||
| while IFS= read -r change; do | ||
| echo "- $change" >> /tmp/pr_body.md | ||
| done < /tmp/key_changes.txt | ||
| fi | ||
|
|
||
| cat >> /tmp/pr_body.md << 'EOF' | ||
|
|
||
| ### Semantic Versioning Rules | ||
|
|
||
| According to our [CONTRIBUTING.md](../blob/main/CONTRIBUTING.md): | ||
|
|
||
| - **Major**: Incompatible API changes | ||
| - **Minor**: Added functionality that is backwards-compatible | ||
| - **Patch**: Backwards-compatible bug fixes | ||
|
|
||
| ### Next Steps | ||
|
|
||
| After merging this PR: | ||
| 1. Create a git tag: `git tag v$NEW_VERSION` | ||
| 2. Run the [release workflow](../actions/workflows/release.yml) with tag `v$NEW_VERSION` | ||
|
|
||
| --- | ||
|
|
||
| π€ Auto-generated by [bump-version workflow](../actions/runs/$RUN_ID) | ||
| EOF | ||
|
|
||
| # Replace variables | ||
| sed -i "s/\$CURRENT_VERSION/$CURRENT_VERSION/g" /tmp/pr_body.md | ||
| sed -i "s/\$NEW_VERSION/$NEW_VERSION/g" /tmp/pr_body.md | ||
| sed -i "s/\$BUMP_TYPE_UPPER/$(echo $BUMP_TYPE | tr '[:lower:]' '[:upper:]')/g" /tmp/pr_body.md | ||
| sed -i "s|\$REASONING|$REASONING|g" /tmp/pr_body.md | ||
| sed -i "s/\$RUN_ID/${{ github.run_id }}/g" /tmp/pr_body.md | ||
|
|
||
| # Add AI provider info if available | ||
| if [ -n "$AI_PROVIDER" ]; then | ||
| sed -i "s/\$AI_PROVIDER_TEXT/ (using $AI_PROVIDER)/g" /tmp/pr_body.md | ||
| else | ||
| sed -i "s/\$AI_PROVIDER_TEXT//g" /tmp/pr_body.md | ||
| fi | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| cat /tmp/pr_body.md | ||
|
|
||
| - name: Create Pull Request | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'false' && steps.check-bump.outputs.needs_bump == 'true' | ||
| uses: peter-evans/create-pull-request@v6 | ||
| with: | ||
| token: ${{ secrets.FLASHINFER_BOT_TOKEN }} | ||
| commit-message: "release: bump version to ${{ steps.final-decision.outputs.new_version }}" | ||
| title: "Release: Bump version to v${{ steps.final-decision.outputs.new_version }}" | ||
| body-path: /tmp/pr_body.md | ||
| branch: bump-version-${{ steps.final-decision.outputs.new_version }} | ||
| delete-branch: true | ||
| labels: | | ||
| version-bump | ||
| automated | ||
| release | ||
| committer: flashinfer-bot <flashinfer-bot@users.noreply.github.com> | ||
| author: flashinfer-bot <flashinfer-bot@users.noreply.github.com> | ||
|
|
||
| - name: Summary | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'false' | ||
| run: | | ||
| echo "## Version Bump Summary" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| if [ "${{ steps.check-bump.outputs.needs_bump }}" = "true" ]; then | ||
| echo "β Version bump PR created" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Current version**: ${{ steps.current-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **New version**: ${{ steps.final-decision.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "- **Bump type**: ${{ steps.final-decision.outputs.bump_type }}" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| # Add AI provider info if available | ||
| if [ -n "${{ steps.analyze.outputs.ai_provider }}" ]; then | ||
| echo "- **AI provider**: ${{ steps.analyze.outputs.ai_provider }}" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
| else | ||
| echo "βΉοΈ No version bump needed" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "No significant changes detected since the last release." >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| - name: Already has open PR | ||
| if: steps.check-existing-pr.outputs.has_existing_pr == 'true' | ||
| run: | | ||
| echo "## Version Bump Summary" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "β οΈ A version bump PR already exists: #${{ steps.check-existing-pr.outputs.existing_pr_number }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "Please review and merge the existing PR before creating a new one." >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| exit 0 | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard against
nullfromgh pr listto avoid false positives.Current test treats
"null"as a PR number. Use// empty.Apply:
π Committable suggestion
π€ Prompt for AI Agents