@postman-cse/onboarding-repo-sync 2.1.5 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/action.yml +27 -1
- package/dist/action.cjs +866 -104
- package/dist/cli.cjs +1322 -108
- package/dist/index.cjs +876 -104
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -92333,11 +92333,11 @@ var require_valid = __commonJS({
|
|
|
92333
92333
|
var require_clean = __commonJS({
|
|
92334
92334
|
"node_modules/postman-collection/node_modules/semver/functions/clean.js"(exports2, module2) {
|
|
92335
92335
|
var parse2 = require_parse5();
|
|
92336
|
-
var
|
|
92336
|
+
var clean2 = (version2, options) => {
|
|
92337
92337
|
const s = parse2(version2.trim().replace(/^[=v]+/, ""), options);
|
|
92338
92338
|
return s ? s.version : null;
|
|
92339
92339
|
};
|
|
92340
|
-
module2.exports =
|
|
92340
|
+
module2.exports = clean2;
|
|
92341
92341
|
}
|
|
92342
92342
|
});
|
|
92343
92343
|
|
|
@@ -93648,7 +93648,7 @@ var require_semver2 = __commonJS({
|
|
|
93648
93648
|
var identifiers = require_identifiers();
|
|
93649
93649
|
var parse2 = require_parse5();
|
|
93650
93650
|
var valid = require_valid();
|
|
93651
|
-
var
|
|
93651
|
+
var clean2 = require_clean();
|
|
93652
93652
|
var inc = require_inc();
|
|
93653
93653
|
var diff = require_diff();
|
|
93654
93654
|
var major = require_major();
|
|
@@ -93686,7 +93686,7 @@ var require_semver2 = __commonJS({
|
|
|
93686
93686
|
module2.exports = {
|
|
93687
93687
|
parse: parse2,
|
|
93688
93688
|
valid,
|
|
93689
|
-
clean,
|
|
93689
|
+
clean: clean2,
|
|
93690
93690
|
inc,
|
|
93691
93691
|
diff,
|
|
93692
93692
|
major,
|
|
@@ -119787,14 +119787,19 @@ var require_node2 = __commonJS({
|
|
|
119787
119787
|
// src/index.ts
|
|
119788
119788
|
var index_exports = {};
|
|
119789
119789
|
__export(index_exports, {
|
|
119790
|
+
StateUnreadableError: () => StateUnreadableError,
|
|
119791
|
+
assertBranchAssetIds: () => assertBranchAssetIds,
|
|
119790
119792
|
assertPathWithinCwd: () => assertPathWithinCwd,
|
|
119793
|
+
buildBranchAssetMarker: () => buildBranchAssetMarker,
|
|
119791
119794
|
createRepoSyncDependencies: () => createRepoSyncDependencies,
|
|
119795
|
+
decideBranchTier: () => decideBranchTier,
|
|
119792
119796
|
getInput: () => getInput2,
|
|
119793
119797
|
hasInput: () => hasInput,
|
|
119794
119798
|
readActionInputs: () => readActionInputs,
|
|
119795
119799
|
resolveInputs: () => resolveInputs,
|
|
119796
119800
|
resolvePostmanApiKeyAndTeamId: () => resolvePostmanApiKeyAndTeamId,
|
|
119797
119801
|
runAction: () => runAction,
|
|
119802
|
+
runGatedSkip: () => runGatedSkip,
|
|
119798
119803
|
runRepoSync: () => runRepoSync
|
|
119799
119804
|
});
|
|
119800
119805
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -122078,7 +122083,7 @@ function getIDToken(aud) {
|
|
|
122078
122083
|
}
|
|
122079
122084
|
|
|
122080
122085
|
// src/index.ts
|
|
122081
|
-
var
|
|
122086
|
+
var import_node_fs4 = require("node:fs");
|
|
122082
122087
|
var path8 = __toESM(require("node:path"), 1);
|
|
122083
122088
|
|
|
122084
122089
|
// node_modules/js-yaml/dist/js-yaml.mjs
|
|
@@ -125201,6 +125206,9 @@ function buildCiWorkflowLines(installUrl, postmanRegion) {
|
|
|
125201
125206
|
" branches: [main]",
|
|
125202
125207
|
" schedule:",
|
|
125203
125208
|
' - cron: "0 */6 * * *"',
|
|
125209
|
+
"concurrency:",
|
|
125210
|
+
" group: postman-onboard-${{ github.head_ref || github.ref_name }}",
|
|
125211
|
+
" cancel-in-progress: false",
|
|
125204
125212
|
"jobs:",
|
|
125205
125213
|
" test:",
|
|
125206
125214
|
" runs-on: ubuntu-latest",
|
|
@@ -125217,7 +125225,7 @@ function buildCiWorkflowLines(installUrl, postmanRegion) {
|
|
|
125217
125225
|
" ruby <<'RUBY'",
|
|
125218
125226
|
" require 'yaml'",
|
|
125219
125227
|
" config = YAML.load_file('.postman/resources.yaml') || {}",
|
|
125220
|
-
" cloud = config.fetch('cloudResources', {})",
|
|
125228
|
+
" cloud = config.fetch('canonical', config.fetch('cloudResources', {}))",
|
|
125221
125229
|
" collections = cloud.fetch('collections', {})",
|
|
125222
125230
|
" environments = cloud.fetch('environments', {})",
|
|
125223
125231
|
" smoke = collections.find { |path, _| path.include?('[Smoke]') }&.last",
|
|
@@ -125415,6 +125423,58 @@ function buildAdoCiWorkflowLines(installUrl, postmanRegion) {
|
|
|
125415
125423
|
""
|
|
125416
125424
|
];
|
|
125417
125425
|
}
|
|
125426
|
+
function renderGcWorkflowTemplate() {
|
|
125427
|
+
return [
|
|
125428
|
+
"name: Postman Preview GC",
|
|
125429
|
+
"on:",
|
|
125430
|
+
" delete:",
|
|
125431
|
+
' branches: ["**"]',
|
|
125432
|
+
" pull_request:",
|
|
125433
|
+
" types: [closed]",
|
|
125434
|
+
" schedule:",
|
|
125435
|
+
' - cron: "0 2 * * *"',
|
|
125436
|
+
" workflow_dispatch:",
|
|
125437
|
+
" inputs:",
|
|
125438
|
+
" branch:",
|
|
125439
|
+
" description: Branch name to GC (optional, otherwise sweep by TTL/branch-existence)",
|
|
125440
|
+
" required: false",
|
|
125441
|
+
"concurrency:",
|
|
125442
|
+
" group: postman-preview-gc-${{ github.ref_name }}",
|
|
125443
|
+
" cancel-in-progress: false",
|
|
125444
|
+
"jobs:",
|
|
125445
|
+
" gc:",
|
|
125446
|
+
" runs-on: ubuntu-latest",
|
|
125447
|
+
" if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository",
|
|
125448
|
+
" steps:",
|
|
125449
|
+
" - uses: actions/checkout@v5",
|
|
125450
|
+
" with:",
|
|
125451
|
+
" fetch-depth: 0",
|
|
125452
|
+
" - name: Run Postman preview GC (provider-neutral cli.cjs gc)",
|
|
125453
|
+
" env:",
|
|
125454
|
+
" POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }}",
|
|
125455
|
+
" POSTMAN_ACCESS_TOKEN: ${{ secrets.POSTMAN_ACCESS_TOKEN }}",
|
|
125456
|
+
" POSTMAN_WORKSPACE_ID: ${{ vars.POSTMAN_WORKSPACE_ID }}",
|
|
125457
|
+
" REPO_URL: https://github.com/${{ github.repository }}",
|
|
125458
|
+
" run: |",
|
|
125459
|
+
" set -euo pipefail",
|
|
125460
|
+
" # The repo-sync action bundles a provider-neutral gc command (cli.cjs gc)",
|
|
125461
|
+
" # that uses the Postman access token for inventory/deletion and the",
|
|
125462
|
+
" # provider ambient credential (GITHUB_TOKEN via git ls-remote) for branch existence.",
|
|
125463
|
+
" # Daily scheduled run is the retention executor (TTL contract of last resort).",
|
|
125464
|
+
' if [ -n "${{ inputs.branch }}" ]; then',
|
|
125465
|
+
' npx @postman-cse/onboarding-repo-sync gc --branch "${{ inputs.branch }}" --workspace-id "$POSTMAN_WORKSPACE_ID" --repo-url "$REPO_URL"',
|
|
125466
|
+
" else",
|
|
125467
|
+
' npx @postman-cse/onboarding-repo-sync gc --workspace-id "$POSTMAN_WORKSPACE_ID" --repo-url "$REPO_URL"',
|
|
125468
|
+
" fi",
|
|
125469
|
+
" - name: Orphan audit summary (job summary)",
|
|
125470
|
+
" if: always()",
|
|
125471
|
+
" run: |",
|
|
125472
|
+
' echo "### Preview GC orphan audit" >> "$GITHUB_STEP_SUMMARY"',
|
|
125473
|
+
' echo "Marker-guarded deletion only \u2014 strangers (no marker) are never deleted. See gc-summary-json for structured counts." >> "$GITHUB_STEP_SUMMARY"',
|
|
125474
|
+
""
|
|
125475
|
+
].join("\n");
|
|
125476
|
+
}
|
|
125477
|
+
var GC_WORKFLOW_TEMPLATE = renderGcWorkflowTemplate();
|
|
125418
125478
|
function getCiWorkflowTemplate(provider, options = {}) {
|
|
125419
125479
|
if (provider === "azure-devops") {
|
|
125420
125480
|
const rawUrl = String(options.postmanCliInstallUrl || "").trim() || DEFAULT_POSTMAN_CLI_INSTALL_URL;
|
|
@@ -126985,6 +127045,53 @@ function createInternalIntegrationAdapter(options) {
|
|
|
126985
127045
|
return new BifrostInternalIntegrationAdapter(options);
|
|
126986
127046
|
}
|
|
126987
127047
|
|
|
127048
|
+
// src/lib/retry.ts
|
|
127049
|
+
function sleep(delayMs) {
|
|
127050
|
+
return new Promise((resolve3) => {
|
|
127051
|
+
setTimeout(resolve3, delayMs);
|
|
127052
|
+
});
|
|
127053
|
+
}
|
|
127054
|
+
function normalizeRetryOptions(options) {
|
|
127055
|
+
return {
|
|
127056
|
+
maxAttempts: Math.max(1, options.maxAttempts ?? 3),
|
|
127057
|
+
delayMs: Math.max(0, options.delayMs ?? 2e3),
|
|
127058
|
+
backoffMultiplier: Math.max(1, options.backoffMultiplier ?? 1),
|
|
127059
|
+
maxDelayMs: options.maxDelayMs === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, options.maxDelayMs),
|
|
127060
|
+
onRetry: options.onRetry ?? (async () => void 0),
|
|
127061
|
+
shouldRetry: options.shouldRetry ?? (() => true),
|
|
127062
|
+
sleep: options.sleep ?? sleep
|
|
127063
|
+
};
|
|
127064
|
+
}
|
|
127065
|
+
async function retry(operation, options = {}) {
|
|
127066
|
+
const normalized = normalizeRetryOptions(options);
|
|
127067
|
+
let nextDelayMs = normalized.delayMs;
|
|
127068
|
+
for (let attempt = 1; attempt <= normalized.maxAttempts; attempt += 1) {
|
|
127069
|
+
try {
|
|
127070
|
+
return await operation();
|
|
127071
|
+
} catch (error2) {
|
|
127072
|
+
const shouldRetry = attempt < normalized.maxAttempts && normalized.shouldRetry(error2, {
|
|
127073
|
+
attempt,
|
|
127074
|
+
maxAttempts: normalized.maxAttempts
|
|
127075
|
+
});
|
|
127076
|
+
if (!shouldRetry) {
|
|
127077
|
+
throw error2;
|
|
127078
|
+
}
|
|
127079
|
+
await normalized.onRetry({
|
|
127080
|
+
attempt,
|
|
127081
|
+
maxAttempts: normalized.maxAttempts,
|
|
127082
|
+
delayMs: nextDelayMs,
|
|
127083
|
+
error: error2
|
|
127084
|
+
});
|
|
127085
|
+
await normalized.sleep(nextDelayMs);
|
|
127086
|
+
nextDelayMs = Math.min(
|
|
127087
|
+
normalized.maxDelayMs,
|
|
127088
|
+
Math.round(nextDelayMs * normalized.backoffMultiplier)
|
|
127089
|
+
);
|
|
127090
|
+
}
|
|
127091
|
+
}
|
|
127092
|
+
throw new Error("Retry exhausted without returning or throwing");
|
|
127093
|
+
}
|
|
127094
|
+
|
|
126988
127095
|
// src/contracts.ts
|
|
126989
127096
|
var postmanRepoSyncActionContract = {
|
|
126990
127097
|
name: "postman-repo-sync-action",
|
|
@@ -127154,6 +127261,25 @@ var postmanRepoSyncActionContract = {
|
|
|
127154
127261
|
default: "warn",
|
|
127155
127262
|
allowedValues: ["enforce", "warn"]
|
|
127156
127263
|
},
|
|
127264
|
+
"branch-strategy": {
|
|
127265
|
+
description: "Branch-aware sync strategy. legacy (default) keeps branch-blind behavior; publish-gate restricts canonical writes to the canonical branch and skips repo-sync on other branches; preview additionally maintains suffixed per-branch preview asset sets.",
|
|
127266
|
+
required: false,
|
|
127267
|
+
default: "legacy",
|
|
127268
|
+
allowedValues: ["legacy", "preview", "publish-gate"]
|
|
127269
|
+
},
|
|
127270
|
+
"canonical-branch": {
|
|
127271
|
+
description: "Explicit canonical branch (the sole writer of canonical assets and tracked state). Defaults to the provider-resolved default branch; required on providers without a default-branch variable (Bitbucket, Azure DevOps) when branch-strategy is not legacy.",
|
|
127272
|
+
required: false
|
|
127273
|
+
},
|
|
127274
|
+
"channels": {
|
|
127275
|
+
description: 'Comma-separated channel map for long-lived promotion branches, e.g. "develop=DEV, staging=STAGE, release/*=RC". Channel branches maintain prefix-named parallel asset sets and never mutate canonical assets.',
|
|
127276
|
+
required: false
|
|
127277
|
+
},
|
|
127278
|
+
"preview-ttl": {
|
|
127279
|
+
description: "Sliding TTL in days for preview asset sets (refreshed on every successful preview sync; the retention contract of last resort when no provider credential is available for branch-existence checks).",
|
|
127280
|
+
required: false,
|
|
127281
|
+
default: "30"
|
|
127282
|
+
},
|
|
127157
127283
|
"github-token": {
|
|
127158
127284
|
description: "GitHub token used for repo variable persistence and commits.",
|
|
127159
127285
|
required: false
|
|
@@ -127191,6 +127317,11 @@ var postmanRepoSyncActionContract = {
|
|
|
127191
127317
|
description: "Spec UID from bootstrap, persisted into .postman/resources.yaml cloudResources.",
|
|
127192
127318
|
required: false
|
|
127193
127319
|
},
|
|
127320
|
+
"spec-content-changed": {
|
|
127321
|
+
description: "Whether bootstrap changed canonical spec content; controls final native Spec Hub tag publication.",
|
|
127322
|
+
required: false,
|
|
127323
|
+
default: "true"
|
|
127324
|
+
},
|
|
127194
127325
|
"spec-path": {
|
|
127195
127326
|
description: "Optional repo-root-relative path to the local spec file for resources/workflows metadata.",
|
|
127196
127327
|
required: false
|
|
@@ -127235,6 +127366,18 @@ var postmanRepoSyncActionContract = {
|
|
|
127235
127366
|
},
|
|
127236
127367
|
"commit-sha": {
|
|
127237
127368
|
description: "Commit SHA produced by repo-write-mode, if any."
|
|
127369
|
+
},
|
|
127370
|
+
"sync-status": {
|
|
127371
|
+
description: "Branch-aware sync status: synced, skipped-branch-gate, or empty under branch-strategy legacy."
|
|
127372
|
+
},
|
|
127373
|
+
"branch-decision": {
|
|
127374
|
+
description: "Serialized BranchDecision JSON for downstream actions (also exported as POSTMAN_BRANCH_DECISION)."
|
|
127375
|
+
},
|
|
127376
|
+
"spec-version-tag": {
|
|
127377
|
+
description: "Native Spec Hub version tag created after successful canonical repo-sync finalization."
|
|
127378
|
+
},
|
|
127379
|
+
"spec-version-url": {
|
|
127380
|
+
description: "Read-only URL for the tagged Spec Hub snapshot."
|
|
127238
127381
|
}
|
|
127239
127382
|
},
|
|
127240
127383
|
behavior: {
|
|
@@ -127302,53 +127445,6 @@ var PostmanAssetsClient = class {
|
|
|
127302
127445
|
}
|
|
127303
127446
|
};
|
|
127304
127447
|
|
|
127305
|
-
// src/lib/retry.ts
|
|
127306
|
-
function sleep(delayMs) {
|
|
127307
|
-
return new Promise((resolve3) => {
|
|
127308
|
-
setTimeout(resolve3, delayMs);
|
|
127309
|
-
});
|
|
127310
|
-
}
|
|
127311
|
-
function normalizeRetryOptions(options) {
|
|
127312
|
-
return {
|
|
127313
|
-
maxAttempts: Math.max(1, options.maxAttempts ?? 3),
|
|
127314
|
-
delayMs: Math.max(0, options.delayMs ?? 2e3),
|
|
127315
|
-
backoffMultiplier: Math.max(1, options.backoffMultiplier ?? 1),
|
|
127316
|
-
maxDelayMs: options.maxDelayMs === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, options.maxDelayMs),
|
|
127317
|
-
onRetry: options.onRetry ?? (async () => void 0),
|
|
127318
|
-
shouldRetry: options.shouldRetry ?? (() => true),
|
|
127319
|
-
sleep: options.sleep ?? sleep
|
|
127320
|
-
};
|
|
127321
|
-
}
|
|
127322
|
-
async function retry(operation, options = {}) {
|
|
127323
|
-
const normalized = normalizeRetryOptions(options);
|
|
127324
|
-
let nextDelayMs = normalized.delayMs;
|
|
127325
|
-
for (let attempt = 1; attempt <= normalized.maxAttempts; attempt += 1) {
|
|
127326
|
-
try {
|
|
127327
|
-
return await operation();
|
|
127328
|
-
} catch (error2) {
|
|
127329
|
-
const shouldRetry = attempt < normalized.maxAttempts && normalized.shouldRetry(error2, {
|
|
127330
|
-
attempt,
|
|
127331
|
-
maxAttempts: normalized.maxAttempts
|
|
127332
|
-
});
|
|
127333
|
-
if (!shouldRetry) {
|
|
127334
|
-
throw error2;
|
|
127335
|
-
}
|
|
127336
|
-
await normalized.onRetry({
|
|
127337
|
-
attempt,
|
|
127338
|
-
maxAttempts: normalized.maxAttempts,
|
|
127339
|
-
delayMs: nextDelayMs,
|
|
127340
|
-
error: error2
|
|
127341
|
-
});
|
|
127342
|
-
await normalized.sleep(nextDelayMs);
|
|
127343
|
-
nextDelayMs = Math.min(
|
|
127344
|
-
normalized.maxDelayMs,
|
|
127345
|
-
Math.round(nextDelayMs * normalized.backoffMultiplier)
|
|
127346
|
-
);
|
|
127347
|
-
}
|
|
127348
|
-
}
|
|
127349
|
-
throw new Error("Retry exhausted without returning or throwing");
|
|
127350
|
-
}
|
|
127351
|
-
|
|
127352
127448
|
// src/lib/postman/postman-gateway-assets-client.ts
|
|
127353
127449
|
var MAX_CREATE_FLIGHTS = 256;
|
|
127354
127450
|
var createFlights = /* @__PURE__ */ new Map();
|
|
@@ -127374,6 +127470,84 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127374
127470
|
if (!envelope) return null;
|
|
127375
127471
|
return this.asRecord(envelope.data) ?? envelope;
|
|
127376
127472
|
}
|
|
127473
|
+
/** Native Spec Hub tags attach to the latest changelog group. */
|
|
127474
|
+
async tagSpecVersion(specId, name) {
|
|
127475
|
+
const trimmed = name.trim().slice(0, 255);
|
|
127476
|
+
const response = await this.gateway.requestJson({
|
|
127477
|
+
service: "specification",
|
|
127478
|
+
method: "post",
|
|
127479
|
+
path: `/specifications/${specId}/tags`,
|
|
127480
|
+
body: { name: trimmed }
|
|
127481
|
+
});
|
|
127482
|
+
const record = this.dataOf(response) ?? {};
|
|
127483
|
+
return { id: String(record.id ?? "").trim(), name: String(record.name ?? trimmed).trim() };
|
|
127484
|
+
}
|
|
127485
|
+
async listSpecVersionTags(specId) {
|
|
127486
|
+
const response = await this.gateway.requestJson({
|
|
127487
|
+
service: "specification",
|
|
127488
|
+
method: "get",
|
|
127489
|
+
path: `/specifications/${specId}/tags`,
|
|
127490
|
+
query: { limit: "50" }
|
|
127491
|
+
});
|
|
127492
|
+
const data = Array.isArray(response?.data) ? response.data : [];
|
|
127493
|
+
return data.map((entry) => this.asRecord(entry)).filter((entry) => entry !== null).map((entry) => ({
|
|
127494
|
+
id: String(entry.id ?? "").trim(),
|
|
127495
|
+
// listTags returns `message`; createTag returns `name`. Accept both.
|
|
127496
|
+
name: String(entry.name ?? entry.message ?? "").trim()
|
|
127497
|
+
})).filter((entry) => entry.id || entry.name);
|
|
127498
|
+
}
|
|
127499
|
+
async deleteCollection(collectionUid) {
|
|
127500
|
+
const bareId = String(collectionUid).split("-").slice(-5).join("-") || collectionUid;
|
|
127501
|
+
await this.gateway.requestJson({
|
|
127502
|
+
service: "collection",
|
|
127503
|
+
method: "delete",
|
|
127504
|
+
path: `/v3/collections/${bareId}`
|
|
127505
|
+
});
|
|
127506
|
+
}
|
|
127507
|
+
async listSpecifications(workspaceId) {
|
|
127508
|
+
const response = await this.gateway.requestJson({
|
|
127509
|
+
service: "specification",
|
|
127510
|
+
method: "get",
|
|
127511
|
+
path: `/specifications?containerType=workspace&containerId=${workspaceId}`
|
|
127512
|
+
});
|
|
127513
|
+
const data = Array.isArray(response?.data) ? response.data : [];
|
|
127514
|
+
return data.map((entry) => this.asRecord(entry)).filter((entry) => entry !== null).map((entry) => ({ uid: String(entry.id ?? entry.uid ?? "").trim(), name: String(entry.name ?? "").trim() })).filter((entry) => entry.uid && entry.name);
|
|
127515
|
+
}
|
|
127516
|
+
async getSpecContent(specId) {
|
|
127517
|
+
const files = await this.gateway.requestJson({
|
|
127518
|
+
service: "specification",
|
|
127519
|
+
method: "get",
|
|
127520
|
+
path: `/specifications/${specId}/files`
|
|
127521
|
+
});
|
|
127522
|
+
const entries = Array.isArray(files?.data) ? files.data : [];
|
|
127523
|
+
const root = entries.map((entry) => this.asRecord(entry)).find((entry) => entry?.type === "ROOT") ?? entries.map((entry) => this.asRecord(entry)).find((entry) => entry !== null);
|
|
127524
|
+
const fileId = String(root?.id ?? "").trim();
|
|
127525
|
+
if (!fileId) return void 0;
|
|
127526
|
+
const file = await this.gateway.requestJson({
|
|
127527
|
+
service: "specification",
|
|
127528
|
+
method: "get",
|
|
127529
|
+
path: `/specifications/${specId}/files/${fileId}`,
|
|
127530
|
+
query: { fields: "content" }
|
|
127531
|
+
});
|
|
127532
|
+
const record = this.dataOf(file);
|
|
127533
|
+
return typeof record?.content === "string" ? record.content : void 0;
|
|
127534
|
+
}
|
|
127535
|
+
async listSpecCollections(specId) {
|
|
127536
|
+
const response = await this.gateway.requestJson({
|
|
127537
|
+
service: "specification",
|
|
127538
|
+
method: "get",
|
|
127539
|
+
path: `/specifications/${specId}/collections`
|
|
127540
|
+
});
|
|
127541
|
+
const data = Array.isArray(response?.data) ? response.data : [];
|
|
127542
|
+
return data.map((entry) => this.asRecord(entry)).filter((entry) => entry !== null).map((entry) => ({ uid: String(entry.collection ?? entry.collectionId ?? entry.id ?? "").trim(), name: String(entry.name ?? "").trim() })).filter((entry) => entry.uid);
|
|
127543
|
+
}
|
|
127544
|
+
async deleteSpec(specId) {
|
|
127545
|
+
await this.gateway.requestJson({
|
|
127546
|
+
service: "specification",
|
|
127547
|
+
method: "delete",
|
|
127548
|
+
path: `/specifications/${specId}`
|
|
127549
|
+
});
|
|
127550
|
+
}
|
|
127377
127551
|
idOf(record) {
|
|
127378
127552
|
if (!record) return "";
|
|
127379
127553
|
const id = record.uid ?? record.id;
|
|
@@ -127658,6 +127832,9 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127658
127832
|
path: `/mocks?workspace=${ws}`,
|
|
127659
127833
|
body
|
|
127660
127834
|
},
|
|
127835
|
+
// Unsafe create: never blind re-POST. An ESOCKETTIMEDOUT after accept
|
|
127836
|
+
// may still have created the mock; reconcile via discovery below and
|
|
127837
|
+
// let the orchestrator retry the whole create-or-adopt cycle.
|
|
127661
127838
|
{ retryTransient: false }
|
|
127662
127839
|
);
|
|
127663
127840
|
const record = this.dataOf(response);
|
|
@@ -127696,6 +127873,33 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127696
127873
|
environment: String(m.environment ?? "")
|
|
127697
127874
|
}));
|
|
127698
127875
|
}
|
|
127876
|
+
/**
|
|
127877
|
+
* Delete an environment through the sync service (GC path). The path id is
|
|
127878
|
+
* the bare model id (public uid tail), mirroring updateEnvironment.
|
|
127879
|
+
*/
|
|
127880
|
+
async deleteEnvironment(uid) {
|
|
127881
|
+
await this.gateway.requestJson({
|
|
127882
|
+
service: "sync",
|
|
127883
|
+
method: "delete",
|
|
127884
|
+
path: `/environment/${this.toModelId(uid)}`
|
|
127885
|
+
});
|
|
127886
|
+
}
|
|
127887
|
+
/** Delete a mock server (GC path). */
|
|
127888
|
+
async deleteMock(uid) {
|
|
127889
|
+
await this.gateway.requestJson({
|
|
127890
|
+
service: "mock",
|
|
127891
|
+
method: "delete",
|
|
127892
|
+
path: `/mocks/${this.toModelId(uid)}`
|
|
127893
|
+
});
|
|
127894
|
+
}
|
|
127895
|
+
/** Delete a collection-based monitor (jobTemplate) (GC path). */
|
|
127896
|
+
async deleteMonitor(uid) {
|
|
127897
|
+
await this.gateway.requestJson({
|
|
127898
|
+
service: "monitors",
|
|
127899
|
+
method: "delete",
|
|
127900
|
+
path: `/jobTemplates/${this.toModelId(uid)}`
|
|
127901
|
+
});
|
|
127902
|
+
}
|
|
127699
127903
|
async mockExists(uid) {
|
|
127700
127904
|
try {
|
|
127701
127905
|
await this.gateway.requestJson({
|
|
@@ -128202,6 +128406,331 @@ function validateCertMaterial(certBase64, keyBase64, passphrase) {
|
|
|
128202
128406
|
}
|
|
128203
128407
|
}
|
|
128204
128408
|
|
|
128409
|
+
// src/lib/repo/branch-decision.ts
|
|
128410
|
+
var import_node_fs3 = require("node:fs");
|
|
128411
|
+
var import_node_crypto3 = require("node:crypto");
|
|
128412
|
+
var ContractError = class extends Error {
|
|
128413
|
+
code;
|
|
128414
|
+
constructor(code, message) {
|
|
128415
|
+
super(`${code}: ${message}`);
|
|
128416
|
+
this.code = code;
|
|
128417
|
+
this.name = "ContractError";
|
|
128418
|
+
}
|
|
128419
|
+
};
|
|
128420
|
+
function clean(value) {
|
|
128421
|
+
const trimmed = (value ?? "").trim();
|
|
128422
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
128423
|
+
}
|
|
128424
|
+
function stripRefPrefix(ref) {
|
|
128425
|
+
const raw = clean(ref);
|
|
128426
|
+
if (!raw) {
|
|
128427
|
+
return { kind: "unknown" };
|
|
128428
|
+
}
|
|
128429
|
+
if (raw.startsWith("refs/heads/")) {
|
|
128430
|
+
return { name: raw.slice("refs/heads/".length), kind: "branch" };
|
|
128431
|
+
}
|
|
128432
|
+
if (raw.startsWith("refs/tags/")) {
|
|
128433
|
+
return { name: raw.slice("refs/tags/".length), kind: "tag" };
|
|
128434
|
+
}
|
|
128435
|
+
if (raw.startsWith("refs/pull/") || raw.startsWith("refs/merge")) {
|
|
128436
|
+
return { kind: "unknown" };
|
|
128437
|
+
}
|
|
128438
|
+
return { name: raw, kind: "branch" };
|
|
128439
|
+
}
|
|
128440
|
+
function detectProvider(env) {
|
|
128441
|
+
if (clean(env.GITHUB_ACTIONS) || clean(env.GITHUB_REPOSITORY)) return "github";
|
|
128442
|
+
if (clean(env.GITLAB_CI) || clean(env.CI_PROJECT_PATH)) return "gitlab";
|
|
128443
|
+
if (clean(env.BITBUCKET_REPO_SLUG) || clean(env.BITBUCKET_BRANCH)) return "bitbucket";
|
|
128444
|
+
if (clean(env.TF_BUILD) || clean(env.BUILD_REPOSITORY_URI)) return "azure-devops";
|
|
128445
|
+
return "unknown";
|
|
128446
|
+
}
|
|
128447
|
+
function readGithubEvent(env) {
|
|
128448
|
+
const path9 = clean(env.GITHUB_EVENT_PATH);
|
|
128449
|
+
if (!path9) return void 0;
|
|
128450
|
+
try {
|
|
128451
|
+
return JSON.parse((0, import_node_fs3.readFileSync)(path9, "utf8"));
|
|
128452
|
+
} catch {
|
|
128453
|
+
return void 0;
|
|
128454
|
+
}
|
|
128455
|
+
}
|
|
128456
|
+
function resolveBranchIdentity(env = process.env, overrides = {}) {
|
|
128457
|
+
const provider = detectProvider(env);
|
|
128458
|
+
const explicitDefault = clean(overrides.defaultBranch);
|
|
128459
|
+
let headBranch;
|
|
128460
|
+
let rawRef;
|
|
128461
|
+
let refKind;
|
|
128462
|
+
let isPrContext = false;
|
|
128463
|
+
let isForkPr = false;
|
|
128464
|
+
let defaultBranch = explicitDefault;
|
|
128465
|
+
let headSha;
|
|
128466
|
+
switch (provider) {
|
|
128467
|
+
case "github": {
|
|
128468
|
+
const event = readGithubEvent(env);
|
|
128469
|
+
headSha = clean(env.GITHUB_SHA);
|
|
128470
|
+
defaultBranch ??= clean(event?.repository?.default_branch);
|
|
128471
|
+
const headRef = clean(env.GITHUB_HEAD_REF);
|
|
128472
|
+
if (headRef) {
|
|
128473
|
+
isPrContext = true;
|
|
128474
|
+
headBranch = headRef;
|
|
128475
|
+
rawRef = clean(env.GITHUB_REF) ?? headRef;
|
|
128476
|
+
refKind = "branch";
|
|
128477
|
+
const headRepo = event?.pull_request?.head?.repo?.full_name;
|
|
128478
|
+
const baseRepo = event?.pull_request?.base?.repo?.full_name ?? event?.repository?.full_name;
|
|
128479
|
+
isForkPr = Boolean(headRepo && baseRepo && headRepo !== baseRepo);
|
|
128480
|
+
headSha = clean(event?.pull_request?.head?.sha) ?? headSha;
|
|
128481
|
+
} else {
|
|
128482
|
+
rawRef = clean(env.GITHUB_REF) ?? clean(env.GITHUB_REF_NAME);
|
|
128483
|
+
const parsed = stripRefPrefix(rawRef);
|
|
128484
|
+
headBranch = parsed.kind === "branch" ? parsed.name : void 0;
|
|
128485
|
+
refKind = parsed.kind;
|
|
128486
|
+
}
|
|
128487
|
+
break;
|
|
128488
|
+
}
|
|
128489
|
+
case "gitlab": {
|
|
128490
|
+
headSha = clean(env.CI_COMMIT_SHA);
|
|
128491
|
+
defaultBranch ??= clean(env.CI_DEFAULT_BRANCH);
|
|
128492
|
+
const mrSource = clean(env.CI_MERGE_REQUEST_SOURCE_BRANCH_NAME);
|
|
128493
|
+
if (mrSource) {
|
|
128494
|
+
isPrContext = true;
|
|
128495
|
+
headBranch = mrSource;
|
|
128496
|
+
rawRef = mrSource;
|
|
128497
|
+
refKind = "branch";
|
|
128498
|
+
const sourceProject = clean(env.CI_MERGE_REQUEST_SOURCE_PROJECT_ID);
|
|
128499
|
+
const targetProject = clean(env.CI_MERGE_REQUEST_PROJECT_ID);
|
|
128500
|
+
isForkPr = Boolean(sourceProject && targetProject && sourceProject !== targetProject);
|
|
128501
|
+
} else if (clean(env.CI_COMMIT_TAG)) {
|
|
128502
|
+
rawRef = clean(env.CI_COMMIT_TAG);
|
|
128503
|
+
refKind = "tag";
|
|
128504
|
+
} else {
|
|
128505
|
+
headBranch = clean(env.CI_COMMIT_BRANCH) ?? clean(env.CI_COMMIT_REF_NAME);
|
|
128506
|
+
rawRef = headBranch;
|
|
128507
|
+
refKind = headBranch ? "branch" : "unknown";
|
|
128508
|
+
}
|
|
128509
|
+
break;
|
|
128510
|
+
}
|
|
128511
|
+
case "bitbucket": {
|
|
128512
|
+
headSha = clean(env.BITBUCKET_COMMIT);
|
|
128513
|
+
if (clean(env.BITBUCKET_TAG)) {
|
|
128514
|
+
rawRef = clean(env.BITBUCKET_TAG);
|
|
128515
|
+
refKind = "tag";
|
|
128516
|
+
} else {
|
|
128517
|
+
headBranch = clean(env.BITBUCKET_BRANCH);
|
|
128518
|
+
rawRef = headBranch;
|
|
128519
|
+
refKind = headBranch ? "branch" : "unknown";
|
|
128520
|
+
isPrContext = Boolean(clean(env.BITBUCKET_PR_ID));
|
|
128521
|
+
}
|
|
128522
|
+
break;
|
|
128523
|
+
}
|
|
128524
|
+
case "azure-devops": {
|
|
128525
|
+
headSha = clean(env.BUILD_SOURCEVERSION);
|
|
128526
|
+
const prSource = clean(env.SYSTEM_PULLREQUEST_SOURCEBRANCH);
|
|
128527
|
+
if (prSource) {
|
|
128528
|
+
isPrContext = true;
|
|
128529
|
+
const parsed = stripRefPrefix(prSource);
|
|
128530
|
+
headBranch = parsed.kind === "branch" ? parsed.name : void 0;
|
|
128531
|
+
rawRef = prSource;
|
|
128532
|
+
refKind = parsed.kind;
|
|
128533
|
+
const forkFlag = clean(env.SYSTEM_PULLREQUEST_ISFORK);
|
|
128534
|
+
isForkPr = forkFlag?.toLowerCase() === "true";
|
|
128535
|
+
} else {
|
|
128536
|
+
rawRef = clean(env.BUILD_SOURCEBRANCH);
|
|
128537
|
+
const parsed = stripRefPrefix(rawRef);
|
|
128538
|
+
headBranch = parsed.kind === "branch" ? parsed.name : void 0;
|
|
128539
|
+
refKind = parsed.kind;
|
|
128540
|
+
}
|
|
128541
|
+
break;
|
|
128542
|
+
}
|
|
128543
|
+
default: {
|
|
128544
|
+
refKind = "unknown";
|
|
128545
|
+
}
|
|
128546
|
+
}
|
|
128547
|
+
if (refKind === "branch" && headBranch && defaultBranch && headBranch === defaultBranch) {
|
|
128548
|
+
refKind = "default-branch";
|
|
128549
|
+
}
|
|
128550
|
+
return { provider, headBranch, rawRef, defaultBranch, refKind, isPrContext, isForkPr, headSha };
|
|
128551
|
+
}
|
|
128552
|
+
function parseChannelRules(input) {
|
|
128553
|
+
const raw = clean(input);
|
|
128554
|
+
const rules = [];
|
|
128555
|
+
for (const part of raw ? raw.split(",") : []) {
|
|
128556
|
+
const entry = part.trim();
|
|
128557
|
+
if (!entry) continue;
|
|
128558
|
+
const eq = entry.indexOf("=");
|
|
128559
|
+
if (eq <= 0 || eq === entry.length - 1) {
|
|
128560
|
+
throw new ContractError(
|
|
128561
|
+
"CONTRACT_CHANNELS_INPUT_INVALID",
|
|
128562
|
+
`channels entry "${entry}" must be <branch-or-glob>=<CODE>`
|
|
128563
|
+
);
|
|
128564
|
+
}
|
|
128565
|
+
const pattern = entry.slice(0, eq).trim();
|
|
128566
|
+
const code = entry.slice(eq + 1).trim().toUpperCase();
|
|
128567
|
+
if (!/^[A-Z][A-Z0-9_-]{0,15}$/.test(code)) {
|
|
128568
|
+
throw new ContractError(
|
|
128569
|
+
"CONTRACT_CHANNELS_INPUT_INVALID",
|
|
128570
|
+
`channel code "${code}" must be 1-16 chars, A-Z 0-9 _ -, starting with a letter`
|
|
128571
|
+
);
|
|
128572
|
+
}
|
|
128573
|
+
rules.push({ pattern, code });
|
|
128574
|
+
}
|
|
128575
|
+
if (!rules.some((rule) => rule.pattern === "release/*")) {
|
|
128576
|
+
rules.push({ pattern: "release/*", code: "RC" });
|
|
128577
|
+
}
|
|
128578
|
+
return rules;
|
|
128579
|
+
}
|
|
128580
|
+
function matchChannel(branch, rules) {
|
|
128581
|
+
for (const rule of rules) {
|
|
128582
|
+
if (rule.pattern.endsWith("*")) {
|
|
128583
|
+
const prefix = rule.pattern.slice(0, -1);
|
|
128584
|
+
if (branch.startsWith(prefix)) return rule;
|
|
128585
|
+
} else if (branch === rule.pattern) {
|
|
128586
|
+
return rule;
|
|
128587
|
+
}
|
|
128588
|
+
}
|
|
128589
|
+
return void 0;
|
|
128590
|
+
}
|
|
128591
|
+
function resolveBranchDecision(options) {
|
|
128592
|
+
const { strategy, identity } = options;
|
|
128593
|
+
const channels = options.channels ?? [];
|
|
128594
|
+
if (strategy === "legacy") {
|
|
128595
|
+
return {
|
|
128596
|
+
tier: "legacy",
|
|
128597
|
+
strategy,
|
|
128598
|
+
identity,
|
|
128599
|
+
canonicalBranch: clean(options.canonicalBranch) ?? identity.defaultBranch,
|
|
128600
|
+
reason: "branch-strategy legacy: branch-blind pre-v2 behavior"
|
|
128601
|
+
};
|
|
128602
|
+
}
|
|
128603
|
+
const canonicalBranch = clean(options.canonicalBranch) ?? identity.defaultBranch;
|
|
128604
|
+
if (!canonicalBranch) {
|
|
128605
|
+
throw new ContractError(
|
|
128606
|
+
"CONTRACT_DEFAULT_BRANCH_UNRESOLVED",
|
|
128607
|
+
`cannot resolve the canonical branch on ${identity.provider} (no explicit canonical-branch input and the provider exposes no default-branch variable). Set the canonical-branch input.`
|
|
128608
|
+
);
|
|
128609
|
+
}
|
|
128610
|
+
if (identity.refKind === "tag" || identity.refKind === "unknown" || !identity.headBranch) {
|
|
128611
|
+
return {
|
|
128612
|
+
tier: "gated",
|
|
128613
|
+
strategy,
|
|
128614
|
+
identity,
|
|
128615
|
+
canonicalBranch,
|
|
128616
|
+
reason: `ref kind ${identity.refKind}: never canonical/preview-eligible; no-op with annotation`
|
|
128617
|
+
};
|
|
128618
|
+
}
|
|
128619
|
+
if (identity.headBranch === canonicalBranch) {
|
|
128620
|
+
return {
|
|
128621
|
+
tier: "canonical",
|
|
128622
|
+
strategy,
|
|
128623
|
+
identity,
|
|
128624
|
+
canonicalBranch,
|
|
128625
|
+
reason: `head branch equals canonical branch ${canonicalBranch}`
|
|
128626
|
+
};
|
|
128627
|
+
}
|
|
128628
|
+
const channel = matchChannel(identity.headBranch, channels);
|
|
128629
|
+
if (channel) {
|
|
128630
|
+
return {
|
|
128631
|
+
tier: "channel",
|
|
128632
|
+
strategy,
|
|
128633
|
+
identity,
|
|
128634
|
+
canonicalBranch,
|
|
128635
|
+
channel,
|
|
128636
|
+
reason: `branch ${identity.headBranch} matches channel ${channel.pattern}=${channel.code}`
|
|
128637
|
+
};
|
|
128638
|
+
}
|
|
128639
|
+
if (strategy === "preview") {
|
|
128640
|
+
if (identity.isForkPr) {
|
|
128641
|
+
return {
|
|
128642
|
+
tier: "gated",
|
|
128643
|
+
strategy,
|
|
128644
|
+
identity,
|
|
128645
|
+
canonicalBranch,
|
|
128646
|
+
reason: "fork PR: preview-ineligible (same-repo gate), gated instead"
|
|
128647
|
+
};
|
|
128648
|
+
}
|
|
128649
|
+
return {
|
|
128650
|
+
tier: "preview",
|
|
128651
|
+
strategy,
|
|
128652
|
+
identity,
|
|
128653
|
+
canonicalBranch,
|
|
128654
|
+
reason: `branch ${identity.headBranch} under branch-strategy preview`
|
|
128655
|
+
};
|
|
128656
|
+
}
|
|
128657
|
+
return {
|
|
128658
|
+
tier: "gated",
|
|
128659
|
+
strategy,
|
|
128660
|
+
identity,
|
|
128661
|
+
canonicalBranch,
|
|
128662
|
+
reason: `branch ${identity.headBranch} under branch-strategy publish-gate`
|
|
128663
|
+
};
|
|
128664
|
+
}
|
|
128665
|
+
var BRANCH_DECISION_ENV = "POSTMAN_BRANCH_DECISION";
|
|
128666
|
+
function serializeBranchDecision(decision) {
|
|
128667
|
+
return JSON.stringify(decision);
|
|
128668
|
+
}
|
|
128669
|
+
function parseBranchDecision(raw) {
|
|
128670
|
+
const value = clean(raw);
|
|
128671
|
+
if (!value) return void 0;
|
|
128672
|
+
let parsed;
|
|
128673
|
+
try {
|
|
128674
|
+
parsed = JSON.parse(value);
|
|
128675
|
+
} catch {
|
|
128676
|
+
throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION is not valid JSON");
|
|
128677
|
+
}
|
|
128678
|
+
const candidate = parsed;
|
|
128679
|
+
const tiers = ["canonical", "channel", "preview", "gated", "legacy"];
|
|
128680
|
+
if (!candidate || typeof candidate !== "object" || !tiers.includes(candidate.tier) || !candidate.identity) {
|
|
128681
|
+
throw new ContractError("CONTRACT_BRANCH_DECISION_INVALID", "POSTMAN_BRANCH_DECISION does not carry a valid BranchDecision");
|
|
128682
|
+
}
|
|
128683
|
+
return candidate;
|
|
128684
|
+
}
|
|
128685
|
+
function resolveEffectiveBranchDecision(options, env = process.env) {
|
|
128686
|
+
const inherited = parseBranchDecision(env[BRANCH_DECISION_ENV]);
|
|
128687
|
+
if (inherited) return inherited;
|
|
128688
|
+
return resolveBranchDecision(options);
|
|
128689
|
+
}
|
|
128690
|
+
var PREVIEW_SLUG_MAX = 30;
|
|
128691
|
+
function buildBranchSlug(rawBranch) {
|
|
128692
|
+
const sanitized = rawBranch.replace(/^refs\/heads\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
|
|
128693
|
+
const truncated = sanitized.slice(0, PREVIEW_SLUG_MAX);
|
|
128694
|
+
const lossy = truncated !== rawBranch.replace(/^refs\/heads\//, "");
|
|
128695
|
+
if (!lossy) {
|
|
128696
|
+
return { suffix: truncated, slug: truncated, lossy };
|
|
128697
|
+
}
|
|
128698
|
+
const hash = (0, import_node_crypto3.createHash)("sha256").update(rawBranch).digest("hex").slice(0, 6);
|
|
128699
|
+
return { suffix: `${truncated}-${hash}`, slug: truncated, lossy };
|
|
128700
|
+
}
|
|
128701
|
+
function previewAssetName(baseName, rawBranch) {
|
|
128702
|
+
return `${baseName} @${buildBranchSlug(rawBranch).suffix}`;
|
|
128703
|
+
}
|
|
128704
|
+
function channelAssetName(baseName, code) {
|
|
128705
|
+
return `[${code}] ${baseName}`;
|
|
128706
|
+
}
|
|
128707
|
+
var MARKER_KEY = "x-pm-onboarding";
|
|
128708
|
+
function parseAssetMarker(description) {
|
|
128709
|
+
if (!description) return void 0;
|
|
128710
|
+
const index = description.indexOf(`${MARKER_KEY}:`);
|
|
128711
|
+
if (index === -1) return void 0;
|
|
128712
|
+
const jsonStart = description.indexOf("{", index);
|
|
128713
|
+
if (jsonStart === -1) return void 0;
|
|
128714
|
+
let depth = 0;
|
|
128715
|
+
for (let i = jsonStart; i < description.length; i += 1) {
|
|
128716
|
+
const ch = description[i];
|
|
128717
|
+
if (ch === "{") depth += 1;
|
|
128718
|
+
else if (ch === "}") {
|
|
128719
|
+
depth -= 1;
|
|
128720
|
+
if (depth === 0) {
|
|
128721
|
+
try {
|
|
128722
|
+
const parsed = JSON.parse(description.slice(jsonStart, i + 1));
|
|
128723
|
+
if (parsed && typeof parsed === "object" && parsed.repo && parsed.role) return parsed;
|
|
128724
|
+
} catch {
|
|
128725
|
+
return void 0;
|
|
128726
|
+
}
|
|
128727
|
+
return void 0;
|
|
128728
|
+
}
|
|
128729
|
+
}
|
|
128730
|
+
}
|
|
128731
|
+
return void 0;
|
|
128732
|
+
}
|
|
128733
|
+
|
|
128205
128734
|
// src/index.ts
|
|
128206
128735
|
function parseBooleanInput(value, defaultValue) {
|
|
128207
128736
|
const normalized = String(value || "").trim().toLowerCase();
|
|
@@ -128220,16 +128749,16 @@ function getInput2(name, env = process.env) {
|
|
|
128220
128749
|
const runnerRaw = runnerName === normalizedName ? void 0 : env[runnerName];
|
|
128221
128750
|
const hasNormalized = normalizedRaw !== void 0;
|
|
128222
128751
|
const hasRunner = runnerRaw !== void 0;
|
|
128752
|
+
const normalizedValue = normalizeInputValue(normalizedRaw);
|
|
128753
|
+
const runnerValue = normalizeInputValue(runnerRaw);
|
|
128223
128754
|
if (hasNormalized && hasRunner) {
|
|
128224
|
-
|
|
128225
|
-
const runnerValue = normalizeInputValue(runnerRaw);
|
|
128226
|
-
if (normalizedValue !== runnerValue) {
|
|
128755
|
+
if (normalizedValue && runnerValue && normalizedValue !== runnerValue) {
|
|
128227
128756
|
throw new Error(
|
|
128228
128757
|
`Conflicting values for ${name}: ${normalizedName}=${JSON.stringify(normalizedValue)} vs ${runnerName}=${JSON.stringify(runnerValue)}`
|
|
128229
128758
|
);
|
|
128230
128759
|
}
|
|
128231
128760
|
}
|
|
128232
|
-
return
|
|
128761
|
+
return normalizedValue || runnerValue;
|
|
128233
128762
|
}
|
|
128234
128763
|
function hasInput(name, env = process.env) {
|
|
128235
128764
|
const normalizedName = `INPUT_${name.replace(/-/g, "_").toUpperCase()}`;
|
|
@@ -128291,6 +128820,17 @@ function parseCredentialPreflight(value) {
|
|
|
128291
128820
|
`Unsupported credential-preflight "${normalized}". Supported values: ${allowed.join(", ")}`
|
|
128292
128821
|
);
|
|
128293
128822
|
}
|
|
128823
|
+
function parseBranchStrategy(value) {
|
|
128824
|
+
const definition = postmanRepoSyncActionContract.inputs["branch-strategy"];
|
|
128825
|
+
const allowed = definition.allowedValues ?? [];
|
|
128826
|
+
const normalized = String(value || "").trim() || (definition.default ?? "legacy");
|
|
128827
|
+
if (allowed.includes(normalized)) {
|
|
128828
|
+
return normalized;
|
|
128829
|
+
}
|
|
128830
|
+
throw new Error(
|
|
128831
|
+
`Unsupported branch-strategy "${normalized}". Supported values: ${allowed.join(", ")}`
|
|
128832
|
+
);
|
|
128833
|
+
}
|
|
128294
128834
|
function normalizeReleaseLabel(value) {
|
|
128295
128835
|
const cleaned = normalizeInputValue(value).replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
|
|
128296
128836
|
return cleaned;
|
|
@@ -128335,6 +128875,7 @@ function resolveInputs(env = process.env) {
|
|
|
128335
128875
|
smokeCollectionId: getInput2("smoke-collection-id", env),
|
|
128336
128876
|
contractCollectionId: getInput2("contract-collection-id", env),
|
|
128337
128877
|
specId: getInput2("spec-id", env),
|
|
128878
|
+
specContentChanged: parseBooleanInput(getInput2("spec-content-changed", env), true),
|
|
128338
128879
|
specPath: getInput2("spec-path", env),
|
|
128339
128880
|
collectionSyncMode: normalizeCollectionSyncMode(getInput2("collection-sync-mode", env) || "refresh"),
|
|
128340
128881
|
specSyncMode: normalizeSpecSyncMode(getInput2("spec-sync-mode", env) || "update"),
|
|
@@ -128357,6 +128898,10 @@ function resolveInputs(env = process.env) {
|
|
|
128357
128898
|
postmanApiKey: getInput2("postman-api-key", env),
|
|
128358
128899
|
postmanAccessToken: getInput2("postman-access-token", env),
|
|
128359
128900
|
credentialPreflight: parseCredentialPreflight(getInput2("credential-preflight", env)),
|
|
128901
|
+
branchStrategy: parseBranchStrategy(getInput2("branch-strategy", env)),
|
|
128902
|
+
canonicalBranch: getInput2("canonical-branch", env) || void 0,
|
|
128903
|
+
channels: getInput2("channels", env) || void 0,
|
|
128904
|
+
previewTtlDays: Math.max(1, Number.parseInt(getInput2("preview-ttl", env) || "30", 10) || 30),
|
|
128360
128905
|
adoToken: getInput2("ado-token", env) || normalizeInputValue(env.SYSTEM_ACCESSTOKEN),
|
|
128361
128906
|
githubToken: getInput2("github-token", env),
|
|
128362
128907
|
ghFallbackToken: getInput2("gh-fallback-token", env),
|
|
@@ -128383,6 +128928,40 @@ function resolveInputs(env = process.env) {
|
|
|
128383
128928
|
postmanIapubBase: endpointProfile.iapubBaseUrl
|
|
128384
128929
|
};
|
|
128385
128930
|
}
|
|
128931
|
+
function buildBranchAssetMarker(decision, inputs, now = /* @__PURE__ */ new Date()) {
|
|
128932
|
+
if (decision.tier !== "preview" && decision.tier !== "channel") {
|
|
128933
|
+
return void 0;
|
|
128934
|
+
}
|
|
128935
|
+
const rawBranch = decision.identity.headBranch;
|
|
128936
|
+
const repo = inputs.repoUrl || inputs.repository;
|
|
128937
|
+
if (!rawBranch || !repo) {
|
|
128938
|
+
return void 0;
|
|
128939
|
+
}
|
|
128940
|
+
const ttlMs = inputs.previewTtlDays * 24 * 60 * 60 * 1e3;
|
|
128941
|
+
return {
|
|
128942
|
+
repo,
|
|
128943
|
+
rawBranch,
|
|
128944
|
+
sanitizedBranch: buildBranchSlug(rawBranch).suffix,
|
|
128945
|
+
role: decision.tier,
|
|
128946
|
+
headSha: decision.identity.headSha,
|
|
128947
|
+
createdAt: now.toISOString(),
|
|
128948
|
+
lastSyncedAt: now.toISOString(),
|
|
128949
|
+
...decision.tier === "preview" ? { expiresAt: new Date(now.getTime() + ttlMs).toISOString() } : {}
|
|
128950
|
+
};
|
|
128951
|
+
}
|
|
128952
|
+
function assertBranchAssetIds(inputs, decision, branchOwnedIds = process.env.POSTMAN_BRANCH_ASSET_IDS === "owned") {
|
|
128953
|
+
if (decision.tier === "legacy" || decision.tier === "canonical" || branchOwnedIds) return;
|
|
128954
|
+
const provided = [
|
|
128955
|
+
["baseline-collection-id", inputs.baselineCollectionId],
|
|
128956
|
+
["smoke-collection-id", inputs.smokeCollectionId],
|
|
128957
|
+
["contract-collection-id", inputs.contractCollectionId]
|
|
128958
|
+
].filter(([, value]) => Boolean(value));
|
|
128959
|
+
if (provided.length > 0) {
|
|
128960
|
+
throw new Error(
|
|
128961
|
+
`CONTRACT_BRANCH_CANONICAL_WRITE: a ${decision.tier} repo-sync run cannot accept explicit collection IDs (${provided.map(([name]) => name).join(", ")}). Run bootstrap in the same branch-aware pipeline so it can produce branch-owned IDs.`
|
|
128962
|
+
);
|
|
128963
|
+
}
|
|
128964
|
+
}
|
|
128386
128965
|
function buildEnvironmentValues(envName, baseUrl) {
|
|
128387
128966
|
return [
|
|
128388
128967
|
{ key: "baseUrl", value: baseUrl, type: "default" },
|
|
@@ -128395,12 +128974,48 @@ function buildEnvironmentValues(envName, baseUrl) {
|
|
|
128395
128974
|
];
|
|
128396
128975
|
}
|
|
128397
128976
|
var LEGACY_BASELINE_COLLECTION_PREFIX = "[Baseline]";
|
|
128977
|
+
var RESOURCES_STATE_VERSION = 2;
|
|
128978
|
+
var SUPPORTED_STATE_VERSIONS = /* @__PURE__ */ new Set([1, RESOURCES_STATE_VERSION]);
|
|
128979
|
+
var StateUnreadableError = class extends Error {
|
|
128980
|
+
code = "CONTRACT_STATE_UNREADABLE";
|
|
128981
|
+
constructor(message) {
|
|
128982
|
+
super(`CONTRACT_STATE_UNREADABLE: ${message}`);
|
|
128983
|
+
this.name = "StateUnreadableError";
|
|
128984
|
+
}
|
|
128985
|
+
};
|
|
128398
128986
|
function readResourcesState() {
|
|
128987
|
+
let raw;
|
|
128399
128988
|
try {
|
|
128400
|
-
|
|
128989
|
+
raw = (0, import_node_fs4.readFileSync)(".postman/resources.yaml", "utf8");
|
|
128401
128990
|
} catch {
|
|
128402
128991
|
return null;
|
|
128403
128992
|
}
|
|
128993
|
+
let parsed;
|
|
128994
|
+
try {
|
|
128995
|
+
parsed = load(raw);
|
|
128996
|
+
} catch (error2) {
|
|
128997
|
+
throw new StateUnreadableError(
|
|
128998
|
+
`.postman/resources.yaml exists but is not parseable YAML (${error2 instanceof Error ? error2.message : String(error2)}). Fix or delete the file; refusing to treat tracked state as absent.`
|
|
128999
|
+
);
|
|
129000
|
+
}
|
|
129001
|
+
if (parsed === null || parsed === void 0) {
|
|
129002
|
+
return null;
|
|
129003
|
+
}
|
|
129004
|
+
if (typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
129005
|
+
throw new StateUnreadableError(
|
|
129006
|
+
".postman/resources.yaml exists but does not contain a YAML mapping. Fix or delete the file; refusing to treat tracked state as absent."
|
|
129007
|
+
);
|
|
129008
|
+
}
|
|
129009
|
+
const state = parsed;
|
|
129010
|
+
if (state.version !== void 0 && !SUPPORTED_STATE_VERSIONS.has(Number(state.version))) {
|
|
129011
|
+
throw new StateUnreadableError(
|
|
129012
|
+
`.postman/resources.yaml declares unsupported state version ${String(state.version)} (supported: 1, ${RESOURCES_STATE_VERSION}). Upgrade the action or fix the file.`
|
|
129013
|
+
);
|
|
129014
|
+
}
|
|
129015
|
+
if (state.canonical && !state.cloudResources) {
|
|
129016
|
+
state.cloudResources = { ...state.canonical };
|
|
129017
|
+
}
|
|
129018
|
+
return state;
|
|
128404
129019
|
}
|
|
128405
129020
|
function findCloudResourceId(map, matcher) {
|
|
128406
129021
|
if (!map) {
|
|
@@ -128435,7 +129050,7 @@ function isOpenApiSpecFile(filePath) {
|
|
|
128435
129050
|
return false;
|
|
128436
129051
|
}
|
|
128437
129052
|
try {
|
|
128438
|
-
const raw = (0,
|
|
129053
|
+
const raw = (0, import_node_fs4.readFileSync)(filePath, "utf8");
|
|
128439
129054
|
const parsed = filePath.endsWith(".json") ? JSON.parse(raw) : load(raw);
|
|
128440
129055
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
128441
129056
|
return false;
|
|
@@ -128464,7 +129079,7 @@ function scanLocalSpecReferences(baseDir = ".") {
|
|
|
128464
129079
|
const found = /* @__PURE__ */ new Set();
|
|
128465
129080
|
const refs = [];
|
|
128466
129081
|
const visit2 = (currentDir) => {
|
|
128467
|
-
for (const entry of (0,
|
|
129082
|
+
for (const entry of (0, import_node_fs4.readdirSync)(currentDir, { withFileTypes: true })) {
|
|
128468
129083
|
if (ignoredDirs.has(entry.name)) {
|
|
128469
129084
|
continue;
|
|
128470
129085
|
}
|
|
@@ -128494,7 +129109,7 @@ function resolveMappedSpecReference(explicitSpecPath, discoveredSpecs) {
|
|
|
128494
129109
|
const normalizedExplicitPath = normalizeToPosix(explicitSpecPath.trim());
|
|
128495
129110
|
if (normalizedExplicitPath) {
|
|
128496
129111
|
const explicitFullPath = path8.resolve(normalizedExplicitPath);
|
|
128497
|
-
if ((0,
|
|
129112
|
+
if ((0, import_node_fs4.existsSync)(explicitFullPath) && (0, import_node_fs4.statSync)(explicitFullPath).isFile()) {
|
|
128498
129113
|
return {
|
|
128499
129114
|
repoRelativePath: normalizedExplicitPath,
|
|
128500
129115
|
configRelativePath: normalizeToPosix(path8.join("..", normalizedExplicitPath))
|
|
@@ -128521,7 +129136,11 @@ function createOutputs(inputs) {
|
|
|
128521
129136
|
"mock-url": "",
|
|
128522
129137
|
"monitor-id": "",
|
|
128523
129138
|
"repo-sync-summary-json": "{}",
|
|
128524
|
-
"commit-sha": ""
|
|
129139
|
+
"commit-sha": "",
|
|
129140
|
+
"sync-status": "",
|
|
129141
|
+
"branch-decision": "",
|
|
129142
|
+
"spec-version-tag": "",
|
|
129143
|
+
"spec-version-url": ""
|
|
128525
129144
|
};
|
|
128526
129145
|
}
|
|
128527
129146
|
function readActionInputs(actionCore) {
|
|
@@ -128566,6 +129185,10 @@ function readActionInputs(actionCore) {
|
|
|
128566
129185
|
INPUT_POSTMAN_API_KEY: postmanApiKey,
|
|
128567
129186
|
INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
|
|
128568
129187
|
INPUT_CREDENTIAL_PREFLIGHT: readInput(actionCore, "credential-preflight") || "warn",
|
|
129188
|
+
INPUT_BRANCH_STRATEGY: readInput(actionCore, "branch-strategy"),
|
|
129189
|
+
INPUT_CANONICAL_BRANCH: readInput(actionCore, "canonical-branch"),
|
|
129190
|
+
INPUT_CHANNELS: readInput(actionCore, "channels"),
|
|
129191
|
+
INPUT_PREVIEW_TTL: readInput(actionCore, "preview-ttl"),
|
|
128569
129192
|
INPUT_ADO_TOKEN: adoToken,
|
|
128570
129193
|
INPUT_GITHUB_TOKEN: githubToken,
|
|
128571
129194
|
INPUT_GH_FALLBACK_TOKEN: ghFallbackToken,
|
|
@@ -128680,7 +129303,7 @@ async function persistSslSecrets(inputs, actionCore, actionExec, repository, env
|
|
|
128680
129303
|
);
|
|
128681
129304
|
}
|
|
128682
129305
|
}
|
|
128683
|
-
async function upsertEnvironments(inputs, dependencies, resourcesState) {
|
|
129306
|
+
async function upsertEnvironments(inputs, dependencies, resourcesState, assetMarker) {
|
|
128684
129307
|
const envUids = {
|
|
128685
129308
|
...getEnvironmentUidsFromResources(resourcesState),
|
|
128686
129309
|
...inputs.environmentUids
|
|
@@ -128690,7 +129313,6 @@ async function upsertEnvironments(inputs, dependencies, resourcesState) {
|
|
|
128690
129313
|
}
|
|
128691
129314
|
for (const envName of inputs.environments) {
|
|
128692
129315
|
const runtimeUrl = String(inputs.envRuntimeUrls[envName] || "").trim();
|
|
128693
|
-
const values = buildEnvironmentValues(envName, runtimeUrl);
|
|
128694
129316
|
const displayName = `${inputs.projectName} - ${envName}`;
|
|
128695
129317
|
let existingUid = String(envUids[envName] || "").trim();
|
|
128696
129318
|
if (!existingUid) {
|
|
@@ -128706,10 +129328,27 @@ async function upsertEnvironments(inputs, dependencies, resourcesState) {
|
|
|
128706
129328
|
}
|
|
128707
129329
|
}
|
|
128708
129330
|
if (existingUid) {
|
|
128709
|
-
|
|
129331
|
+
let marker = assetMarker;
|
|
129332
|
+
if (marker) {
|
|
129333
|
+
try {
|
|
129334
|
+
const existing = await dependencies.postman.getEnvironment(existingUid);
|
|
129335
|
+
const values3 = existing.data?.values ?? existing.values ?? [];
|
|
129336
|
+
const prior = values3.find((value) => value.key === "x-pm-onboarding")?.value;
|
|
129337
|
+
const priorMarker = parseAssetMarker(prior ? `x-pm-onboarding: ${prior}` : void 0);
|
|
129338
|
+
if (priorMarker?.repo === marker.repo && priorMarker.rawBranch === marker.rawBranch) {
|
|
129339
|
+
marker = { ...marker, createdAt: priorMarker.createdAt };
|
|
129340
|
+
}
|
|
129341
|
+
} catch {
|
|
129342
|
+
}
|
|
129343
|
+
}
|
|
129344
|
+
const values2 = buildEnvironmentValues(envName, runtimeUrl);
|
|
129345
|
+
if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
|
|
129346
|
+
await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
|
|
128710
129347
|
envUids[envName] = existingUid;
|
|
128711
129348
|
continue;
|
|
128712
129349
|
}
|
|
129350
|
+
const values = buildEnvironmentValues(envName, runtimeUrl);
|
|
129351
|
+
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
128713
129352
|
envUids[envName] = await dependencies.postman.createEnvironment(
|
|
128714
129353
|
inputs.workspaceId,
|
|
128715
129354
|
displayName,
|
|
@@ -128719,7 +129358,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState) {
|
|
|
128719
129358
|
return envUids;
|
|
128720
129359
|
}
|
|
128721
129360
|
function ensureDir(path9) {
|
|
128722
|
-
(0,
|
|
129361
|
+
(0, import_node_fs4.mkdirSync)(path9, { recursive: true });
|
|
128723
129362
|
}
|
|
128724
129363
|
function getCollectionDirectoryName(kind, projectName) {
|
|
128725
129364
|
if (kind === "Baseline") {
|
|
@@ -128756,7 +129395,7 @@ function stripVolatileFields(obj) {
|
|
|
128756
129395
|
}
|
|
128757
129396
|
function writeJsonFile(path9, content, normalize3 = false) {
|
|
128758
129397
|
const data = normalize3 ? stripVolatileFields(content) : content;
|
|
128759
|
-
(0,
|
|
129398
|
+
(0, import_node_fs4.writeFileSync)(path9, JSON.stringify(data, null, 2));
|
|
128760
129399
|
}
|
|
128761
129400
|
function buildMappedSpecCloudKey(mappedSource, specSyncMode, releaseLabel) {
|
|
128762
129401
|
if (specSyncMode !== "version") {
|
|
@@ -128780,31 +129419,30 @@ function resolveDurableWorkspaceId(options) {
|
|
|
128780
129419
|
}
|
|
128781
129420
|
return prior === candidate ? prior : void 0;
|
|
128782
129421
|
}
|
|
128783
|
-
function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir, localSpecRefs, mappedSpecRef, specId, existingSpecs) {
|
|
128784
|
-
const manifest = {};
|
|
129422
|
+
function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir, localSpecRefs, mappedSpecRef, specId, existingSpecs, priorState) {
|
|
129423
|
+
const manifest = { ...priorState ?? {} };
|
|
129424
|
+
delete manifest.version;
|
|
129425
|
+
delete manifest.workspace;
|
|
129426
|
+
delete manifest.localResources;
|
|
129427
|
+
delete manifest.cloudResources;
|
|
129428
|
+
delete manifest.canonical;
|
|
129429
|
+
manifest.version = RESOURCES_STATE_VERSION;
|
|
128785
129430
|
if (workspaceId) {
|
|
128786
129431
|
manifest.workspace = { id: workspaceId };
|
|
128787
129432
|
}
|
|
128788
|
-
const localResources = {};
|
|
128789
129433
|
const cloudResources = {};
|
|
128790
129434
|
const collectionKeys = Object.keys(collectionMap);
|
|
128791
129435
|
if (collectionKeys.length > 0) {
|
|
128792
|
-
localResources.collections = collectionKeys;
|
|
128793
129436
|
cloudResources.collections = collectionMap;
|
|
128794
129437
|
}
|
|
128795
129438
|
const envEntries = Object.entries(envMap);
|
|
128796
129439
|
if (envEntries.length > 0) {
|
|
128797
|
-
localResources.environments = envEntries.map(
|
|
128798
|
-
([envName]) => `../${artifactDir}/environments/${envName}.postman_environment.json`
|
|
128799
|
-
);
|
|
128800
129440
|
cloudResources.environments = {};
|
|
128801
129441
|
for (const [envName, envUid] of envEntries) {
|
|
128802
129442
|
cloudResources.environments[`../${artifactDir}/environments/${envName}.postman_environment.json`] = envUid;
|
|
128803
129443
|
}
|
|
128804
129444
|
}
|
|
128805
|
-
|
|
128806
|
-
localResources.specs = localSpecRefs;
|
|
128807
|
-
}
|
|
129445
|
+
void localSpecRefs;
|
|
128808
129446
|
const specs = { ...existingSpecs || {} };
|
|
128809
129447
|
if (mappedSpecRef && specId) {
|
|
128810
129448
|
specs[mappedSpecRef] = specId;
|
|
@@ -128812,11 +129450,8 @@ function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir,
|
|
|
128812
129450
|
if (Object.keys(specs).length > 0) {
|
|
128813
129451
|
cloudResources.specs = specs;
|
|
128814
129452
|
}
|
|
128815
|
-
if (Object.keys(localResources).length > 0) {
|
|
128816
|
-
manifest.localResources = localResources;
|
|
128817
|
-
}
|
|
128818
129453
|
if (Object.keys(cloudResources).length > 0) {
|
|
128819
|
-
manifest.
|
|
129454
|
+
manifest.canonical = cloudResources;
|
|
128820
129455
|
}
|
|
128821
129456
|
return dump(manifest, {
|
|
128822
129457
|
lineWidth: -1,
|
|
@@ -128857,21 +129492,21 @@ function assertPathWithinCwd(targetPath, fieldName) {
|
|
|
128857
129492
|
if (!rawPath || hasControlCharacter2(originalPath) || path8.isAbsolute(rawPath) || path8.win32.isAbsolute(rawPath) || segments.includes("..") || rawPath.startsWith(":") || hasControlCharacter2(rawPath)) {
|
|
128858
129493
|
throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
|
|
128859
129494
|
}
|
|
128860
|
-
const base = (0,
|
|
129495
|
+
const base = (0, import_node_fs4.realpathSync)(process.cwd());
|
|
128861
129496
|
const resolved = path8.resolve(base, rawPath);
|
|
128862
129497
|
const relative4 = path8.relative(base, resolved);
|
|
128863
129498
|
if (relative4.startsWith("..") || path8.isAbsolute(relative4)) {
|
|
128864
129499
|
throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
|
|
128865
129500
|
}
|
|
128866
129501
|
let existingPath = resolved;
|
|
128867
|
-
while (!(0,
|
|
129502
|
+
while (!(0, import_node_fs4.existsSync)(existingPath)) {
|
|
128868
129503
|
const parent = path8.dirname(existingPath);
|
|
128869
129504
|
if (parent === existingPath) {
|
|
128870
129505
|
break;
|
|
128871
129506
|
}
|
|
128872
129507
|
existingPath = parent;
|
|
128873
129508
|
}
|
|
128874
|
-
const realExistingPath = (0,
|
|
129509
|
+
const realExistingPath = (0, import_node_fs4.realpathSync)(existingPath);
|
|
128875
129510
|
const realRelative = path8.relative(base, realExistingPath);
|
|
128876
129511
|
if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
|
|
128877
129512
|
throw new Error(`${fieldName} must stay within the repository root; received ${targetPath}`);
|
|
@@ -128899,8 +129534,8 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
128899
129534
|
ensureDir(specsDir);
|
|
128900
129535
|
ensureDir(".postman");
|
|
128901
129536
|
const globalsFilePath = `${globalsDir}/workspace.globals.yaml`;
|
|
128902
|
-
if (!(0,
|
|
128903
|
-
(0,
|
|
129537
|
+
if (!(0, import_node_fs4.existsSync)(globalsFilePath)) {
|
|
129538
|
+
(0, import_node_fs4.writeFileSync)(globalsFilePath, "name: Globals\nvalues: []\n");
|
|
128904
129539
|
}
|
|
128905
129540
|
if (inputs.generateCiWorkflow) {
|
|
128906
129541
|
const ciDir = inputs.ciWorkflowPath.split("/").slice(0, -1).join("/");
|
|
@@ -128947,7 +129582,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
128947
129582
|
workspaceLinkEnabled: inputs.workspaceLinkEnabled,
|
|
128948
129583
|
workspaceLinkStatus: options.workspaceLinkStatus
|
|
128949
129584
|
});
|
|
128950
|
-
(0,
|
|
129585
|
+
(0, import_node_fs4.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
|
|
128951
129586
|
durableWorkspaceId,
|
|
128952
129587
|
manifestCollections,
|
|
128953
129588
|
envUids,
|
|
@@ -128955,10 +129590,11 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
128955
129590
|
discoveredSpecs.map((spec) => spec.configRelativePath),
|
|
128956
129591
|
mappedSpecCloudKey,
|
|
128957
129592
|
inputs.specId || void 0,
|
|
128958
|
-
options.existingSpecs
|
|
129593
|
+
options.existingSpecs,
|
|
129594
|
+
options.priorState
|
|
128959
129595
|
));
|
|
128960
129596
|
if (mappedSpec && Object.keys(manifestCollections).length > 0) {
|
|
128961
|
-
(0,
|
|
129597
|
+
(0, import_node_fs4.writeFileSync)(
|
|
128962
129598
|
".postman/workflows.yaml",
|
|
128963
129599
|
buildSpecCollectionWorkflowManifest(
|
|
128964
129600
|
mappedSpec.configRelativePath,
|
|
@@ -129003,19 +129639,29 @@ async function commitAndPushGeneratedFiles(inputs, dependencies) {
|
|
|
129003
129639
|
const dir = parts.slice(0, -1).join("/");
|
|
129004
129640
|
ensureDir(dir);
|
|
129005
129641
|
}
|
|
129006
|
-
(0,
|
|
129642
|
+
(0, import_node_fs4.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
|
|
129643
|
+
if (inputs.provider === "github" || inputs.provider === "unknown") {
|
|
129644
|
+
const gcPath = ".github/workflows/postman-preview-gc.yml";
|
|
129645
|
+
if (inputs.ciWorkflowPath.endsWith(".github/workflows/ci.yml") || inputs.ciWorkflowPath === ".github/workflows/ci.yml") {
|
|
129646
|
+
ensureDir(".github/workflows");
|
|
129647
|
+
(0, import_node_fs4.writeFileSync)(gcPath, renderGcWorkflowTemplate());
|
|
129648
|
+
}
|
|
129649
|
+
}
|
|
129007
129650
|
}
|
|
129008
129651
|
if (!dependencies.repoMutation || inputs.repoWriteMode === "none") {
|
|
129009
129652
|
return { commitSha: "", resolvedCurrentRef: "", pushed: false };
|
|
129010
129653
|
}
|
|
129011
129654
|
const provisionPath = ".github/workflows/provision.yml";
|
|
129012
|
-
const provisionExists = inputs.provider === "github" && (0,
|
|
129655
|
+
const provisionExists = inputs.provider === "github" && (0, import_node_fs4.existsSync)(provisionPath);
|
|
129656
|
+
const gcWorkflowPath = ".github/workflows/postman-preview-gc.yml";
|
|
129657
|
+
const gcExists = inputs.generateCiWorkflow && (0, import_node_fs4.existsSync)(gcWorkflowPath);
|
|
129013
129658
|
const stagePaths = [
|
|
129014
129659
|
inputs.artifactDir,
|
|
129015
129660
|
".postman",
|
|
129016
129661
|
inputs.generateCiWorkflow ? inputs.ciWorkflowPath : null,
|
|
129662
|
+
gcExists ? gcWorkflowPath : null,
|
|
129017
129663
|
provisionExists ? provisionPath : null
|
|
129018
|
-
].filter((entry) => typeof entry === "string" && ((0,
|
|
129664
|
+
].filter((entry) => typeof entry === "string" && ((0, import_node_fs4.existsSync)(entry) || entry === provisionPath));
|
|
129019
129665
|
if (stagePaths.length === 0) {
|
|
129020
129666
|
dependencies.core.info("No generated repository paths were found; skipping repo mutation.");
|
|
129021
129667
|
return {
|
|
@@ -129063,6 +129709,31 @@ async function runRepoSync(inputs, dependencies) {
|
|
|
129063
129709
|
}
|
|
129064
129710
|
}
|
|
129065
129711
|
async function runRepoSyncInner(inputs, dependencies) {
|
|
129712
|
+
const branchDecision = decideBranchTier(inputs);
|
|
129713
|
+
assertBranchAssetIds(inputs, branchDecision);
|
|
129714
|
+
const isCanonicalWriter = branchDecision.tier === "legacy" || branchDecision.tier === "canonical";
|
|
129715
|
+
if (!isCanonicalWriter) {
|
|
129716
|
+
if (branchDecision.tier === "preview" && branchDecision.identity.headBranch) {
|
|
129717
|
+
inputs = {
|
|
129718
|
+
...inputs,
|
|
129719
|
+
projectName: previewAssetName(inputs.projectName, branchDecision.identity.headBranch),
|
|
129720
|
+
workspaceLinkEnabled: false,
|
|
129721
|
+
environmentSyncEnabled: false,
|
|
129722
|
+
repoWriteMode: "none"
|
|
129723
|
+
};
|
|
129724
|
+
} else if (branchDecision.tier === "channel" && branchDecision.channel) {
|
|
129725
|
+
inputs = {
|
|
129726
|
+
...inputs,
|
|
129727
|
+
projectName: channelAssetName(inputs.projectName, branchDecision.channel.code),
|
|
129728
|
+
workspaceLinkEnabled: false,
|
|
129729
|
+
environmentSyncEnabled: false,
|
|
129730
|
+
repoWriteMode: "none"
|
|
129731
|
+
};
|
|
129732
|
+
}
|
|
129733
|
+
dependencies.core.info(
|
|
129734
|
+
`branch-aware sync: ${branchDecision.tier} run \u2014 branch-scoped asset set "${inputs.projectName}", no workspace repo-link mutation, no state write-back`
|
|
129735
|
+
);
|
|
129736
|
+
}
|
|
129066
129737
|
const outputs = createOutputs(inputs);
|
|
129067
129738
|
const versionRequested = inputs.collectionSyncMode === "version" || inputs.specSyncMode === "version";
|
|
129068
129739
|
const releaseLabel = deriveReleaseLabel(inputs);
|
|
@@ -129070,7 +129741,8 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
129070
129741
|
throw new Error("release-label is required when collection-sync-mode or spec-sync-mode is version");
|
|
129071
129742
|
}
|
|
129072
129743
|
const assetProjectName = createAssetProjectName(inputs, releaseLabel);
|
|
129073
|
-
const
|
|
129744
|
+
const trackedState = readResourcesState();
|
|
129745
|
+
const resourcesState = isCanonicalWriter ? trackedState : trackedState?.workspace ? { workspace: trackedState.workspace } : null;
|
|
129074
129746
|
if (resourcesState) {
|
|
129075
129747
|
if (!inputs.workspaceId && resourcesState.workspace?.id) {
|
|
129076
129748
|
inputs.workspaceId = resourcesState.workspace.id;
|
|
@@ -129096,7 +129768,8 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
129096
129768
|
}
|
|
129097
129769
|
}
|
|
129098
129770
|
}
|
|
129099
|
-
const
|
|
129771
|
+
const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
|
|
129772
|
+
const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
|
|
129100
129773
|
outputs["environment-uids-json"] = JSON.stringify(envUids);
|
|
129101
129774
|
if (inputs.environmentSyncEnabled && inputs.workspaceId && dependencies.internalIntegration) {
|
|
129102
129775
|
const associations = Object.entries(envUids).map(([envName, envUid]) => ({
|
|
@@ -129152,11 +129825,23 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
129152
129825
|
}
|
|
129153
129826
|
}
|
|
129154
129827
|
if (!resolvedMockUrl) {
|
|
129155
|
-
const mock = await
|
|
129156
|
-
|
|
129157
|
-
|
|
129158
|
-
|
|
129159
|
-
|
|
129828
|
+
const mock = await retry(
|
|
129829
|
+
() => dependencies.postman.createMock(
|
|
129830
|
+
inputs.workspaceId,
|
|
129831
|
+
mockName,
|
|
129832
|
+
inputs.baselineCollectionId,
|
|
129833
|
+
mockEnvUid
|
|
129834
|
+
),
|
|
129835
|
+
{
|
|
129836
|
+
maxAttempts: 3,
|
|
129837
|
+
delayMs: 2e3,
|
|
129838
|
+
backoffMultiplier: 2,
|
|
129839
|
+
onRetry: ({ attempt, error: error2 }) => {
|
|
129840
|
+
dependencies.core.warning(
|
|
129841
|
+
`Mock create attempt ${attempt} failed (${error2 instanceof Error ? error2.message : String(error2)}); retrying`
|
|
129842
|
+
);
|
|
129843
|
+
}
|
|
129844
|
+
}
|
|
129160
129845
|
);
|
|
129161
129846
|
resolvedMockUrl = mock.url;
|
|
129162
129847
|
dependencies.core.info(`Created new mock: ${resolvedMockUrl}`);
|
|
@@ -129225,16 +129910,19 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
129225
129910
|
);
|
|
129226
129911
|
} catch (error2) {
|
|
129227
129912
|
outputs["workspace-link-status"] = "failed";
|
|
129228
|
-
|
|
129229
|
-
|
|
129230
|
-
|
|
129913
|
+
const message = `Workspace link failed: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
129914
|
+
if (branchDecision.tier === "canonical") {
|
|
129915
|
+
throw new Error(message, { cause: error2 });
|
|
129916
|
+
}
|
|
129917
|
+
dependencies.core.warning(message);
|
|
129231
129918
|
}
|
|
129232
129919
|
}
|
|
129233
129920
|
await exportArtifacts(inputs, dependencies, envUids, assetProjectName, {
|
|
129234
129921
|
workspaceLinkStatus: outputs["workspace-link-status"],
|
|
129235
129922
|
priorWorkspaceId: resourcesState?.workspace?.id,
|
|
129236
129923
|
existingSpecs: resourcesState?.cloudResources?.specs,
|
|
129237
|
-
releaseLabel
|
|
129924
|
+
releaseLabel,
|
|
129925
|
+
priorState: resourcesState
|
|
129238
129926
|
});
|
|
129239
129927
|
const commit = await commitAndPushGeneratedFiles(inputs, dependencies);
|
|
129240
129928
|
outputs["commit-sha"] = commit.commitSha;
|
|
@@ -129242,6 +129930,38 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
129242
129930
|
outputs["resolved-current-ref"] = commit.resolvedCurrentRef;
|
|
129243
129931
|
}
|
|
129244
129932
|
outputs["repo-sync-summary-json"] = createRepoSummary(outputs, envUids, commit.pushed);
|
|
129933
|
+
if (branchDecision.tier === "canonical" && inputs.specId && inputs.specContentChanged !== false && dependencies.postman.tagSpecVersion) {
|
|
129934
|
+
const shortSha = (branchDecision.identity.headSha ?? "").slice(0, 7);
|
|
129935
|
+
const tagName = inputs.releaseLabel ? `${inputs.releaseLabel}${shortSha ? ` (${shortSha})` : ""}` : shortSha || `sync-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
129936
|
+
try {
|
|
129937
|
+
const tag = await dependencies.postman.tagSpecVersion(inputs.specId, tagName);
|
|
129938
|
+
outputs["spec-version-tag"] = tag.name || tagName;
|
|
129939
|
+
if (tag.id) {
|
|
129940
|
+
outputs["spec-version-url"] = `https://web.postman.co/workspace/${encodeURIComponent(inputs.workspaceId)}/specification/${encodeURIComponent(inputs.specId)}?tagId=${encodeURIComponent(tag.id)}&versionLabel=${encodeURIComponent(tag.name || tagName)}`;
|
|
129941
|
+
}
|
|
129942
|
+
dependencies.core.info(`Tagged spec version at finalize: ${tag.name || tagName}`);
|
|
129943
|
+
} catch (error2) {
|
|
129944
|
+
const status = error2.status;
|
|
129945
|
+
if (status === 409) {
|
|
129946
|
+
const tags = await dependencies.postman.listSpecVersionTags?.(inputs.specId).catch(() => []) ?? [];
|
|
129947
|
+
const latest = tags[0];
|
|
129948
|
+
if (latest && (latest.name === tagName || /\([0-9a-f]{7}\)$/.test(latest.name) || /^[0-9a-f]{7}$/.test(latest.name))) {
|
|
129949
|
+
outputs["spec-version-tag"] = latest.name;
|
|
129950
|
+
outputs["spec-version-url"] = `https://web.postman.co/workspace/${encodeURIComponent(inputs.workspaceId)}/specification/${encodeURIComponent(inputs.specId)}?tagId=${encodeURIComponent(latest.id)}&versionLabel=${encodeURIComponent(latest.name)}`;
|
|
129951
|
+
dependencies.core.info(`Latest changelog group already tagged as "${latest.name}"; adopting.`);
|
|
129952
|
+
} else {
|
|
129953
|
+
dependencies.core.warning("Latest changelog group already carries a hand-applied tag; leaving it in place.");
|
|
129954
|
+
}
|
|
129955
|
+
} else {
|
|
129956
|
+
dependencies.core.warning(`Spec version tagging failed (non-fatal): ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
129957
|
+
}
|
|
129958
|
+
}
|
|
129959
|
+
}
|
|
129960
|
+
if (inputs.branchStrategy !== "legacy" || process.env[BRANCH_DECISION_ENV]) {
|
|
129961
|
+
const decision = decideBranchTier(inputs);
|
|
129962
|
+
outputs["sync-status"] = "synced";
|
|
129963
|
+
outputs["branch-decision"] = serializeBranchDecision(decision);
|
|
129964
|
+
}
|
|
129245
129965
|
for (const [name, value] of Object.entries(outputs)) {
|
|
129246
129966
|
dependencies.core.setOutput(name, value);
|
|
129247
129967
|
}
|
|
@@ -129431,7 +130151,19 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
129431
130151
|
listMonitors: gatewayAssets.listMonitors.bind(gatewayAssets),
|
|
129432
130152
|
monitorExists: gatewayAssets.monitorExists.bind(gatewayAssets),
|
|
129433
130153
|
findMonitorByCollection: gatewayAssets.findMonitorByCollection.bind(gatewayAssets),
|
|
129434
|
-
runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets)
|
|
130154
|
+
runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets),
|
|
130155
|
+
listEnvironments: gatewayAssets.listEnvironments.bind(gatewayAssets),
|
|
130156
|
+
// GC path (preview/channel retention machine — lib/repo/preview-gc.ts).
|
|
130157
|
+
deleteEnvironment: gatewayAssets.deleteEnvironment.bind(gatewayAssets),
|
|
130158
|
+
deleteMock: gatewayAssets.deleteMock.bind(gatewayAssets),
|
|
130159
|
+
deleteMonitor: gatewayAssets.deleteMonitor.bind(gatewayAssets),
|
|
130160
|
+
deleteCollection: gatewayAssets.deleteCollection.bind(gatewayAssets),
|
|
130161
|
+
listSpecifications: gatewayAssets.listSpecifications.bind(gatewayAssets),
|
|
130162
|
+
getSpecContent: gatewayAssets.getSpecContent.bind(gatewayAssets),
|
|
130163
|
+
listSpecCollections: gatewayAssets.listSpecCollections.bind(gatewayAssets),
|
|
130164
|
+
deleteSpec: gatewayAssets.deleteSpec.bind(gatewayAssets),
|
|
130165
|
+
tagSpecVersion: gatewayAssets.tagSpecVersion.bind(gatewayAssets),
|
|
130166
|
+
listSpecVersionTags: gatewayAssets.listSpecVersionTags.bind(gatewayAssets)
|
|
129435
130167
|
};
|
|
129436
130168
|
const repoMutation = repository && (inputs.repoWriteMode === "commit-only" || inputs.repoWriteMode === "commit-and-push") ? new RepoMutationService({
|
|
129437
130169
|
provider: inputs.provider,
|
|
@@ -129468,8 +130200,43 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
129468
130200
|
repoMutation
|
|
129469
130201
|
};
|
|
129470
130202
|
}
|
|
130203
|
+
function decideBranchTier(inputs, env = process.env) {
|
|
130204
|
+
return resolveEffectiveBranchDecision(
|
|
130205
|
+
{
|
|
130206
|
+
strategy: inputs.branchStrategy,
|
|
130207
|
+
identity: resolveBranchIdentity(env, { defaultBranch: inputs.canonicalBranch }),
|
|
130208
|
+
canonicalBranch: inputs.canonicalBranch,
|
|
130209
|
+
channels: parseChannelRules(inputs.channels)
|
|
130210
|
+
},
|
|
130211
|
+
env
|
|
130212
|
+
);
|
|
130213
|
+
}
|
|
130214
|
+
function runGatedSkip(inputs, decision, actionCore) {
|
|
130215
|
+
actionCore.info(
|
|
130216
|
+
`branch-aware sync: gated run (${decision.reason}) \u2014 repo-sync skipped, zero workspace writes`
|
|
130217
|
+
);
|
|
130218
|
+
const outputs = createOutputs(inputs);
|
|
130219
|
+
outputs["sync-status"] = "skipped-branch-gate";
|
|
130220
|
+
outputs["branch-decision"] = serializeBranchDecision(decision);
|
|
130221
|
+
outputs["repo-sync-summary-json"] = JSON.stringify({
|
|
130222
|
+
status: "skipped-branch-gate",
|
|
130223
|
+
reason: decision.reason
|
|
130224
|
+
});
|
|
130225
|
+
for (const [name, value] of Object.entries(outputs)) {
|
|
130226
|
+
actionCore.setOutput(name, value);
|
|
130227
|
+
}
|
|
130228
|
+
return outputs;
|
|
130229
|
+
}
|
|
129471
130230
|
async function runAction(actionCore = core_exports, actionExec = exec_exports) {
|
|
129472
130231
|
const inputs = readActionInputs(actionCore);
|
|
130232
|
+
const branchDecision = decideBranchTier(inputs);
|
|
130233
|
+
if (branchDecision.tier === "gated") {
|
|
130234
|
+
return runGatedSkip(inputs, branchDecision, actionCore);
|
|
130235
|
+
}
|
|
130236
|
+
if (branchDecision.tier !== "legacy") {
|
|
130237
|
+
actionCore.info(`branch-aware sync: tier=${branchDecision.tier} (${branchDecision.reason})`);
|
|
130238
|
+
process.env[BRANCH_DECISION_ENV] = serializeBranchDecision(branchDecision);
|
|
130239
|
+
}
|
|
129473
130240
|
await mintAccessTokenIfNeeded(inputs, {
|
|
129474
130241
|
info: (message) => actionCore.info(message),
|
|
129475
130242
|
warning: (message) => actionCore.warning(message)
|
|
@@ -129526,14 +130293,19 @@ async function runAction(actionCore = core_exports, actionExec = exec_exports) {
|
|
|
129526
130293
|
}
|
|
129527
130294
|
// Annotate the CommonJS export names for ESM import in node:
|
|
129528
130295
|
0 && (module.exports = {
|
|
130296
|
+
StateUnreadableError,
|
|
130297
|
+
assertBranchAssetIds,
|
|
129529
130298
|
assertPathWithinCwd,
|
|
130299
|
+
buildBranchAssetMarker,
|
|
129530
130300
|
createRepoSyncDependencies,
|
|
130301
|
+
decideBranchTier,
|
|
129531
130302
|
getInput,
|
|
129532
130303
|
hasInput,
|
|
129533
130304
|
readActionInputs,
|
|
129534
130305
|
resolveInputs,
|
|
129535
130306
|
resolvePostmanApiKeyAndTeamId,
|
|
129536
130307
|
runAction,
|
|
130308
|
+
runGatedSkip,
|
|
129537
130309
|
runRepoSync
|
|
129538
130310
|
});
|
|
129539
130311
|
/*! Bundled license information:
|