Skip to content

Release

Release #255

Workflow file for this run

name: Release
'on':
workflow_dispatch:
inputs:
version:
description: 'Explicit CalVer (e.g. 2026.05.13-2). Empty = auto-compute today.'
required: false
type: string
default: ''
dry_run:
description: 'Dry-run preview only (no publish or push)'
required: false
type: boolean
default: false
publish-only:
description: 'Publish an already prepared version through GitHub OIDC; requires version.'
required: false
type: boolean
default: false
permissions:
contents: read
id-token: write
concurrency:
group: release
cancel-in-progress: false
jobs:
release:
runs-on: ubuntu-latest
# `--ref main` resolves at run start, so the release can always check out a commit
# whose CI has not finished yet; the test gate then runs the full suite in-job.
# Measured full-gate releases land at 22-26 min, so a 30 min cap has under 5 min
# of headroom and kills the job mid-suite (run 33605173502). Budget for the slow
# path plus growth; gate-reused releases still finish in ~4 min.
timeout-minutes: 50
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Configure git identity
run: |
git config user.name "senpi-release-bot"
git config user.email "actions@github.com"
- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org/'
package-manager-cache: false
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: '1.4.0'
- name: Assert bun 1.4 toolchain
run: bash scripts/assert-bun-toolchain.sh
- name: Install dependencies
run: npm install --ignore-scripts --no-audit --no-fund
# coding-agent tool tests resolve rg/fd via system binaries first and only
# download from GitHub releases as a fallback. Unauthenticated downloads
# are rate-limited on shared runner egress IPs, which flakes the release
# gate; provisioning the binaries here keeps the fallback unused.
- name: Provision ripgrep and fd
run: sudo apt-get update && sudo apt-get install -y ripgrep fd-find
- name: Build all workspaces (so husky pre-commit type check resolves)
run: npm run build
- name: Reset auto-generated and npm-install drift files (not part of release diff)
run: git checkout -- packages/ai/src/models.generated.ts packages/ai/src/image-models.generated.ts package-lock.json
- name: Run release
if: inputs.publish-only != true
env:
GH_TOKEN: ${{ secrets.UPSTREAM_AUTOMATION_TOKEN }}
SENPI_SKIP_PM_VERIFY: '1'
run: |
test -n "$GH_TOKEN" || {
echo "::error::UPSTREAM_AUTOMATION_TOKEN is required to push release commits and tags through branch protection."
exit 1
}
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
ARGS=()
if [ -n "${{ inputs.version }}" ]; then
ARGS+=(--version "${{ inputs.version }}")
fi
if [ "${{ inputs.dry_run }}" = "true" ]; then
ARGS+=(--dry-run)
fi
npm run release -- "${ARGS[@]}"
- name: Publish prepared version
if: inputs.publish-only == true
env:
EXPECTED_VERSION: ${{ inputs.version }}
DRY_RUN: ${{ inputs.dry_run }}
run: |
test -n "$EXPECTED_VERSION" || {
echo "publish-only requires an explicit version" >&2
exit 1
}
ACTUAL_VERSION="$(node -p 'require("./packages/coding-agent/package.json").version')"
test "$ACTUAL_VERSION" = "$EXPECTED_VERSION" || {
echo "expected $EXPECTED_VERSION, found $ACTUAL_VERSION" >&2
exit 1
}
PUBLISH_ARGS=()
if [ "$DRY_RUN" = "true" ]; then
PUBLISH_ARGS+=(--dry-run)
fi
node scripts/publish.mjs "${PUBLISH_ARGS[@]}"
- name: Workflow summary
if: always()
shell: bash
run: |
{
echo "## Release"
echo
echo "| Field | Value |"
echo "| --- | --- |"
echo "| Job status | ${{ job.status }} |"
echo "| Mode | ${{ inputs.publish-only && 'publish-only' || 'release' }} |"
echo "| Dry run | ${{ inputs.dry_run }} |"
echo "| Version | ${{ inputs.version || 'auto' }} |"
echo "| Commit | ${{ github.sha }} |"
} >> "$GITHUB_STEP_SUMMARY"