Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
371 changes: 368 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,48 @@
name: Release

run-name: ${{ format('Release {0} [{1}]', github.event.inputs.release_tag, github.event.inputs.dry_run == 'true' && 'dry-run' || 'live') }}

on:
workflow_dispatch:
inputs:
release_tag:
description: "Release tag (e.g. v1.9.0)"
required: true
dry_run:
description: "Run in dry-run mode"
required: true
type: boolean
default: true
release_crates:
description: "Release crates.io packages"
required: true
type: boolean
default: false
release_csharp:
description: "Release C# SDK"
required: true
type: boolean
default: false
release_cpp:
description: "Release C++ bindings"
required: true
type: boolean
default: false
release_npm:
description: "Release NPM package"
required: true
type: boolean
default: false
release_docker:
description: "Release Docker container"
required: true
type: boolean
default: false
update_mirror_latest_version:
description: "Update S3 mirror latest-version marker"
required: true
type: boolean
default: false

permissions:
contents: write
Expand All @@ -12,8 +53,332 @@ concurrency:
cancel-in-progress: true

jobs:
foo:
# This job runs before all of our release jobs. If there is a release problem we should
# try to fail during this step to prevent partial releases.
build-cargo-release:
runs-on: spacetimedb-new-runner-2
steps:
- name: Checkout release tag
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.release_tag }}

- name: Set up Rust
uses: dsherret/rust-toolchain-file@v1
- name: Set default rust toolchain
run: rustup default $(rustup show active-toolchain | cut -d' ' -f1)

- name: Cache cargo
uses: swatinem/rust-cache@v2
with:
workspaces: ./

- name: Install cargo-release
run: |
cargo install --path tools/release
# ensure the binary exists
which cargo-release
# copy it into a sharable directory
mkdir -p shared-bin
cp "$(which cargo-release)" shared-bin/

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: cargo-release-bin
path: shared-bin/

release-crates:
needs: build-cargo-release
runs-on: spacetimedb-new-runner-2
if: ${{ inputs.release_crates }}
env:
CARGO_TERM_COLOR: always
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

steps:
- name: Checkout specific tag
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.release_tag }}

- name: Set up Rust
uses: dsherret/rust-toolchain-file@v1
- name: Set default rust toolchain
run: rustup default $(rustup show active-toolchain | cut -d' ' -f1)

- name: Download cargo-release
uses: actions/download-artifact@v4
with:
name: cargo-release-bin
path: ./shared-bin

- name: Make binary executable and on PATH
run: |
chmod +x ./shared-bin/cargo-release
echo "$PWD/shared-bin" >> "$GITHUB_PATH"

# TODO: dry-run via publishing to a local registry: https://doc.rust-lang.org/cargo/reference/registries.html
- name: Run release (dry-run)
if: ${{ inputs.dry_run }}
# NOTE: This will print a warning that `cargo-release release crates` dry runs are not supported
run: cargo-release release crates --dry-run

- name: Run release
if: ${{ !inputs.dry_run }}
run: cargo-release release crates

release-csharp:
needs: build-cargo-release
runs-on: spacetimedb-new-runner-2
if: ${{ inputs.release_csharp }}
env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}

steps:
- name: Checkout specific tag
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.release_tag }}

- name: Set up Rust
uses: dsherret/rust-toolchain-file@v1
- name: Set default rust toolchain
run: rustup default $(rustup show active-toolchain | cut -d' ' -f1)

- name: Download cargo-release
uses: actions/download-artifact@v4
with:
name: cargo-release-bin
path: ./shared-bin

- name: Make binary executable and on PATH
run: |
chmod +x ./shared-bin/cargo-release
echo "$PWD/shared-bin" >> "$GITHUB_PATH"

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
global-json-path: global.json

- name: Install NuGet
shell: bash
run: |
sudo apt install -y mono-complete
mkdir bin
cd bin
wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
# We're on linux, so we need to do a mono dance to make NuGet invocations look the same as they would on e.g. windows
mv nuget.exe nuget-mono.exe
cat <<'EOF' | sed 's/^ *//' >nuget
#!/bin/bash
DIR="$(dirname "$(readlink -f "$0")")"
mono "$DIR/nuget-mono.exe" "$@"
EOF
chmod +x nuget
echo "$PWD" >> $GITHUB_PATH

- name: Setup SSH key for Unity SDK repo
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.UNITY_SDK_DEPLOY_KEY }}

- name: Configure git
run: |
git config --global user.name "Release Bot"
git config --global user.email "no-reply@clockworklabs.io"
# Remove any HTTPS to SSH conversion set by checkout action
git config --global --unset-all url.https://github.com/.insteadOf || true
# Ensure SSH is used instead of HTTPS for GitHub
git config --global url."git@github.com:".insteadOf "https://github.com/"
# Verify configuration
echo "Git URL rewrite config:"
git config --global --get-regexp url

- name: Run C# SDK release (dry-run)
if: ${{ inputs.dry_run }}
run: cargo-release release csharp ${{ github.event.inputs.release_tag }} --dry-run

- name: Run C# SDK release
if: ${{ !inputs.dry_run }}
run: cargo-release release csharp ${{ github.event.inputs.release_tag }}

release-cpp:
needs: build-cargo-release
runs-on: spacetimedb-new-runner-2
if: ${{ inputs.release_cpp }}
env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

steps:
- name: Checkout specific tag
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.release_tag }}

- name: Set up Rust
uses: dsherret/rust-toolchain-file@v1
- name: Set default rust toolchain
run: rustup default $(rustup show active-toolchain | cut -d' ' -f1)

- name: Download cargo-release
uses: actions/download-artifact@v4
with:
name: cargo-release-bin
path: ./shared-bin

- name: Make binary executable and on PATH
run: |
chmod +x ./shared-bin/cargo-release
echo "$PWD/shared-bin" >> "$GITHUB_PATH"

- name: Setup SSH key for C++ SDK repo
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.CPP_SDK_DEPLOY_KEY }}

- name: Configure git
run: |
git config --global user.name "Release Bot"
git config --global user.email "no-reply@clockworklabs.io"
# Remove any HTTPS to SSH conversion set by checkout action
git config --global --unset-all url.https://github.com/.insteadOf || true
# Ensure SSH is used instead of HTTPS for GitHub
git config --global url."git@github.com:".insteadOf "https://github.com/"
# Verify configuration
echo "Git URL rewrite config:"
git config --global --get-regexp url

- name: Run C++ SDK release (dry-run)
if: ${{ inputs.dry_run }}
run: cargo-release release cpp ${{ github.event.inputs.release_tag }} --dry-run

- name: Run C++ SDK release
if: ${{ !inputs.dry_run }}
run: cargo-release release cpp ${{ github.event.inputs.release_tag }}

release-npm:
needs: build-cargo-release
runs-on: ubuntu-latest
if: ${{ inputs.release_npm }}
env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

permissions:
id-token: write
contents: write
packages: write

steps:
- name: Be done
run: echo
- name: Checkout specific tag
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.release_tag }}

- name: Download cargo-release
uses: actions/download-artifact@v4
with:
name: cargo-release-bin
path: ./shared-bin

- name: Make binary executable and on PATH
run: |
chmod +x ./shared-bin/cargo-release
echo "$PWD/shared-bin" >> "$GITHUB_PATH"

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22.x'
registry-url: 'https://registry.npmjs.org'

- name: Install pnpm
run: npm install -g pnpm

- name: Run NPM release (dry-run)
if: ${{ inputs.dry_run }}
run: cargo-release release npm ${{ github.event.inputs.release_tag }} --dry-run

- name: Run NPM release
if: ${{ !inputs.dry_run }}
run: cargo-release release npm ${{ github.event.inputs.release_tag }}

release-docker:
needs: build-cargo-release
runs-on: spacetimedb-new-runner-2
env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ inputs.release_docker }}

steps:
- name: Checkout specific tag
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.release_tag }}

- name: Download cargo-release
uses: actions/download-artifact@v4
with:
name: cargo-release-bin
path: ./shared-bin

- name: Make binary executable and on PATH
run: |
chmod +x ./shared-bin/cargo-release
echo "$PWD/shared-bin" >> "$GITHUB_PATH"

# We need network=host during dry-runs but it's fine during non dry-runs as well
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host
- name: Login to DockerHub
uses: docker/login-action@v3
if: ${{ !inputs.dry_run }}
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
# Docker Hub access tokens are passed to docker/login-action via the password input.
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Run Docker release
run: cargo-release release docker ${{ github.event.inputs.release_tag }} ${{ inputs.dry_run && '--dry-run' || '' }}

update-mirror-latest-version:
runs-on: ubuntu-latest
if: ${{ !inputs.dry_run && inputs.update_mirror_latest_version }}

steps:
- name: Verify mirror tag prefix exists
env:
RELEASE_TAG: ${{ github.event.inputs.release_tag }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: us-east-1
run: |
set -uo pipefail

PREFIX="refs/tags/$RELEASE_TAG/"
COUNT="$(aws s3api list-objects-v2 \
--bucket spacetimedb-client-binaries \
--prefix "$PREFIX" \
--max-keys 1 \
--query 'length(not_null(Contents, `[]`))')"
test "$COUNT" -gt 0

- name: Generate latest-version marker
env:
RELEASE_TAG: ${{ github.event.inputs.release_tag }}
run: printf '%s\n' "$RELEASE_TAG" > latest-version

- name: Upload latest-version to S3 mirror
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: us-east-1
run: aws s3 cp latest-version s3://spacetimedb-client-binaries/latest-version --acl public-read
Loading
Loading