@thanaen/ado-cli 0.3.0 → 0.5.0
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 -2
- package/dist/cli.js +78 -6
- package/package.json +1 -1
- package/skills/ado-workflows/SKILL.md +4 -9
package/README.md
CHANGED
|
@@ -72,8 +72,8 @@ ado smoke
|
|
|
72
72
|
- `workitem-comment-update <id> <commentId> --text="..." [--file=path]`
|
|
73
73
|
- `prs [status] [top] [repo]`
|
|
74
74
|
- `pr-get <id> [repo]`
|
|
75
|
-
- `pr-create --title=... --source=... --target=... [--description=...] [--repo=...] [--work-items=123,456]`
|
|
76
|
-
- `pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456]`
|
|
75
|
+
- `pr-create --title=... --source=... --target=... [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]`
|
|
76
|
+
- `pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]`
|
|
77
77
|
- `pr-cherry-pick <id> --target=... [--topic=branch-name] [--repo=...]`
|
|
78
78
|
- `pr-approve <id> [repo]`
|
|
79
79
|
- `pr-autocomplete <id> [repo]`
|
package/dist/cli.js
CHANGED
|
@@ -57273,6 +57273,12 @@ function parseWorkItemIds(rawValue) {
|
|
|
57273
57273
|
const ids = rawValue.split(",").map((part) => Number(part.trim())).filter((id) => Number.isFinite(id) && id > 0);
|
|
57274
57274
|
return [...new Set(ids)];
|
|
57275
57275
|
}
|
|
57276
|
+
function parsePrTags(rawValue) {
|
|
57277
|
+
if (!rawValue)
|
|
57278
|
+
return [];
|
|
57279
|
+
const tags = rawValue.split(",").map((part) => part.trim()).filter((tag) => tag.length > 0);
|
|
57280
|
+
return [...new Set(tags)];
|
|
57281
|
+
}
|
|
57276
57282
|
function buildPullRequestArtifactUrl(pr) {
|
|
57277
57283
|
const projectId = pr?.repository?.project?.id;
|
|
57278
57284
|
const repoId = pr?.repository?.id;
|
|
@@ -57406,6 +57412,7 @@ var import_GitInterfaces = __toESM(require_GitInterfaces(), 1);
|
|
|
57406
57412
|
var import_WorkItemTrackingInterfaces = __toESM(require_WorkItemTrackingInterfaces(), 1);
|
|
57407
57413
|
var import_BuildInterfaces = __toESM(require_BuildInterfaces(), 1);
|
|
57408
57414
|
var import_VSSInterfaces = __toESM(require_VSSInterfaces(), 1);
|
|
57415
|
+
process.removeAllListeners("warning");
|
|
57409
57416
|
function pickRepo(config, value) {
|
|
57410
57417
|
return value || config.repo;
|
|
57411
57418
|
}
|
|
@@ -57458,6 +57465,40 @@ async function cmdSmoke(config) {
|
|
|
57458
57465
|
console.log("Pull request: none found");
|
|
57459
57466
|
}
|
|
57460
57467
|
}
|
|
57468
|
+
async function cmdStatus() {
|
|
57469
|
+
const localConfig = loadLocalConfig();
|
|
57470
|
+
const fileConfig = loadFileConfig();
|
|
57471
|
+
const pat = process.env.DEVOPS_PAT ?? localConfig.pat ?? fileConfig.pat;
|
|
57472
|
+
if (!pat) {
|
|
57473
|
+
console.error("Not ready: DEVOPS_PAT is not set");
|
|
57474
|
+
process.exit(1);
|
|
57475
|
+
}
|
|
57476
|
+
const collectionUrl = process.env.ADO_COLLECTION_URL ?? localConfig.collectionUrl ?? fileConfig.collectionUrl ?? "";
|
|
57477
|
+
const project = process.env.ADO_PROJECT ?? localConfig.project ?? fileConfig.project ?? "";
|
|
57478
|
+
const repo = process.env.ADO_REPO ?? localConfig.repo ?? fileConfig.repo ?? "";
|
|
57479
|
+
const hasPlaceholder = (v) => v.includes("<your-");
|
|
57480
|
+
if (!collectionUrl || hasPlaceholder(collectionUrl)) {
|
|
57481
|
+
console.error("Not ready: ADO_COLLECTION_URL is not configured");
|
|
57482
|
+
process.exit(1);
|
|
57483
|
+
}
|
|
57484
|
+
if (!project || hasPlaceholder(project)) {
|
|
57485
|
+
console.error("Not ready: ADO_PROJECT is not configured");
|
|
57486
|
+
process.exit(1);
|
|
57487
|
+
}
|
|
57488
|
+
if (!repo || hasPlaceholder(repo)) {
|
|
57489
|
+
console.error("Not ready: ADO_REPO is not configured");
|
|
57490
|
+
process.exit(1);
|
|
57491
|
+
}
|
|
57492
|
+
try {
|
|
57493
|
+
const config = getConfig();
|
|
57494
|
+
const witApi = await config.connection.getWorkItemTrackingApi();
|
|
57495
|
+
await witApi.queryByWiql({ query: "SELECT [System.Id] FROM WorkItems ORDER BY [System.ChangedDate] DESC" }, { project: config.project }, undefined, 1);
|
|
57496
|
+
console.log("Ready");
|
|
57497
|
+
} catch (err) {
|
|
57498
|
+
console.error(`Not ready: ${err instanceof Error ? err.message : String(err)}`);
|
|
57499
|
+
process.exit(1);
|
|
57500
|
+
}
|
|
57501
|
+
}
|
|
57461
57502
|
async function cmdRepos(config) {
|
|
57462
57503
|
const gitApi = await config.connection.getGitApi();
|
|
57463
57504
|
const repos = await gitApi.getRepositories(config.project);
|
|
@@ -57765,6 +57806,24 @@ async function linkWorkItemsToPr(config, _repo, pr, workItemIds) {
|
|
|
57765
57806
|
console.log(`Linked work item #${workItemId} to PR #${pr?.pullRequestId}`);
|
|
57766
57807
|
}
|
|
57767
57808
|
}
|
|
57809
|
+
async function addTagsToPr(config, repoName, pullRequestId, tags) {
|
|
57810
|
+
if (tags.length === 0)
|
|
57811
|
+
return;
|
|
57812
|
+
const gitApi = await config.connection.getGitApi();
|
|
57813
|
+
const repository = await gitApi.getRepository(repoName, config.project);
|
|
57814
|
+
const repositoryId = repository?.id;
|
|
57815
|
+
if (!repositoryId) {
|
|
57816
|
+
throw new Error(`Repository "${repoName}" not found.`);
|
|
57817
|
+
}
|
|
57818
|
+
const existing = await gitApi.getPullRequestLabels(repositoryId, pullRequestId, config.project);
|
|
57819
|
+
const existingTags = new Set(existing.map((label) => label.name).filter(Boolean));
|
|
57820
|
+
for (const tag of tags) {
|
|
57821
|
+
if (existingTags.has(tag))
|
|
57822
|
+
continue;
|
|
57823
|
+
await gitApi.createPullRequestLabel({ name: tag }, repositoryId, pullRequestId, config.project);
|
|
57824
|
+
console.log(`Added tag "${tag}" to PR #${pullRequestId}`);
|
|
57825
|
+
}
|
|
57826
|
+
}
|
|
57768
57827
|
async function cmdPrCreate(config, args) {
|
|
57769
57828
|
const kv = Object.fromEntries(args.map((arg) => {
|
|
57770
57829
|
const [k, ...rest] = arg.split("=");
|
|
@@ -57776,8 +57835,9 @@ async function cmdPrCreate(config, args) {
|
|
|
57776
57835
|
const description = kv.description ?? "";
|
|
57777
57836
|
const repo = pickRepo(config, kv.repo);
|
|
57778
57837
|
const workItemIds = parseWorkItemIds(kv["work-items"]);
|
|
57838
|
+
const tags = parsePrTags(kv.tags);
|
|
57779
57839
|
if (!title || !source || !target) {
|
|
57780
|
-
console.error("Usage: pr-create --title=... --source=feature/x --target=develop [--description=...] [--repo=...] [--work-items=123,456]");
|
|
57840
|
+
console.error("Usage: pr-create --title=... --source=feature/x --target=develop [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]");
|
|
57781
57841
|
process.exit(1);
|
|
57782
57842
|
}
|
|
57783
57843
|
const gitApi = await config.connection.getGitApi();
|
|
@@ -57792,11 +57852,14 @@ async function cmdPrCreate(config, args) {
|
|
|
57792
57852
|
const createdPr = await gitApi.getPullRequestById(created.pullRequestId, config.project);
|
|
57793
57853
|
await linkWorkItemsToPr(config, repo, createdPr, workItemIds);
|
|
57794
57854
|
}
|
|
57855
|
+
if (created.pullRequestId && tags.length > 0) {
|
|
57856
|
+
await addTagsToPr(config, repo, created.pullRequestId, tags);
|
|
57857
|
+
}
|
|
57795
57858
|
}
|
|
57796
57859
|
async function cmdPrUpdate(config, idRaw, args) {
|
|
57797
57860
|
const id = Number(idRaw);
|
|
57798
57861
|
if (!Number.isFinite(id)) {
|
|
57799
|
-
console.error("Usage: pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456]");
|
|
57862
|
+
console.error("Usage: pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]");
|
|
57800
57863
|
process.exit(1);
|
|
57801
57864
|
}
|
|
57802
57865
|
const kv = Object.fromEntries(args.map((arg) => {
|
|
@@ -57806,12 +57869,13 @@ async function cmdPrUpdate(config, idRaw, args) {
|
|
|
57806
57869
|
const repo = pickRepo(config, kv.repo);
|
|
57807
57870
|
const body = {};
|
|
57808
57871
|
const workItemIds = parseWorkItemIds(kv["work-items"]);
|
|
57872
|
+
const tags = parsePrTags(kv.tags);
|
|
57809
57873
|
if (kv.title !== undefined)
|
|
57810
57874
|
body.title = kv.title;
|
|
57811
57875
|
if (kv.description !== undefined)
|
|
57812
57876
|
body.description = kv.description;
|
|
57813
|
-
if (Object.keys(body).length === 0 && workItemIds.length === 0) {
|
|
57814
|
-
console.error("Usage: pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456]");
|
|
57877
|
+
if (Object.keys(body).length === 0 && workItemIds.length === 0 && tags.length === 0) {
|
|
57878
|
+
console.error("Usage: pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]");
|
|
57815
57879
|
process.exit(1);
|
|
57816
57880
|
}
|
|
57817
57881
|
const gitApi = await config.connection.getGitApi();
|
|
@@ -57825,6 +57889,9 @@ async function cmdPrUpdate(config, idRaw, args) {
|
|
|
57825
57889
|
if (workItemIds.length > 0) {
|
|
57826
57890
|
await linkWorkItemsToPr(config, repo, updated, workItemIds);
|
|
57827
57891
|
}
|
|
57892
|
+
if (tags.length > 0) {
|
|
57893
|
+
await addTagsToPr(config, repo, id, tags);
|
|
57894
|
+
}
|
|
57828
57895
|
}
|
|
57829
57896
|
async function cmdPrCherryPick(config, args) {
|
|
57830
57897
|
const usage = "Usage: pr-cherry-pick <id> --target=main [--topic=branch-name] [--repo=...]";
|
|
@@ -57957,6 +58024,7 @@ Commands:
|
|
|
57957
58024
|
-v, --version
|
|
57958
58025
|
init [--local]
|
|
57959
58026
|
config
|
|
58027
|
+
status
|
|
57960
58028
|
smoke
|
|
57961
58029
|
repos
|
|
57962
58030
|
branches [repo]
|
|
@@ -57967,8 +58035,8 @@ Commands:
|
|
|
57967
58035
|
workitem-comment-update <id> <commentId> --text="..." [--file=path]
|
|
57968
58036
|
prs [status] [top] [repo]
|
|
57969
58037
|
pr-get <id> [repo]
|
|
57970
|
-
pr-create --title=... --source=... --target=... [--description=...] [--repo=...] [--work-items=123,456]
|
|
57971
|
-
pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456]
|
|
58038
|
+
pr-create --title=... --source=... --target=... [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]
|
|
58039
|
+
pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]
|
|
57972
58040
|
pr-cherry-pick <id> --target=... [--topic=branch-name] [--repo=...]
|
|
57973
58041
|
pr-approve <id> [repo]
|
|
57974
58042
|
pr-autocomplete <id> [repo]
|
|
@@ -57998,6 +58066,10 @@ async function main() {
|
|
|
57998
58066
|
cmdConfig();
|
|
57999
58067
|
return;
|
|
58000
58068
|
}
|
|
58069
|
+
if (command === "status") {
|
|
58070
|
+
await cmdStatus();
|
|
58071
|
+
return;
|
|
58072
|
+
}
|
|
58001
58073
|
const config = getConfig();
|
|
58002
58074
|
switch (command) {
|
|
58003
58075
|
case "smoke":
|
package/package.json
CHANGED
|
@@ -9,13 +9,8 @@ Use the `ado` CLI instead of ad-hoc curl commands.
|
|
|
9
9
|
|
|
10
10
|
## Preflight
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
2. Verify connectivity:
|
|
15
|
-
- `ado smoke`
|
|
16
|
-
- If needed, run an independent host check (outside the CLI) to distinguish network issues from ADO config issues.
|
|
17
|
-
|
|
18
|
-
If auth is missing, stop and ask for `DEVOPS_PAT`.
|
|
12
|
+
Run `ado status` before any other command. It checks token, configuration, and connectivity in one step.
|
|
13
|
+
If it reports an issue, guide the user to run `ado init` (or `ado init --local` for per-project setup) to configure the CLI.
|
|
19
14
|
|
|
20
15
|
## Core commands
|
|
21
16
|
|
|
@@ -33,8 +28,8 @@ If auth is missing, stop and ask for `DEVOPS_PAT`.
|
|
|
33
28
|
- Update an existing comment on a work item: `ado workitem-comment-update <id> <commentId> --text="..."`
|
|
34
29
|
- List PRs: `ado prs active 10 "MyRepo"`
|
|
35
30
|
- Get PR: `ado pr-get <id> "MyRepo"`
|
|
36
|
-
- Create PR: `ado pr-create --title="..." --source="feature/x" --target="develop" --description="..." --repo="MyRepo" --work-items=123,456`
|
|
37
|
-
- Update PR: `ado pr-update <id> --title="..." --description="..." --repo="MyRepo" --work-items=123,456`
|
|
31
|
+
- Create PR: `ado pr-create --title="..." --source="feature/x" --target="develop" --description="..." --repo="MyRepo" --work-items=123,456 --tags=backend,release-1`
|
|
32
|
+
- Update PR: `ado pr-update <id> --title="..." --description="..." --repo="MyRepo" --work-items=123,456 --tags=backend,release-1`
|
|
38
33
|
- Cherry-pick PR onto another branch: `ado pr-cherry-pick <id> --target="main" --topic="cherry-pick-branch" --repo="MyRepo"`
|
|
39
34
|
- Approve PR: `ado pr-approve <id> "MyRepo"`
|
|
40
35
|
- Enable auto-complete: `ado pr-autocomplete <id> "MyRepo"`
|