create-release.yml 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. name: Create Release
  2. # This workflow creates git tags and GitHub releases after version bump PRs are merged.
  3. # It detects when a version bump PR (with 'version-bump' label) is merged and creates
  4. # the corresponding tag and release automatically.
  5. on:
  6. push:
  7. branches: [main]
  8. workflow_dispatch:
  9. inputs:
  10. version:
  11. description: 'Version to release (e.g., 0.5.0)'
  12. required: false
  13. type: string
  14. permissions:
  15. contents: write
  16. jobs:
  17. check-if-version-bump:
  18. name: Check if Version Bump PR Merged
  19. runs-on: ubuntu-latest
  20. outputs:
  21. should_release: ${{ steps.check.outputs.should_release }}
  22. version: ${{ steps.check.outputs.version }}
  23. steps:
  24. - name: Checkout code
  25. uses: actions/checkout@v4
  26. with:
  27. fetch-depth: 2
  28. - name: Check if this was a version bump PR merge
  29. id: check
  30. uses: actions/github-script@v7
  31. with:
  32. script: |
  33. const fs = require('fs');
  34. // Manual trigger - use provided version
  35. if (context.eventName === 'workflow_dispatch' && context.payload.inputs.version) {
  36. core.setOutput('should_release', 'true');
  37. core.setOutput('version', context.payload.inputs.version);
  38. console.log(`Manual release triggered for version: ${context.payload.inputs.version}`);
  39. return;
  40. }
  41. // Get the commit that triggered this workflow
  42. const commit = context.sha;
  43. // Find PRs that were merged with this commit
  44. const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
  45. owner: context.repo.owner,
  46. repo: context.repo.repo,
  47. commit_sha: commit
  48. });
  49. // Check if any of these PRs had the version-bump label
  50. const versionBumpPR = prs.find(pr =>
  51. pr.labels.some(label => label.name === 'version-bump')
  52. );
  53. if (versionBumpPR) {
  54. console.log(`Version bump PR detected: #${versionBumpPR.number}`);
  55. // Read VERSION file to get the new version
  56. const version = fs.readFileSync('VERSION', 'utf8').trim();
  57. core.setOutput('should_release', 'true');
  58. core.setOutput('version', version);
  59. console.log(`Will create release for version: ${version}`);
  60. } else {
  61. console.log('Not a version bump PR - skipping release creation');
  62. core.setOutput('should_release', 'false');
  63. }
  64. create-tag-and-release:
  65. name: Create Git Tag and GitHub Release
  66. runs-on: ubuntu-latest
  67. needs: check-if-version-bump
  68. if: needs.check-if-version-bump.outputs.should_release == 'true'
  69. steps:
  70. - name: Checkout code
  71. uses: actions/checkout@v4
  72. with:
  73. fetch-depth: 0
  74. - name: Configure Git
  75. run: |
  76. git config user.name "github-actions[bot]"
  77. git config user.email "github-actions[bot]@users.noreply.github.com"
  78. - name: Check if tag already exists
  79. id: check_tag
  80. run: |
  81. VERSION="${{ needs.check-if-version-bump.outputs.version }}"
  82. if git rev-parse "v$VERSION" >/dev/null 2>&1; then
  83. echo "tag_exists=true" >> $GITHUB_OUTPUT
  84. echo "⚠️ Tag v$VERSION already exists"
  85. else
  86. echo "tag_exists=false" >> $GITHUB_OUTPUT
  87. echo "✅ Tag v$VERSION does not exist - will create"
  88. fi
  89. - name: Create git tag
  90. if: steps.check_tag.outputs.tag_exists == 'false'
  91. run: |
  92. VERSION="${{ needs.check-if-version-bump.outputs.version }}"
  93. echo "Creating tag: v$VERSION"
  94. git tag "v$VERSION"
  95. git push origin "v$VERSION"
  96. echo "## ✅ Git Tag Created" >> $GITHUB_STEP_SUMMARY
  97. echo "" >> $GITHUB_STEP_SUMMARY
  98. echo "- **Tag:** v$VERSION" >> $GITHUB_STEP_SUMMARY
  99. echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
  100. - name: Extract release notes from CHANGELOG
  101. id: release_notes
  102. run: |
  103. VERSION="${{ needs.check-if-version-bump.outputs.version }}"
  104. if [ -f CHANGELOG.md ]; then
  105. RELEASE_NOTES=$(awk '/^## \['"$VERSION"'\]/{flag=1; next} /^## \[/{flag=0} flag' CHANGELOG.md)
  106. if [ -z "$RELEASE_NOTES" ]; then
  107. RELEASE_NOTES="Release v$VERSION
  108. See [CHANGELOG.md](CHANGELOG.md) for details."
  109. fi
  110. else
  111. RELEASE_NOTES="Release v$VERSION"
  112. fi
  113. echo "$RELEASE_NOTES" > /tmp/release_notes.md
  114. echo "## 📝 Release Notes Preview" >> $GITHUB_STEP_SUMMARY
  115. echo "" >> $GITHUB_STEP_SUMMARY
  116. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  117. cat /tmp/release_notes.md >> $GITHUB_STEP_SUMMARY
  118. echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
  119. - name: Check if release already exists
  120. id: check_release
  121. run: |
  122. VERSION="${{ needs.check-if-version-bump.outputs.version }}"
  123. if gh release view "v$VERSION" >/dev/null 2>&1; then
  124. echo "release_exists=true" >> $GITHUB_OUTPUT
  125. echo "⚠️ Release v$VERSION already exists"
  126. else
  127. echo "release_exists=false" >> $GITHUB_OUTPUT
  128. echo "✅ Release v$VERSION does not exist - will create"
  129. fi
  130. env:
  131. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  132. - name: Create GitHub release
  133. if: steps.check_release.outputs.release_exists == 'false'
  134. run: |
  135. VERSION="${{ needs.check-if-version-bump.outputs.version }}"
  136. echo "Creating GitHub release: v$VERSION"
  137. gh release create "v$VERSION" \
  138. --title "v$VERSION" \
  139. --notes-file /tmp/release_notes.md \
  140. --latest
  141. echo "## 🚀 GitHub Release Created" >> $GITHUB_STEP_SUMMARY
  142. echo "" >> $GITHUB_STEP_SUMMARY
  143. echo "- **Release:** v$VERSION" >> $GITHUB_STEP_SUMMARY
  144. echo "- **URL:** https://github.com/${{ github.repository }}/releases/tag/v$VERSION" >> $GITHUB_STEP_SUMMARY
  145. env:
  146. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  147. - name: Summary
  148. if: always()
  149. run: |
  150. VERSION="${{ needs.check-if-version-bump.outputs.version }}"
  151. TAG_EXISTS="${{ steps.check_tag.outputs.tag_exists }}"
  152. RELEASE_EXISTS="${{ steps.check_release.outputs.release_exists }}"
  153. echo "" >> $GITHUB_STEP_SUMMARY
  154. echo "---" >> $GITHUB_STEP_SUMMARY
  155. echo "" >> $GITHUB_STEP_SUMMARY
  156. echo "### 📊 Release Summary" >> $GITHUB_STEP_SUMMARY
  157. echo "" >> $GITHUB_STEP_SUMMARY
  158. echo "**Version:** v$VERSION" >> $GITHUB_STEP_SUMMARY
  159. echo "" >> $GITHUB_STEP_SUMMARY
  160. if [ "$TAG_EXISTS" = "true" ]; then
  161. echo "- ⏭️ Git tag already existed (skipped)" >> $GITHUB_STEP_SUMMARY
  162. else
  163. echo "- ✅ Git tag created" >> $GITHUB_STEP_SUMMARY
  164. fi
  165. if [ "$RELEASE_EXISTS" = "true" ]; then
  166. echo "- ⏭️ GitHub release already existed (skipped)" >> $GITHUB_STEP_SUMMARY
  167. else
  168. echo "- ✅ GitHub release created" >> $GITHUB_STEP_SUMMARY
  169. fi
  170. echo "" >> $GITHUB_STEP_SUMMARY
  171. echo "🎉 **Release v$VERSION is now available!**" >> $GITHUB_STEP_SUMMARY