azdo-cli 0.10.0-develop.317 → 0.10.0-develop.348
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 -2
- package/dist/index.js +55 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Azure DevOps CLI focused on work item read/write workflows.
|
|
|
16
16
|
- Check branch pull request status, open PRs to `develop`, list PR comment threads for any PR (`--pr-number`), and resolve/reopen threads from the CLI (`pr`)
|
|
17
17
|
- Persist org/project/default fields in local config (`config`)
|
|
18
18
|
- List all fields of a work item (`list-fields`)
|
|
19
|
-
-
|
|
19
|
+
- Authenticate per Azure DevOps organization with `azdo auth login` — OAuth (Microsoft Entra) by default, or a Personal Access Token via `--use-pat` (or the `AZDO_PAT` env var). Credentials are stored in the OS credential store. Inspect with `azdo auth status`, remove with `azdo auth logout`. See [docs/authentication.md](docs/authentication.md).
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
@@ -27,6 +27,9 @@ npm install -g azdo-cli
|
|
|
27
27
|
## Quick Start
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
+
# Sign in to an organization (OAuth by default; add --use-pat for a PAT)
|
|
31
|
+
azdo auth login --org myorg
|
|
32
|
+
|
|
30
33
|
# Configure defaults once
|
|
31
34
|
azdo config set org myorg
|
|
32
35
|
azdo config set project myproject
|
|
@@ -56,7 +59,7 @@ azdo pr comment-reopen 17 --pr-number 64
|
|
|
56
59
|
|
|
57
60
|
| Topic | File |
|
|
58
61
|
|-------|------|
|
|
59
|
-
| Authentication & PAT
|
|
62
|
+
| Authentication (OAuth & PAT) | [docs/authentication.md](docs/authentication.md) |
|
|
60
63
|
| Linux credential store setup | [docs/linux-credential-store.md](docs/linux-credential-store.md) |
|
|
61
64
|
| Full command reference | [docs/commands.md](docs/commands.md) |
|
|
62
65
|
| Development setup | [docs/development.md](docs/development.md) |
|
package/dist/index.js
CHANGED
|
@@ -766,22 +766,42 @@ async function status() {
|
|
|
766
766
|
|
|
767
767
|
// src/services/git-remote.ts
|
|
768
768
|
import { execSync } from "child_process";
|
|
769
|
+
|
|
770
|
+
// src/services/remote-warning.ts
|
|
771
|
+
var WARNING = "azdo: warning: origin includes embedded credentials; consider removing them with 'git remote set-url origin <clean-url>'\n";
|
|
772
|
+
var warned = false;
|
|
773
|
+
function noticeCredentialBearingRemote() {
|
|
774
|
+
if (warned) {
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
warned = true;
|
|
778
|
+
try {
|
|
779
|
+
process.stderr.write(WARNING);
|
|
780
|
+
} catch {
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// src/services/git-remote.ts
|
|
769
785
|
var patterns = [
|
|
770
|
-
// HTTPS (current): https://dev.azure.com/{org}/{project}/_git/{repo}
|
|
771
|
-
/^https?:\/\/dev\.azure\.com\/([^/]+)\/([^/]+)\/_git\/([^/]
|
|
772
|
-
// HTTPS (legacy + DefaultCollection): https://{org}.visualstudio.com/DefaultCollection/{project}/_git/{repo}
|
|
773
|
-
/^https?:\/\/([^.]+)\.visualstudio\.com\/DefaultCollection\/([^/]+)\/_git\/([^/]
|
|
774
|
-
// HTTPS (legacy): https://{org}.visualstudio.com/{project}/_git/{repo}
|
|
775
|
-
/^https?:\/\/([^.]+)\.visualstudio\.com\/([^/]+)\/_git\/([^/]
|
|
776
|
-
// SSH (current): git@ssh.dev.azure.com:v3/{org}/{project}/{repo}
|
|
777
|
-
/^git@ssh\.dev\.azure\.com:v3\/([^/]+)\/([^/]+)\/([^/]
|
|
778
|
-
// SSH (legacy): {org}@vs-ssh.visualstudio.com:v3/{org}/{project}/{repo}
|
|
779
|
-
/^[^@]+@vs-ssh\.visualstudio\.com:v3\/([^/]+)\/([^/]+)\/([^/]
|
|
786
|
+
// HTTPS (current): https://[user[:token]@]dev.azure.com/{org}/{project}/_git/{repo}[.git]
|
|
787
|
+
/^https?:\/\/(?:[^@/]+@)?dev\.azure\.com\/([^/]+)\/([^/]+)\/_git\/([^/]+?)(?:\.git)?$/,
|
|
788
|
+
// HTTPS (legacy + DefaultCollection): https://[user[:token]@]{org}.visualstudio.com/DefaultCollection/{project}/_git/{repo}[.git]
|
|
789
|
+
/^https?:\/\/(?:[^@/]+@)?([^.]+)\.visualstudio\.com\/DefaultCollection\/([^/]+)\/_git\/([^/]+?)(?:\.git)?$/,
|
|
790
|
+
// HTTPS (legacy): https://[user[:token]@]{org}.visualstudio.com/{project}/_git/{repo}[.git]
|
|
791
|
+
/^https?:\/\/(?:[^@/]+@)?([^.]+)\.visualstudio\.com\/([^/]+)\/_git\/([^/]+?)(?:\.git)?$/,
|
|
792
|
+
// SSH (current): git@ssh.dev.azure.com:v3/{org}/{project}/{repo}[.git]
|
|
793
|
+
/^git@ssh\.dev\.azure\.com:v3\/([^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?$/,
|
|
794
|
+
// SSH (legacy): {org}@vs-ssh.visualstudio.com:v3/{org}/{project}/{repo}[.git]
|
|
795
|
+
/^[^@]+@vs-ssh\.visualstudio\.com:v3\/([^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?$/
|
|
780
796
|
];
|
|
797
|
+
var httpsUserinfo = /^https?:\/\/[^@/]+@/;
|
|
781
798
|
function parseAzdoRemote(url) {
|
|
782
799
|
for (const pattern of patterns) {
|
|
783
800
|
const match = pattern.exec(url);
|
|
784
801
|
if (match) {
|
|
802
|
+
if (httpsUserinfo.test(url)) {
|
|
803
|
+
noticeCredentialBearingRemote();
|
|
804
|
+
}
|
|
785
805
|
const project = match[2];
|
|
786
806
|
if (/^DefaultCollection$/i.test(project)) {
|
|
787
807
|
return { org: match[1], project: "" };
|
|
@@ -808,6 +828,9 @@ function parseRepoName(url) {
|
|
|
808
828
|
for (const pattern of patterns) {
|
|
809
829
|
const match = pattern.exec(url);
|
|
810
830
|
if (match) {
|
|
831
|
+
if (httpsUserinfo.test(url)) {
|
|
832
|
+
noticeCredentialBearingRemote();
|
|
833
|
+
}
|
|
811
834
|
return match[3];
|
|
812
835
|
}
|
|
813
836
|
}
|
|
@@ -2624,6 +2647,21 @@ function parsePositivePrNumber(raw) {
|
|
|
2624
2647
|
const n = Number.parseInt(raw, 10);
|
|
2625
2648
|
return Number.isFinite(n) && n > 0 ? n : null;
|
|
2626
2649
|
}
|
|
2650
|
+
var PR_NUMBER_HELP = "target the pull request with this numeric id, instead of the current branch's PR. When omitted, the CLI auto-detects the pull request whose source branch equals refs/heads/<current branch> in the Azure DevOps repository identified by the origin remote; if zero or more than one open PR matches, the command fails with a message naming the searched branch.";
|
|
2651
|
+
function configureUnwrappedHelp(command) {
|
|
2652
|
+
return command.configureHelp({ helpWidth: 1e3 });
|
|
2653
|
+
}
|
|
2654
|
+
function autoDetectZeroMatch(branch) {
|
|
2655
|
+
return `No open pull request matches branch ${branch}. Pass --pr-number to target a specific PR, or push the branch and open a pull request.`;
|
|
2656
|
+
}
|
|
2657
|
+
function autoDetectMultiMatch(branch, ids) {
|
|
2658
|
+
return `Multiple open pull requests match branch ${branch}: ${ids.map((id) => `#${id}`).join(", ")}. Re-run with --pr-number to choose.`;
|
|
2659
|
+
}
|
|
2660
|
+
function writeContractError(line) {
|
|
2661
|
+
process.stderr.write(`${line}
|
|
2662
|
+
`);
|
|
2663
|
+
process.exitCode = 1;
|
|
2664
|
+
}
|
|
2627
2665
|
function formatBranchName(refName) {
|
|
2628
2666
|
return refName.startsWith("refs/heads/") ? refName.slice("refs/heads/".length) : refName;
|
|
2629
2667
|
}
|
|
@@ -2799,7 +2837,7 @@ ${result.pullRequest.url ?? "\u2014"}
|
|
|
2799
2837
|
}
|
|
2800
2838
|
function createPrCommentsCommand() {
|
|
2801
2839
|
const command = new Command12("comments");
|
|
2802
|
-
command.description("List pull request comment threads for the current branch").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--pr-number <N>",
|
|
2840
|
+
configureUnwrappedHelp(command).description("List pull request comment threads for the current branch").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--pr-number <N>", PR_NUMBER_HELP).option("--hide-resolved", "hide threads whose status is resolved / won't fix / closed / by design").option("--json", "output JSON").action(async (options) => {
|
|
2803
2841
|
validateOrgProjectPair(options);
|
|
2804
2842
|
let context;
|
|
2805
2843
|
let explicitPrId = null;
|
|
@@ -2831,12 +2869,11 @@ function createPrCommentsCommand() {
|
|
|
2831
2869
|
status: "active"
|
|
2832
2870
|
});
|
|
2833
2871
|
if (pullRequests.length === 0) {
|
|
2834
|
-
|
|
2872
|
+
writeContractError(autoDetectZeroMatch(resolved.branch));
|
|
2835
2873
|
return;
|
|
2836
2874
|
}
|
|
2837
2875
|
if (pullRequests.length > 1) {
|
|
2838
|
-
|
|
2839
|
-
writeError(`Multiple active pull requests found for branch ${resolved.branch}: ${ids}. Use pr status to review them.`);
|
|
2876
|
+
writeContractError(autoDetectMultiMatch(resolved.branch, pullRequests.map((pr) => pr.id)));
|
|
2840
2877
|
return;
|
|
2841
2878
|
}
|
|
2842
2879
|
pullRequest = pullRequests[0];
|
|
@@ -2900,12 +2937,11 @@ async function resolveThreadTarget(threadIdRaw, options) {
|
|
|
2900
2937
|
status: "active"
|
|
2901
2938
|
});
|
|
2902
2939
|
if (pullRequests.length === 0) {
|
|
2903
|
-
|
|
2940
|
+
writeContractError(autoDetectZeroMatch(resolved.branch));
|
|
2904
2941
|
return null;
|
|
2905
2942
|
}
|
|
2906
2943
|
if (pullRequests.length > 1) {
|
|
2907
|
-
|
|
2908
|
-
writeError(`Multiple active pull requests found for branch ${resolved.branch}: ${ids}. Use pr status to review them.`);
|
|
2944
|
+
writeContractError(autoDetectMultiMatch(resolved.branch, pullRequests.map((pr) => pr.id)));
|
|
2909
2945
|
return null;
|
|
2910
2946
|
}
|
|
2911
2947
|
pullRequest = pullRequests[0];
|
|
@@ -2973,14 +3009,14 @@ async function runThreadStateChange(threadIdRaw, options, direction) {
|
|
|
2973
3009
|
}
|
|
2974
3010
|
function createPrCommentResolveCommand() {
|
|
2975
3011
|
const command = new Command12("comment-resolve");
|
|
2976
|
-
command.description("Mark a pull request comment thread as resolved").argument("<threadId>", "numeric id of the thread to resolve").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--pr-number <N>",
|
|
3012
|
+
configureUnwrappedHelp(command).description("Mark a pull request comment thread as resolved").argument("<threadId>", "numeric id of the thread to resolve").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, options) => {
|
|
2977
3013
|
await runThreadStateChange(threadIdRaw, options, "resolve");
|
|
2978
3014
|
});
|
|
2979
3015
|
return command;
|
|
2980
3016
|
}
|
|
2981
3017
|
function createPrCommentReopenCommand() {
|
|
2982
3018
|
const command = new Command12("comment-reopen");
|
|
2983
|
-
command.description("Reopen (set to active) a previously resolved pull request comment thread").argument("<threadId>", "numeric id of the thread to reopen").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--pr-number <N>",
|
|
3019
|
+
configureUnwrappedHelp(command).description("Reopen (set to active) a previously resolved pull request comment thread").argument("<threadId>", "numeric id of the thread to reopen").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, options) => {
|
|
2984
3020
|
await runThreadStateChange(threadIdRaw, options, "reopen");
|
|
2985
3021
|
});
|
|
2986
3022
|
return command;
|