azdo-cli 0.5.0-017-pr-comments-threads.240 → 0.5.0-017-pr-comments-threads.244
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/index.js +82 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2396,12 +2396,25 @@ function mapThread(thread) {
|
|
|
2396
2396
|
comments
|
|
2397
2397
|
};
|
|
2398
2398
|
}
|
|
2399
|
+
var RESOLVED_THREAD_STATUSES = /* @__PURE__ */ new Set(["fixed", "wontFix", "closed", "byDesign"]);
|
|
2400
|
+
function isThreadResolved(status) {
|
|
2401
|
+
return RESOLVED_THREAD_STATUSES.has(status);
|
|
2402
|
+
}
|
|
2399
2403
|
async function readJsonResponse(response) {
|
|
2400
2404
|
if (!response.ok) {
|
|
2401
2405
|
throw new Error(`HTTP_${response.status}`);
|
|
2402
2406
|
}
|
|
2403
2407
|
return response.json();
|
|
2404
2408
|
}
|
|
2409
|
+
async function getPullRequestById(context, repo, pat, prId) {
|
|
2410
|
+
const url = new URL(
|
|
2411
|
+
`https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/git/repositories/${encodeURIComponent(repo)}/pullRequests/${prId}`
|
|
2412
|
+
);
|
|
2413
|
+
url.searchParams.set("api-version", "7.1");
|
|
2414
|
+
const response = await fetchWithErrors(url.toString(), { headers: authHeaders(pat) });
|
|
2415
|
+
const data = await readJsonResponse(response);
|
|
2416
|
+
return mapPullRequest(repo, data);
|
|
2417
|
+
}
|
|
2405
2418
|
async function listPullRequests(context, repo, pat, sourceBranch, opts) {
|
|
2406
2419
|
const response = await fetchWithErrors(
|
|
2407
2420
|
buildPullRequestsUrl(context, repo, sourceBranch, opts).toString(),
|
|
@@ -2471,6 +2484,13 @@ async function getPullRequestThreads(context, repo, pat, prId) {
|
|
|
2471
2484
|
}
|
|
2472
2485
|
|
|
2473
2486
|
// src/commands/pr.ts
|
|
2487
|
+
function parsePositivePrNumber(raw) {
|
|
2488
|
+
if (!/^\d+$/.test(raw)) {
|
|
2489
|
+
return null;
|
|
2490
|
+
}
|
|
2491
|
+
const n = Number.parseInt(raw, 10);
|
|
2492
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
2493
|
+
}
|
|
2474
2494
|
function formatBranchName(refName) {
|
|
2475
2495
|
return refName.startsWith("refs/heads/") ? refName.slice("refs/heads/".length) : refName;
|
|
2476
2496
|
}
|
|
@@ -2525,20 +2545,33 @@ function formatPullRequestBlock(pullRequest) {
|
|
|
2525
2545
|
...formatPullRequestChecks(pullRequest.checks)
|
|
2526
2546
|
].join("\n");
|
|
2527
2547
|
}
|
|
2548
|
+
function threadStatusLabel(status) {
|
|
2549
|
+
return isThreadResolved(status) ? "resolved" : status;
|
|
2550
|
+
}
|
|
2528
2551
|
function formatThreads(prId, title, threads) {
|
|
2529
2552
|
const lines = [`Active comments for pull request #${prId}: ${title}`];
|
|
2530
2553
|
for (const thread of threads) {
|
|
2531
|
-
lines.push("", `Thread #${thread.id} [${thread.status}] ${thread.threadContext ?? "(general)"}`);
|
|
2554
|
+
lines.push("", `Thread #${thread.id} [${threadStatusLabel(thread.status)}] ${thread.threadContext ?? "(general)"}`);
|
|
2532
2555
|
for (const comment of thread.comments) {
|
|
2533
2556
|
lines.push(` ${comment.author ?? "Unknown"}: ${comment.content}`);
|
|
2534
2557
|
}
|
|
2535
2558
|
}
|
|
2536
2559
|
return lines.join("\n");
|
|
2537
2560
|
}
|
|
2538
|
-
async function resolvePrCommandContext(options) {
|
|
2561
|
+
async function resolvePrCommandContext(options, resolveOpts = {}) {
|
|
2562
|
+
const requireBranch = resolveOpts.requireBranch ?? true;
|
|
2539
2563
|
const context = resolveContext(options);
|
|
2540
2564
|
const repo = detectRepoName();
|
|
2541
|
-
|
|
2565
|
+
let branch;
|
|
2566
|
+
if (requireBranch) {
|
|
2567
|
+
branch = getCurrentBranch();
|
|
2568
|
+
} else {
|
|
2569
|
+
try {
|
|
2570
|
+
branch = getCurrentBranch();
|
|
2571
|
+
} catch {
|
|
2572
|
+
branch = null;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2542
2575
|
const credential = await requirePat(context.org);
|
|
2543
2576
|
return {
|
|
2544
2577
|
context,
|
|
@@ -2555,15 +2588,15 @@ function createPrStatusCommand() {
|
|
|
2555
2588
|
try {
|
|
2556
2589
|
const resolved = await resolvePrCommandContext(options);
|
|
2557
2590
|
context = resolved.context;
|
|
2558
|
-
const
|
|
2591
|
+
const branch = resolved.branch;
|
|
2592
|
+
const pullRequests = await listPullRequests(resolved.context, resolved.repo, resolved.pat, branch);
|
|
2559
2593
|
const pullRequestsWithChecks = await Promise.all(
|
|
2560
2594
|
pullRequests.map(async (pullRequest) => ({
|
|
2561
2595
|
...pullRequest,
|
|
2562
2596
|
checks: await getPullRequestChecks(resolved.context, resolved.repo, resolved.pat, pullRequest.id)
|
|
2563
2597
|
}))
|
|
2564
2598
|
);
|
|
2565
|
-
const { branch, repo
|
|
2566
|
-
const result = { branch, repository: repo, pullRequests: pullRequestsWithChecks };
|
|
2599
|
+
const result = { branch, repository: resolved.repo, pullRequests: pullRequestsWithChecks };
|
|
2567
2600
|
if (options.json) {
|
|
2568
2601
|
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
2569
2602
|
`);
|
|
@@ -2604,11 +2637,12 @@ function createPrOpenCommand() {
|
|
|
2604
2637
|
writeError("Pull request creation requires a source branch other than develop.");
|
|
2605
2638
|
return;
|
|
2606
2639
|
}
|
|
2640
|
+
const openBranch = resolved.branch;
|
|
2607
2641
|
const result = await openPullRequest(
|
|
2608
2642
|
resolved.context,
|
|
2609
2643
|
resolved.repo,
|
|
2610
2644
|
resolved.pat,
|
|
2611
|
-
|
|
2645
|
+
openBranch,
|
|
2612
2646
|
title,
|
|
2613
2647
|
description
|
|
2614
2648
|
);
|
|
@@ -2641,27 +2675,52 @@ ${result.pullRequest.url ?? "\u2014"}
|
|
|
2641
2675
|
}
|
|
2642
2676
|
function createPrCommentsCommand() {
|
|
2643
2677
|
const command = new Command12("comments");
|
|
2644
|
-
command.description("List
|
|
2678
|
+
command.description("List pull request comment threads for the current branch").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--pr-number <N>", "target the pull request with this numeric id, instead of the current branch's PR").option("--hide-resolved", "hide threads whose status is resolved / won't fix / closed / by design").option("--json", "output JSON").action(async (options) => {
|
|
2645
2679
|
validateOrgProjectPair(options);
|
|
2646
2680
|
let context;
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
});
|
|
2653
|
-
if (pullRequests.length === 0) {
|
|
2654
|
-
writeError(`No active pull request found for branch ${resolved.branch}.`);
|
|
2681
|
+
let explicitPrId = null;
|
|
2682
|
+
if (options.prNumber !== void 0) {
|
|
2683
|
+
explicitPrId = parsePositivePrNumber(options.prNumber);
|
|
2684
|
+
if (explicitPrId === null) {
|
|
2685
|
+
writeError(`Invalid --pr-number "${options.prNumber}"; expected a positive integer.`);
|
|
2655
2686
|
return;
|
|
2656
2687
|
}
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2688
|
+
}
|
|
2689
|
+
try {
|
|
2690
|
+
const resolved = await resolvePrCommandContext(options, { requireBranch: explicitPrId === null });
|
|
2691
|
+
context = resolved.context;
|
|
2692
|
+
let pullRequest;
|
|
2693
|
+
let branchLabel;
|
|
2694
|
+
if (explicitPrId !== null) {
|
|
2695
|
+
try {
|
|
2696
|
+
pullRequest = await getPullRequestById(resolved.context, resolved.repo, resolved.pat, explicitPrId);
|
|
2697
|
+
} catch (err) {
|
|
2698
|
+
if (err instanceof Error && err.message.startsWith("NOT_FOUND")) {
|
|
2699
|
+
writeError(`Pull request #${explicitPrId} not found in ${resolved.context.org}/${resolved.context.project}/${resolved.repo}.`);
|
|
2700
|
+
return;
|
|
2701
|
+
}
|
|
2702
|
+
throw err;
|
|
2703
|
+
}
|
|
2704
|
+
branchLabel = resolved.branch ?? pullRequest.sourceRefName;
|
|
2705
|
+
} else {
|
|
2706
|
+
const pullRequests = await listPullRequests(resolved.context, resolved.repo, resolved.pat, resolved.branch, {
|
|
2707
|
+
status: "active"
|
|
2708
|
+
});
|
|
2709
|
+
if (pullRequests.length === 0) {
|
|
2710
|
+
writeError(`No active pull request found for branch ${resolved.branch}.`);
|
|
2711
|
+
return;
|
|
2712
|
+
}
|
|
2713
|
+
if (pullRequests.length > 1) {
|
|
2714
|
+
const ids = pullRequests.map((pr) => `#${pr.id}`).join(", ");
|
|
2715
|
+
writeError(`Multiple active pull requests found for branch ${resolved.branch}: ${ids}. Use pr status to review them.`);
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2718
|
+
pullRequest = pullRequests[0];
|
|
2719
|
+
branchLabel = resolved.branch;
|
|
2661
2720
|
}
|
|
2662
|
-
const
|
|
2663
|
-
const threads =
|
|
2664
|
-
const result = { branch:
|
|
2721
|
+
const allThreads = await getPullRequestThreads(resolved.context, resolved.repo, resolved.pat, pullRequest.id);
|
|
2722
|
+
const threads = options.hideResolved ? allThreads.filter((thread) => !isThreadResolved(thread.status)) : allThreads;
|
|
2723
|
+
const result = { branch: branchLabel, pullRequest, threads };
|
|
2665
2724
|
if (options.json) {
|
|
2666
2725
|
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
2667
2726
|
`);
|