gflows 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -2
- package/CHANGELOG.md +7 -0
- package/README.md +6 -4
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/src/commands/completion.ts +8 -6
- package/src/commands/help.ts +2 -2
- package/src/commands/mcp.ts +13 -5
- package/src/commands/release.ts +89 -18
- package/src/commands/schema.ts +6 -3
- package/src/interactive.ts +11 -6
- package/src/parse.ts +14 -3
- package/src/tui/flows.tsx +16 -9
- package/src/types.ts +5 -0
package/AGENTS.md
CHANGED
|
@@ -46,8 +46,9 @@ gflows start release v1.2.0
|
|
|
46
46
|
# … changelog / commits …
|
|
47
47
|
gflows finish release -y -p
|
|
48
48
|
|
|
49
|
-
# Quick release from dev (bump + merge main + tag, no release/* branch)
|
|
50
|
-
gflows release up patch -y -p
|
|
49
|
+
# Quick release from dev (bump or keep version + merge main + tag, no release/* branch)
|
|
50
|
+
gflows release up patch -y -p # or -P; must be on dev
|
|
51
|
+
gflows release current -y -p # after a manual bump; tags package version as-is
|
|
51
52
|
|
|
52
53
|
# Stuck
|
|
53
54
|
gflows doctor --json
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.1] - 2026-07-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Quick release can keep the package version already on disk: `gflows release current -y -p` (or choose **keep current** in the hub / interactive prompt)
|
|
15
|
+
- MCP `gflows_release` accepts `keepCurrent: true` as an alternative to `bumpType`
|
|
16
|
+
|
|
10
17
|
## [1.2.0] - 2026-07-25
|
|
11
18
|
|
|
12
19
|
### Added
|
package/README.md
CHANGED
|
@@ -130,7 +130,7 @@ main ← release / hotfix only (production)
|
|
|
130
130
|
| **dev** | Integration (created by `init` from main) |
|
|
131
131
|
| **feature / bugfix / chore / spike** | Day-to-day work → merge to **dev** |
|
|
132
132
|
| **release / hotfix** | Versioned (`vX.Y.Z`) → **main**, then **main → dev**, + tag |
|
|
133
|
-
| **quick release** (`gflows release`) | From **dev** only: bump → **main** → tag → sync **dev**
|
|
133
|
+
| **quick release** (`gflows release`) | From **dev** only: bump or keep → **main** → tag → sync **dev** |
|
|
134
134
|
|
|
135
135
|
|
|
136
136
|
**Lifecycle:** `init` → `start` → commit → (`sync`) → (`pr`) → `finish`
|
|
@@ -217,11 +217,13 @@ Hub: `g` → select the action. Typed short form assumes `alias g=gflows`.
|
|
|
217
217
|
| `gflows start release v1.4.0` | `g -S -r v1.4.0` |
|
|
218
218
|
| `gflows finish release -y -p` | `g -F -r -y -p` |
|
|
219
219
|
|
|
220
|
-
**Quick release from `dev`** —
|
|
220
|
+
**Quick release from `dev`** — merge **main**, tag, sync **main → dev** (no `release/*` branch). Choose a bump, or keep a version you already set manually.
|
|
221
221
|
|
|
222
222
|
| Long | Short |
|
|
223
223
|
|------|-------|
|
|
224
|
-
| `gflows release up patch -y -p` | — |
|
|
224
|
+
| `gflows release up patch -y -p` | — (bump, then ship) |
|
|
225
|
+
| `gflows release up minor -y -p` | — |
|
|
226
|
+
| `gflows release current -y -p` | — (keep `package.json` version; no bump commit) |
|
|
225
227
|
|
|
226
228
|
**Hotfix**
|
|
227
229
|
|
|
@@ -274,7 +276,7 @@ Bare `gflows` / `g` in a **TTY** opens the Ink hub (see [Way 1](#way-1--hub-reco
|
|
|
274
276
|
| `init` `-I` | Ensure main; create dev |
|
|
275
277
|
| `start` `-S` | Create typed branch |
|
|
276
278
|
| `finish` `-F` | Merge + close (plan; delete default **on**) |
|
|
277
|
-
| `release` | Quick release from `dev` (bump + main + tag)|
|
|
279
|
+
| `release` | Quick release from `dev` (bump/keep + main + tag)|
|
|
278
280
|
| `sync` | Update branch from its base |
|
|
279
281
|
| `pr` | Open PR/MR (`gh` / `glab`) |
|
|
280
282
|
| `switch` `-W` | Switch branch |
|
package/llms.txt
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
- `gflows viz`: scrollback status panel — lifecycle, branches, recommended next step
|
|
15
15
|
- `gflows init` / `start` / `finish` / `release` / `sync` / `pr`
|
|
16
16
|
- `gflows release up patch -y -p` — quick ship from `dev` (bump + merge main + tag)
|
|
17
|
+
- `gflows release current -y -p` — same, but keep the package version already on disk (after a manual bump)
|
|
17
18
|
- `gflows continue` / `undo` / `abort` — recovery after conflicts
|
|
18
19
|
- `gflows doctor` / `info` / `config` / `status --json` / `mcp`
|
|
19
20
|
|
package/package.json
CHANGED
|
@@ -135,8 +135,8 @@ _gflows() {
|
|
|
135
135
|
;;
|
|
136
136
|
release)
|
|
137
137
|
if (( cword == cmd_idx + 1 )); then
|
|
138
|
-
COMPREPLY=($(compgen -W "up" -- "$cur"))
|
|
139
|
-
elif (( cword == cmd_idx + 2 )); then
|
|
138
|
+
COMPREPLY=($(compgen -W "up current" -- "$cur"))
|
|
139
|
+
elif (( cword == cmd_idx + 2 )) && [[ "${D}words[cmd_idx + 1]}" == "up" ]]; then
|
|
140
140
|
COMPREPLY=($(compgen -W "${BUMP_TYPES.join(" ")}" -- "$cur"))
|
|
141
141
|
else
|
|
142
142
|
COMPREPLY=()
|
|
@@ -226,7 +226,7 @@ _gflows() {
|
|
|
226
226
|
if [[ "${D}words[CURRENT-1]}" == "up" ]]; then
|
|
227
227
|
_values "bump-type" ${BUMP_TYPES.map((t) => `"${t}"`).join(" ")}
|
|
228
228
|
else
|
|
229
|
-
_values "
|
|
229
|
+
_values "mode" "up" "current"
|
|
230
230
|
fi
|
|
231
231
|
;;
|
|
232
232
|
esac
|
|
@@ -334,9 +334,11 @@ complete -c gflows -f -n "__fish_seen_subcommand_from bump; and not __fish_seen_
|
|
|
334
334
|
complete -c gflows -f -n "__fish_seen_subcommand_from bump; and __fish_seen_subcommand_from up down" \\
|
|
335
335
|
-a "patch minor major"
|
|
336
336
|
|
|
337
|
-
# release up [patch|minor|major]
|
|
338
|
-
complete -c gflows -f -n "__fish_seen_subcommand_from release; and not __fish_seen_subcommand_from up" \\
|
|
339
|
-
-a "up"
|
|
337
|
+
# release up [patch|minor|major] | current
|
|
338
|
+
complete -c gflows -f -n "__fish_seen_subcommand_from release; and not __fish_seen_subcommand_from up current" \\
|
|
339
|
+
-a "up" -d "Bump then release"
|
|
340
|
+
complete -c gflows -f -n "__fish_seen_subcommand_from release; and not __fish_seen_subcommand_from up current" \\
|
|
341
|
+
-a "current" -d "Keep current version (no bump)"
|
|
340
342
|
complete -c gflows -f -n "__fish_seen_subcommand_from release; and __fish_seen_subcommand_from up" \\
|
|
341
343
|
-a "patch minor major"
|
|
342
344
|
|
package/src/commands/help.ts
CHANGED
|
@@ -19,7 +19,7 @@ Commands:
|
|
|
19
19
|
init, -I Ensure main, create dev (TTY: wizard; optional package.json script alias)
|
|
20
20
|
start, -S Create workflow branch (TTY: prompts if args missing)
|
|
21
21
|
finish, -F Merge and close branch (plan + delete by default)
|
|
22
|
-
release Quick release from dev (bump + merge main + tag)
|
|
22
|
+
release Quick release from dev (bump or keep version + merge main + tag)
|
|
23
23
|
sync Update current branch from its base
|
|
24
24
|
pr Open PR/MR via gh or glab (correct base)
|
|
25
25
|
switch, -W Switch branch (picker or name)
|
|
@@ -62,7 +62,7 @@ Init: --script-alias <name> Add package.json script (e.g. g → "gflows")
|
|
|
62
62
|
Start: --force Allow dirty working tree
|
|
63
63
|
Finish: --no-ff Always create merge commit; -D/--delete, -N/--no-delete;
|
|
64
64
|
--squash, --preview, --bump; -s/--sign, -T/--no-tag, -M/--tag-message, -m/--message
|
|
65
|
-
Release: up <patch|minor|major> (from dev only); -y -p|-P; --preview; -s/--sign
|
|
65
|
+
Release: up <patch|minor|major> | current (from dev only); -y -p|-P; --preview; -s/--sign
|
|
66
66
|
Sync: --rebase, --force
|
|
67
67
|
List: -r, --include-remote Include remote-tracking branches
|
|
68
68
|
Switch: --move | --restore | --clean | --destroy | --cancel
|
package/src/commands/mcp.ts
CHANGED
|
@@ -96,19 +96,22 @@ const TOOLS = [
|
|
|
96
96
|
{
|
|
97
97
|
name: "gflows_release",
|
|
98
98
|
description:
|
|
99
|
-
"Quick release from dev: bump
|
|
99
|
+
"Quick release from dev: optional bump (or keep current version), merge into main, tag, sync main→dev. Pass bumpType or keepCurrent.",
|
|
100
100
|
inputSchema: {
|
|
101
101
|
type: "object",
|
|
102
102
|
properties: {
|
|
103
103
|
path: { type: "string" },
|
|
104
104
|
bumpType: {
|
|
105
105
|
type: "string",
|
|
106
|
-
description: "Semver segment to bump: patch, minor, or major",
|
|
106
|
+
description: "Semver segment to bump: patch, minor, or major (omit when keepCurrent)",
|
|
107
|
+
},
|
|
108
|
+
keepCurrent: {
|
|
109
|
+
type: "boolean",
|
|
110
|
+
description: "Tag the package version already on disk (no bump commit)",
|
|
107
111
|
},
|
|
108
112
|
push: { type: "boolean" },
|
|
109
113
|
preview: { type: "boolean" },
|
|
110
114
|
},
|
|
111
|
-
required: ["bumpType"],
|
|
112
115
|
},
|
|
113
116
|
},
|
|
114
117
|
{
|
|
@@ -178,8 +181,13 @@ async function runTool(
|
|
|
178
181
|
else argv.push("-P");
|
|
179
182
|
break;
|
|
180
183
|
case "gflows_release": {
|
|
181
|
-
|
|
182
|
-
|
|
184
|
+
if (args.keepCurrent === true) {
|
|
185
|
+
argv.push("release", "current");
|
|
186
|
+
} else if (typeof args.bumpType === "string" && args.bumpType.trim() !== "") {
|
|
187
|
+
argv.push("release", "up", args.bumpType.trim());
|
|
188
|
+
} else {
|
|
189
|
+
throw new Error("gflows_release: pass bumpType (patch|minor|major) or keepCurrent: true");
|
|
190
|
+
}
|
|
183
191
|
if (args.preview) argv.push("--preview");
|
|
184
192
|
if (args.push) argv.push("-p");
|
|
185
193
|
else argv.push("-P");
|
package/src/commands/release.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Quick release from the long-lived `dev` branch: bump, merge into main, tag, sync main→dev.
|
|
2
|
+
* Quick release from the long-lived `dev` branch: bump (or keep), merge into main, tag, sync main→dev.
|
|
3
3
|
* @module commands/release
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -21,9 +21,18 @@ import {
|
|
|
21
21
|
import { hint, success } from "../out.js";
|
|
22
22
|
import { PACKAGE_JSON } from "../packages.js";
|
|
23
23
|
import type { BumpType, ParsedArgs } from "../types.js";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
applyVersionToPackages,
|
|
26
|
+
computeBump,
|
|
27
|
+
JSR_JSON,
|
|
28
|
+
readPackageVersion,
|
|
29
|
+
sortedPackageRoots,
|
|
30
|
+
} from "../version-bump.js";
|
|
25
31
|
import { type FinishContext, runFinishPlan } from "./finish.js";
|
|
26
32
|
|
|
33
|
+
/** Interactive choice: keep package version as-is, or bump a semver segment. */
|
|
34
|
+
type ReleaseVersionChoice = "current" | BumpType;
|
|
35
|
+
|
|
27
36
|
/**
|
|
28
37
|
* Runs quick release: only valid when HEAD is the configured `dev` branch.
|
|
29
38
|
*/
|
|
@@ -66,24 +75,30 @@ export async function run(args: ParsedArgs): Promise<void> {
|
|
|
66
75
|
);
|
|
67
76
|
}
|
|
68
77
|
|
|
78
|
+
let keepCurrent = args.keepCurrent === true;
|
|
69
79
|
let bumpType: BumpType | undefined = args.bumpType;
|
|
80
|
+
|
|
70
81
|
if (args.bumpDirection === "down") {
|
|
71
82
|
console.error(
|
|
72
|
-
"gflows release: only 'up' is supported (not 'down'). Example: gflows release up patch",
|
|
83
|
+
"gflows release: only 'up' or 'current' is supported (not 'down'). Example: gflows release up patch",
|
|
73
84
|
);
|
|
74
85
|
process.exit(EXIT_USER);
|
|
75
86
|
}
|
|
76
87
|
if (args.bumpDirection && args.bumpDirection !== "up") {
|
|
77
88
|
console.error(
|
|
78
|
-
"gflows release: expected 'up <patch|minor|major>'. Example: gflows release up patch",
|
|
89
|
+
"gflows release: expected 'up <patch|minor|major>' or 'current'. Example: gflows release up patch",
|
|
79
90
|
);
|
|
80
91
|
process.exit(EXIT_USER);
|
|
81
92
|
}
|
|
93
|
+
if (keepCurrent && (args.bumpDirection || bumpType)) {
|
|
94
|
+
console.error("gflows release: use either 'current' or 'up <patch|minor|major>', not both.");
|
|
95
|
+
process.exit(EXIT_USER);
|
|
96
|
+
}
|
|
82
97
|
|
|
83
|
-
if (!bumpType) {
|
|
98
|
+
if (!keepCurrent && !bumpType) {
|
|
84
99
|
if (!isTTY) {
|
|
85
100
|
console.error(
|
|
86
|
-
"gflows release: when not in a TTY,
|
|
101
|
+
"gflows release: when not in a TTY, specify version mode. Examples: gflows release current -y -P or gflows release up patch -y -P",
|
|
87
102
|
);
|
|
88
103
|
process.exit(EXIT_USER);
|
|
89
104
|
}
|
|
@@ -96,14 +111,32 @@ export async function run(args: ParsedArgs): Promise<void> {
|
|
|
96
111
|
}
|
|
97
112
|
})();
|
|
98
113
|
const currentVer = computedPreview?.oldVersion ?? "?";
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
// `release up` already chose bumping — only ask which segment.
|
|
115
|
+
if (args.bumpDirection === "up") {
|
|
116
|
+
bumpType = await selectPrompt<BumpType>({
|
|
117
|
+
message: `Bump version (current ${currentVer})`,
|
|
118
|
+
options: [
|
|
119
|
+
{ label: "patch (x.y.Z)", value: "patch" },
|
|
120
|
+
{ label: "minor (x.Y.0)", value: "minor" },
|
|
121
|
+
{ label: "major (X.0.0)", value: "major" },
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
const choice = await selectPrompt<ReleaseVersionChoice>({
|
|
126
|
+
message: `Version for release (current ${currentVer})`,
|
|
127
|
+
options: [
|
|
128
|
+
{ label: `keep current (${currentVer})`, value: "current" },
|
|
129
|
+
{ label: "bump patch (x.y.Z)", value: "patch" },
|
|
130
|
+
{ label: "bump minor (x.Y.0)", value: "minor" },
|
|
131
|
+
{ label: "bump major (X.0.0)", value: "major" },
|
|
132
|
+
],
|
|
133
|
+
});
|
|
134
|
+
if (choice === "current") {
|
|
135
|
+
keepCurrent = true;
|
|
136
|
+
} else {
|
|
137
|
+
bumpType = choice;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
107
140
|
}
|
|
108
141
|
|
|
109
142
|
let doPush = false;
|
|
@@ -123,18 +156,56 @@ export async function run(args: ParsedArgs): Promise<void> {
|
|
|
123
156
|
doPush = false;
|
|
124
157
|
}
|
|
125
158
|
|
|
126
|
-
|
|
159
|
+
let oldVersion: string;
|
|
160
|
+
let newVersion: string;
|
|
161
|
+
let roots: string[];
|
|
162
|
+
|
|
163
|
+
if (keepCurrent) {
|
|
164
|
+
roots = sortedPackageRoots(repoRoot);
|
|
165
|
+
if (roots.length === 0) {
|
|
166
|
+
console.error(
|
|
167
|
+
`gflows release: no package.json found under ${repoRoot}. Run from project root or use -C <dir>.`,
|
|
168
|
+
);
|
|
169
|
+
process.exit(EXIT_USER);
|
|
170
|
+
}
|
|
171
|
+
const primaryRoot = roots[0];
|
|
172
|
+
if (primaryRoot === undefined) {
|
|
173
|
+
console.error(
|
|
174
|
+
`gflows release: no package.json found under ${repoRoot}. Run from project root or use -C <dir>.`,
|
|
175
|
+
);
|
|
176
|
+
process.exit(EXIT_USER);
|
|
177
|
+
}
|
|
178
|
+
oldVersion = readPackageVersion(primaryRoot).raw;
|
|
179
|
+
newVersion = oldVersion;
|
|
180
|
+
} else {
|
|
181
|
+
if (!bumpType) {
|
|
182
|
+
console.error(
|
|
183
|
+
"gflows release: expected 'up <patch|minor|major>' or 'current'. Example: gflows release up patch",
|
|
184
|
+
);
|
|
185
|
+
process.exit(EXIT_USER);
|
|
186
|
+
}
|
|
187
|
+
({ oldVersion, newVersion, roots } = computeBump(repoRoot, "up", bumpType));
|
|
188
|
+
}
|
|
189
|
+
|
|
127
190
|
const tagName = normalizeTagVersion(newVersion);
|
|
128
191
|
|
|
129
192
|
if (await tagExists(repoRoot, tagName, opts)) {
|
|
130
193
|
console.error(`gflows release: tag '${tagName}' already exists.`);
|
|
131
|
-
hint(
|
|
194
|
+
hint(
|
|
195
|
+
keepCurrent
|
|
196
|
+
? "Bump the version first, or delete the tag if you intend to recreate it."
|
|
197
|
+
: "Use a different bump (minor/major), or delete the tag if you intend to recreate it.",
|
|
198
|
+
);
|
|
132
199
|
process.exit(2);
|
|
133
200
|
}
|
|
134
201
|
|
|
135
202
|
console.error("gflows release plan:");
|
|
136
203
|
console.error(` from: ${config.dev}`);
|
|
137
|
-
|
|
204
|
+
if (keepCurrent) {
|
|
205
|
+
console.error(` version: ${newVersion} (keep current, no bump)`);
|
|
206
|
+
} else {
|
|
207
|
+
console.error(` bump: ${oldVersion} → ${newVersion}`);
|
|
208
|
+
}
|
|
138
209
|
console.error(` merge: → ${config.main}, then ${config.main} → ${config.dev}`);
|
|
139
210
|
console.error(` tag: ${tagName}`);
|
|
140
211
|
console.error(` push: ${doPush ? "yes" : "no"}`);
|
|
@@ -159,7 +230,7 @@ export async function run(args: ParsedArgs): Promise<void> {
|
|
|
159
230
|
process.exit(EXIT_USER);
|
|
160
231
|
}
|
|
161
232
|
|
|
162
|
-
if (!opts.dryRun) {
|
|
233
|
+
if (!keepCurrent && !opts.dryRun) {
|
|
163
234
|
applyVersionToPackages(repoRoot, roots, newVersion);
|
|
164
235
|
for (const dir of roots) {
|
|
165
236
|
await runGit(["add", "--", join(dir, PACKAGE_JSON)], {
|
package/src/commands/schema.ts
CHANGED
|
@@ -57,7 +57,7 @@ export async function run(_args: ParsedArgs): Promise<void> {
|
|
|
57
57
|
"-m/--message",
|
|
58
58
|
],
|
|
59
59
|
release: [
|
|
60
|
-
"up patch|minor|major",
|
|
60
|
+
"up patch|minor|major | current",
|
|
61
61
|
"-y",
|
|
62
62
|
"-p/--push",
|
|
63
63
|
"-P/--no-push",
|
|
@@ -74,7 +74,7 @@ export async function run(_args: ParsedArgs): Promise<void> {
|
|
|
74
74
|
agentNotes: [
|
|
75
75
|
"Always pass explicit flags in non-TTY (never assume interactive hub).",
|
|
76
76
|
"Prefer -y to accept finish plan (delete defaults on); pass -P or -p for push.",
|
|
77
|
-
"Quick release from dev: gflows release up patch -y -p (or -P).",
|
|
77
|
+
"Quick release from dev: gflows release up patch -y -p (or -P); or gflows release current -y -p after a manual bump.",
|
|
78
78
|
"On conflict: gflows continue | gflows abort | gflows undo.",
|
|
79
79
|
"Use gflows schema and AGENTS.md as source of truth.",
|
|
80
80
|
],
|
|
@@ -87,7 +87,10 @@ function commandMeta(command: string): { summary: string; interactiveOk: boolean
|
|
|
87
87
|
init: { summary: "Ensure main; create dev", interactiveOk: true },
|
|
88
88
|
start: { summary: "Create workflow branch", interactiveOk: true },
|
|
89
89
|
finish: { summary: "Merge and close workflow branch", interactiveOk: true },
|
|
90
|
-
release: {
|
|
90
|
+
release: {
|
|
91
|
+
summary: "Quick release from dev (bump or keep version, merge main, tag)",
|
|
92
|
+
interactiveOk: true,
|
|
93
|
+
},
|
|
91
94
|
switch: { summary: "Switch workflow branch", interactiveOk: true },
|
|
92
95
|
delete: { summary: "Delete local workflow branches", interactiveOk: true },
|
|
93
96
|
list: { summary: "List workflow branches", interactiveOk: false },
|
package/src/interactive.ts
CHANGED
|
@@ -127,16 +127,21 @@ async function runHubAction(cwd: string, action: string): Promise<void> {
|
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
129
129
|
if (action === "release") {
|
|
130
|
-
const
|
|
131
|
-
message: "
|
|
130
|
+
const choice = await selectPrompt<"current" | "patch" | "minor" | "major">({
|
|
131
|
+
message: "Version for release",
|
|
132
132
|
options: [
|
|
133
|
-
{ label: "
|
|
134
|
-
{ label: "
|
|
135
|
-
{ label: "
|
|
133
|
+
{ label: "keep current", value: "current" },
|
|
134
|
+
{ label: "bump patch (x.y.Z)", value: "patch" },
|
|
135
|
+
{ label: "bump minor (x.Y.0)", value: "minor" },
|
|
136
|
+
{ label: "bump major (X.0.0)", value: "major" },
|
|
136
137
|
],
|
|
137
138
|
});
|
|
138
139
|
const push = await confirmPrompt({ message: "Push after release?", initialValue: false });
|
|
139
|
-
|
|
140
|
+
const releaseArgv =
|
|
141
|
+
choice === "current"
|
|
142
|
+
? (["release", "current", "-y", push ? "-p" : "-P"] as string[])
|
|
143
|
+
: (["release", "up", choice, "-y", push ? "-p" : "-P"] as string[]);
|
|
144
|
+
await dispatch(cwd, releaseArgv);
|
|
140
145
|
return;
|
|
141
146
|
}
|
|
142
147
|
if (action === "sync") {
|
package/src/parse.ts
CHANGED
|
@@ -236,7 +236,9 @@ function resolveName(
|
|
|
236
236
|
}
|
|
237
237
|
if (command === "bump" || command === "release") {
|
|
238
238
|
const dir = positionals[skip];
|
|
239
|
-
if (dir === "up" || dir === "down"
|
|
239
|
+
if (dir === "up" || dir === "down" || (command === "release" && dir === "current")) {
|
|
240
|
+
return dir;
|
|
241
|
+
}
|
|
240
242
|
return undefined;
|
|
241
243
|
}
|
|
242
244
|
if (command === "switch" || command === "pr" || command === "sync") {
|
|
@@ -248,11 +250,15 @@ function resolveName(
|
|
|
248
250
|
function resolveBump(positionals: string[]): {
|
|
249
251
|
direction?: "up" | "down";
|
|
250
252
|
type?: "patch" | "minor" | "major";
|
|
253
|
+
keepCurrent?: boolean;
|
|
251
254
|
} {
|
|
252
255
|
// Skip leading command when present; with -U, positionals start at up/down
|
|
253
256
|
const skip = positionals[0] === "bump" || positionals[0] === "release" ? 1 : 0;
|
|
254
257
|
const a = positionals[skip];
|
|
255
258
|
const b = positionals[skip + 1];
|
|
259
|
+
if (positionals[0] === "release" && a === "current") {
|
|
260
|
+
return { keepCurrent: true };
|
|
261
|
+
}
|
|
256
262
|
const direction = a === "up" || a === "down" ? a : undefined;
|
|
257
263
|
const type = b === "patch" || b === "minor" || b === "major" ? b : undefined;
|
|
258
264
|
return { direction, type };
|
|
@@ -297,6 +303,7 @@ function emptyArgs(cwd: string, pathStr: string | undefined): ParsedArgs {
|
|
|
297
303
|
squash: false,
|
|
298
304
|
preview: false,
|
|
299
305
|
bumpOnFinish: false,
|
|
306
|
+
keepCurrent: false,
|
|
300
307
|
includeRemote: false,
|
|
301
308
|
json: false,
|
|
302
309
|
rebase: false,
|
|
@@ -336,10 +343,13 @@ export function parse(
|
|
|
336
343
|
|
|
337
344
|
const type = resolveType(command, positionals, v);
|
|
338
345
|
const name = resolveName(command, positionals, v);
|
|
339
|
-
const
|
|
346
|
+
const bumpResolved =
|
|
340
347
|
command === "bump" || command === "release"
|
|
341
348
|
? resolveBump(positionals)
|
|
342
|
-
: { direction: undefined, type: undefined };
|
|
349
|
+
: { direction: undefined, type: undefined, keepCurrent: undefined };
|
|
350
|
+
const bumpDirection = bumpResolved.direction;
|
|
351
|
+
const bumpType = bumpResolved.type;
|
|
352
|
+
const keepCurrent = bumpResolved.keepCurrent === true;
|
|
343
353
|
const configArgs = command === "config" ? resolveConfigArgs(positionals) : {};
|
|
344
354
|
|
|
345
355
|
const branchNames =
|
|
@@ -395,6 +405,7 @@ export function parse(
|
|
|
395
405
|
branchNames,
|
|
396
406
|
bumpDirection,
|
|
397
407
|
bumpType,
|
|
408
|
+
keepCurrent,
|
|
398
409
|
configAction: configArgs.action,
|
|
399
410
|
configKey: configArgs.key,
|
|
400
411
|
configValue: configArgs.value,
|
package/src/tui/flows.tsx
CHANGED
|
@@ -135,21 +135,22 @@ export function ReleaseFlow({
|
|
|
135
135
|
onCancel: () => void;
|
|
136
136
|
}): React.ReactElement {
|
|
137
137
|
const [step, setStep] = useState<"type" | "push">("type");
|
|
138
|
-
const [
|
|
138
|
+
const [choice, setChoice] = useState<"current" | "patch" | "minor" | "major">("current");
|
|
139
139
|
|
|
140
140
|
if (step === "type") {
|
|
141
141
|
return (
|
|
142
142
|
<WizardFrame title="Quick release from dev">
|
|
143
|
-
<InkSelect<"patch" | "minor" | "major">
|
|
144
|
-
message="
|
|
143
|
+
<InkSelect<"current" | "patch" | "minor" | "major">
|
|
144
|
+
message="Version for release"
|
|
145
145
|
options={[
|
|
146
|
-
{ value: "
|
|
147
|
-
{ value: "
|
|
148
|
-
{ value: "
|
|
146
|
+
{ value: "current", label: "keep current" },
|
|
147
|
+
{ value: "patch", label: "bump patch (x.y.Z)" },
|
|
148
|
+
{ value: "minor", label: "bump minor (x.Y.0)" },
|
|
149
|
+
{ value: "major", label: "bump major (X.0.0)" },
|
|
149
150
|
]}
|
|
150
151
|
onCancel={onCancel}
|
|
151
152
|
onSubmit={(t) => {
|
|
152
|
-
|
|
153
|
+
setChoice(t);
|
|
153
154
|
setStep("push");
|
|
154
155
|
}}
|
|
155
156
|
/>
|
|
@@ -157,14 +158,20 @@ export function ReleaseFlow({
|
|
|
157
158
|
);
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
const title = choice === "current" ? "Release · keep current" : `Release · up ${choice}`;
|
|
162
|
+
|
|
160
163
|
return (
|
|
161
|
-
<WizardFrame title={
|
|
164
|
+
<WizardFrame title={title}>
|
|
162
165
|
<InkConfirm
|
|
163
166
|
message="Push after release?"
|
|
164
167
|
initialValue={false}
|
|
165
168
|
onCancel={onCancel}
|
|
166
169
|
onSubmit={(push) => {
|
|
167
|
-
onDone(
|
|
170
|
+
onDone(
|
|
171
|
+
choice === "current"
|
|
172
|
+
? ["release", "current", "-y", push ? "-p" : "-P"]
|
|
173
|
+
: ["release", "up", choice, "-y", push ? "-p" : "-P"],
|
|
174
|
+
);
|
|
168
175
|
}}
|
|
169
176
|
/>
|
|
170
177
|
</WizardFrame>
|
package/src/types.ts
CHANGED
|
@@ -134,6 +134,11 @@ export interface ParsedArgs {
|
|
|
134
134
|
bumpDirection?: BumpDirection;
|
|
135
135
|
/** Bump type (patch | minor | major). */
|
|
136
136
|
bumpType?: BumpType;
|
|
137
|
+
/**
|
|
138
|
+
* Quick release: tag the package version already on disk (no bump commit).
|
|
139
|
+
* From `gflows release current`.
|
|
140
|
+
*/
|
|
141
|
+
keepCurrent?: boolean;
|
|
137
142
|
/** Config get/set action. */
|
|
138
143
|
configAction?: ConfigAction;
|
|
139
144
|
/** Config key (main, dev, remote, or prefixes.<type>). */
|