release #106
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: release | |
| on: | |
| # Auto-trigger after all build/test workflows complete | |
| workflow_run: | |
| workflows: ["wheels", "wheels-docker", "wstest", "main"] | |
| types: [completed] | |
| # Manual dispatch for debugging | |
| workflow_dispatch: | |
| jobs: | |
| check-all-workflows: | |
| name: Check if all workflows completed | |
| runs-on: ubuntu-latest | |
| outputs: | |
| all_complete: ${{ steps.check.outputs.all_complete }} | |
| wheels_run_id: ${{ steps.check.outputs.wheels_run_id }} | |
| wheels_docker_run_id: ${{ steps.check.outputs.wheels_docker_run_id }} | |
| wstest_run_id: ${{ steps.check.outputs.wstest_run_id }} | |
| main_run_id: ${{ steps.check.outputs.main_run_id }} | |
| steps: | |
| - name: Check all required workflows completed | |
| id: check | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const requiredWorkflows = ['wheels', 'wheels-docker', 'wstest', 'main']; | |
| const commitSha = context.payload.workflow_run.head_sha; | |
| console.log('─────────────────────────────────────────────────'); | |
| console.log('🔍 Checking workflow completion status'); | |
| console.log('─────────────────────────────────────────────────'); | |
| console.log(`Commit SHA: ${commitSha}`); | |
| console.log(`Triggered by: ${context.payload.workflow_run.name}`); | |
| console.log(''); | |
| // Get all workflow runs for this commit | |
| const { data: runs } = await github.rest.actions.listWorkflowRunsForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| head_sha: commitSha, | |
| per_page: 100 | |
| }); | |
| // Group by workflow name and find latest run for each | |
| const latestRuns = {}; | |
| for (const run of runs.workflow_runs) { | |
| const workflowName = run.name; | |
| if (requiredWorkflows.includes(workflowName)) { | |
| if (!latestRuns[workflowName] || run.id > latestRuns[workflowName].id) { | |
| latestRuns[workflowName] = run; | |
| } | |
| } | |
| } | |
| // Check if all required workflows completed successfully | |
| console.log('Required workflows status:'); | |
| const allComplete = requiredWorkflows.every(name => { | |
| const run = latestRuns[name]; | |
| const complete = run && run.status === 'completed' && run.conclusion === 'success'; | |
| const status = run ? `${run.status}/${run.conclusion}` : 'not found'; | |
| console.log(` ${complete ? '✅' : '⏳'} ${name.padEnd(20)} : ${status}`); | |
| return complete; | |
| }); | |
| console.log(''); | |
| if (!allComplete) { | |
| console.log('⏳ Not all workflows complete yet - exiting early'); | |
| console.log(' This is normal! Release will proceed once all workflows finish.'); | |
| } else { | |
| console.log('✅ All workflows complete - proceeding with release!'); | |
| } | |
| console.log('─────────────────────────────────────────────────'); | |
| core.setOutput('all_complete', allComplete ? 'true' : 'false'); | |
| // Output run IDs for artifact downloads (using sanitized names) | |
| core.setOutput('wheels_run_id', latestRuns['wheels']?.id || ''); | |
| core.setOutput('wheels_docker_run_id', latestRuns['wheels-docker']?.id || ''); | |
| core.setOutput('wstest_run_id', latestRuns['wstest']?.id || ''); | |
| core.setOutput('main_run_id', latestRuns['main']?.id || ''); | |
| identifiers: | |
| needs: check-all-workflows | |
| if: needs.check-all-workflows.outputs.all_complete == 'true' | |
| # GitHub needs to know where .cicd/workflows/identifiers.yml lives at parse time, | |
| # and submodules aren't included in that context! thus the following does NOT work: | |
| # uses: ./.cicd/workflows/identifiers.yml | |
| # we MUST reference the remote repo directly: | |
| uses: wamp-proto/wamp-cicd/.github/workflows/identifiers.yml@main | |
| # IMPORTANT: we still need .cicd as a Git submodule in the using repo though! | |
| # because e.g. identifiers.yml wants to access scripts/sanitize.sh ! | |
| # Nightly and stable GitHub releases (consolidates wheels from both workflows) | |
| release-nightly: | |
| name: Nightly & Stable GitHub Releases | |
| needs: [check-all-workflows, identifiers] | |
| runs-on: ubuntu-latest | |
| # Only create releases for nightly and stable builds (explicit positive list) | |
| if: | | |
| needs.check-all-workflows.outputs.all_complete == 'true' && | |
| github.event_name == 'workflow_run' && | |
| github.event.workflow_run.conclusion == 'success' && | |
| (needs.identifiers.outputs.release_type == 'nightly' || needs.identifiers.outputs.release_type == 'stable') | |
| env: | |
| RELEASE_TYPE: ${{ needs.identifiers.outputs.release_type }} | |
| RELEASE_NAME: ${{ needs.identifiers.outputs.release_name }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Download all wheel artifacts (from wheels workflow) | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: wheels-* | |
| merge-multiple: true | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download source distribution | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-distribution | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download Linux wheels without NVX | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: linux-wheels-no-nvx | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download manylinux wheel artifacts (from wheels-docker workflow) | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: artifacts-* | |
| merge-multiple: true | |
| path: wheelhouse/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_docker_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download wstest conformance summary | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: conformance-summary-* | |
| merge-multiple: true | |
| path: wstest-results/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wstest_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download FlatBuffers schema artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: flatbuffers-schema-* | |
| merge-multiple: true | |
| path: flatbuffers-schema/ | |
| run-id: ${{ needs.check-all-workflows.outputs.main_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Consolidate all artifacts | |
| run: | | |
| echo "==> Consolidating all artifacts into unified release directory..." | |
| mkdir -p release-artifacts | |
| # Copy wheels from wheels workflow | |
| if [ -d "dist" ]; then | |
| echo "Copying wheels workflow artifacts..." | |
| find dist -type f \( -name "*.whl" -o -name "*.tar.gz" \) -exec cp {} release-artifacts/ \; | |
| fi | |
| # Copy wheels from wheels-docker workflow | |
| if [ -d "wheelhouse" ]; then | |
| echo "Copying wheels-docker workflow artifacts..." | |
| find wheelhouse -type f \( -name "*.whl" -o -name "*.tar.gz" \) -exec cp {} release-artifacts/ \; | |
| fi | |
| # Copy wstest conformance results | |
| if [ -d "wstest-results" ]; then | |
| echo "Copying wstest conformance results..." | |
| find wstest-results -type f -exec cp {} release-artifacts/ \; | |
| fi | |
| # Package FlatBuffers schema as tarball | |
| if [ -d "flatbuffers-schema" ]; then | |
| echo "Packaging FlatBuffers schema..." | |
| tar -czf release-artifacts/flatbuffers-schema.tar.gz -C flatbuffers-schema . | |
| fi | |
| echo "" | |
| echo "==> Unified release artifact inventory:" | |
| ls -la release-artifacts/ || echo "No artifacts found" | |
| echo "" | |
| echo "Wheels: $(find release-artifacts -name "*.whl" | wc -l)" | |
| echo "Source dists: $(find release-artifacts -name "*.tar.gz" ! -name "flatbuffers-schema.tar.gz" | wc -l)" | |
| echo "Wstest reports: $(find release-artifacts -name "*wstest*" | wc -l)" | |
| echo "FlatBuffers schema: $(ls release-artifacts/flatbuffers-schema.tar.gz 2>/dev/null && echo 'packaged' || echo 'not found')" | |
| - name: Install jinja2-cli for template rendering | |
| run: | | |
| pip install jinja2-cli | |
| - name: Render release notes from Jinja2 template | |
| run: | | |
| echo "==> Preparing release notes using Jinja2 template..." | |
| echo "Release type: $RELEASE_TYPE" | |
| echo "Release name: $RELEASE_NAME" | |
| # Collect template variables | |
| COMMIT_SHA="${GITHUB_SHA::8}" | |
| BUILD_DATE="$(date -u +'%Y-%m-%d %H:%M:%S UTC')" | |
| WHEEL_COUNT="$(find release-artifacts -name "*.whl" | wc -l)" | |
| SDIST_COUNT="$(find release-artifacts -name "*.tar.gz" | wc -l)" | |
| # Select template based on release type | |
| if [ "$RELEASE_TYPE" = "stable" ]; then | |
| TEMPLATE=".github/templates/release-stable.md.j2" | |
| else | |
| TEMPLATE=".github/templates/release-nightly.md.j2" | |
| fi | |
| # Render template using jinja2 | |
| jinja2 "$TEMPLATE" \ | |
| -D release_name="$RELEASE_NAME" \ | |
| -D commit_sha="$COMMIT_SHA" \ | |
| -D build_date="$BUILD_DATE" \ | |
| -D wheel_count="$WHEEL_COUNT" \ | |
| -D sdist_count="$SDIST_COUNT" \ | |
| -o release-notes.md | |
| echo "" | |
| echo "==> Generated release notes:" | |
| cat release-notes.md | |
| - name: Create unified GitHub release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| echo "==> Creating unified GitHub release..." | |
| echo "Release type: $RELEASE_TYPE" | |
| echo "Release name: $RELEASE_NAME" | |
| # Delete existing release if it exists (for nightly builds) | |
| gh release delete "$RELEASE_NAME" --repo "$GITHUB_REPOSITORY" --yes || true | |
| # Set release title based on type | |
| if [ "$RELEASE_TYPE" = "stable" ]; then | |
| TITLE="Release $RELEASE_NAME" | |
| else | |
| TITLE="Nightly Build $RELEASE_NAME" | |
| fi | |
| # Create the release using rendered notes | |
| gh release create "$RELEASE_NAME" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "$TITLE" \ | |
| --notes-file release-notes.md \ | |
| release-artifacts/* | |
| echo "✅ Release $RELEASE_NAME created successfully" | |
| # Stable release publishing: PyPI and RTD (consolidates from both wheel workflows) | |
| release-stable: | |
| name: Stable Release (PyPI & RTD) | |
| needs: [check-all-workflows, identifiers, release-nightly] | |
| runs-on: ubuntu-latest | |
| # Only publish to PyPI for stable releases (explicit positive list) | |
| if: | | |
| needs.check-all-workflows.outputs.all_complete == 'true' && | |
| needs.identifiers.outputs.release_type == 'stable' | |
| env: | |
| RELEASE_TYPE: ${{ needs.identifiers.outputs.release_type }} | |
| RELEASE_NAME: ${{ needs.identifiers.outputs.release_name }} | |
| environment: | |
| name: pypi | |
| url: https://pypi.org/p/autobahn | |
| permissions: | |
| id-token: write # For trusted publishing | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Download macOS wheels | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: wheels-macos-arm64 | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download Windows wheels | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: wheels-windows-x86_64 | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download source distribution | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: source-distribution | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download Linux wheels without NVX | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: linux-wheels-no-nvx | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Download manylinux wheels with NVX (from wheels-docker) | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: artifacts-* | |
| merge-multiple: true | |
| path: dist/ | |
| run-id: ${{ needs.check-all-workflows.outputs.wheels_docker_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: List artifacts for PyPI publishing | |
| run: | | |
| echo "Publishing to PyPI for release: $RELEASE_NAME" | |
| ls -la dist/ | |
| echo "" | |
| echo "macOS wheels: $(find dist -name "*macos*.whl" 2>/dev/null | wc -l)" | |
| echo "Windows wheels: $(find dist -name "*win*.whl" 2>/dev/null | wc -l)" | |
| echo "Linux manylinux wheels: $(find dist -name "*manylinux*.whl" 2>/dev/null | wc -l)" | |
| echo "Linux fallback wheels: $(find dist -name "*linux*.whl" ! -name "*manylinux*.whl" 2>/dev/null | wc -l)" | |
| echo "Source distributions: $(find dist -name "*.tar.gz" 2>/dev/null | wc -l)" | |
| echo "" | |
| echo "Total PyPI artifacts: $(find dist -type f \( -name "*.whl" -o -name "*.tar.gz" \) | wc -l)" | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| # Uses trusted publishing - no API token needed | |
| # Configure at: https://pypi.org/manage/account/publishing/ | |
| verbose: true | |
| - name: Trigger RTD build | |
| env: | |
| RTD_TOKEN: ${{ secrets.RTD_TOKEN }} | |
| run: | | |
| if [ -n "$RTD_TOKEN" ]; then | |
| echo "Triggering Read the Docs build for autobahn..." | |
| curl -X POST \ | |
| -H "Authorization: Token $RTD_TOKEN" \ | |
| "https://readthedocs.org/api/v3/projects/autobahn/versions/latest/builds/" | |
| echo "✅ RTD build triggered successfully" | |
| else | |
| echo "⚠️ RTD_TOKEN not configured, skipping RTD build trigger" | |
| fi |