azdo-cli 0.22.0-feature-046-config-help.765 → 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.
- package/README.md +2 -1
- package/dist/index.js +150 -22
- 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
|
@@ -2794,14 +2794,16 @@ function renderSettingsHelp(settings = SETTINGS) {
|
|
|
2794
2794
|
for (const setting of settings) {
|
|
2795
2795
|
const facts = [
|
|
2796
2796
|
describeSettingValues(setting),
|
|
2797
|
-
`scope: ${setting.scoped ? "global, or per organization with --org <org>" : "global only"}
|
|
2797
|
+
`scope: ${setting.scoped ? "global, or per organization with --org <org>" : "global only"}`,
|
|
2798
|
+
...setting.required ? ["required"] : [],
|
|
2799
|
+
...setting.env ? [`env: ${setting.env} overrides the stored value`] : [],
|
|
2800
|
+
`example: azdo config set ${setting.key} ${setting.example}`
|
|
2798
2801
|
];
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
lines.push("");
|
|
2802
|
+
lines.push(
|
|
2803
|
+
` ${setting.key.padEnd(keyWidth)}${setting.description}`,
|
|
2804
|
+
...facts.map((fact) => `${indent}${fact}`),
|
|
2805
|
+
""
|
|
2806
|
+
);
|
|
2805
2807
|
}
|
|
2806
2808
|
return lines.join("\n").trimEnd();
|
|
2807
2809
|
}
|
|
@@ -4103,6 +4105,19 @@ async function updateThreadComment(context, repo, cred, prId, threadId, commentI
|
|
|
4103
4105
|
publishedAt: data.publishedDate ?? null
|
|
4104
4106
|
};
|
|
4105
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
|
+
}
|
|
4106
4121
|
async function postThreadComment(context, repo, cred, prId, threadId, content) {
|
|
4107
4122
|
const response = await fetchWithErrors(buildThreadCommentUrl(context, repo, prId, threadId).toString(), {
|
|
4108
4123
|
method: "POST",
|
|
@@ -5184,6 +5199,7 @@ function createPrCommentsCommand() {
|
|
|
5184
5199
|
command.addCommand(createPrCommentsReplyCommand());
|
|
5185
5200
|
command.addCommand(createPrCommentsAddCommand());
|
|
5186
5201
|
command.addCommand(createPrCommentsEditCommand());
|
|
5202
|
+
command.addCommand(createPrCommentsDeleteCommand());
|
|
5187
5203
|
return command;
|
|
5188
5204
|
}
|
|
5189
5205
|
function parseTargetPrNumber(options) {
|
|
@@ -5502,7 +5518,26 @@ function createPrCommentAddCommand() {
|
|
|
5502
5518
|
'Post a new comment thread on the pull request overview (alias of "azdo pr comments add")'
|
|
5503
5519
|
);
|
|
5504
5520
|
}
|
|
5505
|
-
|
|
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) {
|
|
5506
5541
|
try {
|
|
5507
5542
|
return await getPullRequestThread(
|
|
5508
5543
|
target.context,
|
|
@@ -5521,12 +5556,7 @@ async function fetchThreadForEdit(target) {
|
|
|
5521
5556
|
}
|
|
5522
5557
|
function selectEditableComment(thread, explicitCommentId, target) {
|
|
5523
5558
|
if (explicitCommentId !== null) {
|
|
5524
|
-
|
|
5525
|
-
if (match === void 0) {
|
|
5526
|
-
writeError(`Comment #${explicitCommentId} not found in thread #${target.threadId} on pull request #${target.pullRequest.id}.`, EXIT_NOT_FOUND);
|
|
5527
|
-
return null;
|
|
5528
|
-
}
|
|
5529
|
-
return match;
|
|
5559
|
+
return findCommentInThread(thread, explicitCommentId, target);
|
|
5530
5560
|
}
|
|
5531
5561
|
const first = [...thread.comments].sort((a, b) => a.id - b.id)[0];
|
|
5532
5562
|
if (first === void 0) {
|
|
@@ -5561,13 +5591,9 @@ async function runCommentEdit(threadIdRaw, text, options) {
|
|
|
5561
5591
|
if (body === null) {
|
|
5562
5592
|
return;
|
|
5563
5593
|
}
|
|
5564
|
-
|
|
5565
|
-
if (
|
|
5566
|
-
|
|
5567
|
-
if (explicitCommentId === null) {
|
|
5568
|
-
writeError(`Invalid --comment-id "${options.commentId}"; expected a positive integer.`);
|
|
5569
|
-
return;
|
|
5570
|
-
}
|
|
5594
|
+
const explicitCommentId = parseExplicitCommentId(options);
|
|
5595
|
+
if (explicitCommentId === "invalid") {
|
|
5596
|
+
return;
|
|
5571
5597
|
}
|
|
5572
5598
|
const target = await resolveThreadTarget(threadIdRaw, options, {
|
|
5573
5599
|
onContextResolved: (resolved) => {
|
|
@@ -5577,7 +5603,7 @@ async function runCommentEdit(threadIdRaw, text, options) {
|
|
|
5577
5603
|
if (target === null) {
|
|
5578
5604
|
return;
|
|
5579
5605
|
}
|
|
5580
|
-
const thread = await
|
|
5606
|
+
const thread = await fetchTargetThread(target);
|
|
5581
5607
|
if (thread === null) {
|
|
5582
5608
|
return;
|
|
5583
5609
|
}
|
|
@@ -5639,6 +5665,107 @@ function createPrCommentEditCommand() {
|
|
|
5639
5665
|
'Edit an existing pull request comment in place (alias of "azdo pr comments edit")'
|
|
5640
5666
|
);
|
|
5641
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
|
+
}
|
|
5642
5769
|
var LIST_STATUS_VALUES = ["active", "completed", "abandoned", "all"];
|
|
5643
5770
|
var DEFAULT_LIST_TOP = 25;
|
|
5644
5771
|
function formatPullRequestListEntry(pullRequest) {
|
|
@@ -5904,6 +6031,7 @@ function createPrCommand() {
|
|
|
5904
6031
|
command.addCommand(createPrWorkItemsCommand());
|
|
5905
6032
|
command.addCommand(createPrReviewersCommand());
|
|
5906
6033
|
command.addCommand(createPrCommentEditCommand());
|
|
6034
|
+
command.addCommand(createPrCommentDeleteCommand());
|
|
5907
6035
|
return command;
|
|
5908
6036
|
}
|
|
5909
6037
|
|