azdo-cli 0.5.0-017-pr-comments-threads.244 → 0.5.0-017-pr-comments-threads.246

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.
Files changed (2) hide show
  1. package/dist/index.js +143 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2396,6 +2396,14 @@ function mapThread(thread) {
2396
2396
  comments
2397
2397
  };
2398
2398
  }
2399
+ function toActiveCommentThread(thread) {
2400
+ return {
2401
+ id: thread.id,
2402
+ status: thread.status,
2403
+ threadContext: thread.threadContext?.filePath ?? null,
2404
+ comments: thread.comments.map(mapComment).filter((comment) => comment !== null)
2405
+ };
2406
+ }
2399
2407
  var RESOLVED_THREAD_STATUSES = /* @__PURE__ */ new Set(["fixed", "wontFix", "closed", "byDesign"]);
2400
2408
  function isThreadResolved(status) {
2401
2409
  return RESOLVED_THREAD_STATUSES.has(status);
@@ -2406,6 +2414,22 @@ async function readJsonResponse(response) {
2406
2414
  }
2407
2415
  return response.json();
2408
2416
  }
2417
+ async function patchThreadStatus(context, repo, pat, prId, threadId, status) {
2418
+ const url = new URL(
2419
+ `https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/git/repositories/${encodeURIComponent(repo)}/pullRequests/${prId}/threads/${threadId}`
2420
+ );
2421
+ url.searchParams.set("api-version", "7.1");
2422
+ const response = await fetchWithErrors(url.toString(), {
2423
+ method: "PATCH",
2424
+ headers: {
2425
+ ...authHeaders(pat),
2426
+ "Content-Type": "application/json"
2427
+ },
2428
+ body: JSON.stringify({ status })
2429
+ });
2430
+ const data = await readJsonResponse(response);
2431
+ return toActiveCommentThread(data);
2432
+ }
2409
2433
  async function getPullRequestById(context, repo, pat, prId) {
2410
2434
  const url = new URL(
2411
2435
  `https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/git/repositories/${encodeURIComponent(repo)}/pullRequests/${prId}`
@@ -2739,12 +2763,131 @@ function createPrCommentsCommand() {
2739
2763
  });
2740
2764
  return command;
2741
2765
  }
2766
+ async function resolveThreadTarget(threadIdRaw, options) {
2767
+ validateOrgProjectPair(options);
2768
+ const threadId = parsePositivePrNumber(threadIdRaw);
2769
+ if (threadId === null) {
2770
+ writeError(`Invalid thread id "${threadIdRaw}"; expected a positive integer.`);
2771
+ return null;
2772
+ }
2773
+ let explicitPrId = null;
2774
+ if (options.prNumber !== void 0) {
2775
+ explicitPrId = parsePositivePrNumber(options.prNumber);
2776
+ if (explicitPrId === null) {
2777
+ writeError(`Invalid --pr-number "${options.prNumber}"; expected a positive integer.`);
2778
+ return null;
2779
+ }
2780
+ }
2781
+ const resolved = await resolvePrCommandContext(options, { requireBranch: explicitPrId === null });
2782
+ let pullRequest;
2783
+ if (explicitPrId !== null) {
2784
+ try {
2785
+ pullRequest = await getPullRequestById(resolved.context, resolved.repo, resolved.pat, explicitPrId);
2786
+ } catch (err) {
2787
+ if (err instanceof Error && err.message.startsWith("NOT_FOUND")) {
2788
+ writeError(`Pull request #${explicitPrId} not found in ${resolved.context.org}/${resolved.context.project}/${resolved.repo}.`);
2789
+ return null;
2790
+ }
2791
+ throw err;
2792
+ }
2793
+ } else {
2794
+ const pullRequests = await listPullRequests(resolved.context, resolved.repo, resolved.pat, resolved.branch, {
2795
+ status: "active"
2796
+ });
2797
+ if (pullRequests.length === 0) {
2798
+ writeError(`No active pull request found for branch ${resolved.branch}.`);
2799
+ return null;
2800
+ }
2801
+ if (pullRequests.length > 1) {
2802
+ const ids = pullRequests.map((pr) => `#${pr.id}`).join(", ");
2803
+ writeError(`Multiple active pull requests found for branch ${resolved.branch}: ${ids}. Use pr status to review them.`);
2804
+ return null;
2805
+ }
2806
+ pullRequest = pullRequests[0];
2807
+ }
2808
+ return { context: resolved.context, repo: resolved.repo, pat: resolved.pat, pullRequest, threadId };
2809
+ }
2810
+ async function runThreadStateChange(threadIdRaw, options, direction) {
2811
+ let context;
2812
+ try {
2813
+ const target = await resolveThreadTarget(threadIdRaw, options);
2814
+ if (target === null) {
2815
+ return;
2816
+ }
2817
+ context = target.context;
2818
+ const threads = await getPullRequestThreads(target.context, target.repo, target.pat, target.pullRequest.id);
2819
+ const thread = threads.find((t) => t.id === target.threadId);
2820
+ if (!thread) {
2821
+ writeError(`Thread #${target.threadId} not found on pull request #${target.pullRequest.id}.`);
2822
+ return;
2823
+ }
2824
+ const alreadyInTargetState = direction === "resolve" ? isThreadResolved(thread.status) : !isThreadResolved(thread.status);
2825
+ const targetStatus = direction === "resolve" ? "fixed" : "active";
2826
+ if (alreadyInTargetState) {
2827
+ const humanLabel = direction === "resolve" ? "resolved" : "active";
2828
+ const noopResult = {
2829
+ pullRequestId: target.pullRequest.id,
2830
+ threadId: target.threadId,
2831
+ status: targetStatus,
2832
+ noop: true
2833
+ };
2834
+ if (options.json) {
2835
+ process.stdout.write(`${JSON.stringify(noopResult, null, 2)}
2836
+ `);
2837
+ return;
2838
+ }
2839
+ process.stdout.write(`Thread #${target.threadId} is already ${humanLabel} on pull request #${target.pullRequest.id}.
2840
+ `);
2841
+ return;
2842
+ }
2843
+ const updated = await patchThreadStatus(
2844
+ target.context,
2845
+ target.repo,
2846
+ target.pat,
2847
+ target.pullRequest.id,
2848
+ target.threadId,
2849
+ targetStatus
2850
+ );
2851
+ const result = {
2852
+ pullRequestId: target.pullRequest.id,
2853
+ threadId: target.threadId,
2854
+ status: targetStatus,
2855
+ noop: false
2856
+ };
2857
+ if (options.json) {
2858
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
2859
+ `);
2860
+ return;
2861
+ }
2862
+ const verb = direction === "resolve" ? "resolved" : "reopened";
2863
+ process.stdout.write(`Thread #${target.threadId} ${verb} on pull request #${target.pullRequest.id} (status: ${updated.status}).
2864
+ `);
2865
+ } catch (err) {
2866
+ handlePrCommandError(err, context, "write");
2867
+ }
2868
+ }
2869
+ function createPrCommentResolveCommand() {
2870
+ const command = new Command12("comment-resolve");
2871
+ command.description("Mark a pull request comment thread as resolved").argument("<threadId>", "numeric id of the thread to resolve").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("--json", "output JSON").action(async (threadIdRaw, options) => {
2872
+ await runThreadStateChange(threadIdRaw, options, "resolve");
2873
+ });
2874
+ return command;
2875
+ }
2876
+ function createPrCommentReopenCommand() {
2877
+ const command = new Command12("comment-reopen");
2878
+ command.description("Reopen (set to active) a previously resolved pull request comment thread").argument("<threadId>", "numeric id of the thread to reopen").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("--json", "output JSON").action(async (threadIdRaw, options) => {
2879
+ await runThreadStateChange(threadIdRaw, options, "reopen");
2880
+ });
2881
+ return command;
2882
+ }
2742
2883
  function createPrCommand() {
2743
2884
  const command = new Command12("pr");
2744
2885
  command.description("Manage Azure DevOps pull requests");
2745
2886
  command.addCommand(createPrStatusCommand());
2746
2887
  command.addCommand(createPrOpenCommand());
2747
2888
  command.addCommand(createPrCommentsCommand());
2889
+ command.addCommand(createPrCommentResolveCommand());
2890
+ command.addCommand(createPrCommentReopenCommand());
2748
2891
  return command;
2749
2892
  }
2750
2893
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azdo-cli",
3
- "version": "0.5.0-017-pr-comments-threads.244",
3
+ "version": "0.5.0-017-pr-comments-threads.246",
4
4
  "description": "Azure DevOps CLI tool",
5
5
  "type": "module",
6
6
  "bin": {