feat(releases): weekly tagged releases and a stable update channel for team mode (GSTA-98)

Every Monday morning .github/workflows/weekly-release.yml tags the newest green
commit on main as v<VERSION>, publishes a GitHub Release from the CHANGELOG
headlines and fast-forwards refs/heads/stable to it (scripts/release-cut.ts;
workflow_dispatch with dry_run, and ref for a hotfix). Team-mode installs
follow stable through the new update_channel key (auto: stable when
team_mode, else main) in bin/gstack-session-update, bin/gstack-update-check,
bin/gstack-upgrade and /gstack-upgrade. Per-merge stamping and the merge
train are unchanged. docs/releases.md explains it.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-25 23:28:22 +00:00
1 parent c23d7d48fe
commit 853efc9fdb
17 files changed
+1266 -34

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
name: Weekly release
# Tags the newest green commit on main as v<VERSION>, publishes the GitHub
# Release, and fast-forwards refs/heads/stable to it (docs/releases.md). Team
# installs follow stable, so this is the only thing that moves them. Runs
# every Monday morning Pacific; run it by hand with a ref for a hotfix, or
# with dry_run to see the plan and change nothing. The candidate's gate must
# already be green (free-tests, no red check run, a green Main backstop gate
# run, no active freeze): this workflow never runs tests or paid evals.
on:
schedule:
# Monday 14:00 UTC: 07:00 PDT, 06:00 PST.
- cron: '0 14 * * 1'
workflow_dispatch:
inputs:
dry_run:
description: 'Print the plan (candidate, tag, stable move, notes) and change nothing'
type: boolean
default: true
ref:
description: 'Hotfix: release this commit of main instead of the newest green one (full SHA)'
type: string
default: ''
# One cut at a time; a second dispatch waits for the first.
concurrency:
group: weekly-release
cancel-in-progress: false
permissions: {}
jobs:
cut:
name: Cut the release
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
# The tag, the stable branch and the release.
contents: write
# Reads check runs and backstop runs of the candidate.
actions: read
checks: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: main
fetch-depth: 0
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.4.2
- name: Fetch stable and the tags
run: |
set -euo pipefail
git fetch --quiet origin '+refs/heads/stable:refs/remotes/origin/stable' 2>/dev/null || echo "origin has no stable yet: this cut creates it"
git fetch --quiet --tags origin
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Plan and cut
env:
GH_TOKEN: ${{ github.token }}
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run && 'true' || 'false' }}
RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || '' }}
run: |
set -euo pipefail
args=(--repo "$GITHUB_REPOSITORY" --summary "$GITHUB_STEP_SUMMARY")
[ "$DRY_RUN" = true ] && args+=(--dry-run)
[ -n "$RELEASE_REF" ] && args+=(--ref "$RELEASE_REF")
echo "## Weekly release ($([ "$DRY_RUN" = true ] && echo 'dry run' || echo 'cut'))" >> "$GITHUB_STEP_SUMMARY"
bun --no-env-file --config=/dev/null --no-install run scripts/release-cut.ts "${args[@]}"