Generics & variance, algebraic-effect handlers, and documentation com… #16
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: Release | |
| # Tag-triggered release. THIS is the only thing that publishes Osprey. | |
| # Pushing a tag like v1.2.3 builds per-platform binaries, cuts a GitHub Release, | |
| # updates the Homebrew tap + Scoop bucket, publishes the per-platform VSIX to the | |
| # VS Code Marketplace, and (only on success) deploys the website + web compiler. | |
| # | |
| # Trigger rules (see docs/RELEASING.md): | |
| # - release -> ONLY on tag push v* | |
| # - CI -> ONLY on PR to main (ci.yml / ci-windows.yml) | |
| # - merge to main -> nothing | |
| # | |
| # Version stamping ([SWR-VERSION-BUILD-STAMPING]): the version is derived from | |
| # the tag and stamped into every artifact. Source stays at 0.0.0-dev. | |
| # | |
| # Cost gate ([SWR-REL-CHANGES-*]): the `scope` job diffs this tag against the | |
| # previous one and gates the rest, so a website/benchmark-only tag deploys the | |
| # site without rebuilding the macOS/Windows binary matrix or republishing | |
| # brew/scoop/VSIX/Marketplace. Ruleset: .github/release-scope.json. | |
| # | |
| # Job shapes follow Shipwright's templates/gh-actions/*.yml (binary-multiplatform, | |
| # publish-brew-tap, publish-scoop-bucket, publish-vsix-per-platform, | |
| # release-change-detection). | |
| on: | |
| push: | |
| tags: ['v*'] | |
| permissions: | |
| contents: write | |
| env: | |
| # Stable identity used across formula/manifest/marketplace. | |
| PRODUCT_REPO: Nimblesite/osprey | |
| HOMEPAGE: https://ospreylang.dev | |
| DESCRIPTION: "Osprey — a functional language with algebraic effects, fibers, and compile-time safety" | |
| jobs: | |
| # -------------------------------------------------------------------------- | |
| # Release scope (COST GATE) — diff this tag against the previous release tag and | |
| # decide which surfaces must publish, so the expensive macOS/Windows build matrix | |
| # only runs when the artifact it produces actually changed. Ruleset lives in | |
| # .github/release-scope.json. Implements [SWR-REL-CHANGES-*]: | |
| # binary changed -> full release (build matrix + every channel) | |
| # vsix changed -> still build the matrix (the VSIX bundles a binary at the | |
| # new tag version), publish the VSIX, skip the other channels | |
| # website only -> deploy the site, skip the whole matrix | |
| # unclassified path -> full release, fail-safe | |
| scope: | |
| name: Decide release scope | |
| uses: ./.github/workflows/release-change-detection.yml | |
| permissions: | |
| contents: read | |
| with: | |
| # Pinned Shipwright commit the classifier is installed from [SWR-SEC-ACTION-PINNING]. | |
| shipwright_rev: 78f1455f27e8bfefc96e757a3eab23289be0e3f7 | |
| # -------------------------------------------------------------------------- | |
| version: | |
| name: Resolve version from tag | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.v.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| cache-dependency-path: vscode-extension/package-lock.json | |
| - name: Install Shipwright validator dependencies | |
| working-directory: vscode-extension | |
| run: npm ci | |
| - name: Derive version + validate manifest | |
| id: v | |
| run: | | |
| set -euo pipefail | |
| version="${GITHUB_REF_NAME#v}" | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| echo "Releasing osprey $version" | |
| # [SWR-VERSION-MANIFEST] validate shipwright.json before building anything. | |
| npm run test:shipwright --prefix vscode-extension | |
| # -------------------------------------------------------------------------- | |
| build: | |
| name: Build ${{ matrix.platform }} | |
| needs: [version, scope] | |
| # The expensive native matrix runs only when an artifact that bundles a binary | |
| # changed — a full release, or a vsix/jetbrains change (which must rebuild the | |
| # binary at the new tag version). A website-only tag skips it. [SWR-REL-CHANGES-MATRIX] | |
| if: ${{ needs.scope.outputs.build_matrix == 'true' }} | |
| runs-on: ${{ matrix.os }} | |
| # Windows is the newest, least-proven target — keep a win32 hiccup from | |
| # blocking the mac/linux binaries + VSIX publish. A win32 failure shows as a | |
| # failed leg (warning) but doesn't fail the build job. | |
| continue-on-error: ${{ matrix.platform == 'win32-x64' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: darwin-arm64 | |
| os: macos-14 | |
| # darwin-x64 (Intel mac) is dropped: GitHub is deprecating the free | |
| # `macos-13` Intel runner and it no longer allocates (jobs queue | |
| # indefinitely). Restore this leg once an Intel runner is available | |
| # (paid large runner) or via an Apple-Silicon → x86_64 cross-compile. | |
| - platform: linux-x64 | |
| os: ubuntu-latest | |
| - platform: win32-x64 | |
| os: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # ---- Linux + macOS: toolchain + C archives + stamped binary ------------- | |
| - name: Build (Linux/macOS) | |
| if: runner.os != 'Windows' | |
| uses: ./.github/actions/setup-osprey-compiler | |
| with: | |
| version: ${{ needs.version.outputs.version }} | |
| # ---- Windows: MSYS2 (MinGW C runtime) + cargo ------------------------- | |
| - name: Install Rust (Windows) | |
| if: runner.os == 'Windows' | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Setup MSYS2 (Windows) | |
| if: runner.os == 'Windows' | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: UCRT64 | |
| path-type: inherit | |
| install: >- | |
| make | |
| mingw-w64-ucrt-x86_64-gcc | |
| mingw-w64-ucrt-x86_64-llvm | |
| mingw-w64-ucrt-x86_64-pkgconf | |
| mingw-w64-ucrt-x86_64-openssl | |
| - name: Build (Windows) | |
| if: runner.os == 'Windows' | |
| shell: msys2 {0} | |
| env: | |
| OSPREY_VERSION: ${{ needs.version.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| make _runtime CC=gcc AR=ar SHELL=/usr/bin/bash MKDIR='mkdir -p' | |
| cargo build --release -p osprey-cli | |
| # ---- Verify version contract [SWR-VERSION-CLI-OUTPUT] ------------------ | |
| - name: Verify version | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| exe=""; [ "${{ runner.os }}" = "Windows" ] && exe=".exe" | |
| "target/release/osprey${exe}" --version | grep -Fx "osprey ${{ needs.version.outputs.version }}" | |
| # ---- Package: binary + runtime libs -> tar.gz + sha256 ----------------- | |
| - name: Package | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| v="${{ needs.version.outputs.version }}" | |
| plat="${{ matrix.platform }}" | |
| exe=""; [ "${{ runner.os }}" = "Windows" ] && exe=".exe" | |
| staging="osprey-$v-$plat" | |
| mkdir -p "dist/$staging" | |
| cp "target/release/osprey${exe}" "dist/$staging/" | |
| cp compiler/lib/lib*.a "dist/$staging/" 2>/dev/null || cp compiler/bin/lib*.a "dist/$staging/" 2>/dev/null || true | |
| tar -czf "dist/$staging.tar.gz" -C dist "$staging" | |
| # macOS ships shasum (Perl) but not sha256sum; Windows Git Bash ships | |
| # sha256sum but not shasum; Linux has both. Identical output format | |
| # (`<hash> <file>`), so the downstream `cut -d' ' -f1` parsing in the | |
| # brew/scoop jobs is unaffected. | |
| sha256() { if command -v shasum >/dev/null 2>&1; then shasum -a 256 "$@"; else sha256sum "$@"; fi; } | |
| ( cd dist && sha256 "$staging.tar.gz" | tee "$staging.tar.gz.sha256" ) | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: osprey-${{ matrix.platform }} | |
| path: dist/*.tar.gz* | |
| # -------------------------------------------------------------------------- | |
| github-release: | |
| name: Publish GitHub Release | |
| needs: [version, build, scope] | |
| # The standalone binary GitHub Release (and the brew/scoop jobs that depend on | |
| # it) only ship on a full release. [SWR-REL-CHANGES-CASCADE] | |
| if: ${{ needs.scope.outputs.full == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.version.outputs.version }} | |
| files: dist/*.tar.gz | |
| fail_on_unmatched_files: true | |
| # -------------------------------------------------------------------------- | |
| # Token preflight — brew/scoop (BREW_SCOOP_PAT) and Open VSX (OPEN_VSX_PAT) use | |
| # standing tokens that can't be minted from OIDC. Probe them once so those jobs | |
| # SKIP cleanly when the token isn't configured (the Marketplace OIDC publish + | |
| # binaries + GitHub Release + site still ship). Secrets aren't readable in a | |
| # job-level `if:`, so we surface their presence as booleans here. Add the | |
| # secrets later and re-run the skipped jobs — no re-tag needed. | |
| preflight: | |
| name: Probe optional publish tokens | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| has_brew: ${{ steps.probe.outputs.has_brew }} | |
| has_ovsx: ${{ steps.probe.outputs.has_ovsx }} | |
| steps: | |
| - id: probe | |
| env: | |
| BREW_SCOOP_PAT: ${{ secrets.BREW_SCOOP_PAT }} | |
| OPEN_VSX_PAT: ${{ secrets.OPEN_VSX_PAT }} | |
| run: | | |
| set -euo pipefail | |
| if [ -n "${BREW_SCOOP_PAT:-}" ]; then echo "has_brew=true" >> "$GITHUB_OUTPUT"; else echo "has_brew=false" >> "$GITHUB_OUTPUT"; echo "::warning::BREW_SCOOP_PAT not set — Homebrew + Scoop publish will be skipped"; fi | |
| if [ -n "${OPEN_VSX_PAT:-}" ]; then echo "has_ovsx=true" >> "$GITHUB_OUTPUT"; else echo "has_ovsx=false" >> "$GITHUB_OUTPUT"; echo "::warning::OPEN_VSX_PAT not set — Open VSX publish will be skipped"; fi | |
| # -------------------------------------------------------------------------- | |
| # Homebrew tap — shape from templates/gh-actions/publish-brew-tap.yml, adapted | |
| # to install the runtime libs and depend on llvm (osprey shells out to it). | |
| brew: | |
| name: Publish Homebrew formula | |
| needs: [version, github-release, preflight] | |
| if: ${{ needs.preflight.outputs.has_brew == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: { path: dist, merge-multiple: true } | |
| - uses: actions/checkout@v4 | |
| with: | |
| repository: Nimblesite/homebrew-tap | |
| token: ${{ secrets.BREW_SCOOP_PAT }} | |
| path: tap | |
| - name: Write formula | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| base="https://github.com/${PRODUCT_REPO}/releases/download/v${VERSION}" | |
| sha() { cut -d' ' -f1 "dist/osprey-${VERSION}-$1.tar.gz.sha256"; } | |
| arm=$(sha darwin-arm64); linux=$(sha linux-x64) | |
| mkdir -p tap/Formula | |
| cat > tap/Formula/osprey.rb <<RUBY | |
| # typed: false | |
| # frozen_string_literal: true | |
| class Osprey < Formula | |
| desc "${DESCRIPTION}" | |
| homepage "${HOMEPAGE}" | |
| version "${VERSION}" | |
| depends_on "llvm" | |
| on_macos do | |
| # Apple Silicon only — no Intel mac build (see release.yml matrix). | |
| on_arm do | |
| url "${base}/osprey-${VERSION}-darwin-arm64.tar.gz" | |
| sha256 "${arm}" | |
| end | |
| end | |
| on_linux do | |
| url "${base}/osprey-${VERSION}-linux-x64.tar.gz" | |
| sha256 "${linux}" | |
| end | |
| def install | |
| bin.install "osprey" | |
| lib.install Dir["lib*.a"] | |
| end | |
| test do | |
| assert_match "osprey ${VERSION}", shell_output("#{bin}/osprey --version") | |
| end | |
| end | |
| RUBY | |
| - name: Commit + push | |
| working-directory: tap | |
| run: | | |
| set -euo pipefail | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/osprey.rb | |
| git commit -m "osprey ${{ needs.version.outputs.version }}" || exit 0 | |
| git push | |
| # -------------------------------------------------------------------------- | |
| # Scoop bucket — shape from templates/gh-actions/publish-scoop-bucket.yml. | |
| # Windows install depends on llvm + gcc (MinGW) since osprey shells out to | |
| # llc/clang/gcc at compile time. [WINDOWS-PORT] | |
| scoop: | |
| name: Publish Scoop manifest | |
| needs: [version, github-release, preflight] | |
| if: ${{ needs.preflight.outputs.has_brew == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: { path: dist, merge-multiple: true } | |
| - uses: actions/checkout@v4 | |
| with: | |
| repository: Nimblesite/scoop-bucket | |
| token: ${{ secrets.BREW_SCOOP_PAT }} | |
| path: bucket | |
| - uses: actions/setup-node@v4 | |
| with: { node-version: '20' } | |
| - name: Write manifest | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| HASH=$(cut -d' ' -f1 "dist/osprey-${VERSION}-win32-x64.tar.gz.sha256") | |
| URL="https://github.com/${PRODUCT_REPO}/releases/download/v${VERSION}/osprey-${VERSION}-win32-x64.tar.gz" | |
| node - "$URL" "$HASH" <<'NODE' | |
| const fs = require("node:fs"); | |
| const [, , url, hash] = process.argv; | |
| const v = process.env.VERSION; | |
| const manifest = { | |
| version: v, | |
| description: process.env.DESCRIPTION, | |
| homepage: process.env.HOMEPAGE, | |
| license: "MIT", | |
| depends: ["llvm", "gcc"], | |
| architecture: { "64bit": { url, hash, extract_dir: `osprey-${v}-win32-x64` } }, | |
| bin: "osprey.exe", | |
| checkver: { github: `https://github.com/${process.env.PRODUCT_REPO}` }, | |
| autoupdate: { | |
| architecture: { | |
| "64bit": { | |
| url: `https://github.com/${process.env.PRODUCT_REPO}/releases/download/v$version/osprey-$version-win32-x64.tar.gz`, | |
| extract_dir: "osprey-$version-win32-x64", | |
| }, | |
| }, | |
| }, | |
| }; | |
| fs.mkdirSync("bucket/bucket", { recursive: true }); | |
| fs.writeFileSync("bucket/bucket/osprey.json", JSON.stringify(manifest, null, 2) + "\n"); | |
| NODE | |
| - name: Commit + push | |
| working-directory: bucket | |
| run: | | |
| set -euo pipefail | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add bucket/osprey.json | |
| git commit -m "osprey ${{ needs.version.outputs.version }}" || exit 0 | |
| git push | |
| # -------------------------------------------------------------------------- | |
| # Per-platform VSIX — shape from templates/gh-actions/publish-vsix-per-platform.yml | |
| # (which follows the official microsoft/vscode-platform-specific-sample). The | |
| # matching osprey binary + runtime libs + shipwright.json are bundled so the | |
| # extension launches a version-matched compiler verified by @nimblesite/shipwright-vscode. | |
| vsix: | |
| name: Publish VSIX ${{ matrix.target }} | |
| needs: [version, build, scope] | |
| # Package the per-platform VSIX only when the extension changed (or a full | |
| # release). build_matrix is guaranteed true here, so the bundled binary is | |
| # rebuilt at the new tag version. [SWR-REL-CHANGES-MATRIX] | |
| if: ${{ needs.scope.outputs.vsix == 'true' }} | |
| runs-on: ${{ matrix.os }} | |
| # Match the build job: a win32 VSIX hiccup must not block the mac/linux | |
| # VSIXes from reaching the Marketplace. | |
| continue-on-error: ${{ matrix.target == 'win32-x64' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { os: macos-14, target: darwin-arm64, artifact: darwin-arm64 } | |
| # darwin-x64 dropped — see the build matrix note (no Intel runner). | |
| - { os: ubuntu-latest, target: linux-x64, artifact: linux-x64 } | |
| - { os: windows-latest, target: win32-x64, artifact: win32-x64 } | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: { node-version: '20' } | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: osprey-${{ matrix.artifact }} | |
| path: dist | |
| - name: Stage bundled compiler + manifest | |
| shell: bash | |
| env: | |
| VERSION: ${{ needs.version.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| tar -xzf "dist/osprey-${VERSION}-${{ matrix.target }}.tar.gz" -C dist | |
| dest="vscode-extension/bin/${{ matrix.target }}" | |
| mkdir -p "$dest" | |
| cp -r "dist/osprey-${VERSION}-${{ matrix.target }}/." "$dest/" | |
| # Stamp + bundle shipwright.json so the extension can version-check the | |
| # bundled binary at activation. [SWR-VERSION-MANIFEST] | |
| node -e ' | |
| const fs=require("fs"); const v=process.env.VERSION; | |
| const m=JSON.parse(fs.readFileSync("shipwright.json","utf8")); | |
| m.product.version=v; | |
| for (const c of m.components) if (c.expectedVersion) c.expectedVersion=v; | |
| fs.writeFileSync("vscode-extension/shipwright.json", JSON.stringify(m,null,2)+"\n"); | |
| ' | |
| - name: Install deps + stamp package.json | |
| working-directory: vscode-extension | |
| run: | | |
| npm install | |
| npm version "${{ needs.version.outputs.version }}" --no-git-tag-version --allow-same-version | |
| npm run compile | |
| - name: Package VSIX | |
| working-directory: vscode-extension | |
| run: npx vsce package --target ${{ matrix.target }} | |
| - name: Verify bundled binary is inside the VSIX | |
| shell: bash | |
| working-directory: vscode-extension | |
| run: | | |
| set -euo pipefail | |
| exe=""; [ "${{ runner.os }}" = "Windows" ] && exe=".exe" | |
| unzip -l *.vsix | grep -F "extension/bin/${{ matrix.target }}/osprey${exe}" | |
| # Packaging is per-platform (each VSIX bundles the matching native binary); | |
| # publishing is centralised in the publish-marketplace / publish-openvsx | |
| # jobs so the registry tokens live in one least-privilege place. | |
| - name: Upload VSIX artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: osprey-vsix-${{ matrix.target }} | |
| path: vscode-extension/*.vsix | |
| if-no-files-found: error | |
| retention-days: 7 | |
| # -------------------------------------------------------------------------- | |
| # Marketplace publish — passwordless via Microsoft Entra ID OIDC. The `release` | |
| # environment gives the GitHub OIDC subject the stable | |
| # repo:Nimblesite/osprey:environment:release shape that the shared | |
| # `Nimblesite-VSCode-Marketplace` app's federated credential trusts; the | |
| # short-lived Marketplace token is minted from that session and handed to vsce | |
| # via VSCE_PAT — no PAT is stored. AZURE_CLIENT_ID + AZURE_TENANT_ID are the | |
| # non-sensitive identifiers of the shared app/tenant. See | |
| # Nimblesite/NimblesiteDeployment docs/vscode-marketplace-oidc.md. | |
| publish-marketplace: | |
| name: Publish VSIX to VS Code Marketplace | |
| needs: [version, vsix] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| environment: release | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/setup-node@v4 | |
| with: { node-version: '20' } | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| pattern: osprey-vsix-* | |
| path: artifacts | |
| - uses: azure/login@v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| allow-no-subscriptions: true | |
| # One `vsce publish` per platform-specific VSIX — vsce silently uses only | |
| # the first when several are globbed into a single call. A hyphenated tag | |
| # (v1.2.3-rc.1) is a prerelease and gets --pre-release. The Marketplace | |
| # token is minted from the Entra OIDC session via az; the resource GUID is | |
| # the immutable first-party app id vsce authenticates against. | |
| - name: Publish each platform VSIX (Entra OIDC, no PAT) | |
| run: | | |
| set -euo pipefail | |
| shopt -s globstar nullglob | |
| flag="" | |
| if [[ "${GITHUB_REF_NAME}" == *-* ]]; then | |
| flag="--pre-release" | |
| echo "Prerelease tag ${GITHUB_REF_NAME}; publishing with --pre-release" | |
| fi | |
| VSCE_PAT="$(az account get-access-token \ | |
| --resource 499b84ac-1321-427f-aa17-267ca6975798 \ | |
| --query accessToken -o tsv)" | |
| echo "::add-mask::${VSCE_PAT}" | |
| export VSCE_PAT | |
| published=0 | |
| for vsix in artifacts/**/*.vsix; do | |
| echo "Publishing ${vsix}" | |
| npx --yes @vscode/vsce@3.9.2 publish --skip-duplicate ${flag} --packagePath "${vsix}" | |
| published=$((published + 1)) | |
| done | |
| if [ "${published}" -eq 0 ]; then | |
| echo "::error::no VSIX artifacts found to publish" | |
| exit 1 | |
| fi | |
| echo "Published ${published} VSIX(es) to the Marketplace" | |
| # -------------------------------------------------------------------------- | |
| # Open VSX publish — serves the VS Code forks (Cursor, Windsurf, …). Open VSX | |
| # has no OIDC trusted-publishing path today, so this uses an Open VSX token | |
| # scoped to the protected `release` environment. Independent of the Marketplace | |
| # publish so one registry hiccup never blocks the other. | |
| publish-openvsx: | |
| name: Publish VSIX to Open VSX | |
| needs: [version, vsix, preflight] | |
| if: ${{ needs.preflight.outputs.has_ovsx == 'true' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| environment: release | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/setup-node@v4 | |
| with: { node-version: '20' } | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| pattern: osprey-vsix-* | |
| path: artifacts | |
| - name: Publish each platform VSIX to Open VSX | |
| env: | |
| OVSX_PAT: ${{ secrets.OPEN_VSX_PAT }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${OVSX_PAT:-}" ]; then | |
| echo "::error::OPEN_VSX_PAT secret is not set; cannot publish to Open VSX" | |
| exit 1 | |
| fi | |
| shopt -s globstar nullglob | |
| flag="" | |
| if [[ "${GITHUB_REF_NAME}" == *-* ]]; then | |
| flag="--pre-release" | |
| echo "Prerelease tag ${GITHUB_REF_NAME}; publishing with --pre-release" | |
| fi | |
| published=0 | |
| for vsix in artifacts/**/*.vsix; do | |
| echo "Publishing ${vsix}" | |
| npx --yes ovsx@1.0.0 publish --skip-duplicate ${flag} --packagePath "${vsix}" | |
| published=$((published + 1)) | |
| done | |
| if [ "${published}" -eq 0 ]; then | |
| echo "::error::no VSIX artifacts found to publish" | |
| exit 1 | |
| fi | |
| echo "Published ${published} VSIX(es) to Open VSX" | |
| # -------------------------------------------------------------------------- | |
| # Website deploy — the live site updates ONLY as part of a release (never on a | |
| # push to main). Decoupled from the binary release: it deploys whenever the | |
| # website surface changed (full release, or a website-only tag), so benchmark / | |
| # docs updates ship without rebuilding the whole binary matrix. [SWR-REL-CHANGES] | |
| # Stable tags only: a SemVer prerelease tag (v1.2.3-rc.1) contains a hyphen and | |
| # is skipped, so a prerelease never overwrites the live site. | |
| deploy-site: | |
| name: Deploy website to GitHub Pages | |
| needs: [scope] | |
| if: ${{ needs.scope.outputs.website == 'true' && !contains(github.ref_name, '-') }} | |
| uses: ./.github/workflows/deploy-pages.yml | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| deploy-webcompiler: | |
| name: Deploy web compiler | |
| needs: [github-release] | |
| # Non-blocking: the browser compiler on Fly.io is an optional add-on, not a | |
| # release artifact. The deploy step itself is `continue-on-error` inside | |
| # deploy-webcompiler.yml (continue-on-error is not valid on a `uses:` job), | |
| # so a Fly outage or invalid/banned FLY_API_TOKEN can't fail the release. | |
| uses: ./.github/workflows/deploy-webcompiler.yml | |
| secrets: inherit |