|
| 1 | +--- |
| 2 | +name: back-merge |
| 3 | +description: > |
| 4 | + Creates or checks back-merge PRs (main/master → development) across repos after a release. |
| 5 | + Use whenever the user wants to check or create back-merge PRs, verify post-release branch sync, |
| 6 | + or audit which repos are missing a back-merge. |
| 7 | + Triggers on: /back-merge, "back merge", "backmerge", "check back merges", "create back-merge PRs", |
| 8 | + "are back merges done", "post-release back merge". |
| 9 | +--- |
| 10 | + |
| 11 | +# Back-Merge Skill |
| 12 | + |
| 13 | +Creates or checks PRs that merge `main/master → development` across repos after a release. |
| 14 | +Supports two input modes and two run modes. |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## Usage |
| 19 | + |
| 20 | +When this skill activates, greet the user with this help block before doing anything else: |
| 21 | + |
| 22 | +``` |
| 23 | +👋 /back-merge — Back-merge PR checker & creator |
| 24 | +
|
| 25 | +How to use: |
| 26 | + /back-merge → I'll ask how to specify repos |
| 27 | + /back-merge "<fixVersion>" → pull repos from a Jira release |
| 28 | + /back-merge <github-url1> <github-url2> ... → use a direct repo list |
| 29 | + /back-merge "<fixVersion>" <github-url1> ... → combine both sources |
| 30 | +
|
| 31 | +Modes (specify after your input, or I'll ask): |
| 32 | + check — read-only audit, shows what needs back-merging (default, recommended) |
| 33 | + create — raises PRs for all repos that need them (asks for confirmation first) |
| 34 | +
|
| 35 | +Examples: |
| 36 | + /back-merge "DX | 16-08-2026 | Release" check |
| 37 | + /back-merge https://github.com/org/repo1 https://github.com/org/repo2 |
| 38 | + /back-merge "PROJ | 16-08-2026 | Release" create |
| 39 | +
|
| 40 | +Requirements: |
| 41 | + gh CLI → brew install gh && gh auth login |
| 42 | + Jira MCP (only needed for fixVersion mode) — must be connected in Claude Code |
| 43 | +``` |
| 44 | + |
| 45 | +Only show this block once at the start. Then proceed to collect inputs. |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +## Inputs |
| 50 | + |
| 51 | +| Input | Format | Example | |
| 52 | +|-------|--------|---------| |
| 53 | +| `fixVersion` | Jira fixVersion string | `PROJ \| 16-08-2026 \| Release` | |
| 54 | +| `repo_list` | Space or comma-separated GitHub URLs | `https://github.com/org/repo1 https://github.com/org/repo2` | |
| 55 | +| `mode` | `check` or `create` | `check` | |
| 56 | + |
| 57 | +**If neither fixVersion nor repo_list is provided** — use AskUserQuestion: |
| 58 | + |
| 59 | +> **Question:** "How would you like to specify the repos to back-merge?" |
| 60 | +> - `fixVersion` — pull repos from a Jira release (e.g. `PROJ | 16-08-2026 | Release`) |
| 61 | +> - `Repo list` — paste GitHub repo URLs directly |
| 62 | +> - `Both` — combine repos from a fixVersion AND a manual list |
| 63 | +> |
| 64 | +> *(User can select "Other" to type a custom value)* |
| 65 | +
|
| 66 | +Do not proceed without knowing the scope. |
| 67 | + |
| 68 | +**If mode is not provided** — use AskUserQuestion: |
| 69 | + |
| 70 | +> **Question:** "Which mode do you want to run?" |
| 71 | +> - `Check` — read-only, shows what needs back-merging without creating any PRs *(Recommended)* |
| 72 | +> - `Create PRs` — creates back-merge PRs for all repos that need them |
| 73 | +> |
| 74 | +> *(User can select "Other" to specify a custom behaviour)* |
| 75 | +
|
| 76 | +--- |
| 77 | + |
| 78 | +## Step 1 — Resolve Repo List |
| 79 | + |
| 80 | +### 1a — From fixVersion |
| 81 | + |
| 82 | +**Extract the project key** from the fixVersion string — it is the first segment before the first `|`: |
| 83 | +- `"DX | 16-08-2026 | Release"` → project key = `DX` |
| 84 | +- `"PROJ | 16-08-2026 | Release"` → project key = `PROJ` |
| 85 | + |
| 86 | +Query Jira using the extracted project key: |
| 87 | + |
| 88 | +``` |
| 89 | +project = {project_key} AND fixVersion = "{fixVersion}" ORDER BY created ASC |
| 90 | +``` |
| 91 | + |
| 92 | +Scan every ticket's `comment.comments[].body` AND the master release ticket's `description` for GitHub PR URLs: |
| 93 | + |
| 94 | +``` |
| 95 | +pattern: https://github\.com/[^/]+/[^/]+/pull/\d+ |
| 96 | +``` |
| 97 | + |
| 98 | +For each unique PR URL, extract `owner` and `repo` from the URL path. Deduplicate by `owner/repo`. This is your repo list. |
| 99 | + |
| 100 | +If no PR URLs are found → warn the user and stop: |
| 101 | +> `⚠️ No GitHub PRs found for fixVersion "{fixVersion}". Cannot determine repo scope.` |
| 102 | +
|
| 103 | +### 1b — From repo_list |
| 104 | + |
| 105 | +Parse each GitHub URL to extract `owner/repo`: |
| 106 | +- `https://github.com/org/repo-name` → `org/repo-name` |
| 107 | + |
| 108 | +Deduplicate silently. If a URL can't be parsed → skip it and flag: |
| 109 | +> `⚠️ Could not parse repo from URL: {url} — skipped.` |
| 110 | +
|
| 111 | +### Step 1 output — display resolved repos before proceeding |
| 112 | + |
| 113 | +After resolving the repo list, always show this table: |
| 114 | + |
| 115 | +``` |
| 116 | +📋 Repos resolved (N total) |
| 117 | +
|
| 118 | +# | Repo | Source |
| 119 | +--|---------------------------|-------- |
| 120 | +1 | org/repo-one | fixVersion |
| 121 | +2 | org/repo-two | manual list |
| 122 | +3 | org/repo-three | fixVersion |
| 123 | +``` |
| 124 | + |
| 125 | +Do not proceed to Step 2 until this table is shown. |
| 126 | + |
| 127 | +--- |
| 128 | + |
| 129 | +## Step 2 & 3 — Run the bundled script |
| 130 | + |
| 131 | +Use `scripts/back-merge.sh` — do not regenerate this logic inline. |
| 132 | + |
| 133 | +```bash |
| 134 | +SKILL_DIR="$(dirname "$(realpath "$0")")/.." # or: ~/.claude/skills/back-merge |
| 135 | + |
| 136 | +# check mode |
| 137 | +bash "$SKILL_DIR/scripts/back-merge.sh" check \ |
| 138 | + owner/repo1 owner/repo2 ... |
| 139 | + |
| 140 | +# create mode — pass the full fixVersion string as the second argument |
| 141 | +bash "$SKILL_DIR/scripts/back-merge.sh" create "{fixVersion}" \ |
| 142 | + owner/repo1 owner/repo2 ... |
| 143 | + |
| 144 | +# create mode — no fixVersion (repo list only) |
| 145 | +bash "$SKILL_DIR/scripts/back-merge.sh" create "" \ |
| 146 | + owner/repo1 owner/repo2 ... |
| 147 | +``` |
| 148 | + |
| 149 | +**Before running in create mode** — show the resolved repos table from Step 1 if not already visible, then use AskUserQuestion: |
| 150 | + |
| 151 | +> **Question:** "Ready to create back-merge PRs for the N repos listed above. Proceed?" |
| 152 | +> - `Yes, create PRs` — proceed with PR creation |
| 153 | +> - `No, abort` — stop without making any changes |
| 154 | +> - `Check only` — switch to check mode instead (read-only, no PRs created) |
| 155 | +> |
| 156 | +> *(User can select "Other" to specify which repos to skip or override)* |
| 157 | +
|
| 158 | +Do not create any PRs until the user confirms. |
| 159 | + |
| 160 | +The script outputs one pipe-delimited line per repo: |
| 161 | + |
| 162 | +``` |
| 163 | +owner/repo|STATUS_CODE|branch_used|details |
| 164 | +``` |
| 165 | + |
| 166 | +| STATUS_CODE | Meaning | |
| 167 | +|-------------|---------| |
| 168 | +| `IN_SYNC` | branches are in sync | |
| 169 | +| `NEEDS_MERGE` | back-merge needed (`details` = "base is N commits ahead (status)") | |
| 170 | +| `PR_OPEN` | open PR already exists (`details` = "PR#N url") | |
| 171 | +| `CREATED` | PR created (`details` = PR URL) | |
| 172 | +| `NO_DEV` | no development branch | |
| 173 | +| `NO_BASE` | no main or master branch | |
| 174 | +| `ACCESS_ERROR` | API error / no access | |
| 175 | +| `ERROR` | PR creation failed (`details` = error message) | |
| 176 | + |
| 177 | +Parse the output and render the table below. |
| 178 | + |
| 179 | +### Check mode output table |
| 180 | + |
| 181 | +``` |
| 182 | +Repo | Status | Details |
| 183 | +org/repo-one | ✅ In sync | — |
| 184 | +org/repo-two | ⚠️ Back-merge needed | main is 4 commits ahead |
| 185 | +org/repo-three | 🔄 PR open — pending merge | PR#456 <url> |
| 186 | +org/repo-four | ❌ No dev branch | — |
| 187 | +org/repo-five | ❌ Access error | — |
| 188 | +``` |
| 189 | + |
| 190 | +Do not create any PRs in check mode. |
| 191 | + |
| 192 | +### Create mode output table |
| 193 | + |
| 194 | +``` |
| 195 | +Repo | Result | PR |
| 196 | +org/repo-one | ✅ Created | PR#789 <url> |
| 197 | +org/repo-two | ⏭️ Skipped — PR open | PR#456 <url> |
| 198 | +org/repo-three | ⏭️ Skipped — in sync | — |
| 199 | +org/repo-four | ⏭️ Skipped — no dev branch | — |
| 200 | +``` |
| 201 | + |
| 202 | +**`ERROR` rows**: report the details verbatim — do not retry silently. If details contains "No commits between", treat it as `IN_SYNC`. |
| 203 | + |
| 204 | +--- |
| 205 | + |
| 206 | +## Corner Cases Handled |
| 207 | + |
| 208 | +| # | Scenario | Behaviour | |
| 209 | +|---|----------|-----------| |
| 210 | +| 1 | Repo has no `development` branch | Flagged `❌ No dev branch`, skipped | |
| 211 | +| 2 | Repo has no `main` or `master` | Flagged `❌ No main/master branch`, skipped | |
| 212 | +| 3 | main and development are identical (in sync) | Flagged `✅ In sync`, no PR created | |
| 213 | +| 4 | Back-merge PR already open | Reported as `🔄 pending merge`, not duplicated | |
| 214 | +| 5 | Back-merge PR was closed (not merged) | New PR created — closed ≠ done | |
| 215 | +| 6 | Branches diverged (both have unique commits) | PR created anyway — GitHub surfaces conflicts | |
| 216 | +| 7 | `gh` cannot access repo (private / permissions) | Flagged `❌ Access error`, skipped | |
| 217 | +| 8 | Duplicate repos in manual list | Deduplicated silently before processing | |
| 218 | +| 9 | Unparseable URL in manual list | Flagged and skipped, rest continues | |
| 219 | +| 10 | fixVersion has no PRs / no repos found | Warn user and stop — no scope to act on | |
| 220 | +| 11 | PR creation fails with "no commits between" | Treated as `✅ In sync` — already resolved | |
| 221 | +| 12 | Mode not specified | Ask via AskUserQuestion (see Inputs section) | |
| 222 | +| 13 | Repo list + fixVersion both provided | Merge both lists, deduplicate, proceed | |
| 223 | + |
| 224 | +--- |
| 225 | + |
| 226 | +## Final Summary Output |
| 227 | + |
| 228 | +After all repos are processed: |
| 229 | + |
| 230 | +``` |
| 231 | +✅ Back-merge run complete |
| 232 | +
|
| 233 | +Mode: check | create |
| 234 | +Input: fixVersion "{fixVersion}" | {N} repos from list |
| 235 | +
|
| 236 | +📊 Summary: |
| 237 | + ⚠️ Needs back-merge: <N repos — listed> |
| 238 | + 🔄 PR open (pending merge): <N repos — listed with PR links> |
| 239 | + ✅ In sync: <N repos> |
| 240 | + ❌ Skipped (no dev branch): <N repos> |
| 241 | + ❌ Skipped (access error): <N repos> |
| 242 | +
|
| 243 | +[create mode only] |
| 244 | + ✅ PRs created: <N> — <links> |
| 245 | +``` |
| 246 | + |
| 247 | +--- |
| 248 | + |
| 249 | +## Error Handling |
| 250 | + |
| 251 | +- **`gh` not authenticated**: Run `gh auth status`; ask user to run `gh auth login` if needed |
| 252 | +- **Jira MCP not available**: Cannot resolve fixVersion — ask user to switch to repo_list input mode |
| 253 | +- **All repos in sync**: Report clearly — no action needed |
| 254 | +- **Partial failures**: Always continue processing remaining repos; report failures at the end |
0 commit comments