@alejandrochaves/devflow-cli 1.3.2 → 1.4.0
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/dist/commands/amend.d.ts.map +1 -1
- package/dist/commands/amend.js +139 -68
- package/dist/commands/amend.js.map +1 -1
- package/dist/commands/branch.d.ts.map +1 -1
- package/dist/commands/branch.js +201 -80
- package/dist/commands/branch.js.map +1 -1
- package/dist/commands/changelog.d.ts.map +1 -1
- package/dist/commands/changelog.js +62 -32
- package/dist/commands/changelog.js.map +1 -1
- package/dist/commands/cleanup.d.ts.map +1 -1
- package/dist/commands/cleanup.js +10 -3
- package/dist/commands/cleanup.js.map +1 -1
- package/dist/commands/commit.d.ts.map +1 -1
- package/dist/commands/commit.js +343 -175
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/fixup.d.ts.map +1 -1
- package/dist/commands/fixup.js +129 -81
- package/dist/commands/fixup.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +223 -110
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/issue.d.ts.map +1 -1
- package/dist/commands/issue.js +341 -83
- package/dist/commands/issue.js.map +1 -1
- package/dist/commands/issues.d.ts.map +1 -1
- package/dist/commands/issues.js +166 -77
- package/dist/commands/issues.js.map +1 -1
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +81 -46
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/merge.d.ts.map +1 -1
- package/dist/commands/merge.js +78 -38
- package/dist/commands/merge.js.map +1 -1
- package/dist/commands/pr.d.ts.map +1 -1
- package/dist/commands/pr.js +110 -42
- package/dist/commands/pr.js.map +1 -1
- package/dist/commands/release.d.ts.map +1 -1
- package/dist/commands/release.js +70 -37
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +144 -84
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/stash.d.ts.map +1 -1
- package/dist/commands/stash.js +164 -94
- package/dist/commands/stash.js.map +1 -1
- package/dist/commands/test-plan.d.ts.map +1 -1
- package/dist/commands/test-plan.js +86 -42
- package/dist/commands/test-plan.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +9 -3
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/worktree.d.ts.map +1 -1
- package/dist/commands/worktree.js +168 -96
- package/dist/commands/worktree.js.map +1 -1
- package/dist/prompts.d.ts +62 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +130 -0
- package/dist/prompts.js.map +1 -0
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amend.d.ts","sourceRoot":"","sources":["../../src/commands/amend.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"amend.d.ts","sourceRoot":"","sources":["../../src/commands/amend.ts"],"names":[],"mappings":"AA6CA,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AASD,wBAAsB,YAAY,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0O5E"}
|
package/dist/commands/amend.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { confirm
|
|
1
|
+
import { confirm } from "@inquirer/prompts";
|
|
2
2
|
import { execSync } from "child_process";
|
|
3
3
|
import { loadConfig } from "../config.js";
|
|
4
4
|
import { inferTicket } from "../git.js";
|
|
5
5
|
import { bold, dim, green, yellow, cyan } from "../colors.js";
|
|
6
|
+
import { selectWithBack, inputWithBack, confirmWithBack, searchWithBack, BACK_VALUE } from "../prompts.js";
|
|
6
7
|
function getLastCommitMessage() {
|
|
7
8
|
return execSync("git log -1 --format=%s", { encoding: "utf-8" }).trim();
|
|
8
9
|
}
|
|
@@ -51,78 +52,140 @@ export async function amendCommand(options = {}) {
|
|
|
51
52
|
}
|
|
52
53
|
let newMessage = lastMessage;
|
|
53
54
|
if (editMessage) {
|
|
54
|
-
//
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
let
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const filtered = config.scopes.filter((s) => !term ||
|
|
72
|
-
s.value.includes(term.toLowerCase()) ||
|
|
73
|
-
s.description.toLowerCase().includes(term.toLowerCase()));
|
|
74
|
-
if (parsed.scope) {
|
|
75
|
-
filtered.sort((a, b) => a.value === parsed.scope ? -1 : b.value === parsed.scope ? 1 : 0);
|
|
55
|
+
// Initialize state from parsed message
|
|
56
|
+
const state = {
|
|
57
|
+
type: options.type || parsed.type || "",
|
|
58
|
+
scope: options.scope ?? parsed.scope ?? "",
|
|
59
|
+
message: options.message || parsed.message || "",
|
|
60
|
+
isBreaking: options.breaking ?? parsed.breaking,
|
|
61
|
+
};
|
|
62
|
+
let currentStep = "type";
|
|
63
|
+
// Skip steps that have flags
|
|
64
|
+
if (options.type)
|
|
65
|
+
currentStep = "scope";
|
|
66
|
+
while (currentStep !== undefined) {
|
|
67
|
+
switch (currentStep) {
|
|
68
|
+
case "type": {
|
|
69
|
+
if (options.type) {
|
|
70
|
+
currentStep = "scope";
|
|
71
|
+
break;
|
|
76
72
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
73
|
+
const result = await selectWithBack({
|
|
74
|
+
message: "Select commit type:",
|
|
75
|
+
choices: config.commitTypes.map((t) => ({ value: t.value, name: t.label })),
|
|
76
|
+
default: state.type,
|
|
77
|
+
showBack: false, // First step
|
|
78
|
+
});
|
|
79
|
+
if (result === BACK_VALUE) {
|
|
80
|
+
// Can't go back from first step
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
state.type = result;
|
|
84
|
+
currentStep = "scope";
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case "scope": {
|
|
89
|
+
if (options.scope !== undefined) {
|
|
90
|
+
currentStep = "message";
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
if (config.scopes.length > 0) {
|
|
94
|
+
const result = await searchWithBack({
|
|
95
|
+
message: parsed.scope
|
|
96
|
+
? `Select scope (current: ${cyan(parsed.scope)}):`
|
|
97
|
+
: "Select scope (type to filter):",
|
|
98
|
+
source: (term) => {
|
|
99
|
+
const filtered = config.scopes.filter((s) => !term ||
|
|
100
|
+
s.value.includes(term.toLowerCase()) ||
|
|
101
|
+
s.description.toLowerCase().includes(term.toLowerCase()));
|
|
102
|
+
if (parsed.scope) {
|
|
103
|
+
filtered.sort((a, b) => a.value === parsed.scope ? -1 : b.value === parsed.scope ? 1 : 0);
|
|
104
|
+
}
|
|
105
|
+
return filtered.map((s) => ({
|
|
106
|
+
value: s.value,
|
|
107
|
+
name: `${s.value} — ${s.description}`,
|
|
108
|
+
}));
|
|
109
|
+
},
|
|
110
|
+
showBack: !options.type,
|
|
111
|
+
});
|
|
112
|
+
if (result === BACK_VALUE) {
|
|
113
|
+
currentStep = "type";
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
state.scope = result;
|
|
117
|
+
currentStep = "message";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const result = await inputWithBack({
|
|
122
|
+
message: "Enter scope (optional):",
|
|
123
|
+
default: state.scope,
|
|
124
|
+
showBack: !options.type,
|
|
125
|
+
});
|
|
126
|
+
if (result === BACK_VALUE) {
|
|
127
|
+
currentStep = "type";
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
state.scope = result;
|
|
131
|
+
currentStep = "message";
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "message": {
|
|
137
|
+
if (options.message) {
|
|
138
|
+
currentStep = "breaking";
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
const result = await inputWithBack({
|
|
142
|
+
message: "Enter commit message:",
|
|
143
|
+
default: state.message,
|
|
144
|
+
validate: (val) => val.trim().length > 0 || "Commit message is required",
|
|
145
|
+
showBack: true,
|
|
146
|
+
});
|
|
147
|
+
if (result === BACK_VALUE) {
|
|
148
|
+
currentStep = options.scope !== undefined ? "type" : "scope";
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
state.message = result;
|
|
152
|
+
currentStep = "breaking";
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case "breaking": {
|
|
157
|
+
if (options.breaking !== undefined || options.yes) {
|
|
158
|
+
currentStep = undefined;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
const result = await confirmWithBack({
|
|
162
|
+
message: "Is this a breaking change?",
|
|
163
|
+
default: state.isBreaking,
|
|
164
|
+
showBack: true,
|
|
165
|
+
});
|
|
166
|
+
if (result === BACK_VALUE) {
|
|
167
|
+
currentStep = options.message ? "scope" : "message";
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
state.isBreaking = result;
|
|
171
|
+
currentStep = undefined;
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
default:
|
|
176
|
+
currentStep = undefined;
|
|
177
|
+
}
|
|
115
178
|
}
|
|
116
179
|
const ticket = parsed.ticket || inferTicket();
|
|
117
|
-
const breaking = isBreaking ? "!" : "";
|
|
118
|
-
const scope =
|
|
180
|
+
const breaking = state.isBreaking ? "!" : "";
|
|
181
|
+
const scope = state.scope || "";
|
|
119
182
|
// Build using format
|
|
120
183
|
let result = config.commitFormat;
|
|
121
|
-
result = result.replace("{type}", type);
|
|
184
|
+
result = result.replace("{type}", state.type);
|
|
122
185
|
result = result.replace("{ticket}", ticket);
|
|
123
186
|
result = result.replace("{breaking}", breaking);
|
|
124
187
|
result = result.replace("{scope}", scope);
|
|
125
|
-
result = result.replace("{message}", message.trim());
|
|
188
|
+
result = result.replace("{message}", state.message.trim());
|
|
126
189
|
result = result.replace(/\[\]/g, "");
|
|
127
190
|
result = result.replace(/\(\)/g, "");
|
|
128
191
|
newMessage = result;
|
|
@@ -146,11 +209,19 @@ export async function amendCommand(options = {}) {
|
|
|
146
209
|
}
|
|
147
210
|
// Confirm (skip if --yes)
|
|
148
211
|
if (!options.yes) {
|
|
149
|
-
const
|
|
212
|
+
const confirmResult = await selectWithBack({
|
|
150
213
|
message: "Amend this commit?",
|
|
151
|
-
|
|
214
|
+
choices: [
|
|
215
|
+
{ value: "yes", name: "Yes, amend commit" },
|
|
216
|
+
{ value: "no", name: "No, abort" },
|
|
217
|
+
],
|
|
218
|
+
default: "yes",
|
|
219
|
+
showBack: true,
|
|
152
220
|
});
|
|
153
|
-
if (
|
|
221
|
+
if (confirmResult === BACK_VALUE) {
|
|
222
|
+
return amendCommand(options);
|
|
223
|
+
}
|
|
224
|
+
if (confirmResult !== "yes") {
|
|
154
225
|
console.log("Aborted.");
|
|
155
226
|
process.exit(0);
|
|
156
227
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amend.js","sourceRoot":"","sources":["../../src/commands/amend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"amend.js","sourceRoot":"","sources":["../../src/commands/amend.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"AAQA,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3E,MAAM,CAaR;AAkBD,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAWD,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2S9E"}
|
package/dist/commands/branch.js
CHANGED
|
@@ -4,6 +4,7 @@ import { loadConfig } from "../config.js";
|
|
|
4
4
|
import { bold, dim, green, cyan, gray } from "../colors.js";
|
|
5
5
|
import { setTestPlan } from "../test-plan.js";
|
|
6
6
|
import { createTicketProvider, inferBranchTypeFromLabels } from "../providers/tickets.js";
|
|
7
|
+
import { selectWithBack, inputWithBack, BACK_VALUE } from "../prompts.js";
|
|
7
8
|
export function formatBranchName(format, vars) {
|
|
8
9
|
let result = format;
|
|
9
10
|
result = result.replace("{type}", vars.type);
|
|
@@ -37,95 +38,173 @@ export async function branchCommand(options = {}) {
|
|
|
37
38
|
const config = loadConfig();
|
|
38
39
|
const branchFormat = config.branchFormat;
|
|
39
40
|
const needsTicket = branchFormat.includes("{ticket}");
|
|
40
|
-
// Check if ticket provider is configured
|
|
41
41
|
const ticketProvider = createTicketProvider(config.ticketProvider);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
// Initialize state
|
|
43
|
+
const state = {
|
|
44
|
+
ticket: options.ticket?.trim() || "",
|
|
45
|
+
type: options.type || "",
|
|
46
|
+
description: options.description || "",
|
|
47
|
+
};
|
|
48
|
+
// Determine starting step
|
|
49
|
+
let currentStep = "ticketMethod";
|
|
47
50
|
if (options.ticket !== undefined) {
|
|
48
|
-
ticket = options.ticket.trim() || "UNTRACKED";
|
|
51
|
+
state.ticket = options.ticket.trim() || "UNTRACKED";
|
|
52
|
+
currentStep = "type";
|
|
49
53
|
}
|
|
50
|
-
else if (ticketProvider
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
message: "How do you want to select the ticket?",
|
|
54
|
-
choices: [
|
|
55
|
-
{ value: "pick", name: "Pick from open issues (assigned to me)" },
|
|
56
|
-
{ value: "manual", name: "Enter manually" },
|
|
57
|
-
{ value: "skip", name: "Skip (UNTRACKED)" },
|
|
58
|
-
],
|
|
59
|
-
});
|
|
60
|
-
if (ticketMethod === "pick") {
|
|
61
|
-
const issues = ticketProvider.listOpen({ assignee: "@me" });
|
|
62
|
-
if (issues.length === 0) {
|
|
63
|
-
console.log(dim("No open issues assigned to you. Falling back to manual input."));
|
|
64
|
-
ticket = await input({
|
|
65
|
-
message: "Ticket number (leave blank for UNTRACKED):",
|
|
66
|
-
});
|
|
67
|
-
ticket = ticket.trim() || "UNTRACKED";
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
selectedIssue = await select({
|
|
71
|
-
message: "Select an issue:",
|
|
72
|
-
choices: issues.map(formatIssueChoice),
|
|
73
|
-
});
|
|
74
|
-
ticket = selectedIssue.id;
|
|
75
|
-
inferredType = inferBranchTypeFromLabels(selectedIssue.labels);
|
|
76
|
-
suggestedDescription = toKebabCase(selectedIssue.title);
|
|
77
|
-
if (inferredType) {
|
|
78
|
-
console.log(dim(` Inferred type from labels: ${cyan(inferredType)}`));
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else if (ticketMethod === "manual") {
|
|
83
|
-
ticket = await input({
|
|
84
|
-
message: "Ticket number (leave blank for UNTRACKED):",
|
|
85
|
-
});
|
|
86
|
-
ticket = ticket.trim() || "UNTRACKED";
|
|
54
|
+
else if (!ticketProvider || !needsTicket) {
|
|
55
|
+
if (needsTicket) {
|
|
56
|
+
currentStep = "ticketInput";
|
|
87
57
|
}
|
|
88
58
|
else {
|
|
89
|
-
|
|
59
|
+
currentStep = "type";
|
|
90
60
|
}
|
|
91
61
|
}
|
|
92
|
-
else if (needsTicket) {
|
|
93
|
-
// No provider, use manual input
|
|
94
|
-
ticket = await input({
|
|
95
|
-
message: "Ticket number (leave blank for UNTRACKED):",
|
|
96
|
-
});
|
|
97
|
-
ticket = ticket.trim() || "UNTRACKED";
|
|
98
|
-
}
|
|
99
|
-
// Get type from flag or prompt
|
|
100
|
-
let type;
|
|
101
62
|
if (options.type) {
|
|
102
|
-
type = options.type;
|
|
63
|
+
state.type = options.type;
|
|
64
|
+
if (currentStep === "type")
|
|
65
|
+
currentStep = "description";
|
|
103
66
|
}
|
|
104
|
-
else {
|
|
105
|
-
const typeChoices = config.branchTypes.map((t) => ({ value: t, name: t }));
|
|
106
|
-
const defaultType = inferredType && config.branchTypes.includes(inferredType) ? inferredType : undefined;
|
|
107
|
-
type = await select({
|
|
108
|
-
message: "Select branch type:",
|
|
109
|
-
choices: typeChoices,
|
|
110
|
-
default: defaultType,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
// Get description from flag or prompt
|
|
114
|
-
let description;
|
|
115
67
|
if (options.description) {
|
|
116
|
-
description = options.description;
|
|
68
|
+
state.description = options.description;
|
|
69
|
+
}
|
|
70
|
+
// Skip interactive flow if all options provided
|
|
71
|
+
if (options.ticket !== undefined && options.type && options.description) {
|
|
72
|
+
state.ticket = options.ticket.trim() || "UNTRACKED";
|
|
73
|
+
// Skip to branch creation
|
|
117
74
|
}
|
|
118
75
|
else {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
76
|
+
// Interactive step flow
|
|
77
|
+
while (currentStep !== undefined) {
|
|
78
|
+
switch (currentStep) {
|
|
79
|
+
case "ticketMethod": {
|
|
80
|
+
const result = await selectWithBack({
|
|
81
|
+
message: "How do you want to select the ticket?",
|
|
82
|
+
choices: [
|
|
83
|
+
{ value: "pick", name: "Pick from open issues (assigned to me)" },
|
|
84
|
+
{ value: "manual", name: "Enter manually" },
|
|
85
|
+
{ value: "skip", name: "Skip (UNTRACKED)" },
|
|
86
|
+
],
|
|
87
|
+
showBack: false, // First step, no back
|
|
88
|
+
});
|
|
89
|
+
if (result === "pick") {
|
|
90
|
+
currentStep = "ticketPick";
|
|
91
|
+
}
|
|
92
|
+
else if (result === "manual") {
|
|
93
|
+
currentStep = "ticketInput";
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
state.ticket = "UNTRACKED";
|
|
97
|
+
currentStep = "type";
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case "ticketInput": {
|
|
102
|
+
const showBack = ticketProvider && needsTicket;
|
|
103
|
+
const result = await inputWithBack({
|
|
104
|
+
message: "Ticket number (leave blank for UNTRACKED):",
|
|
105
|
+
default: state.ticket !== "UNTRACKED" ? state.ticket : undefined,
|
|
106
|
+
showBack,
|
|
107
|
+
});
|
|
108
|
+
if (result === BACK_VALUE) {
|
|
109
|
+
currentStep = "ticketMethod";
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
state.ticket = result.trim() || "UNTRACKED";
|
|
113
|
+
currentStep = options.type ? "description" : "type";
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case "ticketPick": {
|
|
118
|
+
if (!ticketProvider) {
|
|
119
|
+
currentStep = "ticketInput";
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
const issues = ticketProvider.listOpen({ assignee: "@me" });
|
|
123
|
+
if (issues.length === 0) {
|
|
124
|
+
console.log(dim("No open issues assigned to you. Falling back to manual input."));
|
|
125
|
+
currentStep = "ticketInput";
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
const result = await selectWithBack({
|
|
129
|
+
message: "Select an issue:",
|
|
130
|
+
choices: issues.map(formatIssueChoice),
|
|
131
|
+
showBack: true,
|
|
132
|
+
});
|
|
133
|
+
if (result === BACK_VALUE) {
|
|
134
|
+
currentStep = "ticketMethod";
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
state.selectedIssue = result;
|
|
138
|
+
state.ticket = state.selectedIssue.id;
|
|
139
|
+
state.inferredType = inferBranchTypeFromLabels(state.selectedIssue.labels);
|
|
140
|
+
state.suggestedDescription = toKebabCase(state.selectedIssue.title);
|
|
141
|
+
if (state.inferredType) {
|
|
142
|
+
console.log(dim(` Inferred type from labels: ${cyan(state.inferredType)}`));
|
|
143
|
+
}
|
|
144
|
+
currentStep = options.type ? "description" : "type";
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case "type": {
|
|
149
|
+
if (options.type) {
|
|
150
|
+
currentStep = "description";
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
const typeChoices = config.branchTypes.map((t) => ({ value: t, name: t }));
|
|
154
|
+
const defaultType = state.inferredType && config.branchTypes.includes(state.inferredType)
|
|
155
|
+
? state.inferredType
|
|
156
|
+
: state.type || undefined;
|
|
157
|
+
// Determine if we can go back
|
|
158
|
+
const canGoBack = needsTicket && !options.ticket;
|
|
159
|
+
const result = await selectWithBack({
|
|
160
|
+
message: "Select branch type:",
|
|
161
|
+
choices: typeChoices,
|
|
162
|
+
default: defaultType,
|
|
163
|
+
showBack: canGoBack,
|
|
164
|
+
});
|
|
165
|
+
if (result === BACK_VALUE) {
|
|
166
|
+
if (ticketProvider && needsTicket) {
|
|
167
|
+
currentStep = state.selectedIssue ? "ticketPick" : "ticketMethod";
|
|
168
|
+
}
|
|
169
|
+
else if (needsTicket) {
|
|
170
|
+
currentStep = "ticketInput";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
state.type = result;
|
|
175
|
+
currentStep = "description";
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case "description": {
|
|
180
|
+
if (options.description) {
|
|
181
|
+
currentStep = undefined;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
const result = await inputWithBack({
|
|
185
|
+
message: "Short description:",
|
|
186
|
+
default: state.suggestedDescription || state.description || undefined,
|
|
187
|
+
validate: (val) => val.trim().length > 0 || "Description is required",
|
|
188
|
+
showBack: true,
|
|
189
|
+
});
|
|
190
|
+
if (result === BACK_VALUE) {
|
|
191
|
+
currentStep = options.type ? (needsTicket ? "ticketMethod" : "type") : "type";
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
state.description = result;
|
|
195
|
+
currentStep = undefined;
|
|
196
|
+
}
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
default:
|
|
200
|
+
currentStep = undefined;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
124
203
|
}
|
|
125
|
-
const kebab = toKebabCase(description);
|
|
204
|
+
const kebab = toKebabCase(state.description);
|
|
126
205
|
const branchName = formatBranchName(branchFormat, {
|
|
127
|
-
type,
|
|
128
|
-
ticket,
|
|
206
|
+
type: state.type,
|
|
207
|
+
ticket: state.ticket,
|
|
129
208
|
description: kebab,
|
|
130
209
|
});
|
|
131
210
|
console.log(`\n${dim("───")} ${bold("Branch Preview")} ${dim("───")}`);
|
|
@@ -137,17 +216,59 @@ export async function branchCommand(options = {}) {
|
|
|
137
216
|
}
|
|
138
217
|
// Confirm (skip if --yes)
|
|
139
218
|
if (!options.yes) {
|
|
140
|
-
const
|
|
219
|
+
const confirmResult = await selectWithBack({
|
|
141
220
|
message: "Create this branch?",
|
|
142
|
-
|
|
221
|
+
choices: [
|
|
222
|
+
{ value: "yes", name: "Yes, create branch" },
|
|
223
|
+
{ value: "no", name: "No, abort" },
|
|
224
|
+
],
|
|
225
|
+
default: "yes",
|
|
226
|
+
showBack: true,
|
|
227
|
+
});
|
|
228
|
+
if (confirmResult === BACK_VALUE) {
|
|
229
|
+
// Restart the flow
|
|
230
|
+
return branchCommand(options);
|
|
231
|
+
}
|
|
232
|
+
if (confirmResult !== "yes") {
|
|
233
|
+
console.log("Aborted.");
|
|
234
|
+
process.exit(0);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Check if branch already exists
|
|
238
|
+
let branchExists = false;
|
|
239
|
+
try {
|
|
240
|
+
execSync(`git rev-parse --verify ${branchName}`, { stdio: "pipe" });
|
|
241
|
+
branchExists = true;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
branchExists = false;
|
|
245
|
+
}
|
|
246
|
+
if (branchExists) {
|
|
247
|
+
const action = await select({
|
|
248
|
+
message: `Branch "${branchName}" already exists. What do you want to do?`,
|
|
249
|
+
choices: [
|
|
250
|
+
{ value: "checkout", name: "Checkout the existing branch" },
|
|
251
|
+
{ value: "new", name: "Create with a different name" },
|
|
252
|
+
{ value: "abort", name: "Abort" },
|
|
253
|
+
],
|
|
143
254
|
});
|
|
144
|
-
if (
|
|
255
|
+
if (action === "checkout") {
|
|
256
|
+
execSync(`git checkout ${branchName}`, { stdio: "inherit" });
|
|
257
|
+
console.log(green(`✓ Checked out existing branch: ${branchName}`));
|
|
258
|
+
}
|
|
259
|
+
else if (action === "new") {
|
|
260
|
+
console.log("Aborted. Please run devflow branch again with a different description.");
|
|
261
|
+
process.exit(0);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
145
264
|
console.log("Aborted.");
|
|
146
265
|
process.exit(0);
|
|
147
266
|
}
|
|
148
267
|
}
|
|
149
|
-
|
|
150
|
-
|
|
268
|
+
else {
|
|
269
|
+
execSync(`git checkout -b ${branchName}`, { stdio: "inherit" });
|
|
270
|
+
console.log(green(`✓ Branch created: ${branchName}`));
|
|
271
|
+
}
|
|
151
272
|
// Handle test plan from flag or prompt
|
|
152
273
|
if (options.testPlan) {
|
|
153
274
|
const steps = options.testPlan.split("|").map((s) => s.trim()).filter(Boolean);
|