Beta Release #201
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: Continuous Delivery | |
| run-name: ${{ inputs.docs_only && 'Docs Only' || (inputs.production_release && 'Production Release' || 'Beta Release') }} | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths-ignore: | |
| - "docs/**" | |
| - "*.md" | |
| - ".github/assets/**" | |
| - "mkdocs.yml" | |
| - ".readthedocs.yaml" | |
| workflow_dispatch: | |
| inputs: | |
| production_release: | |
| description: "Production release?" | |
| type: boolean | |
| required: true | |
| default: false | |
| docs_only: | |
| description: "Publish docs only (skip release and PyPI)?" | |
| type: boolean | |
| required: true | |
| default: false | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'push' }} | |
| permissions: | |
| contents: read | |
| packages: read | |
| jobs: | |
| release: | |
| name: Semantic Release | |
| # Skip release job when docs_only flag is set | |
| if: ${{ !inputs.docs_only }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| outputs: | |
| released: ${{ steps.release.outputs.released }} | |
| permissions: | |
| # IMPORTANT: mandatory for trusted publishing and GitHub releases | |
| id-token: write | |
| contents: write | |
| packages: read | |
| steps: | |
| - uses: actions/create-github-app-token@v3 | |
| id: app-token | |
| with: | |
| app-id: ${{ secrets.BOT_ID }} | |
| private-key: ${{ secrets.BOT_SK }} | |
| - uses: actions/checkout@v6 | |
| with: | |
| # Fetch entire repository history so we can determine version number from it | |
| fetch-depth: 0 | |
| token: ${{ steps.app-token.outputs.token }} | |
| - run: git config --global user.name "CI" && git config --global user.email "ci@local" | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: | | |
| uv.lock | |
| pyproject.toml | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "22" | |
| - name: Install pnpm | |
| uses: pnpm/action-setup@v5 | |
| - name: Install JavaScript workspace dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build bundled web UI | |
| run: uv run poe web-build | |
| - name: Run release smoke checks | |
| run: | | |
| set -o pipefail | |
| uv run poe db-migrations-check | |
| uv run pytest tests/core/unit/ -m "core and unit" -n auto -q | |
| - name: Run Semantic Release | |
| id: release | |
| env: | |
| GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: | | |
| rm -rf dist/ | |
| if [[ "${{ inputs.production_release }}" == "true" ]]; then | |
| uv run semantic-release version | |
| else | |
| uv run semantic-release version --as-prerelease --prerelease-token beta | |
| fi | |
| # Detect whether a release was built | |
| if ls dist/*.whl 1>/dev/null 2>&1; then | |
| echo "released=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "released=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Ensure version tag is on main | |
| if: steps.release.outputs.released == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: | | |
| # semantic-release creates a version-bump commit and tags it, but if the | |
| # push races with other merges the tag can land on a detached branch. | |
| # Force-push main so the tagged commit is always reachable. | |
| git push origin HEAD:main --force | |
| - name: Publish GitHub Release | |
| if: steps.release.outputs.released == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: uv run semantic-release publish | |
| - name: Publish to PyPI | |
| if: steps.release.outputs.released == 'true' | |
| uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| verbose: true | |
| publish-docs: | |
| name: Publish Documentation | |
| # Conditionally depend on release job (only when not docs_only mode) | |
| needs: release | |
| # Run docs publishing in two scenarios: | |
| # 1. After a successful production release on main branch | |
| # 2. When docs_only flag is set (on main branch only) | |
| # Note: docs_only takes precedence if both flags are set | |
| if: always() && !cancelled() && github.ref == 'refs/heads/main' && (needs.release.result == 'success' || needs.release.result == 'skipped') && (inputs.production_release || inputs.docs_only) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: | | |
| uv.lock | |
| pyproject.toml | |
| - name: Install dependencies | |
| run: uv sync --frozen --dev | |
| - name: Build documentation | |
| run: uv run mkdocs build | |
| - name: Setup Pages | |
| uses: actions/configure-pages@v6 | |
| - name: Upload artifact | |
| uses: actions/upload-pages-artifact@v4 | |
| with: | |
| path: site | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v5 |