Skip to content

publish

publish #19

Workflow file for this run

# =============================================================================
# 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