@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/dist/index.cjs
CHANGED
|
@@ -118067,6 +118067,102 @@ function resolvePostmanEndpointProfile(stack, region = "us", env = process.env)
|
|
|
118067
118067
|
};
|
|
118068
118068
|
}
|
|
118069
118069
|
|
|
118070
|
+
// src/lib/postman/environment-yaml.ts
|
|
118071
|
+
var import_fs_utils = __toESM(require_dist5(), 1);
|
|
118072
|
+
var EXTENSION = ".environment.yaml";
|
|
118073
|
+
var SEPARATOR = " - ";
|
|
118074
|
+
var MAX_BASENAME_BYTES = 64;
|
|
118075
|
+
var SANITIZE_OPTIONS = {
|
|
118076
|
+
replacement: "-",
|
|
118077
|
+
combineConsecutiveReplacements: true
|
|
118078
|
+
};
|
|
118079
|
+
function assertWellFormed(value, label) {
|
|
118080
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
118081
|
+
const current2 = value.charCodeAt(index);
|
|
118082
|
+
if (current2 >= 55296 && current2 <= 56319) {
|
|
118083
|
+
const next = value.charCodeAt(index + 1);
|
|
118084
|
+
if (next < 56320 || next > 57343) throw new Error(`${label} must contain well-formed Unicode`);
|
|
118085
|
+
index += 1;
|
|
118086
|
+
} else if (current2 >= 56320 && current2 <= 57343) {
|
|
118087
|
+
throw new Error(`${label} must contain well-formed Unicode`);
|
|
118088
|
+
}
|
|
118089
|
+
}
|
|
118090
|
+
}
|
|
118091
|
+
function safeEnvironmentName(value) {
|
|
118092
|
+
assertWellFormed(value, "environment name");
|
|
118093
|
+
const hasInvalidCharacter = [...value].some((char) => {
|
|
118094
|
+
const code = char.charCodeAt(0);
|
|
118095
|
+
return char === "/" || char === "\\" || code <= 31 || code >= 127 && code <= 159;
|
|
118096
|
+
});
|
|
118097
|
+
if (!value || hasInvalidCharacter) {
|
|
118098
|
+
throw new Error("environment name must be non-empty and contain no path separators or control characters");
|
|
118099
|
+
}
|
|
118100
|
+
return (0, import_fs_utils.sanitizeFilename)(value, {
|
|
118101
|
+
...SANITIZE_OPTIONS,
|
|
118102
|
+
maxLength: MAX_BASENAME_BYTES - Buffer.byteLength(SEPARATOR)
|
|
118103
|
+
});
|
|
118104
|
+
}
|
|
118105
|
+
function environmentFileName(projectName, environmentName) {
|
|
118106
|
+
assertWellFormed(projectName, "project name");
|
|
118107
|
+
const suffix = safeEnvironmentName(environmentName);
|
|
118108
|
+
const projectBudget = Math.max(
|
|
118109
|
+
0,
|
|
118110
|
+
MAX_BASENAME_BYTES - Buffer.byteLength(SEPARATOR) - Buffer.byteLength(suffix)
|
|
118111
|
+
);
|
|
118112
|
+
const prefix = (0, import_fs_utils.sanitizeFilename)(projectName, { ...SANITIZE_OPTIONS, maxLength: projectBudget });
|
|
118113
|
+
return `${prefix ? `${prefix}${SEPARATOR}` : ""}${suffix}${EXTENSION}`;
|
|
118114
|
+
}
|
|
118115
|
+
function assertUniqueEnvironmentFileNames(projectName, environmentNames) {
|
|
118116
|
+
const owners = /* @__PURE__ */ new Map();
|
|
118117
|
+
for (const environmentName of environmentNames) {
|
|
118118
|
+
const fileName = environmentFileName(projectName, environmentName);
|
|
118119
|
+
const key = fileName.normalize("NFD").toUpperCase().toLowerCase();
|
|
118120
|
+
const owner = owners.get(key);
|
|
118121
|
+
if (owner) {
|
|
118122
|
+
throw new Error(
|
|
118123
|
+
`Environment identities "${owner}" and "${environmentName}" resolve to the same artifact filename ${fileName}`
|
|
118124
|
+
);
|
|
118125
|
+
}
|
|
118126
|
+
owners.set(key, environmentName);
|
|
118127
|
+
}
|
|
118128
|
+
}
|
|
118129
|
+
function environmentManifestRef(artifactDir, projectName, environmentName) {
|
|
118130
|
+
return `../${artifactDir}/environments/${environmentFileName(projectName, environmentName)}`;
|
|
118131
|
+
}
|
|
118132
|
+
function legacyEnvironmentManifestRef(artifactDir, environmentName) {
|
|
118133
|
+
return `../${artifactDir}/environments/${environmentName}.postman_environment.json`;
|
|
118134
|
+
}
|
|
118135
|
+
function serializeEnvironmentYaml(payload, displayName) {
|
|
118136
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
118137
|
+
throw new Error("sync-service environment must contain an object body");
|
|
118138
|
+
}
|
|
118139
|
+
const body = payload;
|
|
118140
|
+
if (!Array.isArray(body.values)) {
|
|
118141
|
+
throw new Error("sync-service environment must contain a values array");
|
|
118142
|
+
}
|
|
118143
|
+
const values = body.values.map((entry) => {
|
|
118144
|
+
const input = entry && typeof entry === "object" && !Array.isArray(entry) ? entry : {};
|
|
118145
|
+
const secret = input.secret === true || input.type === "secret";
|
|
118146
|
+
const output = {
|
|
118147
|
+
key: input.key == null ? "" : String(input.key)
|
|
118148
|
+
};
|
|
118149
|
+
if (secret) {
|
|
118150
|
+
output.secret = true;
|
|
118151
|
+
if (input.source != null) output.source = input.source;
|
|
118152
|
+
} else {
|
|
118153
|
+
output.value = input.value == null ? "" : String(input.value);
|
|
118154
|
+
}
|
|
118155
|
+
if (input.enabled === false) output.disabled = true;
|
|
118156
|
+
if (input.description != null) output.description = String(input.description);
|
|
118157
|
+
return output;
|
|
118158
|
+
});
|
|
118159
|
+
const environment = { name: displayName, values };
|
|
118160
|
+
if (Number.isInteger(body.color) && Number(body.color) >= 0 && Number(body.color) < 360) {
|
|
118161
|
+
environment.color = Number(body.color);
|
|
118162
|
+
}
|
|
118163
|
+
return dump(environment, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false });
|
|
118164
|
+
}
|
|
118165
|
+
|
|
118070
118166
|
// src/lib/ci-workflow-template.ts
|
|
118071
118167
|
var DEFAULT_POSTMAN_CLI_INSTALL_URL = POSTMAN_ENDPOINT_PROFILES.prod.cliInstallUrl;
|
|
118072
118168
|
var DEFAULT_POSTMAN_CLI_WINDOWS_INSTALL_URL = POSTMAN_ENDPOINT_PROFILES.prod.cliWindowsInstallUrl;
|
|
@@ -118094,6 +118190,16 @@ function resolveCiRunnerOs(runnerOsOption) {
|
|
|
118094
118190
|
}
|
|
118095
118191
|
throw new Error("ci-runner-os must be one of: linux, windows; got: " + runnerOs);
|
|
118096
118192
|
}
|
|
118193
|
+
function expectedEnvironmentFileName(projectName) {
|
|
118194
|
+
const name = String(projectName || "").trim();
|
|
118195
|
+
return name ? environmentFileName(name, "prod") : "";
|
|
118196
|
+
}
|
|
118197
|
+
function rubyStringLiteral(value) {
|
|
118198
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
118199
|
+
}
|
|
118200
|
+
function powershellStringLiteral(value) {
|
|
118201
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
118202
|
+
}
|
|
118097
118203
|
function renderCiWorkflowTemplate(options = {}) {
|
|
118098
118204
|
const runnerOs = resolveCiRunnerOs(options.runnerOs);
|
|
118099
118205
|
if (runnerOs === "windows") {
|
|
@@ -118102,9 +118208,15 @@ function renderCiWorkflowTemplate(options = {}) {
|
|
|
118102
118208
|
const rawUrl = String(options.postmanCliInstallUrl || "").trim() || DEFAULT_POSTMAN_CLI_INSTALL_URL;
|
|
118103
118209
|
const installUrl = validateHttpsInstallUrl(rawUrl);
|
|
118104
118210
|
const postmanRegion = resolvePostmanRegion(options.postmanRegion);
|
|
118105
|
-
return buildCiWorkflowLines(
|
|
118211
|
+
return buildCiWorkflowLines(
|
|
118212
|
+
installUrl,
|
|
118213
|
+
postmanRegion,
|
|
118214
|
+
options.privateMockAuth === true,
|
|
118215
|
+
options.projectName
|
|
118216
|
+
).join("\n");
|
|
118106
118217
|
}
|
|
118107
|
-
function buildCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
118218
|
+
function buildCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, projectName) {
|
|
118219
|
+
const expectedEnvironment = expectedEnvironmentFileName(projectName);
|
|
118108
118220
|
return [
|
|
118109
118221
|
"name: CI/CD Pipeline",
|
|
118110
118222
|
"on:",
|
|
@@ -118142,11 +118254,18 @@ function buildCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
|
118142
118254
|
" environments = cloud.fetch('environments', {})",
|
|
118143
118255
|
" smoke = collections.find { |path, _| path.include?('[Smoke]') }&.last",
|
|
118144
118256
|
" contract = collections.find { |path, _| path.include?('[Contract]') }&.last",
|
|
118145
|
-
|
|
118257
|
+
` expected_environment = ${rubyStringLiteral(expectedEnvironment)}`,
|
|
118258
|
+
" environment = environments.find { |path, _| File.basename(path) == expected_environment }&.last unless expected_environment.empty?",
|
|
118259
|
+
" environment ||= environments.find { |path, _| File.basename(path) == 'prod.postman_environment.json' }&.last",
|
|
118260
|
+
// A repo whose environments are named only `stage` or `dev` has no prod file to
|
|
118261
|
+
// match, and aborting there would break generated CI that worked before the YAML
|
|
118262
|
+
// migration. One environment is unambiguous, so use it; two or more without a
|
|
118263
|
+
// prod match is a real ambiguity and still aborts.
|
|
118264
|
+
" environment ||= environments.values.first if environments.size == 1",
|
|
118146
118265
|
" missing = []",
|
|
118147
|
-
" missing << '
|
|
118148
|
-
" missing << '
|
|
118149
|
-
" missing << 'environment' unless environment",
|
|
118266
|
+
" missing << '[Smoke] collection' unless smoke",
|
|
118267
|
+
" missing << '[Contract] collection' unless contract",
|
|
118268
|
+
" missing << (expected_environment.empty? ? 'environment' : expected_environment) unless environment",
|
|
118150
118269
|
` abort("Missing Postman resource IDs in .postman/resources.yaml: #{missing.join(', ')}") unless missing.empty?`,
|
|
118151
118270
|
" File.open(ENV.fetch('GITHUB_ENV'), 'a') do |file|",
|
|
118152
118271
|
' file.puts("POSTMAN_SMOKE_COLLECTION_UID=#{smoke}")',
|
|
@@ -118256,7 +118375,8 @@ function buildAdoWindowsCollectionRunLines(displayName, collectionEnvironmentNam
|
|
|
118256
118375
|
...privateMockAuth ? [" POSTMAN_API_KEY: $(POSTMAN_API_KEY)"] : []
|
|
118257
118376
|
];
|
|
118258
118377
|
}
|
|
118259
|
-
function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
118378
|
+
function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, projectName) {
|
|
118379
|
+
const expectedEnvironment = expectedEnvironmentFileName(projectName);
|
|
118260
118380
|
return [
|
|
118261
118381
|
"trigger:",
|
|
118262
118382
|
" branches:",
|
|
@@ -118301,22 +118421,38 @@ function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAu
|
|
|
118301
118421
|
" $contract = ''",
|
|
118302
118422
|
" $environment = ''",
|
|
118303
118423
|
" $fallbackEnvironment = ''",
|
|
118424
|
+
" $environmentCount = 0",
|
|
118425
|
+
` $expectedEnvironment = ${powershellStringLiteral(expectedEnvironment)}`,
|
|
118304
118426
|
" foreach ($line in Get-Content -LiteralPath '.postman/resources.yaml') {",
|
|
118305
|
-
" if ($line -match '^ (collections|environments):\\s*$') { $section = $Matches[1]; continue }",
|
|
118427
|
+
" if ($line -match '^ (collections|environments|specs):\\s*$') { $section = $Matches[1]; continue }",
|
|
118306
118428
|
" if ($line -notmatch '^ (.+?):\\s+(.+?)\\s*$') { continue }",
|
|
118307
|
-
|
|
118429
|
+
" $rawKey = $Matches[1].Trim()",
|
|
118430
|
+
` if ($rawKey.StartsWith("'") -and $rawKey.EndsWith("'")) {`,
|
|
118431
|
+
` $key = $rawKey.Substring(1, $rawKey.Length - 2) -replace "''", "'"`,
|
|
118432
|
+
` } elseif ($rawKey.StartsWith('"') -and $rawKey.EndsWith('"')) {`,
|
|
118433
|
+
" $key = $rawKey.Substring(1, $rawKey.Length - 2)",
|
|
118434
|
+
" } else {",
|
|
118435
|
+
" $key = $rawKey",
|
|
118436
|
+
" }",
|
|
118308
118437
|
` $value = $Matches[2].Trim().Trim("'").Trim('"')`,
|
|
118309
118438
|
" if ($section -eq 'collections' -and $key -match '\\[Smoke\\]') { $smoke = $value }",
|
|
118310
118439
|
" if ($section -eq 'collections' -and $key -match '\\[Contract\\]') { $contract = $value }",
|
|
118311
118440
|
" if ($section -eq 'environments') {",
|
|
118441
|
+
" $environmentCount += 1",
|
|
118312
118442
|
" if ([string]::IsNullOrWhiteSpace($fallbackEnvironment)) { $fallbackEnvironment = $value }",
|
|
118313
|
-
"
|
|
118443
|
+
" $fileName = [IO.Path]::GetFileName($key)",
|
|
118444
|
+
" if ($fileName -eq $expectedEnvironment) { $environment = $value }",
|
|
118445
|
+
" if ([string]::IsNullOrWhiteSpace($environment) -and $fileName -eq 'prod.postman_environment.json') { $environment = $value }",
|
|
118314
118446
|
" }",
|
|
118315
118447
|
" }",
|
|
118316
|
-
|
|
118317
|
-
|
|
118318
|
-
" if ([string]::IsNullOrWhiteSpace($
|
|
118319
|
-
"
|
|
118448
|
+
// Matches the Ruby resolvers: a single environment is unambiguous, so use it
|
|
118449
|
+
// rather than aborting a pipeline that worked before the YAML migration.
|
|
118450
|
+
" if ([string]::IsNullOrWhiteSpace($environment) -and $environmentCount -eq 1) { $environment = $fallbackEnvironment }",
|
|
118451
|
+
" $missing = @()",
|
|
118452
|
+
" if ([string]::IsNullOrWhiteSpace($smoke)) { $missing += '[Smoke] collection' }",
|
|
118453
|
+
" if ([string]::IsNullOrWhiteSpace($contract)) { $missing += '[Contract] collection' }",
|
|
118454
|
+
" if ([string]::IsNullOrWhiteSpace($environment)) { $missing += $(if ($expectedEnvironment) { $expectedEnvironment } else { 'environment' }) }",
|
|
118455
|
+
" if ($missing.Count) { throw ('Missing Postman resource IDs in .postman/resources.yaml: ' + ($missing -join ', ')) }",
|
|
118320
118456
|
' Write-Host "##vso[task.setvariable variable=POSTMAN_SMOKE_COLLECTION_UID]$smoke"',
|
|
118321
118457
|
' Write-Host "##vso[task.setvariable variable=POSTMAN_CONTRACT_COLLECTION_UID]$contract"',
|
|
118322
118458
|
' Write-Host "##vso[task.setvariable variable=POSTMAN_ENVIRONMENT_UID]$environment"',
|
|
@@ -118346,7 +118482,8 @@ function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAu
|
|
|
118346
118482
|
""
|
|
118347
118483
|
];
|
|
118348
118484
|
}
|
|
118349
|
-
function buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
118485
|
+
function buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, projectName) {
|
|
118486
|
+
const expectedEnvironment = expectedEnvironmentFileName(projectName);
|
|
118350
118487
|
return [
|
|
118351
118488
|
"trigger:",
|
|
118352
118489
|
" branches:",
|
|
@@ -118373,16 +118510,29 @@ function buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) {
|
|
|
118373
118510
|
" env:",
|
|
118374
118511
|
" POSTMAN_API_KEY: $(POSTMAN_API_KEY)",
|
|
118375
118512
|
" - script: |",
|
|
118376
|
-
"
|
|
118377
|
-
"
|
|
118378
|
-
"
|
|
118379
|
-
"
|
|
118380
|
-
|
|
118381
|
-
|
|
118382
|
-
|
|
118383
|
-
|
|
118384
|
-
|
|
118385
|
-
|
|
118513
|
+
" ruby <<'RUBY'",
|
|
118514
|
+
" require 'yaml'",
|
|
118515
|
+
" config = YAML.load_file('.postman/resources.yaml') || {}",
|
|
118516
|
+
" cloud = config.fetch('canonical', config.fetch('cloudResources', {}))",
|
|
118517
|
+
" collections = cloud.fetch('collections', {})",
|
|
118518
|
+
" environments = cloud.fetch('environments', {})",
|
|
118519
|
+
" smoke = collections.find { |path, _| path.include?('[Smoke]') }&.last",
|
|
118520
|
+
" contract = collections.find { |path, _| path.include?('[Contract]') }&.last",
|
|
118521
|
+
` expected_environment = ${rubyStringLiteral(expectedEnvironment)}`,
|
|
118522
|
+
" environment = environments.find { |path, _| File.basename(path) == expected_environment }&.last unless expected_environment.empty?",
|
|
118523
|
+
" environment ||= environments.find { |path, _| File.basename(path) == 'prod.postman_environment.json' }&.last",
|
|
118524
|
+
// See the GitHub resolver: one environment is unambiguous, two or more without a
|
|
118525
|
+
// prod match still aborts.
|
|
118526
|
+
" environment ||= environments.values.first if environments.size == 1",
|
|
118527
|
+
" missing = []",
|
|
118528
|
+
" missing << '[Smoke] collection' unless smoke",
|
|
118529
|
+
" missing << '[Contract] collection' unless contract",
|
|
118530
|
+
" missing << (expected_environment.empty? ? 'environment' : expected_environment) unless environment",
|
|
118531
|
+
` abort("Missing Postman resource IDs in .postman/resources.yaml: #{missing.join(', ')}") unless missing.empty?`,
|
|
118532
|
+
' puts "##vso[task.setvariable variable=POSTMAN_SMOKE_COLLECTION_UID]#{smoke}"',
|
|
118533
|
+
' puts "##vso[task.setvariable variable=POSTMAN_CONTRACT_COLLECTION_UID]#{contract}"',
|
|
118534
|
+
' puts "##vso[task.setvariable variable=POSTMAN_ENVIRONMENT_UID]#{environment}"',
|
|
118535
|
+
" RUBY",
|
|
118386
118536
|
" displayName: Resolve Postman Resource IDs",
|
|
118387
118537
|
" - script: |",
|
|
118388
118538
|
' mkdir -p "$(Agent.TempDirectory)/postman-ssl"',
|
|
@@ -118538,7 +118688,7 @@ function getCiWorkflowTemplate(provider, options = {}) {
|
|
|
118538
118688
|
const postmanRegion = resolvePostmanRegion(options.postmanRegion);
|
|
118539
118689
|
const installUrl = validateHttpsInstallUrl(rawUrl);
|
|
118540
118690
|
const privateMockAuth = options.privateMockAuth === true;
|
|
118541
|
-
return (runnerOs === "windows" ? buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth) : buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth)).join("\n");
|
|
118691
|
+
return (runnerOs === "windows" ? buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, options.projectName) : buildAdoCiWorkflowLines(installUrl, postmanRegion, privateMockAuth, options.projectName)).join("\n");
|
|
118542
118692
|
}
|
|
118543
118693
|
return renderCiWorkflowTemplate(options);
|
|
118544
118694
|
}
|
|
@@ -130051,16 +130201,71 @@ function matchesCollectionDirectory(filePath, directoryName) {
|
|
|
130051
130201
|
function matchesBaselineCollectionResource(filePath, assetProjectName) {
|
|
130052
130202
|
return matchesCollectionDirectory(filePath, assetProjectName) || matchesCollectionDirectory(filePath, `${LEGACY_BASELINE_COLLECTION_PREFIX} ${assetProjectName}`);
|
|
130053
130203
|
}
|
|
130054
|
-
function
|
|
130204
|
+
function getEnvironmentOwnershipFromResources(resourcesState, artifactDir, projectName, environmentNames) {
|
|
130205
|
+
const result = {};
|
|
130206
|
+
for (const environmentName of environmentNames) {
|
|
130207
|
+
result[environmentName] = {
|
|
130208
|
+
currentRef: canonicalizeRelativePath(environmentManifestRef(artifactDir, projectName, environmentName)),
|
|
130209
|
+
legacyRef: canonicalizeRelativePath(legacyEnvironmentManifestRef(artifactDir, environmentName))
|
|
130210
|
+
};
|
|
130211
|
+
}
|
|
130055
130212
|
const cloudEnvironments = resourcesState?.cloudResources?.environments;
|
|
130056
130213
|
if (!cloudEnvironments) {
|
|
130057
|
-
return
|
|
130214
|
+
return result;
|
|
130058
130215
|
}
|
|
130059
|
-
|
|
130060
|
-
|
|
130061
|
-
|
|
130062
|
-
|
|
130063
|
-
|
|
130216
|
+
const normalizedEntries = Object.entries(cloudEnvironments).map(([filePath, uid]) => [
|
|
130217
|
+
canonicalizeRelativePath(filePath),
|
|
130218
|
+
uid
|
|
130219
|
+
]);
|
|
130220
|
+
for (const environmentName of environmentNames) {
|
|
130221
|
+
const ownership = result[environmentName];
|
|
130222
|
+
const currentUids = new Set(
|
|
130223
|
+
normalizedEntries.filter(([filePath]) => filePath === ownership.currentRef).map(([, uid]) => uid)
|
|
130224
|
+
);
|
|
130225
|
+
const legacyUids = new Set(
|
|
130226
|
+
normalizedEntries.filter(([filePath]) => filePath === ownership.legacyRef).map(([, uid]) => uid)
|
|
130227
|
+
);
|
|
130228
|
+
if (currentUids.size > 1 || legacyUids.size > 1) {
|
|
130229
|
+
throw new StateUnreadableError(
|
|
130230
|
+
`.postman/resources.yaml maps environment "${environmentName}" artifact to multiple UIDs. Reconcile the entries before rerunning.`
|
|
130231
|
+
);
|
|
130232
|
+
}
|
|
130233
|
+
ownership.currentUid = [...currentUids][0];
|
|
130234
|
+
ownership.legacyUid = [...legacyUids][0];
|
|
130235
|
+
const uids = new Set([ownership.currentUid, ownership.legacyUid].filter(Boolean));
|
|
130236
|
+
if (uids.size > 1) {
|
|
130237
|
+
throw new StateUnreadableError(
|
|
130238
|
+
`.postman/resources.yaml maps canonical and legacy artifacts for environment "${environmentName}" to different UIDs. Reconcile the entries before rerunning.`
|
|
130239
|
+
);
|
|
130240
|
+
}
|
|
130241
|
+
}
|
|
130242
|
+
return result;
|
|
130243
|
+
}
|
|
130244
|
+
function getEnvironmentUidsFromOwnership(ownership) {
|
|
130245
|
+
const result = {};
|
|
130246
|
+
for (const [environmentName, entry] of Object.entries(ownership)) {
|
|
130247
|
+
const uid = entry.currentUid || entry.legacyUid;
|
|
130248
|
+
if (uid) result[environmentName] = uid;
|
|
130249
|
+
}
|
|
130250
|
+
return result;
|
|
130251
|
+
}
|
|
130252
|
+
function assertEnvironmentTargetAvailable(options) {
|
|
130253
|
+
assertPathWithinCwd(options.filePath, "environment target");
|
|
130254
|
+
let stats;
|
|
130255
|
+
try {
|
|
130256
|
+
stats = (0, import_node_fs6.lstatSync)(options.filePath);
|
|
130257
|
+
} catch (error2) {
|
|
130258
|
+
if (error2.code === "ENOENT") return;
|
|
130259
|
+
throw error2;
|
|
130260
|
+
}
|
|
130261
|
+
if (stats.isSymbolicLink() || !stats.isFile()) {
|
|
130262
|
+
throw new StateUnreadableError(
|
|
130263
|
+
`${options.filePath} exists but is not a regular owned environment file. Remove it before rerunning; no cloud environment was changed.`
|
|
130264
|
+
);
|
|
130265
|
+
}
|
|
130266
|
+
if (options.currentUid) return;
|
|
130267
|
+
throw new StateUnreadableError(
|
|
130268
|
+
`${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.`
|
|
130064
130269
|
);
|
|
130065
130270
|
}
|
|
130066
130271
|
function normalizeToPosix(filePath) {
|
|
@@ -130485,12 +130690,34 @@ async function persistSslSecrets(inputs, actionCore, _actionExec, repository, en
|
|
|
130485
130690
|
}
|
|
130486
130691
|
}
|
|
130487
130692
|
async function upsertEnvironments(inputs, dependencies, resourcesState, assetMarker) {
|
|
130693
|
+
const environmentNames = /* @__PURE__ */ new Set([
|
|
130694
|
+
...inputs.environments,
|
|
130695
|
+
...Object.keys(inputs.environmentUids)
|
|
130696
|
+
]);
|
|
130697
|
+
assertUniqueEnvironmentFileNames(inputs.projectName, environmentNames);
|
|
130698
|
+
const trackedOwnership = getEnvironmentOwnershipFromResources(
|
|
130699
|
+
resourcesState,
|
|
130700
|
+
inputs.artifactDir,
|
|
130701
|
+
inputs.projectName,
|
|
130702
|
+
environmentNames
|
|
130703
|
+
);
|
|
130704
|
+
const trackedUids = getEnvironmentUidsFromOwnership(trackedOwnership);
|
|
130705
|
+
for (const environmentName of environmentNames) {
|
|
130706
|
+
assertEnvironmentTargetAvailable({
|
|
130707
|
+
filePath: path9.join(
|
|
130708
|
+
inputs.artifactDir,
|
|
130709
|
+
"environments",
|
|
130710
|
+
environmentFileName(inputs.projectName, environmentName)
|
|
130711
|
+
),
|
|
130712
|
+
currentUid: trackedOwnership[environmentName].currentUid
|
|
130713
|
+
});
|
|
130714
|
+
}
|
|
130488
130715
|
const envUids = {
|
|
130489
|
-
...
|
|
130716
|
+
...trackedUids,
|
|
130490
130717
|
...inputs.environmentUids
|
|
130491
130718
|
};
|
|
130492
130719
|
if (!inputs.workspaceId) {
|
|
130493
|
-
return envUids;
|
|
130720
|
+
return { envUids, ownership: trackedOwnership };
|
|
130494
130721
|
}
|
|
130495
130722
|
const mask = resolveRepoSyncMasker(dependencies);
|
|
130496
130723
|
const envRemediation = "verify access-token/team/workspace permissions then rerun";
|
|
@@ -130592,7 +130819,7 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130592
130819
|
);
|
|
130593
130820
|
}
|
|
130594
130821
|
}
|
|
130595
|
-
return envUids;
|
|
130822
|
+
return { envUids, ownership: trackedOwnership };
|
|
130596
130823
|
}
|
|
130597
130824
|
async function upsertMockEnvironment(inputs, dependencies, assetProjectName, mockUrl, privateMockAuth) {
|
|
130598
130825
|
if (!inputs.mockEnvironmentEnabled || !inputs.workspaceId || !mockUrl) {
|
|
@@ -130752,7 +130979,21 @@ function resolveDurableWorkspaceId(options) {
|
|
|
130752
130979
|
}
|
|
130753
130980
|
return prior === candidate ? prior : void 0;
|
|
130754
130981
|
}
|
|
130755
|
-
function buildResourcesManifest(
|
|
130982
|
+
function buildResourcesManifest(options) {
|
|
130983
|
+
const {
|
|
130984
|
+
workspaceId,
|
|
130985
|
+
collectionMap,
|
|
130986
|
+
envMap,
|
|
130987
|
+
artifactDir,
|
|
130988
|
+
projectName,
|
|
130989
|
+
localSpecRefs,
|
|
130990
|
+
mappedSpecRef,
|
|
130991
|
+
specId,
|
|
130992
|
+
existingSpecs,
|
|
130993
|
+
priorState,
|
|
130994
|
+
preserveGeneratedAssets = false,
|
|
130995
|
+
preservePriorEnvironmentAssets = preserveGeneratedAssets
|
|
130996
|
+
} = options;
|
|
130756
130997
|
const manifest = { ...priorState ?? {} };
|
|
130757
130998
|
delete manifest.version;
|
|
130758
130999
|
delete manifest.workspace;
|
|
@@ -130769,15 +131010,26 @@ function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir,
|
|
|
130769
131010
|
if (collectionKeys.length > 0) {
|
|
130770
131011
|
cloudResources.collections = effectiveCollectionMap;
|
|
130771
131012
|
}
|
|
130772
|
-
const priorEnvironmentMap =
|
|
131013
|
+
const priorEnvironmentMap = preservePriorEnvironmentAssets ? { ...priorState?.cloudResources?.environments ?? {} } : {};
|
|
130773
131014
|
const envEntries = Object.entries(envMap);
|
|
131015
|
+
for (const [envName] of envEntries) {
|
|
131016
|
+
const replacedRefs = /* @__PURE__ */ new Set([
|
|
131017
|
+
canonicalizeRelativePath(environmentManifestRef(artifactDir, projectName, envName)),
|
|
131018
|
+
canonicalizeRelativePath(legacyEnvironmentManifestRef(artifactDir, envName))
|
|
131019
|
+
]);
|
|
131020
|
+
for (const filePath of Object.keys(priorEnvironmentMap)) {
|
|
131021
|
+
if (replacedRefs.has(canonicalizeRelativePath(filePath))) {
|
|
131022
|
+
delete priorEnvironmentMap[filePath];
|
|
131023
|
+
}
|
|
131024
|
+
}
|
|
131025
|
+
}
|
|
130774
131026
|
if (Object.keys(priorEnvironmentMap).length > 0 || envEntries.length > 0) {
|
|
130775
131027
|
cloudResources.environments = priorEnvironmentMap;
|
|
130776
131028
|
}
|
|
130777
131029
|
if (envEntries.length > 0) {
|
|
130778
131030
|
cloudResources.environments ??= {};
|
|
130779
131031
|
for (const [envName, envUid] of envEntries) {
|
|
130780
|
-
cloudResources.environments[
|
|
131032
|
+
cloudResources.environments[environmentManifestRef(artifactDir, projectName, envName)] = envUid;
|
|
130781
131033
|
}
|
|
130782
131034
|
}
|
|
130783
131035
|
void localSpecRefs;
|
|
@@ -131513,18 +131765,19 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131513
131765
|
}
|
|
131514
131766
|
ensureDir(".postman");
|
|
131515
131767
|
assertPathWithinCwd(".postman/resources.yaml", "resources state target");
|
|
131516
|
-
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
|
|
131517
|
-
durableWorkspaceId,
|
|
131518
|
-
{},
|
|
131519
|
-
{},
|
|
131520
|
-
inputs.artifactDir,
|
|
131521
|
-
|
|
131522
|
-
|
|
131523
|
-
|
|
131524
|
-
|
|
131525
|
-
options.
|
|
131526
|
-
|
|
131527
|
-
|
|
131768
|
+
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest({
|
|
131769
|
+
workspaceId: durableWorkspaceId,
|
|
131770
|
+
collectionMap: {},
|
|
131771
|
+
envMap: {},
|
|
131772
|
+
artifactDir: inputs.artifactDir,
|
|
131773
|
+
projectName: inputs.projectName,
|
|
131774
|
+
localSpecRefs: discoveredSpecs.map((spec) => spec.configRelativePath),
|
|
131775
|
+
mappedSpecRef: mappedSpecCloudKey,
|
|
131776
|
+
specId: inputs.specId || void 0,
|
|
131777
|
+
existingSpecs: preservePriorWorkspaceResources ? options.existingSpecs : void 0,
|
|
131778
|
+
priorState: options.priorState,
|
|
131779
|
+
preserveGeneratedAssets: preservePriorWorkspaceResources
|
|
131780
|
+
}));
|
|
131528
131781
|
dependencies.core.info(
|
|
131529
131782
|
"onboarding-scope=spec-only; updated only workspace/spec state in .postman/resources.yaml."
|
|
131530
131783
|
);
|
|
@@ -131590,15 +131843,31 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131590
131843
|
}
|
|
131591
131844
|
}
|
|
131592
131845
|
const environmentSpecs = [
|
|
131593
|
-
...Object.entries(envUids).map(([envName, envUid]) =>
|
|
131594
|
-
envName
|
|
131595
|
-
|
|
131596
|
-
|
|
131597
|
-
|
|
131846
|
+
...Object.entries(envUids).map(([envName, envUid]) => {
|
|
131847
|
+
const ownership = options.environmentOwnership[envName];
|
|
131848
|
+
if (!ownership) {
|
|
131849
|
+
throw new Error(
|
|
131850
|
+
`environment "${envName}" has a UID but no manifest ownership entry; environment sync and artifact export disagree`
|
|
131851
|
+
);
|
|
131852
|
+
}
|
|
131853
|
+
return {
|
|
131854
|
+
kind: "environment",
|
|
131855
|
+
envName,
|
|
131856
|
+
envUid,
|
|
131857
|
+
filePath: `${environmentsDir}/${environmentFileName(inputs.projectName, envName)}`,
|
|
131858
|
+
currentUid: ownership.currentUid,
|
|
131859
|
+
legacyUid: ownership.legacyUid,
|
|
131860
|
+
legacyFilePath: ownership.legacyUid === envUid ? `${environmentsDir}/${envName}.postman_environment.json` : void 0
|
|
131861
|
+
};
|
|
131862
|
+
}),
|
|
131598
131863
|
...options.mockEnvironmentUid ? [{
|
|
131864
|
+
kind: "mock",
|
|
131599
131865
|
envName: "manual-validation",
|
|
131600
131866
|
envUid: options.mockEnvironmentUid,
|
|
131601
|
-
filePath: `${mocksDir}/manual-validation.postman_environment.json
|
|
131867
|
+
filePath: `${mocksDir}/manual-validation.postman_environment.json`,
|
|
131868
|
+
currentUid: void 0,
|
|
131869
|
+
legacyUid: void 0,
|
|
131870
|
+
legacyFilePath: void 0
|
|
131602
131871
|
}] : []
|
|
131603
131872
|
];
|
|
131604
131873
|
const environmentStartedAt = Date.now();
|
|
@@ -131618,26 +131887,50 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131618
131887
|
`environment-artifact-acquisition count=${environmentSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - environmentStartedAt} status=${environmentStatus}`
|
|
131619
131888
|
);
|
|
131620
131889
|
}
|
|
131890
|
+
const legacyEnvironmentCleanupPaths = [];
|
|
131621
131891
|
for (const [index, spec] of environmentSpecs.entries()) {
|
|
131622
|
-
|
|
131623
|
-
|
|
131892
|
+
if (spec.kind === "mock") {
|
|
131893
|
+
assertPathWithinCwd(spec.filePath, "environment target");
|
|
131894
|
+
writeJsonFile(spec.filePath, sanitizeMockEnvironmentArtifact(environmentPayloads[index]), true);
|
|
131895
|
+
continue;
|
|
131896
|
+
}
|
|
131897
|
+
assertEnvironmentTargetAvailable({
|
|
131898
|
+
filePath: spec.filePath,
|
|
131899
|
+
currentUid: spec.currentUid
|
|
131900
|
+
});
|
|
131901
|
+
(0, import_node_fs6.writeFileSync)(
|
|
131624
131902
|
spec.filePath,
|
|
131625
|
-
|
|
131626
|
-
true
|
|
131903
|
+
serializeEnvironmentYaml(environmentPayloads[index], `${inputs.projectName} - ${spec.envName}`)
|
|
131627
131904
|
);
|
|
131905
|
+
if (spec.legacyFilePath) {
|
|
131906
|
+
legacyEnvironmentCleanupPaths.push(spec.legacyFilePath);
|
|
131907
|
+
}
|
|
131628
131908
|
}
|
|
131629
131909
|
assertPathWithinCwd(".postman/resources.yaml", "resources state target");
|
|
131630
|
-
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
|
|
131631
|
-
durableWorkspaceId,
|
|
131632
|
-
manifestCollections,
|
|
131633
|
-
envUids,
|
|
131634
|
-
inputs.artifactDir,
|
|
131635
|
-
|
|
131636
|
-
|
|
131637
|
-
|
|
131638
|
-
|
|
131639
|
-
options.
|
|
131640
|
-
|
|
131910
|
+
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest({
|
|
131911
|
+
workspaceId: durableWorkspaceId,
|
|
131912
|
+
collectionMap: manifestCollections,
|
|
131913
|
+
envMap: envUids,
|
|
131914
|
+
artifactDir: inputs.artifactDir,
|
|
131915
|
+
projectName: inputs.projectName,
|
|
131916
|
+
localSpecRefs: discoveredSpecs.map((spec) => spec.configRelativePath),
|
|
131917
|
+
mappedSpecRef: mappedSpecCloudKey,
|
|
131918
|
+
specId: inputs.specId || void 0,
|
|
131919
|
+
existingSpecs: options.existingSpecs,
|
|
131920
|
+
priorState: options.priorState,
|
|
131921
|
+
// The export path always rewrites collections from this run, but keeps prior
|
|
131922
|
+
// environments so an environment tracked by an earlier run is not dropped.
|
|
131923
|
+
preserveGeneratedAssets: false,
|
|
131924
|
+
preservePriorEnvironmentAssets: preservePriorWorkspaceResources
|
|
131925
|
+
}));
|
|
131926
|
+
for (const legacyFilePath of legacyEnvironmentCleanupPaths) {
|
|
131927
|
+
assertPathWithinCwd(legacyFilePath, "legacy environment target");
|
|
131928
|
+
try {
|
|
131929
|
+
(0, import_node_fs6.unlinkSync)(legacyFilePath);
|
|
131930
|
+
} catch (error2) {
|
|
131931
|
+
if (error2.code !== "ENOENT") throw error2;
|
|
131932
|
+
}
|
|
131933
|
+
}
|
|
131641
131934
|
if (mappedSpec && Object.keys(manifestCollections).length > 0) {
|
|
131642
131935
|
let existingWorkflows;
|
|
131643
131936
|
try {
|
|
@@ -131662,6 +131955,7 @@ function renderCiWorkflow(inputs, privateMockAuth) {
|
|
|
131662
131955
|
}
|
|
131663
131956
|
if (inputs.provider === "azure-devops") {
|
|
131664
131957
|
return getCiWorkflowTemplate(inputs.provider, {
|
|
131958
|
+
projectName: inputs.projectName,
|
|
131665
131959
|
postmanCliInstallUrl: inputs.postmanCliInstallUrl,
|
|
131666
131960
|
postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
|
|
131667
131961
|
runnerOs: inputs.ciRunnerOs,
|
|
@@ -131670,6 +131964,7 @@ function renderCiWorkflow(inputs, privateMockAuth) {
|
|
|
131670
131964
|
});
|
|
131671
131965
|
}
|
|
131672
131966
|
return renderCiWorkflowTemplate({
|
|
131967
|
+
projectName: inputs.projectName,
|
|
131673
131968
|
postmanCliInstallUrl: inputs.postmanCliInstallUrl,
|
|
131674
131969
|
postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
|
|
131675
131970
|
runnerOs: inputs.ciRunnerOs,
|
|
@@ -131918,10 +132213,10 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
|
|
|
131918
132213
|
}
|
|
131919
132214
|
}
|
|
131920
132215
|
const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
|
|
131921
|
-
const envUids = onboardingScope === "full" ? await logger.phase(
|
|
132216
|
+
const { envUids, ownership: environmentOwnership } = onboardingScope === "full" ? await logger.phase(
|
|
131922
132217
|
"sync-environments",
|
|
131923
132218
|
async () => upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker)
|
|
131924
|
-
) : {};
|
|
132219
|
+
) : { envUids: {}, ownership: {} };
|
|
131925
132220
|
outputs["environment-uids-json"] = JSON.stringify(envUids);
|
|
131926
132221
|
dependencies.core.setOutput("environment-uids-json", outputs["environment-uids-json"]);
|
|
131927
132222
|
if (inputs.environmentSyncEnabled && inputs.workspaceId && dependencies.internalIntegration) {
|
|
@@ -132321,6 +132616,7 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
|
|
|
132321
132616
|
mockEnvironmentUid: outputs["mock-environment-uid"] || void 0,
|
|
132322
132617
|
releaseLabel,
|
|
132323
132618
|
priorState: resourcesState,
|
|
132619
|
+
environmentOwnership,
|
|
132324
132620
|
preparedPrebuiltCollections,
|
|
132325
132621
|
privateMockAuth: outputs["mock-auth-required"] === "true"
|
|
132326
132622
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postman-cs/onboarding-repo-sync",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Postman repo sync GitHub Action.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"@actions/core": "^3.0.1",
|
|
56
56
|
"@actions/exec": "^3.0.0",
|
|
57
57
|
"@postman-cs/automation-core": "^1.8.1",
|
|
58
|
+
"@postman/fs-utils": "0.3.1",
|
|
58
59
|
"js-yaml": "^5.2.1",
|
|
59
60
|
"libsodium-wrappers": "0.8.4",
|
|
60
61
|
"undici": "^8.10.0"
|