Create Release #5
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
| # .github/workflows/create-release.yml | |
| # Manual workflow to create GitHub releases from stored build artifacts. | |
| # This allows you to test builds locally before making them public. | |
| name: Create Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag_name: | |
| description: 'Tag version to release (e.g., v1.0.0)' | |
| required: true | |
| type: string | |
| release_type: | |
| description: 'Release type' | |
| required: true | |
| default: 'release' | |
| type: choice | |
| options: | |
| - release | |
| - prerelease | |
| make_latest: | |
| description: 'Mark as latest release' | |
| required: true | |
| default: true | |
| type: boolean | |
| jobs: | |
| create-release: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # To create the release | |
| actions: read # To download artifacts | |
| pull-requests: read # To read PRs for the changelog | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ inputs.tag_name }} | |
| - name: Validate tag exists | |
| run: | | |
| if ! git tag --list | grep -q "^${{ inputs.tag_name }}$"; then | |
| echo "ERROR: Tag '${{ inputs.tag_name }}' does not exist!" | |
| exit 1 | |
| fi | |
| echo "SUCCESS: Tag '${{ inputs.tag_name }}' found" | |
| - name: Find build artifact | |
| id: find_artifact | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const artifactName = `PyFlowGraph-Windows-${{ inputs.tag_name }}`; | |
| // Search for recent successful builds (last 50 runs) | |
| const workflowRuns = await github.rest.actions.listWorkflowRunsForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| workflow_id: 'windows-build.yml', | |
| status: 'completed', | |
| conclusion: 'success', | |
| per_page: 50 | |
| }); | |
| console.log(`Searching for artifact '${artifactName}' in ${workflowRuns.data.workflow_runs.length} recent successful builds...`); | |
| // Search through recent successful builds to find the artifact | |
| let foundArtifact = null; | |
| let foundRunId = null; | |
| for (const run of workflowRuns.data.workflow_runs) { | |
| const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: run.id | |
| }); | |
| const artifact = artifacts.data.artifacts.find(a => a.name === artifactName); | |
| if (artifact) { | |
| foundArtifact = artifact; | |
| foundRunId = run.id; | |
| console.log(`Found artifact '${artifactName}' in build run ${run.id} (commit: ${run.head_sha.substring(0,7)})`); | |
| break; | |
| } | |
| } | |
| if (!foundArtifact) { | |
| throw new Error(`Artifact '${artifactName}' not found in any recent successful builds`); | |
| } | |
| console.log(`Using artifact: ${foundArtifact.name} (ID: ${foundArtifact.id})`); | |
| core.setOutput('artifact_id', foundArtifact.id); | |
| core.setOutput('run_id', foundRunId); | |
| core.setOutput('artifact_name', foundArtifact.name); | |
| - name: Download build artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: PyFlowGraph-Windows-${{ inputs.tag_name }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-id: ${{ steps.find_artifact.outputs.run_id }} | |
| - name: Verify and prepare artifact for release | |
| id: verify | |
| run: | | |
| zip_file="PyFlowGraph-Windows-${{ inputs.tag_name }}.zip" | |
| # Check if PyFlowGraph.exe exists (artifact was extracted directly to working directory) | |
| if [ ! -f "PyFlowGraph.exe" ]; then | |
| echo "ERROR: PyFlowGraph.exe not found in current directory" | |
| echo "Directory contents:" | |
| ls -la | |
| exit 1 | |
| fi | |
| # Verify key components exist | |
| if [ ! -d "examples" ] || [ ! -d "python_runtime" ]; then | |
| echo "ERROR: Missing required directories (examples or python_runtime)" | |
| ls -la | |
| exit 1 | |
| fi | |
| echo "SUCCESS: Found all required artifact components" | |
| echo "- PyFlowGraph.exe: $(ls -lh PyFlowGraph.exe | awk '{print $5}')" | |
| echo "- Examples directory: $(ls examples | wc -l) files" | |
| echo "- Python runtime directory exists: ✅" | |
| # Create release zip file from current directory contents | |
| echo "Creating release zip: $zip_file" | |
| if command -v zip >/dev/null 2>&1; then | |
| # Exclude development files but keep examples/*.md and LICENSE.txt | |
| zip -r "$zip_file" . -x ".git/*" ".github/*" "src/*" "tests/*" "test_reports/*" "docs/*" "images/*" "pre-release/*" ".gitignore" "README.md" "CLAUDE.md" "requirements.txt" "run.sh" "run.bat" "run_test_gui.bat" "*.log" | |
| else | |
| # Fallback for systems without zip command | |
| tar -czf "${zip_file%.zip}.tar.gz" --exclude='.git' --exclude='.github' --exclude='src' --exclude='tests' --exclude='test_reports' --exclude='docs' --exclude='images' --exclude='pre-release' --exclude='.gitignore' --exclude='README.md' --exclude='CLAUDE.md' --exclude='requirements.txt' --exclude='run.sh' --exclude='run.bat' --exclude='run_test_gui.bat' --exclude='*.log' . | |
| zip_file="${zip_file%.zip}.tar.gz" | |
| fi | |
| file_size=$(stat -f%z "$zip_file" 2>/dev/null || stat -c%s "$zip_file" 2>/dev/null) | |
| echo "SUCCESS: Created release package: $zip_file ($file_size bytes)" | |
| echo "zip_file=$zip_file" >> $GITHUB_OUTPUT | |
| - name: Generate changelog | |
| id: changelog | |
| uses: mikepenz/release-changelog-builder-action@v4 | |
| with: | |
| fromTag: ${{ inputs.tag_name }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create GitHub release | |
| id: create_release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ inputs.tag_name }} | |
| name: ${{ inputs.tag_name }} | |
| body: | | |
| ## What's Changed | |
| --- | |
| ${{ steps.changelog.outputs.changelog }} | |
| --- | |
| **Build Information:** | |
| - Built from commit: ${{ github.sha }} | |
| - Artifact: ${{ steps.verify.outputs.zip_file }} | |
| - Build run: [#${{ steps.find_artifact.outputs.run_id }}](https://github.com/${{ github.repository }}/actions/runs/${{ steps.find_artifact.outputs.run_id }}) | |
| files: ${{ steps.verify.outputs.zip_file }} | |
| prerelease: ${{ inputs.release_type == 'prerelease' }} | |
| make_latest: ${{ inputs.make_latest }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Release summary | |
| run: | | |
| echo "## Release Created Successfully" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tag:** ${{ inputs.tag_name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Type:** ${{ inputs.release_type }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Latest:** ${{ inputs.make_latest }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release URL:** ${{ steps.create_release.outputs.url }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "The release has been published and is now available for download." |