@pruddiman/dispatch 1.3.0 → 1.3.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/dist/cli.js +99 -56
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1030,7 +1030,8 @@ function slugify(input3, maxLength) {
|
|
|
1030
1030
|
|
|
1031
1031
|
// src/datasources/github.ts
|
|
1032
1032
|
init_logger();
|
|
1033
|
-
|
|
1033
|
+
|
|
1034
|
+
// src/helpers/branch-validation.ts
|
|
1034
1035
|
var InvalidBranchNameError = class extends Error {
|
|
1035
1036
|
constructor(branch, reason) {
|
|
1036
1037
|
const detail = reason ? ` (${reason})` : "";
|
|
@@ -1038,14 +1039,6 @@ var InvalidBranchNameError = class extends Error {
|
|
|
1038
1039
|
this.name = "InvalidBranchNameError";
|
|
1039
1040
|
}
|
|
1040
1041
|
};
|
|
1041
|
-
async function git(args, cwd) {
|
|
1042
|
-
const { stdout } = await exec("git", args, { cwd });
|
|
1043
|
-
return stdout;
|
|
1044
|
-
}
|
|
1045
|
-
async function gh(args, cwd) {
|
|
1046
|
-
const { stdout } = await exec("gh", args, { cwd });
|
|
1047
|
-
return stdout;
|
|
1048
|
-
}
|
|
1049
1042
|
var VALID_BRANCH_NAME_RE = /^[a-zA-Z0-9._\-/]+$/;
|
|
1050
1043
|
function isValidBranchName(name) {
|
|
1051
1044
|
if (name.length === 0 || name.length > 255) return false;
|
|
@@ -1057,6 +1050,17 @@ function isValidBranchName(name) {
|
|
|
1057
1050
|
if (name.includes("//")) return false;
|
|
1058
1051
|
return true;
|
|
1059
1052
|
}
|
|
1053
|
+
|
|
1054
|
+
// src/datasources/github.ts
|
|
1055
|
+
var exec = promisify(execFile);
|
|
1056
|
+
async function git(args, cwd) {
|
|
1057
|
+
const { stdout } = await exec("git", args, { cwd });
|
|
1058
|
+
return stdout;
|
|
1059
|
+
}
|
|
1060
|
+
async function gh(args, cwd) {
|
|
1061
|
+
const { stdout } = await exec("gh", args, { cwd });
|
|
1062
|
+
return stdout;
|
|
1063
|
+
}
|
|
1060
1064
|
function buildBranchName(issueNumber, title, username = "unknown") {
|
|
1061
1065
|
const slug = slugify(title, 50);
|
|
1062
1066
|
return `${username}/dispatch/${issueNumber}-${slug}`;
|
|
@@ -1267,6 +1271,25 @@ import { execFile as execFile2 } from "child_process";
|
|
|
1267
1271
|
import { promisify as promisify2 } from "util";
|
|
1268
1272
|
init_logger();
|
|
1269
1273
|
var exec2 = promisify2(execFile2);
|
|
1274
|
+
function mapWorkItemToIssueDetails(item, id, comments, defaults) {
|
|
1275
|
+
const fields = item.fields ?? {};
|
|
1276
|
+
return {
|
|
1277
|
+
number: String(item.id ?? id),
|
|
1278
|
+
title: fields["System.Title"] ?? defaults?.title ?? "",
|
|
1279
|
+
body: fields["System.Description"] ?? defaults?.body ?? "",
|
|
1280
|
+
labels: (fields["System.Tags"] ?? "").split(";").map((t) => t.trim()).filter(Boolean),
|
|
1281
|
+
state: fields["System.State"] ?? defaults?.state ?? "",
|
|
1282
|
+
url: item._links?.html?.href ?? item.url ?? "",
|
|
1283
|
+
comments,
|
|
1284
|
+
acceptanceCriteria: fields["Microsoft.VSTS.Common.AcceptanceCriteria"] ?? "",
|
|
1285
|
+
iterationPath: fields["System.IterationPath"] || void 0,
|
|
1286
|
+
areaPath: fields["System.AreaPath"] || void 0,
|
|
1287
|
+
assignee: fields["System.AssignedTo"]?.displayName || void 0,
|
|
1288
|
+
priority: fields["Microsoft.VSTS.Common.Priority"] ?? void 0,
|
|
1289
|
+
storyPoints: fields["Microsoft.VSTS.Scheduling.StoryPoints"] ?? fields["Microsoft.VSTS.Scheduling.Effort"] ?? fields["Microsoft.VSTS.Scheduling.Size"] ?? void 0,
|
|
1290
|
+
workItemType: fields["System.WorkItemType"] || defaults?.workItemType || void 0
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1270
1293
|
async function detectWorkItemType(opts = {}) {
|
|
1271
1294
|
try {
|
|
1272
1295
|
const args = ["boards", "work-item", "type", "list", "--output", "json"];
|
|
@@ -1325,17 +1348,50 @@ var datasource2 = {
|
|
|
1325
1348
|
} catch {
|
|
1326
1349
|
throw new Error(`Failed to parse Azure CLI output: ${stdout.slice(0, 200)}`);
|
|
1327
1350
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1351
|
+
if (!Array.isArray(data)) return [];
|
|
1352
|
+
const ids = data.map((row) => String(row.id ?? row.ID ?? "")).filter(Boolean);
|
|
1353
|
+
if (ids.length === 0) return [];
|
|
1354
|
+
try {
|
|
1355
|
+
const batchArgs = [
|
|
1356
|
+
"boards",
|
|
1357
|
+
"work-item",
|
|
1358
|
+
"show",
|
|
1359
|
+
"--id",
|
|
1360
|
+
...ids,
|
|
1361
|
+
"--output",
|
|
1362
|
+
"json"
|
|
1363
|
+
];
|
|
1364
|
+
if (opts.org) batchArgs.push("--org", opts.org);
|
|
1365
|
+
if (opts.project) batchArgs.push("--project", opts.project);
|
|
1366
|
+
const { stdout: batchStdout } = await exec2("az", batchArgs, {
|
|
1367
|
+
cwd: opts.cwd || process.cwd()
|
|
1368
|
+
});
|
|
1369
|
+
let batchItems;
|
|
1370
|
+
try {
|
|
1371
|
+
batchItems = JSON.parse(batchStdout);
|
|
1372
|
+
} catch {
|
|
1373
|
+
throw new Error(`Failed to parse Azure CLI output: ${batchStdout.slice(0, 200)}`);
|
|
1336
1374
|
}
|
|
1375
|
+
const itemsArray = Array.isArray(batchItems) ? batchItems : [batchItems];
|
|
1376
|
+
const commentsArray = [];
|
|
1377
|
+
const CONCURRENCY = 5;
|
|
1378
|
+
for (let i = 0; i < itemsArray.length; i += CONCURRENCY) {
|
|
1379
|
+
const batch = itemsArray.slice(i, i + CONCURRENCY);
|
|
1380
|
+
const batchResults = await Promise.all(
|
|
1381
|
+
batch.map((item) => fetchComments(String(item.id), opts))
|
|
1382
|
+
);
|
|
1383
|
+
commentsArray.push(...batchResults);
|
|
1384
|
+
}
|
|
1385
|
+
return itemsArray.map(
|
|
1386
|
+
(item, i) => mapWorkItemToIssueDetails(item, String(item.id), commentsArray[i])
|
|
1387
|
+
);
|
|
1388
|
+
} catch (err) {
|
|
1389
|
+
log.debug(`Batch work-item show failed, falling back to individual fetches: ${log.extractMessage(err)}`);
|
|
1390
|
+
const results = await Promise.all(
|
|
1391
|
+
ids.map((id) => datasource2.fetch(id, opts))
|
|
1392
|
+
);
|
|
1393
|
+
return results;
|
|
1337
1394
|
}
|
|
1338
|
-
return items;
|
|
1339
1395
|
},
|
|
1340
1396
|
async fetch(issueId, opts = {}) {
|
|
1341
1397
|
const args = [
|
|
@@ -1362,24 +1418,8 @@ var datasource2 = {
|
|
|
1362
1418
|
} catch {
|
|
1363
1419
|
throw new Error(`Failed to parse Azure CLI output: ${stdout.slice(0, 200)}`);
|
|
1364
1420
|
}
|
|
1365
|
-
const fields = item.fields ?? {};
|
|
1366
1421
|
const comments = await fetchComments(issueId, opts);
|
|
1367
|
-
return
|
|
1368
|
-
number: String(item.id ?? issueId),
|
|
1369
|
-
title: fields["System.Title"] ?? "",
|
|
1370
|
-
body: fields["System.Description"] ?? "",
|
|
1371
|
-
labels: (fields["System.Tags"] ?? "").split(";").map((t) => t.trim()).filter(Boolean),
|
|
1372
|
-
state: fields["System.State"] ?? "",
|
|
1373
|
-
url: item._links?.html?.href ?? item.url ?? "",
|
|
1374
|
-
comments,
|
|
1375
|
-
acceptanceCriteria: fields["Microsoft.VSTS.Common.AcceptanceCriteria"] ?? "",
|
|
1376
|
-
iterationPath: fields["System.IterationPath"] || void 0,
|
|
1377
|
-
areaPath: fields["System.AreaPath"] || void 0,
|
|
1378
|
-
assignee: fields["System.AssignedTo"]?.displayName || void 0,
|
|
1379
|
-
priority: fields["Microsoft.VSTS.Common.Priority"] ?? void 0,
|
|
1380
|
-
storyPoints: fields["Microsoft.VSTS.Scheduling.StoryPoints"] ?? fields["Microsoft.VSTS.Scheduling.Effort"] ?? fields["Microsoft.VSTS.Scheduling.Size"] ?? void 0,
|
|
1381
|
-
workItemType: fields["System.WorkItemType"] || void 0
|
|
1382
|
-
};
|
|
1422
|
+
return mapWorkItemToIssueDetails(item, issueId, comments);
|
|
1383
1423
|
},
|
|
1384
1424
|
async update(issueId, title, body, opts = {}) {
|
|
1385
1425
|
const args = [
|
|
@@ -1442,30 +1482,26 @@ var datasource2 = {
|
|
|
1442
1482
|
} catch {
|
|
1443
1483
|
throw new Error(`Failed to parse Azure CLI output: ${stdout.slice(0, 200)}`);
|
|
1444
1484
|
}
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
state: fields["System.State"] ?? "New",
|
|
1452
|
-
url: item._links?.html?.href ?? item.url ?? "",
|
|
1453
|
-
comments: [],
|
|
1454
|
-
acceptanceCriteria: fields["Microsoft.VSTS.Common.AcceptanceCriteria"] ?? "",
|
|
1455
|
-
iterationPath: fields["System.IterationPath"] || void 0,
|
|
1456
|
-
areaPath: fields["System.AreaPath"] || void 0,
|
|
1457
|
-
assignee: fields["System.AssignedTo"]?.displayName || void 0,
|
|
1458
|
-
priority: fields["Microsoft.VSTS.Common.Priority"] ?? void 0,
|
|
1459
|
-
storyPoints: fields["Microsoft.VSTS.Scheduling.StoryPoints"] ?? fields["Microsoft.VSTS.Scheduling.Effort"] ?? fields["Microsoft.VSTS.Scheduling.Size"] ?? void 0,
|
|
1460
|
-
workItemType: fields["System.WorkItemType"] || workItemType
|
|
1461
|
-
};
|
|
1485
|
+
return mapWorkItemToIssueDetails(item, String(item.id), [], {
|
|
1486
|
+
title,
|
|
1487
|
+
body,
|
|
1488
|
+
state: "New",
|
|
1489
|
+
workItemType
|
|
1490
|
+
});
|
|
1462
1491
|
},
|
|
1463
1492
|
async getDefaultBranch(opts) {
|
|
1464
1493
|
try {
|
|
1465
1494
|
const { stdout } = await exec2("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], { cwd: opts.cwd });
|
|
1466
1495
|
const parts = stdout.trim().split("/");
|
|
1467
|
-
|
|
1468
|
-
|
|
1496
|
+
const branch = parts[parts.length - 1];
|
|
1497
|
+
if (!isValidBranchName(branch)) {
|
|
1498
|
+
throw new InvalidBranchNameError(branch, "from symbolic-ref output");
|
|
1499
|
+
}
|
|
1500
|
+
return branch;
|
|
1501
|
+
} catch (err) {
|
|
1502
|
+
if (err instanceof InvalidBranchNameError) {
|
|
1503
|
+
throw err;
|
|
1504
|
+
}
|
|
1469
1505
|
try {
|
|
1470
1506
|
await exec2("git", ["rev-parse", "--verify", "main"], { cwd: opts.cwd });
|
|
1471
1507
|
return "main";
|
|
@@ -1499,9 +1535,16 @@ var datasource2 = {
|
|
|
1499
1535
|
},
|
|
1500
1536
|
buildBranchName(issueNumber, title, username) {
|
|
1501
1537
|
const slug = slugify(title, 50);
|
|
1502
|
-
|
|
1538
|
+
const branch = `${username}/dispatch/${issueNumber}-${slug}`;
|
|
1539
|
+
if (!isValidBranchName(branch)) {
|
|
1540
|
+
throw new InvalidBranchNameError(branch);
|
|
1541
|
+
}
|
|
1542
|
+
return branch;
|
|
1503
1543
|
},
|
|
1504
1544
|
async createAndSwitchBranch(branchName, opts) {
|
|
1545
|
+
if (!isValidBranchName(branchName)) {
|
|
1546
|
+
throw new InvalidBranchNameError(branchName);
|
|
1547
|
+
}
|
|
1505
1548
|
try {
|
|
1506
1549
|
await exec2("git", ["checkout", "-b", branchName], { cwd: opts.cwd });
|
|
1507
1550
|
} catch (err) {
|
|
@@ -5136,7 +5179,7 @@ async function main() {
|
|
|
5136
5179
|
process.exit(0);
|
|
5137
5180
|
}
|
|
5138
5181
|
if (args.version) {
|
|
5139
|
-
console.log(`dispatch v${"1.3.
|
|
5182
|
+
console.log(`dispatch v${"1.3.1"}`);
|
|
5140
5183
|
process.exit(0);
|
|
5141
5184
|
}
|
|
5142
5185
|
const orchestrator = await boot9({ cwd: args.cwd });
|