azdo-cli 0.22.0-feature-046-config-help.767 → 0.22.0-feature-047-pr-comment-delete.770

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
@@ -83,10 +83,11 @@ azdo pr status # PR checks (status + branch policies +
83
83
  azdo pr comment-resolve 17 --pr-number 64 # idempotent: exit 0 even when already resolved
84
84
  azdo pr comment-reopen 17 --pr-number 64
85
85
 
86
- # Write to a PR — new thread, in-place edit, reply
86
+ # Write to a PR — new thread, in-place edit, delete, reply
87
87
  azdo pr comments add --file plan.md --pr-number 64 --dry-run # preview, writes nothing
88
88
  azdo pr comments add --file plan.md --pr-number 64 # NEW thread on the overview
89
89
  azdo pr comments edit 148 --file plan.md --pr-number 64 # rewrite it in place
90
+ azdo pr comments delete 148 --comment-id 3 --pr-number 64 # delete a comment (irreversible; no prompt)
90
91
  azdo pr comments reply 148 "Great suggestion, I'll address it." # human-readable output
91
92
  azdo pr comments reply 148 "Done." --pr-number 64 --json # JSON: { pullRequestId, threadId, commentId, content }
92
93
  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",
@@ -5186,6 +5199,7 @@ function createPrCommentsCommand() {
5186
5199
  command.addCommand(createPrCommentsReplyCommand());
5187
5200
  command.addCommand(createPrCommentsAddCommand());
5188
5201
  command.addCommand(createPrCommentsEditCommand());
5202
+ command.addCommand(createPrCommentsDeleteCommand());
5189
5203
  return command;
5190
5204
  }
5191
5205
  function parseTargetPrNumber(options) {
@@ -5504,7 +5518,26 @@ function createPrCommentAddCommand() {
5504
5518
  'Post a new comment thread on the pull request overview (alias of "azdo pr comments add")'
5505
5519
  );
5506
5520
  }
5507
- async function fetchThreadForEdit(target) {
5521
+ function parseExplicitCommentId(options) {
5522
+ if (options.commentId === void 0) {
5523
+ return null;
5524
+ }
5525
+ const parsed = parsePositivePrNumber(options.commentId);
5526
+ if (parsed === null) {
5527
+ writeError(`Invalid --comment-id "${options.commentId}"; expected a positive integer.`);
5528
+ return "invalid";
5529
+ }
5530
+ return parsed;
5531
+ }
5532
+ function findCommentInThread(thread, commentId, target) {
5533
+ const match = thread.comments.find((comment) => comment.id === commentId);
5534
+ if (match === void 0) {
5535
+ writeError(`Comment #${commentId} not found in thread #${target.threadId} on pull request #${target.pullRequest.id}.`, EXIT_NOT_FOUND);
5536
+ return null;
5537
+ }
5538
+ return match;
5539
+ }
5540
+ async function fetchTargetThread(target) {
5508
5541
  try {
5509
5542
  return await getPullRequestThread(
5510
5543
  target.context,
@@ -5523,12 +5556,7 @@ async function fetchThreadForEdit(target) {
5523
5556
  }
5524
5557
  function selectEditableComment(thread, explicitCommentId, target) {
5525
5558
  if (explicitCommentId !== null) {
5526
- const match = thread.comments.find((comment) => comment.id === explicitCommentId);
5527
- if (match === void 0) {
5528
- writeError(`Comment #${explicitCommentId} not found in thread #${target.threadId} on pull request #${target.pullRequest.id}.`, EXIT_NOT_FOUND);
5529
- return null;
5530
- }
5531
- return match;
5559
+ return findCommentInThread(thread, explicitCommentId, target);
5532
5560
  }
5533
5561
  const first = [...thread.comments].sort((a, b) => a.id - b.id)[0];
5534
5562
  if (first === void 0) {
@@ -5563,13 +5591,9 @@ async function runCommentEdit(threadIdRaw, text, options) {
5563
5591
  if (body === null) {
5564
5592
  return;
5565
5593
  }
5566
- let explicitCommentId = null;
5567
- if (options.commentId !== void 0) {
5568
- explicitCommentId = parsePositivePrNumber(options.commentId);
5569
- if (explicitCommentId === null) {
5570
- writeError(`Invalid --comment-id "${options.commentId}"; expected a positive integer.`);
5571
- return;
5572
- }
5594
+ const explicitCommentId = parseExplicitCommentId(options);
5595
+ if (explicitCommentId === "invalid") {
5596
+ return;
5573
5597
  }
5574
5598
  const target = await resolveThreadTarget(threadIdRaw, options, {
5575
5599
  onContextResolved: (resolved) => {
@@ -5579,7 +5603,7 @@ async function runCommentEdit(threadIdRaw, text, options) {
5579
5603
  if (target === null) {
5580
5604
  return;
5581
5605
  }
5582
- const thread = await fetchThreadForEdit(target);
5606
+ const thread = await fetchTargetThread(target);
5583
5607
  if (thread === null) {
5584
5608
  return;
5585
5609
  }
@@ -5641,6 +5665,107 @@ function createPrCommentEditCommand() {
5641
5665
  'Edit an existing pull request comment in place (alias of "azdo pr comments edit")'
5642
5666
  );
5643
5667
  }
5668
+ function selectDeletableComment(thread, explicitCommentId, target) {
5669
+ if (explicitCommentId !== null) {
5670
+ return findCommentInThread(thread, explicitCommentId, target);
5671
+ }
5672
+ const comments = [...thread.comments].sort((a, b) => a.id - b.id);
5673
+ if (comments.length === 1) {
5674
+ return comments[0];
5675
+ }
5676
+ if (comments.length === 0) {
5677
+ writeError(`Thread #${target.threadId} on pull request #${target.pullRequest.id} has no comment to delete.`, EXIT_NOT_FOUND);
5678
+ return null;
5679
+ }
5680
+ const candidates = comments.map((comment) => `#${comment.id} (${comment.author ?? "Unknown"})`).join(", ");
5681
+ writeError(
5682
+ `Thread #${target.threadId} on pull request #${target.pullRequest.id} holds ${comments.length} comments; pass --comment-id to choose one: ${candidates}.`
5683
+ );
5684
+ return null;
5685
+ }
5686
+ function reportDeleteResult(result, json, comment) {
5687
+ if (json) {
5688
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
5689
+ `);
5690
+ return;
5691
+ }
5692
+ if (result.dryRun) {
5693
+ process.stdout.write(
5694
+ `Dry run: would delete comment #${result.commentId} by ${comment.author ?? "Unknown"} (${comment.content.length} chars) from thread #${result.threadId} on pull request #${result.pullRequestId}.
5695
+ `
5696
+ );
5697
+ return;
5698
+ }
5699
+ process.stdout.write(
5700
+ `Comment #${result.commentId} deleted from thread #${result.threadId} on pull request #${result.pullRequestId}.
5701
+ `
5702
+ );
5703
+ }
5704
+ async function runCommentDelete(threadIdRaw, options) {
5705
+ let context;
5706
+ try {
5707
+ const explicitCommentId = parseExplicitCommentId(options);
5708
+ if (explicitCommentId === "invalid") {
5709
+ return;
5710
+ }
5711
+ const target = await resolveThreadTarget(threadIdRaw, options, {
5712
+ onContextResolved: (resolved) => {
5713
+ context = resolved;
5714
+ }
5715
+ });
5716
+ if (target === null) {
5717
+ return;
5718
+ }
5719
+ const thread = await fetchTargetThread(target);
5720
+ if (thread === null) {
5721
+ return;
5722
+ }
5723
+ const comment = selectDeletableComment(thread, explicitCommentId, target);
5724
+ if (comment === null) {
5725
+ return;
5726
+ }
5727
+ const dryRun = options.dryRun === true;
5728
+ if (!dryRun) {
5729
+ await deleteThreadComment(
5730
+ target.context,
5731
+ target.repo,
5732
+ target.pat,
5733
+ target.pullRequest.id,
5734
+ target.threadId,
5735
+ comment.id
5736
+ );
5737
+ }
5738
+ reportDeleteResult(
5739
+ {
5740
+ pullRequestId: target.pullRequest.id,
5741
+ threadId: target.threadId,
5742
+ commentId: comment.id,
5743
+ deleted: !dryRun,
5744
+ dryRun
5745
+ },
5746
+ options.json === true,
5747
+ comment
5748
+ );
5749
+ } catch (err) {
5750
+ handlePrCommandError(err, context, "write");
5751
+ }
5752
+ }
5753
+ function buildCommentDeleteCommand(name, description) {
5754
+ const command = new Command12(name);
5755
+ 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) => {
5756
+ await runCommentDelete(threadIdRaw, mergedPrOptions(command2));
5757
+ });
5758
+ return command;
5759
+ }
5760
+ function createPrCommentsDeleteCommand() {
5761
+ return buildCommentDeleteCommand("delete", "Delete a pull request comment (no confirmation prompt; irreversible)");
5762
+ }
5763
+ function createPrCommentDeleteCommand() {
5764
+ return buildCommentDeleteCommand(
5765
+ "comment-delete",
5766
+ 'Delete a pull request comment (alias of "azdo pr comments delete"; no confirmation prompt; irreversible)'
5767
+ );
5768
+ }
5644
5769
  var LIST_STATUS_VALUES = ["active", "completed", "abandoned", "all"];
5645
5770
  var DEFAULT_LIST_TOP = 25;
5646
5771
  function formatPullRequestListEntry(pullRequest) {
@@ -5906,6 +6031,7 @@ function createPrCommand() {
5906
6031
  command.addCommand(createPrWorkItemsCommand());
5907
6032
  command.addCommand(createPrReviewersCommand());
5908
6033
  command.addCommand(createPrCommentEditCommand());
6034
+ command.addCommand(createPrCommentDeleteCommand());
5909
6035
  return command;
5910
6036
  }
5911
6037
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azdo-cli",
3
- "version": "0.22.0-feature-046-config-help.767",
3
+ "version": "0.22.0-feature-047-pr-comment-delete.770",
4
4
  "description": "Azure DevOps CLI tool",
5
5
  "type": "module",
6
6
  "bin": {