azdo-cli 0.19.0-feature-037-api-error-surfacing.693 → 0.19.0-feature-037-api-error-surfacing.692
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/dist/index.js +57 -182
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -326,52 +326,6 @@ async function fetchRaw(url, init) {
|
|
|
326
326
|
const body = await response.text();
|
|
327
327
|
return { status: response.status, body };
|
|
328
328
|
}
|
|
329
|
-
var MAX_DETAIL_CHARS = 500;
|
|
330
|
-
var MAX_RAW_BODY_CHARS = 200;
|
|
331
|
-
var failureDetails = /* @__PURE__ */ new WeakMap();
|
|
332
|
-
function describeFailureBody(body, contentType) {
|
|
333
|
-
if (body === null) return null;
|
|
334
|
-
const trimmed = body.trim();
|
|
335
|
-
if (trimmed === "") return null;
|
|
336
|
-
if (contentType.toLowerCase().startsWith("text/html") || trimmed.startsWith("<")) {
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
const redacted = redactBody(trimmed) ?? trimmed;
|
|
340
|
-
let parsed;
|
|
341
|
-
try {
|
|
342
|
-
parsed = JSON.parse(redacted);
|
|
343
|
-
} catch {
|
|
344
|
-
return truncateDetail(redacted.slice(0, MAX_RAW_BODY_CHARS));
|
|
345
|
-
}
|
|
346
|
-
if (typeof parsed !== "object" || parsed === null) {
|
|
347
|
-
return truncateDetail(redacted.slice(0, MAX_RAW_BODY_CHARS));
|
|
348
|
-
}
|
|
349
|
-
const record = parsed;
|
|
350
|
-
const parts = [];
|
|
351
|
-
if (typeof record.message === "string" && record.message.trim() !== "") {
|
|
352
|
-
parts.push(record.message.trim());
|
|
353
|
-
}
|
|
354
|
-
if (typeof record.typeKey === "string" && record.typeKey.trim() !== "") {
|
|
355
|
-
parts.push(`[${record.typeKey.trim()}]`);
|
|
356
|
-
} else if (typeof record.errorCode === "number" || typeof record.errorCode === "string") {
|
|
357
|
-
parts.push(`[errorCode ${record.errorCode}]`);
|
|
358
|
-
}
|
|
359
|
-
if (parts.length === 0) {
|
|
360
|
-
return truncateDetail(redacted.slice(0, MAX_RAW_BODY_CHARS));
|
|
361
|
-
}
|
|
362
|
-
return truncateDetail(parts.join(" "));
|
|
363
|
-
}
|
|
364
|
-
function truncateDetail(detail) {
|
|
365
|
-
const collapsed = detail.replace(/\s+/g, " ").trim();
|
|
366
|
-
if (collapsed === "") return null;
|
|
367
|
-
return collapsed.length > MAX_DETAIL_CHARS ? `${collapsed.slice(0, MAX_DETAIL_CHARS)}\u2026(truncated)` : collapsed;
|
|
368
|
-
}
|
|
369
|
-
function withDetail(sentinel, detail) {
|
|
370
|
-
return detail === null ? sentinel : `${sentinel}: ${detail}`;
|
|
371
|
-
}
|
|
372
|
-
function httpError(response) {
|
|
373
|
-
return new Error(withDetail(`HTTP_${response.status}`, failureDetails.get(response) ?? null));
|
|
374
|
-
}
|
|
375
329
|
async function fetchWithErrors(url, init) {
|
|
376
330
|
const writer = getActiveTraceWriter();
|
|
377
331
|
let response;
|
|
@@ -380,7 +334,6 @@ async function fetchWithErrors(url, init) {
|
|
|
380
334
|
} catch (err) {
|
|
381
335
|
throw new Error("NETWORK_ERROR", { cause: err });
|
|
382
336
|
}
|
|
383
|
-
let tracedBody = null;
|
|
384
337
|
if (writer) {
|
|
385
338
|
const reqHeaders = redactHeaders(init.headers ?? {});
|
|
386
339
|
const reqBody = typeof init.body === "string" ? redactBody(init.body) : null;
|
|
@@ -390,7 +343,6 @@ async function fetchWithErrors(url, init) {
|
|
|
390
343
|
responseBody = await clone.text();
|
|
391
344
|
} catch {
|
|
392
345
|
}
|
|
393
|
-
tracedBody = responseBody;
|
|
394
346
|
const respHeaders = {};
|
|
395
347
|
response.headers.forEach((v, k) => {
|
|
396
348
|
respHeaders[k] = v;
|
|
@@ -407,33 +359,18 @@ async function fetchWithErrors(url, init) {
|
|
|
407
359
|
};
|
|
408
360
|
writer.append(entry);
|
|
409
361
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (!response.ok) {
|
|
413
|
-
let body = tracedBody;
|
|
414
|
-
if (body === null) {
|
|
415
|
-
try {
|
|
416
|
-
body = await response.clone().text();
|
|
417
|
-
} catch {
|
|
418
|
-
body = null;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
failureDetail = describeFailureBody(body, contentType);
|
|
422
|
-
if (failureDetail !== null) {
|
|
423
|
-
failureDetails.set(response, failureDetail);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
if (response.status === 401) throw new Error(withDetail("AUTH_FAILED", failureDetail));
|
|
427
|
-
if (response.status === 403) throw new Error(withDetail("PERMISSION_DENIED", failureDetail));
|
|
362
|
+
if (response.status === 401) throw new Error("AUTH_FAILED");
|
|
363
|
+
if (response.status === 403) throw new Error("PERMISSION_DENIED");
|
|
428
364
|
if (response.status === 404) {
|
|
429
365
|
let detail = "";
|
|
430
366
|
try {
|
|
431
|
-
const body =
|
|
367
|
+
const body = await response.text();
|
|
432
368
|
detail = ` | url=${url} | body=${body}`;
|
|
433
369
|
} catch {
|
|
434
370
|
}
|
|
435
371
|
throw new Error(`NOT_FOUND${detail}`);
|
|
436
372
|
}
|
|
373
|
+
const contentType = response.headers?.get("content-type") ?? "";
|
|
437
374
|
if (contentType.toLowerCase().startsWith("text/html")) {
|
|
438
375
|
throw new Error("AUTH_FAILED");
|
|
439
376
|
}
|
|
@@ -527,7 +464,7 @@ async function readWriteResponse(response, errorCode) {
|
|
|
527
464
|
throw new Error(`${errorCode}: ${serverMessage}`);
|
|
528
465
|
}
|
|
529
466
|
if (!response.ok) {
|
|
530
|
-
throw
|
|
467
|
+
throw new Error(`HTTP_${response.status}`);
|
|
531
468
|
}
|
|
532
469
|
const data = await response.json();
|
|
533
470
|
return {
|
|
@@ -550,7 +487,7 @@ async function getWorkItemFields(context, id, cred) {
|
|
|
550
487
|
}
|
|
551
488
|
}
|
|
552
489
|
if (!response.ok) {
|
|
553
|
-
throw
|
|
490
|
+
throw new Error(`HTTP_${response.status}`);
|
|
554
491
|
}
|
|
555
492
|
const data = await response.json();
|
|
556
493
|
return data.fields;
|
|
@@ -602,7 +539,7 @@ async function fetchWorkItemResponse(context, id, cred, options = {}) {
|
|
|
602
539
|
}
|
|
603
540
|
}
|
|
604
541
|
if (!response.ok) {
|
|
605
|
-
throw
|
|
542
|
+
throw new Error(`HTTP_${response.status}`);
|
|
606
543
|
}
|
|
607
544
|
return await response.json();
|
|
608
545
|
}
|
|
@@ -613,7 +550,7 @@ async function getOrgFieldNames(context, cred) {
|
|
|
613
550
|
url.searchParams.set("api-version", "7.1");
|
|
614
551
|
const response = await fetchWithErrors(url.toString(), { headers: authHeaders(cred) });
|
|
615
552
|
if (!response.ok) {
|
|
616
|
-
throw
|
|
553
|
+
throw new Error(`HTTP_${response.status}`);
|
|
617
554
|
}
|
|
618
555
|
const data = await response.json();
|
|
619
556
|
return (data.value ?? []).map((f) => f.referenceName);
|
|
@@ -695,7 +632,7 @@ async function getWorkItemFieldValue(context, id, cred, fieldName) {
|
|
|
695
632
|
}
|
|
696
633
|
}
|
|
697
634
|
if (!response.ok) {
|
|
698
|
-
throw
|
|
635
|
+
throw new Error(`HTTP_${response.status}`);
|
|
699
636
|
}
|
|
700
637
|
const data = await response.json();
|
|
701
638
|
const value = data.fields[fieldName];
|
|
@@ -713,7 +650,7 @@ async function listWorkItemComments(context, id, cred) {
|
|
|
713
650
|
{ headers: authHeaders(cred) }
|
|
714
651
|
);
|
|
715
652
|
if (!response.ok) {
|
|
716
|
-
throw
|
|
653
|
+
throw new Error(`HTTP_${response.status}`);
|
|
717
654
|
}
|
|
718
655
|
const data = await response.json();
|
|
719
656
|
comments.push(
|
|
@@ -743,7 +680,7 @@ async function addWorkItemComment(context, id, cred, text, format = "html") {
|
|
|
743
680
|
throw new Error(`BAD_REQUEST: ${serverMessage}`);
|
|
744
681
|
}
|
|
745
682
|
if (!response.ok) {
|
|
746
|
-
throw
|
|
683
|
+
throw new Error(`HTTP_${response.status}`);
|
|
747
684
|
}
|
|
748
685
|
const data = await response.json();
|
|
749
686
|
return {
|
|
@@ -795,7 +732,7 @@ async function applyWorkItemPatch(context, id, cred, operations) {
|
|
|
795
732
|
async function downloadAttachment(url, cred) {
|
|
796
733
|
const response = await fetchWithErrors(url, { headers: authHeaders(cred) });
|
|
797
734
|
if (!response.ok) {
|
|
798
|
-
throw
|
|
735
|
+
throw new Error(`HTTP_${response.status}`);
|
|
799
736
|
}
|
|
800
737
|
return response.arrayBuffer();
|
|
801
738
|
}
|
|
@@ -820,7 +757,7 @@ async function createAttachment(context, fileName, content, cred) {
|
|
|
820
757
|
}
|
|
821
758
|
}
|
|
822
759
|
if (!response.ok) {
|
|
823
|
-
throw
|
|
760
|
+
throw new Error(`HTTP_${response.status}`);
|
|
824
761
|
}
|
|
825
762
|
return await response.json();
|
|
826
763
|
}
|
|
@@ -1610,23 +1547,6 @@ function toMarkdown(content) {
|
|
|
1610
1547
|
}
|
|
1611
1548
|
|
|
1612
1549
|
// src/services/command-helpers.ts
|
|
1613
|
-
function isSentinel(message, sentinel) {
|
|
1614
|
-
return message === sentinel || message.startsWith(`${sentinel}: `);
|
|
1615
|
-
}
|
|
1616
|
-
function sentinelDetail(message, sentinel) {
|
|
1617
|
-
return message.startsWith(`${sentinel}: `) ? message.slice(sentinel.length + 2) : null;
|
|
1618
|
-
}
|
|
1619
|
-
function splitSentinel(message) {
|
|
1620
|
-
const separator = message.indexOf(": ");
|
|
1621
|
-
return separator === -1 ? { sentinel: message, detail: null } : { sentinel: message.slice(0, separator), detail: message.slice(separator + 2) };
|
|
1622
|
-
}
|
|
1623
|
-
function writeErrorDetail(message, sentinel) {
|
|
1624
|
-
const detail = sentinelDetail(message, sentinel);
|
|
1625
|
-
if (detail !== null) {
|
|
1626
|
-
process.stderr.write(` ${detail}
|
|
1627
|
-
`);
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
1550
|
async function promptYesNo(prompt) {
|
|
1631
1551
|
if (!process.stdin.isTTY) return true;
|
|
1632
1552
|
process.stderr.write(prompt);
|
|
@@ -1688,18 +1608,16 @@ function handleCommandError(err, id, context, scope = "write", exit = true) {
|
|
|
1688
1608
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1689
1609
|
const msg = error.message;
|
|
1690
1610
|
const scopeLabel = scope === "read" ? "Work Items (read)" : "Work Items (Read & Write)";
|
|
1691
|
-
if (
|
|
1611
|
+
if (msg === "AUTH_FAILED") {
|
|
1692
1612
|
process.stderr.write(
|
|
1693
1613
|
`Error: Authentication failed. Check that your PAT is valid and has the "${scopeLabel}" scope.
|
|
1694
1614
|
`
|
|
1695
1615
|
);
|
|
1696
|
-
|
|
1697
|
-
} else if (isSentinel(msg, "PERMISSION_DENIED")) {
|
|
1616
|
+
} else if (msg === "PERMISSION_DENIED") {
|
|
1698
1617
|
process.stderr.write(
|
|
1699
1618
|
`Error: Access denied. Your PAT may lack ${scope} permissions for project "${context?.project}".
|
|
1700
1619
|
`
|
|
1701
1620
|
);
|
|
1702
|
-
writeErrorDetail(msg, "PERMISSION_DENIED");
|
|
1703
1621
|
} else if (msg.startsWith("NOT_FOUND")) {
|
|
1704
1622
|
process.stderr.write(
|
|
1705
1623
|
`Error: Work item ${id} not found in ${context?.org}/${context?.project}.
|
|
@@ -3214,10 +3132,10 @@ function buildUpsertResult(action, writeResult, fields, fallbackWorkItemType) {
|
|
|
3214
3132
|
};
|
|
3215
3133
|
}
|
|
3216
3134
|
function isUpdateWriteError(err) {
|
|
3217
|
-
return
|
|
3135
|
+
return err.message === "AUTH_FAILED" || err.message === "PERMISSION_DENIED" || err.message.startsWith("NOT_FOUND") || err.message === "NETWORK_ERROR" || err.message.startsWith("BAD_REQUEST:") || err.message.startsWith("UPDATE_REJECTED:");
|
|
3218
3136
|
}
|
|
3219
3137
|
function isCreateWriteError(err) {
|
|
3220
|
-
return
|
|
3138
|
+
return err.message === "AUTH_FAILED" || err.message === "PERMISSION_DENIED" || err.message === "NETWORK_ERROR" || err.message.startsWith("BAD_REQUEST:") || err.message.startsWith("HTTP_");
|
|
3221
3139
|
}
|
|
3222
3140
|
function handleUpsertError(err, id, context) {
|
|
3223
3141
|
if (!(err instanceof Error)) {
|
|
@@ -3547,7 +3465,7 @@ function isThreadResolved(status2) {
|
|
|
3547
3465
|
}
|
|
3548
3466
|
async function readJsonResponse(response) {
|
|
3549
3467
|
if (!response.ok) {
|
|
3550
|
-
throw
|
|
3468
|
+
throw new Error(`HTTP_${response.status}`);
|
|
3551
3469
|
}
|
|
3552
3470
|
return response.json();
|
|
3553
3471
|
}
|
|
@@ -3634,32 +3552,19 @@ async function getPullRequestBuilds(context, cred, prId) {
|
|
|
3634
3552
|
isBlocking: null
|
|
3635
3553
|
}));
|
|
3636
3554
|
}
|
|
3637
|
-
var MAX_PR_DESCRIPTION_CHARS = 4e3;
|
|
3638
|
-
var DESCRIPTION_SEPARATOR = "\n\n";
|
|
3639
3555
|
function composeDescription(description, template) {
|
|
3640
|
-
if (description
|
|
3641
|
-
return
|
|
3556
|
+
if (description !== void 0 && template !== null) {
|
|
3557
|
+
return `${description}
|
|
3558
|
+
|
|
3559
|
+
${template.content}`;
|
|
3642
3560
|
}
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
separatorChars: separator.length,
|
|
3651
|
-
templateChars: templateContent.length,
|
|
3652
|
-
templatePath: template?.path ?? null,
|
|
3653
|
-
totalChars: text.length
|
|
3654
|
-
};
|
|
3655
|
-
}
|
|
3656
|
-
function formatDescriptionOverflow(composed) {
|
|
3657
|
-
const overflow = composed.totalChars - MAX_PR_DESCRIPTION_CHARS;
|
|
3658
|
-
const breakdown = composed.templateChars > 0 && composed.providedChars > 0 ? ` (${composed.providedChars} provided + ${composed.separatorChars} separator + ${composed.templateChars} from the repository pull request template ${composed.templatePath})` : composed.templateChars > 0 ? ` (all of it from the repository pull request template ${composed.templatePath})` : "";
|
|
3659
|
-
return `description is ${composed.totalChars} characters${breakdown}, exceeding the Azure DevOps limit of ${MAX_PR_DESCRIPTION_CHARS} characters. Shorten the description by at least ${overflow} characters.`;
|
|
3660
|
-
}
|
|
3661
|
-
function describeDescriptionBudget(composed) {
|
|
3662
|
-
return `description: ${composed.providedChars} provided + ${composed.separatorChars} separator + ${composed.templateChars} template = ${composed.totalChars} characters (client limit ${MAX_PR_DESCRIPTION_CHARS})`;
|
|
3561
|
+
if (description !== void 0) {
|
|
3562
|
+
return description;
|
|
3563
|
+
}
|
|
3564
|
+
if (template !== null) {
|
|
3565
|
+
return template.content;
|
|
3566
|
+
}
|
|
3567
|
+
return null;
|
|
3663
3568
|
}
|
|
3664
3569
|
async function openPullRequest(context, repo, cred, sourceBranch, title, description) {
|
|
3665
3570
|
const existing = await listPullRequests(context, repo, cred, sourceBranch, {
|
|
@@ -3680,40 +3585,29 @@ async function openPullRequest(context, repo, cred, sourceBranch, title, descrip
|
|
|
3680
3585
|
const repository = await getRepository(context, repo, cred);
|
|
3681
3586
|
const defaultBranch = repository.defaultBranch ? repository.defaultBranch.replace(/^refs\/heads\//, "") : "develop";
|
|
3682
3587
|
const template = await resolvePullRequestTemplate(context, repo, cred, defaultBranch, "develop");
|
|
3683
|
-
const
|
|
3684
|
-
if (
|
|
3588
|
+
const finalDescription = composeDescription(description, template);
|
|
3589
|
+
if (finalDescription === null) {
|
|
3685
3590
|
throw new Error("DESCRIPTION_REQUIRED");
|
|
3686
3591
|
}
|
|
3687
|
-
if (composed.totalChars > MAX_PR_DESCRIPTION_CHARS) {
|
|
3688
|
-
throw new Error(`DESCRIPTION_TOO_LONG: ${formatDescriptionOverflow(composed)}`);
|
|
3689
|
-
}
|
|
3690
3592
|
const payload = {
|
|
3691
3593
|
sourceRefName: `refs/heads/${sourceBranch}`,
|
|
3692
3594
|
targetRefName: "refs/heads/develop",
|
|
3693
3595
|
title,
|
|
3694
|
-
description:
|
|
3596
|
+
description: finalDescription
|
|
3695
3597
|
};
|
|
3696
3598
|
const url = new URL(
|
|
3697
3599
|
`https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/git/repositories/${encodeURIComponent(repo)}/pullrequests`
|
|
3698
3600
|
);
|
|
3699
3601
|
url.searchParams.set("api-version", "7.1");
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
});
|
|
3710
|
-
data = await readJsonResponse(response);
|
|
3711
|
-
} catch (err) {
|
|
3712
|
-
if (err instanceof Error && err.message.startsWith("HTTP_400")) {
|
|
3713
|
-
throw new Error(`${err.message} | ${describeDescriptionBudget(composed)}`, { cause: err });
|
|
3714
|
-
}
|
|
3715
|
-
throw err;
|
|
3716
|
-
}
|
|
3602
|
+
const response = await fetchWithErrors(url.toString(), {
|
|
3603
|
+
method: "POST",
|
|
3604
|
+
headers: {
|
|
3605
|
+
...authHeaders(cred),
|
|
3606
|
+
"Content-Type": "application/json"
|
|
3607
|
+
},
|
|
3608
|
+
body: JSON.stringify(payload)
|
|
3609
|
+
});
|
|
3610
|
+
const data = await readJsonResponse(response);
|
|
3717
3611
|
return {
|
|
3718
3612
|
branch: sourceBranch,
|
|
3719
3613
|
targetBranch: "develop",
|
|
@@ -3851,7 +3745,7 @@ async function patchWorkItemRelations(context, cred, workItemId, operation) {
|
|
|
3851
3745
|
body: JSON.stringify([operation])
|
|
3852
3746
|
});
|
|
3853
3747
|
if (!response.ok) {
|
|
3854
|
-
throw
|
|
3748
|
+
throw new Error(`HTTP_${response.status}`);
|
|
3855
3749
|
}
|
|
3856
3750
|
}
|
|
3857
3751
|
async function linkWorkItemToPullRequest(context, repo, cred, prId, workItemId) {
|
|
@@ -3900,7 +3794,7 @@ async function resolveReviewerIdentity(org, cred, input) {
|
|
|
3900
3794
|
headers: authHeaders(cred)
|
|
3901
3795
|
});
|
|
3902
3796
|
} catch (err) {
|
|
3903
|
-
if (err instanceof Error &&
|
|
3797
|
+
if (err instanceof Error && err.message === "AUTH_FAILED") {
|
|
3904
3798
|
throw new Error("IDENTITY_SCOPE_MISSING", { cause: err });
|
|
3905
3799
|
}
|
|
3906
3800
|
throw err;
|
|
@@ -3959,7 +3853,7 @@ async function removePullRequestReviewer(context, repo, cred, prId, reviewerId)
|
|
|
3959
3853
|
headers: authHeaders(cred)
|
|
3960
3854
|
});
|
|
3961
3855
|
if (!response.ok) {
|
|
3962
|
-
throw
|
|
3856
|
+
throw new Error(`HTTP_${response.status}`);
|
|
3963
3857
|
}
|
|
3964
3858
|
return { reviewer: existing, noop: false };
|
|
3965
3859
|
}
|
|
@@ -3998,7 +3892,7 @@ async function fetchRepositoryItemContent(context, repo, cred, path3, branch) {
|
|
|
3998
3892
|
throw err;
|
|
3999
3893
|
}
|
|
4000
3894
|
if (!response.ok) {
|
|
4001
|
-
throw
|
|
3895
|
+
throw new Error(`HTTP_${response.status}`);
|
|
4002
3896
|
}
|
|
4003
3897
|
return response.text();
|
|
4004
3898
|
}
|
|
@@ -4133,7 +4027,7 @@ function writeError(message, exitCode = 1) {
|
|
|
4133
4027
|
}
|
|
4134
4028
|
function handlePrCommandError(err, context, mode = "read") {
|
|
4135
4029
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
4136
|
-
if (
|
|
4030
|
+
if (error.message === "AUTH_FAILED") {
|
|
4137
4031
|
const scopeLabel = mode === "write" ? "Code (Read & Write)" : "Code (Read)";
|
|
4138
4032
|
writeError(`Authentication failed. Check that your PAT is valid and has the "${scopeLabel}" scope.`, EXIT_NOT_PERMITTED);
|
|
4139
4033
|
const credentialHint = describeResolvedCredential();
|
|
@@ -4141,7 +4035,6 @@ function handlePrCommandError(err, context, mode = "read") {
|
|
|
4141
4035
|
process.stderr.write(` ${credentialHint}
|
|
4142
4036
|
`);
|
|
4143
4037
|
}
|
|
4144
|
-
writeErrorDetail(error.message, "AUTH_FAILED");
|
|
4145
4038
|
return;
|
|
4146
4039
|
}
|
|
4147
4040
|
if (error.message === "IDENTITY_SCOPE_MISSING") {
|
|
@@ -4151,9 +4044,8 @@ function handlePrCommandError(err, context, mode = "read") {
|
|
|
4151
4044
|
);
|
|
4152
4045
|
return;
|
|
4153
4046
|
}
|
|
4154
|
-
if (
|
|
4047
|
+
if (error.message === "PERMISSION_DENIED") {
|
|
4155
4048
|
writeError(`Access denied. Your PAT may lack ${mode} permissions for project "${context?.project}".`, EXIT_NOT_PERMITTED);
|
|
4156
|
-
writeErrorDetail(error.message, "PERMISSION_DENIED");
|
|
4157
4049
|
return;
|
|
4158
4050
|
}
|
|
4159
4051
|
if (error.message === "NETWORK_ERROR") {
|
|
@@ -4165,12 +4057,7 @@ function handlePrCommandError(err, context, mode = "read") {
|
|
|
4165
4057
|
return;
|
|
4166
4058
|
}
|
|
4167
4059
|
if (error.message.startsWith("HTTP_")) {
|
|
4168
|
-
|
|
4169
|
-
writeError(`Azure DevOps request failed with ${sentinel}.`);
|
|
4170
|
-
if (detail !== null) {
|
|
4171
|
-
process.stderr.write(` ${detail}
|
|
4172
|
-
`);
|
|
4173
|
-
}
|
|
4060
|
+
writeError(`Azure DevOps request failed with ${error.message}.`);
|
|
4174
4061
|
return;
|
|
4175
4062
|
}
|
|
4176
4063
|
writeError(error.message);
|
|
@@ -4402,10 +4289,6 @@ ${result.pullRequest.url ?? "\u2014"}
|
|
|
4402
4289
|
writeError("--description is required for pull request creation.");
|
|
4403
4290
|
return;
|
|
4404
4291
|
}
|
|
4405
|
-
if (err instanceof Error && err.message.startsWith("DESCRIPTION_TOO_LONG: ")) {
|
|
4406
|
-
writeError(err.message.slice("DESCRIPTION_TOO_LONG: ".length));
|
|
4407
|
-
return;
|
|
4408
|
-
}
|
|
4409
4292
|
handlePrCommandError(err, context, "write");
|
|
4410
4293
|
}
|
|
4411
4294
|
});
|
|
@@ -5215,7 +5098,7 @@ function withApiVersion(url) {
|
|
|
5215
5098
|
}
|
|
5216
5099
|
async function readJsonResponse2(response) {
|
|
5217
5100
|
if (!response.ok) {
|
|
5218
|
-
throw
|
|
5101
|
+
throw new Error(`HTTP_${response.status}`);
|
|
5219
5102
|
}
|
|
5220
5103
|
return await response.json();
|
|
5221
5104
|
}
|
|
@@ -5491,7 +5374,7 @@ async function getRunLog(context, cred, buildId, logId) {
|
|
|
5491
5374
|
);
|
|
5492
5375
|
const response = await fetchWithErrors(url.toString(), { headers: authHeaders(cred) });
|
|
5493
5376
|
if (!response.ok) {
|
|
5494
|
-
throw
|
|
5377
|
+
throw new Error(`HTTP_${response.status}`);
|
|
5495
5378
|
}
|
|
5496
5379
|
return response.text();
|
|
5497
5380
|
}
|
|
@@ -5507,14 +5390,12 @@ function writeError2(message) {
|
|
|
5507
5390
|
}
|
|
5508
5391
|
function handlePipelineError(err, context) {
|
|
5509
5392
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
5510
|
-
if (
|
|
5393
|
+
if (error.message === "AUTH_FAILED") {
|
|
5511
5394
|
writeError2('Authentication failed. Check that your credential is valid and has the "Build (Read)" scope.');
|
|
5512
|
-
writeErrorDetail(error.message, "AUTH_FAILED");
|
|
5513
5395
|
return;
|
|
5514
5396
|
}
|
|
5515
|
-
if (
|
|
5397
|
+
if (error.message === "PERMISSION_DENIED") {
|
|
5516
5398
|
writeError2(`Access denied. Your credential may lack pipeline permissions for project "${context?.project}".`);
|
|
5517
|
-
writeErrorDetail(error.message, "PERMISSION_DENIED");
|
|
5518
5399
|
return;
|
|
5519
5400
|
}
|
|
5520
5401
|
if (error.message === "NETWORK_ERROR") {
|
|
@@ -5526,12 +5407,7 @@ function handlePipelineError(err, context) {
|
|
|
5526
5407
|
return;
|
|
5527
5408
|
}
|
|
5528
5409
|
if (error.message.startsWith("HTTP_")) {
|
|
5529
|
-
|
|
5530
|
-
writeError2(`Azure DevOps request failed with ${sentinel}.`);
|
|
5531
|
-
if (detail !== null) {
|
|
5532
|
-
process.stderr.write(` ${detail}
|
|
5533
|
-
`);
|
|
5534
|
-
}
|
|
5410
|
+
writeError2(`Azure DevOps request failed with ${error.message}.`);
|
|
5535
5411
|
return;
|
|
5536
5412
|
}
|
|
5537
5413
|
writeError2(error.message);
|
|
@@ -6423,7 +6299,7 @@ function mapRelationType(raw) {
|
|
|
6423
6299
|
};
|
|
6424
6300
|
}
|
|
6425
6301
|
async function readJsonResponse3(response) {
|
|
6426
|
-
if (!response.ok) throw
|
|
6302
|
+
if (!response.ok) throw new Error(`HTTP_${response.status}`);
|
|
6427
6303
|
return await response.json();
|
|
6428
6304
|
}
|
|
6429
6305
|
function parseTargetId(url) {
|
|
@@ -6471,7 +6347,7 @@ async function addWorkItemRelation(context, cred, type, id1, id2) {
|
|
|
6471
6347
|
{ op: "add", path: "/relations/-", value: { rel: relType.referenceName, url: targetUrl } }
|
|
6472
6348
|
])
|
|
6473
6349
|
});
|
|
6474
|
-
if (!response.ok) throw
|
|
6350
|
+
if (!response.ok) throw new Error(`HTTP_${response.status}`);
|
|
6475
6351
|
return { status: "added", type: relType.name, referenceName: relType.referenceName, id1, id2 };
|
|
6476
6352
|
}
|
|
6477
6353
|
async function removeWorkItemRelation(context, cred, type, id1, id2) {
|
|
@@ -6491,7 +6367,7 @@ async function removeWorkItemRelation(context, cred, type, id1, id2) {
|
|
|
6491
6367
|
headers: { ...authHeaders(cred), "Content-Type": "application/json-patch+json" },
|
|
6492
6368
|
body: JSON.stringify([{ op: "remove", path: `/relations/${index}` }])
|
|
6493
6369
|
});
|
|
6494
|
-
if (!response.ok) throw
|
|
6370
|
+
if (!response.ok) throw new Error(`HTTP_${response.status}`);
|
|
6495
6371
|
return { status: "removed", type: relType.name, referenceName: relType.referenceName, id1, id2 };
|
|
6496
6372
|
}
|
|
6497
6373
|
async function listWorkItemRelations(context, cred, id) {
|
|
@@ -6579,12 +6455,11 @@ function handleRelationError(err, id1) {
|
|
|
6579
6455
|
const target = id1 !== void 0 ? id1 : "unknown";
|
|
6580
6456
|
process.stderr.write(`Error: work item #${target} not found.
|
|
6581
6457
|
`);
|
|
6582
|
-
} else if (
|
|
6458
|
+
} else if (msg === "AUTH_FAILED") {
|
|
6583
6459
|
process.stderr.write(
|
|
6584
6460
|
`Error: authentication failed. Check your PAT has Work Items \u2192 Read & Write scope.
|
|
6585
6461
|
`
|
|
6586
6462
|
);
|
|
6587
|
-
writeErrorDetail(msg, "AUTH_FAILED");
|
|
6588
6463
|
} else {
|
|
6589
6464
|
process.stderr.write(`Error: ${msg}
|
|
6590
6465
|
`);
|