mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-02 03:35:09 +02:00
feat(skills): /ship and /document-release always prefix PR titles with v<VERSION>
ship/SKILL.md.tmpl Step 19: idempotency block now always rewrites titles to start with v$NEW_VERSION via the new helper. Removes the "custom title kept intentionally" loophole that let unprefixed titles persist forever. Adds a post-edit self-check that re-fetches the title and retries once if the edit didn't stick. Inline comments on the create-PR snippets at lines 867 and 876 make the rule unmissable. document-release/SKILL.md.tmpl Step 9: new "PR/MR title sync" sub-step calls the same helper after the body update. Catches the case where Step 8 bumped VERSION after /ship had already created the PR — title now follows VERSION instead of going stale. Golden fixtures regenerated for claude/codex/factory ship variants. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1018,6 +1018,54 @@ rm -f /tmp/gstack-pr-body-$$.md
|
||||
7. If `gh pr edit` / `glab mr update` fails: warn "Could not update PR/MR body — documentation changes are in the
|
||||
commit." and continue.
|
||||
|
||||
**PR/MR title sync (idempotent, always-on):**
|
||||
|
||||
PR titles must always start with `v<VERSION>` — same rule as `/ship`. If Step 8 bumped VERSION after `/ship` had already created the PR, the title is now stale. This sub-step fixes it.
|
||||
|
||||
1. Read the current VERSION:
|
||||
|
||||
```bash
|
||||
V=$(cat VERSION 2>/dev/null | tr -d '[:space:]')
|
||||
```
|
||||
|
||||
If `VERSION` does not exist or is empty, skip this sub-step entirely.
|
||||
|
||||
2. Read the current PR/MR title:
|
||||
|
||||
**If GitHub:**
|
||||
```bash
|
||||
CURRENT_TITLE=$(gh pr view --json title -q .title 2>/dev/null || true)
|
||||
```
|
||||
|
||||
**If GitLab:**
|
||||
```bash
|
||||
CURRENT_TITLE=$(glab mr view -F json 2>/dev/null | jq -r .title 2>/dev/null || true)
|
||||
```
|
||||
|
||||
If `CURRENT_TITLE` is empty (no open PR/MR), skip with message "No PR/MR found — skipping title sync."
|
||||
|
||||
3. Compute the corrected title using the shared helper (single source of truth — same one `/ship` uses):
|
||||
|
||||
```bash
|
||||
NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$V" "$CURRENT_TITLE")
|
||||
```
|
||||
|
||||
The helper handles three cases: title already correct (no-op), title has a different `v<X.Y.Z.W>` prefix (replace it), or title has no version prefix (prepend one).
|
||||
|
||||
4. If `NEW_TITLE` differs from `CURRENT_TITLE`, update it:
|
||||
|
||||
**If GitHub:**
|
||||
```bash
|
||||
gh pr edit --title "$NEW_TITLE"
|
||||
```
|
||||
|
||||
**If GitLab:**
|
||||
```bash
|
||||
glab mr update -t "$NEW_TITLE"
|
||||
```
|
||||
|
||||
5. If the edit command fails: warn "Could not update PR/MR title — documentation changes are still in the commit." and continue. Do not block on title sync failure.
|
||||
|
||||
**Structured doc health summary (final output):**
|
||||
|
||||
Output a scannable summary showing every documentation file's status:
|
||||
|
||||
@@ -342,6 +342,54 @@ rm -f /tmp/gstack-pr-body-$$.md
|
||||
7. If `gh pr edit` / `glab mr update` fails: warn "Could not update PR/MR body — documentation changes are in the
|
||||
commit." and continue.
|
||||
|
||||
**PR/MR title sync (idempotent, always-on):**
|
||||
|
||||
PR titles must always start with `v<VERSION>` — same rule as `/ship`. If Step 8 bumped VERSION after `/ship` had already created the PR, the title is now stale. This sub-step fixes it.
|
||||
|
||||
1. Read the current VERSION:
|
||||
|
||||
```bash
|
||||
V=$(cat VERSION 2>/dev/null | tr -d '[:space:]')
|
||||
```
|
||||
|
||||
If `VERSION` does not exist or is empty, skip this sub-step entirely.
|
||||
|
||||
2. Read the current PR/MR title:
|
||||
|
||||
**If GitHub:**
|
||||
```bash
|
||||
CURRENT_TITLE=$(gh pr view --json title -q .title 2>/dev/null || true)
|
||||
```
|
||||
|
||||
**If GitLab:**
|
||||
```bash
|
||||
CURRENT_TITLE=$(glab mr view -F json 2>/dev/null | jq -r .title 2>/dev/null || true)
|
||||
```
|
||||
|
||||
If `CURRENT_TITLE` is empty (no open PR/MR), skip with message "No PR/MR found — skipping title sync."
|
||||
|
||||
3. Compute the corrected title using the shared helper (single source of truth — same one `/ship` uses):
|
||||
|
||||
```bash
|
||||
NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$V" "$CURRENT_TITLE")
|
||||
```
|
||||
|
||||
The helper handles three cases: title already correct (no-op), title has a different `v<X.Y.Z.W>` prefix (replace it), or title has no version prefix (prepend one).
|
||||
|
||||
4. If `NEW_TITLE` differs from `CURRENT_TITLE`, update it:
|
||||
|
||||
**If GitHub:**
|
||||
```bash
|
||||
gh pr edit --title "$NEW_TITLE"
|
||||
```
|
||||
|
||||
**If GitLab:**
|
||||
```bash
|
||||
glab mr update -t "$NEW_TITLE"
|
||||
```
|
||||
|
||||
5. If the edit command fails: warn "Could not update PR/MR title — documentation changes are still in the commit." and continue. Do not block on title sync failure.
|
||||
|
||||
**Structured doc health summary (final output):**
|
||||
|
||||
Output a scannable summary showing every documentation file's status:
|
||||
|
||||
+12
-1
@@ -2760,7 +2760,14 @@ glab mr view -F json 2>/dev/null | jq -r 'if .state == "opened" then "MR_EXISTS"
|
||||
|
||||
If an **open** PR/MR already exists: **update** the PR body using `gh pr edit --body "..."` (GitHub) or `glab mr update -d "..."` (GitLab). Always regenerate the PR body from scratch using this run's fresh results (test output, coverage audit, review findings, adversarial review, TODOS summary, documentation_section from Step 18). Never reuse stale PR body content from a prior run.
|
||||
|
||||
**Also update the PR title** if the version changed on rerun. PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first. If the current title's version prefix doesn't match `NEW_VERSION`, run `gh pr edit --title "v$NEW_VERSION <type>: <summary>"` (or the `glab mr update -t ...` equivalent). This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version. If the title has no `v<X.Y.Z.W>` prefix (a custom title kept intentionally), leave the title alone — only rewrite titles that already follow the format.
|
||||
**Always update the PR title to start with `v$NEW_VERSION`.** PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first, no exceptions, no "custom title kept intentionally" escape hatch. The shared helper `bin/gstack-pr-title-rewrite.sh` is the single source of truth for the rule.
|
||||
|
||||
1. Read the current title: `CURRENT=$(gh pr view --json title -q .title)` (or `glab mr view -F json | jq -r .title`).
|
||||
2. Compute the corrected title: `NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$NEW_VERSION" "$CURRENT")`. The helper handles three cases: title already correct (no-op), title has a different `v<X.Y.Z.W>` prefix (replace it), or title has no version prefix (prepend one).
|
||||
3. If `NEW_TITLE` differs from `CURRENT`, run `gh pr edit --title "$NEW_TITLE"` (or `glab mr update -t "$NEW_TITLE"`).
|
||||
4. **Self-check:** re-fetch the title and assert it starts with `v$NEW_VERSION `. If it does not, retry the edit once. If still wrong, surface the failure to the user.
|
||||
|
||||
This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version, and forces the format on PRs that were created without it.
|
||||
|
||||
Print the existing URL and continue to Step 20.
|
||||
|
||||
@@ -2830,6 +2837,8 @@ you missed it.>
|
||||
**If GitHub:**
|
||||
|
||||
```bash
|
||||
# PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
gh pr create --base <base> --title "v$NEW_VERSION <type>: <summary>" --body "$(cat <<'EOF'
|
||||
<PR body from above>
|
||||
EOF
|
||||
@@ -2839,6 +2848,8 @@ EOF
|
||||
**If GitLab:**
|
||||
|
||||
```bash
|
||||
# MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
glab mr create -b <base> -t "v$NEW_VERSION <type>: <summary>" -d "$(cat <<'EOF'
|
||||
<MR body from above>
|
||||
EOF
|
||||
|
||||
+12
-1
@@ -794,7 +794,14 @@ glab mr view -F json 2>/dev/null | jq -r 'if .state == "opened" then "MR_EXISTS"
|
||||
|
||||
If an **open** PR/MR already exists: **update** the PR body using `gh pr edit --body "..."` (GitHub) or `glab mr update -d "..."` (GitLab). Always regenerate the PR body from scratch using this run's fresh results (test output, coverage audit, review findings, adversarial review, TODOS summary, documentation_section from Step 18). Never reuse stale PR body content from a prior run.
|
||||
|
||||
**Also update the PR title** if the version changed on rerun. PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first. If the current title's version prefix doesn't match `NEW_VERSION`, run `gh pr edit --title "v$NEW_VERSION <type>: <summary>"` (or the `glab mr update -t ...` equivalent). This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version. If the title has no `v<X.Y.Z.W>` prefix (a custom title kept intentionally), leave the title alone — only rewrite titles that already follow the format.
|
||||
**Always update the PR title to start with `v$NEW_VERSION`.** PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first, no exceptions, no "custom title kept intentionally" escape hatch. The shared helper `bin/gstack-pr-title-rewrite.sh` is the single source of truth for the rule.
|
||||
|
||||
1. Read the current title: `CURRENT=$(gh pr view --json title -q .title)` (or `glab mr view -F json | jq -r .title`).
|
||||
2. Compute the corrected title: `NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$NEW_VERSION" "$CURRENT")`. The helper handles three cases: title already correct (no-op), title has a different `v<X.Y.Z.W>` prefix (replace it), or title has no version prefix (prepend one).
|
||||
3. If `NEW_TITLE` differs from `CURRENT`, run `gh pr edit --title "$NEW_TITLE"` (or `glab mr update -t "$NEW_TITLE"`).
|
||||
4. **Self-check:** re-fetch the title and assert it starts with `v$NEW_VERSION `. If it does not, retry the edit once. If still wrong, surface the failure to the user.
|
||||
|
||||
This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version, and forces the format on PRs that were created without it.
|
||||
|
||||
Print the existing URL and continue to Step 20.
|
||||
|
||||
@@ -864,6 +871,8 @@ you missed it.>
|
||||
**If GitHub:**
|
||||
|
||||
```bash
|
||||
# PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
gh pr create --base <base> --title "v$NEW_VERSION <type>: <summary>" --body "$(cat <<'EOF'
|
||||
<PR body from above>
|
||||
EOF
|
||||
@@ -873,6 +882,8 @@ EOF
|
||||
**If GitLab:**
|
||||
|
||||
```bash
|
||||
# MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
glab mr create -b <base> -t "v$NEW_VERSION <type>: <summary>" -d "$(cat <<'EOF'
|
||||
<MR body from above>
|
||||
EOF
|
||||
|
||||
+12
-1
@@ -2760,7 +2760,14 @@ glab mr view -F json 2>/dev/null | jq -r 'if .state == "opened" then "MR_EXISTS"
|
||||
|
||||
If an **open** PR/MR already exists: **update** the PR body using `gh pr edit --body "..."` (GitHub) or `glab mr update -d "..."` (GitLab). Always regenerate the PR body from scratch using this run's fresh results (test output, coverage audit, review findings, adversarial review, TODOS summary, documentation_section from Step 18). Never reuse stale PR body content from a prior run.
|
||||
|
||||
**Also update the PR title** if the version changed on rerun. PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first. If the current title's version prefix doesn't match `NEW_VERSION`, run `gh pr edit --title "v$NEW_VERSION <type>: <summary>"` (or the `glab mr update -t ...` equivalent). This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version. If the title has no `v<X.Y.Z.W>` prefix (a custom title kept intentionally), leave the title alone — only rewrite titles that already follow the format.
|
||||
**Always update the PR title to start with `v$NEW_VERSION`.** PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first, no exceptions, no "custom title kept intentionally" escape hatch. The shared helper `bin/gstack-pr-title-rewrite.sh` is the single source of truth for the rule.
|
||||
|
||||
1. Read the current title: `CURRENT=$(gh pr view --json title -q .title)` (or `glab mr view -F json | jq -r .title`).
|
||||
2. Compute the corrected title: `NEW_TITLE=$(~/.claude/skills/gstack/bin/gstack-pr-title-rewrite.sh "$NEW_VERSION" "$CURRENT")`. The helper handles three cases: title already correct (no-op), title has a different `v<X.Y.Z.W>` prefix (replace it), or title has no version prefix (prepend one).
|
||||
3. If `NEW_TITLE` differs from `CURRENT`, run `gh pr edit --title "$NEW_TITLE"` (or `glab mr update -t "$NEW_TITLE"`).
|
||||
4. **Self-check:** re-fetch the title and assert it starts with `v$NEW_VERSION `. If it does not, retry the edit once. If still wrong, surface the failure to the user.
|
||||
|
||||
This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version, and forces the format on PRs that were created without it.
|
||||
|
||||
Print the existing URL and continue to Step 20.
|
||||
|
||||
@@ -2830,6 +2837,8 @@ you missed it.>
|
||||
**If GitHub:**
|
||||
|
||||
```bash
|
||||
# PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
gh pr create --base <base> --title "v$NEW_VERSION <type>: <summary>" --body "$(cat <<'EOF'
|
||||
<PR body from above>
|
||||
EOF
|
||||
@@ -2839,6 +2848,8 @@ EOF
|
||||
**If GitLab:**
|
||||
|
||||
```bash
|
||||
# MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
glab mr create -b <base> -t "v$NEW_VERSION <type>: <summary>" -d "$(cat <<'EOF'
|
||||
<MR body from above>
|
||||
EOF
|
||||
|
||||
+12
-1
@@ -2375,7 +2375,14 @@ glab mr view -F json 2>/dev/null | jq -r 'if .state == "opened" then "MR_EXISTS"
|
||||
|
||||
If an **open** PR/MR already exists: **update** the PR body using `gh pr edit --body "..."` (GitHub) or `glab mr update -d "..."` (GitLab). Always regenerate the PR body from scratch using this run's fresh results (test output, coverage audit, review findings, adversarial review, TODOS summary, documentation_section from Step 18). Never reuse stale PR body content from a prior run.
|
||||
|
||||
**Also update the PR title** if the version changed on rerun. PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first. If the current title's version prefix doesn't match `NEW_VERSION`, run `gh pr edit --title "v$NEW_VERSION <type>: <summary>"` (or the `glab mr update -t ...` equivalent). This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version. If the title has no `v<X.Y.Z.W>` prefix (a custom title kept intentionally), leave the title alone — only rewrite titles that already follow the format.
|
||||
**Always update the PR title to start with `v$NEW_VERSION`.** PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first, no exceptions, no "custom title kept intentionally" escape hatch. The shared helper `bin/gstack-pr-title-rewrite.sh` is the single source of truth for the rule.
|
||||
|
||||
1. Read the current title: `CURRENT=$(gh pr view --json title -q .title)` (or `glab mr view -F json | jq -r .title`).
|
||||
2. Compute the corrected title: `NEW_TITLE=$($GSTACK_ROOT/bin/gstack-pr-title-rewrite.sh "$NEW_VERSION" "$CURRENT")`. The helper handles three cases: title already correct (no-op), title has a different `v<X.Y.Z.W>` prefix (replace it), or title has no version prefix (prepend one).
|
||||
3. If `NEW_TITLE` differs from `CURRENT`, run `gh pr edit --title "$NEW_TITLE"` (or `glab mr update -t "$NEW_TITLE"`).
|
||||
4. **Self-check:** re-fetch the title and assert it starts with `v$NEW_VERSION `. If it does not, retry the edit once. If still wrong, surface the failure to the user.
|
||||
|
||||
This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version, and forces the format on PRs that were created without it.
|
||||
|
||||
Print the existing URL and continue to Step 20.
|
||||
|
||||
@@ -2445,6 +2452,8 @@ you missed it.>
|
||||
**If GitHub:**
|
||||
|
||||
```bash
|
||||
# PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
gh pr create --base <base> --title "v$NEW_VERSION <type>: <summary>" --body "$(cat <<'EOF'
|
||||
<PR body from above>
|
||||
EOF
|
||||
@@ -2454,6 +2463,8 @@ EOF
|
||||
**If GitLab:**
|
||||
|
||||
```bash
|
||||
# MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
glab mr create -b <base> -t "v$NEW_VERSION <type>: <summary>" -d "$(cat <<'EOF'
|
||||
<MR body from above>
|
||||
EOF
|
||||
|
||||
+12
-1
@@ -2751,7 +2751,14 @@ glab mr view -F json 2>/dev/null | jq -r 'if .state == "opened" then "MR_EXISTS"
|
||||
|
||||
If an **open** PR/MR already exists: **update** the PR body using `gh pr edit --body "..."` (GitHub) or `glab mr update -d "..."` (GitLab). Always regenerate the PR body from scratch using this run's fresh results (test output, coverage audit, review findings, adversarial review, TODOS summary, documentation_section from Step 18). Never reuse stale PR body content from a prior run.
|
||||
|
||||
**Also update the PR title** if the version changed on rerun. PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first. If the current title's version prefix doesn't match `NEW_VERSION`, run `gh pr edit --title "v$NEW_VERSION <type>: <summary>"` (or the `glab mr update -t ...` equivalent). This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version. If the title has no `v<X.Y.Z.W>` prefix (a custom title kept intentionally), leave the title alone — only rewrite titles that already follow the format.
|
||||
**Always update the PR title to start with `v$NEW_VERSION`.** PR titles use the workspace-aware format `v<NEW_VERSION> <type>: <summary>` — version ALWAYS first, no exceptions, no "custom title kept intentionally" escape hatch. The shared helper `bin/gstack-pr-title-rewrite.sh` is the single source of truth for the rule.
|
||||
|
||||
1. Read the current title: `CURRENT=$(gh pr view --json title -q .title)` (or `glab mr view -F json | jq -r .title`).
|
||||
2. Compute the corrected title: `NEW_TITLE=$($GSTACK_ROOT/bin/gstack-pr-title-rewrite.sh "$NEW_VERSION" "$CURRENT")`. The helper handles three cases: title already correct (no-op), title has a different `v<X.Y.Z.W>` prefix (replace it), or title has no version prefix (prepend one).
|
||||
3. If `NEW_TITLE` differs from `CURRENT`, run `gh pr edit --title "$NEW_TITLE"` (or `glab mr update -t "$NEW_TITLE"`).
|
||||
4. **Self-check:** re-fetch the title and assert it starts with `v$NEW_VERSION `. If it does not, retry the edit once. If still wrong, surface the failure to the user.
|
||||
|
||||
This keeps the title truthful when Step 12's queue-drift detection rebumps a stale version, and forces the format on PRs that were created without it.
|
||||
|
||||
Print the existing URL and continue to Step 20.
|
||||
|
||||
@@ -2821,6 +2828,8 @@ you missed it.>
|
||||
**If GitHub:**
|
||||
|
||||
```bash
|
||||
# PR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
gh pr create --base <base> --title "v$NEW_VERSION <type>: <summary>" --body "$(cat <<'EOF'
|
||||
<PR body from above>
|
||||
EOF
|
||||
@@ -2830,6 +2839,8 @@ EOF
|
||||
**If GitLab:**
|
||||
|
||||
```bash
|
||||
# MR title MUST start with v$NEW_VERSION — enforced on every run, no exceptions.
|
||||
# (See Step 19 idempotency block + bin/gstack-pr-title-rewrite.sh for the rule.)
|
||||
glab mr create -b <base> -t "v$NEW_VERSION <type>: <summary>" -d "$(cat <<'EOF'
|
||||
<MR body from above>
|
||||
EOF
|
||||
|
||||
Reference in New Issue
Block a user