@postman-cs/onboarding-repo-sync 2.10.9 → 2.11.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 +10 -1
- package/action.yml +1 -1
- package/dist/action.cjs +118 -10
- package/dist/cli.cjs +118 -10
- package/dist/index.cjs +118 -10
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -69,6 +69,15 @@ The example permissions let `GITHUB_TOKEN` commit generated artifacts and update
|
|
|
69
69
|
|
|
70
70
|
`postman-access-token` is required: every asset operation (environment create/get/update, collection read, mock, monitor) plus workspace-to-repository linking and system environment association runs through the access-token gateway. Use `postman-resolve-service-token-action` to mint it at runtime from a [Postman service account](https://learning.postman.com/docs/administration/service-accounts/) PMAK. Without it the action fails fast — the PMAK is not an asset-routing fallback; it only mints/re-mints the access token, powers the generated CI workflow's `postman login --with-api-key`, and mints the CI `POSTMAN_API_KEY` secret. See [docs/credentials.md](docs/credentials.md).
|
|
71
71
|
|
|
72
|
+
To manage the complete values for an environment, use a rich entry in the same input. String entries remain backward-compatible and receive generated values; rich entries replace the environment values exactly as supplied (plus the action's branch-ownership marker when applicable).
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
environments-json: >-
|
|
76
|
+
[{"slug":"dev","values":[{"key":"baseUrl","value":"https://dev.example.com"},{"key":"jwtToken","value":"","type":"secret"}]}]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Secret-typed values must be empty. Supply the real secret as a masked runtime variable from the customer's vault when running the collection; repo-sync neither reads nor persists that value. `value`, `type`, and `enabled` default to `""`, `"default"`, and `true`. `env-runtime-urls-json` and generated credential slots apply only to string entries because a rich entry is the complete desired definition.
|
|
80
|
+
|
|
72
81
|
### Disable CI workflow generation
|
|
73
82
|
|
|
74
83
|
For existing repositories that already own their CI workflow, disable workflow generation:
|
|
@@ -178,7 +187,7 @@ with:
|
|
|
178
187
|
| `mock-visibility` | Required mock access policy. Public is anonymous; private requires a runtime x-api-key supplied by the caller and is never persisted by repo-sync. | no | `private` |
|
|
179
188
|
| `mock-environment-enabled` | Create or update a dedicated manual-validation environment whose baseUrl is the validated mock URL. This environment is excluded from runtime CI selection and never contains a mock credential. | no | `false` |
|
|
180
189
|
| `monitor-cron` | Cron expression for monitor scheduling (e.g. '0 */6 * * *'). When empty, the monitor is created disabled and triggered to run once per workflow invocation (and once on every subsequent run). | no | `""` |
|
|
181
|
-
| `environments-json` | JSON array of environment slugs to create or
|
|
190
|
+
| `environments-json` | JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots. | no | `["prod"]` |
|
|
182
191
|
| `git-provider` | Git provider override ('github', 'gitlab', 'bitbucket', 'azure-devops'). Auto-detected from environment when omitted. | no | |
|
|
183
192
|
| `ado-token` | Azure DevOps personal access token or system token used to push commits in Azure Pipelines. Defaults to SYSTEM_ACCESSTOKEN when available. | no | |
|
|
184
193
|
| `repo-url` | Explicit repository URL (GitHub, GitLab, or Azure DevOps). Defaults to the URL inferred from runner environment when omitted. For commit-and-push it must identify the checked-out origin. | no | |
|
package/action.yml
CHANGED
|
@@ -76,7 +76,7 @@ inputs:
|
|
|
76
76
|
required: false
|
|
77
77
|
default: ""
|
|
78
78
|
environments-json:
|
|
79
|
-
description: JSON array of environment slugs to create or
|
|
79
|
+
description: JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.
|
|
80
80
|
required: false
|
|
81
81
|
default: '["prod"]'
|
|
82
82
|
git-provider:
|
package/dist/action.cjs
CHANGED
|
@@ -121357,7 +121357,7 @@ var postmanRepoSyncActionContract = {
|
|
|
121357
121357
|
default: ""
|
|
121358
121358
|
},
|
|
121359
121359
|
"environments-json": {
|
|
121360
|
-
description: "JSON array of environment slugs to create or
|
|
121360
|
+
description: "JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.",
|
|
121361
121361
|
required: false,
|
|
121362
121362
|
default: '["prod"]'
|
|
121363
121363
|
},
|
|
@@ -129598,13 +129598,117 @@ function parseJsonMap(raw) {
|
|
|
129598
129598
|
])
|
|
129599
129599
|
);
|
|
129600
129600
|
}
|
|
129601
|
-
function
|
|
129602
|
-
if (!raw.trim()) return [];
|
|
129603
|
-
|
|
129601
|
+
function parseEnvironmentInputs(raw) {
|
|
129602
|
+
if (!raw.trim()) return { environments: [], definitions: /* @__PURE__ */ Object.create(null) };
|
|
129603
|
+
let parsed;
|
|
129604
|
+
try {
|
|
129605
|
+
parsed = JSON.parse(raw);
|
|
129606
|
+
} catch {
|
|
129607
|
+
throw new Error("environments-json must contain valid JSON");
|
|
129608
|
+
}
|
|
129604
129609
|
if (!Array.isArray(parsed)) {
|
|
129605
|
-
throw new Error("
|
|
129610
|
+
throw new Error("environments-json must be a JSON array");
|
|
129611
|
+
}
|
|
129612
|
+
const environments = [];
|
|
129613
|
+
const definitions = /* @__PURE__ */ Object.create(null);
|
|
129614
|
+
const seen = /* @__PURE__ */ new Map();
|
|
129615
|
+
parsed.forEach((entry, environmentIndex) => {
|
|
129616
|
+
const label = `environments-json[${environmentIndex}]`;
|
|
129617
|
+
let slug;
|
|
129618
|
+
let rich = false;
|
|
129619
|
+
if (typeof entry === "string") {
|
|
129620
|
+
slug = entry;
|
|
129621
|
+
} else {
|
|
129622
|
+
if (!isPlainObject2(entry)) {
|
|
129623
|
+
throw new Error(`${label} must be a slug string or an environment definition`);
|
|
129624
|
+
}
|
|
129625
|
+
const unknownFields = Object.keys(entry).filter((key) => key !== "slug" && key !== "values");
|
|
129626
|
+
if (unknownFields.length > 0) {
|
|
129627
|
+
throw new Error(`${label} contains unsupported field "${unknownFields[0]}"`);
|
|
129628
|
+
}
|
|
129629
|
+
if (typeof entry.slug !== "string" || !Array.isArray(entry.values)) {
|
|
129630
|
+
throw new Error(`${label} must contain a string slug and a values array`);
|
|
129631
|
+
}
|
|
129632
|
+
slug = entry.slug;
|
|
129633
|
+
rich = true;
|
|
129634
|
+
const keys = /* @__PURE__ */ new Set();
|
|
129635
|
+
definitions[slug] = entry.values.map((value, valueIndex) => {
|
|
129636
|
+
const valueLabel = `${label}.values[${valueIndex}]`;
|
|
129637
|
+
if (!isPlainObject2(value)) {
|
|
129638
|
+
throw new Error(`${valueLabel} must be an object`);
|
|
129639
|
+
}
|
|
129640
|
+
const unknownValueFields = Object.keys(value).filter(
|
|
129641
|
+
(key) => !["key", "value", "type", "enabled"].includes(key)
|
|
129642
|
+
);
|
|
129643
|
+
if (unknownValueFields.length > 0) {
|
|
129644
|
+
throw new Error(`${valueLabel} contains unsupported field "${unknownValueFields[0]}"`);
|
|
129645
|
+
}
|
|
129646
|
+
if (typeof value.key !== "string" || !value.key.trim() || value.key !== value.key.trim()) {
|
|
129647
|
+
throw new Error(`${valueLabel}.key must be a non-empty string without surrounding whitespace`);
|
|
129648
|
+
}
|
|
129649
|
+
if (value.key === "x-pm-onboarding") {
|
|
129650
|
+
throw new Error(`${valueLabel}.key is reserved by repo-sync`);
|
|
129651
|
+
}
|
|
129652
|
+
if (keys.has(value.key)) {
|
|
129653
|
+
throw new Error(`${label} contains duplicate variable key "${value.key}"`);
|
|
129654
|
+
}
|
|
129655
|
+
keys.add(value.key);
|
|
129656
|
+
if (value.value !== void 0 && typeof value.value !== "string") {
|
|
129657
|
+
throw new Error(`${valueLabel}.value must be a string when provided`);
|
|
129658
|
+
}
|
|
129659
|
+
if (value.type !== void 0 && value.type !== "default" && value.type !== "secret") {
|
|
129660
|
+
throw new Error(`${valueLabel}.type must be "default" or "secret"`);
|
|
129661
|
+
}
|
|
129662
|
+
if (value.enabled !== void 0 && typeof value.enabled !== "boolean") {
|
|
129663
|
+
throw new Error(`${valueLabel}.enabled must be a boolean when provided`);
|
|
129664
|
+
}
|
|
129665
|
+
const type = value.type ?? "default";
|
|
129666
|
+
const normalizedValue = value.value ?? "";
|
|
129667
|
+
if (type === "secret" && normalizedValue) {
|
|
129668
|
+
throw new Error(`${valueLabel} cannot contain a populated secret value; inject it at runtime`);
|
|
129669
|
+
}
|
|
129670
|
+
return { key: value.key, value: normalizedValue, type, enabled: value.enabled ?? true };
|
|
129671
|
+
});
|
|
129672
|
+
}
|
|
129673
|
+
if (rich && !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(slug)) {
|
|
129674
|
+
throw new Error(`${label} rich slug must use only letters, numbers, dots, hyphens, or underscores`);
|
|
129675
|
+
}
|
|
129676
|
+
if (rich && Object.prototype.hasOwnProperty.call(Object.prototype, slug)) {
|
|
129677
|
+
throw new Error(`${label} rich slug conflicts with a reserved object property`);
|
|
129678
|
+
}
|
|
129679
|
+
if (rich && /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(slug)) {
|
|
129680
|
+
throw new Error(`${label} rich slug conflicts with a Windows device name`);
|
|
129681
|
+
}
|
|
129682
|
+
if (!rich && !slug.trim()) {
|
|
129683
|
+
throw new Error(`${label} slug must be a non-empty string`);
|
|
129684
|
+
}
|
|
129685
|
+
const priorWasRich = seen.get(slug);
|
|
129686
|
+
if (priorWasRich !== void 0 && (rich || priorWasRich)) {
|
|
129687
|
+
throw new Error(`environments-json contains duplicate slug "${slug}"`);
|
|
129688
|
+
}
|
|
129689
|
+
if (priorWasRich === void 0) seen.set(slug, rich);
|
|
129690
|
+
environments.push(slug);
|
|
129691
|
+
});
|
|
129692
|
+
return { environments, definitions };
|
|
129693
|
+
}
|
|
129694
|
+
function normalizeProgrammaticEnvironmentDefinitions(inputs) {
|
|
129695
|
+
const definitions = inputs.environmentDefinitions;
|
|
129696
|
+
if (!definitions) return inputs;
|
|
129697
|
+
const prototype = Object.getPrototypeOf(definitions);
|
|
129698
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
129699
|
+
throw new Error("environmentDefinitions must be a plain object");
|
|
129700
|
+
}
|
|
129701
|
+
const entries = inputs.environments.map(
|
|
129702
|
+
(slug) => Object.prototype.hasOwnProperty.call(definitions, slug) ? { slug, values: definitions[slug] } : slug
|
|
129703
|
+
);
|
|
129704
|
+
let raw;
|
|
129705
|
+
try {
|
|
129706
|
+
raw = JSON.stringify(entries);
|
|
129707
|
+
} catch {
|
|
129708
|
+
throw new Error("environmentDefinitions must contain JSON-serializable values");
|
|
129606
129709
|
}
|
|
129607
|
-
|
|
129710
|
+
const parsed = parseEnvironmentInputs(raw);
|
|
129711
|
+
return { ...inputs, environments: parsed.environments, environmentDefinitions: parsed.definitions };
|
|
129608
129712
|
}
|
|
129609
129713
|
function readInput(actionCore, name, required = false) {
|
|
129610
129714
|
return actionCore.getInput(name, { required }).trim();
|
|
@@ -129701,7 +129805,7 @@ function resolveInputs(env = process.env) {
|
|
|
129701
129805
|
},
|
|
129702
129806
|
env
|
|
129703
129807
|
);
|
|
129704
|
-
const
|
|
129808
|
+
const parsedEnvironments = parseEnvironmentInputs(getInput2("environments-json", env) || '["prod"]');
|
|
129705
129809
|
const secretsResolverProvider = parseSecretsResolverProvider(getInput2("secrets-resolver", env));
|
|
129706
129810
|
const systemEnvMap = parseJsonMap(getInput2("system-env-map-json", env) || "{}");
|
|
129707
129811
|
const environmentUids = parseJsonMap(getInput2("environment-uids-json", env) || "{}");
|
|
@@ -129739,7 +129843,8 @@ function resolveInputs(env = process.env) {
|
|
|
129739
129843
|
secretsResolverProvider,
|
|
129740
129844
|
specSyncMode: normalizeSpecSyncMode(getInput2("spec-sync-mode", env) || "update"),
|
|
129741
129845
|
releaseLabel: normalizeReleaseLabel(getInput2("release-label", env)) || void 0,
|
|
129742
|
-
environments: environments.length > 0 ? environments : ["prod"],
|
|
129846
|
+
environments: parsedEnvironments.environments.length > 0 ? parsedEnvironments.environments : ["prod"],
|
|
129847
|
+
environmentDefinitions: parsedEnvironments.definitions,
|
|
129743
129848
|
repoUrl: repoContext.repoUrl || "",
|
|
129744
129849
|
integrationBackend: getInput2("integration-backend", env) || "bifrost",
|
|
129745
129850
|
workspaceLinkEnabled: parseBooleanInput(getInput2("workspace-link-enabled", env), true),
|
|
@@ -130407,7 +130512,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130407
130512
|
}
|
|
130408
130513
|
} catch {
|
|
130409
130514
|
}
|
|
130410
|
-
const
|
|
130515
|
+
const definedValues2 = inputs.environmentDefinitions?.[envName];
|
|
130516
|
+
const values2 = definedValues2 ? definedValues2.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130411
130517
|
secretsResolverProvider: inputs.secretsResolverProvider,
|
|
130412
130518
|
preservedCredentialValues: priorValues
|
|
130413
130519
|
});
|
|
@@ -130430,7 +130536,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130430
130536
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
130431
130537
|
continue;
|
|
130432
130538
|
}
|
|
130433
|
-
const
|
|
130539
|
+
const definedValues = inputs.environmentDefinitions?.[envName];
|
|
130540
|
+
const values = definedValues ? definedValues.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130434
130541
|
secretsResolverProvider: inputs.secretsResolverProvider
|
|
130435
130542
|
});
|
|
130436
130543
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
@@ -131621,6 +131728,7 @@ async function commitAndPushGeneratedFiles(inputs, dependencies, privateMockAuth
|
|
|
131621
131728
|
};
|
|
131622
131729
|
}
|
|
131623
131730
|
async function runRepoSync(inputs, dependencies, executionContext) {
|
|
131731
|
+
inputs = normalizeProgrammaticEnvironmentDefinitions(inputs);
|
|
131624
131732
|
const telemetry = createTelemetryContext({ action: "postman-repo-sync-action", actionVersion: resolveActionVersion2(), logger: dependencies.core });
|
|
131625
131733
|
telemetry.setTeamId(dependencies.teamId);
|
|
131626
131734
|
const logger = resolveRepoSyncLogger(dependencies);
|
package/dist/cli.cjs
CHANGED
|
@@ -119462,7 +119462,7 @@ var postmanRepoSyncActionContract = {
|
|
|
119462
119462
|
default: ""
|
|
119463
119463
|
},
|
|
119464
119464
|
"environments-json": {
|
|
119465
|
-
description: "JSON array of environment slugs to create or
|
|
119465
|
+
description: "JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.",
|
|
119466
119466
|
required: false,
|
|
119467
119467
|
default: '["prod"]'
|
|
119468
119468
|
},
|
|
@@ -127651,13 +127651,117 @@ function parseJsonMap(raw) {
|
|
|
127651
127651
|
])
|
|
127652
127652
|
);
|
|
127653
127653
|
}
|
|
127654
|
-
function
|
|
127655
|
-
if (!raw.trim()) return [];
|
|
127656
|
-
|
|
127654
|
+
function parseEnvironmentInputs(raw) {
|
|
127655
|
+
if (!raw.trim()) return { environments: [], definitions: /* @__PURE__ */ Object.create(null) };
|
|
127656
|
+
let parsed;
|
|
127657
|
+
try {
|
|
127658
|
+
parsed = JSON.parse(raw);
|
|
127659
|
+
} catch {
|
|
127660
|
+
throw new Error("environments-json must contain valid JSON");
|
|
127661
|
+
}
|
|
127657
127662
|
if (!Array.isArray(parsed)) {
|
|
127658
|
-
throw new Error("
|
|
127663
|
+
throw new Error("environments-json must be a JSON array");
|
|
127664
|
+
}
|
|
127665
|
+
const environments = [];
|
|
127666
|
+
const definitions = /* @__PURE__ */ Object.create(null);
|
|
127667
|
+
const seen = /* @__PURE__ */ new Map();
|
|
127668
|
+
parsed.forEach((entry, environmentIndex) => {
|
|
127669
|
+
const label = `environments-json[${environmentIndex}]`;
|
|
127670
|
+
let slug;
|
|
127671
|
+
let rich = false;
|
|
127672
|
+
if (typeof entry === "string") {
|
|
127673
|
+
slug = entry;
|
|
127674
|
+
} else {
|
|
127675
|
+
if (!isPlainObject2(entry)) {
|
|
127676
|
+
throw new Error(`${label} must be a slug string or an environment definition`);
|
|
127677
|
+
}
|
|
127678
|
+
const unknownFields = Object.keys(entry).filter((key) => key !== "slug" && key !== "values");
|
|
127679
|
+
if (unknownFields.length > 0) {
|
|
127680
|
+
throw new Error(`${label} contains unsupported field "${unknownFields[0]}"`);
|
|
127681
|
+
}
|
|
127682
|
+
if (typeof entry.slug !== "string" || !Array.isArray(entry.values)) {
|
|
127683
|
+
throw new Error(`${label} must contain a string slug and a values array`);
|
|
127684
|
+
}
|
|
127685
|
+
slug = entry.slug;
|
|
127686
|
+
rich = true;
|
|
127687
|
+
const keys = /* @__PURE__ */ new Set();
|
|
127688
|
+
definitions[slug] = entry.values.map((value, valueIndex) => {
|
|
127689
|
+
const valueLabel = `${label}.values[${valueIndex}]`;
|
|
127690
|
+
if (!isPlainObject2(value)) {
|
|
127691
|
+
throw new Error(`${valueLabel} must be an object`);
|
|
127692
|
+
}
|
|
127693
|
+
const unknownValueFields = Object.keys(value).filter(
|
|
127694
|
+
(key) => !["key", "value", "type", "enabled"].includes(key)
|
|
127695
|
+
);
|
|
127696
|
+
if (unknownValueFields.length > 0) {
|
|
127697
|
+
throw new Error(`${valueLabel} contains unsupported field "${unknownValueFields[0]}"`);
|
|
127698
|
+
}
|
|
127699
|
+
if (typeof value.key !== "string" || !value.key.trim() || value.key !== value.key.trim()) {
|
|
127700
|
+
throw new Error(`${valueLabel}.key must be a non-empty string without surrounding whitespace`);
|
|
127701
|
+
}
|
|
127702
|
+
if (value.key === "x-pm-onboarding") {
|
|
127703
|
+
throw new Error(`${valueLabel}.key is reserved by repo-sync`);
|
|
127704
|
+
}
|
|
127705
|
+
if (keys.has(value.key)) {
|
|
127706
|
+
throw new Error(`${label} contains duplicate variable key "${value.key}"`);
|
|
127707
|
+
}
|
|
127708
|
+
keys.add(value.key);
|
|
127709
|
+
if (value.value !== void 0 && typeof value.value !== "string") {
|
|
127710
|
+
throw new Error(`${valueLabel}.value must be a string when provided`);
|
|
127711
|
+
}
|
|
127712
|
+
if (value.type !== void 0 && value.type !== "default" && value.type !== "secret") {
|
|
127713
|
+
throw new Error(`${valueLabel}.type must be "default" or "secret"`);
|
|
127714
|
+
}
|
|
127715
|
+
if (value.enabled !== void 0 && typeof value.enabled !== "boolean") {
|
|
127716
|
+
throw new Error(`${valueLabel}.enabled must be a boolean when provided`);
|
|
127717
|
+
}
|
|
127718
|
+
const type = value.type ?? "default";
|
|
127719
|
+
const normalizedValue = value.value ?? "";
|
|
127720
|
+
if (type === "secret" && normalizedValue) {
|
|
127721
|
+
throw new Error(`${valueLabel} cannot contain a populated secret value; inject it at runtime`);
|
|
127722
|
+
}
|
|
127723
|
+
return { key: value.key, value: normalizedValue, type, enabled: value.enabled ?? true };
|
|
127724
|
+
});
|
|
127725
|
+
}
|
|
127726
|
+
if (rich && !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(slug)) {
|
|
127727
|
+
throw new Error(`${label} rich slug must use only letters, numbers, dots, hyphens, or underscores`);
|
|
127728
|
+
}
|
|
127729
|
+
if (rich && Object.prototype.hasOwnProperty.call(Object.prototype, slug)) {
|
|
127730
|
+
throw new Error(`${label} rich slug conflicts with a reserved object property`);
|
|
127731
|
+
}
|
|
127732
|
+
if (rich && /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(slug)) {
|
|
127733
|
+
throw new Error(`${label} rich slug conflicts with a Windows device name`);
|
|
127734
|
+
}
|
|
127735
|
+
if (!rich && !slug.trim()) {
|
|
127736
|
+
throw new Error(`${label} slug must be a non-empty string`);
|
|
127737
|
+
}
|
|
127738
|
+
const priorWasRich = seen.get(slug);
|
|
127739
|
+
if (priorWasRich !== void 0 && (rich || priorWasRich)) {
|
|
127740
|
+
throw new Error(`environments-json contains duplicate slug "${slug}"`);
|
|
127741
|
+
}
|
|
127742
|
+
if (priorWasRich === void 0) seen.set(slug, rich);
|
|
127743
|
+
environments.push(slug);
|
|
127744
|
+
});
|
|
127745
|
+
return { environments, definitions };
|
|
127746
|
+
}
|
|
127747
|
+
function normalizeProgrammaticEnvironmentDefinitions(inputs) {
|
|
127748
|
+
const definitions = inputs.environmentDefinitions;
|
|
127749
|
+
if (!definitions) return inputs;
|
|
127750
|
+
const prototype = Object.getPrototypeOf(definitions);
|
|
127751
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
127752
|
+
throw new Error("environmentDefinitions must be a plain object");
|
|
127753
|
+
}
|
|
127754
|
+
const entries = inputs.environments.map(
|
|
127755
|
+
(slug) => Object.prototype.hasOwnProperty.call(definitions, slug) ? { slug, values: definitions[slug] } : slug
|
|
127756
|
+
);
|
|
127757
|
+
let raw;
|
|
127758
|
+
try {
|
|
127759
|
+
raw = JSON.stringify(entries);
|
|
127760
|
+
} catch {
|
|
127761
|
+
throw new Error("environmentDefinitions must contain JSON-serializable values");
|
|
127659
127762
|
}
|
|
127660
|
-
|
|
127763
|
+
const parsed = parseEnvironmentInputs(raw);
|
|
127764
|
+
return { ...inputs, environments: parsed.environments, environmentDefinitions: parsed.definitions };
|
|
127661
127765
|
}
|
|
127662
127766
|
function normalizeRepoWriteMode(value) {
|
|
127663
127767
|
if (value === "none" || value === "commit-only" || value === "commit-and-push") {
|
|
@@ -127751,7 +127855,7 @@ function resolveInputs(env = process.env) {
|
|
|
127751
127855
|
},
|
|
127752
127856
|
env
|
|
127753
127857
|
);
|
|
127754
|
-
const
|
|
127858
|
+
const parsedEnvironments = parseEnvironmentInputs(getInput("environments-json", env) || '["prod"]');
|
|
127755
127859
|
const secretsResolverProvider = parseSecretsResolverProvider(getInput("secrets-resolver", env));
|
|
127756
127860
|
const systemEnvMap = parseJsonMap(getInput("system-env-map-json", env) || "{}");
|
|
127757
127861
|
const environmentUids = parseJsonMap(getInput("environment-uids-json", env) || "{}");
|
|
@@ -127789,7 +127893,8 @@ function resolveInputs(env = process.env) {
|
|
|
127789
127893
|
secretsResolverProvider,
|
|
127790
127894
|
specSyncMode: normalizeSpecSyncMode(getInput("spec-sync-mode", env) || "update"),
|
|
127791
127895
|
releaseLabel: normalizeReleaseLabel(getInput("release-label", env)) || void 0,
|
|
127792
|
-
environments: environments.length > 0 ? environments : ["prod"],
|
|
127896
|
+
environments: parsedEnvironments.environments.length > 0 ? parsedEnvironments.environments : ["prod"],
|
|
127897
|
+
environmentDefinitions: parsedEnvironments.definitions,
|
|
127793
127898
|
repoUrl: repoContext.repoUrl || "",
|
|
127794
127899
|
integrationBackend: getInput("integration-backend", env) || "bifrost",
|
|
127795
127900
|
workspaceLinkEnabled: parseBooleanInput(getInput("workspace-link-enabled", env), true),
|
|
@@ -128316,7 +128421,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
128316
128421
|
}
|
|
128317
128422
|
} catch {
|
|
128318
128423
|
}
|
|
128319
|
-
const
|
|
128424
|
+
const definedValues2 = inputs.environmentDefinitions?.[envName];
|
|
128425
|
+
const values2 = definedValues2 ? definedValues2.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
128320
128426
|
secretsResolverProvider: inputs.secretsResolverProvider,
|
|
128321
128427
|
preservedCredentialValues: priorValues
|
|
128322
128428
|
});
|
|
@@ -128339,7 +128445,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
128339
128445
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
128340
128446
|
continue;
|
|
128341
128447
|
}
|
|
128342
|
-
const
|
|
128448
|
+
const definedValues = inputs.environmentDefinitions?.[envName];
|
|
128449
|
+
const values = definedValues ? definedValues.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
128343
128450
|
secretsResolverProvider: inputs.secretsResolverProvider
|
|
128344
128451
|
});
|
|
128345
128452
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
@@ -129530,6 +129637,7 @@ async function commitAndPushGeneratedFiles(inputs, dependencies, privateMockAuth
|
|
|
129530
129637
|
};
|
|
129531
129638
|
}
|
|
129532
129639
|
async function runRepoSync(inputs, dependencies, executionContext) {
|
|
129640
|
+
inputs = normalizeProgrammaticEnvironmentDefinitions(inputs);
|
|
129533
129641
|
const telemetry = createTelemetryContext({ action: "postman-repo-sync-action", actionVersion: resolveActionVersion2(), logger: dependencies.core });
|
|
129534
129642
|
telemetry.setTeamId(dependencies.teamId);
|
|
129535
129643
|
const logger = resolveRepoSyncLogger(dependencies);
|
package/dist/index.cjs
CHANGED
|
@@ -121383,7 +121383,7 @@ var postmanRepoSyncActionContract = {
|
|
|
121383
121383
|
default: ""
|
|
121384
121384
|
},
|
|
121385
121385
|
"environments-json": {
|
|
121386
|
-
description: "JSON array of environment slugs to create or
|
|
121386
|
+
description: "JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.",
|
|
121387
121387
|
required: false,
|
|
121388
121388
|
default: '["prod"]'
|
|
121389
121389
|
},
|
|
@@ -129624,13 +129624,117 @@ function parseJsonMap(raw) {
|
|
|
129624
129624
|
])
|
|
129625
129625
|
);
|
|
129626
129626
|
}
|
|
129627
|
-
function
|
|
129628
|
-
if (!raw.trim()) return [];
|
|
129629
|
-
|
|
129627
|
+
function parseEnvironmentInputs(raw) {
|
|
129628
|
+
if (!raw.trim()) return { environments: [], definitions: /* @__PURE__ */ Object.create(null) };
|
|
129629
|
+
let parsed;
|
|
129630
|
+
try {
|
|
129631
|
+
parsed = JSON.parse(raw);
|
|
129632
|
+
} catch {
|
|
129633
|
+
throw new Error("environments-json must contain valid JSON");
|
|
129634
|
+
}
|
|
129630
129635
|
if (!Array.isArray(parsed)) {
|
|
129631
|
-
throw new Error("
|
|
129636
|
+
throw new Error("environments-json must be a JSON array");
|
|
129637
|
+
}
|
|
129638
|
+
const environments = [];
|
|
129639
|
+
const definitions = /* @__PURE__ */ Object.create(null);
|
|
129640
|
+
const seen = /* @__PURE__ */ new Map();
|
|
129641
|
+
parsed.forEach((entry, environmentIndex) => {
|
|
129642
|
+
const label = `environments-json[${environmentIndex}]`;
|
|
129643
|
+
let slug;
|
|
129644
|
+
let rich = false;
|
|
129645
|
+
if (typeof entry === "string") {
|
|
129646
|
+
slug = entry;
|
|
129647
|
+
} else {
|
|
129648
|
+
if (!isPlainObject2(entry)) {
|
|
129649
|
+
throw new Error(`${label} must be a slug string or an environment definition`);
|
|
129650
|
+
}
|
|
129651
|
+
const unknownFields = Object.keys(entry).filter((key) => key !== "slug" && key !== "values");
|
|
129652
|
+
if (unknownFields.length > 0) {
|
|
129653
|
+
throw new Error(`${label} contains unsupported field "${unknownFields[0]}"`);
|
|
129654
|
+
}
|
|
129655
|
+
if (typeof entry.slug !== "string" || !Array.isArray(entry.values)) {
|
|
129656
|
+
throw new Error(`${label} must contain a string slug and a values array`);
|
|
129657
|
+
}
|
|
129658
|
+
slug = entry.slug;
|
|
129659
|
+
rich = true;
|
|
129660
|
+
const keys = /* @__PURE__ */ new Set();
|
|
129661
|
+
definitions[slug] = entry.values.map((value, valueIndex) => {
|
|
129662
|
+
const valueLabel = `${label}.values[${valueIndex}]`;
|
|
129663
|
+
if (!isPlainObject2(value)) {
|
|
129664
|
+
throw new Error(`${valueLabel} must be an object`);
|
|
129665
|
+
}
|
|
129666
|
+
const unknownValueFields = Object.keys(value).filter(
|
|
129667
|
+
(key) => !["key", "value", "type", "enabled"].includes(key)
|
|
129668
|
+
);
|
|
129669
|
+
if (unknownValueFields.length > 0) {
|
|
129670
|
+
throw new Error(`${valueLabel} contains unsupported field "${unknownValueFields[0]}"`);
|
|
129671
|
+
}
|
|
129672
|
+
if (typeof value.key !== "string" || !value.key.trim() || value.key !== value.key.trim()) {
|
|
129673
|
+
throw new Error(`${valueLabel}.key must be a non-empty string without surrounding whitespace`);
|
|
129674
|
+
}
|
|
129675
|
+
if (value.key === "x-pm-onboarding") {
|
|
129676
|
+
throw new Error(`${valueLabel}.key is reserved by repo-sync`);
|
|
129677
|
+
}
|
|
129678
|
+
if (keys.has(value.key)) {
|
|
129679
|
+
throw new Error(`${label} contains duplicate variable key "${value.key}"`);
|
|
129680
|
+
}
|
|
129681
|
+
keys.add(value.key);
|
|
129682
|
+
if (value.value !== void 0 && typeof value.value !== "string") {
|
|
129683
|
+
throw new Error(`${valueLabel}.value must be a string when provided`);
|
|
129684
|
+
}
|
|
129685
|
+
if (value.type !== void 0 && value.type !== "default" && value.type !== "secret") {
|
|
129686
|
+
throw new Error(`${valueLabel}.type must be "default" or "secret"`);
|
|
129687
|
+
}
|
|
129688
|
+
if (value.enabled !== void 0 && typeof value.enabled !== "boolean") {
|
|
129689
|
+
throw new Error(`${valueLabel}.enabled must be a boolean when provided`);
|
|
129690
|
+
}
|
|
129691
|
+
const type = value.type ?? "default";
|
|
129692
|
+
const normalizedValue = value.value ?? "";
|
|
129693
|
+
if (type === "secret" && normalizedValue) {
|
|
129694
|
+
throw new Error(`${valueLabel} cannot contain a populated secret value; inject it at runtime`);
|
|
129695
|
+
}
|
|
129696
|
+
return { key: value.key, value: normalizedValue, type, enabled: value.enabled ?? true };
|
|
129697
|
+
});
|
|
129698
|
+
}
|
|
129699
|
+
if (rich && !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(slug)) {
|
|
129700
|
+
throw new Error(`${label} rich slug must use only letters, numbers, dots, hyphens, or underscores`);
|
|
129701
|
+
}
|
|
129702
|
+
if (rich && Object.prototype.hasOwnProperty.call(Object.prototype, slug)) {
|
|
129703
|
+
throw new Error(`${label} rich slug conflicts with a reserved object property`);
|
|
129704
|
+
}
|
|
129705
|
+
if (rich && /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(slug)) {
|
|
129706
|
+
throw new Error(`${label} rich slug conflicts with a Windows device name`);
|
|
129707
|
+
}
|
|
129708
|
+
if (!rich && !slug.trim()) {
|
|
129709
|
+
throw new Error(`${label} slug must be a non-empty string`);
|
|
129710
|
+
}
|
|
129711
|
+
const priorWasRich = seen.get(slug);
|
|
129712
|
+
if (priorWasRich !== void 0 && (rich || priorWasRich)) {
|
|
129713
|
+
throw new Error(`environments-json contains duplicate slug "${slug}"`);
|
|
129714
|
+
}
|
|
129715
|
+
if (priorWasRich === void 0) seen.set(slug, rich);
|
|
129716
|
+
environments.push(slug);
|
|
129717
|
+
});
|
|
129718
|
+
return { environments, definitions };
|
|
129719
|
+
}
|
|
129720
|
+
function normalizeProgrammaticEnvironmentDefinitions(inputs) {
|
|
129721
|
+
const definitions = inputs.environmentDefinitions;
|
|
129722
|
+
if (!definitions) return inputs;
|
|
129723
|
+
const prototype = Object.getPrototypeOf(definitions);
|
|
129724
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
129725
|
+
throw new Error("environmentDefinitions must be a plain object");
|
|
129726
|
+
}
|
|
129727
|
+
const entries = inputs.environments.map(
|
|
129728
|
+
(slug) => Object.prototype.hasOwnProperty.call(definitions, slug) ? { slug, values: definitions[slug] } : slug
|
|
129729
|
+
);
|
|
129730
|
+
let raw;
|
|
129731
|
+
try {
|
|
129732
|
+
raw = JSON.stringify(entries);
|
|
129733
|
+
} catch {
|
|
129734
|
+
throw new Error("environmentDefinitions must contain JSON-serializable values");
|
|
129632
129735
|
}
|
|
129633
|
-
|
|
129736
|
+
const parsed = parseEnvironmentInputs(raw);
|
|
129737
|
+
return { ...inputs, environments: parsed.environments, environmentDefinitions: parsed.definitions };
|
|
129634
129738
|
}
|
|
129635
129739
|
function readInput(actionCore, name, required = false) {
|
|
129636
129740
|
return actionCore.getInput(name, { required }).trim();
|
|
@@ -129727,7 +129831,7 @@ function resolveInputs(env = process.env) {
|
|
|
129727
129831
|
},
|
|
129728
129832
|
env
|
|
129729
129833
|
);
|
|
129730
|
-
const
|
|
129834
|
+
const parsedEnvironments = parseEnvironmentInputs(getInput2("environments-json", env) || '["prod"]');
|
|
129731
129835
|
const secretsResolverProvider = parseSecretsResolverProvider(getInput2("secrets-resolver", env));
|
|
129732
129836
|
const systemEnvMap = parseJsonMap(getInput2("system-env-map-json", env) || "{}");
|
|
129733
129837
|
const environmentUids = parseJsonMap(getInput2("environment-uids-json", env) || "{}");
|
|
@@ -129765,7 +129869,8 @@ function resolveInputs(env = process.env) {
|
|
|
129765
129869
|
secretsResolverProvider,
|
|
129766
129870
|
specSyncMode: normalizeSpecSyncMode(getInput2("spec-sync-mode", env) || "update"),
|
|
129767
129871
|
releaseLabel: normalizeReleaseLabel(getInput2("release-label", env)) || void 0,
|
|
129768
|
-
environments: environments.length > 0 ? environments : ["prod"],
|
|
129872
|
+
environments: parsedEnvironments.environments.length > 0 ? parsedEnvironments.environments : ["prod"],
|
|
129873
|
+
environmentDefinitions: parsedEnvironments.definitions,
|
|
129769
129874
|
repoUrl: repoContext.repoUrl || "",
|
|
129770
129875
|
integrationBackend: getInput2("integration-backend", env) || "bifrost",
|
|
129771
129876
|
workspaceLinkEnabled: parseBooleanInput(getInput2("workspace-link-enabled", env), true),
|
|
@@ -130433,7 +130538,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130433
130538
|
}
|
|
130434
130539
|
} catch {
|
|
130435
130540
|
}
|
|
130436
|
-
const
|
|
130541
|
+
const definedValues2 = inputs.environmentDefinitions?.[envName];
|
|
130542
|
+
const values2 = definedValues2 ? definedValues2.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130437
130543
|
secretsResolverProvider: inputs.secretsResolverProvider,
|
|
130438
130544
|
preservedCredentialValues: priorValues
|
|
130439
130545
|
});
|
|
@@ -130456,7 +130562,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130456
130562
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
130457
130563
|
continue;
|
|
130458
130564
|
}
|
|
130459
|
-
const
|
|
130565
|
+
const definedValues = inputs.environmentDefinitions?.[envName];
|
|
130566
|
+
const values = definedValues ? definedValues.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130460
130567
|
secretsResolverProvider: inputs.secretsResolverProvider
|
|
130461
130568
|
});
|
|
130462
130569
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
@@ -131647,6 +131754,7 @@ async function commitAndPushGeneratedFiles(inputs, dependencies, privateMockAuth
|
|
|
131647
131754
|
};
|
|
131648
131755
|
}
|
|
131649
131756
|
async function runRepoSync(inputs, dependencies, executionContext) {
|
|
131757
|
+
inputs = normalizeProgrammaticEnvironmentDefinitions(inputs);
|
|
131650
131758
|
const telemetry = createTelemetryContext({ action: "postman-repo-sync-action", actionVersion: resolveActionVersion2(), logger: dependencies.core });
|
|
131651
131759
|
telemetry.setTeamId(dependencies.teamId);
|
|
131652
131760
|
const logger = resolveRepoSyncLogger(dependencies);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postman-cs/onboarding-repo-sync",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Postman repo sync GitHub Action.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"verify:dist:assert": "npm run verify:dist:shape && npm run verify:dist:parity",
|
|
26
26
|
"verify:dist": "npm run build && npm run verify:dist:assert",
|
|
27
27
|
"docs:tables": "node scripts/render-action-tables.mjs",
|
|
28
|
+
"docs:pins": "node scripts/check-doc-pins.mjs",
|
|
28
29
|
"lint": "eslint .",
|
|
29
30
|
"lint:fix": "eslint . --fix",
|
|
30
31
|
"test": "vitest run --exclude tests/ci-workflow-template.test.ts && vitest run tests/ci-workflow-template.test.ts && node --test .github/scripts/dispatch-e2e-monitor.test.mjs .github/scripts/prefetch-vendored-deps.test.mjs .github/scripts/verify-e2e-release.test.mjs",
|