Finalize Release #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Finalize Release" | |
| on: | |
| workflow_run: | |
| workflows: ["Package and Release"] | |
| types: [completed] | |
| branches: [release] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to finalize (e.g., 0.1.0)" | |
| required: true | |
| type: string | |
| jobs: | |
| finalize-release: | |
| runs-on: ubuntu-latest | |
| if: | |
| ${{ github.event.workflow_run.conclusion == 'success' || github.event_name | |
| == 'workflow_dispatch' }} | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: release | |
| lfs: true | |
| fetch-depth: 0 # Fetch all history for changelog generation | |
| fetch-tags: true # Explicitly fetch all tags | |
| - name: Get version from files | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| # Manual trigger - use provided version | |
| VERSION="${{ github.event.inputs.version }}" | |
| else | |
| # Automatic trigger - read from files | |
| VERSION=$(python -c "from quickview import __version__; print(__version__)") | |
| fi | |
| echo "VERSION=$VERSION" >> $GITHUB_ENV | |
| echo "APP_TAG=v$VERSION" >> $GITHUB_ENV | |
| echo "Using version: $VERSION" | |
| - name: Wait for all platform builds to complete | |
| id: wait_for_builds | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const maxWaitTime = 30 * 60 * 1000; // 30 minutes | |
| const pollInterval = 30 * 1000; // 30 seconds | |
| const startTime = Date.now(); | |
| let releaseReady = false; | |
| let releaseId = null; | |
| while (Date.now() - startTime < maxWaitTime) { | |
| // Get the draft release | |
| const releases = await github.rest.repos.listReleases({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| const draftRelease = releases.data.find(release => | |
| release.draft && release.tag_name === '${{ env.APP_TAG }}' | |
| ); | |
| if (!draftRelease) { | |
| console.log('Draft release not found yet, waiting...'); | |
| await new Promise(resolve => setTimeout(resolve, pollInterval)); | |
| continue; | |
| } | |
| // Check if we have assets for both macOS targets | |
| const expectedAssets = 2; // aarch64 and x86_64 for macOS | |
| if (draftRelease.assets.length >= expectedAssets) { | |
| console.log(`Found ${draftRelease.assets.length} assets, proceeding with release`); | |
| releaseId = draftRelease.id; | |
| releaseReady = true; | |
| break; | |
| } else { | |
| console.log(`Found ${draftRelease.assets.length}/${expectedAssets} assets, waiting for more...`); | |
| await new Promise(resolve => setTimeout(resolve, pollInterval)); | |
| } | |
| } | |
| if (!releaseReady) { | |
| throw new Error('Timeout waiting for all platform builds to complete'); | |
| } | |
| return releaseId; | |
| - name: Generate comprehensive release notes | |
| run: | | |
| # Fetch all tags from all branches to ensure we have complete history | |
| git fetch --all --tags | |
| # Get all tags sorted by version | |
| ALL_TAGS=$(git tag -l "v*" --sort=-version:refname) | |
| echo "All tags found: $ALL_TAGS" | |
| # Get the current tag (the one we're creating) | |
| CURRENT_TAG="${{ env.APP_TAG }}" | |
| # Find the previous tag (excluding the current one if it exists) | |
| PREV_TAG="" | |
| for tag in $ALL_TAGS; do | |
| if [ "$tag" != "$CURRENT_TAG" ]; then | |
| PREV_TAG=$tag | |
| break | |
| fi | |
| done | |
| echo "Previous tag: ${PREV_TAG:-none}" | |
| echo "Current tag: $CURRENT_TAG" | |
| # Generate changelog | |
| if [ -z "$PREV_TAG" ]; then | |
| echo "No previous tag found, including all commits" | |
| # For first release, get all commits | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s" --reverse HEAD 2>/dev/null || echo "- Initial release") | |
| else | |
| echo "Generating changelog from $PREV_TAG to $CURRENT_TAG" | |
| # Since tags are on master, get commits between tags | |
| # Use the current tag if it exists, otherwise use HEAD | |
| if git rev-parse "$CURRENT_TAG" >/dev/null 2>&1; then | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s" ${PREV_TAG}..${CURRENT_TAG} 2>/dev/null || echo "- Release updates") | |
| else | |
| CHANGELOG=$(git log --oneline --pretty=format:"- %s" ${PREV_TAG}..HEAD 2>/dev/null || echo "- Release updates") | |
| fi | |
| fi | |
| # Filter out version bump commits and merge commits | |
| CHANGELOG=$(echo "$CHANGELOG" | grep -v "^- Bump version:" | grep -v "^- Merge" | grep -v "^- \[pre-commit\]" || true) | |
| # If changelog is empty, use a default message | |
| if [ -z "$CHANGELOG" ]; then | |
| CHANGELOG="- Release updates" | |
| fi | |
| echo "Generated changelog:" | |
| echo "$CHANGELOG" | |
| cat > release_notes.md << EOF | |
| ## What's New in v${{ env.VERSION }} | |
| $CHANGELOG | |
| ## Downloads | |
| This release includes distributables for the following platforms: | |
| ### macOS | |
| - **Apple Silicon (M1/M2/M3)**: Download the \`aarch64\` version | |
| - **Intel Macs**: Download the \`x64\` version | |
| Reminder: After download, use the following command in Terminal to unblock the app for macOS | |
| ``` | |
| xattr -d com.apple.quarantine <your_filename>.dmg | |
| ``` | |
| ## Support | |
| If you encounter any issues: | |
| 1. Check the [Issues](https://github.com/${{ github.repository }}/issues) page | |
| 2. Create a new issue with details about your problem | |
| 3. Include your operating system and version information | |
| --- | |
| **Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG:-"Initial"}...${{ env.APP_TAG }} | |
| EOF | |
| - name: Publish the release | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const releaseNotes = fs.readFileSync('release_notes.md', 'utf8'); | |
| const releaseId = '${{ steps.wait_for_builds.outputs.result }}'; | |
| await github.rest.repos.updateRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| release_id: parseInt(releaseId), | |
| draft: false, | |
| body: releaseNotes, | |
| name: `QuickView release v${{ env.VERSION }}`, | |
| }); | |
| console.log('Release v${{ env.VERSION }} published successfully!'); | |
| - name: Create release summary | |
| run: | | |
| echo "## Release Published!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Trigger**: ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: v${{ env.VERSION }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tag**: ${{ env.APP_TAG }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release URL**: https://github.com/${{ github.repository }}/releases/tag/${{ env.APP_TAG }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "The release is now live with all platform distributables attached!" >> $GITHUB_STEP_SUMMARY |