release #55
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 main workflow completes | |
| workflow_run: | |
| workflows: ["main"] | |
| types: [completed] | |
| # Manual dispatch for debugging | |
| workflow_dispatch: | |
| permissions: | |
| id-token: write # Required for PyPI trusted publishing (OIDC) | |
| contents: write # Required for creating GitHub releases | |
| discussions: write # Required for posting to discussions | |
| pull-requests: read # Required for identifiers workflow | |
| jobs: | |
| check-main-workflow: | |
| name: Check if main workflow completed successfully | |
| runs-on: ubuntu-latest | |
| outputs: | |
| main_run_id: ${{ steps.check.outputs.main_run_id }} | |
| should_proceed: ${{ steps.check.outputs.should_proceed }} | |
| steps: | |
| - name: Check main workflow completion | |
| id: check | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const commitSha = context.payload.workflow_run?.head_sha || context.sha; | |
| const triggeredBy = context.payload.workflow_run?.name || 'manual (workflow_dispatch)'; | |
| console.log('─────────────────────────────────────────────────'); | |
| console.log('🔍 Checking main workflow completion status'); | |
| console.log('─────────────────────────────────────────────────'); | |
| console.log(`Event: ${context.eventName}`); | |
| console.log(`Commit SHA: ${commitSha}`); | |
| console.log(`Triggered by: ${triggeredBy}`); | |
| console.log(''); | |
| // Get 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 | |
| }); | |
| // Find latest main workflow run | |
| const mainRun = runs.workflow_runs | |
| .filter(run => run.name === 'main') | |
| .sort((a, b) => b.id - a.id)[0]; | |
| const mainComplete = mainRun && mainRun.status === 'completed' && mainRun.conclusion === 'success'; | |
| const status = mainRun ? `${mainRun.status}/${mainRun.conclusion}` : 'not found'; | |
| console.log(`Main workflow: ${status}`); | |
| console.log(''); | |
| if (!mainComplete) { | |
| console.log('⏳ Main workflow not complete yet - exiting early'); | |
| console.log(' This is normal! Release will proceed once main workflow finishes.'); | |
| } else { | |
| console.log('✅ Main workflow complete - proceeding with release!'); | |
| } | |
| console.log('─────────────────────────────────────────────────'); | |
| core.setOutput('should_proceed', mainComplete ? 'true' : 'false'); | |
| core.setOutput('main_run_id', mainRun?.id || ''); | |
| identifiers: | |
| name: Identifiers | |
| needs: check-main-workflow | |
| if: needs.check-main-workflow.outputs.should_proceed == '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 ! | |
| # Development/Nightly GitHub releases (for untagged master builds) | |
| release-development: | |
| name: Development/Nightly GitHub Release | |
| needs: [check-main-workflow, identifiers] | |
| runs-on: ubuntu-24.04 | |
| # Only create releases for development/nightly builds (not stable tags) | |
| if: | | |
| needs.check-main-workflow.outputs.should_proceed == 'true' && | |
| (github.event_name == 'workflow_dispatch' || | |
| (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')) && | |
| (needs.identifiers.outputs.release_type == 'development' || needs.identifiers.outputs.release_type == 'nightly') | |
| 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: Install uv | |
| uses: astral-sh/setup-uv@v6 | |
| - name: Set up Python 3.11 | |
| run: uv python install 3.11 | |
| - name: Install just | |
| uses: extractions/setup-just@v3 | |
| - name: Create venv and install build tools | |
| run: | | |
| just create cpy311 | |
| just install-build-tools cpy311 | |
| - name: Build distribution packages | |
| run: just dist cpy311 | |
| - name: Verify packages | |
| run: just verify-dist cpy311 | |
| - name: List built packages | |
| run: | | |
| echo "Built packages:" | |
| ls -lh dist/ | |
| - name: Validate and prepare release fileset for GitHub | |
| uses: wamp-proto/wamp-cicd/actions/check-release-fileset@main | |
| with: | |
| distdir: dist | |
| mode: strict | |
| keep-metadata: true # Keep CHECKSUMS for user verification | |
| targets: | | |
| py3-none-any | |
| source | |
| - name: Create development GitHub release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.identifiers.outputs.release_name }} | |
| name: Development Build ${{ needs.identifiers.outputs.release_name }} | |
| body: | | |
| ## Crossbar.io Development Build | |
| **Release:** ${{ needs.identifiers.outputs.release_name }} | |
| **Type:** ${{ needs.identifiers.outputs.release_type }} | |
| **Branch:** ${{ needs.identifiers.outputs.base_branch }} | |
| **Commit:** ${{ needs.identifiers.outputs.head_sha }} | |
| This is an automated development/nightly build for testing purposes. | |
| **Installation:** | |
| ```bash | |
| pip install https://github.com/crossbario/crossbar/releases/download/${{ needs.identifiers.outputs.release_name }}/crossbar-*.whl | |
| ``` | |
| **Files:** | |
| - Universal wheel (py3-none-any) | |
| - Source distribution (.tar.gz) | |
| - SHA256 checksums (CHECKSUMS-ALL.sha256) | |
| ⚠️ This is a development build - for production use, install from PyPI. | |
| files: dist/* | |
| draft: false | |
| prerelease: true | |
| discussion_category_name: ci-cd | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Production releases (for tagged stable builds) - GitHub + PyPI | |
| release-production: | |
| name: Production Release (GitHub + PyPI) | |
| needs: [check-main-workflow, identifiers] | |
| runs-on: ubuntu-24.04 | |
| # Only publish to PyPI for stable releases (explicit tag check) | |
| if: | | |
| needs.check-main-workflow.outputs.should_proceed == 'true' && | |
| (github.event_name == 'workflow_dispatch' || | |
| (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')) && | |
| 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/crossbar | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v6 | |
| - name: Set up Python 3.11 | |
| run: uv python install 3.11 | |
| - name: Install just | |
| uses: extractions/setup-just@v3 | |
| - name: Create venv and install build tools | |
| run: | | |
| just create cpy311 | |
| just install-build-tools cpy311 | |
| - name: Build distribution packages | |
| run: just dist cpy311 | |
| - name: Verify packages | |
| run: just verify-dist cpy311 | |
| - name: List built packages | |
| run: | | |
| echo "Built packages:" | |
| ls -lh dist/ | |
| - name: Validate and prepare release fileset for GitHub | |
| uses: wamp-proto/wamp-cicd/actions/check-release-fileset@main | |
| with: | |
| distdir: dist | |
| mode: strict | |
| keep-metadata: true # Keep CHECKSUMS for user verification | |
| targets: | | |
| py3-none-any | |
| source | |
| - name: Get version | |
| id: get_version | |
| run: | | |
| VERSION="${RELEASE_NAME#v}" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| # IMPORTANT: tag_name MUST be explicitly specified here! | |
| # | |
| # When this workflow runs via workflow_run trigger (after the main workflow | |
| # completes), github.ref is "refs/heads/master" (a branch), NOT the tag. | |
| # This is because workflow_run context inherits from the triggering workflow's | |
| # context, and even though the main workflow was triggered by a tag push, | |
| # the github.ref in the workflow_run context points to the default branch. | |
| # | |
| # The softprops/action-gh-release action defaults to using github.ref for | |
| # the tag name when tag_name is not specified. Since github.ref is a branch | |
| # (not a tag), the action fails with: "GitHub Releases requires a tag" | |
| # | |
| # Solution: Explicitly pass tag_name using the version extracted from | |
| # the identifiers workflow, which correctly detected the tag via | |
| # `git describe --tags --exact-match` on the head_sha. | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ steps.get_version.outputs.version }} | |
| name: v${{ steps.get_version.outputs.version }} | |
| body: | | |
| ## Crossbar.io v${{ steps.get_version.outputs.version }} | |
| Crossbar.io - Open source networking platform for distributed and microservice applications | |
| **Installation:** | |
| ```bash | |
| pip install crossbar==${{ steps.get_version.outputs.version }} | |
| ``` | |
| **Links:** | |
| - 📦 PyPI: https://pypi.org/project/crossbar/${{ steps.get_version.outputs.version }}/ | |
| - 📖 Docs: https://crossbar.io/docs/ | |
| - 💻 Source: https://github.com/crossbario/crossbar/tree/v${{ steps.get_version.outputs.version }} | |
| See [NEWS.rst](https://github.com/crossbario/crossbar/blob/master/NEWS.rst) for details. | |
| Also published to PyPI: https://pypi.org/project/crossbar/ | |
| files: dist/* | |
| draft: false | |
| prerelease: false | |
| discussion_category_name: ci-cd | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Validate and clean release fileset for PyPI | |
| uses: wamp-proto/wamp-cicd/actions/check-release-fileset@main | |
| with: | |
| distdir: dist | |
| mode: strict | |
| # keep-metadata: false (default - removes CHECKSUMS, build-info.txt etc for PyPI) | |
| targets: | | |
| py3-none-any | |
| source | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| # Use OIDC trusted publishing (no password needed) | |
| # Automatically generates and uploads attestations | |
| packages-dir: dist/ | |
| verify-metadata: true | |
| skip-existing: false | |
| print-hash: true | |
| attestations: true |