@postman-cs/onboarding-repo-sync 2.11.2 → 3.0.1
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 +3 -3
- package/dist/action.cjs +372 -75
- package/dist/cli.cjs +372 -75
- package/dist/index.cjs +372 -75
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ jobs:
|
|
|
30
30
|
postman-region: us
|
|
31
31
|
postman-api-key: ${{ secrets.POSTMAN_API_KEY }}
|
|
32
32
|
|
|
33
|
-
- uses: postman-cs/postman-repo-sync-action@
|
|
33
|
+
- uses: postman-cs/postman-repo-sync-action@v3
|
|
34
34
|
with:
|
|
35
35
|
project-name: core-payments
|
|
36
36
|
postman-region: us
|
|
@@ -51,7 +51,7 @@ The example permissions let `GITHUB_TOKEN` commit generated artifacts and update
|
|
|
51
51
|
### Full sync with workspace assets
|
|
52
52
|
|
|
53
53
|
```yaml
|
|
54
|
-
- uses: postman-cs/postman-repo-sync-action@
|
|
54
|
+
- uses: postman-cs/postman-repo-sync-action@v3
|
|
55
55
|
with:
|
|
56
56
|
project-name: core-payments
|
|
57
57
|
workspace-id: ws-123
|
|
@@ -292,7 +292,7 @@ postman/collections/[Smoke] core-payments/
|
|
|
292
292
|
<folder>.yaml
|
|
293
293
|
<request>.yaml
|
|
294
294
|
postman/environments/
|
|
295
|
-
prod.
|
|
295
|
+
core-payments - prod.environment.yaml
|
|
296
296
|
.postman/
|
|
297
297
|
resources.yaml
|
|
298
298
|
```
|
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) {
|
|
@@ -130649,7 +130876,8 @@ function getCollectionDirectoryName(kind, projectName) {
|
|
|
130649
130876
|
var VOLATILE_KEYS = /* @__PURE__ */ new Set([
|
|
130650
130877
|
"createdAt",
|
|
130651
130878
|
"updatedAt",
|
|
130652
|
-
"lastUpdatedBy"
|
|
130879
|
+
"lastUpdatedBy",
|
|
130880
|
+
"lastRevision"
|
|
130653
130881
|
]);
|
|
130654
130882
|
function stripVolatileFields(obj) {
|
|
130655
130883
|
if (Array.isArray(obj)) {
|
|
@@ -130726,7 +130954,21 @@ function resolveDurableWorkspaceId(options) {
|
|
|
130726
130954
|
}
|
|
130727
130955
|
return prior === candidate ? prior : void 0;
|
|
130728
130956
|
}
|
|
130729
|
-
function buildResourcesManifest(
|
|
130957
|
+
function buildResourcesManifest(options) {
|
|
130958
|
+
const {
|
|
130959
|
+
workspaceId,
|
|
130960
|
+
collectionMap,
|
|
130961
|
+
envMap,
|
|
130962
|
+
artifactDir,
|
|
130963
|
+
projectName,
|
|
130964
|
+
localSpecRefs,
|
|
130965
|
+
mappedSpecRef,
|
|
130966
|
+
specId,
|
|
130967
|
+
existingSpecs,
|
|
130968
|
+
priorState,
|
|
130969
|
+
preserveGeneratedAssets = false,
|
|
130970
|
+
preservePriorEnvironmentAssets = preserveGeneratedAssets
|
|
130971
|
+
} = options;
|
|
130730
130972
|
const manifest = { ...priorState ?? {} };
|
|
130731
130973
|
delete manifest.version;
|
|
130732
130974
|
delete manifest.workspace;
|
|
@@ -130743,15 +130985,26 @@ function buildResourcesManifest(workspaceId, collectionMap, envMap, artifactDir,
|
|
|
130743
130985
|
if (collectionKeys.length > 0) {
|
|
130744
130986
|
cloudResources.collections = effectiveCollectionMap;
|
|
130745
130987
|
}
|
|
130746
|
-
const priorEnvironmentMap =
|
|
130988
|
+
const priorEnvironmentMap = preservePriorEnvironmentAssets ? { ...priorState?.cloudResources?.environments ?? {} } : {};
|
|
130747
130989
|
const envEntries = Object.entries(envMap);
|
|
130990
|
+
for (const [envName] of envEntries) {
|
|
130991
|
+
const replacedRefs = /* @__PURE__ */ new Set([
|
|
130992
|
+
canonicalizeRelativePath(environmentManifestRef(artifactDir, projectName, envName)),
|
|
130993
|
+
canonicalizeRelativePath(legacyEnvironmentManifestRef(artifactDir, envName))
|
|
130994
|
+
]);
|
|
130995
|
+
for (const filePath of Object.keys(priorEnvironmentMap)) {
|
|
130996
|
+
if (replacedRefs.has(canonicalizeRelativePath(filePath))) {
|
|
130997
|
+
delete priorEnvironmentMap[filePath];
|
|
130998
|
+
}
|
|
130999
|
+
}
|
|
131000
|
+
}
|
|
130748
131001
|
if (Object.keys(priorEnvironmentMap).length > 0 || envEntries.length > 0) {
|
|
130749
131002
|
cloudResources.environments = priorEnvironmentMap;
|
|
130750
131003
|
}
|
|
130751
131004
|
if (envEntries.length > 0) {
|
|
130752
131005
|
cloudResources.environments ??= {};
|
|
130753
131006
|
for (const [envName, envUid] of envEntries) {
|
|
130754
|
-
cloudResources.environments[
|
|
131007
|
+
cloudResources.environments[environmentManifestRef(artifactDir, projectName, envName)] = envUid;
|
|
130755
131008
|
}
|
|
130756
131009
|
}
|
|
130757
131010
|
void localSpecRefs;
|
|
@@ -131487,18 +131740,19 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131487
131740
|
}
|
|
131488
131741
|
ensureDir(".postman");
|
|
131489
131742
|
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
|
-
|
|
131743
|
+
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest({
|
|
131744
|
+
workspaceId: durableWorkspaceId,
|
|
131745
|
+
collectionMap: {},
|
|
131746
|
+
envMap: {},
|
|
131747
|
+
artifactDir: inputs.artifactDir,
|
|
131748
|
+
projectName: inputs.projectName,
|
|
131749
|
+
localSpecRefs: discoveredSpecs.map((spec) => spec.configRelativePath),
|
|
131750
|
+
mappedSpecRef: mappedSpecCloudKey,
|
|
131751
|
+
specId: inputs.specId || void 0,
|
|
131752
|
+
existingSpecs: preservePriorWorkspaceResources ? options.existingSpecs : void 0,
|
|
131753
|
+
priorState: options.priorState,
|
|
131754
|
+
preserveGeneratedAssets: preservePriorWorkspaceResources
|
|
131755
|
+
}));
|
|
131502
131756
|
dependencies.core.info(
|
|
131503
131757
|
"onboarding-scope=spec-only; updated only workspace/spec state in .postman/resources.yaml."
|
|
131504
131758
|
);
|
|
@@ -131564,15 +131818,31 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131564
131818
|
}
|
|
131565
131819
|
}
|
|
131566
131820
|
const environmentSpecs = [
|
|
131567
|
-
...Object.entries(envUids).map(([envName, envUid]) =>
|
|
131568
|
-
envName
|
|
131569
|
-
|
|
131570
|
-
|
|
131571
|
-
|
|
131821
|
+
...Object.entries(envUids).map(([envName, envUid]) => {
|
|
131822
|
+
const ownership = options.environmentOwnership[envName];
|
|
131823
|
+
if (!ownership) {
|
|
131824
|
+
throw new Error(
|
|
131825
|
+
`environment "${envName}" has a UID but no manifest ownership entry; environment sync and artifact export disagree`
|
|
131826
|
+
);
|
|
131827
|
+
}
|
|
131828
|
+
return {
|
|
131829
|
+
kind: "environment",
|
|
131830
|
+
envName,
|
|
131831
|
+
envUid,
|
|
131832
|
+
filePath: `${environmentsDir}/${environmentFileName(inputs.projectName, envName)}`,
|
|
131833
|
+
currentUid: ownership.currentUid,
|
|
131834
|
+
legacyUid: ownership.legacyUid,
|
|
131835
|
+
legacyFilePath: ownership.legacyUid === envUid ? `${environmentsDir}/${envName}.postman_environment.json` : void 0
|
|
131836
|
+
};
|
|
131837
|
+
}),
|
|
131572
131838
|
...options.mockEnvironmentUid ? [{
|
|
131839
|
+
kind: "mock",
|
|
131573
131840
|
envName: "manual-validation",
|
|
131574
131841
|
envUid: options.mockEnvironmentUid,
|
|
131575
|
-
filePath: `${mocksDir}/manual-validation.postman_environment.json
|
|
131842
|
+
filePath: `${mocksDir}/manual-validation.postman_environment.json`,
|
|
131843
|
+
currentUid: void 0,
|
|
131844
|
+
legacyUid: void 0,
|
|
131845
|
+
legacyFilePath: void 0
|
|
131576
131846
|
}] : []
|
|
131577
131847
|
];
|
|
131578
131848
|
const environmentStartedAt = Date.now();
|
|
@@ -131592,26 +131862,50 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
|
|
|
131592
131862
|
`environment-artifact-acquisition count=${environmentSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - environmentStartedAt} status=${environmentStatus}`
|
|
131593
131863
|
);
|
|
131594
131864
|
}
|
|
131865
|
+
const legacyEnvironmentCleanupPaths = [];
|
|
131595
131866
|
for (const [index, spec] of environmentSpecs.entries()) {
|
|
131596
|
-
|
|
131597
|
-
|
|
131867
|
+
if (spec.kind === "mock") {
|
|
131868
|
+
assertPathWithinCwd(spec.filePath, "environment target");
|
|
131869
|
+
writeJsonFile(spec.filePath, sanitizeMockEnvironmentArtifact(environmentPayloads[index]), true);
|
|
131870
|
+
continue;
|
|
131871
|
+
}
|
|
131872
|
+
assertEnvironmentTargetAvailable({
|
|
131873
|
+
filePath: spec.filePath,
|
|
131874
|
+
currentUid: spec.currentUid
|
|
131875
|
+
});
|
|
131876
|
+
(0, import_node_fs6.writeFileSync)(
|
|
131598
131877
|
spec.filePath,
|
|
131599
|
-
|
|
131600
|
-
true
|
|
131878
|
+
serializeEnvironmentYaml(environmentPayloads[index], `${inputs.projectName} - ${spec.envName}`)
|
|
131601
131879
|
);
|
|
131880
|
+
if (spec.legacyFilePath) {
|
|
131881
|
+
legacyEnvironmentCleanupPaths.push(spec.legacyFilePath);
|
|
131882
|
+
}
|
|
131602
131883
|
}
|
|
131603
131884
|
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
|
-
|
|
131885
|
+
(0, import_node_fs6.writeFileSync)(".postman/resources.yaml", buildResourcesManifest({
|
|
131886
|
+
workspaceId: durableWorkspaceId,
|
|
131887
|
+
collectionMap: manifestCollections,
|
|
131888
|
+
envMap: envUids,
|
|
131889
|
+
artifactDir: inputs.artifactDir,
|
|
131890
|
+
projectName: inputs.projectName,
|
|
131891
|
+
localSpecRefs: discoveredSpecs.map((spec) => spec.configRelativePath),
|
|
131892
|
+
mappedSpecRef: mappedSpecCloudKey,
|
|
131893
|
+
specId: inputs.specId || void 0,
|
|
131894
|
+
existingSpecs: options.existingSpecs,
|
|
131895
|
+
priorState: options.priorState,
|
|
131896
|
+
// The export path always rewrites collections from this run, but keeps prior
|
|
131897
|
+
// environments so an environment tracked by an earlier run is not dropped.
|
|
131898
|
+
preserveGeneratedAssets: false,
|
|
131899
|
+
preservePriorEnvironmentAssets: preservePriorWorkspaceResources
|
|
131900
|
+
}));
|
|
131901
|
+
for (const legacyFilePath of legacyEnvironmentCleanupPaths) {
|
|
131902
|
+
assertPathWithinCwd(legacyFilePath, "legacy environment target");
|
|
131903
|
+
try {
|
|
131904
|
+
(0, import_node_fs6.unlinkSync)(legacyFilePath);
|
|
131905
|
+
} catch (error2) {
|
|
131906
|
+
if (error2.code !== "ENOENT") throw error2;
|
|
131907
|
+
}
|
|
131908
|
+
}
|
|
131615
131909
|
if (mappedSpec && Object.keys(manifestCollections).length > 0) {
|
|
131616
131910
|
let existingWorkflows;
|
|
131617
131911
|
try {
|
|
@@ -131636,6 +131930,7 @@ function renderCiWorkflow(inputs, privateMockAuth) {
|
|
|
131636
131930
|
}
|
|
131637
131931
|
if (inputs.provider === "azure-devops") {
|
|
131638
131932
|
return getCiWorkflowTemplate(inputs.provider, {
|
|
131933
|
+
projectName: inputs.projectName,
|
|
131639
131934
|
postmanCliInstallUrl: inputs.postmanCliInstallUrl,
|
|
131640
131935
|
postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
|
|
131641
131936
|
runnerOs: inputs.ciRunnerOs,
|
|
@@ -131644,6 +131939,7 @@ function renderCiWorkflow(inputs, privateMockAuth) {
|
|
|
131644
131939
|
});
|
|
131645
131940
|
}
|
|
131646
131941
|
return renderCiWorkflowTemplate({
|
|
131942
|
+
projectName: inputs.projectName,
|
|
131647
131943
|
postmanCliInstallUrl: inputs.postmanCliInstallUrl,
|
|
131648
131944
|
postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
|
|
131649
131945
|
runnerOs: inputs.ciRunnerOs,
|
|
@@ -131892,10 +132188,10 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
|
|
|
131892
132188
|
}
|
|
131893
132189
|
}
|
|
131894
132190
|
const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
|
|
131895
|
-
const envUids = onboardingScope === "full" ? await logger.phase(
|
|
132191
|
+
const { envUids, ownership: environmentOwnership } = onboardingScope === "full" ? await logger.phase(
|
|
131896
132192
|
"sync-environments",
|
|
131897
132193
|
async () => upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker)
|
|
131898
|
-
) : {};
|
|
132194
|
+
) : { envUids: {}, ownership: {} };
|
|
131899
132195
|
outputs["environment-uids-json"] = JSON.stringify(envUids);
|
|
131900
132196
|
dependencies.core.setOutput("environment-uids-json", outputs["environment-uids-json"]);
|
|
131901
132197
|
if (inputs.environmentSyncEnabled && inputs.workspaceId && dependencies.internalIntegration) {
|
|
@@ -132295,6 +132591,7 @@ async function runRepoSyncInner(inputs, dependencies, executionContext) {
|
|
|
132295
132591
|
mockEnvironmentUid: outputs["mock-environment-uid"] || void 0,
|
|
132296
132592
|
releaseLabel,
|
|
132297
132593
|
priorState: resourcesState,
|
|
132594
|
+
environmentOwnership,
|
|
132298
132595
|
preparedPrebuiltCollections,
|
|
132299
132596
|
privateMockAuth: outputs["mock-auth-required"] === "true"
|
|
132300
132597
|
})
|