Files
get-shit-done/.github/workflows/canary.yml
Tom Boucher f2ada8500c chore(#2868): switch canary publish from main to dev branch (#2871)
* chore(#2868): switch canary publish from main to dev branch

Swaps the four `if:` guards in `.github/workflows/canary.yml` from
`refs/heads/main` to `refs/heads/dev` so the canary stream is owned
by the new long-lived integration branch. Adds a policy comment at
the top of the workflow documenting the branch->dist-tag mapping
(dev=@canary, main=@next/@latest, no overlap).

Closes #2868

* fix(#2868): summary block matches publish-step gate

CodeRabbit caught: the Summary step keyed off DRY_RUN only, so a
non-dry-run on main would falsely report "Published"/"Tagged" even
though all four publish steps were skipped by the new dev-only gate.

Add PUBLISH_ELIGIBLE env mirroring the publish-step `if:` expression
and a VALIDATION ONLY branch in the summary so non-dev runs report
honestly.
2026-04-29 17:43:30 -04:00

158 lines
6.0 KiB
YAML

# Release stream policy:
# dev → @canary (this workflow — preview builds for the long-lived integration branch)
# main → @next (RC train, see release.yml)
# main → @latest (stable cuts, see release.yml)
#
# Streams do not mix. The publish/tag steps below gate on `refs/heads/dev` so a
# workflow_dispatch run on any other branch (including main) completes the
# build/test/dry-run validation but does not publish or tag.
name: Canary
on:
workflow_dispatch:
inputs:
dry_run:
description: 'Dry run (skip npm publish, tagging, and push)'
required: false
type: boolean
default: false
concurrency:
group: canary
cancel-in-progress: false
env:
NODE_VERSION: 24
jobs:
canary:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
id-token: write
environment: npm-publish
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org'
cache: 'npm'
- name: Determine canary version
id: canary
run: |
# Strip any pre-release suffix from package.json version to get base (e.g. 1.39.0-rc.4 → 1.39.0)
RAW=$(node -p "require('./package.json').version")
BASE=$(echo "$RAW" | sed 's/-.*//')
# Find next sequential canary number from existing tags
N=1
while git tag -l "v${BASE}-canary.${N}" | grep -q .; do
N=$((N + 1))
done
CANARY_VERSION="${BASE}-canary.${N}"
echo "canary_version=$CANARY_VERSION" >> "$GITHUB_OUTPUT"
- name: Configure git identity
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Bump to canary version
env:
CANARY_VERSION: ${{ steps.canary.outputs.canary_version }}
run: |
npm version "$CANARY_VERSION" --no-git-tag-version
cd sdk && npm version "$CANARY_VERSION" --no-git-tag-version && cd ..
- name: Install and test
run: |
npm ci
npm test
- name: Build SDK dist for tarball
run: npm run build:sdk
- name: Verify tarball ships sdk/dist/cli.js (bug #2647)
run: bash scripts/verify-tarball-sdk-dist.sh
- name: Dry-run publish validation
run: |
npm publish --dry-run --tag canary
cd sdk && npm publish --dry-run --tag canary
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Tag and push
if: ${{ github.ref == 'refs/heads/dev' && !inputs.dry_run }}
env:
CANARY_VERSION: ${{ steps.canary.outputs.canary_version }}
run: |
git tag "v${CANARY_VERSION}"
git push origin "v${CANARY_VERSION}"
- name: Publish to npm (canary)
if: ${{ github.ref == 'refs/heads/dev' && !inputs.dry_run }}
run: npm publish --provenance --access public --tag canary
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish SDK to npm (canary)
if: ${{ github.ref == 'refs/heads/dev' && !inputs.dry_run }}
run: cd sdk && npm publish --provenance --access public --tag canary
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Verify publish
if: ${{ github.ref == 'refs/heads/dev' && !inputs.dry_run }}
env:
CANARY_VERSION: ${{ steps.canary.outputs.canary_version }}
run: |
PUBLISHED="NOT_FOUND"
SDK_PUBLISHED="NOT_FOUND"
for delay in 5 10 20 30 45; do
PUBLISHED=$(npm view get-shit-done-cc@"$CANARY_VERSION" version 2>/dev/null || echo "NOT_FOUND")
SDK_PUBLISHED=$(npm view @gsd-build/sdk@"$CANARY_VERSION" version 2>/dev/null || echo "NOT_FOUND")
if [ "$PUBLISHED" = "$CANARY_VERSION" ] && [ "$SDK_PUBLISHED" = "$CANARY_VERSION" ]; then
break
fi
echo "Not yet live (sleeping ${delay}s)..."
sleep "$delay"
done
if [ "$PUBLISHED" != "$CANARY_VERSION" ]; then
echo "::error::Published version verification failed. Expected $CANARY_VERSION, got $PUBLISHED"
exit 1
fi
echo "Verified: get-shit-done-cc@$CANARY_VERSION is live on npm"
if [ "$SDK_PUBLISHED" != "$CANARY_VERSION" ]; then
echo "::error::SDK version verification failed. Expected $CANARY_VERSION, got $SDK_PUBLISHED"
exit 1
fi
echo "Verified: @gsd-build/sdk@$CANARY_VERSION is live on npm"
CANARY_TAG=$(npm dist-tag ls get-shit-done-cc 2>/dev/null | grep "canary:" | awk '{print $2}')
echo "canary dist-tag points to: $CANARY_TAG"
- name: Summary
env:
CANARY_VERSION: ${{ steps.canary.outputs.canary_version }}
DRY_RUN: ${{ inputs.dry_run }}
PUBLISH_ELIGIBLE: ${{ github.ref == 'refs/heads/dev' && !inputs.dry_run }}
BRANCH_REF: ${{ github.ref }}
run: |
echo "## Canary v${CANARY_VERSION}" >> "$GITHUB_STEP_SUMMARY"
if [ "$DRY_RUN" = "true" ]; then
echo "**DRY RUN** — npm publish, tagging, and push skipped" >> "$GITHUB_STEP_SUMMARY"
elif [ "$PUBLISH_ELIGIBLE" != "true" ]; then
echo "**VALIDATION ONLY** — publish/tag skipped for \`${BRANCH_REF}\`; canary publish is gated to \`refs/heads/dev\`." >> "$GITHUB_STEP_SUMMARY"
else
echo "- Published to npm as \`canary\`" >> "$GITHUB_STEP_SUMMARY"
echo "- SDK also published: \`@gsd-build/sdk@${CANARY_VERSION}\` on \`canary\`" >> "$GITHUB_STEP_SUMMARY"
echo "- Tagged \`v${CANARY_VERSION}\`" >> "$GITHUB_STEP_SUMMARY"
echo "- Install: \`npx get-shit-done-cc@canary\`" >> "$GITHUB_STEP_SUMMARY"
fi