@postman-cse/onboarding-bootstrap 0.9.1 → 0.10.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/.github/workflows/contract-smoke.yml +155 -0
- package/.omc/sessions/b36ac16d-ce26-4e94-ae7e-dd817f2430a3.json +8 -0
- package/CLAUDE.md +57 -0
- package/README.md +124 -12
- package/action.yml +17 -18
- package/dist/cli.cjs +231 -489
- package/dist/index.cjs +226 -480
- package/package.json +3 -2
- package/src/cli.ts +5 -11
- package/src/contracts.ts +24 -24
- package/src/index.ts +253 -323
- package/src/lib/postman/postman-assets-client.ts +27 -4
- package/tests/bootstrap-action.test.ts +565 -79
- package/tests/cli.test.ts +12 -6
- package/tests/contract.test.ts +20 -3
- package/tests/postman-assets-client.test.ts +153 -0
package/dist/cli.cjs
CHANGED
|
@@ -22777,6 +22777,7 @@ var require_stringify = __commonJS({
|
|
|
22777
22777
|
nullStr: "null",
|
|
22778
22778
|
simpleKeys: false,
|
|
22779
22779
|
singleQuote: null,
|
|
22780
|
+
trailingComma: false,
|
|
22780
22781
|
trueStr: "true",
|
|
22781
22782
|
verifyAliasOrder: true
|
|
22782
22783
|
}, doc.schema.toStringOptions, options);
|
|
@@ -23294,12 +23295,19 @@ ${indent}${line}` : "\n";
|
|
|
23294
23295
|
if (comment)
|
|
23295
23296
|
reqNewline = true;
|
|
23296
23297
|
let str = stringify2.stringify(item, itemCtx, () => comment = null);
|
|
23297
|
-
|
|
23298
|
+
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
|
|
23299
|
+
if (i < items.length - 1) {
|
|
23298
23300
|
str += ",";
|
|
23301
|
+
} else if (ctx.options.trailingComma) {
|
|
23302
|
+
if (ctx.options.lineWidth > 0) {
|
|
23303
|
+
reqNewline || (reqNewline = lines.reduce((sum, line) => sum + line.length + 2, 2) + (str.length + 2) > ctx.options.lineWidth);
|
|
23304
|
+
}
|
|
23305
|
+
if (reqNewline) {
|
|
23306
|
+
str += ",";
|
|
23307
|
+
}
|
|
23308
|
+
}
|
|
23299
23309
|
if (comment)
|
|
23300
23310
|
str += stringifyComment.lineComment(str, itemIndent, commentString(comment));
|
|
23301
|
-
if (!reqNewline && (lines.length > linesAtValue || str.includes("\n")))
|
|
23302
|
-
reqNewline = true;
|
|
23303
23311
|
lines.push(str);
|
|
23304
23312
|
linesAtValue = lines.length;
|
|
23305
23313
|
}
|
|
@@ -26313,17 +26321,22 @@ var require_compose_node = __commonJS({
|
|
|
26313
26321
|
case "block-map":
|
|
26314
26322
|
case "block-seq":
|
|
26315
26323
|
case "flow-collection":
|
|
26316
|
-
|
|
26317
|
-
|
|
26318
|
-
|
|
26324
|
+
try {
|
|
26325
|
+
node = composeCollection.composeCollection(CN, ctx, token, props, onError);
|
|
26326
|
+
if (anchor)
|
|
26327
|
+
node.anchor = anchor.source.substring(1);
|
|
26328
|
+
} catch (error) {
|
|
26329
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
26330
|
+
onError(token, "RESOURCE_EXHAUSTION", message);
|
|
26331
|
+
}
|
|
26319
26332
|
break;
|
|
26320
26333
|
default: {
|
|
26321
26334
|
const message = token.type === "error" ? token.message : `Unsupported token (type: ${token.type})`;
|
|
26322
26335
|
onError(token, "UNEXPECTED_TOKEN", message);
|
|
26323
|
-
node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError);
|
|
26324
26336
|
isSrcToken = false;
|
|
26325
26337
|
}
|
|
26326
26338
|
}
|
|
26339
|
+
node ?? (node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError));
|
|
26327
26340
|
if (anchor && node.anchor === "")
|
|
26328
26341
|
onError(anchor, "BAD_ALIAS", "Anchor cannot be an empty string");
|
|
26329
26342
|
if (atKey && ctx.options.stringKeys && (!identity.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
|
|
@@ -28687,6 +28700,7 @@ var io2 = __toESM(require_io(), 1);
|
|
|
28687
28700
|
var core = __toESM(require_core(), 1);
|
|
28688
28701
|
var exec = __toESM(require_exec(), 1);
|
|
28689
28702
|
var io = __toESM(require_io(), 1);
|
|
28703
|
+
var import_node_fs = require("node:fs");
|
|
28690
28704
|
var import_yaml = __toESM(require_dist(), 1);
|
|
28691
28705
|
|
|
28692
28706
|
// src/contracts.ts
|
|
@@ -28714,6 +28728,22 @@ var openAlphaActionContract = {
|
|
|
28714
28728
|
description: "Existing contract collection ID.",
|
|
28715
28729
|
required: false
|
|
28716
28730
|
},
|
|
28731
|
+
"collection-sync-mode": {
|
|
28732
|
+
description: "Collection lifecycle policy: reuse existing collections, refresh them from the latest spec, or version them by release label.",
|
|
28733
|
+
required: false,
|
|
28734
|
+
default: "refresh",
|
|
28735
|
+
allowedValues: ["reuse", "refresh", "version"]
|
|
28736
|
+
},
|
|
28737
|
+
"spec-sync-mode": {
|
|
28738
|
+
description: "Spec lifecycle policy: update the canonical spec or create/reuse a versioned spec for the resolved release label.",
|
|
28739
|
+
required: false,
|
|
28740
|
+
default: "update",
|
|
28741
|
+
allowedValues: ["update", "version"]
|
|
28742
|
+
},
|
|
28743
|
+
"release-label": {
|
|
28744
|
+
description: "Optional release label. When omitted for versioned sync, the action derives one from GitHub ref metadata.",
|
|
28745
|
+
required: false
|
|
28746
|
+
},
|
|
28717
28747
|
"project-name": {
|
|
28718
28748
|
description: "Service project name.",
|
|
28719
28749
|
required: true
|
|
@@ -28734,20 +28764,14 @@ var openAlphaActionContract = {
|
|
|
28734
28764
|
description: "Comma-separated workspace admin user ids.",
|
|
28735
28765
|
required: false
|
|
28736
28766
|
},
|
|
28767
|
+
"workspace-team-id": {
|
|
28768
|
+
description: "Numeric sub-team ID for org-mode workspace creation.",
|
|
28769
|
+
required: false
|
|
28770
|
+
},
|
|
28737
28771
|
"spec-url": {
|
|
28738
28772
|
description: "HTTPS URL to the OpenAPI document.",
|
|
28739
28773
|
required: true
|
|
28740
28774
|
},
|
|
28741
|
-
"environments-json": {
|
|
28742
|
-
description: "JSON array of environment slugs to preserve in bootstrap outputs.",
|
|
28743
|
-
required: false,
|
|
28744
|
-
default: '["prod"]'
|
|
28745
|
-
},
|
|
28746
|
-
"system-env-map-json": {
|
|
28747
|
-
description: "JSON map of environment slug to system environment id.",
|
|
28748
|
-
required: false,
|
|
28749
|
-
default: "{}"
|
|
28750
|
-
},
|
|
28751
28775
|
"governance-mapping-json": {
|
|
28752
28776
|
description: "JSON map of business domain to governance group name.",
|
|
28753
28777
|
required: false,
|
|
@@ -28761,19 +28785,6 @@ var openAlphaActionContract = {
|
|
|
28761
28785
|
description: "Postman access token used for governance and workspace mutations.",
|
|
28762
28786
|
required: false
|
|
28763
28787
|
},
|
|
28764
|
-
"github-token": {
|
|
28765
|
-
description: "GitHub token for repository variable persistence.",
|
|
28766
|
-
required: false
|
|
28767
|
-
},
|
|
28768
|
-
"gh-fallback-token": {
|
|
28769
|
-
description: "Fallback token for repository variable APIs.",
|
|
28770
|
-
required: false
|
|
28771
|
-
},
|
|
28772
|
-
"github-auth-mode": {
|
|
28773
|
-
description: "GitHub auth mode for repository variable APIs.",
|
|
28774
|
-
required: false,
|
|
28775
|
-
default: "github_token_first"
|
|
28776
|
-
},
|
|
28777
28788
|
"integration-backend": {
|
|
28778
28789
|
description: "Integration backend for downstream workspace connectivity.",
|
|
28779
28790
|
required: false,
|
|
@@ -28819,8 +28830,8 @@ var openAlphaActionContract = {
|
|
|
28819
28830
|
"OpenAPI operation summary normalization before upload (missing or oversized summaries)",
|
|
28820
28831
|
"spec linting by UID",
|
|
28821
28832
|
"baseline, smoke, and contract collection generation",
|
|
28833
|
+
"collection refresh and versioning policies",
|
|
28822
28834
|
"collection tagging",
|
|
28823
|
-
"GitHub repository variable persistence for downstream sync steps",
|
|
28824
28835
|
"workspace, spec, and collection outputs"
|
|
28825
28836
|
],
|
|
28826
28837
|
removedBehavior: [
|
|
@@ -28911,189 +28922,6 @@ function sanitizeHeaders(headers, secretValues) {
|
|
|
28911
28922
|
return sanitized;
|
|
28912
28923
|
}
|
|
28913
28924
|
|
|
28914
|
-
// src/lib/github/github-api-client.ts
|
|
28915
|
-
function buildErrorMessage(method, path2, response, body, masker) {
|
|
28916
|
-
const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
28917
|
-
const sanitizedBody = masker(body || "");
|
|
28918
|
-
return sanitizedBody ? masker(`${method} ${path2} failed with ${status} - ${sanitizedBody}`) : masker(`${method} ${path2} failed with ${status} - [REDACTED]`);
|
|
28919
|
-
}
|
|
28920
|
-
var GitHubApiClient = class {
|
|
28921
|
-
apiBase;
|
|
28922
|
-
authMode;
|
|
28923
|
-
appToken;
|
|
28924
|
-
fallbackToken;
|
|
28925
|
-
fetchImpl;
|
|
28926
|
-
owner;
|
|
28927
|
-
repo;
|
|
28928
|
-
repository;
|
|
28929
|
-
secretMasker;
|
|
28930
|
-
token;
|
|
28931
|
-
constructor(options) {
|
|
28932
|
-
this.apiBase = String(options.apiBase || "https://api.github.com").replace(
|
|
28933
|
-
/\/+$/,
|
|
28934
|
-
""
|
|
28935
|
-
);
|
|
28936
|
-
this.appToken = String(options.appToken || "").trim();
|
|
28937
|
-
this.authMode = options.authMode || "github_token_first";
|
|
28938
|
-
this.fallbackToken = String(options.fallbackToken || "").trim();
|
|
28939
|
-
this.fetchImpl = options.fetch ?? fetch;
|
|
28940
|
-
this.repository = options.repository;
|
|
28941
|
-
const [owner, repo] = options.repository.split("/");
|
|
28942
|
-
this.owner = owner;
|
|
28943
|
-
this.repo = repo;
|
|
28944
|
-
this.token = String(options.token || "").trim();
|
|
28945
|
-
this.secretMasker = options.secretMasker ?? createSecretMasker([this.token, this.fallbackToken, this.appToken]);
|
|
28946
|
-
}
|
|
28947
|
-
getTokenOrder() {
|
|
28948
|
-
const ordered = [];
|
|
28949
|
-
if (this.authMode === "app_token") {
|
|
28950
|
-
if (this.appToken) ordered.push(this.appToken);
|
|
28951
|
-
if (this.token && this.token !== this.appToken) ordered.push(this.token);
|
|
28952
|
-
if (this.fallbackToken && this.fallbackToken !== this.appToken && this.fallbackToken !== this.token) {
|
|
28953
|
-
ordered.push(this.fallbackToken);
|
|
28954
|
-
}
|
|
28955
|
-
return ordered;
|
|
28956
|
-
}
|
|
28957
|
-
if (this.authMode === "fallback_pat_first") {
|
|
28958
|
-
if (this.fallbackToken) ordered.push(this.fallbackToken);
|
|
28959
|
-
if (this.token && this.token !== this.fallbackToken) ordered.push(this.token);
|
|
28960
|
-
return ordered;
|
|
28961
|
-
}
|
|
28962
|
-
if (this.token) ordered.push(this.token);
|
|
28963
|
-
if (this.fallbackToken && this.fallbackToken !== this.token) {
|
|
28964
|
-
ordered.push(this.fallbackToken);
|
|
28965
|
-
}
|
|
28966
|
-
return ordered;
|
|
28967
|
-
}
|
|
28968
|
-
isVariablesEndpoint(path2) {
|
|
28969
|
-
return path2.startsWith(`/repos/${this.owner}/${this.repo}/actions/variables`);
|
|
28970
|
-
}
|
|
28971
|
-
canUseFallback(path2) {
|
|
28972
|
-
return this.isVariablesEndpoint(path2) || path2.includes(`/repos/${this.owner}/${this.repo}/contents`) || path2.includes("/dispatches");
|
|
28973
|
-
}
|
|
28974
|
-
rateLimitDelayMs(response, attempt) {
|
|
28975
|
-
const retryAfter = Number(response.headers.get("retry-after") || "");
|
|
28976
|
-
if (Number.isFinite(retryAfter) && retryAfter > 0) {
|
|
28977
|
-
return Math.min(retryAfter * 1e3, 12e4);
|
|
28978
|
-
}
|
|
28979
|
-
const resetAtSeconds = Number(response.headers.get("x-ratelimit-reset") || "");
|
|
28980
|
-
if (Number.isFinite(resetAtSeconds) && resetAtSeconds > 0) {
|
|
28981
|
-
const delta = resetAtSeconds * 1e3 - Date.now();
|
|
28982
|
-
if (delta > 0) {
|
|
28983
|
-
return Math.min(delta + 250, 12e4);
|
|
28984
|
-
}
|
|
28985
|
-
}
|
|
28986
|
-
const base = Math.min(5e3 * Math.pow(2, attempt), 12e4);
|
|
28987
|
-
const jitter = Math.floor(Math.random() * 250);
|
|
28988
|
-
return Math.min(base + jitter, 12e4);
|
|
28989
|
-
}
|
|
28990
|
-
async requestWithToken(path2, init, token) {
|
|
28991
|
-
const MAX_RETRIES = 5;
|
|
28992
|
-
const normalizedToken = String(token || "").trim();
|
|
28993
|
-
if (!normalizedToken) {
|
|
28994
|
-
throw new Error(`Missing GitHub auth token for request ${path2}`);
|
|
28995
|
-
}
|
|
28996
|
-
for (let attempt = 0; ; attempt++) {
|
|
28997
|
-
const response = await this.fetchImpl(`${this.apiBase}${path2}`, {
|
|
28998
|
-
...init,
|
|
28999
|
-
headers: {
|
|
29000
|
-
Accept: "application/vnd.github+json",
|
|
29001
|
-
Authorization: `Bearer ${normalizedToken}`,
|
|
29002
|
-
"Content-Type": "application/json",
|
|
29003
|
-
...init.headers || {}
|
|
29004
|
-
}
|
|
29005
|
-
});
|
|
29006
|
-
if (attempt < MAX_RETRIES && (response.status === 403 || response.status === 429)) {
|
|
29007
|
-
const body = await response.clone().text().catch(() => "");
|
|
29008
|
-
if (isRateLimitedResponse(response, body)) {
|
|
29009
|
-
const delay = this.rateLimitDelayMs(response, attempt);
|
|
29010
|
-
console.log(
|
|
29011
|
-
`GitHub API rate limited, retrying in ${Math.ceil(delay / 1e3)}s (attempt ${attempt + 1}/${MAX_RETRIES})...`
|
|
29012
|
-
);
|
|
29013
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
29014
|
-
continue;
|
|
29015
|
-
}
|
|
29016
|
-
}
|
|
29017
|
-
return response;
|
|
29018
|
-
}
|
|
29019
|
-
}
|
|
29020
|
-
async request(path2, init = {}) {
|
|
29021
|
-
const orderedTokens = this.getTokenOrder();
|
|
29022
|
-
if (orderedTokens.length === 0) {
|
|
29023
|
-
throw new Error("No GitHub auth token configured");
|
|
29024
|
-
}
|
|
29025
|
-
const first = await this.requestWithToken(path2, init, orderedTokens[0]);
|
|
29026
|
-
if (orderedTokens.length < 2 || !this.canUseFallback(path2)) {
|
|
29027
|
-
return first;
|
|
29028
|
-
}
|
|
29029
|
-
const isVariableGet404 = first.status === 404 && (!init.method || init.method === "GET") && this.isVariablesEndpoint(path2);
|
|
29030
|
-
if (first.status !== 403 && !isVariableGet404) {
|
|
29031
|
-
return first;
|
|
29032
|
-
}
|
|
29033
|
-
return this.requestWithToken(path2, init, orderedTokens[1]);
|
|
29034
|
-
}
|
|
29035
|
-
async setRepositoryVariable(name, value) {
|
|
29036
|
-
if (!value) {
|
|
29037
|
-
throw new Error(`Repo variable ${name} is empty`);
|
|
29038
|
-
}
|
|
29039
|
-
const path2 = `/repos/${this.repository}/actions/variables`;
|
|
29040
|
-
const body = JSON.stringify({ name, value: String(value) });
|
|
29041
|
-
const createResponse = await this.request(path2, {
|
|
29042
|
-
method: "POST",
|
|
29043
|
-
body
|
|
29044
|
-
});
|
|
29045
|
-
if (createResponse.ok || createResponse.status === 201) {
|
|
29046
|
-
return;
|
|
29047
|
-
}
|
|
29048
|
-
if (createResponse.status === 409 || createResponse.status === 422) {
|
|
29049
|
-
const updatePath = `/repos/${this.repository}/actions/variables/${name}`;
|
|
29050
|
-
const updateResponse = await this.request(updatePath, {
|
|
29051
|
-
method: "PATCH",
|
|
29052
|
-
body
|
|
29053
|
-
});
|
|
29054
|
-
if (updateResponse.ok) {
|
|
29055
|
-
return;
|
|
29056
|
-
}
|
|
29057
|
-
const text2 = await updateResponse.text().catch(() => "");
|
|
29058
|
-
throw new Error(
|
|
29059
|
-
buildErrorMessage("PATCH", updatePath, updateResponse, text2, this.secretMasker)
|
|
29060
|
-
);
|
|
29061
|
-
}
|
|
29062
|
-
const text = await createResponse.text().catch(() => "");
|
|
29063
|
-
throw new Error(
|
|
29064
|
-
buildErrorMessage("POST", path2, createResponse, text, this.secretMasker)
|
|
29065
|
-
);
|
|
29066
|
-
}
|
|
29067
|
-
async getRepositoryVariable(name) {
|
|
29068
|
-
const path2 = `/repos/${this.repository}/actions/variables/${name}`;
|
|
29069
|
-
const response = await this.request(path2, {
|
|
29070
|
-
method: "GET"
|
|
29071
|
-
});
|
|
29072
|
-
if (response.status === 404) {
|
|
29073
|
-
return "";
|
|
29074
|
-
}
|
|
29075
|
-
if (!response.ok) {
|
|
29076
|
-
const text = await response.text().catch(() => "");
|
|
29077
|
-
throw new Error(
|
|
29078
|
-
buildErrorMessage("GET", path2, response, text, this.secretMasker)
|
|
29079
|
-
);
|
|
29080
|
-
}
|
|
29081
|
-
const data = await response.json();
|
|
29082
|
-
return String(data.value || "");
|
|
29083
|
-
}
|
|
29084
|
-
};
|
|
29085
|
-
function isRateLimitedResponse(response, body) {
|
|
29086
|
-
if (response.status !== 403 && response.status !== 429) return false;
|
|
29087
|
-
const remaining = response.headers.get("x-ratelimit-remaining");
|
|
29088
|
-
const retryAfter = response.headers.get("retry-after");
|
|
29089
|
-
if (remaining === "0") return true;
|
|
29090
|
-
if (retryAfter) return true;
|
|
29091
|
-
const message = body.toLowerCase();
|
|
29092
|
-
if (message.includes("secondary rate limit")) return true;
|
|
29093
|
-
if (message.includes("api rate limit exceeded")) return true;
|
|
29094
|
-
return response.status === 429;
|
|
29095
|
-
}
|
|
29096
|
-
|
|
29097
28925
|
// src/lib/http-error.ts
|
|
29098
28926
|
function truncate(value, limit) {
|
|
29099
28927
|
if (value.length <= limit) {
|
|
@@ -29276,6 +29104,16 @@ var PostmanAssetsClient = class {
|
|
|
29276
29104
|
}
|
|
29277
29105
|
return void 0;
|
|
29278
29106
|
}
|
|
29107
|
+
async getTeams() {
|
|
29108
|
+
const data = await this.request("/teams");
|
|
29109
|
+
const teams = data?.data ?? [];
|
|
29110
|
+
return Array.isArray(teams) ? teams.filter((t) => t?.id && t?.name).map((t) => ({
|
|
29111
|
+
id: Number(t.id),
|
|
29112
|
+
name: String(t.name),
|
|
29113
|
+
handle: String(t.handle || ""),
|
|
29114
|
+
...t.organizationId != null ? { organizationId: Number(t.organizationId) } : {}
|
|
29115
|
+
})) : [];
|
|
29116
|
+
}
|
|
29279
29117
|
async request(path2, init = {}) {
|
|
29280
29118
|
const url = path2.startsWith("http") ? path2 : `${this.baseUrl}${path2}`;
|
|
29281
29119
|
const response = await this.fetchImpl(url, {
|
|
@@ -29304,13 +29142,14 @@ var PostmanAssetsClient = class {
|
|
|
29304
29142
|
return null;
|
|
29305
29143
|
}
|
|
29306
29144
|
}
|
|
29307
|
-
async createWorkspace(name, about) {
|
|
29145
|
+
async createWorkspace(name, about, targetTeamId) {
|
|
29308
29146
|
return retry(async () => {
|
|
29309
29147
|
const payload = {
|
|
29310
29148
|
workspace: {
|
|
29311
29149
|
about,
|
|
29312
29150
|
name,
|
|
29313
|
-
type: "team"
|
|
29151
|
+
type: "team",
|
|
29152
|
+
...targetTeamId != null && !Number.isNaN(targetTeamId) ? { teamId: targetTeamId } : {}
|
|
29314
29153
|
}
|
|
29315
29154
|
};
|
|
29316
29155
|
let created;
|
|
@@ -29322,7 +29161,7 @@ var PostmanAssetsClient = class {
|
|
|
29322
29161
|
} catch (err) {
|
|
29323
29162
|
if (err instanceof Error && err.message.includes("Only personal workspaces")) {
|
|
29324
29163
|
throw new Error(
|
|
29325
|
-
"Workspace creation failed:
|
|
29164
|
+
"Workspace creation failed: This may be an Org-mode account that requires a workspace-team-id input. The Postman API does not allow creating team workspaces at the organization level. Use the workspace-team-id input to specify which sub-team should own this workspace."
|
|
29326
29165
|
);
|
|
29327
29166
|
}
|
|
29328
29167
|
throw err;
|
|
@@ -29341,7 +29180,11 @@ var PostmanAssetsClient = class {
|
|
|
29341
29180
|
return {
|
|
29342
29181
|
id: workspaceId
|
|
29343
29182
|
};
|
|
29344
|
-
}, {
|
|
29183
|
+
}, {
|
|
29184
|
+
maxAttempts: 3,
|
|
29185
|
+
delayMs: 2e3,
|
|
29186
|
+
shouldRetry: (err) => !(err instanceof Error && err.message.includes("workspace-team-id"))
|
|
29187
|
+
});
|
|
29345
29188
|
}
|
|
29346
29189
|
async listWorkspaces() {
|
|
29347
29190
|
const data = await this.request("/workspaces");
|
|
@@ -30153,31 +29996,17 @@ function requireInput(actionCore, name) {
|
|
|
30153
29996
|
function optionalInput(actionCore, name) {
|
|
30154
29997
|
return normalizeInputValue(actionCore.getInput(name));
|
|
30155
29998
|
}
|
|
30156
|
-
function
|
|
30157
|
-
|
|
30158
|
-
return
|
|
30159
|
-
} catch (error) {
|
|
30160
|
-
throw new Error(
|
|
30161
|
-
`Invalid JSON for ${inputName}: ${error instanceof Error ? error.message : String(error)}`
|
|
30162
|
-
);
|
|
29999
|
+
function parseCollectionSyncMode(value) {
|
|
30000
|
+
if (value === "reuse" || value === "version") {
|
|
30001
|
+
return value;
|
|
30163
30002
|
}
|
|
30003
|
+
return "refresh";
|
|
30164
30004
|
}
|
|
30165
|
-
function
|
|
30166
|
-
if (
|
|
30167
|
-
|
|
30005
|
+
function parseSpecSyncMode(value) {
|
|
30006
|
+
if (value === "version") {
|
|
30007
|
+
return value;
|
|
30168
30008
|
}
|
|
30169
|
-
return
|
|
30170
|
-
}
|
|
30171
|
-
function asStringMap(value, inputName) {
|
|
30172
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30173
|
-
throw new Error(`${inputName} must be a JSON object`);
|
|
30174
|
-
}
|
|
30175
|
-
return Object.fromEntries(
|
|
30176
|
-
Object.entries(value).map(([key, entry]) => [
|
|
30177
|
-
key,
|
|
30178
|
-
String(entry)
|
|
30179
|
-
])
|
|
30180
|
-
);
|
|
30009
|
+
return "update";
|
|
30181
30010
|
}
|
|
30182
30011
|
function resolveInputs(env = process.env) {
|
|
30183
30012
|
const repoContext = detectRepoContext(
|
|
@@ -30205,28 +30034,31 @@ function resolveInputs(env = process.env) {
|
|
|
30205
30034
|
}
|
|
30206
30035
|
}
|
|
30207
30036
|
return {
|
|
30208
|
-
projectName: getInput("project-name", env) ?? "",
|
|
30037
|
+
projectName: getInput("project-name", env) ?? env.GITHUB_REPOSITORY?.split("/").pop() ?? env.CI_PROJECT_NAME ?? "",
|
|
30209
30038
|
workspaceId: getInput("workspace-id", env),
|
|
30210
30039
|
specId: getInput("spec-id", env),
|
|
30211
30040
|
baselineCollectionId: getInput("baseline-collection-id", env),
|
|
30212
30041
|
smokeCollectionId: getInput("smoke-collection-id", env),
|
|
30213
30042
|
contractCollectionId: getInput("contract-collection-id", env),
|
|
30043
|
+
collectionSyncMode: parseCollectionSyncMode(getInput("collection-sync-mode", env)),
|
|
30044
|
+
specSyncMode: parseSpecSyncMode(getInput("spec-sync-mode", env)),
|
|
30045
|
+
releaseLabel: getInput("release-label", env),
|
|
30214
30046
|
domain: getInput("domain", env),
|
|
30215
30047
|
domainCode: getInput("domain-code", env),
|
|
30216
30048
|
requesterEmail: getInput("requester-email", env),
|
|
30217
30049
|
workspaceAdminUserIds: getInput("workspace-admin-user-ids", env) || env.WORKSPACE_ADMIN_USER_IDS || "",
|
|
30050
|
+
workspaceTeamId: getInput("workspace-team-id", env) || env.POSTMAN_WORKSPACE_TEAM_ID,
|
|
30218
30051
|
teamId: getInput("team-id", env) || env.POSTMAN_TEAM_ID || "",
|
|
30219
30052
|
repoUrl: repoContext.repoUrl || "",
|
|
30220
30053
|
specUrl,
|
|
30221
|
-
environmentsJson: getInput("environments-json", env) ?? openAlphaActionContract.inputs["environments-json"].default ?? '["prod"]',
|
|
30222
|
-
systemEnvMapJson: getInput("system-env-map-json", env) ?? openAlphaActionContract.inputs["system-env-map-json"].default ?? "{}",
|
|
30223
30054
|
governanceMappingJson: getInput("governance-mapping-json", env) ?? openAlphaActionContract.inputs["governance-mapping-json"].default ?? "{}",
|
|
30224
30055
|
postmanApiKey: getInput("postman-api-key", env) ?? "",
|
|
30225
30056
|
postmanAccessToken: getInput("postman-access-token", env),
|
|
30226
|
-
|
|
30227
|
-
|
|
30228
|
-
|
|
30229
|
-
|
|
30057
|
+
integrationBackend,
|
|
30058
|
+
githubRefName: env.GITHUB_REF_NAME,
|
|
30059
|
+
githubHeadRef: env.GITHUB_HEAD_REF,
|
|
30060
|
+
githubRef: env.GITHUB_REF,
|
|
30061
|
+
githubSha: env.GITHUB_SHA
|
|
30230
30062
|
};
|
|
30231
30063
|
}
|
|
30232
30064
|
function createPlannedOutputs(inputs) {
|
|
@@ -30257,12 +30089,8 @@ function readActionInputs(actionCore) {
|
|
|
30257
30089
|
const specUrl = requireInput(actionCore, "spec-url");
|
|
30258
30090
|
const postmanApiKey = requireInput(actionCore, "postman-api-key");
|
|
30259
30091
|
const postmanAccessToken = optionalInput(actionCore, "postman-access-token");
|
|
30260
|
-
const githubToken = optionalInput(actionCore, "github-token");
|
|
30261
|
-
const ghFallbackToken = optionalInput(actionCore, "gh-fallback-token");
|
|
30262
30092
|
actionCore.setSecret(postmanApiKey);
|
|
30263
30093
|
if (postmanAccessToken) actionCore.setSecret(postmanAccessToken);
|
|
30264
|
-
if (githubToken) actionCore.setSecret(githubToken);
|
|
30265
|
-
if (ghFallbackToken) actionCore.setSecret(ghFallbackToken);
|
|
30266
30094
|
const inputs = resolveInputs({
|
|
30267
30095
|
...process.env,
|
|
30268
30096
|
INPUT_PROJECT_NAME: projectName,
|
|
@@ -30271,6 +30099,9 @@ function readActionInputs(actionCore) {
|
|
|
30271
30099
|
INPUT_BASELINE_COLLECTION_ID: optionalInput(actionCore, "baseline-collection-id"),
|
|
30272
30100
|
INPUT_SMOKE_COLLECTION_ID: optionalInput(actionCore, "smoke-collection-id"),
|
|
30273
30101
|
INPUT_CONTRACT_COLLECTION_ID: optionalInput(actionCore, "contract-collection-id"),
|
|
30102
|
+
INPUT_COLLECTION_SYNC_MODE: optionalInput(actionCore, "collection-sync-mode") ?? openAlphaActionContract.inputs["collection-sync-mode"].default,
|
|
30103
|
+
INPUT_SPEC_SYNC_MODE: optionalInput(actionCore, "spec-sync-mode") ?? openAlphaActionContract.inputs["spec-sync-mode"].default,
|
|
30104
|
+
INPUT_RELEASE_LABEL: optionalInput(actionCore, "release-label"),
|
|
30274
30105
|
INPUT_DOMAIN: optionalInput(actionCore, "domain"),
|
|
30275
30106
|
INPUT_DOMAIN_CODE: optionalInput(actionCore, "domain-code"),
|
|
30276
30107
|
INPUT_REQUESTER_EMAIL: optionalInput(actionCore, "requester-email"),
|
|
@@ -30278,17 +30109,13 @@ function readActionInputs(actionCore) {
|
|
|
30278
30109
|
actionCore,
|
|
30279
30110
|
"workspace-admin-user-ids"
|
|
30280
30111
|
),
|
|
30112
|
+
INPUT_WORKSPACE_TEAM_ID: optionalInput(actionCore, "workspace-team-id") || process.env.POSTMAN_WORKSPACE_TEAM_ID,
|
|
30281
30113
|
INPUT_TEAM_ID: optionalInput(actionCore, "postman-team-id") || process.env.POSTMAN_TEAM_ID,
|
|
30282
30114
|
INPUT_REPO_URL: optionalInput(actionCore, "repo-url"),
|
|
30283
30115
|
INPUT_SPEC_URL: specUrl,
|
|
30284
|
-
INPUT_ENVIRONMENTS_JSON: optionalInput(actionCore, "environments-json") ?? openAlphaActionContract.inputs["environments-json"].default,
|
|
30285
|
-
INPUT_SYSTEM_ENV_MAP_JSON: optionalInput(actionCore, "system-env-map-json") ?? openAlphaActionContract.inputs["system-env-map-json"].default,
|
|
30286
30116
|
INPUT_GOVERNANCE_MAPPING_JSON: optionalInput(actionCore, "governance-mapping-json") ?? openAlphaActionContract.inputs["governance-mapping-json"].default,
|
|
30287
30117
|
INPUT_POSTMAN_API_KEY: postmanApiKey,
|
|
30288
30118
|
INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
|
|
30289
|
-
INPUT_GITHUB_TOKEN: githubToken,
|
|
30290
|
-
INPUT_GH_FALLBACK_TOKEN: ghFallbackToken,
|
|
30291
|
-
INPUT_GITHUB_AUTH_MODE: optionalInput(actionCore, "github-auth-mode") ?? openAlphaActionContract.inputs["github-auth-mode"].default,
|
|
30292
30119
|
INPUT_INTEGRATION_BACKEND: optionalInput(actionCore, "integration-backend") ?? openAlphaActionContract.inputs["integration-backend"].default
|
|
30293
30120
|
});
|
|
30294
30121
|
return inputs;
|
|
@@ -30365,6 +30192,45 @@ async function fetchSpecDocument(specUrl, specFetcher) {
|
|
|
30365
30192
|
}
|
|
30366
30193
|
);
|
|
30367
30194
|
}
|
|
30195
|
+
function normalizeReleaseLabel(value) {
|
|
30196
|
+
const trimmed = String(value || "").trim();
|
|
30197
|
+
if (!trimmed) {
|
|
30198
|
+
return void 0;
|
|
30199
|
+
}
|
|
30200
|
+
return trimmed.replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "").replace(/^refs\/pull\//, "pull-").replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || void 0;
|
|
30201
|
+
}
|
|
30202
|
+
function deriveReleaseLabel(inputs) {
|
|
30203
|
+
if (inputs.releaseLabel) {
|
|
30204
|
+
return normalizeReleaseLabel(inputs.releaseLabel);
|
|
30205
|
+
}
|
|
30206
|
+
return normalizeReleaseLabel(inputs.githubRefName) ?? normalizeReleaseLabel(inputs.githubHeadRef) ?? normalizeReleaseLabel(inputs.githubRef);
|
|
30207
|
+
}
|
|
30208
|
+
function createAssetProjectName(inputs, releaseLabel) {
|
|
30209
|
+
if (!releaseLabel) {
|
|
30210
|
+
return inputs.projectName;
|
|
30211
|
+
}
|
|
30212
|
+
return `${inputs.projectName} ${releaseLabel}`;
|
|
30213
|
+
}
|
|
30214
|
+
function readResourcesState() {
|
|
30215
|
+
try {
|
|
30216
|
+
return (0, import_yaml.parse)((0, import_node_fs.readFileSync)(".postman/resources.yaml", "utf8"));
|
|
30217
|
+
} catch {
|
|
30218
|
+
return null;
|
|
30219
|
+
}
|
|
30220
|
+
}
|
|
30221
|
+
function getFirstCloudResourceId(map) {
|
|
30222
|
+
if (!map) {
|
|
30223
|
+
return void 0;
|
|
30224
|
+
}
|
|
30225
|
+
return Object.values(map)[0];
|
|
30226
|
+
}
|
|
30227
|
+
function findCloudResourceId(map, matcher) {
|
|
30228
|
+
if (!map) {
|
|
30229
|
+
return void 0;
|
|
30230
|
+
}
|
|
30231
|
+
const match = Object.entries(map).find(([filePath]) => matcher(filePath));
|
|
30232
|
+
return match?.[1];
|
|
30233
|
+
}
|
|
30368
30234
|
var SPEC_SUMMARY_MAX_LEN = 200;
|
|
30369
30235
|
var SPEC_HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
30370
30236
|
"get",
|
|
@@ -30453,122 +30319,28 @@ function validateSpecStructure(content) {
|
|
|
30453
30319
|
throw new Error('Spec is missing "openapi" or "swagger" version field');
|
|
30454
30320
|
}
|
|
30455
30321
|
}
|
|
30456
|
-
function varName(projectName, baseName) {
|
|
30457
|
-
const slug = projectName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
30458
|
-
return `POSTMAN_${slug}_${baseName}`;
|
|
30459
|
-
}
|
|
30460
|
-
async function readVariable(github, projectName, baseName) {
|
|
30461
|
-
if (!github) {
|
|
30462
|
-
return void 0;
|
|
30463
|
-
}
|
|
30464
|
-
const namespaced = await github.getRepositoryVariable(varName(projectName, baseName)).catch(() => void 0);
|
|
30465
|
-
if (namespaced) {
|
|
30466
|
-
return namespaced;
|
|
30467
|
-
}
|
|
30468
|
-
const legacy = await github.getRepositoryVariable(`POSTMAN_${baseName}`).catch(() => void 0);
|
|
30469
|
-
return legacy || void 0;
|
|
30470
|
-
}
|
|
30471
|
-
async function persistVariable(github, name, value, actionCore) {
|
|
30472
|
-
if (!github || !value) {
|
|
30473
|
-
return;
|
|
30474
|
-
}
|
|
30475
|
-
try {
|
|
30476
|
-
await github.setRepositoryVariable(name, value);
|
|
30477
|
-
} catch (err) {
|
|
30478
|
-
actionCore.warning(
|
|
30479
|
-
`Failed to persist ${name}: ${err instanceof Error ? err.message : String(err)}`
|
|
30480
|
-
);
|
|
30481
|
-
}
|
|
30482
|
-
}
|
|
30483
|
-
async function writeVariable(github, projectName, baseName, value, actionCore) {
|
|
30484
|
-
if (!github || !value) {
|
|
30485
|
-
return;
|
|
30486
|
-
}
|
|
30487
|
-
await persistVariable(github, varName(projectName, baseName), value, actionCore);
|
|
30488
|
-
await persistVariable(github, `POSTMAN_${baseName}`, value, actionCore);
|
|
30489
|
-
}
|
|
30490
|
-
async function persistBootstrapRepositoryVariables(github, projectName, outputs, systemEnvMap, environments, lintSummary, actionCore) {
|
|
30491
|
-
await persistVariable(
|
|
30492
|
-
github,
|
|
30493
|
-
"LINT_WARNINGS",
|
|
30494
|
-
String(lintSummary.lintWarnings),
|
|
30495
|
-
actionCore
|
|
30496
|
-
);
|
|
30497
|
-
await persistVariable(
|
|
30498
|
-
github,
|
|
30499
|
-
"LINT_ERRORS",
|
|
30500
|
-
String(lintSummary.lintErrors),
|
|
30501
|
-
actionCore
|
|
30502
|
-
);
|
|
30503
|
-
await writeVariable(
|
|
30504
|
-
github,
|
|
30505
|
-
projectName,
|
|
30506
|
-
"WORKSPACE_ID",
|
|
30507
|
-
outputs["workspace-id"],
|
|
30508
|
-
actionCore
|
|
30509
|
-
);
|
|
30510
|
-
await writeVariable(github, projectName, "SPEC_UID", outputs["spec-id"], actionCore);
|
|
30511
|
-
await writeVariable(
|
|
30512
|
-
github,
|
|
30513
|
-
projectName,
|
|
30514
|
-
"BASELINE_COLLECTION_UID",
|
|
30515
|
-
outputs["baseline-collection-id"],
|
|
30516
|
-
actionCore
|
|
30517
|
-
);
|
|
30518
|
-
await writeVariable(
|
|
30519
|
-
github,
|
|
30520
|
-
projectName,
|
|
30521
|
-
"SMOKE_COLLECTION_UID",
|
|
30522
|
-
outputs["smoke-collection-id"],
|
|
30523
|
-
actionCore
|
|
30524
|
-
);
|
|
30525
|
-
await writeVariable(
|
|
30526
|
-
github,
|
|
30527
|
-
projectName,
|
|
30528
|
-
"CONTRACT_COLLECTION_UID",
|
|
30529
|
-
outputs["contract-collection-id"],
|
|
30530
|
-
actionCore
|
|
30531
|
-
);
|
|
30532
|
-
for (const envName of environments) {
|
|
30533
|
-
const systemEnvId = systemEnvMap[envName];
|
|
30534
|
-
if (!systemEnvId) {
|
|
30535
|
-
continue;
|
|
30536
|
-
}
|
|
30537
|
-
await writeVariable(
|
|
30538
|
-
github,
|
|
30539
|
-
projectName,
|
|
30540
|
-
`SYSTEM_ENV_${envName.toUpperCase()}`,
|
|
30541
|
-
systemEnvId,
|
|
30542
|
-
actionCore
|
|
30543
|
-
);
|
|
30544
|
-
}
|
|
30545
|
-
}
|
|
30546
30322
|
async function runBootstrap(inputs, dependencies) {
|
|
30547
30323
|
const outputs = createPlannedOutputs(inputs);
|
|
30548
|
-
const
|
|
30549
|
-
|
|
30550
|
-
|
|
30551
|
-
|
|
30552
|
-
|
|
30553
|
-
|
|
30554
|
-
|
|
30555
|
-
);
|
|
30324
|
+
const requiresReleaseLabel = inputs.collectionSyncMode === "version" || inputs.specSyncMode === "version";
|
|
30325
|
+
const releaseLabel = requiresReleaseLabel ? deriveReleaseLabel(inputs) : void 0;
|
|
30326
|
+
if (requiresReleaseLabel && !releaseLabel) {
|
|
30327
|
+
throw new Error(
|
|
30328
|
+
"Versioned spec or collection sync requires a release-label or derivable GitHub ref metadata"
|
|
30329
|
+
);
|
|
30330
|
+
}
|
|
30556
30331
|
const workspaceName = createWorkspaceName(inputs);
|
|
30557
30332
|
const aboutText = `Auto-provisioned by Postman CS open-alpha for ${inputs.projectName}`;
|
|
30558
30333
|
await runGroup(dependencies.core, "Install Postman CLI", async () => {
|
|
30559
30334
|
await ensurePostmanCli(dependencies, inputs.postmanApiKey);
|
|
30560
30335
|
});
|
|
30561
|
-
const
|
|
30562
|
-
let
|
|
30563
|
-
|
|
30564
|
-
|
|
30565
|
-
|
|
30566
|
-
dependencies.github,
|
|
30567
|
-
inputs.projectName,
|
|
30568
|
-
"WORKSPACE_ID"
|
|
30569
|
-
);
|
|
30570
|
-
workspaceId = repoWorkspaceId;
|
|
30336
|
+
const resourcesState = readResourcesState();
|
|
30337
|
+
let explicitWorkspaceId = inputs.workspaceId;
|
|
30338
|
+
if (!explicitWorkspaceId && resourcesState?.workspace?.id) {
|
|
30339
|
+
explicitWorkspaceId = resourcesState.workspace.id;
|
|
30340
|
+
dependencies.core.info("Resolved workspace-id from .postman/resources.yaml");
|
|
30571
30341
|
}
|
|
30342
|
+
const repoWorkspaceId = explicitWorkspaceId;
|
|
30343
|
+
let workspaceId = explicitWorkspaceId;
|
|
30572
30344
|
let teamId = inputs.teamId || "";
|
|
30573
30345
|
if (!teamId) {
|
|
30574
30346
|
teamId = await dependencies.postman.getAutoDerivedTeamId() || "";
|
|
@@ -30602,24 +30374,65 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30602
30374
|
} else if (workspaceId) {
|
|
30603
30375
|
dependencies.core.info(`Using existing workspace: ${workspaceId}`);
|
|
30604
30376
|
}
|
|
30377
|
+
let workspaceTeamId;
|
|
30378
|
+
if (inputs.workspaceTeamId) {
|
|
30379
|
+
workspaceTeamId = parseInt(inputs.workspaceTeamId, 10);
|
|
30380
|
+
if (Number.isNaN(workspaceTeamId)) {
|
|
30381
|
+
throw new Error(`workspace-team-id must be a numeric sub-team ID, got: ${inputs.workspaceTeamId}`);
|
|
30382
|
+
}
|
|
30383
|
+
}
|
|
30384
|
+
if (!workspaceId && !workspaceTeamId) {
|
|
30385
|
+
try {
|
|
30386
|
+
const teams = await dependencies.postman.getTeams();
|
|
30387
|
+
if (teams.length > 1 && teams.every((t) => t.organizationId == null)) {
|
|
30388
|
+
dependencies.core.warning(
|
|
30389
|
+
"GET /teams returned multiple teams but none include organizationId. Org-mode detection may be degraded due to an upstream API change. If workspace creation fails, set workspace-team-id explicitly."
|
|
30390
|
+
);
|
|
30391
|
+
}
|
|
30392
|
+
const orgIds = new Set(teams.filter((t) => t.organizationId != null).map((t) => t.organizationId));
|
|
30393
|
+
const meTeamId = parseInt(teamId, 10);
|
|
30394
|
+
const isOrgMode = teams.length > 1 && orgIds.size === 1 && orgIds.has(meTeamId);
|
|
30395
|
+
if (isOrgMode) {
|
|
30396
|
+
const teamList = teams.map((t) => ` ${t.id} ${t.name}`).join("\n");
|
|
30397
|
+
throw new Error(
|
|
30398
|
+
`Org-mode account detected. Workspace creation requires a specific sub-team ID.
|
|
30399
|
+
|
|
30400
|
+
Available sub-teams:
|
|
30401
|
+
${teamList}
|
|
30402
|
+
|
|
30403
|
+
To fix this, set the workspace-team-id input in your workflow:
|
|
30404
|
+
workspace-team-id: '<id>'
|
|
30405
|
+
|
|
30406
|
+
Or for reuse across runs, create a repository variable and reference it:
|
|
30407
|
+
workspace-team-id: \${{ vars.POSTMAN_WORKSPACE_TEAM_ID }}
|
|
30408
|
+
|
|
30409
|
+
For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID=<id>.`
|
|
30410
|
+
);
|
|
30411
|
+
} else if (teams.length > 1) {
|
|
30412
|
+
dependencies.core.warning(
|
|
30413
|
+
`API key has access to ${teams.length} teams but org-mode could not be confirmed. Proceeding without teamId. If workspace creation fails, set workspace-team-id explicitly.`
|
|
30414
|
+
);
|
|
30415
|
+
}
|
|
30416
|
+
} catch (err) {
|
|
30417
|
+
if (err instanceof Error && err.message.includes("Org-mode account detected")) {
|
|
30418
|
+
throw err;
|
|
30419
|
+
}
|
|
30420
|
+
dependencies.core.warning(
|
|
30421
|
+
`Could not check for org-mode sub-teams: ${err instanceof Error ? err.message : String(err)}`
|
|
30422
|
+
);
|
|
30423
|
+
}
|
|
30424
|
+
}
|
|
30605
30425
|
if (!workspaceId) {
|
|
30606
30426
|
const workspace = await runGroup(
|
|
30607
30427
|
dependencies.core,
|
|
30608
30428
|
"Create Postman Workspace",
|
|
30609
|
-
async () => dependencies.postman.createWorkspace(workspaceName, aboutText)
|
|
30429
|
+
async () => dependencies.postman.createWorkspace(workspaceName, aboutText, workspaceTeamId)
|
|
30610
30430
|
);
|
|
30611
30431
|
workspaceId = workspace.id;
|
|
30612
30432
|
}
|
|
30613
30433
|
outputs["workspace-id"] = workspaceId || "";
|
|
30614
30434
|
outputs["workspace-url"] = `https://go.postman.co/workspace/${workspaceId}`;
|
|
30615
30435
|
outputs["workspace-name"] = workspaceName;
|
|
30616
|
-
await writeVariable(
|
|
30617
|
-
dependencies.github,
|
|
30618
|
-
inputs.projectName,
|
|
30619
|
-
"WORKSPACE_ID",
|
|
30620
|
-
outputs["workspace-id"],
|
|
30621
|
-
dependencies.core
|
|
30622
|
-
);
|
|
30623
30436
|
if (inputs.domain && dependencies.internalIntegration) {
|
|
30624
30437
|
await runGroup(
|
|
30625
30438
|
dependencies.core,
|
|
@@ -30674,33 +30487,43 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30674
30487
|
);
|
|
30675
30488
|
}
|
|
30676
30489
|
let specId = inputs.specId;
|
|
30677
|
-
if (!specId
|
|
30678
|
-
specId =
|
|
30490
|
+
if (!specId) {
|
|
30491
|
+
specId = getFirstCloudResourceId(resourcesState?.cloudResources?.specs);
|
|
30492
|
+
if (specId) {
|
|
30493
|
+
dependencies.core.info("Resolved spec-id from .postman/resources.yaml");
|
|
30494
|
+
}
|
|
30679
30495
|
}
|
|
30680
|
-
let baselineCollectionId = inputs.baselineCollectionId;
|
|
30681
|
-
let smokeCollectionId = inputs.smokeCollectionId;
|
|
30682
|
-
let contractCollectionId = inputs.contractCollectionId;
|
|
30683
|
-
if (
|
|
30496
|
+
let baselineCollectionId = inputs.collectionSyncMode === "refresh" ? void 0 : inputs.baselineCollectionId;
|
|
30497
|
+
let smokeCollectionId = inputs.collectionSyncMode === "refresh" ? void 0 : inputs.smokeCollectionId;
|
|
30498
|
+
let contractCollectionId = inputs.collectionSyncMode === "refresh" ? void 0 : inputs.contractCollectionId;
|
|
30499
|
+
if (inputs.collectionSyncMode !== "refresh") {
|
|
30500
|
+
const cloudCollections = resourcesState?.cloudResources?.collections;
|
|
30684
30501
|
if (!baselineCollectionId) {
|
|
30685
|
-
baselineCollectionId =
|
|
30686
|
-
|
|
30687
|
-
|
|
30688
|
-
"BASELINE_COLLECTION_UID"
|
|
30502
|
+
baselineCollectionId = findCloudResourceId(
|
|
30503
|
+
cloudCollections,
|
|
30504
|
+
(filePath) => filePath.includes("[Baseline]")
|
|
30689
30505
|
);
|
|
30506
|
+
if (baselineCollectionId) {
|
|
30507
|
+
dependencies.core.info("Resolved baseline-collection-id from .postman/resources.yaml");
|
|
30508
|
+
}
|
|
30690
30509
|
}
|
|
30691
30510
|
if (!smokeCollectionId) {
|
|
30692
|
-
smokeCollectionId =
|
|
30693
|
-
|
|
30694
|
-
|
|
30695
|
-
"SMOKE_COLLECTION_UID"
|
|
30511
|
+
smokeCollectionId = findCloudResourceId(
|
|
30512
|
+
cloudCollections,
|
|
30513
|
+
(filePath) => filePath.includes("[Smoke]")
|
|
30696
30514
|
);
|
|
30515
|
+
if (smokeCollectionId) {
|
|
30516
|
+
dependencies.core.info("Resolved smoke-collection-id from .postman/resources.yaml");
|
|
30517
|
+
}
|
|
30697
30518
|
}
|
|
30698
30519
|
if (!contractCollectionId) {
|
|
30699
|
-
contractCollectionId =
|
|
30700
|
-
|
|
30701
|
-
|
|
30702
|
-
"CONTRACT_COLLECTION_UID"
|
|
30520
|
+
contractCollectionId = findCloudResourceId(
|
|
30521
|
+
cloudCollections,
|
|
30522
|
+
(filePath) => filePath.includes("[Contract]")
|
|
30703
30523
|
);
|
|
30524
|
+
if (contractCollectionId) {
|
|
30525
|
+
dependencies.core.info("Resolved contract-collection-id from .postman/resources.yaml");
|
|
30526
|
+
}
|
|
30704
30527
|
}
|
|
30705
30528
|
}
|
|
30706
30529
|
if (specId) {
|
|
@@ -30724,7 +30547,10 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30724
30547
|
} else {
|
|
30725
30548
|
specId = await dependencies.postman.uploadSpec(
|
|
30726
30549
|
workspaceId || "",
|
|
30727
|
-
|
|
30550
|
+
createAssetProjectName(
|
|
30551
|
+
inputs,
|
|
30552
|
+
inputs.specSyncMode === "version" ? releaseLabel : void 0
|
|
30553
|
+
),
|
|
30728
30554
|
document
|
|
30729
30555
|
);
|
|
30730
30556
|
}
|
|
@@ -30733,13 +30559,6 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30733
30559
|
}
|
|
30734
30560
|
);
|
|
30735
30561
|
void specContent;
|
|
30736
|
-
await writeVariable(
|
|
30737
|
-
dependencies.github,
|
|
30738
|
-
inputs.projectName,
|
|
30739
|
-
"SPEC_UID",
|
|
30740
|
-
outputs["spec-id"],
|
|
30741
|
-
dependencies.core
|
|
30742
|
-
);
|
|
30743
30562
|
const lintSummary = await runGroup(
|
|
30744
30563
|
dependencies.core,
|
|
30745
30564
|
"Lint Spec via Postman CLI",
|
|
@@ -30777,13 +30596,15 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30777
30596
|
dependencies.core,
|
|
30778
30597
|
"Generate Collections from Spec",
|
|
30779
30598
|
async () => {
|
|
30780
|
-
|
|
30781
|
-
|
|
30782
|
-
outputs["
|
|
30599
|
+
const shouldReuseCollections = inputs.collectionSyncMode !== "refresh";
|
|
30600
|
+
const assetProjectName = inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
|
|
30601
|
+
outputs["baseline-collection-id"] = shouldReuseCollections ? baselineCollectionId || "" : "";
|
|
30602
|
+
outputs["smoke-collection-id"] = shouldReuseCollections ? smokeCollectionId || "" : "";
|
|
30603
|
+
outputs["contract-collection-id"] = shouldReuseCollections ? contractCollectionId || "" : "";
|
|
30783
30604
|
if (!outputs["baseline-collection-id"]) {
|
|
30784
30605
|
outputs["baseline-collection-id"] = await dependencies.postman.generateCollection(
|
|
30785
30606
|
outputs["spec-id"],
|
|
30786
|
-
|
|
30607
|
+
assetProjectName,
|
|
30787
30608
|
"[Baseline]"
|
|
30788
30609
|
);
|
|
30789
30610
|
} else {
|
|
@@ -30791,17 +30612,10 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30791
30612
|
`Using existing baseline collection: ${outputs["baseline-collection-id"]}`
|
|
30792
30613
|
);
|
|
30793
30614
|
}
|
|
30794
|
-
await writeVariable(
|
|
30795
|
-
dependencies.github,
|
|
30796
|
-
inputs.projectName,
|
|
30797
|
-
"BASELINE_COLLECTION_UID",
|
|
30798
|
-
outputs["baseline-collection-id"],
|
|
30799
|
-
dependencies.core
|
|
30800
|
-
);
|
|
30801
30615
|
if (!outputs["smoke-collection-id"]) {
|
|
30802
30616
|
outputs["smoke-collection-id"] = await dependencies.postman.generateCollection(
|
|
30803
30617
|
outputs["spec-id"],
|
|
30804
|
-
|
|
30618
|
+
assetProjectName,
|
|
30805
30619
|
"[Smoke]"
|
|
30806
30620
|
);
|
|
30807
30621
|
} else {
|
|
@@ -30809,17 +30623,10 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30809
30623
|
`Using existing smoke collection: ${outputs["smoke-collection-id"]}`
|
|
30810
30624
|
);
|
|
30811
30625
|
}
|
|
30812
|
-
await writeVariable(
|
|
30813
|
-
dependencies.github,
|
|
30814
|
-
inputs.projectName,
|
|
30815
|
-
"SMOKE_COLLECTION_UID",
|
|
30816
|
-
outputs["smoke-collection-id"],
|
|
30817
|
-
dependencies.core
|
|
30818
|
-
);
|
|
30819
30626
|
if (!outputs["contract-collection-id"]) {
|
|
30820
30627
|
outputs["contract-collection-id"] = await dependencies.postman.generateCollection(
|
|
30821
30628
|
outputs["spec-id"],
|
|
30822
|
-
|
|
30629
|
+
assetProjectName,
|
|
30823
30630
|
"[Contract]"
|
|
30824
30631
|
);
|
|
30825
30632
|
} else {
|
|
@@ -30827,13 +30634,6 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30827
30634
|
`Using existing contract collection: ${outputs["contract-collection-id"]}`
|
|
30828
30635
|
);
|
|
30829
30636
|
}
|
|
30830
|
-
await writeVariable(
|
|
30831
|
-
dependencies.github,
|
|
30832
|
-
inputs.projectName,
|
|
30833
|
-
"CONTRACT_COLLECTION_UID",
|
|
30834
|
-
outputs["contract-collection-id"],
|
|
30835
|
-
dependencies.core
|
|
30836
|
-
);
|
|
30837
30637
|
}
|
|
30838
30638
|
);
|
|
30839
30639
|
outputs["collections-json"] = JSON.stringify({
|
|
@@ -30871,27 +30671,6 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30871
30671
|
]);
|
|
30872
30672
|
}
|
|
30873
30673
|
);
|
|
30874
|
-
if (dependencies.github) {
|
|
30875
|
-
const github = dependencies.github;
|
|
30876
|
-
await runGroup(
|
|
30877
|
-
dependencies.core,
|
|
30878
|
-
"Store Postman UIDs as Repo Variables",
|
|
30879
|
-
async () => {
|
|
30880
|
-
await persistBootstrapRepositoryVariables(
|
|
30881
|
-
github,
|
|
30882
|
-
inputs.projectName,
|
|
30883
|
-
outputs,
|
|
30884
|
-
systemEnvMap,
|
|
30885
|
-
environments,
|
|
30886
|
-
{
|
|
30887
|
-
lintErrors: lintSummary.errors,
|
|
30888
|
-
lintWarnings: lintSummary.warnings
|
|
30889
|
-
},
|
|
30890
|
-
dependencies.core
|
|
30891
|
-
);
|
|
30892
|
-
}
|
|
30893
|
-
);
|
|
30894
|
-
}
|
|
30895
30674
|
for (const [name, value] of Object.entries(outputs)) {
|
|
30896
30675
|
dependencies.core.setOutput(name, value);
|
|
30897
30676
|
}
|
|
@@ -30905,9 +30684,6 @@ async function runAction(actionCore = core, actionExec = exec, actionIo = io) {
|
|
|
30905
30684
|
io: actionIo,
|
|
30906
30685
|
specFetcher: fetch
|
|
30907
30686
|
});
|
|
30908
|
-
if (!dependencies.github) {
|
|
30909
|
-
actionCore.info("GitHub repository variable persistence disabled for this run");
|
|
30910
|
-
}
|
|
30911
30687
|
if (inputs.domain && !dependencies.internalIntegration) {
|
|
30912
30688
|
actionCore.warning(
|
|
30913
30689
|
"Skipping governance assignment because postman-access-token is not configured"
|
|
@@ -30918,22 +30694,12 @@ async function runAction(actionCore = core, actionExec = exec, actionIo = io) {
|
|
|
30918
30694
|
function createBootstrapDependencies(inputs, factories) {
|
|
30919
30695
|
const secretMasker = createSecretMasker([
|
|
30920
30696
|
inputs.postmanApiKey,
|
|
30921
|
-
inputs.postmanAccessToken
|
|
30922
|
-
inputs.githubToken,
|
|
30923
|
-
inputs.ghFallbackToken
|
|
30697
|
+
inputs.postmanAccessToken
|
|
30924
30698
|
]);
|
|
30925
30699
|
const postman = new PostmanAssetsClient({
|
|
30926
30700
|
apiKey: inputs.postmanApiKey,
|
|
30927
30701
|
secretMasker
|
|
30928
30702
|
});
|
|
30929
|
-
const repository = extractRepositorySlug(inputs.repoUrl);
|
|
30930
|
-
const github = inputs.githubToken && inputs.repoUrl && repository ? new GitHubApiClient({
|
|
30931
|
-
authMode: inputs.githubAuthMode,
|
|
30932
|
-
fallbackToken: inputs.ghFallbackToken,
|
|
30933
|
-
repository,
|
|
30934
|
-
secretMasker,
|
|
30935
|
-
token: inputs.githubToken
|
|
30936
|
-
}) : void 0;
|
|
30937
30703
|
const internalIntegration = inputs.postmanAccessToken ? createInternalIntegrationAdapter({
|
|
30938
30704
|
accessToken: inputs.postmanAccessToken,
|
|
30939
30705
|
backend: inputs.integrationBackend,
|
|
@@ -30943,30 +30709,12 @@ function createBootstrapDependencies(inputs, factories) {
|
|
|
30943
30709
|
return {
|
|
30944
30710
|
core: factories.core,
|
|
30945
30711
|
exec: factories.exec,
|
|
30946
|
-
github,
|
|
30947
30712
|
io: factories.io,
|
|
30948
30713
|
internalIntegration,
|
|
30949
30714
|
postman,
|
|
30950
30715
|
specFetcher: factories.specFetcher ?? fetch
|
|
30951
30716
|
};
|
|
30952
30717
|
}
|
|
30953
|
-
function extractRepositorySlug(repoUrl) {
|
|
30954
|
-
const normalized = normalizeInputValue(repoUrl);
|
|
30955
|
-
if (!normalized) {
|
|
30956
|
-
return void 0;
|
|
30957
|
-
}
|
|
30958
|
-
try {
|
|
30959
|
-
const parsed = new URL(normalized);
|
|
30960
|
-
const pathname = parsed.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
|
|
30961
|
-
const segments = pathname.split("/").filter(Boolean);
|
|
30962
|
-
if (segments.length >= 2) {
|
|
30963
|
-
return `${segments[0]}/${segments[1]}`;
|
|
30964
|
-
}
|
|
30965
|
-
return void 0;
|
|
30966
|
-
} catch {
|
|
30967
|
-
return void 0;
|
|
30968
|
-
}
|
|
30969
|
-
}
|
|
30970
30718
|
var currentModulePath = typeof __filename === "string" ? __filename : "";
|
|
30971
30719
|
var entrypoint = process.argv[1];
|
|
30972
30720
|
if (entrypoint && currentModulePath === entrypoint) {
|
|
@@ -31089,9 +30837,7 @@ function createCliExec(secretMasker) {
|
|
|
31089
30837
|
function createCliDependencies(inputs) {
|
|
31090
30838
|
const secretMasker = createSecretMasker([
|
|
31091
30839
|
inputs.postmanApiKey,
|
|
31092
|
-
inputs.postmanAccessToken
|
|
31093
|
-
inputs.githubToken,
|
|
31094
|
-
inputs.ghFallbackToken
|
|
30840
|
+
inputs.postmanAccessToken
|
|
31095
30841
|
]);
|
|
31096
30842
|
const cliExec = createCliExec(secretMasker);
|
|
31097
30843
|
return createBootstrapDependencies(inputs, {
|
|
@@ -31112,18 +30858,17 @@ function parseCliArgs(argv, env = process.env) {
|
|
|
31112
30858
|
"baseline-collection-id",
|
|
31113
30859
|
"smoke-collection-id",
|
|
31114
30860
|
"contract-collection-id",
|
|
30861
|
+
"collection-sync-mode",
|
|
30862
|
+
"spec-sync-mode",
|
|
30863
|
+
"release-label",
|
|
31115
30864
|
"domain",
|
|
31116
30865
|
"domain-code",
|
|
31117
30866
|
"requester-email",
|
|
31118
30867
|
"workspace-admin-user-ids",
|
|
31119
|
-
"environments-json",
|
|
31120
|
-
"system-env-map-json",
|
|
31121
30868
|
"governance-mapping-json",
|
|
31122
30869
|
"integration-backend",
|
|
31123
|
-
"github-auth-mode",
|
|
31124
|
-
"github-token",
|
|
31125
|
-
"gh-fallback-token",
|
|
31126
30870
|
"team-id",
|
|
30871
|
+
"workspace-team-id",
|
|
31127
30872
|
"repo-url"
|
|
31128
30873
|
];
|
|
31129
30874
|
const inputEnv = { ...env };
|
|
@@ -31163,9 +30908,6 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
31163
30908
|
const config = parseCliArgs(argv, env);
|
|
31164
30909
|
const inputs = resolveInputs(config.inputEnv);
|
|
31165
30910
|
const dependencies = createCliDependencies(inputs);
|
|
31166
|
-
if (!dependencies.github) {
|
|
31167
|
-
dependencies.core.info("GitHub repository variable persistence disabled for this run");
|
|
31168
|
-
}
|
|
31169
30911
|
if (inputs.domain && !dependencies.internalIntegration) {
|
|
31170
30912
|
dependencies.core.warning(
|
|
31171
30913
|
"Skipping governance assignment because postman-access-token is not configured"
|