azdo-cli 0.22.0-develop.782 → 0.22.0-develop.787

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 (3) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +141 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -85,10 +85,11 @@ azdo pr status --pr-number 64 # same view for one PR by number, any st
85
85
  azdo pr comment-resolve 17 --pr-number 64 # idempotent: exit 0 even when already resolved
86
86
  azdo pr comment-reopen 17 --pr-number 64
87
87
 
88
- # Write to a PR — new thread, in-place edit, reply
88
+ # Write to a PR — new thread, in-place edit, delete, reply
89
89
  azdo pr comments add --file plan.md --pr-number 64 --dry-run # preview, writes nothing
90
90
  azdo pr comments add --file plan.md --pr-number 64 # NEW thread on the overview
91
91
  azdo pr comments edit 148 --file plan.md --pr-number 64 # rewrite it in place
92
+ azdo pr comments delete 148 --comment-id 3 --pr-number 64 # delete a comment (irreversible; no prompt)
92
93
  azdo pr comments reply 148 "Great suggestion, I'll address it." # human-readable output
93
94
  azdo pr comments reply 148 "Done." --pr-number 64 --json # JSON: { pullRequestId, threadId, commentId, content }
94
95
  azdo pr comment-reply 148 "Done." --pr-number 64 # flat alias, identical behaviour
package/dist/index.js CHANGED
@@ -4105,6 +4105,19 @@ async function updateThreadComment(context, repo, cred, prId, threadId, commentI
4105
4105
  publishedAt: data.publishedDate ?? null
4106
4106
  };
4107
4107
  }
4108
+ async function deleteThreadComment(context, repo, cred, prId, threadId, commentId) {
4109
+ const url = new URL(
4110
+ `https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/git/repositories/${encodeURIComponent(repo)}/pullRequests/${prId}/threads/${threadId}/comments/${commentId}`
4111
+ );
4112
+ url.searchParams.set("api-version", "7.1");
4113
+ const response = await fetchWithErrors(url.toString(), {
4114
+ method: "DELETE",
4115
+ headers: authHeaders(cred)
4116
+ });
4117
+ if (!response.ok) {
4118
+ throw httpError(response);
4119
+ }
4120
+ }
4108
4121
  async function postThreadComment(context, repo, cred, prId, threadId, content) {
4109
4122
  const response = await fetchWithErrors(buildThreadCommentUrl(context, repo, prId, threadId).toString(), {
4110
4123
  method: "POST",
@@ -5229,6 +5242,7 @@ function createPrCommentsCommand() {
5229
5242
  command.addCommand(createPrCommentsReplyCommand());
5230
5243
  command.addCommand(createPrCommentsAddCommand());
5231
5244
  command.addCommand(createPrCommentsEditCommand());
5245
+ command.addCommand(createPrCommentsDeleteCommand());
5232
5246
  return command;
5233
5247
  }
5234
5248
  function parseTargetPrNumber(options) {
@@ -5547,7 +5561,26 @@ function createPrCommentAddCommand() {
5547
5561
  'Post a new comment thread on the pull request overview (alias of "azdo pr comments add")'
5548
5562
  );
5549
5563
  }
5550
- async function fetchThreadForEdit(target) {
5564
+ function parseExplicitCommentId(options) {
5565
+ if (options.commentId === void 0) {
5566
+ return null;
5567
+ }
5568
+ const parsed = parsePositivePrNumber(options.commentId);
5569
+ if (parsed === null) {
5570
+ writeError(`Invalid --comment-id "${options.commentId}"; expected a positive integer.`);
5571
+ return "invalid";
5572
+ }
5573
+ return parsed;
5574
+ }
5575
+ function findCommentInThread(thread, commentId, target) {
5576
+ const match = thread.comments.find((comment) => comment.id === commentId);
5577
+ if (match === void 0) {
5578
+ writeError(`Comment #${commentId} not found in thread #${target.threadId} on pull request #${target.pullRequest.id}.`, EXIT_NOT_FOUND);
5579
+ return null;
5580
+ }
5581
+ return match;
5582
+ }
5583
+ async function fetchTargetThread(target) {
5551
5584
  try {
5552
5585
  return await getPullRequestThread(
5553
5586
  target.context,
@@ -5566,12 +5599,7 @@ async function fetchThreadForEdit(target) {
5566
5599
  }
5567
5600
  function selectEditableComment(thread, explicitCommentId, target) {
5568
5601
  if (explicitCommentId !== null) {
5569
- const match = thread.comments.find((comment) => comment.id === explicitCommentId);
5570
- if (match === void 0) {
5571
- writeError(`Comment #${explicitCommentId} not found in thread #${target.threadId} on pull request #${target.pullRequest.id}.`, EXIT_NOT_FOUND);
5572
- return null;
5573
- }
5574
- return match;
5602
+ return findCommentInThread(thread, explicitCommentId, target);
5575
5603
  }
5576
5604
  const first = [...thread.comments].sort((a, b) => a.id - b.id)[0];
5577
5605
  if (first === void 0) {
@@ -5606,13 +5634,9 @@ async function runCommentEdit(threadIdRaw, text, options) {
5606
5634
  if (body === null) {
5607
5635
  return;
5608
5636
  }
5609
- let explicitCommentId = null;
5610
- if (options.commentId !== void 0) {
5611
- explicitCommentId = parsePositivePrNumber(options.commentId);
5612
- if (explicitCommentId === null) {
5613
- writeError(`Invalid --comment-id "${options.commentId}"; expected a positive integer.`);
5614
- return;
5615
- }
5637
+ const explicitCommentId = parseExplicitCommentId(options);
5638
+ if (explicitCommentId === "invalid") {
5639
+ return;
5616
5640
  }
5617
5641
  const target = await resolveThreadTarget(threadIdRaw, options, {
5618
5642
  onContextResolved: (resolved) => {
@@ -5622,7 +5646,7 @@ async function runCommentEdit(threadIdRaw, text, options) {
5622
5646
  if (target === null) {
5623
5647
  return;
5624
5648
  }
5625
- const thread = await fetchThreadForEdit(target);
5649
+ const thread = await fetchTargetThread(target);
5626
5650
  if (thread === null) {
5627
5651
  return;
5628
5652
  }
@@ -5684,6 +5708,107 @@ function createPrCommentEditCommand() {
5684
5708
  'Edit an existing pull request comment in place (alias of "azdo pr comments edit")'
5685
5709
  );
5686
5710
  }
5711
+ function selectDeletableComment(thread, explicitCommentId, target) {
5712
+ if (explicitCommentId !== null) {
5713
+ return findCommentInThread(thread, explicitCommentId, target);
5714
+ }
5715
+ const comments = [...thread.comments].sort((a, b) => a.id - b.id);
5716
+ if (comments.length === 1) {
5717
+ return comments[0];
5718
+ }
5719
+ if (comments.length === 0) {
5720
+ writeError(`Thread #${target.threadId} on pull request #${target.pullRequest.id} has no comment to delete.`, EXIT_NOT_FOUND);
5721
+ return null;
5722
+ }
5723
+ const candidates = comments.map((comment) => `#${comment.id} (${comment.author ?? "Unknown"})`).join(", ");
5724
+ writeError(
5725
+ `Thread #${target.threadId} on pull request #${target.pullRequest.id} holds ${comments.length} comments; pass --comment-id to choose one: ${candidates}.`
5726
+ );
5727
+ return null;
5728
+ }
5729
+ function reportDeleteResult(result, json, comment) {
5730
+ if (json) {
5731
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
5732
+ `);
5733
+ return;
5734
+ }
5735
+ if (result.dryRun) {
5736
+ process.stdout.write(
5737
+ `Dry run: would delete comment #${result.commentId} by ${comment.author ?? "Unknown"} (${comment.content.length} chars) from thread #${result.threadId} on pull request #${result.pullRequestId}.
5738
+ `
5739
+ );
5740
+ return;
5741
+ }
5742
+ process.stdout.write(
5743
+ `Comment #${result.commentId} deleted from thread #${result.threadId} on pull request #${result.pullRequestId}.
5744
+ `
5745
+ );
5746
+ }
5747
+ async function runCommentDelete(threadIdRaw, options) {
5748
+ let context;
5749
+ try {
5750
+ const explicitCommentId = parseExplicitCommentId(options);
5751
+ if (explicitCommentId === "invalid") {
5752
+ return;
5753
+ }
5754
+ const target = await resolveThreadTarget(threadIdRaw, options, {
5755
+ onContextResolved: (resolved) => {
5756
+ context = resolved;
5757
+ }
5758
+ });
5759
+ if (target === null) {
5760
+ return;
5761
+ }
5762
+ const thread = await fetchTargetThread(target);
5763
+ if (thread === null) {
5764
+ return;
5765
+ }
5766
+ const comment = selectDeletableComment(thread, explicitCommentId, target);
5767
+ if (comment === null) {
5768
+ return;
5769
+ }
5770
+ const dryRun = options.dryRun === true;
5771
+ if (!dryRun) {
5772
+ await deleteThreadComment(
5773
+ target.context,
5774
+ target.repo,
5775
+ target.pat,
5776
+ target.pullRequest.id,
5777
+ target.threadId,
5778
+ comment.id
5779
+ );
5780
+ }
5781
+ reportDeleteResult(
5782
+ {
5783
+ pullRequestId: target.pullRequest.id,
5784
+ threadId: target.threadId,
5785
+ commentId: comment.id,
5786
+ deleted: !dryRun,
5787
+ dryRun
5788
+ },
5789
+ options.json === true,
5790
+ comment
5791
+ );
5792
+ } catch (err) {
5793
+ handlePrCommandError(err, context, "write");
5794
+ }
5795
+ }
5796
+ function buildCommentDeleteCommand(name, description) {
5797
+ const command = new Command12(name);
5798
+ withCommonPrOptions(configureUnwrappedHelp(command)).description(description).argument("<threadId>", "numeric id of the thread holding the comment").option("--comment-id <N>", "numeric id of the comment to delete; may be omitted only when the thread holds a single comment").option("--dry-run", "resolve the target comment and print what would be deleted, without deleting anything").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, _options, command2) => {
5799
+ await runCommentDelete(threadIdRaw, mergedPrOptions(command2));
5800
+ });
5801
+ return command;
5802
+ }
5803
+ function createPrCommentsDeleteCommand() {
5804
+ return buildCommentDeleteCommand("delete", "Delete a pull request comment (no confirmation prompt; irreversible)");
5805
+ }
5806
+ function createPrCommentDeleteCommand() {
5807
+ return buildCommentDeleteCommand(
5808
+ "comment-delete",
5809
+ 'Delete a pull request comment (alias of "azdo pr comments delete"; no confirmation prompt; irreversible)'
5810
+ );
5811
+ }
5687
5812
  var LIST_STATUS_VALUES = ["active", "completed", "abandoned", "all"];
5688
5813
  var DEFAULT_LIST_TOP = 25;
5689
5814
  function formatPullRequestListEntry(pullRequest) {
@@ -5949,6 +6074,7 @@ function createPrCommand() {
5949
6074
  command.addCommand(createPrWorkItemsCommand());
5950
6075
  command.addCommand(createPrReviewersCommand());
5951
6076
  command.addCommand(createPrCommentEditCommand());
6077
+ command.addCommand(createPrCommentDeleteCommand());
5952
6078
  return command;
5953
6079
  }
5954
6080
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azdo-cli",
3
- "version": "0.22.0-develop.782",
3
+ "version": "0.22.0-develop.787",
4
4
  "description": "Azure DevOps CLI tool",
5
5
  "type": "module",
6
6
  "bin": {