-
Notifications
You must be signed in to change notification settings - Fork 8.1k
feat: add /speckit.ship command — release engineering automation #2045
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,255 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: Automate the release pipeline including pre-flight checks, branch sync, changelog generation, CI verification, and pull request creation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scripts: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## User Input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $ARGUMENTS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| You **MUST** consider the user input before proceeding (if not empty). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Pre-Execution Checks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Check for extension hooks (before ship)**: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Check if `.specify/extensions.yml` exists in the project root. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If it exists, read it and look for entries under the `hooks.before_ship` key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If the hook has no `condition` field, or it is null/empty, treat the hook as executable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - For each executable hook, output the following based on its `optional` flag: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Optional hook** (`optional: true`): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Extension Hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Optional Pre-Hook**: {extension} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Command: `/{command}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Description: {description} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Prompt: {prompt} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| To execute: `/{command}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Mandatory hook** (`optional: false`): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Extension Hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Automatic Pre-Hook**: {extension} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Executing: `/{command}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| EXECUTE_COMMAND: {command} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Wait for the result of the hook command before proceeding to the Outline. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Goal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Automate the complete release engineering workflow: verify readiness, synchronize branches, generate a changelog, verify CI status, create a well-structured pull request, and archive release artifacts. This command transforms the implemented feature into a shippable, reviewable PR with full traceability back to the original specification. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Operating Constraints | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **SAFE BY DEFAULT**: Every destructive or potentially destructive operation (e.g., rebase/merge during branch sync, push/force push, branch delete, PR creation) requires explicit user confirmation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - For the branch sync flow, add a required confirmation prompt **immediately before** performing any rebase/merge, with the default answer set to **no**. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Add a separate required confirmation prompt **immediately before** performing any push (including force push) to the remote, with the default answer set to **no**. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Default to dry-run mode for destructive git operations wherever possible. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **TRACEABILITY**: The PR description and changelog must link back to spec, plan, tasks, review, and QA artifacts for full audit trail. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Outline | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. Run `{SCRIPT}` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot"). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. **Pre-Flight Readiness Checks**: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Run a comprehensive readiness assessment before proceeding: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Task Completion**: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Read `tasks.md` and count total tasks vs. completed tasks (marked `[X]` or `[x]`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If any tasks are incomplete: **STOP** and warn. Ask user to confirm proceeding or run `/speckit.implement` first. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Review Status** (if FEATURE_DIR/reviews/ exists): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Read the most recent review report | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If verdict is ❌ CHANGES REQUIRED: **STOP** and warn. Recommend running `/speckit.review` after fixes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If verdict is ⚠️ APPROVED WITH CONDITIONS: Warn but allow proceeding with confirmation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **QA Status** (if FEATURE_DIR/qa/ exists): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Read the most recent QA report | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If verdict is ❌ QA FAILED: **STOP** and warn. Recommend running `/speckit.qa` after fixes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If verdict is ⚠️ QA PASSED WITH NOTES: Warn but allow proceeding with confirmation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Working Tree**: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Run `git status` to check for uncommitted changes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - If uncommitted changes exist: prompt user to commit or stash before proceeding | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Display a readiness summary: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Ship Readiness Check: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ✅ Tasks: 12/12 complete | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ✅ Review: APPROVED | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ⚠️ QA: PASSED WITH NOTES (2 non-critical items) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ✅ Working tree: Clean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Overall: READY TO SHIP (with notes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Proceed? (yes/no) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. **Determine Shipping Configuration**: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Detect the current feature branch: `git branch --show-current` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Determine the target branch (default: `main`; override via user input or `.specify/config.yml`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Determine the target branch (default: `main`; override via user input or `.specify/config.yml`) | |
| - Determine the target branch (default: `main`; allow override via user input/prompt) |
Copilot
AI
Apr 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gh pr create example uses --body-file {pr_description_file}, but the template never defines/writes {pr_description_file} in the gh-available path (it only specifies a filename when gh is unavailable). Clarify where the PR body file is written (ideally always write it to FEATURE_DIR/releases/pr-description-{timestamp}.md and reuse that path for both branches).
| ```bash | |
| gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file} | |
| ``` | |
| - If `gh` is not available: | |
| - Prompt the user for explicit confirmation **before** writing the PR description file (default **no**) | |
| - Save the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md` | |
| - Write the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md` and use that path as `{pr_description_file}`: | |
| ```bash | |
| gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file} | |
| ``` | |
| - If `gh` is not available: | |
| - Prompt the user for explicit confirmation **before** writing the PR description file (default **no**) | |
| - Save the PR description to the same path: `FEATURE_DIR/releases/pr-description-{timestamp}.md` |
Copilot
AI
Apr 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR creation is called out as requiring explicit user confirmation in the operating constraints, but Step 8 goes straight to gh pr create without an explicit confirmation prompt right before executing it. Add a confirm gate (default "no") prior to PR creation, and ensure the manual fallback also asks before writing the PR description file if you're treating file writes as destructive.
| ```bash | |
| gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file} | |
| ``` | |
| - If `gh` is not available: | |
| - Save the PR description to `FEATURE_DIR/releases/pr-description-{timestamp}.md` | |
| - Provide instructions for manual PR creation | |
| - Output the PR title and description for copy-paste | |
| - Prompt the user for explicit confirmation **right before** creating the PR (default **no**). For example: | |
| ```bash | |
| read -r -p "Proceed to create a GitHub pull request now? [y/N] " confirm_pr | |
| case "${confirm_pr}" in | |
| [Yy][Ee][Ss]|[Yy]) | |
| gh pr create --base {target_branch} --head {feature_branch} --title "{PR title}" --body-file {pr_description_file} | |
| ;; | |
| *) | |
| echo "Skipping PR creation; you can run 'gh pr create' manually later." | |
| ;; | |
| esac | |
| ``` | |
| - If `gh` is not available: | |
| - Prompt the user for explicit confirmation **before** writing any PR description file (default **no**). For example: | |
| ```bash | |
| read -r -p "Save PR description and proceed with manual PR creation steps? [y/N] " confirm_pr_file | |
| case "${confirm_pr_file}" in | |
| [Yy][Ee][Ss]|[Yy]) | |
| pr_description_path="FEATURE_DIR/releases/pr-description-{timestamp}.md" | |
| # Write PR description content to "${pr_description_path}" | |
| echo "PR description saved to ${pr_description_path}." | |
| echo "Use this file when creating your PR manually in the Git provider UI." | |
| ;; | |
| *) | |
| echo "Skipping PR description file write and manual PR instructions." | |
| ;; | |
| esac | |
| ``` | |
| - Provide instructions for manual PR creation | |
| - Output the PR title and description for copy-paste (only if the user confirmed saving or otherwise requested output) |
Copilot
AI
Apr 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The post-ship message suggests running /speckit.retro, but that command doesn’t exist in this repository (no template/command file, and no other references found). Either add the retro command in the same PR series or adjust this “Next steps” guidance to only mention commands that are currently available.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| # Release: [FEATURE NAME] | ||
|
|
||
| **Date**: [DATE] | ||
| **Branch**: [feature_branch] → [target_branch] | ||
| **PR**: [#number — title](URL) | ||
| **Status**: [🚀 Shipped / ⏳ Pending Review / ❌ Blocked] | ||
|
|
||
| --- | ||
|
|
||
| ## Summary | ||
|
|
||
| [One-paragraph summary of the shipped feature, derived from spec.md overview.] | ||
|
|
||
| --- | ||
|
|
||
| ## Changelog Entry | ||
|
|
||
| ### Added | ||
| - [New feature or capability from spec] | ||
|
|
||
| ### Changed | ||
| - [Modification to existing behavior] | ||
|
|
||
| ### Fixed | ||
| - [Bug fix discovered during implementation] | ||
|
|
||
| ### Technical Notes | ||
| - [Key architecture decisions from plan.md] | ||
|
|
||
| --- | ||
|
|
||
| ## Readiness Check Results | ||
|
|
||
| | Check | Status | Details | | ||
| |-------|--------|---------| | ||
| | Tasks complete | ✅/❌ | [X]/[Y] tasks completed | | ||
| | Code review | ✅/⚠️/❌ | [Review verdict] | | ||
| | QA testing | ✅/⚠️/❌ | [QA verdict] | | ||
| | CI pipeline | ✅/❌ | [CI run ID or status] | | ||
| | Working tree | ✅/❌ | [Clean/dirty] | | ||
|
|
||
| --- | ||
|
|
||
| ## PR Description | ||
|
|
||
| ### Summary | ||
| [Feature summary from spec.md] | ||
|
|
||
| ### Specification | ||
| [Key requirements summary] | ||
|
|
||
| ### Implementation | ||
| [Architecture decisions and completed tasks summary] | ||
|
|
||
| ### Testing | ||
| [QA and test coverage summary] | ||
|
|
||
| ### Review Notes | ||
| [Review findings summary and conditions] | ||
|
|
||
| ### Checklist | ||
| - [ ] All tasks completed | ||
| - [ ] Code review passed | ||
| - [ ] QA testing passed | ||
| - [ ] CI pipeline green | ||
| - [ ] Changelog updated | ||
| - [ ] Documentation updated (if applicable) | ||
|
|
||
| --- | ||
|
|
||
| ## Artifacts | ||
|
|
||
| | Artifact | Path | | ||
| |----------|------| | ||
| | Specification | [FEATURE_DIR/spec.md] | | ||
| | Plan | [FEATURE_DIR/plan.md] | | ||
| | Tasks | [FEATURE_DIR/tasks.md] | | ||
| | Review | [FEATURE_DIR/reviews/review-{timestamp}.md] | | ||
| | QA Report | [FEATURE_DIR/qa/qa-{timestamp}.md] | | ||
| | This Release | [FEATURE_DIR/releases/release-{timestamp}.md] | | ||
|
|
||
| --- | ||
|
|
||
| ## Git Info | ||
|
|
||
| | Property | Value | | ||
| |----------|-------| | ||
| | Feature branch | [branch name] | | ||
| | Target branch | [main/develop] | | ||
| | Commit range | [base_sha..head_sha] | | ||
| | Commits | [count] | | ||
| | Files changed | [count] | | ||
| | Lines | +[additions] / -[deletions] | | ||
|
|
||
| --- | ||
|
|
||
| *Generated by `/speckit.ship` — Release automation for spec-driven development.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This flow recommends
/speckit.reviewand/speckit.qa, but those commands don’t appear to exist in this repository (no corresponding templates/commands entries, and no other references found). Either add/land those commands first, gate these instructions behind “if available”, or update the guidance to match the currently shipped command set.