@thanaen/ado-cli 0.3.0 → 0.4.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 +77 -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;
|
|
@@ -57458,6 +57464,40 @@ async function cmdSmoke(config) {
|
|
|
57458
57464
|
console.log("Pull request: none found");
|
|
57459
57465
|
}
|
|
57460
57466
|
}
|
|
57467
|
+
async function cmdStatus() {
|
|
57468
|
+
const localConfig = loadLocalConfig();
|
|
57469
|
+
const fileConfig = loadFileConfig();
|
|
57470
|
+
const pat = process.env.DEVOPS_PAT ?? localConfig.pat ?? fileConfig.pat;
|
|
57471
|
+
if (!pat) {
|
|
57472
|
+
console.error("Not ready: DEVOPS_PAT is not set");
|
|
57473
|
+
process.exit(1);
|
|
57474
|
+
}
|
|
57475
|
+
const collectionUrl = process.env.ADO_COLLECTION_URL ?? localConfig.collectionUrl ?? fileConfig.collectionUrl ?? "";
|
|
57476
|
+
const project = process.env.ADO_PROJECT ?? localConfig.project ?? fileConfig.project ?? "";
|
|
57477
|
+
const repo = process.env.ADO_REPO ?? localConfig.repo ?? fileConfig.repo ?? "";
|
|
57478
|
+
const hasPlaceholder = (v) => v.includes("<your-");
|
|
57479
|
+
if (!collectionUrl || hasPlaceholder(collectionUrl)) {
|
|
57480
|
+
console.error("Not ready: ADO_COLLECTION_URL is not configured");
|
|
57481
|
+
process.exit(1);
|
|
57482
|
+
}
|
|
57483
|
+
if (!project || hasPlaceholder(project)) {
|
|
57484
|
+
console.error("Not ready: ADO_PROJECT is not configured");
|
|
57485
|
+
process.exit(1);
|
|
57486
|
+
}
|
|
57487
|
+
if (!repo || hasPlaceholder(repo)) {
|
|
57488
|
+
console.error("Not ready: ADO_REPO is not configured");
|
|
57489
|
+
process.exit(1);
|
|
57490
|
+
}
|
|
57491
|
+
try {
|
|
57492
|
+
const config = getConfig();
|
|
57493
|
+
const witApi = await config.connection.getWorkItemTrackingApi();
|
|
57494
|
+
await witApi.queryByWiql({ query: "SELECT [System.Id] FROM WorkItems ORDER BY [System.ChangedDate] DESC" }, { project: config.project }, undefined, 1);
|
|
57495
|
+
console.log("Ready");
|
|
57496
|
+
} catch (err) {
|
|
57497
|
+
console.error(`Not ready: ${err instanceof Error ? err.message : String(err)}`);
|
|
57498
|
+
process.exit(1);
|
|
57499
|
+
}
|
|
57500
|
+
}
|
|
57461
57501
|
async function cmdRepos(config) {
|
|
57462
57502
|
const gitApi = await config.connection.getGitApi();
|
|
57463
57503
|
const repos = await gitApi.getRepositories(config.project);
|
|
@@ -57765,6 +57805,24 @@ async function linkWorkItemsToPr(config, _repo, pr, workItemIds) {
|
|
|
57765
57805
|
console.log(`Linked work item #${workItemId} to PR #${pr?.pullRequestId}`);
|
|
57766
57806
|
}
|
|
57767
57807
|
}
|
|
57808
|
+
async function addTagsToPr(config, repoName, pullRequestId, tags) {
|
|
57809
|
+
if (tags.length === 0)
|
|
57810
|
+
return;
|
|
57811
|
+
const gitApi = await config.connection.getGitApi();
|
|
57812
|
+
const repository = await gitApi.getRepository(repoName, config.project);
|
|
57813
|
+
const repositoryId = repository?.id;
|
|
57814
|
+
if (!repositoryId) {
|
|
57815
|
+
throw new Error(`Repository "${repoName}" not found.`);
|
|
57816
|
+
}
|
|
57817
|
+
const existing = await gitApi.getPullRequestLabels(repositoryId, pullRequestId, config.project);
|
|
57818
|
+
const existingTags = new Set(existing.map((label) => label.name).filter(Boolean));
|
|
57819
|
+
for (const tag of tags) {
|
|
57820
|
+
if (existingTags.has(tag))
|
|
57821
|
+
continue;
|
|
57822
|
+
await gitApi.createPullRequestLabel({ name: tag }, repositoryId, pullRequestId, config.project);
|
|
57823
|
+
console.log(`Added tag "${tag}" to PR #${pullRequestId}`);
|
|
57824
|
+
}
|
|
57825
|
+
}
|
|
57768
57826
|
async function cmdPrCreate(config, args) {
|
|
57769
57827
|
const kv = Object.fromEntries(args.map((arg) => {
|
|
57770
57828
|
const [k, ...rest] = arg.split("=");
|
|
@@ -57776,8 +57834,9 @@ async function cmdPrCreate(config, args) {
|
|
|
57776
57834
|
const description = kv.description ?? "";
|
|
57777
57835
|
const repo = pickRepo(config, kv.repo);
|
|
57778
57836
|
const workItemIds = parseWorkItemIds(kv["work-items"]);
|
|
57837
|
+
const tags = parsePrTags(kv.tags);
|
|
57779
57838
|
if (!title || !source || !target) {
|
|
57780
|
-
console.error("Usage: pr-create --title=... --source=feature/x --target=develop [--description=...] [--repo=...] [--work-items=123,456]");
|
|
57839
|
+
console.error("Usage: pr-create --title=... --source=feature/x --target=develop [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]");
|
|
57781
57840
|
process.exit(1);
|
|
57782
57841
|
}
|
|
57783
57842
|
const gitApi = await config.connection.getGitApi();
|
|
@@ -57792,11 +57851,14 @@ async function cmdPrCreate(config, args) {
|
|
|
57792
57851
|
const createdPr = await gitApi.getPullRequestById(created.pullRequestId, config.project);
|
|
57793
57852
|
await linkWorkItemsToPr(config, repo, createdPr, workItemIds);
|
|
57794
57853
|
}
|
|
57854
|
+
if (created.pullRequestId && tags.length > 0) {
|
|
57855
|
+
await addTagsToPr(config, repo, created.pullRequestId, tags);
|
|
57856
|
+
}
|
|
57795
57857
|
}
|
|
57796
57858
|
async function cmdPrUpdate(config, idRaw, args) {
|
|
57797
57859
|
const id = Number(idRaw);
|
|
57798
57860
|
if (!Number.isFinite(id)) {
|
|
57799
|
-
console.error("Usage: pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456]");
|
|
57861
|
+
console.error("Usage: pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]");
|
|
57800
57862
|
process.exit(1);
|
|
57801
57863
|
}
|
|
57802
57864
|
const kv = Object.fromEntries(args.map((arg) => {
|
|
@@ -57806,12 +57868,13 @@ async function cmdPrUpdate(config, idRaw, args) {
|
|
|
57806
57868
|
const repo = pickRepo(config, kv.repo);
|
|
57807
57869
|
const body = {};
|
|
57808
57870
|
const workItemIds = parseWorkItemIds(kv["work-items"]);
|
|
57871
|
+
const tags = parsePrTags(kv.tags);
|
|
57809
57872
|
if (kv.title !== undefined)
|
|
57810
57873
|
body.title = kv.title;
|
|
57811
57874
|
if (kv.description !== undefined)
|
|
57812
57875
|
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]");
|
|
57876
|
+
if (Object.keys(body).length === 0 && workItemIds.length === 0 && tags.length === 0) {
|
|
57877
|
+
console.error("Usage: pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]");
|
|
57815
57878
|
process.exit(1);
|
|
57816
57879
|
}
|
|
57817
57880
|
const gitApi = await config.connection.getGitApi();
|
|
@@ -57825,6 +57888,9 @@ async function cmdPrUpdate(config, idRaw, args) {
|
|
|
57825
57888
|
if (workItemIds.length > 0) {
|
|
57826
57889
|
await linkWorkItemsToPr(config, repo, updated, workItemIds);
|
|
57827
57890
|
}
|
|
57891
|
+
if (tags.length > 0) {
|
|
57892
|
+
await addTagsToPr(config, repo, id, tags);
|
|
57893
|
+
}
|
|
57828
57894
|
}
|
|
57829
57895
|
async function cmdPrCherryPick(config, args) {
|
|
57830
57896
|
const usage = "Usage: pr-cherry-pick <id> --target=main [--topic=branch-name] [--repo=...]";
|
|
@@ -57957,6 +58023,7 @@ Commands:
|
|
|
57957
58023
|
-v, --version
|
|
57958
58024
|
init [--local]
|
|
57959
58025
|
config
|
|
58026
|
+
status
|
|
57960
58027
|
smoke
|
|
57961
58028
|
repos
|
|
57962
58029
|
branches [repo]
|
|
@@ -57967,8 +58034,8 @@ Commands:
|
|
|
57967
58034
|
workitem-comment-update <id> <commentId> --text="..." [--file=path]
|
|
57968
58035
|
prs [status] [top] [repo]
|
|
57969
58036
|
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]
|
|
58037
|
+
pr-create --title=... --source=... --target=... [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]
|
|
58038
|
+
pr-update <id> [--title=...] [--description=...] [--repo=...] [--work-items=123,456] [--tags=tag-a,tag-b]
|
|
57972
58039
|
pr-cherry-pick <id> --target=... [--topic=branch-name] [--repo=...]
|
|
57973
58040
|
pr-approve <id> [repo]
|
|
57974
58041
|
pr-autocomplete <id> [repo]
|
|
@@ -57998,6 +58065,10 @@ async function main() {
|
|
|
57998
58065
|
cmdConfig();
|
|
57999
58066
|
return;
|
|
58000
58067
|
}
|
|
58068
|
+
if (command === "status") {
|
|
58069
|
+
await cmdStatus();
|
|
58070
|
+
return;
|
|
58071
|
+
}
|
|
58001
58072
|
const config = getConfig();
|
|
58002
58073
|
switch (command) {
|
|
58003
58074
|
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"`
|