publish #19
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
| # ============================================================================= | |
| # Publish | |
| # ============================================================================= | |
| # | |
| # Single workflow for preview publish AND release cuts. Both triggers are | |
| # manual (workflow_dispatch). The build + npm publish steps run identically for | |
| # both modes. Only the build profile (debug vs release), npm dist-tag, and the | |
| # release-only tail (crates.io, GitHub release assets, R2, git tag) differ. | |
| # | |
| # Triggers and mapping: | |
| # workflow_dispatch (no version) → trigger=branch npm_tag=<sanitized branch> build=debug | |
| # workflow_dispatch (with version) → trigger=release npm_tag=latest build=release | |
| # (npm_tag becomes `rc` if version contains `-rc.`, or | |
| # `next` if `latest=false`) | |
| # | |
| # Preview publishes are fast: debug sidecar build, npm only (the binary ships | |
| # inside the npm platform package), crates dry-run. Releases add the crates.io | |
| # publish, GitHub release assets, R2 mirror, and git tag. | |
| # ============================================================================= | |
| name: publish | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to release (e.g. 0.2.0 or 0.2.0-rc.1). Leave empty for preview publish on the dispatched branch." | |
| required: false | |
| type: string | |
| latest: | |
| description: "Tag as @latest (release only)" | |
| required: true | |
| type: boolean | |
| default: true | |
| concurrency: | |
| group: publish-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| R2_BUCKET: rivet-releases | |
| R2_ENDPOINT: https://2a94c6a0ced8d35ea63cddc86c2681e7.r2.cloudflarestorage.com | |
| # Platform list kept in sync with packages/*sidecar*/npm/* and the build | |
| # matrix below. Also consumed by scripts/publish discovery via SIDECAR_PLATFORMS. | |
| # arm64 is deferred until its portability fix is verified end-to-end. | |
| SIDECAR_PLATFORMS: "linux-x64-gnu" | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # context — resolve PublishContext once, pin as job outputs | |
| # --------------------------------------------------------------------------- | |
| context: | |
| name: "Context" | |
| runs-on: ubuntu-latest | |
| outputs: | |
| trigger: ${{ steps.ctx.outputs.trigger }} | |
| version: ${{ steps.ctx.outputs.version }} | |
| npm_tag: ${{ steps.ctx.outputs.npm_tag }} | |
| sha: ${{ steps.ctx.outputs.sha }} | |
| latest: ${{ steps.ctx.outputs.latest }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| - name: Install publish scripts | |
| run: pnpm install --frozen-lockfile --filter=publish | |
| - id: ctx | |
| name: Resolve publish context | |
| run: pnpm --filter=publish exec tsx src/ci/bin.ts context-output | |
| # --------------------------------------------------------------------------- | |
| # build-sidecar — debug (preview) or release (release) sidecar binaries | |
| # --------------------------------------------------------------------------- | |
| build-sidecar: | |
| needs: [context] | |
| name: "Build sidecar (${{ matrix.platform }})" | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux-x64-gnu | |
| runner: ubuntu-22.04 | |
| target: x86_64-unknown-linux-gnu | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: . -> target | |
| key: ${{ matrix.target }}-${{ needs.context.outputs.trigger }} | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ~/.cargo/.rusty_v8 | |
| key: ${{ runner.os }}-${{ matrix.target }}-rusty-v8-${{ hashFiles('Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-${{ matrix.target }}-rusty-v8- | |
| # agent-os-sidecar path-depends on the secure-exec crates, which live in the | |
| # sibling repo (preview crates are not published to crates.io). Clone the | |
| # matching preview branch and install its pnpm workspace so the V8 bridge | |
| # build (invoked by secure-exec's cargo build.rs) has esbuild + bridge srcs. | |
| - name: Checkout secure-exec sibling | |
| run: | | |
| git clone --depth 1 --branch split/runtime-preview \ | |
| https://github.com/rivet-dev/secure-exec.git ../secure-exec | |
| (cd ../secure-exec && pnpm install --frozen-lockfile) | |
| # The V8 bridge build script (invoked by cargo build.rs) needs the pnpm | |
| # workspace installed so esbuild and v8-bridge.source.js are available. | |
| - run: pnpm install --frozen-lockfile | |
| - name: Build sidecar binary | |
| id: build | |
| run: | | |
| set -euo pipefail | |
| out="target/sidecar-artifacts/${{ matrix.platform }}" | |
| mkdir -p "$out" | |
| if [ "${{ needs.context.outputs.trigger }}" = "release" ]; then | |
| cargo build --release -p agent-os-sidecar --target ${{ matrix.target }} | |
| profile="release" | |
| else | |
| cargo build -p agent-os-sidecar --target ${{ matrix.target }} | |
| profile="debug" | |
| fi | |
| cp "target/${{ matrix.target }}/${profile}/agent-os-sidecar" "$out/agent-os-sidecar" | |
| echo "dir=$out" >> "$GITHUB_OUTPUT" | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: sidecar-${{ matrix.platform }} | |
| path: ${{ steps.build.outputs.dir }} | |
| if-no-files-found: error | |
| # --------------------------------------------------------------------------- | |
| # publish-npm — place binaries, build TS, publish all packages (all triggers) | |
| # --------------------------------------------------------------------------- | |
| publish-npm: | |
| needs: [context, build-sidecar] | |
| name: "Publish npm" | |
| if: ${{ !cancelled() && needs.build-sidecar.result == 'success' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| registry-url: https://registry.npmjs.org | |
| - run: pnpm install --frozen-lockfile | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| pattern: sidecar-* | |
| path: artifacts | |
| - name: Place sidecar binaries into platform packages | |
| run: | | |
| set -euo pipefail | |
| for p in $SIDECAR_PLATFORMS; do | |
| agent_bin="artifacts/sidecar-${p}/agent-os-sidecar" | |
| agent_dest="packages/sidecar-binary/npm/${p}" | |
| if [ ! -f "$agent_bin" ]; then | |
| echo "::error::missing agent-os-sidecar binary artifact for ${p}" | |
| exit 1 | |
| fi | |
| if [ ! -d "$agent_dest" ]; then | |
| echo "::error::missing platform package dir $agent_dest" | |
| exit 1 | |
| fi | |
| cp "$agent_bin" "${agent_dest}/agent-os-sidecar" | |
| chmod +x "${agent_dest}/agent-os-sidecar" | |
| echo "Placed binaries for ${p}" | |
| done | |
| - name: Bump package versions for build (version-only) | |
| run: | | |
| pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \ | |
| --version ${{ needs.context.outputs.version }} \ | |
| --version-only | |
| - name: Build TypeScript packages | |
| run: | | |
| npx turbo build \ | |
| --filter='!@rivet-dev/agentos-playground' \ | |
| --filter='!./examples/*' | |
| - name: Finalize package versions for publish (inject optionalDeps) | |
| run: | | |
| pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \ | |
| --version ${{ needs.context.outputs.version }} | |
| - name: Publish npm packages | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: | | |
| pnpm --filter=publish exec tsx src/ci/bin.ts publish-npm \ | |
| --tag ${{ needs.context.outputs.npm_tag }} \ | |
| --parallel 16 \ | |
| --retries 3 \ | |
| ${{ needs.context.outputs.trigger == 'release' && '--release-mode' || '' }} | |
| # --------------------------------------------------------------------------- | |
| # release-assets — GitHub release + sidecar/pyodide assets + R2 (release only) | |
| # --------------------------------------------------------------------------- | |
| release-assets: | |
| needs: [context, build-sidecar] | |
| name: "Release assets" | |
| if: ${{ !cancelled() && needs.build-sidecar.result == 'success' && needs.context.outputs.trigger == 'release' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| - run: pnpm install --frozen-lockfile --filter=publish | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| pattern: sidecar-* | |
| path: artifacts | |
| - name: Stage release assets | |
| env: | |
| VERSION: ${{ needs.context.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| declare -A PLATFORM_TARGET=( | |
| [linux-x64-gnu]=x86_64-unknown-linux-gnu | |
| [linux-arm64-gnu]=aarch64-unknown-linux-gnu | |
| ) | |
| # Stage release assets: platform binaries + externalized pyodide assets | |
| # (downloaded by the published execution crate's build.rs). | |
| mkdir -p release-assets | |
| for p in $SIDECAR_PLATFORMS; do | |
| agent_bin="artifacts/sidecar-${p}/agent-os-sidecar" | |
| if [ -f "$agent_bin" ]; then | |
| target="${PLATFORM_TARGET[$p]}" | |
| cp "$agent_bin" "release-assets/agent-os-sidecar-${target}" | |
| else | |
| echo "::warning::missing agent-os-sidecar binary for ${p}" | |
| fi | |
| done | |
| for f in \ | |
| pyodide.asm.wasm \ | |
| pyodide.asm.js \ | |
| python_stdlib.zip \ | |
| numpy-2.2.5-cp313-cp313-pyodide_2025_0_wasm32.whl \ | |
| pandas-2.3.3-cp313-cp313-pyodide_2025_0_wasm32.whl; do | |
| cp "crates/execution/assets/pyodide/${f}" "release-assets/${f}" | |
| done | |
| - name: Create GitHub release and upload assets | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| VERSION: ${{ needs.context.outputs.version }} | |
| NPM_TAG: ${{ needs.context.outputs.npm_tag }} | |
| run: | | |
| set -euo pipefail | |
| if ! gh release view "v${VERSION}" >/dev/null 2>&1; then | |
| PRERELEASE="" | |
| if [ "${NPM_TAG}" = "rc" ]; then PRERELEASE="--prerelease"; fi | |
| gh release create "v${VERSION}" --title "v${VERSION}" --generate-notes $PRERELEASE | |
| fi | |
| # --clobber so re-runs overwrite assets idempotently. | |
| gh release upload "v${VERSION}" release-assets/* --clobber | |
| - name: Upload sidecar binaries to R2 (best-effort) | |
| env: | |
| R2_RELEASES_ACCESS_KEY_ID: ${{ secrets.R2_RELEASES_ACCESS_KEY_ID }} | |
| R2_RELEASES_SECRET_ACCESS_KEY: ${{ secrets.R2_RELEASES_SECRET_ACCESS_KEY }} | |
| VERSION: ${{ needs.context.outputs.version }} | |
| SHA: ${{ needs.context.outputs.sha }} | |
| LATEST: ${{ needs.context.outputs.latest }} | |
| run: | | |
| set -uo pipefail | |
| if [ -z "${R2_RELEASES_ACCESS_KEY_ID:-}" ] || [ -z "${R2_RELEASES_SECRET_ACCESS_KEY:-}" ]; then | |
| echo "R2 credentials not configured; skipping R2 upload (GitHub release assets are authoritative)." | |
| exit 0 | |
| fi | |
| set -e | |
| pnpm --filter=publish exec tsx src/ci/bin.ts upload-r2 \ | |
| --source "$GITHUB_WORKSPACE/release-assets" --sha "$SHA" | |
| pnpm --filter=publish exec tsx src/ci/bin.ts copy-r2 \ | |
| --sha "$SHA" --version "$VERSION" --latest "$LATEST" | |
| # --------------------------------------------------------------------------- | |
| # publish-crates — crates.io (dry-run on preview, full publish on release) | |
| # --------------------------------------------------------------------------- | |
| publish-crates: | |
| needs: [context, build-sidecar, release-assets] | |
| name: "Publish crates.io" | |
| if: ${{ !cancelled() && needs.build-sidecar.result == 'success' && (needs.release-assets.result == 'success' || needs.release-assets.result == 'skipped') }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: . -> target | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ~/.cargo/.rusty_v8 | |
| key: ${{ runner.os }}-x86_64-unknown-linux-gnu-rusty-v8-${{ hashFiles('Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-x86_64-unknown-linux-gnu-rusty-v8- | |
| # a6 crates path-depend on the secure-exec runtime crates (sibling repo). | |
| # Clone the matching preview branch + install its pnpm workspace so the V8 | |
| # bridge build (secure-exec's cargo build.rs) has esbuild + bridge sources. | |
| - name: Checkout secure-exec sibling | |
| run: | | |
| git clone --depth 1 --branch split/runtime-preview \ | |
| https://github.com/rivet-dev/secure-exec.git ../secure-exec | |
| (cd ../secure-exec && pnpm install --frozen-lockfile) | |
| - run: pnpm install --frozen-lockfile | |
| - name: Bump Cargo versions | |
| run: | | |
| pnpm --filter=publish exec tsx src/ci/bin.ts bump-versions \ | |
| --version ${{ needs.context.outputs.version }} \ | |
| --version-only | |
| - name: Dry-run crate publish (preview) | |
| if: ${{ needs.context.outputs.trigger != 'release' }} | |
| run: | | |
| pnpm --filter=publish exec tsx src/ci/bin.ts publish-crates \ | |
| --version ${{ needs.context.outputs.version }} \ | |
| --dry-run \ | |
| --allow-dirty | |
| - name: Publish crates (release) | |
| if: ${{ needs.context.outputs.trigger == 'release' }} | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| run: | | |
| pnpm --filter=publish exec tsx src/ci/bin.ts publish-crates \ | |
| --version ${{ needs.context.outputs.version }} \ | |
| --allow-dirty |