Skip to content

Finalize Release

Finalize Release #1

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