@postman-cs/onboarding-repo-sync 2.11.2 → 3.0.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/README.md +1 -1
- package/dist/action.cjs +370 -74
- package/dist/cli.cjs +370 -74
- package/dist/index.cjs +370 -74
- package/package.json +2 -1
package/README.md
CHANGED
package/dist/action.cjs
CHANGED
|
@@ -118041,6 +118041,102 @@ function resolvePostmanEndpointProfile(stack, region = "us", env = process.env)
|
|
|
118041
118041
|
};
|
|
118042
118042
|
}
|
|
118043
118043
|
|
|
118044
|
+
// src/lib/postman/environment-yaml.ts
|
|
118045
|
+
var import_fs_utils = __toESM(require_dist5(), 1);
|
|
118046
|
+
var EXTENSION = ".environment.yaml";
|
|
118047
|
+
var SEPARATOR = " - ";
|
|
118048
|
+
var MAX_BASENAME_BYTES = 64;
|
|
118049
|
+
var SANITIZE_OPTIONS = {
|
|
118050
|
+
replacement: "-",
|
|
118051
|
+
combineConsecutiveReplacements: true
|
|
118052
|
+
};
|
|
118053
|
+
function assertWellFormed(value, label) {
|
|
118054
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
118055
|
+
const current2 = value.charCodeAt(index);
|
|
118056
|
+
if (current2 >= 55296 && current2 <= 56319) {
|
|
118057
|
+
const next = value.charCodeAt(index + 1);
|
|
118058
|
+
if (next < 56320 || next > 57343) throw new Error(`${label} must contain well-formed Unicode`);
|
|
118059
|
+
index += 1;
|
|
118060
|
+
} else if (current2 >= 56320 && current2 <= 57343) {
|
|
118061
|
+
throw new Error(`${label} must contain well-formed Unicode`);
|
|
118062
|
+
}
|
|
118063
|
+
}
|
|
118064
|
+
}
|
|
118065
|
+
function safeEnvironmentName(value) {
|
|
118066
|
+
assertWellFormed(value, "environment name");
|
|
118067
|
+
const hasInvalidCharacter = [...value].some((char) => {
|
|
118068
|
+
const code = char.charCodeAt(0);
|
|
118069
|
+
return char === "/" || char === "\\" || code <= 31 || code >= 127 && code <= 159;
|
|
118070
|
+
});
|
|
118071
|
+
if (!value || hasInvalidCharacter) {
|
|
118072
|
+
throw new Error("environment name must be non-empty and contain no path separators or control characters");
|
|
118073
|
+
}
|
|
118074
|
+
return (0, import_fs_utils.sanitizeFilename)(value, {
|
|
118075
|
+
...SANITIZE_OPTIONS,
|
|
118076
|
+
maxLength: MAX_BASENAME_BYTES - Buffer.byteLength(SEPARATOR)
|
|
118077
|
+
});
|
|
118078
|
+
}
|
|
118079
|
+
function environmentFileName(projectName, environmentName) {
|
|
118080
|
+
assertWellFormed(projectName, "project name");
|
|
118081
|
+
const suffix = safeEnvironmentName(environmentName);
|
|
118082
|
+
const projectBudget = Math.max(
|
|
118083
|
+
0,
|
|
118084
|
+
MAX_BASENAME_BYTES - Buffer.byteLength(SEPARATOR) - Buffer.byteLength(suffix)
|
|
118085
|
+
);
|
|
118086
|
+
const prefix = (0, import_fs_utils.sanitizeFilename)(projectName, { ...SANITIZE_OPTIONS, maxLength: projectBudget });
|
|
118087
|
+
return `${prefix ? `${prefix}${SEPARATOR}` : ""}${suffix}${EXTENSION}`;
|
|
118088
|
+
}
|
|
118089
|
+
function assertUniqueEnvironmentFileNames(projectName, environmentNames) {
|
|
118090
|
+
const owners = /* @__PURE__ */ new Map();
|
|
118091
|
+
for (const environmentName of environmentNames) {
|
|
118092
|
+
const fileName = environmentFileName(projectName, environmentName);
|
|
118093
|
+
const key = fileName.normalize("NFD").toUpperCase().toLowerCase();
|
|
118094
|
+
const owner = owners.get(key);
|
|
118095
|
+
if (owner) {
|
|
118096
|
+
throw new Error(
|
|
118097
|
+
`Environment identities "${owner}" and "${environmentName}" resolve to the same artifact filename ${fileName}`
|
|
118098
|
+
);
|
|
118099
|
+
}
|
|
118100
|
+
owners.set(key, environmentName);
|
|
118101
|
+
}
|
|
118102
|
+
}
|
|
118103
|
+
function environmentManifestRef(artifactDir, projectName, environmentName) {
|
|
118104
|
+
return `../${artifactDir}/environments/${environmentFileName(projectName, environmentName)}`;
|
|
118105
|
+
}
|
|
118106
|
+
function legacyEnvironmentManifestRef(artifactDir, environmentName) {
|
|
118107
|
+
return `../${artifactDir}/environments/${environmentName}.postman_environment.json`;
|
|
118108
|
+
}
|
|
118109
|
+
function serializeEnvironmentYaml(payload, displayName) {
|
|
118110
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
118111
|
+
throw new Error("sync-service environment must contain an object body");
|
|
118112
|
+
}
|
|
118113
|
+
const body = payload;
|
|
118114
|
+
if (!Array.isArray(body.values)) {
|
|
118115
|
+
throw new Error("sync-service environment must contain a values array");
|
|
118116
|
+
}
|
|
118117
|
+
const values = body.values.map((entry) => {
|
|
118118
|
+
const input = entry && typeof entry === "object" && !Array.isArray(entry) ? entry : {};
|
|
118119
|
+
const secret = input.secret === true || input.type === "secret";
|
|
118120
|
+
const output = {
|
|
118121
|
+
key: input.key == null ? "" : String(input.key)
|
|
118122
|
+
};
|
|
118123
|
+
if (secret) {
|
|
118124
|
+
output.secret = true;
|
|
118125
|
+
if (input.source != null) output.source = input.source;
|
|
118126
|
+
} else {
|
|
118127
|
+
output.value = input.value == null ? "" : String(input.value);
|
|
118128
|
+
}
|
|
118129
|
+
if (input.enabled === false) output.disabled = true;
|
|
118130
|
+
if (input.description != null) output.description = String(input.description);
|
|
118131
|
+
return output;
|
|
118132
|
+
});
|
|
118133
|
+
const environment = { name: displayName, values };
|
|
118134
|
+
if (Number.isInteger(body.color) && Number(body.color) >= 0 && Number(body.color) < 360) {
|
|
118135
|
+
environment.color = Number(body.color);
|
|
118136
|
+
}
|
|
118137
|
+
return dump(environment, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false });
|
|
118138
|
+
}
|
|
118139
|
+
|
|
118044
118140
|
// src/lib/ci-workflow-template.ts
|
|
118045
118141
|
var DEFAULT_POSTMAN_CLI_INSTALL_URL = POSTMAN_ENDPOINT_PROFILES.prod.cliInstallUrl;
|
|
118046
118142
|
var DEFAULT_POSTMAN_CLI_WINDOWS_INSTALL_URL = POSTMAN_ENDPOINT_PROFILES.prod.cliWindowsInstallUrl;
|
|
@@ -118068,6 +118164,16 @@ function resolveCiRunnerOs(runnerOsOption) {
|
|
|
118068
118164
|
}
|
|
118069
118165
|
throw new Error("ci-runner-os must be one of: linux, windows; got: " + runnerOs);
|
|
118070
118166
|
}
|
|
118167
|
+
function expectedEnvironmentFileName(projectName) {
|
|
118168
|
+
const name = String(projectName || "").trim();
|
|
118169
|
+
return name ? environmentFileName(name, "prod") : "";
|
|
118170
|
+
}
|
|
118171
|
+
function rubyStringLiteral(value) {
|
|
118172
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
118173
|
+
}
|
|
118174
|
+
function powershellStringLiteral(value) {
|
|
118175
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
118176
|
+
}
|
|
118071
118177
|
function renderCiWorkflowTemplate(options = {}) {
|
|
118072
118178
|
const runnerOs = resolveCiRunnerOs(options.runnerOs);
|
|
118073
118179
|
if (runnerOs === "windows") {
|
|
@@ -118076,9 +118182,15 @@ function renderCiWorkflowTemplate(options = {}) {
|
|
|
118076
118182
|
const rawUrl = String(options.postmanCliInstallUrl || "").trim() || DEFAULT_POSTMAN_CLI_INSTALL_URL;
|
|
118077
118183
|
const installUrl = validateHttpsInstallUrl(rawUrl);
|
|
118078
118184
|
const postmanRegion = resolvePostmanRegion(options.postmanRegion);
|
|
118079
|
-
return buildCiWorkflowLines(
|
|
118185
|
+
return buildCiWorkflowLines(
|
|
118186
|
+
installUrl,
|
|
118187
|
+
postmanRegion,
|
|
118188
|
+
options.privateMockAuth === true,
|
|
118189
|
+
options.projectName
|
|
118190
|
+
).join("\n");
|
|
118080
118191
|
}
|
|
118081
|
-
function buildCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
118192
|
+
function buildCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, projectName) {
|
|
118193
|
+
const expectedEnvironment = expectedEnvironmentFileName(projectName);
|
|
118082
118194
|
return [
|
|
118083
118195
|
"name: CI/CD Pipeline",
|
|
118084
118196
|
"on:",
|
|
@@ -118116,11 +118228,18 @@ function buildCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
|
118116
118228
|
" environments = cloud.fetch('environments', {})",
|
|
118117
118229
|
" smoke = collections.find { |path, _| path.include?('[Smoke]') }&.last",
|
|
118118
118230
|
" contract = collections.find { |path, _| path.include?('[Contract]') }&.last",
|
|
118119
|
-
|
|
118231
|
+
` expected_environment = ${rubyStringLiteral(expectedEnvironment)}`,
|
|
118232
|
+
" environment = environments.find { |path, _| File.basename(path) == expected_environment }&.last unless expected_environment.empty?",
|
|
118233
|
+
" environment ||= environments.find { |path, _| File.basename(path) == 'prod.postman_environment.json' }&.last",
|
|
118234
|
+
// A repo whose environments are named only `stage` or `dev` has no prod file to
|
|
118235
|
+
// match, and aborting there would break generated CI that worked before the YAML
|
|
118236
|
+
// migration. One environment is unambiguous, so use it; two or more without a
|
|
118237
|
+
// prod match is a real ambiguity and still aborts.
|
|
118238
|
+
" environment ||= environments.values.first if environments.size == 1",
|
|
118120
118239
|
" missing = []",
|
|
118121
|
-
" missing << '
|
|
118122
|
-
" missing << '
|
|
118123
|
-
" missing << 'environment' unless environment",
|
|
118240
|
+
" missing << '[Smoke] collection' unless smoke",
|
|
118241
|
+
" missing << '[Contract] collection' unless contract",
|
|
118242
|
+
" missing << (expected_environment.empty? ? 'environment' : expected_environment) unless environment",
|
|
118124
118243
|
` abort("Missing Postman resource IDs in .postman/resources.yaml: #{missing.join(', ')}") unless missing.empty?`,
|
|
118125
118244
|
" File.open(ENV.fetch('GITHUB_ENV'), 'a') do |file|",
|
|
118126
118245
|
' file.puts("POSTMAN_SMOKE_COLLECTION_UID=#{smoke}")',
|
|
@@ -118230,7 +118349,8 @@ function buildAdoWindowsCollectionRunLines(displayName, collectionEnvironmentNam
|
|
|
118230
118349
|
...privateMockAuth ? [" POSTMAN_API_KEY: $(POSTMAN_API_KEY)"] : []
|
|
118231
118350
|
];
|
|
118232
118351
|
}
|
|
118233
|
-
function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
118352
|
+
function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, projectName) {
|
|
118353
|
+
const expectedEnvironment = expectedEnvironmentFileName(projectName);
|
|
118234
118354
|
return [
|
|
118235
118355
|
"trigger:",
|
|
118236
118356
|
" branches:",
|
|
@@ -118275,22 +118395,38 @@ function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAu
|
|
|
118275
118395
|
" $contract = ''",
|
|
118276
118396
|
" $environment = ''",
|
|
118277
118397
|
" $fallbackEnvironment = ''",
|
|
118398
|
+
" $environmentCount = 0",
|
|
118399
|
+
` $expectedEnvironment = ${powershellStringLiteral(expectedEnvironment)}`,
|
|
118278
118400
|
" foreach ($line in Get-Content -LiteralPath '.postman/resources.yaml') {",
|
|
118279
|
-
" if ($line -match '^ (collections|environments):\\s*$') { $section = $Matches[1]; continue }",
|
|
118401
|
+
" if ($line -match '^ (collections|environments|specs):\\s*$') { $section = $Matches[1]; continue }",
|
|
118280
118402
|
" if ($line -notmatch '^ (.+?):\\s+(.+?)\\s*$') { continue }",
|
|
118281
|
-
|
|
118403
|
+
" $rawKey = $Matches[1].Trim()",
|
|
118404
|
+
` if ($rawKey.StartsWith("'") -and $rawKey.EndsWith("'")) {`,
|
|
118405
|
+
` $key = $rawKey.Substring(1, $rawKey.Length - 2) -replace "''", "'"`,
|
|
118406
|
+
` } elseif ($rawKey.StartsWith('"') -and $rawKey.EndsWith('"')) {`,
|
|
118407
|
+
" $key = $rawKey.Substring(1, $rawKey.Length - 2)",
|
|
118408
|
+
" } else {",
|
|
118409
|
+
" $key = $rawKey",
|
|
118410
|
+
" }",
|
|
118282
118411
|
` $value = $Matches[2].Trim().Trim("'").Trim('"')`,
|
|
118283
118412
|
" if ($section -eq 'collections' -and $key -match '\\[Smoke\\]') { $smoke = $value }",
|
|
118284
118413
|
" if ($section -eq 'collections' -and $key -match '\\[Contract\\]') { $contract = $value }",
|
|
118285
118414
|
" if ($section -eq 'environments') {",
|
|
118415
|
+
" $environmentCount += 1",
|
|
118286
118416
|
" if ([string]::IsNullOrWhiteSpace($fallbackEnvironment)) { $fallbackEnvironment = $value }",
|
|
118287
|
-
"
|
|
118417
|
+
" $fileName = [IO.Path]::GetFileName($key)",
|
|
118418
|
+
" if ($fileName -eq $expectedEnvironment) { $environment = $value }",
|
|
118419
|
+
" if ([string]::IsNullOrWhiteSpace($environment) -and $fileName -eq 'prod.postman_environment.json') { $environment = $value }",
|
|
118288
118420
|
" }",
|
|
118289
118421
|
" }",
|
|
118290
|
-
|
|
118291
|
-
|
|
118292
|
-
" if ([string]::IsNullOrWhiteSpace($
|
|
118293
|
-
"
|
|
118422
|
+
// Matches the Ruby resolvers: a single environment is unambiguous, so use it
|
|
118423
|
+
// rather than aborting a pipeline that worked before the YAML migration.
|
|
118424
|
+
" if ([string]::IsNullOrWhiteSpace($environment) -and $environmentCount -eq 1) { $environment = $fallbackEnvironment }",
|
|
118425
|
+
" $missing = @()",
|
|
118426
|
+
" if ([string]::IsNullOrWhiteSpace($smoke)) { $missing += '[Smoke] collection' }",
|
|
118427
|
+
" if ([string]::IsNullOrWhiteSpace($contract)) { $missing += '[Contract] collection' }",
|
|
118428
|
+
" if ([string]::IsNullOrWhiteSpace($environment)) { $missing += $(if ($expectedEnvironment) { $expectedEnvironment } else { 'environment' }) }",
|
|
118429
|
+
" if ($missing.Count) { throw ('Missing Postman resource IDs in .postman/resources.yaml: ' + ($missing -join ', ')) }",
|
|
118294
118430
|
' Write-Host "##vso[task.setvariable variable=POSTMAN_SMOKE_COLLECTION_UID]$smoke"',
|
|
118295
118431
|
' Write-Host "##vso[task.setvariable variable=POSTMAN_CONTRACT_COLLECTION_UID]$contract"',
|
|
118296
118432
|
' Write-Host "##vso[task.setvariable variable=POSTMAN_ENVIRONMENT_UID]$environment"',
|
|
@@ -118320,7 +118456,8 @@ function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAu
|
|
|
118320
118456
|
""
|
|
118321
118457
|
];
|
|
118322
118458
|
}
|
|
118323
|
-
function buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
118459
|
+
function buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, projectName) {
|
|
118460
|
+
const expectedEnvironment = expectedEnvironmentFileName(projectName);
|
|
118324
118461
|
return [
|
|
118325
118462
|
"trigger:",
|
|
118326
118463
|
" branches:",
|
|
@@ -118347,16 +118484,29 @@ function buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
|
118347
118484
|
" env:",
|
|
118348
118485
|
" POSTMAN_API_KEY: $(POSTMAN_API_KEY)",
|
|
118349
118486
|
" - script: |",
|
|
118350
|
-
"
|
|
118351
|
-
"
|
|
118352
|
-
"
|
|
118353
|
-
"
|
|
118354
|
-
|
|
118355
|
-
|
|
118356
|
-
|
|
118357
|
-
|
|
118358
|
-
|
|
118359
|
-
|
|
118487
|
+
" ruby <<'RUBY'",
|
|
118488
|
+
" require 'yaml'",
|
|
118489
|
+
" config = YAML.load_file('.postman/resources.yaml') || {}",
|
|
118490
|
+
" cloud = config.fetch('canonical', config.fetch('cloudResources', {}))",
|
|
118491
|
+
" collections = cloud.fetch('collections', {})",
|
|
118492
|
+
" environments = cloud.fetch('environments', {})",
|
|
118493
|
+
" smoke = collections.find { |path, _| path.include?('[Smoke]') }&.last",
|
|
118494
|
+
" contract = collections.find { |path, _| path.include?('[Contract]') }&.last",
|
|
118495
|
+
` expected_environment = ${rubyStringLiteral(expectedEnvironment)}`,
|
|
118496
|
+
" environment = environments.find { |path, _| File.basename(path) == expected_environment }&.last unless expected_environment.empty?",
|
|
118497
|
+
" environment ||= environments.find { |path, _| File.basename(path) == 'prod.postman_environment.json' }&.last",
|
|
118498
|
+
// See the GitHub resolver: one environment is unambiguous, two or more without a
|
|
118499
|
+
// prod match still aborts.
|
|
118500
|
+
" environment ||= environments.values.first if environments.size == 1",
|
|
118501
|
+
" missing = []",
|
|
118502
|
+
" missing << '[Smoke] collection' unless smoke",
|
|
118503
|
+
" missing << '[Contract] collection' unless contract",
|
|
118504
|
+
" missing << (expected_environment.empty? ? 'environment' : expected_environment) unless environment",
|
|
118505
|
+
` abort("Missing Postman resource IDs in .postman/resources.yaml: #{missing.join(', ')}") unless missing.empty?`,
|
|
118506
|
+
' puts "##vso[task.setvariable variable=POSTMAN_SMOKE_COLLECTION_UID]#{smoke}"',
|
|
118507
|
+
' puts "##vso[task.setvariable variable=POSTMAN_CONTRACT_COLLECTION_UID]#{contract}"',
|
|
118508
|
+
' puts "##vso[task.setvariable variable=POSTMAN_ENVIRONMENT_UID]#{environment}"',
|
|
118509
|
+
" RUBY",
|
|
118360
118510
|
" displayName: Resolve Postman Resource IDs",
|
|
118361
118511
|
" - script: |",
|
|
118362
118512
|
' mkdir -p "$(Agent.TempDirectory)/postman-ssl"',
|
|
@@ -118512,7 +118662,7 @@ function getCiWorkflowTemplate(provider, options = {}) {
|
|
|
118512
118662
|
const postmanRegion = resolvePostmanRegion(options.postmanRegion);
|
|
118513
118663
|
const installUrl = validateHttpsInstallUrl(rawUrl);
|
|
118514
118664
|
const privateMockAuth = options.privateMockAuth === true;
|
|
118515
|
-
return (runnerOs === "windows" ? buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) : buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth)).join("\n");
|
|
118665
|
+
return (runnerOs === "windows" ? buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, options.projectName) : buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, options.projectName)).join("\n");
|
|
118516
118666
|
}
|
|
118517
118667
|
return renderCiWorkflowTemplate(options);
|
|
118518
118668
|
}
|
|
@@ -130025,16 +130175,71 @@ function matchesCollectionDirectory(filePath, directoryName) {
|
|
|
130025
130175
|
function matchesBaselineCollectionResource(filePath, assetProjectName) {
|
|
130026
130176
|
return matchesCollectionDirectory(filePath, assetProjectName) || matchesCollectionDirectory(filePath, `${LEGACY_BASELINE_COLLECTION_PREFIX} ${assetProjectName}`);
|
|
130027
130177
|
}
|
|
130028
|
-
function
|
|
130178
|
+
function getEnvironmentOwnershipFromResources(resourcesState, artifactDir, projectName, environmentNames) {
|
|
130179
|
+
const result = {};
|
|
130180
|
+
for (const environmentName of environmentNames) {
|
|
130181
|
+
result[environmentName] = {
|
|
130182
|
+
currentRef: canonicalizeRelativePath(environmentManifestRef(artifactDir, projectName, environmentName)),
|
|
130183
|
+
legacyRef: canonicalizeRelativePath(legacyEnvironmentManifestRef(artifactDir, environmentName))
|
|
130184
|
+
};
|
|
130185
|
+
}
|
|
130029
130186
|
const cloudEnvironments = resourcesState?.cloudResources?.environments;
|
|
130030
130187
|
if (!cloudEnvironments) {
|
|
130031
|
-
return
|
|
130188
|
+
return result;
|
|
130032
130189
|
}
|
|
130033
|
-
|
|
130034
|
-
|
|
130035
|
-
|
|
130036
|
-
|
|
130037
|
-
|
|
130190
|
+
const normalizedEntries = Object.entries(cloudEnvironments).map(([filePath, uid]) => [
|
|
130191
|
+
canonicalizeRelativePath(filePath),
|
|
130192
|
+
uid
|
|
130193
|
+
]);
|
|
130194
|
+
for (const environmentName of environmentNames) {
|
|
130195
|
+
const ownership = result[environmentName];
|
|
130196
|
+
const currentUids = new Set(
|
|
130197
|
+
normalizedEntries.filter(([filePath]) => filePath === ownership.currentRef).map(([, uid]) => uid)
|
|
130198
|
+
);
|
|
130199
|
+
const legacyUids = new Set(
|
|
130200
|
+
normalizedEntries.filter(([filePath]) => filePath === ownership.legacyRef).map(([, uid]) => uid)
|
|
130201
|
+
);
|
|
130202
|
+
if (currentUids.size > 1 || legacyUids.size > 1) {
|
|
130203
|
+
throw new StateUnreadableError(
|
|
130204
|
+
`.postman/resources.yaml maps environment "${environmentName}" artifact to multiple UIDs. Reconcile the entries before rerunning.`
|
|
130205
|
+
);
|
|
130206
|
+
}
|
|
130207
|
+
ownership.currentUid = [...currentUids][0];
|
|
130208
|
+
ownership.legacyUid = [...legacyUids][0];
|
|
130209
|
+
const uids = new Set([ownership.currentUid, ownership.legacyUid].filter(Boolean));
|
|
130210
|
+
if (uids.size > 1) {
|
|
130211
|
+
throw new StateUnreadableError(
|
|
130212
|
+
`.postman/resources.yaml maps canonical and legacy artifacts for environment "${environmentName}" to different UIDs. Reconcile the entries before rerunning.`
|
|
130213
|
+
);
|
|
130214
|
+
}
|
|
130215
|
+
}
|
|
130216
|
+
return result;
|
|
130217
|
+
}
|
|
130218
|
+
function getEnvironmentUidsFromOwnership(ownership) {
|
|
130219
|
+
const result = {};
|
|
130220
|
+
for (const [environmentName, entry] of Object.entries(ownership)) {
|
|
130221
|
+
const uid = entry.currentUid || entry.legacyUid;
|
|
130222
|
+
if (uid) result[environmentName] = uid;
|
|
130223
|
+
}
|
|
130224
|
+
return result;
|
|
130225
|
+
}
|
|
130226
|
+
function assertEnvironmentTargetAvailable(options) {
|
|
130227
|
+
assertPathWithinCwd(options.filePath, "environment target");
|
|
130228
|
+
let stats;
|
|
130229
|
+
try {
|
|
130230
|
+
stats = (0, import_node_fs6.lstatSync)(options.filePath);
|
|
130231
|
+
} catch (error2) {
|
|
130232
|
+
if (error2.code === "ENOENT") return;
|
|
130233
|
+
throw error2;
|
|
130234
|
+
}
|
|
130235
|
+
if (stats.isSymbolicLink() || !stats.isFile()) {
|
|
130236
|
+
throw new StateUnreadableError(
|
|
130237
|
+
`${options.filePath} exists but is not a regular owned environment file. Remove it before rerunning; no cloud environment was changed.`
|
|
130238
|
+
);
|
|
130239
|
+
}
|
|
130240
|
+
if (options.currentUid) return;
|
|
130241
|
+
throw new StateUnreadableError(
|
|
130242
|
+
`${options.filePath} exists but is not owned by .postman/resources.yaml. Adopt its UID into the manifest or remove the file before rerunning; no cloud environment was changed.`
|
|
130038
130243
|
);
|
|
130039
130244
|
}
|
|
130040
130245
|
function normalizeToPosix(filePath) {
|
|
@@ -130459,12 +130664,34 @@ async function persistSslSecrets(inputs, actionCore, _actionExec, repository, en
|
|
|
130459
130664
|
}
|
|
130460
130665
|
}
|
|
130461
130666
|
async function upsertEnvironments(inputs, dependencies, resourcesState, assetMarker) {
|
|
130667
|
+
const environmentNames = /* @__PURE__ */ new Set([
|
|
130668
|
+
...inputs.environments,
|
|
130669
|
+
...Object.keys(inputs.environmentUids)
|
|
130670
|
+
]);
|
|
130671
|
+
assertUniqueEnvironmentFileNames(inputs.projectName, environmentNames);
|
|
130672
|
+
const trackedOwnership = getEnvironmentOwnershipFromResources(
|
|
130673
|
+
resourcesState,
|
|
130674
|
+
inputs.artifactDir,
|
|
130675
|
+
inputs.projectName,
|
|
130676
|
+
environmentNames
|
|
130677
|
+
);
|
|
130678
|
+
const trackedUids = getEnvironmentUidsFromOwnership(trackedOwnership);
|
|
130679
|
+
for (const environmentName of environmentNames) {
|
|
130680
|
+
assertEnvironmentTargetAvailable({
|
|
130681
|
+
filePath: path9.join(
|
|
130682
|
+
inputs.artifactDir,
|
|
130683
|
+
"environments",
|
|
130684
|
+
environmentFileName(inputs.projectName, environmentName)
|
|
130685
|
+
),
|
|
130686
|
+
currentUid: trackedOwnership[environmentName].currentUid
|
|
130687
|
+
});
|
|
130688
|
+
}
|
|
130462
130689
|
const envUids = {
|
|
130463
|
-
...
|
|
130690
|
+
...trackedUids,
|
|
130464
130691
|
...inputs.environmentUids
|
|
130465
130692
|
};
|
|
130466
130693
|
if (!inputs.workspaceId) {
|
|
130467
|
-
return envUids;
|
|
130694
|
+
return { envUids, ownership: trackedOwnership };
|
|
130468
130695
|
}
|
|
130469
130696
|
const mask = resolveRepoSyncMasker(dependencies);
|
|
130470
130697
|
const envRemediation = "verify access-token/team/workspace permissions then rerun";
|
|
@@ -130566,7 +130793,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130566
130793
|
);
|
|
130567
130794
|
}
|
|
130568
130795
|
}
|
|
130569
|
-
return envUids;
|
|
130796
|
+
return { envUids, ownership: trackedOwnership };
|
|
130570
130797
|
}
|
|
130571
130798
|
async function upsertMockEnvironment(inputs, dependencies, assetProjectName, mockUrl, privateMockAuth) {
|
|
130572
130799
|
if (!inputs.mockEnvironmentEnabled || !inputs.workspaceId || !mockUrl) {
|
|
@@ -130726,7 +130953,21 @@ function resolveDurableWorkspaceId(options) {
|
|
|
130726
130953
|
}
|
|
130727
130954
|
return prior === candidate ? prior : void 0;
|
|
130728
130955
|
}
|
|
130729
|
-
function buildResourcesManifest(
|
|
130956
|
+
function buildResourcesManifest(options) {
|
|
130957
|
+
const {
|
|
130958
|
+
workspaceId,
|
|
130959
|
+
collectionMap,
|
|
130960
|
+
envMap,
|
|
130961
|
+
artifactDir,
|
|
130962
|
+
projectName,
|
|
130963
|
+
localSpecRefs,
|
|
130964
|
+
mappedSpecRef,
|
|
130965
|
+
specId,
|
|
130966
|
+
existingSpecs,
|
|
130967
|
+
priorState,
|
|
130968
|
+
preserveGeneratedAssets = false,
|
|
130969
|
+
preservePriorEnvironmentAssets = preserveGeneratedAssets
|
|
130970
|
+
} = options;
|
|
130730
130971
|
const manifest = { ...priorState ?? {} };
|
|
130731
130972
|
delete manifest.version;
|
|
130732
130973
|
delete manifest.workspace;
|
|
@@ -130743,15 +130984,26 @@ function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir,
|
|
|
130743
130984
|
if (collectionKeys.length > 0) {
|
|
130744
130985
|
cloudResources.collections = effectiveCollectionMap;
|
|
130745
130986
|
}
|
|
130746
|
-
const priorEnvironmentMap =
|
|
130987
|
+
const priorEnvironmentMap = preservePriorEnvironmentAssets ? { ...priorState?.cloudResources?.environments ?? {} } : {};
|
|
130747
130988
|
const envEntries = Object.entries(envMap);
|
|
130989
|
+
for (const [envName] of envEntries) {
|
|
130990
|
+
const replacedRefs = /* @__PURE__ */ new Set([
|
|
130991
|
+
canonicalizeRelativePath(environmentManifestRef(artifactDir, projectName, envName)),
|
|
130992
|
+
canonicalizeRelativePath(legacyEnvironmentManifestRef(artifactDir, envName))
|
|
130993
|
+
]);
|
|
130994
|
+
for (const filePath of Object.keys(priorEnvironmentMap)) {
|
|
130995
|
+
if (replacedRefs.has(canonicalizeRelativePath(filePath))) {
|
|
130996
|
+
delete priorEnvironmentMap[filePath];
|
|
130997
|
+
}
|
|
130998
|
+
}
|
|
130999
|
+
}
|
|
130748
131000
|
if (Object.keys(priorEnvironmentMap).length > 0 || envEntries.length > 0) {
|
|
130749
131001
|
cloudResources.environments = priorEnvironmentMap;
|
|
130750
131002
|
}
|
|
130751
131003
|
if (envEntries.length > 0) {
|
|
130752
131004
|
cloudResources.environments ??= {};
|
|
130753
131005
|
for (const [envName, envUid] of envEntries) {
|
|
130754
|
-
cloudResources.environments[
|
|
131006
|
+
cloudResources.environments[environmentManifestRef(artifactDir, projectName, envName)] = envUid;
|
|
130755
131007
|
}
|
|
130756
131008
|
}
|
|
130757
131009
|
void localSpecRefs;
|
|
@@ -131487,18 +131739,19 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131487
131739
|
}
|
|
131488
131740
|
ensureDir(".postman");
|
|
131489
131741
|
assertPathWithinCwd(".postman/resources.yaml", "resources state target");
|
|
131490
|
-
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
|
|
131491
|
-
durableWorkspaceId,
|
|
131492
|
-
{},
|
|
131493
|
-
{},
|
|
131494
|
-
inputs.artifactDir,
|
|
131495
|
-
|
|
131496
|
-
|
|
131497
|
-
|
|
131498
|
-
|
|
131499
|
-
options.
|
|
131500
|
-
|
|
131501
|
-
|
|
131742
|
+
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest({
|
|
131743
|
+
workspaceId: durableWorkspaceId,
|
|
131744
|
+
collectionMap: {},
|
|
131745
|
+
envMap: {},
|
|
131746
|
+
artifactDir: inputs.artifactDir,
|
|
131747
|
+
projectName: inputs.projectName,
|
|
131748
|
+
localSpecRefs: discoveredSpecs.map((spec) => spec.configRelativePath),
|
|
131749
|
+
mappedSpecRef: mappedSpecCloudKey,
|
|
131750
|
+
specId: inputs.specId || void 0,
|
|
131751
|
+
existingSpecs: preservePriorWorkspaceResources ? options.existingSpecs : void 0,
|
|
131752
|
+
priorState: options.priorState,
|
|
131753
|
+
preserveGeneratedAssets: preservePriorWorkspaceResources
|
|
131754
|
+
}));
|
|
131502
131755
|
dependencies.core.info(
|
|
131503
131756
|
"onboarding-scope=spec-only; updated only workspace/spec state in .postman/resources.yaml."
|
|
131504
131757
|
);
|
|
@@ -131564,15 +131817,31 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131564
131817
|
}
|
|
131565
131818
|
}
|
|
131566
131819
|
const environmentSpecs = [
|
|
131567
|
-
...Object.entries(envUids).map(([envName, envUid]) =>
|
|
131568
|
-
envName
|
|
131569
|
-
|
|
131570
|
-
|
|
131571
|
-
|
|
131820
|
+
...Object.entries(envUids).map(([envName, envUid]) => {
|
|
131821
|
+
const ownership = options.environmentOwnership[envName];
|
|
131822
|
+
if (!ownership) {
|
|
131823
|
+
throw new Error(
|
|
131824
|
+
`environment "${envName}" has a UID but no manifest ownership entry; environment sync and artifact export disagree`
|
|
131825
|
+
);
|
|
131826
|
+
}
|
|
131827
|
+
return {
|
|
131828
|
+
kind: "environment",
|
|
131829
|
+
envName,
|
|
131830
|
+
envUid,
|
|
131831
|
+
filePath: `${environmentsDir}/${environmentFileName(inputs.projectName, envName)}`,
|
|
131832
|
+
currentUid: ownership.currentUid,
|
|
131833
|
+
legacyUid: ownership.legacyUid,
|
|
131834
|
+
legacyFilePath: ownership.legacyUid === envUid ? `${environmentsDir}/${envName}.postman_environment.json` : void 0
|
|
131835
|
+
};
|
|
131836
|
+
}),
|
|
131572
131837
|
...options.mockEnvironmentUid ? [{
|
|
131838
|
+
kind: "mock",
|
|
131573
131839
|
envName: "manual-validation",
|
|
131574
131840
|
envUid: options.mockEnvironmentUid,
|
|
131575
|
-
filePath: `${mocksDir}/manual-validation.postman_environment.json
|
|
131841
|
+
filePath: `${mocksDir}/manual-validation.postman_environment.json`,
|
|
131842
|
+
currentUid: void 0,
|
|
131843
|
+
legacyUid: void 0,
|
|
131844
|
+
legacyFilePath: void 0
|
|
131576
131845
|
}] : []
|
|
131577
131846
|
];
|
|
131578
131847
|
const environmentStartedAt = Date.now();
|
|
@@ -131592,26 +131861,50 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131592
131861
|
`environment-artifact-acquisition count=${environmentSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - environmentStartedAt} status=${environmentStatus}`
|
|
131593
131862
|
);
|
|
131594
131863
|
}
|
|
131864
|
+
const legacyEnvironmentCleanupPaths = [];
|
|
131595
131865
|
for (const [index, spec] of environmentSpecs.entries()) {
|
|
131596
|
-
|
|
131597
|
-
|
|
131866
|
+
if (spec.kind === "mock") {
|
|
131867
|
+
assertPathWithinCwd(spec.filePath, "environment target");
|
|
131868
|
+
writeJsonFile(spec.filePath, sanitizeMockEnvironmentArtifact(environmentPayloads[index]), true);
|
|
131869
|
+
continue;
|
|
131870
|
+
}
|
|
131871
|
+
assertEnvironmentTargetAvailable({
|
|
131872
|
+
filePath: spec.filePath,
|
|
131873
|
+
currentUid: spec.currentUid
|
|
131874
|
+
});
|
|
131875
|
+
(0, import_node_fs6.writeFileSync)(
|
|
131598
131876
|
spec.filePath,
|
|
131599
|
-
|
|
131600
|
-
true
|
|
131877
|
+
serializeEnvironmentYaml(environmentPayloads[index], `${inputs.projectName} - ${spec.envName}`)
|
|
131601
131878
|
);
|
|
131879
|
+
if (spec.legacyFilePath) {
|
|
131880
|
+
legacyEnvironmentCleanupPaths.push(spec.legacyFilePath);
|
|
131881
|
+
}
|
|
131602
131882
|
}
|
|
131603
131883
|
assertPathWithinCwd(".postman/resources.yaml", "resources state target");
|
|
131604
|
-
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
|
|
131605
|
-
durableWorkspaceId,
|
|
131606
|
-
manifestCollections,
|
|
131607
|
-
envUids,
|
|
131608
|
-
inputs.artifactDir,
|
|
131609
|
-
|
|
131610
|
-
|
|
131611
|
-
|
|
131612
|
-
|
|
131613
|
-
options.
|
|
131614
|
-
|
|
131884
|
+
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest({
|
|
131885
|
+
workspaceId: durableWorkspaceId,
|
|
131886
|
+
collectionMap: manifestCollections,
|
|
131887
|
+
envMap: envUids,
|
|
131888
|
+
artifactDir: inputs.artifactDir,
|
|
131889
|
+
projectName: inputs.projectName,
|
|
131890
|
+
localSpecRefs: discoveredSpecs.map((spec) => spec.configRelativePath),
|
|
131891
|
+
mappedSpecRef: mappedSpecCloudKey,
|
|
131892
|
+
specId: inputs.specId || void 0,
|
|
131893
|
+
existingSpecs: options.existingSpecs,
|
|
131894
|
+
priorState: options.priorState,
|
|
131895
|
+
// The export path always rewrites collections from this run, but keeps prior
|
|
131896
|
+
// environments so an environment tracked by an earlier run is not dropped.
|
|
131897
|
+
preserveGeneratedAssets: false,
|
|
131898
|
+
preservePriorEnvironmentAssets: preservePriorWorkspaceResources
|
|
131899
|
+
}));
|
|
131900
|
+
for (const legacyFilePath of legacyEnvironmentCleanupPaths) {
|
|
131901
|
+
assertPathWithinCwd(legacyFilePath, "legacy environment target");
|
|
131902
|
+
try {
|
|
131903
|
+
(0, import_node_fs6.unlinkSync)(legacyFilePath);
|
|
131904
|
+
} catch (error2) {
|
|
131905
|
+
if (error2.code !== "ENOENT") throw error2;
|
|
131906
|
+
}
|
|
131907
|
+
}
|
|
131615
131908
|
if (mappedSpec && Object.keys(manifestCollections).length > 0) {
|
|
131616
131909
|
let existingWorkflows;
|
|
131617
131910
|
try {
|
|
@@ -131636,6 +131929,7 @@ function renderCiWorkflow(inputs, privateMockAuth) {
|
|
|
131636
131929
|
}
|
|
131637
131930
|
if (inputs.provider === "azure-devops") {
|
|
131638
131931
|
return getCiWorkflowTemplate(inputs.provider, {
|
|
131932
|
+
projectName: inputs.projectName,
|
|
131639
131933
|
postmanCliInstallUrl: inputs.postmanCliInstallUrl,
|
|
131640
131934
|
postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
|
|
131641
131935
|
runnerOs: inputs.ciRunnerOs,
|
|
@@ -131644,6 +131938,7 @@ function renderCiWorkflow(inputs, privateMockAuth) {
|
|
|
131644
131938
|
});
|
|
131645
131939
|
}
|
|
131646
131940
|
return renderCiWorkflowTemplate({
|
|
131941
|
+
projectName: inputs.projectName,
|
|
131647
131942
|
postmanCliInstallUrl: inputs.postmanCliInstallUrl,
|
|
131648
131943
|
postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
|
|
131649
131944
|
runnerOs: inputs.ciRunnerOs,
|
|
@@ -131892,10 +132187,10 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
|
|
|
131892
132187
|
}
|
|
131893
132188
|
}
|
|
131894
132189
|
const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
|
|
131895
|
-
const envUids = onboardingScope === "full" ? await logger.phase(
|
|
132190
|
+
const { envUids, ownership: environmentOwnership } = onboardingScope === "full" ? await logger.phase(
|
|
131896
132191
|
"sync-environments",
|
|
131897
132192
|
async () => upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker)
|
|
131898
|
-
) : {};
|
|
132193
|
+
) : { envUids: {}, ownership: {} };
|
|
131899
132194
|
outputs["environment-uids-json"] = JSON.stringify(envUids);
|
|
131900
132195
|
dependencies.core.setOutput("environment-uids-json", outputs["environment-uids-json"]);
|
|
131901
132196
|
if (inputs.environmentSyncEnabled && inputs.workspaceId && dependencies.internalIntegration) {
|
|
@@ -132295,6 +132590,7 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
|
|
|
132295
132590
|
mockEnvironmentUid: outputs["mock-environment-uid"] || void 0,
|
|
132296
132591
|
releaseLabel,
|
|
132297
132592
|
priorState: resourcesState,
|
|
132593
|
+
environmentOwnership,
|
|
132298
132594
|
preparedPrebuiltCollections,
|
|
132299
132595
|
privateMockAuth: outputs["mock-auth-required"] === "true"
|
|
132300
132596
|
})
|