@postman-cse/onboarding-bootstrap 0.9.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/.github/actionlint.yaml +2 -0
- package/.github/workflows/ci.yml +36 -0
- package/.github/workflows/release.yml +62 -0
- package/README.md +261 -0
- package/action.yml +91 -0
- package/dist/cli.cjs +31207 -0
- package/dist/index.cjs +30998 -0
- package/package.json +43 -0
- package/src/cli.ts +286 -0
- package/src/contracts.ts +166 -0
- package/src/index.ts +1170 -0
- package/src/lib/github/github-api-client.ts +262 -0
- package/src/lib/http-error.ts +80 -0
- package/src/lib/postman/internal-integration-adapter.ts +272 -0
- package/src/lib/postman/postman-assets-client.ts +763 -0
- package/src/lib/postman/workspace-selection.ts +121 -0
- package/src/lib/repo/context.ts +119 -0
- package/src/lib/retry.ts +79 -0
- package/src/lib/secrets.ts +104 -0
- package/tests/bootstrap-action.test.ts +731 -0
- package/tests/cli.test.ts +144 -0
- package/tests/contract.test.ts +106 -0
- package/tests/github-api-client.test.ts +91 -0
- package/tests/internal-integration-adapter.test.ts +244 -0
- package/tests/postman-assets-client.test.ts +115 -0
- package/tests/retry.test.ts +54 -0
- package/tests/secrets.test.ts +66 -0
- package/tests/workspace-selection.test.ts +301 -0
- package/tmp/cli-run-result.json +11 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +8 -0
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@postman-cse/onboarding-bootstrap",
|
|
3
|
+
"version": "0.9.1",
|
|
4
|
+
"description": "Public open-alpha Postman bootstrap GitHub Action.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"postman-bootstrap": "dist/cli.cjs"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "npm run typecheck && rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/index.cjs && esbuild src/cli.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/cli.cjs",
|
|
12
|
+
"check:dist": "npm run build && git diff --exit-code -- dist",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"github-action",
|
|
18
|
+
"postman"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@actions/core": "^1.11.1",
|
|
26
|
+
"@actions/exec": "^1.1.1",
|
|
27
|
+
"@actions/io": "^1.1.3"
|
|
28
|
+
},
|
|
29
|
+
"overrides": {
|
|
30
|
+
"undici": "^6.24.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"esbuild": "^0.27.3",
|
|
34
|
+
"@types/node": "^25.3.5",
|
|
35
|
+
"typescript": "^5.9.3",
|
|
36
|
+
"vitest": "^4.0.18",
|
|
37
|
+
"yaml": "^2.8.2"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/postman-cs/postman-bootstrap-action"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
|
|
6
|
+
import * as io from '@actions/io';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
createBootstrapDependencies,
|
|
10
|
+
resolveInputs,
|
|
11
|
+
type ResolvedInputs,
|
|
12
|
+
runBootstrap,
|
|
13
|
+
type BootstrapExecutionDependencies,
|
|
14
|
+
type ExecLike,
|
|
15
|
+
type PlannedOutputs
|
|
16
|
+
} from './index.js';
|
|
17
|
+
import { createSecretMasker } from './lib/secrets.js';
|
|
18
|
+
|
|
19
|
+
interface CliConfig {
|
|
20
|
+
inputEnv: NodeJS.ProcessEnv;
|
|
21
|
+
resultJsonPath: string;
|
|
22
|
+
dotenvPath?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface CliRuntime {
|
|
26
|
+
env?: NodeJS.ProcessEnv;
|
|
27
|
+
executeBootstrap?: typeof runBootstrap;
|
|
28
|
+
writeStdout?: (chunk: string) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type ReporterCore = BootstrapExecutionDependencies['core'];
|
|
32
|
+
|
|
33
|
+
export class ConsoleReporter implements ReporterCore {
|
|
34
|
+
public error(message: string): void {
|
|
35
|
+
console.error(message);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async group<T>(name: string, fn: () => Promise<T>): Promise<T> {
|
|
39
|
+
console.error(`[group] ${name}`);
|
|
40
|
+
return await fn();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public info(message: string): void {
|
|
44
|
+
console.error(message);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public setOutput(_name: string, _value: string): void {
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public warning(message: string): void {
|
|
51
|
+
console.error(`warning: ${message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function readFlag(argv: string[], name: string): string | undefined {
|
|
56
|
+
const prefix = `--${name}=`;
|
|
57
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
58
|
+
const arg = argv[index];
|
|
59
|
+
if (arg === `--${name}`) {
|
|
60
|
+
return argv[index + 1];
|
|
61
|
+
}
|
|
62
|
+
if (arg?.startsWith(prefix)) {
|
|
63
|
+
return arg.slice(prefix.length);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeCliFlag(name: string): string {
|
|
70
|
+
return `INPUT_${name.replace(/-/g, '_').toUpperCase()}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const execFileAsync = promisify(execFile);
|
|
74
|
+
|
|
75
|
+
function toCommandLabel(commandLine: string, args: string[], secretMasker: (value: string) => string): string {
|
|
76
|
+
const rendered = [commandLine, ...args].join(' ');
|
|
77
|
+
return secretMasker(rendered);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createCliExec(secretMasker: (value: string) => string): ExecLike {
|
|
81
|
+
const execCommand = async (
|
|
82
|
+
commandLine: string,
|
|
83
|
+
args: string[] = [],
|
|
84
|
+
options?: Parameters<ExecLike['exec']>[2]
|
|
85
|
+
): Promise<number> => {
|
|
86
|
+
const output = await getExecOutput(commandLine, args, {
|
|
87
|
+
...options,
|
|
88
|
+
ignoreReturnCode: true
|
|
89
|
+
});
|
|
90
|
+
if (output.exitCode !== 0 && !options?.ignoreReturnCode) {
|
|
91
|
+
throw new Error(`Command failed with exit code ${output.exitCode}: ${toCommandLabel(commandLine, args, secretMasker)}`);
|
|
92
|
+
}
|
|
93
|
+
return output.exitCode;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const getExecOutput = async (
|
|
97
|
+
commandLine: string,
|
|
98
|
+
args: string[] = [],
|
|
99
|
+
options?: Parameters<ExecLike['getExecOutput']>[2]
|
|
100
|
+
): Promise<{ exitCode: number; stdout: string; stderr: string }> => {
|
|
101
|
+
const cwd = options?.cwd;
|
|
102
|
+
const env = options?.env ? { ...process.env, ...options.env } : process.env;
|
|
103
|
+
const commandLabel = toCommandLabel(commandLine, args, secretMasker);
|
|
104
|
+
process.stderr.write(`[command] ${commandLabel}\n`);
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const result = await execFileAsync(commandLine, args, {
|
|
108
|
+
cwd,
|
|
109
|
+
env,
|
|
110
|
+
encoding: 'utf8',
|
|
111
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
112
|
+
windowsHide: true
|
|
113
|
+
});
|
|
114
|
+
const stdout = String(result.stdout ?? '');
|
|
115
|
+
const stderr = String(result.stderr ?? '');
|
|
116
|
+
if (stdout) {
|
|
117
|
+
process.stderr.write(secretMasker(stdout));
|
|
118
|
+
}
|
|
119
|
+
if (stderr) {
|
|
120
|
+
process.stderr.write(secretMasker(stderr));
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
exitCode: 0,
|
|
124
|
+
stdout,
|
|
125
|
+
stderr
|
|
126
|
+
};
|
|
127
|
+
} catch (error) {
|
|
128
|
+
const execError = error as {
|
|
129
|
+
code?: number | string;
|
|
130
|
+
stdout?: string | Buffer;
|
|
131
|
+
stderr?: string | Buffer;
|
|
132
|
+
message?: string;
|
|
133
|
+
};
|
|
134
|
+
const stdout = String(execError.stdout ?? '');
|
|
135
|
+
const stderr = String(execError.stderr ?? '');
|
|
136
|
+
const fallbackMessage = execError.message ? `${execError.message}\n` : '';
|
|
137
|
+
if (stdout) {
|
|
138
|
+
process.stderr.write(secretMasker(stdout));
|
|
139
|
+
}
|
|
140
|
+
if (stderr) {
|
|
141
|
+
process.stderr.write(secretMasker(stderr));
|
|
142
|
+
} else if (fallbackMessage) {
|
|
143
|
+
process.stderr.write(secretMasker(fallbackMessage));
|
|
144
|
+
}
|
|
145
|
+
const numericCode =
|
|
146
|
+
typeof execError.code === 'number'
|
|
147
|
+
? execError.code
|
|
148
|
+
: Number.parseInt(String(execError.code ?? '1'), 10) || 1;
|
|
149
|
+
if (!options?.ignoreReturnCode) {
|
|
150
|
+
throw new Error(`Command failed with exit code ${numericCode}: ${commandLabel}`);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
exitCode: numericCode,
|
|
154
|
+
stdout,
|
|
155
|
+
stderr
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
exec: execCommand,
|
|
162
|
+
getExecOutput
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function createCliDependencies(
|
|
167
|
+
inputs: ResolvedInputs
|
|
168
|
+
): BootstrapExecutionDependencies {
|
|
169
|
+
const secretMasker = createSecretMasker([
|
|
170
|
+
inputs.postmanApiKey,
|
|
171
|
+
inputs.postmanAccessToken,
|
|
172
|
+
inputs.githubToken,
|
|
173
|
+
inputs.ghFallbackToken
|
|
174
|
+
]);
|
|
175
|
+
const cliExec = createCliExec(secretMasker);
|
|
176
|
+
|
|
177
|
+
return createBootstrapDependencies(inputs, {
|
|
178
|
+
core: new ConsoleReporter(),
|
|
179
|
+
exec: cliExec,
|
|
180
|
+
io,
|
|
181
|
+
specFetcher: fetch
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function parseCliArgs(argv: string[], env: NodeJS.ProcessEnv = process.env): CliConfig {
|
|
186
|
+
const inputNames = [
|
|
187
|
+
'project-name',
|
|
188
|
+
'spec-url',
|
|
189
|
+
'postman-api-key',
|
|
190
|
+
'postman-access-token',
|
|
191
|
+
'workspace-id',
|
|
192
|
+
'spec-id',
|
|
193
|
+
'baseline-collection-id',
|
|
194
|
+
'smoke-collection-id',
|
|
195
|
+
'contract-collection-id',
|
|
196
|
+
'domain',
|
|
197
|
+
'domain-code',
|
|
198
|
+
'requester-email',
|
|
199
|
+
'workspace-admin-user-ids',
|
|
200
|
+
'environments-json',
|
|
201
|
+
'system-env-map-json',
|
|
202
|
+
'governance-mapping-json',
|
|
203
|
+
'integration-backend',
|
|
204
|
+
'github-auth-mode',
|
|
205
|
+
'github-token',
|
|
206
|
+
'gh-fallback-token',
|
|
207
|
+
'team-id',
|
|
208
|
+
'repo-url'
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
const inputEnv: NodeJS.ProcessEnv = { ...env };
|
|
212
|
+
for (const name of inputNames) {
|
|
213
|
+
const value = readFlag(argv, name);
|
|
214
|
+
if (value !== undefined) {
|
|
215
|
+
inputEnv[normalizeCliFlag(name)] = value;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
inputEnv,
|
|
221
|
+
resultJsonPath: readFlag(argv, 'result-json') ?? 'postman-bootstrap-result.json',
|
|
222
|
+
dotenvPath: readFlag(argv, 'dotenv-path')
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function toDotenv(outputs: PlannedOutputs): string {
|
|
227
|
+
return Object.entries(outputs)
|
|
228
|
+
.map(([key, value]) => [
|
|
229
|
+
`POSTMAN_BOOTSTRAP_${key.replace(/-/g, '_').toUpperCase()}`,
|
|
230
|
+
value
|
|
231
|
+
] as const)
|
|
232
|
+
.map(([key, value]) => `${key}=${JSON.stringify(value)}`)
|
|
233
|
+
.join('\n');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function writeOptionalFile(filePath: string | undefined, content: string): Promise<void> {
|
|
237
|
+
if (!filePath) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const workspaceRoot = path.resolve(process.cwd());
|
|
241
|
+
const resolved = path.resolve(workspaceRoot, filePath);
|
|
242
|
+
const relative = path.relative(workspaceRoot, resolved);
|
|
243
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
244
|
+
throw new Error(`Output path must stay within workspace: ${filePath}`);
|
|
245
|
+
}
|
|
246
|
+
await mkdir(path.dirname(resolved), { recursive: true });
|
|
247
|
+
await writeFile(resolved, content, 'utf8');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export async function runCli(
|
|
251
|
+
argv: string[] = process.argv.slice(2),
|
|
252
|
+
runtime: CliRuntime = {}
|
|
253
|
+
): Promise<void> {
|
|
254
|
+
const env = runtime.env ?? process.env;
|
|
255
|
+
const config = parseCliArgs(argv, env);
|
|
256
|
+
const inputs = resolveInputs(config.inputEnv);
|
|
257
|
+
const dependencies = createCliDependencies(inputs);
|
|
258
|
+
|
|
259
|
+
if (!dependencies.github) {
|
|
260
|
+
dependencies.core.info('GitHub repository variable persistence disabled for this run');
|
|
261
|
+
}
|
|
262
|
+
if (inputs.domain && !dependencies.internalIntegration) {
|
|
263
|
+
dependencies.core.warning(
|
|
264
|
+
'Skipping governance assignment because postman-access-token is not configured'
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const result = await (runtime.executeBootstrap ?? runBootstrap)(inputs, dependencies);
|
|
269
|
+
|
|
270
|
+
await writeOptionalFile(config.resultJsonPath, JSON.stringify(result, null, 2));
|
|
271
|
+
await writeOptionalFile(config.dotenvPath, toDotenv(result));
|
|
272
|
+
|
|
273
|
+
const writeStdout = runtime.writeStdout ?? ((chunk: string) => process.stdout.write(chunk));
|
|
274
|
+
writeStdout(`${JSON.stringify(result, null, 2)}\n`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const currentModulePath = typeof __filename === 'string' ? __filename : '';
|
|
278
|
+
const entrypoint = process.argv[1];
|
|
279
|
+
|
|
280
|
+
if (entrypoint && currentModulePath === entrypoint) {
|
|
281
|
+
runCli().catch((error) => {
|
|
282
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
283
|
+
process.stderr.write(`${message}\n`);
|
|
284
|
+
process.exitCode = 1;
|
|
285
|
+
});
|
|
286
|
+
}
|
package/src/contracts.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
export interface ActionInputContract {
|
|
2
|
+
description: string;
|
|
3
|
+
required: boolean;
|
|
4
|
+
default?: string;
|
|
5
|
+
allowedValues?: string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ActionOutputContract {
|
|
9
|
+
description: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface BetaActionContract {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
inputs: Record<string, ActionInputContract>;
|
|
16
|
+
outputs: Record<string, ActionOutputContract>;
|
|
17
|
+
retainedBehavior: string[];
|
|
18
|
+
removedBehavior: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const openAlphaActionContract: BetaActionContract = {
|
|
22
|
+
name: 'postman-bootstrap-action',
|
|
23
|
+
description: 'Public open-alpha contract for bootstrapping Postman assets from a registry-backed spec.',
|
|
24
|
+
inputs: {
|
|
25
|
+
|
|
26
|
+
'workspace-id': {
|
|
27
|
+
description: 'Existing Postman workspace ID.',
|
|
28
|
+
required: false
|
|
29
|
+
},
|
|
30
|
+
'spec-id': {
|
|
31
|
+
description: 'Existing Postman spec ID.',
|
|
32
|
+
required: false
|
|
33
|
+
},
|
|
34
|
+
'baseline-collection-id': {
|
|
35
|
+
description: 'Existing baseline collection ID.',
|
|
36
|
+
required: false
|
|
37
|
+
},
|
|
38
|
+
'smoke-collection-id': {
|
|
39
|
+
description: 'Existing smoke collection ID.',
|
|
40
|
+
required: false
|
|
41
|
+
},
|
|
42
|
+
'contract-collection-id': {
|
|
43
|
+
description: 'Existing contract collection ID.',
|
|
44
|
+
required: false
|
|
45
|
+
},
|
|
46
|
+
'project-name': {
|
|
47
|
+
description: 'Service project name.',
|
|
48
|
+
required: true
|
|
49
|
+
},
|
|
50
|
+
domain: {
|
|
51
|
+
description: 'Business domain for the service.',
|
|
52
|
+
required: false
|
|
53
|
+
},
|
|
54
|
+
'domain-code': {
|
|
55
|
+
description: 'Short domain code used in workspace naming.',
|
|
56
|
+
required: false
|
|
57
|
+
},
|
|
58
|
+
'requester-email': {
|
|
59
|
+
description: 'Requester email for audit context.',
|
|
60
|
+
required: false
|
|
61
|
+
},
|
|
62
|
+
'workspace-admin-user-ids': {
|
|
63
|
+
description: 'Comma-separated workspace admin user ids.',
|
|
64
|
+
required: false
|
|
65
|
+
},
|
|
66
|
+
'spec-url': {
|
|
67
|
+
description: 'HTTPS URL to the OpenAPI document.',
|
|
68
|
+
required: true
|
|
69
|
+
},
|
|
70
|
+
'environments-json': {
|
|
71
|
+
description: 'JSON array of environment slugs to preserve in bootstrap outputs.',
|
|
72
|
+
required: false,
|
|
73
|
+
default: '["prod"]'
|
|
74
|
+
},
|
|
75
|
+
'system-env-map-json': {
|
|
76
|
+
description: 'JSON map of environment slug to system environment id.',
|
|
77
|
+
required: false,
|
|
78
|
+
default: '{}'
|
|
79
|
+
},
|
|
80
|
+
'governance-mapping-json': {
|
|
81
|
+
description: 'JSON map of business domain to governance group name.',
|
|
82
|
+
required: false,
|
|
83
|
+
default: '{}'
|
|
84
|
+
},
|
|
85
|
+
'postman-api-key': {
|
|
86
|
+
description: 'Postman API key used for bootstrap operations.',
|
|
87
|
+
required: true
|
|
88
|
+
},
|
|
89
|
+
'postman-access-token': {
|
|
90
|
+
description: 'Postman access token used for governance and workspace mutations.',
|
|
91
|
+
required: false
|
|
92
|
+
},
|
|
93
|
+
'github-token': {
|
|
94
|
+
description: 'GitHub token for repository variable persistence.',
|
|
95
|
+
required: false
|
|
96
|
+
},
|
|
97
|
+
'gh-fallback-token': {
|
|
98
|
+
description: 'Fallback token for repository variable APIs.',
|
|
99
|
+
required: false
|
|
100
|
+
},
|
|
101
|
+
'github-auth-mode': {
|
|
102
|
+
description: 'GitHub auth mode for repository variable APIs.',
|
|
103
|
+
required: false,
|
|
104
|
+
default: 'github_token_first'
|
|
105
|
+
},
|
|
106
|
+
'integration-backend': {
|
|
107
|
+
description: 'Integration backend for downstream workspace connectivity.',
|
|
108
|
+
required: false,
|
|
109
|
+
default: 'bifrost',
|
|
110
|
+
allowedValues: ['bifrost']
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
outputs: {
|
|
114
|
+
'workspace-id': {
|
|
115
|
+
description: 'Postman workspace ID.'
|
|
116
|
+
},
|
|
117
|
+
'workspace-url': {
|
|
118
|
+
description: 'Postman workspace URL.'
|
|
119
|
+
},
|
|
120
|
+
'workspace-name': {
|
|
121
|
+
description: 'Postman workspace name.'
|
|
122
|
+
},
|
|
123
|
+
'spec-id': {
|
|
124
|
+
description: 'Uploaded Postman spec ID.'
|
|
125
|
+
},
|
|
126
|
+
'baseline-collection-id': {
|
|
127
|
+
description: 'Baseline collection ID.'
|
|
128
|
+
},
|
|
129
|
+
'smoke-collection-id': {
|
|
130
|
+
description: 'Smoke collection ID.'
|
|
131
|
+
},
|
|
132
|
+
'contract-collection-id': {
|
|
133
|
+
description: 'Contract collection ID.'
|
|
134
|
+
},
|
|
135
|
+
'collections-json': {
|
|
136
|
+
description: 'JSON summary of generated collections.'
|
|
137
|
+
},
|
|
138
|
+
'lint-summary-json': {
|
|
139
|
+
description: 'JSON summary of lint errors and warnings.'
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
retainedBehavior: [
|
|
143
|
+
'workspace creation',
|
|
144
|
+
'governance group assignment',
|
|
145
|
+
'requester workspace invitation',
|
|
146
|
+
'workspace admin assignment',
|
|
147
|
+
'spec upload to Spec Hub',
|
|
148
|
+
'OpenAPI operation summary normalization before upload (missing or oversized summaries)',
|
|
149
|
+
'spec linting by UID',
|
|
150
|
+
'baseline, smoke, and contract collection generation',
|
|
151
|
+
'collection tagging',
|
|
152
|
+
'GitHub repository variable persistence for downstream sync steps',
|
|
153
|
+
'workspace, spec, and collection outputs'
|
|
154
|
+
],
|
|
155
|
+
removedBehavior: [
|
|
156
|
+
'snake_case input and output names',
|
|
157
|
+
'step mode',
|
|
158
|
+
'hardcoded runtime deployment assumptions',
|
|
159
|
+
'aws, docker, and infra workflow concerns',
|
|
160
|
+
'runtime-coupled workflow tuning knobs',
|
|
161
|
+
'legacy placeholder inputs such as team-id'
|
|
162
|
+
]
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export const contractInputNames = Object.keys(openAlphaActionContract.inputs);
|
|
166
|
+
export const contractOutputNames = Object.keys(openAlphaActionContract.outputs);
|