Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Pipeline Plan 59

Seth Ford edited this page Feb 14, 2026 · 2 revisions

The .claude/ directory has security restrictions preventing writes. The plan is complete — let me present it directly.


Implementation Plan: Release Train Automation

Overview

Add scripts/sw-release.sh — a new standalone script that automates batched releases with semantic versioning, changelog generation, GitHub Release creation, and daemon-integrated scheduling. Follows all existing Shipwright patterns: set -euo pipefail, Bash 3.2 compatibility, emit_event, PASS/FAIL test harness, and daemon config flags.

Files to Modify

File Action Purpose
scripts/sw-release.sh Create Release train orchestration — version determination, changelog generation, GitHub Release creation, schedule management
scripts/sw-release-test.sh Create Test suite — 20+ tests covering version determination, changelog generation, batching, config, schedule triggers
scripts/sw Edit Add release command to CLI router + help text
scripts/sw-daemon.sh Edit Add release train scheduling to patrol loop + config loading
scripts/sw-fleet.sh Edit Add downstream release notification when upstream repo releases
package.json Edit Add sw-release-test.sh to test chain
.github/workflows/release.yml Edit Add optional workflow_dispatch trigger

Implementation Steps

Step 1: Create scripts/sw-release.sh — Core Script

Standard Shipwright boilerplate (set -euo pipefail, VERSION="1.10.0", colors, info()/success()/warn()/error(), emit_event, compat.sh sourcing).

Subcommands: status, plan, create, changelog, config, history, schedule-check, help

Core functions:

  1. release_collect_prs()gh pr list --state merged --base main --json number,title,labels,author,mergedAt filtered by mergedAt > last_tag_date. Last tag found via git describe --tags --abbrev=0 2>/dev/null. Returns JSON array.

  2. release_categorize_prs() — Classify PRs using jq. Priority order:

    • breaking — label breaking-change or title contains BREAKING
    • feature — label enhancement/feature, or title starts with feat:
    • fix — label bug/fix, or title starts with fix:
    • docs — label documentation or title starts with docs:
    • refactor — label refactor or title starts with refactor:
    • other — everything else
  3. release_determine_version() — Read current version from package.json via jq. Parse MAJOR.MINOR.PATCH. If any breaking PR → MAJOR+1, minor=0, patch=0. Else if any feature → MINOR+1, patch=0. Else → PATCH+1. Support --force-bump major|minor|patch override.

  4. release_generate_changelog() — Build markdown section grouped by category. Insert after ## [Unreleased] line in existing CHANGELOG.md. Format: - Title (#number) — @author. Atomic write: tmp file + mv.

  5. release_create() — Full flow:

    • Collect → categorize → determine version
    • Call scripts/update-version.sh $new_version
    • Generate changelog
    • git add -A && git commit -m "release: v${new_version}"
    • git tag "v${new_version}"
    • If --push or auto_push=true: git push origin main --tags
    • If not NO_GITHUB: gh release create "v${new_version}" --title "Shipwright v${new_version}" --notes-file <tmp_notes>
    • Emit release.created, release.tagged, release.published
  6. release_check_eligible() — PR count >= batch_size (default 1), no active pipelines (check daemon state), CI passing on main.

  7. release_schedule_check() — Exit 0 if eligible. Modes: manual (always exit 1), pr_count (merged PRs >= batch_size), daily (24h since last tag), weekly (7d since last tag).

Step 2: Configuration — Daemon Config Integration

Add to .claude/daemon-config.json schema under release_train:

{
 "release_train": {
 "enabled": false,
 "schedule": "manual",
 "batch_size": 5,
 "auto_push": false,
 "auto_publish": false,
 "changelog_path": "CHANGELOG.md",
 "version_source": "package.json"
 }
}

In sw-daemon.sh load_config() (~line 416, after patrol settings), add:

RELEASE_TRAIN_ENABLED=$(jq -r '.release_train.enabled // false' "$config_file")
RELEASE_TRAIN_SCHEDULE=$(jq -r '.release_train.schedule // "manual"' "$config_file")
RELEASE_TRAIN_BATCH_SIZE=$(jq -r '.release_train.batch_size // 5' "$config_file")

Step 3: Daemon Poll Loop Integration

After the patrol block (~line 4914) and inside the now_e scope, add:

# Release train check (independent of patrol)
if [[ "${RELEASE_TRAIN_ENABLED:-false}" == "true" ]]; then
 if [[ $((now_e - LAST_RELEASE_CHECK_EPOCH)) -ge "${RELEASE_TRAIN_CHECK_INTERVAL:-300}" ]]; then
 if "$SCRIPT_DIR/sw-release.sh" schedule-check 2>/dev/null; then
 daemon_log INFO "Release train triggered"
 "$SCRIPT_DIR/sw-release.sh" create --auto || daemon_log WARN "Release creation failed"
 fi
 LAST_RELEASE_CHECK_EPOCH=$now_e
 fi
fi

Initialize LAST_RELEASE_CHECK_EPOCH=0 at top alongside LAST_PATROL_EPOCH.

Step 4: Fleet Downstream Notifications

In sw-fleet.sh, add fleet_notify_release():

  • Reads fleet config repos array
  • For each repo with a GitHub remote, creates an issue or dispatches event
  • Guarded by notify_releases config flag
  • Emit fleet.release_notification event

Step 5: GitHub Workflow Enhancement

Add workflow_dispatch trigger to .github/workflows/release.yml:

on:
 push:
 tags: ["v*"]
 workflow_dispatch:
 inputs:
 version:
 description: "Version to release (e.g., 1.11.0)"
 required: true

Step 6: CLI Router

In scripts/sw:

  • Add help line: ${CYAN}release${RESET} <cmd> ${BOLD}Release train${RESET} — batched releases with changelogs
  • Add route: release) exec "$SCRIPT_DIR/sw-release.sh" "$@" ;;

Step 7: Test Suite

scripts/sw-release-test.sh following sw-fleet-test.sh pattern. 20+ tests with mock gh/git binaries:

# Test Assertion
1 Version: patch only 1.10.01.10.1
2 Version: minor (feature) 1.10.01.11.0
3 Version: major (breaking) 1.10.02.0.0
4 Version: force override --force-bump minor overrides auto
5 Categorize: label-based enhancement → feature
6 Categorize: title-based feat: → feature
7 Categorize: mixed types Multiple categories correct
8 Changelog: format Keep a Changelog markdown
9 Changelog: PR links (#123) format
10 Changelog: empty categories Omitted from output
11 Changelog: insertion After [Unreleased], preserves existing
12 Eligible: batch size Triggers at N PRs
13 Eligible: daily schedule Triggers after 24h
14 Eligible: weekly schedule Triggers after 7d
15 Eligible: no PRs Returns 1
16 Config: defaults Missing config → sensible defaults
17 Config: custom values Custom config respected
18 Status: output Shows pending PRs + version
19 Plan: dry run Correct format, no side effects
20 Events: emission release.created in events.jsonl

Step 8: Register in package.json

Add && bash scripts/sw-release-test.sh to the test script chain.

Task Checklist

  • Task 1: Create scripts/sw-release.sh with boilerplate, subcommand routing, help text
  • Task 2: Implement release_collect_prs() — query merged PRs since last tag
  • Task 3: Implement release_categorize_prs() — label/title-based PR classification
  • Task 4: Implement release_determine_version() — semantic version bump logic
  • Task 5: Implement release_generate_changelog() — Keep a Changelog format
  • Task 6: Implement release_create() — full release flow: version bump → changelog → tag → GitHub Release
  • Task 7: Implement release_check_eligible() and release_schedule_check() — schedule/threshold triggers
  • Task 8: Implement status, plan, config, history subcommands
  • Task 9: Add daemon config loading for release_train.* keys in sw-daemon.sh
  • Task 10: Add release train scheduling to daemon poll loop in sw-daemon.sh
  • Task 11: Add fleet_notify_release() to sw-fleet.sh for downstream notifications
  • Task 12: Add release command to CLI router in scripts/sw (help + route)
  • Task 13: Add workflow_dispatch trigger to .github/workflows/release.yml
  • Task 14: Create scripts/sw-release-test.sh with 20+ tests
  • Task 15: Register sw-release-test.sh in package.json test chain

Testing Approach

All tests use mocked binaries (gh, git) in a temp directory with NO_GITHUB=true. No real API calls. Tests cover:

  1. PR collection — Mock gh pr list returns canned JSON; verify parsing
  2. Categorization — Feed labeled/titled PRs; verify category assignment
  3. Version math1.10.01.10.1 (patch), 1.11.0 (minor), 2.0.0 (major)
  4. Changelog format — Verify Keep a Changelog markdown structure
  5. Changelog insertion — New section after [Unreleased], existing entries preserved
  6. Schedule logic — Mock timestamps/PR counts; verify trigger/no-trigger
  7. Config — Default values when missing; custom values when present
  8. Event emissionrelease.* events in events.jsonl with correct fields

Integration: npm test runs all 23 test suites including the new one.

Definition of Done

  • shipwright release status shows merged PRs since last release with version preview
  • shipwright release plan generates a dry-run (no side effects)
  • shipwright release create executes full release: version bump, changelog, tag, GitHub Release
  • Semantic version auto-determined from PR labels/titles (breaking→major, feature→minor, fix→patch)
  • Changelog generated in Keep a Changelog format with proper categorization
  • GitHub Release created with tag and auto-generated notes
  • Release schedule configurable via daemon-config.json (manual, pr_count, daily, weekly)
  • Daemon poll loop checks release eligibility when release_train.enabled=true
  • Fleet repos notified of upstream releases when configured
  • CLI router dispatches shipwright release <cmd> correctly
  • 20+ tests pass in sw-release-test.sh covering version determination and changelog generation
  • npm test passes with the new test suite included
  • All scripts maintain Bash 3.2 compatibility
  • Events emitted: release.created, release.tagged, release.published, fleet.release_notification

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /