azdo-cli 0.22.0-develop.787 → 0.22.0-develop.790
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 +5 -3
- package/dist/index.js +66 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Azure DevOps CLI focused on work item read/write workflows.
|
|
|
15
15
|
- Attach a local file to a work item, or remove a named attachment (`add-attachment`, `delete-attachment`)
|
|
16
16
|
- Read/write rich-text fields as markdown (`get-md-field`, `set-md-field`)
|
|
17
17
|
- Download images embedded in rich-text fields, optionally resized for LLM use (`get-item`/`get-md-field` `--download-images`, `--resize-images`)
|
|
18
|
-
-
|
|
18
|
+
- List pull requests with their draft state, dates, reviewers, labels and linked work item ids (`pr list --work-items`), check branch pull request status, open PRs to `develop` (optionally pre-filled from a repository-defined template), update an existing PR's title or description (`pr update`), abandon or reactivate one (`pr abandon` / `pr reactivate`), list PR comment threads for any PR (`--pr-number`), resolve/reopen threads, link/unlink work items, and add/remove required or optional reviewers — all from the CLI (`pr`)
|
|
19
19
|
- Feed long PR titles, descriptions and comment bodies from a file or a pipe instead of the shell (`--title-file`, `--description-file`, `--file`; `-` reads standard input)
|
|
20
20
|
- Persist org/project/default fields in local config (`config`)
|
|
21
21
|
- List all fields of a work item (`list-fields`)
|
|
@@ -67,9 +67,11 @@ azdo delete-attachment 12345 screenshot.png --yes # skip the prompt (scr
|
|
|
67
67
|
azdo delete-attachment 12345 screenshot.png --id <guid> # disambiguate when the name is shared
|
|
68
68
|
|
|
69
69
|
# Find a pull request — one API call, any branch
|
|
70
|
-
azdo pr list # active PRs in the repository
|
|
71
|
-
azdo pr list --branch feature/x --json # id, title, source/target, author, url, description
|
|
70
|
+
azdo pr list # active PRs in the repository ([active, draft] marks a draft)
|
|
71
|
+
azdo pr list --branch feature/x --json # id, title, source/target, author, url, description, isDraft,
|
|
72
|
+
# creationDate, closedDate, reviewers (uniqueName, vote), labels
|
|
72
73
|
azdo pr list --status all --top 50
|
|
74
|
+
azdo pr list --work-items --json # + workItemIds per PR: the whole PR ↔ work item map in one call
|
|
73
75
|
|
|
74
76
|
# PR comment threads — list, filter, target by number, resolve or reopen
|
|
75
77
|
azdo pr comments # active-branch PR; code-anchored threads show file:line
|
package/dist/index.js
CHANGED
|
@@ -3704,7 +3704,12 @@ function mapPullRequest(context, repo, pullRequest) {
|
|
|
3704
3704
|
url: pullRequest._links?.web?.href ?? buildPullRequestWebUrl(context, repo, pullRequest.pullRequestId),
|
|
3705
3705
|
description: pullRequest.description?.trim() || null,
|
|
3706
3706
|
createdByUniqueName: pullRequest.createdBy?.uniqueName ?? null,
|
|
3707
|
-
createdById: pullRequest.createdBy?.id ?? null
|
|
3707
|
+
createdById: pullRequest.createdBy?.id ?? null,
|
|
3708
|
+
isDraft: pullRequest.isDraft ?? false,
|
|
3709
|
+
creationDate: pullRequest.creationDate ?? null,
|
|
3710
|
+
closedDate: pullRequest.closedDate ?? null,
|
|
3711
|
+
reviewers: (pullRequest.reviewers ?? []).map(mapReviewer),
|
|
3712
|
+
labels: (pullRequest.labels ?? []).filter((label) => label.active !== false).map((label) => label.name)
|
|
3708
3713
|
};
|
|
3709
3714
|
}
|
|
3710
3715
|
function mapPullRequestCheckName(status2) {
|
|
@@ -3884,6 +3889,15 @@ async function listRepositoryPullRequests(context, repo, cred, opts) {
|
|
|
3884
3889
|
const data = await readJsonResponse(response);
|
|
3885
3890
|
return data.value.map((pullRequest) => mapPullRequest(context, repo, pullRequest));
|
|
3886
3891
|
}
|
|
3892
|
+
async function getPullRequestWorkItemIds(context, repo, cred, prId) {
|
|
3893
|
+
const url = new URL(
|
|
3894
|
+
`https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/git/repositories/${encodeURIComponent(repo)}/pullRequests/${prId}/workitems`
|
|
3895
|
+
);
|
|
3896
|
+
url.searchParams.set("api-version", "7.1");
|
|
3897
|
+
const response = await fetchWithErrors(url.toString(), { headers: authHeaders(cred) });
|
|
3898
|
+
const data = await readJsonResponse(response);
|
|
3899
|
+
return data.value.map((ref) => Number.parseInt(ref.id, 10)).filter((id) => Number.isInteger(id) && id > 0).sort((a, b) => a - b);
|
|
3900
|
+
}
|
|
3887
3901
|
async function getPullRequestChecks(context, repo, cred, prId) {
|
|
3888
3902
|
const response = await fetchWithErrors(
|
|
3889
3903
|
buildPullRequestStatusesUrl(context, repo, prId).toString(),
|
|
@@ -5811,42 +5825,73 @@ function createPrCommentDeleteCommand() {
|
|
|
5811
5825
|
}
|
|
5812
5826
|
var LIST_STATUS_VALUES = ["active", "completed", "abandoned", "all"];
|
|
5813
5827
|
var DEFAULT_LIST_TOP = 25;
|
|
5828
|
+
var WORK_ITEM_LOOKUP_CONCURRENCY = 5;
|
|
5814
5829
|
function formatPullRequestListEntry(pullRequest) {
|
|
5815
|
-
|
|
5816
|
-
|
|
5830
|
+
const state = pullRequest.isDraft ? `${pullRequest.status}, draft` : pullRequest.status;
|
|
5831
|
+
const lines = [
|
|
5832
|
+
`#${pullRequest.id} [${state}] ${pullRequest.title}`,
|
|
5817
5833
|
` ${formatBranchName(pullRequest.sourceRefName)} -> ${formatBranchName(pullRequest.targetRefName)}`,
|
|
5818
|
-
` Author: ${pullRequest.createdBy ?? "Unknown"}
|
|
5819
|
-
|
|
5820
|
-
|
|
5834
|
+
` Author: ${pullRequest.createdBy ?? "Unknown"}`
|
|
5835
|
+
];
|
|
5836
|
+
if ("workItemIds" in pullRequest) {
|
|
5837
|
+
const ids = pullRequest.workItemIds.map((id) => `#${id}`).join(", ");
|
|
5838
|
+
lines.push(` Work items: ${ids || "none"}`);
|
|
5839
|
+
}
|
|
5840
|
+
lines.push(` ${pullRequest.url ?? "\u2014"}`);
|
|
5841
|
+
return lines.join("\n");
|
|
5842
|
+
}
|
|
5843
|
+
function parseListOptions(options) {
|
|
5844
|
+
const status2 = options.status ?? "active";
|
|
5845
|
+
if (!LIST_STATUS_VALUES.includes(status2)) {
|
|
5846
|
+
writeError(`Invalid --status "${status2}"; expected one of ${LIST_STATUS_VALUES.join(", ")}.`);
|
|
5847
|
+
return null;
|
|
5848
|
+
}
|
|
5849
|
+
let top = DEFAULT_LIST_TOP;
|
|
5850
|
+
if (options.top !== void 0) {
|
|
5851
|
+
const parsed = parsePositivePrNumber(options.top);
|
|
5852
|
+
if (parsed === null) {
|
|
5853
|
+
writeError(`Invalid --top "${options.top}"; expected a positive integer.`);
|
|
5854
|
+
return null;
|
|
5855
|
+
}
|
|
5856
|
+
top = parsed;
|
|
5857
|
+
}
|
|
5858
|
+
const branch = options.branch?.trim().replace(/^refs\/heads\//, "") || null;
|
|
5859
|
+
return { status: status2, top, branch };
|
|
5860
|
+
}
|
|
5861
|
+
async function attachWorkItemIds(context, repo, cred, pullRequests) {
|
|
5862
|
+
const result = new Array(pullRequests.length);
|
|
5863
|
+
let next = 0;
|
|
5864
|
+
const worker = async () => {
|
|
5865
|
+
while (next < pullRequests.length) {
|
|
5866
|
+
const index = next;
|
|
5867
|
+
next += 1;
|
|
5868
|
+
const pullRequest = pullRequests[index];
|
|
5869
|
+
const workItemIds = await getPullRequestWorkItemIds(context, repo, cred, pullRequest.id);
|
|
5870
|
+
result[index] = { ...pullRequest, workItemIds };
|
|
5871
|
+
}
|
|
5872
|
+
};
|
|
5873
|
+
await Promise.all(Array.from({ length: Math.min(WORK_ITEM_LOOKUP_CONCURRENCY, pullRequests.length) }, worker));
|
|
5874
|
+
return result;
|
|
5821
5875
|
}
|
|
5822
5876
|
function createPrListCommand() {
|
|
5823
5877
|
const command = new Command12("list");
|
|
5824
|
-
withCommonPrOptions(configureUnwrappedHelp(command)).description("List pull requests in the repository, optionally filtered by source branch").option("--branch <name>", "only pull requests whose source branch is this one (with or without the refs/heads/ prefix)").option("--status <status>", `pull request status filter (${LIST_STATUS_VALUES.join(" | ")})`, "active").option("--top <N>", `maximum number of pull requests to return (default ${DEFAULT_LIST_TOP})`).option("--json", "output JSON").action(async (options) => {
|
|
5878
|
+
withCommonPrOptions(configureUnwrappedHelp(command)).description("List pull requests in the repository, optionally filtered by source branch").option("--branch <name>", "only pull requests whose source branch is this one (with or without the refs/heads/ prefix)").option("--status <status>", `pull request status filter (${LIST_STATUS_VALUES.join(" | ")})`, "active").option("--top <N>", `maximum number of pull requests to return (default ${DEFAULT_LIST_TOP})`).option("--work-items", "also return the ids of each pull request's linked work items (one extra API call per pull request)").option("--json", "output JSON").action(async (options) => {
|
|
5825
5879
|
validateOrgProjectPair(options);
|
|
5826
|
-
const
|
|
5827
|
-
if (
|
|
5828
|
-
writeError(`Invalid --status "${status2}"; expected one of ${LIST_STATUS_VALUES.join(", ")}.`);
|
|
5880
|
+
const parsed = parseListOptions(options);
|
|
5881
|
+
if (parsed === null) {
|
|
5829
5882
|
return;
|
|
5830
5883
|
}
|
|
5831
|
-
|
|
5832
|
-
if (options.top !== void 0) {
|
|
5833
|
-
const parsed = parsePositivePrNumber(options.top);
|
|
5834
|
-
if (parsed === null) {
|
|
5835
|
-
writeError(`Invalid --top "${options.top}"; expected a positive integer.`);
|
|
5836
|
-
return;
|
|
5837
|
-
}
|
|
5838
|
-
top = parsed;
|
|
5839
|
-
}
|
|
5840
|
-
const branch = options.branch?.trim().replace(/^refs\/heads\//, "") || null;
|
|
5884
|
+
const { status: status2, top, branch } = parsed;
|
|
5841
5885
|
let context;
|
|
5842
5886
|
try {
|
|
5843
5887
|
const resolved = await resolvePrCommandContext(options, { requireBranch: false });
|
|
5844
5888
|
context = resolved.context;
|
|
5845
|
-
const
|
|
5889
|
+
const listed = await listRepositoryPullRequests(resolved.context, resolved.repo, resolved.pat, {
|
|
5846
5890
|
sourceBranch: branch ?? void 0,
|
|
5847
5891
|
status: status2,
|
|
5848
5892
|
top
|
|
5849
5893
|
});
|
|
5894
|
+
const pullRequests = options.workItems ? await attachWorkItemIds(resolved.context, resolved.repo, resolved.pat, listed) : listed;
|
|
5850
5895
|
const result = {
|
|
5851
5896
|
repository: resolved.repo,
|
|
5852
5897
|
branch,
|