release: jaclang 0.14.0, jac-byllm 0.6.4, jac-client 0.3.12, jac-scale 0.2.14, jac-super 0.1.10, jac-mcp 0.1.11, jaseci 2.3.13 #453
Workflow file for this run
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: Publish Release | |
| on: | |
| pull_request: | |
| types: [closed] | |
| branches: [main] | |
| permissions: {} | |
| jobs: | |
| # ============================================================================ | |
| # Parse release info from merged PR | |
| # ============================================================================ | |
| parse-release: | |
| if: | | |
| github.repository == 'Jaseci-Labs/jaseci' && | |
| github.event.pull_request.merged == true && | |
| startsWith(github.event.pull_request.head.ref, 'release/') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| permissions: | |
| contents: read | |
| outputs: | |
| has_releases: ${{ steps.parse.outputs.has_releases }} | |
| has_precompile: ${{ steps.parse.outputs.has_precompile }} | |
| matrix: ${{ steps.parse.outputs.matrix }} | |
| precompile_matrix: ${{ steps.parse.outputs.precompile_matrix }} | |
| release_summary: ${{ steps.parse.outputs.release_summary }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Parse release info | |
| id: parse | |
| env: | |
| PR_TITLE: ${{ github.event.pull_request.title }} | |
| run: | | |
| python scripts/parse_release.py --pr-title "$PR_TITLE" | |
| # ============================================================================ | |
| # Approval gate - ONE click to approve all publishing | |
| # ============================================================================ | |
| approve-release: | |
| needs: parse-release | |
| if: needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| environment: pypi | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Approval granted | |
| env: | |
| SUMMARY: ${{ needs.parse-release.outputs.release_summary }} | |
| run: | | |
| echo "Release approved: $SUMMARY" | |
| echo "Proceeding with publish..." | |
| # ============================================================================ | |
| # Precompile bytecode for packages that need it (parallel matrix) | |
| # Each package × Python version combination runs in parallel | |
| # ============================================================================ | |
| precompile: | |
| needs: [parse-release, approve-release] | |
| if: needs.parse-release.outputs.has_precompile == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.parse-release.outputs.precompile_matrix) }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| persist-credentials: false | |
| submodules: ${{ matrix.submodules }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python_version }} | |
| - name: Install jaclang | |
| run: pip install -e ./jac | |
| - name: Install package (if not jaclang) | |
| if: matrix.name != 'jaclang' | |
| run: pip install -e ./${{ matrix.dir }} | |
| - name: Precompile bytecode | |
| run: jac run jac/scripts/precompile_bytecode.jac ./${{ matrix.dir }} | |
| - name: Upload precompiled artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.precompile_artifact }}-${{ matrix.python_version }} | |
| path: ${{ matrix.precompile_path }}/ | |
| retention-days: 1 | |
| # ============================================================================ | |
| # Build packages (with precompiled artifacts if needed) | |
| # ============================================================================ | |
| build: | |
| needs: [parse-release, approve-release, precompile] | |
| # Run even if precompile was skipped (for packages that don't need it) | |
| if: | | |
| always() && | |
| needs.parse-release.outputs.has_releases == 'true' && | |
| needs.approve-release.result == 'success' && | |
| (needs.precompile.result == 'success' || needs.precompile.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.parse-release.outputs.matrix) }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| persist-credentials: false | |
| submodules: ${{ matrix.submodules }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| # Download precompiled artifacts for packages that need them | |
| - name: Download precompiled artifacts | |
| if: matrix.precompile == true | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ${{ matrix.precompile_path }}/ | |
| pattern: ${{ matrix.precompile_artifact }}-* | |
| merge-multiple: true | |
| # Install jaclang for packages that need extra build commands | |
| - name: Install jaclang (for build commands) | |
| if: matrix.extra_build_cmd != '' | |
| run: pip install -e ./jac | |
| # Install the package itself for extra build commands | |
| - name: Install package (for build commands) | |
| if: matrix.extra_build_cmd != '' && matrix.name != 'jaclang' | |
| run: pip install -e ./${{ matrix.dir }} | |
| # Install extra pip dependencies for build commands (e.g., jac-client for admin UI) | |
| - name: Install extra build dependencies | |
| if: matrix.extra_build_deps != '' | |
| run: pip install -e ./${{ matrix.extra_build_deps }} | |
| # Set up Node.js for packages that need it (e.g., admin UI build) | |
| - name: Set up Node.js (for client builds) | |
| if: matrix.needs_nodejs == true | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Set up Bun (for client builds) | |
| if: matrix.needs_nodejs == true | |
| uses: oven-sh/setup-bun@v2 | |
| # Run extra build commands (e.g., bundle_docs for jac-mcp, build_admin_ui for jac-scale) | |
| - name: Run extra build commands | |
| if: matrix.extra_build_cmd != '' | |
| working-directory: ${{ matrix.dir }} | |
| run: ${{ matrix.extra_build_cmd }} | |
| # Build the package | |
| - name: Install build tools | |
| run: pip install build | |
| - name: Build package | |
| working-directory: ${{ matrix.dir }} | |
| run: python -m build | |
| - name: Upload package artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: Packages-${{ matrix.pypi }} | |
| path: ${{ matrix.dir }}/dist/* | |
| # ============================================================================ | |
| # Publish Tier 1: jaclang (base package) | |
| # ============================================================================ | |
| publish-tier1: | |
| needs: [parse-release, build] | |
| if: needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.parse-release.outputs.matrix) }} | |
| steps: | |
| - name: Check if tier 1 | |
| id: check | |
| run: | | |
| if [[ "${{ matrix.tier }}" != "1" ]]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Download package | |
| if: steps.check.outputs.skip != 'true' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: Packages-${{ matrix.pypi }} | |
| path: dist | |
| - name: Publish to PyPI | |
| if: steps.check.outputs.skip != 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| password: ${{ secrets.PYPI_TOKEN }} | |
| wait-tier1: | |
| needs: [parse-release, publish-tier1] | |
| if: needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Wait for tier 1 on PyPI | |
| env: | |
| MATRIX: ${{ needs.parse-release.outputs.matrix }} | |
| run: python scripts/wait_for_pypi.py --matrix "$MATRIX" --tier 1 | |
| # ============================================================================ | |
| # Publish Tier 2: packages depending on jaclang | |
| # ============================================================================ | |
| publish-tier2: | |
| needs: [parse-release, build, wait-tier1] | |
| if: needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.parse-release.outputs.matrix) }} | |
| steps: | |
| - name: Check if tier 2 | |
| id: check | |
| run: | | |
| if [[ "${{ matrix.tier }}" != "2" ]]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Download package | |
| if: steps.check.outputs.skip != 'true' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: Packages-${{ matrix.pypi }} | |
| path: dist | |
| - name: Publish to PyPI | |
| if: steps.check.outputs.skip != 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| password: ${{ secrets.PYPI_TOKEN }} | |
| wait-tier2: | |
| needs: [parse-release, publish-tier2] | |
| if: needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Wait for tier 2 on PyPI | |
| env: | |
| MATRIX: ${{ needs.parse-release.outputs.matrix }} | |
| run: python scripts/wait_for_pypi.py --matrix "$MATRIX" --tier 2 | |
| # ============================================================================ | |
| # Publish Tier 3: jaseci meta-package | |
| # ============================================================================ | |
| publish-tier3: | |
| needs: [parse-release, build, wait-tier2] | |
| if: needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.parse-release.outputs.matrix) }} | |
| steps: | |
| - name: Check if tier 3 | |
| id: check | |
| run: | | |
| if [[ "${{ matrix.tier }}" != "3" ]]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Download package | |
| if: steps.check.outputs.skip != 'true' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: Packages-${{ matrix.pypi }} | |
| path: dist | |
| - name: Publish to PyPI | |
| if: steps.check.outputs.skip != 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| password: ${{ secrets.PYPI_TOKEN }} | |
| wait-tier3: | |
| needs: [parse-release, publish-tier3] | |
| if: needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Wait for tier 3 on PyPI | |
| env: | |
| MATRIX: ${{ needs.parse-release.outputs.matrix }} | |
| run: python scripts/wait_for_pypi.py --matrix "$MATRIX" --tier 3 | |
| # ============================================================================ | |
| # Push tags after successful publish | |
| # ============================================================================ | |
| push-tags: | |
| needs: [parse-release, publish-tier1, publish-tier2, publish-tier3] | |
| if: | | |
| always() && | |
| needs.parse-release.outputs.has_releases == 'true' && | |
| (needs.publish-tier1.result == 'success' || needs.publish-tier2.result == 'success' || needs.publish-tier3.result == 'success') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| outputs: | |
| jaseci_version: ${{ steps.tags.outputs.jaseci_version }} | |
| jaseci_release_tag: ${{ steps.tags.outputs.jaseci_release_tag }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: true | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Push tags | |
| id: tags | |
| env: | |
| MATRIX: ${{ needs.parse-release.outputs.matrix }} | |
| TIER1_RESULT: ${{ needs.publish-tier1.result }} | |
| TIER2_RESULT: ${{ needs.publish-tier2.result }} | |
| TIER3_RESULT: ${{ needs.publish-tier3.result }} | |
| run: | | |
| echo "$MATRIX" | jq -c '.include[]' | while read -r pkg; do | |
| pypi_name=$(echo "$pkg" | jq -r '.pypi') | |
| version=$(echo "$pkg" | jq -r '.version') | |
| tier=$(echo "$pkg" | jq -r '.tier') | |
| case "$tier" in | |
| 1) result="$TIER1_RESULT" ;; | |
| 2) result="$TIER2_RESULT" ;; | |
| 3) result="$TIER3_RESULT" ;; | |
| esac | |
| if [[ "$result" == "success" ]]; then | |
| tag="${pypi_name}-v${version}" | |
| echo "Creating tag: $tag" | |
| git tag --annotate --message="Release ${pypi_name} ${version}" "$tag" "$GITHUB_SHA" | |
| git push origin "$tag" | |
| # For jaseci, also create v{version} tag for backwards compatibility | |
| # This is the primary release tag used for GitHub releases and standalone binaries | |
| if [[ "$pypi_name" == "jaseci" ]]; then | |
| vtag="v${version}" | |
| echo "Creating primary release tag: $vtag" | |
| git tag --annotate --message="Jaseci ${version}" "$vtag" "$GITHUB_SHA" | |
| git push origin "$vtag" | |
| echo "jaseci_version=$version" >> "$GITHUB_OUTPUT" | |
| echo "jaseci_release_tag=$vtag" >> "$GITHUB_OUTPUT" | |
| fi | |
| else | |
| echo "Skipping tag for $pypi_name (tier $tier result: $result)" | |
| fi | |
| done | |
| # ============================================================================ | |
| # Create GitHub Release | |
| # ============================================================================ | |
| create-github-release: | |
| needs: [parse-release, push-tags] | |
| if: always() && needs.push-tags.result == 'success' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download all packages | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| pattern: Packages-* | |
| merge-multiple: true | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| MATRIX: ${{ needs.parse-release.outputs.matrix }} | |
| RELEASE_SUMMARY: ${{ needs.parse-release.outputs.release_summary }} | |
| JASECI_RELEASE_TAG: ${{ needs.push-tags.outputs.jaseci_release_tag }} | |
| run: | | |
| # Use jaseci's v{version} tag if jaseci was released, otherwise first package's tag | |
| if [[ -n "$JASECI_RELEASE_TAG" ]]; then | |
| PRIMARY_TAG="$JASECI_RELEASE_TAG" | |
| else | |
| PRIMARY_TAG=$(echo "$MATRIX" | jq -r '.include[0] | "\(.pypi)-v\(.version)"') | |
| fi | |
| # Build release notes | |
| { | |
| echo "## Packages Released" | |
| echo "" | |
| while read -r pkg; do | |
| pypi_name=$(echo "$pkg" | jq -r '.pypi') | |
| version=$(echo "$pkg" | jq -r '.version') | |
| echo "- **${pypi_name}** ${version} ([PyPI](https://pypi.org/project/${pypi_name}/${version}/))" | |
| done < <(echo "$MATRIX" | jq -c '.include[]') | |
| } > release_notes.md | |
| # Create release | |
| gh release create "$PRIMARY_TAG" \ | |
| --verify-tag \ | |
| --title "Release: $RELEASE_SUMMARY" \ | |
| --notes-file release_notes.md \ | |
| dist/* | |
| # ============================================================================ | |
| # Build standalone binaries (triggered when jaseci is released) | |
| # ============================================================================ | |
| build-standalone-binaries: | |
| needs: [parse-release, wait-tier3, push-tags, create-github-release] | |
| if: | | |
| always() && | |
| needs.wait-tier3.result == 'success' && | |
| needs.push-tags.result == 'success' && | |
| needs.push-tags.outputs.jaseci_version != '' | |
| uses: ./.github/workflows/build-standalone.yml | |
| with: | |
| jaseci_version: ${{ needs.push-tags.outputs.jaseci_version }} | |
| release_tag: ${{ needs.push-tags.outputs.jaseci_release_tag }} | |
| permissions: | |
| contents: write | |
| # ============================================================================ | |
| # Summary | |
| # ============================================================================ | |
| summary: | |
| needs: [parse-release, precompile, build, publish-tier1, publish-tier2, publish-tier3, wait-tier3, push-tags, create-github-release, build-standalone-binaries] | |
| if: always() && needs.parse-release.outputs.has_releases == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Release Summary | |
| env: | |
| SUMMARY: ${{ needs.parse-release.outputs.release_summary }} | |
| PRECOMPILE: ${{ needs.precompile.result }} | |
| BUILD: ${{ needs.build.result }} | |
| TIER1: ${{ needs.publish-tier1.result }} | |
| TIER2: ${{ needs.publish-tier2.result }} | |
| TIER3: ${{ needs.publish-tier3.result }} | |
| TAGS: ${{ needs.push-tags.result }} | |
| RELEASE: ${{ needs.create-github-release.result }} | |
| STANDALONE: ${{ needs.build-standalone-binaries.result }} | |
| JASECI_VERSION: ${{ needs.push-tags.outputs.jaseci_version }} | |
| run: | | |
| { | |
| echo "## Release Summary: $SUMMARY" | |
| echo "" | |
| echo "| Step | Status |" | |
| echo "|------|--------|" | |
| echo "| Precompile | $PRECOMPILE |" | |
| echo "| Build | $BUILD |" | |
| echo "| Publish Tier 1 (jaclang) | $TIER1 |" | |
| echo "| Publish Tier 2 (plugins) | $TIER2 |" | |
| echo "| Publish Tier 3 (jaseci) | $TIER3 |" | |
| echo "| Push Tags | $TAGS |" | |
| echo "| GitHub Release | $RELEASE |" | |
| if [[ -n "$JASECI_VERSION" ]]; then | |
| echo "| Standalone Binaries | $STANDALONE |" | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| if [[ "$TIER1" == "failure" || "$TIER2" == "failure" || "$TIER3" == "failure" ]]; then | |
| echo "::error::Some packages failed to publish" | |
| exit 1 | |
| fi | |
| echo "All packages published successfully!" >> "$GITHUB_STEP_SUMMARY" |