@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/index.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")) {
|
|
@@ -28671,7 +28684,6 @@ var index_exports = {};
|
|
|
28671
28684
|
__export(index_exports, {
|
|
28672
28685
|
createBootstrapDependencies: () => createBootstrapDependencies,
|
|
28673
28686
|
createPlannedOutputs: () => createPlannedOutputs,
|
|
28674
|
-
extractRepositorySlug: () => extractRepositorySlug,
|
|
28675
28687
|
getInput: () => getInput,
|
|
28676
28688
|
lintSpecViaCli: () => lintSpecViaCli,
|
|
28677
28689
|
normalizeSpecDocument: () => normalizeSpecDocument,
|
|
@@ -28684,6 +28696,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
28684
28696
|
var core = __toESM(require_core(), 1);
|
|
28685
28697
|
var exec = __toESM(require_exec(), 1);
|
|
28686
28698
|
var io = __toESM(require_io(), 1);
|
|
28699
|
+
var import_node_fs = require("node:fs");
|
|
28687
28700
|
var import_yaml = __toESM(require_dist(), 1);
|
|
28688
28701
|
|
|
28689
28702
|
// src/contracts.ts
|
|
@@ -28711,6 +28724,22 @@ var openAlphaActionContract = {
|
|
|
28711
28724
|
description: "Existing contract collection ID.",
|
|
28712
28725
|
required: false
|
|
28713
28726
|
},
|
|
28727
|
+
"collection-sync-mode": {
|
|
28728
|
+
description: "Collection lifecycle policy: reuse existing collections, refresh them from the latest spec, or version them by release label.",
|
|
28729
|
+
required: false,
|
|
28730
|
+
default: "refresh",
|
|
28731
|
+
allowedValues: ["reuse", "refresh", "version"]
|
|
28732
|
+
},
|
|
28733
|
+
"spec-sync-mode": {
|
|
28734
|
+
description: "Spec lifecycle policy: update the canonical spec or create/reuse a versioned spec for the resolved release label.",
|
|
28735
|
+
required: false,
|
|
28736
|
+
default: "update",
|
|
28737
|
+
allowedValues: ["update", "version"]
|
|
28738
|
+
},
|
|
28739
|
+
"release-label": {
|
|
28740
|
+
description: "Optional release label. When omitted for versioned sync, the action derives one from GitHub ref metadata.",
|
|
28741
|
+
required: false
|
|
28742
|
+
},
|
|
28714
28743
|
"project-name": {
|
|
28715
28744
|
description: "Service project name.",
|
|
28716
28745
|
required: true
|
|
@@ -28731,20 +28760,14 @@ var openAlphaActionContract = {
|
|
|
28731
28760
|
description: "Comma-separated workspace admin user ids.",
|
|
28732
28761
|
required: false
|
|
28733
28762
|
},
|
|
28763
|
+
"workspace-team-id": {
|
|
28764
|
+
description: "Numeric sub-team ID for org-mode workspace creation.",
|
|
28765
|
+
required: false
|
|
28766
|
+
},
|
|
28734
28767
|
"spec-url": {
|
|
28735
28768
|
description: "HTTPS URL to the OpenAPI document.",
|
|
28736
28769
|
required: true
|
|
28737
28770
|
},
|
|
28738
|
-
"environments-json": {
|
|
28739
|
-
description: "JSON array of environment slugs to preserve in bootstrap outputs.",
|
|
28740
|
-
required: false,
|
|
28741
|
-
default: '["prod"]'
|
|
28742
|
-
},
|
|
28743
|
-
"system-env-map-json": {
|
|
28744
|
-
description: "JSON map of environment slug to system environment id.",
|
|
28745
|
-
required: false,
|
|
28746
|
-
default: "{}"
|
|
28747
|
-
},
|
|
28748
28771
|
"governance-mapping-json": {
|
|
28749
28772
|
description: "JSON map of business domain to governance group name.",
|
|
28750
28773
|
required: false,
|
|
@@ -28758,19 +28781,6 @@ var openAlphaActionContract = {
|
|
|
28758
28781
|
description: "Postman access token used for governance and workspace mutations.",
|
|
28759
28782
|
required: false
|
|
28760
28783
|
},
|
|
28761
|
-
"github-token": {
|
|
28762
|
-
description: "GitHub token for repository variable persistence.",
|
|
28763
|
-
required: false
|
|
28764
|
-
},
|
|
28765
|
-
"gh-fallback-token": {
|
|
28766
|
-
description: "Fallback token for repository variable APIs.",
|
|
28767
|
-
required: false
|
|
28768
|
-
},
|
|
28769
|
-
"github-auth-mode": {
|
|
28770
|
-
description: "GitHub auth mode for repository variable APIs.",
|
|
28771
|
-
required: false,
|
|
28772
|
-
default: "github_token_first"
|
|
28773
|
-
},
|
|
28774
28784
|
"integration-backend": {
|
|
28775
28785
|
description: "Integration backend for downstream workspace connectivity.",
|
|
28776
28786
|
required: false,
|
|
@@ -28816,8 +28826,8 @@ var openAlphaActionContract = {
|
|
|
28816
28826
|
"OpenAPI operation summary normalization before upload (missing or oversized summaries)",
|
|
28817
28827
|
"spec linting by UID",
|
|
28818
28828
|
"baseline, smoke, and contract collection generation",
|
|
28829
|
+
"collection refresh and versioning policies",
|
|
28819
28830
|
"collection tagging",
|
|
28820
|
-
"GitHub repository variable persistence for downstream sync steps",
|
|
28821
28831
|
"workspace, spec, and collection outputs"
|
|
28822
28832
|
],
|
|
28823
28833
|
removedBehavior: [
|
|
@@ -28908,189 +28918,6 @@ function sanitizeHeaders(headers, secretValues) {
|
|
|
28908
28918
|
return sanitized;
|
|
28909
28919
|
}
|
|
28910
28920
|
|
|
28911
|
-
// src/lib/github/github-api-client.ts
|
|
28912
|
-
function buildErrorMessage(method, path, response, body, masker) {
|
|
28913
|
-
const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
28914
|
-
const sanitizedBody = masker(body || "");
|
|
28915
|
-
return sanitizedBody ? masker(`${method} ${path} failed with ${status} - ${sanitizedBody}`) : masker(`${method} ${path} failed with ${status} - [REDACTED]`);
|
|
28916
|
-
}
|
|
28917
|
-
var GitHubApiClient = class {
|
|
28918
|
-
apiBase;
|
|
28919
|
-
authMode;
|
|
28920
|
-
appToken;
|
|
28921
|
-
fallbackToken;
|
|
28922
|
-
fetchImpl;
|
|
28923
|
-
owner;
|
|
28924
|
-
repo;
|
|
28925
|
-
repository;
|
|
28926
|
-
secretMasker;
|
|
28927
|
-
token;
|
|
28928
|
-
constructor(options) {
|
|
28929
|
-
this.apiBase = String(options.apiBase || "https://api.github.com").replace(
|
|
28930
|
-
/\/+$/,
|
|
28931
|
-
""
|
|
28932
|
-
);
|
|
28933
|
-
this.appToken = String(options.appToken || "").trim();
|
|
28934
|
-
this.authMode = options.authMode || "github_token_first";
|
|
28935
|
-
this.fallbackToken = String(options.fallbackToken || "").trim();
|
|
28936
|
-
this.fetchImpl = options.fetch ?? fetch;
|
|
28937
|
-
this.repository = options.repository;
|
|
28938
|
-
const [owner, repo] = options.repository.split("/");
|
|
28939
|
-
this.owner = owner;
|
|
28940
|
-
this.repo = repo;
|
|
28941
|
-
this.token = String(options.token || "").trim();
|
|
28942
|
-
this.secretMasker = options.secretMasker ?? createSecretMasker([this.token, this.fallbackToken, this.appToken]);
|
|
28943
|
-
}
|
|
28944
|
-
getTokenOrder() {
|
|
28945
|
-
const ordered = [];
|
|
28946
|
-
if (this.authMode === "app_token") {
|
|
28947
|
-
if (this.appToken) ordered.push(this.appToken);
|
|
28948
|
-
if (this.token && this.token !== this.appToken) ordered.push(this.token);
|
|
28949
|
-
if (this.fallbackToken && this.fallbackToken !== this.appToken && this.fallbackToken !== this.token) {
|
|
28950
|
-
ordered.push(this.fallbackToken);
|
|
28951
|
-
}
|
|
28952
|
-
return ordered;
|
|
28953
|
-
}
|
|
28954
|
-
if (this.authMode === "fallback_pat_first") {
|
|
28955
|
-
if (this.fallbackToken) ordered.push(this.fallbackToken);
|
|
28956
|
-
if (this.token && this.token !== this.fallbackToken) ordered.push(this.token);
|
|
28957
|
-
return ordered;
|
|
28958
|
-
}
|
|
28959
|
-
if (this.token) ordered.push(this.token);
|
|
28960
|
-
if (this.fallbackToken && this.fallbackToken !== this.token) {
|
|
28961
|
-
ordered.push(this.fallbackToken);
|
|
28962
|
-
}
|
|
28963
|
-
return ordered;
|
|
28964
|
-
}
|
|
28965
|
-
isVariablesEndpoint(path) {
|
|
28966
|
-
return path.startsWith(`/repos/${this.owner}/${this.repo}/actions/variables`);
|
|
28967
|
-
}
|
|
28968
|
-
canUseFallback(path) {
|
|
28969
|
-
return this.isVariablesEndpoint(path) || path.includes(`/repos/${this.owner}/${this.repo}/contents`) || path.includes("/dispatches");
|
|
28970
|
-
}
|
|
28971
|
-
rateLimitDelayMs(response, attempt) {
|
|
28972
|
-
const retryAfter = Number(response.headers.get("retry-after") || "");
|
|
28973
|
-
if (Number.isFinite(retryAfter) && retryAfter > 0) {
|
|
28974
|
-
return Math.min(retryAfter * 1e3, 12e4);
|
|
28975
|
-
}
|
|
28976
|
-
const resetAtSeconds = Number(response.headers.get("x-ratelimit-reset") || "");
|
|
28977
|
-
if (Number.isFinite(resetAtSeconds) && resetAtSeconds > 0) {
|
|
28978
|
-
const delta = resetAtSeconds * 1e3 - Date.now();
|
|
28979
|
-
if (delta > 0) {
|
|
28980
|
-
return Math.min(delta + 250, 12e4);
|
|
28981
|
-
}
|
|
28982
|
-
}
|
|
28983
|
-
const base = Math.min(5e3 * Math.pow(2, attempt), 12e4);
|
|
28984
|
-
const jitter = Math.floor(Math.random() * 250);
|
|
28985
|
-
return Math.min(base + jitter, 12e4);
|
|
28986
|
-
}
|
|
28987
|
-
async requestWithToken(path, init, token) {
|
|
28988
|
-
const MAX_RETRIES = 5;
|
|
28989
|
-
const normalizedToken = String(token || "").trim();
|
|
28990
|
-
if (!normalizedToken) {
|
|
28991
|
-
throw new Error(`Missing GitHub auth token for request ${path}`);
|
|
28992
|
-
}
|
|
28993
|
-
for (let attempt = 0; ; attempt++) {
|
|
28994
|
-
const response = await this.fetchImpl(`${this.apiBase}${path}`, {
|
|
28995
|
-
...init,
|
|
28996
|
-
headers: {
|
|
28997
|
-
Accept: "application/vnd.github+json",
|
|
28998
|
-
Authorization: `Bearer ${normalizedToken}`,
|
|
28999
|
-
"Content-Type": "application/json",
|
|
29000
|
-
...init.headers || {}
|
|
29001
|
-
}
|
|
29002
|
-
});
|
|
29003
|
-
if (attempt < MAX_RETRIES && (response.status === 403 || response.status === 429)) {
|
|
29004
|
-
const body = await response.clone().text().catch(() => "");
|
|
29005
|
-
if (isRateLimitedResponse(response, body)) {
|
|
29006
|
-
const delay = this.rateLimitDelayMs(response, attempt);
|
|
29007
|
-
console.log(
|
|
29008
|
-
`GitHub API rate limited, retrying in ${Math.ceil(delay / 1e3)}s (attempt ${attempt + 1}/${MAX_RETRIES})...`
|
|
29009
|
-
);
|
|
29010
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
29011
|
-
continue;
|
|
29012
|
-
}
|
|
29013
|
-
}
|
|
29014
|
-
return response;
|
|
29015
|
-
}
|
|
29016
|
-
}
|
|
29017
|
-
async request(path, init = {}) {
|
|
29018
|
-
const orderedTokens = this.getTokenOrder();
|
|
29019
|
-
if (orderedTokens.length === 0) {
|
|
29020
|
-
throw new Error("No GitHub auth token configured");
|
|
29021
|
-
}
|
|
29022
|
-
const first = await this.requestWithToken(path, init, orderedTokens[0]);
|
|
29023
|
-
if (orderedTokens.length < 2 || !this.canUseFallback(path)) {
|
|
29024
|
-
return first;
|
|
29025
|
-
}
|
|
29026
|
-
const isVariableGet404 = first.status === 404 && (!init.method || init.method === "GET") && this.isVariablesEndpoint(path);
|
|
29027
|
-
if (first.status !== 403 && !isVariableGet404) {
|
|
29028
|
-
return first;
|
|
29029
|
-
}
|
|
29030
|
-
return this.requestWithToken(path, init, orderedTokens[1]);
|
|
29031
|
-
}
|
|
29032
|
-
async setRepositoryVariable(name, value) {
|
|
29033
|
-
if (!value) {
|
|
29034
|
-
throw new Error(`Repo variable ${name} is empty`);
|
|
29035
|
-
}
|
|
29036
|
-
const path = `/repos/${this.repository}/actions/variables`;
|
|
29037
|
-
const body = JSON.stringify({ name, value: String(value) });
|
|
29038
|
-
const createResponse = await this.request(path, {
|
|
29039
|
-
method: "POST",
|
|
29040
|
-
body
|
|
29041
|
-
});
|
|
29042
|
-
if (createResponse.ok || createResponse.status === 201) {
|
|
29043
|
-
return;
|
|
29044
|
-
}
|
|
29045
|
-
if (createResponse.status === 409 || createResponse.status === 422) {
|
|
29046
|
-
const updatePath = `/repos/${this.repository}/actions/variables/${name}`;
|
|
29047
|
-
const updateResponse = await this.request(updatePath, {
|
|
29048
|
-
method: "PATCH",
|
|
29049
|
-
body
|
|
29050
|
-
});
|
|
29051
|
-
if (updateResponse.ok) {
|
|
29052
|
-
return;
|
|
29053
|
-
}
|
|
29054
|
-
const text2 = await updateResponse.text().catch(() => "");
|
|
29055
|
-
throw new Error(
|
|
29056
|
-
buildErrorMessage("PATCH", updatePath, updateResponse, text2, this.secretMasker)
|
|
29057
|
-
);
|
|
29058
|
-
}
|
|
29059
|
-
const text = await createResponse.text().catch(() => "");
|
|
29060
|
-
throw new Error(
|
|
29061
|
-
buildErrorMessage("POST", path, createResponse, text, this.secretMasker)
|
|
29062
|
-
);
|
|
29063
|
-
}
|
|
29064
|
-
async getRepositoryVariable(name) {
|
|
29065
|
-
const path = `/repos/${this.repository}/actions/variables/${name}`;
|
|
29066
|
-
const response = await this.request(path, {
|
|
29067
|
-
method: "GET"
|
|
29068
|
-
});
|
|
29069
|
-
if (response.status === 404) {
|
|
29070
|
-
return "";
|
|
29071
|
-
}
|
|
29072
|
-
if (!response.ok) {
|
|
29073
|
-
const text = await response.text().catch(() => "");
|
|
29074
|
-
throw new Error(
|
|
29075
|
-
buildErrorMessage("GET", path, response, text, this.secretMasker)
|
|
29076
|
-
);
|
|
29077
|
-
}
|
|
29078
|
-
const data = await response.json();
|
|
29079
|
-
return String(data.value || "");
|
|
29080
|
-
}
|
|
29081
|
-
};
|
|
29082
|
-
function isRateLimitedResponse(response, body) {
|
|
29083
|
-
if (response.status !== 403 && response.status !== 429) return false;
|
|
29084
|
-
const remaining = response.headers.get("x-ratelimit-remaining");
|
|
29085
|
-
const retryAfter = response.headers.get("retry-after");
|
|
29086
|
-
if (remaining === "0") return true;
|
|
29087
|
-
if (retryAfter) return true;
|
|
29088
|
-
const message = body.toLowerCase();
|
|
29089
|
-
if (message.includes("secondary rate limit")) return true;
|
|
29090
|
-
if (message.includes("api rate limit exceeded")) return true;
|
|
29091
|
-
return response.status === 429;
|
|
29092
|
-
}
|
|
29093
|
-
|
|
29094
28921
|
// src/lib/http-error.ts
|
|
29095
28922
|
function truncate(value, limit) {
|
|
29096
28923
|
if (value.length <= limit) {
|
|
@@ -29273,6 +29100,16 @@ var PostmanAssetsClient = class {
|
|
|
29273
29100
|
}
|
|
29274
29101
|
return void 0;
|
|
29275
29102
|
}
|
|
29103
|
+
async getTeams() {
|
|
29104
|
+
const data = await this.request("/teams");
|
|
29105
|
+
const teams = data?.data ?? [];
|
|
29106
|
+
return Array.isArray(teams) ? teams.filter((t) => t?.id && t?.name).map((t) => ({
|
|
29107
|
+
id: Number(t.id),
|
|
29108
|
+
name: String(t.name),
|
|
29109
|
+
handle: String(t.handle || ""),
|
|
29110
|
+
...t.organizationId != null ? { organizationId: Number(t.organizationId) } : {}
|
|
29111
|
+
})) : [];
|
|
29112
|
+
}
|
|
29276
29113
|
async request(path, init = {}) {
|
|
29277
29114
|
const url = path.startsWith("http") ? path : `${this.baseUrl}${path}`;
|
|
29278
29115
|
const response = await this.fetchImpl(url, {
|
|
@@ -29301,13 +29138,14 @@ var PostmanAssetsClient = class {
|
|
|
29301
29138
|
return null;
|
|
29302
29139
|
}
|
|
29303
29140
|
}
|
|
29304
|
-
async createWorkspace(name, about) {
|
|
29141
|
+
async createWorkspace(name, about, targetTeamId) {
|
|
29305
29142
|
return retry(async () => {
|
|
29306
29143
|
const payload = {
|
|
29307
29144
|
workspace: {
|
|
29308
29145
|
about,
|
|
29309
29146
|
name,
|
|
29310
|
-
type: "team"
|
|
29147
|
+
type: "team",
|
|
29148
|
+
...targetTeamId != null && !Number.isNaN(targetTeamId) ? { teamId: targetTeamId } : {}
|
|
29311
29149
|
}
|
|
29312
29150
|
};
|
|
29313
29151
|
let created;
|
|
@@ -29319,7 +29157,7 @@ var PostmanAssetsClient = class {
|
|
|
29319
29157
|
} catch (err) {
|
|
29320
29158
|
if (err instanceof Error && err.message.includes("Only personal workspaces")) {
|
|
29321
29159
|
throw new Error(
|
|
29322
|
-
"Workspace creation failed:
|
|
29160
|
+
"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."
|
|
29323
29161
|
);
|
|
29324
29162
|
}
|
|
29325
29163
|
throw err;
|
|
@@ -29338,7 +29176,11 @@ var PostmanAssetsClient = class {
|
|
|
29338
29176
|
return {
|
|
29339
29177
|
id: workspaceId
|
|
29340
29178
|
};
|
|
29341
|
-
}, {
|
|
29179
|
+
}, {
|
|
29180
|
+
maxAttempts: 3,
|
|
29181
|
+
delayMs: 2e3,
|
|
29182
|
+
shouldRetry: (err) => !(err instanceof Error && err.message.includes("workspace-team-id"))
|
|
29183
|
+
});
|
|
29342
29184
|
}
|
|
29343
29185
|
async listWorkspaces() {
|
|
29344
29186
|
const data = await this.request("/workspaces");
|
|
@@ -30150,31 +29992,17 @@ function requireInput(actionCore, name) {
|
|
|
30150
29992
|
function optionalInput(actionCore, name) {
|
|
30151
29993
|
return normalizeInputValue(actionCore.getInput(name));
|
|
30152
29994
|
}
|
|
30153
|
-
function
|
|
30154
|
-
|
|
30155
|
-
return
|
|
30156
|
-
} catch (error) {
|
|
30157
|
-
throw new Error(
|
|
30158
|
-
`Invalid JSON for ${inputName}: ${error instanceof Error ? error.message : String(error)}`
|
|
30159
|
-
);
|
|
29995
|
+
function parseCollectionSyncMode(value) {
|
|
29996
|
+
if (value === "reuse" || value === "version") {
|
|
29997
|
+
return value;
|
|
30160
29998
|
}
|
|
29999
|
+
return "refresh";
|
|
30161
30000
|
}
|
|
30162
|
-
function
|
|
30163
|
-
if (
|
|
30164
|
-
|
|
30001
|
+
function parseSpecSyncMode(value) {
|
|
30002
|
+
if (value === "version") {
|
|
30003
|
+
return value;
|
|
30165
30004
|
}
|
|
30166
|
-
return
|
|
30167
|
-
}
|
|
30168
|
-
function asStringMap(value, inputName) {
|
|
30169
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
30170
|
-
throw new Error(`${inputName} must be a JSON object`);
|
|
30171
|
-
}
|
|
30172
|
-
return Object.fromEntries(
|
|
30173
|
-
Object.entries(value).map(([key, entry]) => [
|
|
30174
|
-
key,
|
|
30175
|
-
String(entry)
|
|
30176
|
-
])
|
|
30177
|
-
);
|
|
30005
|
+
return "update";
|
|
30178
30006
|
}
|
|
30179
30007
|
function resolveInputs(env = process.env) {
|
|
30180
30008
|
const repoContext = detectRepoContext(
|
|
@@ -30202,28 +30030,31 @@ function resolveInputs(env = process.env) {
|
|
|
30202
30030
|
}
|
|
30203
30031
|
}
|
|
30204
30032
|
return {
|
|
30205
|
-
projectName: getInput("project-name", env) ?? "",
|
|
30033
|
+
projectName: getInput("project-name", env) ?? env.GITHUB_REPOSITORY?.split("/").pop() ?? env.CI_PROJECT_NAME ?? "",
|
|
30206
30034
|
workspaceId: getInput("workspace-id", env),
|
|
30207
30035
|
specId: getInput("spec-id", env),
|
|
30208
30036
|
baselineCollectionId: getInput("baseline-collection-id", env),
|
|
30209
30037
|
smokeCollectionId: getInput("smoke-collection-id", env),
|
|
30210
30038
|
contractCollectionId: getInput("contract-collection-id", env),
|
|
30039
|
+
collectionSyncMode: parseCollectionSyncMode(getInput("collection-sync-mode", env)),
|
|
30040
|
+
specSyncMode: parseSpecSyncMode(getInput("spec-sync-mode", env)),
|
|
30041
|
+
releaseLabel: getInput("release-label", env),
|
|
30211
30042
|
domain: getInput("domain", env),
|
|
30212
30043
|
domainCode: getInput("domain-code", env),
|
|
30213
30044
|
requesterEmail: getInput("requester-email", env),
|
|
30214
30045
|
workspaceAdminUserIds: getInput("workspace-admin-user-ids", env) || env.WORKSPACE_ADMIN_USER_IDS || "",
|
|
30046
|
+
workspaceTeamId: getInput("workspace-team-id", env) || env.POSTMAN_WORKSPACE_TEAM_ID,
|
|
30215
30047
|
teamId: getInput("team-id", env) || env.POSTMAN_TEAM_ID || "",
|
|
30216
30048
|
repoUrl: repoContext.repoUrl || "",
|
|
30217
30049
|
specUrl,
|
|
30218
|
-
environmentsJson: getInput("environments-json", env) ?? openAlphaActionContract.inputs["environments-json"].default ?? '["prod"]',
|
|
30219
|
-
systemEnvMapJson: getInput("system-env-map-json", env) ?? openAlphaActionContract.inputs["system-env-map-json"].default ?? "{}",
|
|
30220
30050
|
governanceMappingJson: getInput("governance-mapping-json", env) ?? openAlphaActionContract.inputs["governance-mapping-json"].default ?? "{}",
|
|
30221
30051
|
postmanApiKey: getInput("postman-api-key", env) ?? "",
|
|
30222
30052
|
postmanAccessToken: getInput("postman-access-token", env),
|
|
30223
|
-
|
|
30224
|
-
|
|
30225
|
-
|
|
30226
|
-
|
|
30053
|
+
integrationBackend,
|
|
30054
|
+
githubRefName: env.GITHUB_REF_NAME,
|
|
30055
|
+
githubHeadRef: env.GITHUB_HEAD_REF,
|
|
30056
|
+
githubRef: env.GITHUB_REF,
|
|
30057
|
+
githubSha: env.GITHUB_SHA
|
|
30227
30058
|
};
|
|
30228
30059
|
}
|
|
30229
30060
|
function createPlannedOutputs(inputs) {
|
|
@@ -30254,12 +30085,8 @@ function readActionInputs(actionCore) {
|
|
|
30254
30085
|
const specUrl = requireInput(actionCore, "spec-url");
|
|
30255
30086
|
const postmanApiKey = requireInput(actionCore, "postman-api-key");
|
|
30256
30087
|
const postmanAccessToken = optionalInput(actionCore, "postman-access-token");
|
|
30257
|
-
const githubToken = optionalInput(actionCore, "github-token");
|
|
30258
|
-
const ghFallbackToken = optionalInput(actionCore, "gh-fallback-token");
|
|
30259
30088
|
actionCore.setSecret(postmanApiKey);
|
|
30260
30089
|
if (postmanAccessToken) actionCore.setSecret(postmanAccessToken);
|
|
30261
|
-
if (githubToken) actionCore.setSecret(githubToken);
|
|
30262
|
-
if (ghFallbackToken) actionCore.setSecret(ghFallbackToken);
|
|
30263
30090
|
const inputs = resolveInputs({
|
|
30264
30091
|
...process.env,
|
|
30265
30092
|
INPUT_PROJECT_NAME: projectName,
|
|
@@ -30268,6 +30095,9 @@ function readActionInputs(actionCore) {
|
|
|
30268
30095
|
INPUT_BASELINE_COLLECTION_ID: optionalInput(actionCore, "baseline-collection-id"),
|
|
30269
30096
|
INPUT_SMOKE_COLLECTION_ID: optionalInput(actionCore, "smoke-collection-id"),
|
|
30270
30097
|
INPUT_CONTRACT_COLLECTION_ID: optionalInput(actionCore, "contract-collection-id"),
|
|
30098
|
+
INPUT_COLLECTION_SYNC_MODE: optionalInput(actionCore, "collection-sync-mode") ?? openAlphaActionContract.inputs["collection-sync-mode"].default,
|
|
30099
|
+
INPUT_SPEC_SYNC_MODE: optionalInput(actionCore, "spec-sync-mode") ?? openAlphaActionContract.inputs["spec-sync-mode"].default,
|
|
30100
|
+
INPUT_RELEASE_LABEL: optionalInput(actionCore, "release-label"),
|
|
30271
30101
|
INPUT_DOMAIN: optionalInput(actionCore, "domain"),
|
|
30272
30102
|
INPUT_DOMAIN_CODE: optionalInput(actionCore, "domain-code"),
|
|
30273
30103
|
INPUT_REQUESTER_EMAIL: optionalInput(actionCore, "requester-email"),
|
|
@@ -30275,17 +30105,13 @@ function readActionInputs(actionCore) {
|
|
|
30275
30105
|
actionCore,
|
|
30276
30106
|
"workspace-admin-user-ids"
|
|
30277
30107
|
),
|
|
30108
|
+
INPUT_WORKSPACE_TEAM_ID: optionalInput(actionCore, "workspace-team-id") || process.env.POSTMAN_WORKSPACE_TEAM_ID,
|
|
30278
30109
|
INPUT_TEAM_ID: optionalInput(actionCore, "postman-team-id") || process.env.POSTMAN_TEAM_ID,
|
|
30279
30110
|
INPUT_REPO_URL: optionalInput(actionCore, "repo-url"),
|
|
30280
30111
|
INPUT_SPEC_URL: specUrl,
|
|
30281
|
-
INPUT_ENVIRONMENTS_JSON: optionalInput(actionCore, "environments-json") ?? openAlphaActionContract.inputs["environments-json"].default,
|
|
30282
|
-
INPUT_SYSTEM_ENV_MAP_JSON: optionalInput(actionCore, "system-env-map-json") ?? openAlphaActionContract.inputs["system-env-map-json"].default,
|
|
30283
30112
|
INPUT_GOVERNANCE_MAPPING_JSON: optionalInput(actionCore, "governance-mapping-json") ?? openAlphaActionContract.inputs["governance-mapping-json"].default,
|
|
30284
30113
|
INPUT_POSTMAN_API_KEY: postmanApiKey,
|
|
30285
30114
|
INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
|
|
30286
|
-
INPUT_GITHUB_TOKEN: githubToken,
|
|
30287
|
-
INPUT_GH_FALLBACK_TOKEN: ghFallbackToken,
|
|
30288
|
-
INPUT_GITHUB_AUTH_MODE: optionalInput(actionCore, "github-auth-mode") ?? openAlphaActionContract.inputs["github-auth-mode"].default,
|
|
30289
30115
|
INPUT_INTEGRATION_BACKEND: optionalInput(actionCore, "integration-backend") ?? openAlphaActionContract.inputs["integration-backend"].default
|
|
30290
30116
|
});
|
|
30291
30117
|
return inputs;
|
|
@@ -30362,6 +30188,45 @@ async function fetchSpecDocument(specUrl, specFetcher) {
|
|
|
30362
30188
|
}
|
|
30363
30189
|
);
|
|
30364
30190
|
}
|
|
30191
|
+
function normalizeReleaseLabel(value) {
|
|
30192
|
+
const trimmed = String(value || "").trim();
|
|
30193
|
+
if (!trimmed) {
|
|
30194
|
+
return void 0;
|
|
30195
|
+
}
|
|
30196
|
+
return trimmed.replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "").replace(/^refs\/pull\//, "pull-").replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || void 0;
|
|
30197
|
+
}
|
|
30198
|
+
function deriveReleaseLabel(inputs) {
|
|
30199
|
+
if (inputs.releaseLabel) {
|
|
30200
|
+
return normalizeReleaseLabel(inputs.releaseLabel);
|
|
30201
|
+
}
|
|
30202
|
+
return normalizeReleaseLabel(inputs.githubRefName) ?? normalizeReleaseLabel(inputs.githubHeadRef) ?? normalizeReleaseLabel(inputs.githubRef);
|
|
30203
|
+
}
|
|
30204
|
+
function createAssetProjectName(inputs, releaseLabel) {
|
|
30205
|
+
if (!releaseLabel) {
|
|
30206
|
+
return inputs.projectName;
|
|
30207
|
+
}
|
|
30208
|
+
return `${inputs.projectName} ${releaseLabel}`;
|
|
30209
|
+
}
|
|
30210
|
+
function readResourcesState() {
|
|
30211
|
+
try {
|
|
30212
|
+
return (0, import_yaml.parse)((0, import_node_fs.readFileSync)(".postman/resources.yaml", "utf8"));
|
|
30213
|
+
} catch {
|
|
30214
|
+
return null;
|
|
30215
|
+
}
|
|
30216
|
+
}
|
|
30217
|
+
function getFirstCloudResourceId(map) {
|
|
30218
|
+
if (!map) {
|
|
30219
|
+
return void 0;
|
|
30220
|
+
}
|
|
30221
|
+
return Object.values(map)[0];
|
|
30222
|
+
}
|
|
30223
|
+
function findCloudResourceId(map, matcher) {
|
|
30224
|
+
if (!map) {
|
|
30225
|
+
return void 0;
|
|
30226
|
+
}
|
|
30227
|
+
const match = Object.entries(map).find(([filePath]) => matcher(filePath));
|
|
30228
|
+
return match?.[1];
|
|
30229
|
+
}
|
|
30365
30230
|
var SPEC_SUMMARY_MAX_LEN = 200;
|
|
30366
30231
|
var SPEC_HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
30367
30232
|
"get",
|
|
@@ -30450,122 +30315,28 @@ function validateSpecStructure(content) {
|
|
|
30450
30315
|
throw new Error('Spec is missing "openapi" or "swagger" version field');
|
|
30451
30316
|
}
|
|
30452
30317
|
}
|
|
30453
|
-
function varName(projectName, baseName) {
|
|
30454
|
-
const slug = projectName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
30455
|
-
return `POSTMAN_${slug}_${baseName}`;
|
|
30456
|
-
}
|
|
30457
|
-
async function readVariable(github, projectName, baseName) {
|
|
30458
|
-
if (!github) {
|
|
30459
|
-
return void 0;
|
|
30460
|
-
}
|
|
30461
|
-
const namespaced = await github.getRepositoryVariable(varName(projectName, baseName)).catch(() => void 0);
|
|
30462
|
-
if (namespaced) {
|
|
30463
|
-
return namespaced;
|
|
30464
|
-
}
|
|
30465
|
-
const legacy = await github.getRepositoryVariable(`POSTMAN_${baseName}`).catch(() => void 0);
|
|
30466
|
-
return legacy || void 0;
|
|
30467
|
-
}
|
|
30468
|
-
async function persistVariable(github, name, value, actionCore) {
|
|
30469
|
-
if (!github || !value) {
|
|
30470
|
-
return;
|
|
30471
|
-
}
|
|
30472
|
-
try {
|
|
30473
|
-
await github.setRepositoryVariable(name, value);
|
|
30474
|
-
} catch (err) {
|
|
30475
|
-
actionCore.warning(
|
|
30476
|
-
`Failed to persist ${name}: ${err instanceof Error ? err.message : String(err)}`
|
|
30477
|
-
);
|
|
30478
|
-
}
|
|
30479
|
-
}
|
|
30480
|
-
async function writeVariable(github, projectName, baseName, value, actionCore) {
|
|
30481
|
-
if (!github || !value) {
|
|
30482
|
-
return;
|
|
30483
|
-
}
|
|
30484
|
-
await persistVariable(github, varName(projectName, baseName), value, actionCore);
|
|
30485
|
-
await persistVariable(github, `POSTMAN_${baseName}`, value, actionCore);
|
|
30486
|
-
}
|
|
30487
|
-
async function persistBootstrapRepositoryVariables(github, projectName, outputs, systemEnvMap, environments, lintSummary, actionCore) {
|
|
30488
|
-
await persistVariable(
|
|
30489
|
-
github,
|
|
30490
|
-
"LINT_WARNINGS",
|
|
30491
|
-
String(lintSummary.lintWarnings),
|
|
30492
|
-
actionCore
|
|
30493
|
-
);
|
|
30494
|
-
await persistVariable(
|
|
30495
|
-
github,
|
|
30496
|
-
"LINT_ERRORS",
|
|
30497
|
-
String(lintSummary.lintErrors),
|
|
30498
|
-
actionCore
|
|
30499
|
-
);
|
|
30500
|
-
await writeVariable(
|
|
30501
|
-
github,
|
|
30502
|
-
projectName,
|
|
30503
|
-
"WORKSPACE_ID",
|
|
30504
|
-
outputs["workspace-id"],
|
|
30505
|
-
actionCore
|
|
30506
|
-
);
|
|
30507
|
-
await writeVariable(github, projectName, "SPEC_UID", outputs["spec-id"], actionCore);
|
|
30508
|
-
await writeVariable(
|
|
30509
|
-
github,
|
|
30510
|
-
projectName,
|
|
30511
|
-
"BASELINE_COLLECTION_UID",
|
|
30512
|
-
outputs["baseline-collection-id"],
|
|
30513
|
-
actionCore
|
|
30514
|
-
);
|
|
30515
|
-
await writeVariable(
|
|
30516
|
-
github,
|
|
30517
|
-
projectName,
|
|
30518
|
-
"SMOKE_COLLECTION_UID",
|
|
30519
|
-
outputs["smoke-collection-id"],
|
|
30520
|
-
actionCore
|
|
30521
|
-
);
|
|
30522
|
-
await writeVariable(
|
|
30523
|
-
github,
|
|
30524
|
-
projectName,
|
|
30525
|
-
"CONTRACT_COLLECTION_UID",
|
|
30526
|
-
outputs["contract-collection-id"],
|
|
30527
|
-
actionCore
|
|
30528
|
-
);
|
|
30529
|
-
for (const envName of environments) {
|
|
30530
|
-
const systemEnvId = systemEnvMap[envName];
|
|
30531
|
-
if (!systemEnvId) {
|
|
30532
|
-
continue;
|
|
30533
|
-
}
|
|
30534
|
-
await writeVariable(
|
|
30535
|
-
github,
|
|
30536
|
-
projectName,
|
|
30537
|
-
`SYSTEM_ENV_${envName.toUpperCase()}`,
|
|
30538
|
-
systemEnvId,
|
|
30539
|
-
actionCore
|
|
30540
|
-
);
|
|
30541
|
-
}
|
|
30542
|
-
}
|
|
30543
30318
|
async function runBootstrap(inputs, dependencies) {
|
|
30544
30319
|
const outputs = createPlannedOutputs(inputs);
|
|
30545
|
-
const
|
|
30546
|
-
|
|
30547
|
-
|
|
30548
|
-
|
|
30549
|
-
|
|
30550
|
-
|
|
30551
|
-
|
|
30552
|
-
);
|
|
30320
|
+
const requiresReleaseLabel = inputs.collectionSyncMode === "version" || inputs.specSyncMode === "version";
|
|
30321
|
+
const releaseLabel = requiresReleaseLabel ? deriveReleaseLabel(inputs) : void 0;
|
|
30322
|
+
if (requiresReleaseLabel && !releaseLabel) {
|
|
30323
|
+
throw new Error(
|
|
30324
|
+
"Versioned spec or collection sync requires a release-label or derivable GitHub ref metadata"
|
|
30325
|
+
);
|
|
30326
|
+
}
|
|
30553
30327
|
const workspaceName = createWorkspaceName(inputs);
|
|
30554
30328
|
const aboutText = `Auto-provisioned by Postman CS open-alpha for ${inputs.projectName}`;
|
|
30555
30329
|
await runGroup(dependencies.core, "Install Postman CLI", async () => {
|
|
30556
30330
|
await ensurePostmanCli(dependencies, inputs.postmanApiKey);
|
|
30557
30331
|
});
|
|
30558
|
-
const
|
|
30559
|
-
let
|
|
30560
|
-
|
|
30561
|
-
|
|
30562
|
-
|
|
30563
|
-
dependencies.github,
|
|
30564
|
-
inputs.projectName,
|
|
30565
|
-
"WORKSPACE_ID"
|
|
30566
|
-
);
|
|
30567
|
-
workspaceId = repoWorkspaceId;
|
|
30332
|
+
const resourcesState = readResourcesState();
|
|
30333
|
+
let explicitWorkspaceId = inputs.workspaceId;
|
|
30334
|
+
if (!explicitWorkspaceId && resourcesState?.workspace?.id) {
|
|
30335
|
+
explicitWorkspaceId = resourcesState.workspace.id;
|
|
30336
|
+
dependencies.core.info("Resolved workspace-id from .postman/resources.yaml");
|
|
30568
30337
|
}
|
|
30338
|
+
const repoWorkspaceId = explicitWorkspaceId;
|
|
30339
|
+
let workspaceId = explicitWorkspaceId;
|
|
30569
30340
|
let teamId = inputs.teamId || "";
|
|
30570
30341
|
if (!teamId) {
|
|
30571
30342
|
teamId = await dependencies.postman.getAutoDerivedTeamId() || "";
|
|
@@ -30599,24 +30370,65 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30599
30370
|
} else if (workspaceId) {
|
|
30600
30371
|
dependencies.core.info(`Using existing workspace: ${workspaceId}`);
|
|
30601
30372
|
}
|
|
30373
|
+
let workspaceTeamId;
|
|
30374
|
+
if (inputs.workspaceTeamId) {
|
|
30375
|
+
workspaceTeamId = parseInt(inputs.workspaceTeamId, 10);
|
|
30376
|
+
if (Number.isNaN(workspaceTeamId)) {
|
|
30377
|
+
throw new Error(`workspace-team-id must be a numeric sub-team ID, got: ${inputs.workspaceTeamId}`);
|
|
30378
|
+
}
|
|
30379
|
+
}
|
|
30380
|
+
if (!workspaceId && !workspaceTeamId) {
|
|
30381
|
+
try {
|
|
30382
|
+
const teams = await dependencies.postman.getTeams();
|
|
30383
|
+
if (teams.length > 1 && teams.every((t) => t.organizationId == null)) {
|
|
30384
|
+
dependencies.core.warning(
|
|
30385
|
+
"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."
|
|
30386
|
+
);
|
|
30387
|
+
}
|
|
30388
|
+
const orgIds = new Set(teams.filter((t) => t.organizationId != null).map((t) => t.organizationId));
|
|
30389
|
+
const meTeamId = parseInt(teamId, 10);
|
|
30390
|
+
const isOrgMode = teams.length > 1 && orgIds.size === 1 && orgIds.has(meTeamId);
|
|
30391
|
+
if (isOrgMode) {
|
|
30392
|
+
const teamList = teams.map((t) => ` ${t.id} ${t.name}`).join("\n");
|
|
30393
|
+
throw new Error(
|
|
30394
|
+
`Org-mode account detected. Workspace creation requires a specific sub-team ID.
|
|
30395
|
+
|
|
30396
|
+
Available sub-teams:
|
|
30397
|
+
${teamList}
|
|
30398
|
+
|
|
30399
|
+
To fix this, set the workspace-team-id input in your workflow:
|
|
30400
|
+
workspace-team-id: '<id>'
|
|
30401
|
+
|
|
30402
|
+
Or for reuse across runs, create a repository variable and reference it:
|
|
30403
|
+
workspace-team-id: \${{ vars.POSTMAN_WORKSPACE_TEAM_ID }}
|
|
30404
|
+
|
|
30405
|
+
For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID=<id>.`
|
|
30406
|
+
);
|
|
30407
|
+
} else if (teams.length > 1) {
|
|
30408
|
+
dependencies.core.warning(
|
|
30409
|
+
`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.`
|
|
30410
|
+
);
|
|
30411
|
+
}
|
|
30412
|
+
} catch (err) {
|
|
30413
|
+
if (err instanceof Error && err.message.includes("Org-mode account detected")) {
|
|
30414
|
+
throw err;
|
|
30415
|
+
}
|
|
30416
|
+
dependencies.core.warning(
|
|
30417
|
+
`Could not check for org-mode sub-teams: ${err instanceof Error ? err.message : String(err)}`
|
|
30418
|
+
);
|
|
30419
|
+
}
|
|
30420
|
+
}
|
|
30602
30421
|
if (!workspaceId) {
|
|
30603
30422
|
const workspace = await runGroup(
|
|
30604
30423
|
dependencies.core,
|
|
30605
30424
|
"Create Postman Workspace",
|
|
30606
|
-
async () => dependencies.postman.createWorkspace(workspaceName, aboutText)
|
|
30425
|
+
async () => dependencies.postman.createWorkspace(workspaceName, aboutText, workspaceTeamId)
|
|
30607
30426
|
);
|
|
30608
30427
|
workspaceId = workspace.id;
|
|
30609
30428
|
}
|
|
30610
30429
|
outputs["workspace-id"] = workspaceId || "";
|
|
30611
30430
|
outputs["workspace-url"] = `https://go.postman.co/workspace/${workspaceId}`;
|
|
30612
30431
|
outputs["workspace-name"] = workspaceName;
|
|
30613
|
-
await writeVariable(
|
|
30614
|
-
dependencies.github,
|
|
30615
|
-
inputs.projectName,
|
|
30616
|
-
"WORKSPACE_ID",
|
|
30617
|
-
outputs["workspace-id"],
|
|
30618
|
-
dependencies.core
|
|
30619
|
-
);
|
|
30620
30432
|
if (inputs.domain && dependencies.internalIntegration) {
|
|
30621
30433
|
await runGroup(
|
|
30622
30434
|
dependencies.core,
|
|
@@ -30671,33 +30483,43 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30671
30483
|
);
|
|
30672
30484
|
}
|
|
30673
30485
|
let specId = inputs.specId;
|
|
30674
|
-
if (!specId
|
|
30675
|
-
specId =
|
|
30486
|
+
if (!specId) {
|
|
30487
|
+
specId = getFirstCloudResourceId(resourcesState?.cloudResources?.specs);
|
|
30488
|
+
if (specId) {
|
|
30489
|
+
dependencies.core.info("Resolved spec-id from .postman/resources.yaml");
|
|
30490
|
+
}
|
|
30676
30491
|
}
|
|
30677
|
-
let baselineCollectionId = inputs.baselineCollectionId;
|
|
30678
|
-
let smokeCollectionId = inputs.smokeCollectionId;
|
|
30679
|
-
let contractCollectionId = inputs.contractCollectionId;
|
|
30680
|
-
if (
|
|
30492
|
+
let baselineCollectionId = inputs.collectionSyncMode === "refresh" ? void 0 : inputs.baselineCollectionId;
|
|
30493
|
+
let smokeCollectionId = inputs.collectionSyncMode === "refresh" ? void 0 : inputs.smokeCollectionId;
|
|
30494
|
+
let contractCollectionId = inputs.collectionSyncMode === "refresh" ? void 0 : inputs.contractCollectionId;
|
|
30495
|
+
if (inputs.collectionSyncMode !== "refresh") {
|
|
30496
|
+
const cloudCollections = resourcesState?.cloudResources?.collections;
|
|
30681
30497
|
if (!baselineCollectionId) {
|
|
30682
|
-
baselineCollectionId =
|
|
30683
|
-
|
|
30684
|
-
|
|
30685
|
-
"BASELINE_COLLECTION_UID"
|
|
30498
|
+
baselineCollectionId = findCloudResourceId(
|
|
30499
|
+
cloudCollections,
|
|
30500
|
+
(filePath) => filePath.includes("[Baseline]")
|
|
30686
30501
|
);
|
|
30502
|
+
if (baselineCollectionId) {
|
|
30503
|
+
dependencies.core.info("Resolved baseline-collection-id from .postman/resources.yaml");
|
|
30504
|
+
}
|
|
30687
30505
|
}
|
|
30688
30506
|
if (!smokeCollectionId) {
|
|
30689
|
-
smokeCollectionId =
|
|
30690
|
-
|
|
30691
|
-
|
|
30692
|
-
"SMOKE_COLLECTION_UID"
|
|
30507
|
+
smokeCollectionId = findCloudResourceId(
|
|
30508
|
+
cloudCollections,
|
|
30509
|
+
(filePath) => filePath.includes("[Smoke]")
|
|
30693
30510
|
);
|
|
30511
|
+
if (smokeCollectionId) {
|
|
30512
|
+
dependencies.core.info("Resolved smoke-collection-id from .postman/resources.yaml");
|
|
30513
|
+
}
|
|
30694
30514
|
}
|
|
30695
30515
|
if (!contractCollectionId) {
|
|
30696
|
-
contractCollectionId =
|
|
30697
|
-
|
|
30698
|
-
|
|
30699
|
-
"CONTRACT_COLLECTION_UID"
|
|
30516
|
+
contractCollectionId = findCloudResourceId(
|
|
30517
|
+
cloudCollections,
|
|
30518
|
+
(filePath) => filePath.includes("[Contract]")
|
|
30700
30519
|
);
|
|
30520
|
+
if (contractCollectionId) {
|
|
30521
|
+
dependencies.core.info("Resolved contract-collection-id from .postman/resources.yaml");
|
|
30522
|
+
}
|
|
30701
30523
|
}
|
|
30702
30524
|
}
|
|
30703
30525
|
if (specId) {
|
|
@@ -30721,7 +30543,10 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30721
30543
|
} else {
|
|
30722
30544
|
specId = await dependencies.postman.uploadSpec(
|
|
30723
30545
|
workspaceId || "",
|
|
30724
|
-
|
|
30546
|
+
createAssetProjectName(
|
|
30547
|
+
inputs,
|
|
30548
|
+
inputs.specSyncMode === "version" ? releaseLabel : void 0
|
|
30549
|
+
),
|
|
30725
30550
|
document
|
|
30726
30551
|
);
|
|
30727
30552
|
}
|
|
@@ -30730,13 +30555,6 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30730
30555
|
}
|
|
30731
30556
|
);
|
|
30732
30557
|
void specContent;
|
|
30733
|
-
await writeVariable(
|
|
30734
|
-
dependencies.github,
|
|
30735
|
-
inputs.projectName,
|
|
30736
|
-
"SPEC_UID",
|
|
30737
|
-
outputs["spec-id"],
|
|
30738
|
-
dependencies.core
|
|
30739
|
-
);
|
|
30740
30558
|
const lintSummary = await runGroup(
|
|
30741
30559
|
dependencies.core,
|
|
30742
30560
|
"Lint Spec via Postman CLI",
|
|
@@ -30774,13 +30592,15 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30774
30592
|
dependencies.core,
|
|
30775
30593
|
"Generate Collections from Spec",
|
|
30776
30594
|
async () => {
|
|
30777
|
-
|
|
30778
|
-
|
|
30779
|
-
outputs["
|
|
30595
|
+
const shouldReuseCollections = inputs.collectionSyncMode !== "refresh";
|
|
30596
|
+
const assetProjectName = inputs.collectionSyncMode === "version" ? createAssetProjectName(inputs, releaseLabel) : inputs.projectName;
|
|
30597
|
+
outputs["baseline-collection-id"] = shouldReuseCollections ? baselineCollectionId || "" : "";
|
|
30598
|
+
outputs["smoke-collection-id"] = shouldReuseCollections ? smokeCollectionId || "" : "";
|
|
30599
|
+
outputs["contract-collection-id"] = shouldReuseCollections ? contractCollectionId || "" : "";
|
|
30780
30600
|
if (!outputs["baseline-collection-id"]) {
|
|
30781
30601
|
outputs["baseline-collection-id"] = await dependencies.postman.generateCollection(
|
|
30782
30602
|
outputs["spec-id"],
|
|
30783
|
-
|
|
30603
|
+
assetProjectName,
|
|
30784
30604
|
"[Baseline]"
|
|
30785
30605
|
);
|
|
30786
30606
|
} else {
|
|
@@ -30788,17 +30608,10 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30788
30608
|
`Using existing baseline collection: ${outputs["baseline-collection-id"]}`
|
|
30789
30609
|
);
|
|
30790
30610
|
}
|
|
30791
|
-
await writeVariable(
|
|
30792
|
-
dependencies.github,
|
|
30793
|
-
inputs.projectName,
|
|
30794
|
-
"BASELINE_COLLECTION_UID",
|
|
30795
|
-
outputs["baseline-collection-id"],
|
|
30796
|
-
dependencies.core
|
|
30797
|
-
);
|
|
30798
30611
|
if (!outputs["smoke-collection-id"]) {
|
|
30799
30612
|
outputs["smoke-collection-id"] = await dependencies.postman.generateCollection(
|
|
30800
30613
|
outputs["spec-id"],
|
|
30801
|
-
|
|
30614
|
+
assetProjectName,
|
|
30802
30615
|
"[Smoke]"
|
|
30803
30616
|
);
|
|
30804
30617
|
} else {
|
|
@@ -30806,17 +30619,10 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30806
30619
|
`Using existing smoke collection: ${outputs["smoke-collection-id"]}`
|
|
30807
30620
|
);
|
|
30808
30621
|
}
|
|
30809
|
-
await writeVariable(
|
|
30810
|
-
dependencies.github,
|
|
30811
|
-
inputs.projectName,
|
|
30812
|
-
"SMOKE_COLLECTION_UID",
|
|
30813
|
-
outputs["smoke-collection-id"],
|
|
30814
|
-
dependencies.core
|
|
30815
|
-
);
|
|
30816
30622
|
if (!outputs["contract-collection-id"]) {
|
|
30817
30623
|
outputs["contract-collection-id"] = await dependencies.postman.generateCollection(
|
|
30818
30624
|
outputs["spec-id"],
|
|
30819
|
-
|
|
30625
|
+
assetProjectName,
|
|
30820
30626
|
"[Contract]"
|
|
30821
30627
|
);
|
|
30822
30628
|
} else {
|
|
@@ -30824,13 +30630,6 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30824
30630
|
`Using existing contract collection: ${outputs["contract-collection-id"]}`
|
|
30825
30631
|
);
|
|
30826
30632
|
}
|
|
30827
|
-
await writeVariable(
|
|
30828
|
-
dependencies.github,
|
|
30829
|
-
inputs.projectName,
|
|
30830
|
-
"CONTRACT_COLLECTION_UID",
|
|
30831
|
-
outputs["contract-collection-id"],
|
|
30832
|
-
dependencies.core
|
|
30833
|
-
);
|
|
30834
30633
|
}
|
|
30835
30634
|
);
|
|
30836
30635
|
outputs["collections-json"] = JSON.stringify({
|
|
@@ -30868,27 +30667,6 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
30868
30667
|
]);
|
|
30869
30668
|
}
|
|
30870
30669
|
);
|
|
30871
|
-
if (dependencies.github) {
|
|
30872
|
-
const github = dependencies.github;
|
|
30873
|
-
await runGroup(
|
|
30874
|
-
dependencies.core,
|
|
30875
|
-
"Store Postman UIDs as Repo Variables",
|
|
30876
|
-
async () => {
|
|
30877
|
-
await persistBootstrapRepositoryVariables(
|
|
30878
|
-
github,
|
|
30879
|
-
inputs.projectName,
|
|
30880
|
-
outputs,
|
|
30881
|
-
systemEnvMap,
|
|
30882
|
-
environments,
|
|
30883
|
-
{
|
|
30884
|
-
lintErrors: lintSummary.errors,
|
|
30885
|
-
lintWarnings: lintSummary.warnings
|
|
30886
|
-
},
|
|
30887
|
-
dependencies.core
|
|
30888
|
-
);
|
|
30889
|
-
}
|
|
30890
|
-
);
|
|
30891
|
-
}
|
|
30892
30670
|
for (const [name, value] of Object.entries(outputs)) {
|
|
30893
30671
|
dependencies.core.setOutput(name, value);
|
|
30894
30672
|
}
|
|
@@ -30902,9 +30680,6 @@ async function runAction(actionCore = core, actionExec = exec, actionIo = io) {
|
|
|
30902
30680
|
io: actionIo,
|
|
30903
30681
|
specFetcher: fetch
|
|
30904
30682
|
});
|
|
30905
|
-
if (!dependencies.github) {
|
|
30906
|
-
actionCore.info("GitHub repository variable persistence disabled for this run");
|
|
30907
|
-
}
|
|
30908
30683
|
if (inputs.domain && !dependencies.internalIntegration) {
|
|
30909
30684
|
actionCore.warning(
|
|
30910
30685
|
"Skipping governance assignment because postman-access-token is not configured"
|
|
@@ -30915,22 +30690,12 @@ async function runAction(actionCore = core, actionExec = exec, actionIo = io) {
|
|
|
30915
30690
|
function createBootstrapDependencies(inputs, factories) {
|
|
30916
30691
|
const secretMasker = createSecretMasker([
|
|
30917
30692
|
inputs.postmanApiKey,
|
|
30918
|
-
inputs.postmanAccessToken
|
|
30919
|
-
inputs.githubToken,
|
|
30920
|
-
inputs.ghFallbackToken
|
|
30693
|
+
inputs.postmanAccessToken
|
|
30921
30694
|
]);
|
|
30922
30695
|
const postman = new PostmanAssetsClient({
|
|
30923
30696
|
apiKey: inputs.postmanApiKey,
|
|
30924
30697
|
secretMasker
|
|
30925
30698
|
});
|
|
30926
|
-
const repository = extractRepositorySlug(inputs.repoUrl);
|
|
30927
|
-
const github = inputs.githubToken && inputs.repoUrl && repository ? new GitHubApiClient({
|
|
30928
|
-
authMode: inputs.githubAuthMode,
|
|
30929
|
-
fallbackToken: inputs.ghFallbackToken,
|
|
30930
|
-
repository,
|
|
30931
|
-
secretMasker,
|
|
30932
|
-
token: inputs.githubToken
|
|
30933
|
-
}) : void 0;
|
|
30934
30699
|
const internalIntegration = inputs.postmanAccessToken ? createInternalIntegrationAdapter({
|
|
30935
30700
|
accessToken: inputs.postmanAccessToken,
|
|
30936
30701
|
backend: inputs.integrationBackend,
|
|
@@ -30940,30 +30705,12 @@ function createBootstrapDependencies(inputs, factories) {
|
|
|
30940
30705
|
return {
|
|
30941
30706
|
core: factories.core,
|
|
30942
30707
|
exec: factories.exec,
|
|
30943
|
-
github,
|
|
30944
30708
|
io: factories.io,
|
|
30945
30709
|
internalIntegration,
|
|
30946
30710
|
postman,
|
|
30947
30711
|
specFetcher: factories.specFetcher ?? fetch
|
|
30948
30712
|
};
|
|
30949
30713
|
}
|
|
30950
|
-
function extractRepositorySlug(repoUrl) {
|
|
30951
|
-
const normalized = normalizeInputValue(repoUrl);
|
|
30952
|
-
if (!normalized) {
|
|
30953
|
-
return void 0;
|
|
30954
|
-
}
|
|
30955
|
-
try {
|
|
30956
|
-
const parsed = new URL(normalized);
|
|
30957
|
-
const pathname = parsed.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
|
|
30958
|
-
const segments = pathname.split("/").filter(Boolean);
|
|
30959
|
-
if (segments.length >= 2) {
|
|
30960
|
-
return `${segments[0]}/${segments[1]}`;
|
|
30961
|
-
}
|
|
30962
|
-
return void 0;
|
|
30963
|
-
} catch {
|
|
30964
|
-
return void 0;
|
|
30965
|
-
}
|
|
30966
|
-
}
|
|
30967
30714
|
var currentModulePath = typeof __filename === "string" ? __filename : "";
|
|
30968
30715
|
var entrypoint = process.argv[1];
|
|
30969
30716
|
if (entrypoint && currentModulePath === entrypoint) {
|
|
@@ -30979,7 +30726,6 @@ if (entrypoint && currentModulePath === entrypoint) {
|
|
|
30979
30726
|
0 && (module.exports = {
|
|
30980
30727
|
createBootstrapDependencies,
|
|
30981
30728
|
createPlannedOutputs,
|
|
30982
|
-
extractRepositorySlug,
|
|
30983
30729
|
getInput,
|
|
30984
30730
|
lintSpecViaCli,
|
|
30985
30731
|
normalizeSpecDocument,
|