@postman-cse/onboarding-bootstrap 0.9.1 → 0.10.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/.github/workflows/contract-smoke.yml +155 -0
- package/.omc/sessions/b36ac16d-ce26-4e94-ae7e-dd817f2430a3.json +8 -0
- package/CLAUDE.md +57 -0
- package/README.md +124 -12
- package/action.yml +17 -18
- package/dist/cli.cjs +231 -489
- package/dist/index.cjs +226 -480
- package/package.json +3 -2
- package/src/cli.ts +5 -11
- package/src/contracts.ts +24 -24
- package/src/index.ts +253 -323
- package/src/lib/postman/postman-assets-client.ts +27 -4
- package/tests/bootstrap-action.test.ts +565 -79
- package/tests/cli.test.ts +12 -6
- package/tests/contract.test.ts +20 -3
- package/tests/postman-assets-client.test.ts +153 -0
package/tests/cli.test.ts
CHANGED
|
@@ -14,6 +14,12 @@ describe('parseCliArgs', () => {
|
|
|
14
14
|
'pmak-test',
|
|
15
15
|
'--workspace-admin-user-ids',
|
|
16
16
|
'101,102',
|
|
17
|
+
'--collection-sync-mode',
|
|
18
|
+
'version',
|
|
19
|
+
'--spec-sync-mode',
|
|
20
|
+
'version',
|
|
21
|
+
'--release-label',
|
|
22
|
+
'v1.2.3',
|
|
17
23
|
'--team-id',
|
|
18
24
|
'12345',
|
|
19
25
|
'--repo-url',
|
|
@@ -30,6 +36,9 @@ describe('parseCliArgs', () => {
|
|
|
30
36
|
expect(config.inputEnv.INPUT_SPEC_URL).toBe('https://example.test/openapi.yaml');
|
|
31
37
|
expect(config.inputEnv.INPUT_POSTMAN_API_KEY).toBe('pmak-test');
|
|
32
38
|
expect(config.inputEnv.INPUT_WORKSPACE_ADMIN_USER_IDS).toBe('101,102');
|
|
39
|
+
expect(config.inputEnv.INPUT_COLLECTION_SYNC_MODE).toBe('version');
|
|
40
|
+
expect(config.inputEnv.INPUT_SPEC_SYNC_MODE).toBe('version');
|
|
41
|
+
expect(config.inputEnv.INPUT_RELEASE_LABEL).toBe('v1.2.3');
|
|
33
42
|
expect(config.inputEnv.INPUT_TEAM_ID).toBe('12345');
|
|
34
43
|
expect(config.inputEnv.INPUT_REPO_URL).toBe('https://github.com/postman-cs/postman-bootstrap-action');
|
|
35
44
|
expect(config.resultJsonPath).toBe('tmp/result.json');
|
|
@@ -49,7 +58,7 @@ describe('toDotenv', () => {
|
|
|
49
58
|
'contract-collection-id': 'col-contract',
|
|
50
59
|
'collections-json': '{"baseline":"col-baseline"}',
|
|
51
60
|
'lint-summary-json': '{"errors":0}'
|
|
52
|
-
});
|
|
61
|
+
} as any);
|
|
53
62
|
|
|
54
63
|
expect(dotenv).toContain('POSTMAN_BOOTSTRAP_WORKSPACE_ID="ws-123"');
|
|
55
64
|
expect(dotenv).toContain('POSTMAN_BOOTSTRAP_SPEC_ID="spec-123"');
|
|
@@ -104,7 +113,7 @@ describe('runCli', () => {
|
|
|
104
113
|
'contract-collection-id': 'col-contract',
|
|
105
114
|
'collections-json': '{"baseline":"col-baseline","smoke":"col-smoke","contract":"col-contract"}',
|
|
106
115
|
'lint-summary-json': '{"errors":0,"total":0,"violations":[],"warnings":0}'
|
|
107
|
-
};
|
|
116
|
+
} as any;
|
|
108
117
|
},
|
|
109
118
|
writeStdout: (chunk) => {
|
|
110
119
|
stdoutChunks.push(chunk);
|
|
@@ -124,21 +133,18 @@ describe('runCli', () => {
|
|
|
124
133
|
});
|
|
125
134
|
|
|
126
135
|
describe('createCliDependencies', () => {
|
|
127
|
-
it('creates
|
|
136
|
+
it('creates internal integration dependencies under token conditions', () => {
|
|
128
137
|
const inputs = resolveInputs({
|
|
129
138
|
INPUT_PROJECT_NAME: 'core-payments',
|
|
130
139
|
INPUT_SPEC_URL: 'https://example.test/openapi.yaml',
|
|
131
140
|
INPUT_POSTMAN_API_KEY: 'pmak-test',
|
|
132
141
|
INPUT_POSTMAN_ACCESS_TOKEN: 'pat-test',
|
|
133
|
-
INPUT_GITHUB_TOKEN: 'gh-token',
|
|
134
|
-
INPUT_GH_FALLBACK_TOKEN: 'gh-fallback',
|
|
135
142
|
INPUT_REPO_URL: 'https://github.com/postman-cs/postman-bootstrap-action',
|
|
136
143
|
INPUT_TEAM_ID: '12345'
|
|
137
144
|
});
|
|
138
145
|
|
|
139
146
|
const dependencies = createCliDependencies(inputs);
|
|
140
147
|
|
|
141
|
-
expect(dependencies.github).toBeDefined();
|
|
142
148
|
expect(dependencies.internalIntegration).toBeDefined();
|
|
143
149
|
});
|
|
144
150
|
});
|
package/tests/contract.test.ts
CHANGED
|
@@ -41,6 +41,26 @@ describe('open-alpha action contract', () => {
|
|
|
41
41
|
expect(resolveInputs({}).integrationBackend).toBe('bifrost');
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
+
it('defaults lifecycle controls in contract, manifest, and runtime', () => {
|
|
45
|
+
expect(openAlphaActionContract.inputs['collection-sync-mode'].default).toBe('refresh');
|
|
46
|
+
expect(openAlphaActionContract.inputs['collection-sync-mode'].allowedValues).toEqual([
|
|
47
|
+
'reuse',
|
|
48
|
+
'refresh',
|
|
49
|
+
'version'
|
|
50
|
+
]);
|
|
51
|
+
expect(actionManifest.inputs['collection-sync-mode'].default).toBe('refresh');
|
|
52
|
+
expect(resolveInputs({}).collectionSyncMode).toBe('refresh');
|
|
53
|
+
|
|
54
|
+
expect(openAlphaActionContract.inputs['spec-sync-mode'].default).toBe('update');
|
|
55
|
+
expect(openAlphaActionContract.inputs['spec-sync-mode'].allowedValues).toEqual([
|
|
56
|
+
'update',
|
|
57
|
+
'version'
|
|
58
|
+
]);
|
|
59
|
+
expect(actionManifest.inputs['spec-sync-mode'].default).toBe('update');
|
|
60
|
+
expect(resolveInputs({}).specSyncMode).toBe('update');
|
|
61
|
+
|
|
62
|
+
});
|
|
63
|
+
|
|
44
64
|
it('rejects unsupported integration backends during input resolution', () => {
|
|
45
65
|
expect(() =>
|
|
46
66
|
resolveInputs({
|
|
@@ -63,9 +83,6 @@ describe('open-alpha action contract', () => {
|
|
|
63
83
|
expect(openAlphaActionContract.retainedBehavior).toContain(
|
|
64
84
|
'governance group assignment'
|
|
65
85
|
);
|
|
66
|
-
expect(openAlphaActionContract.retainedBehavior).toContain(
|
|
67
|
-
'GitHub repository variable persistence for downstream sync steps'
|
|
68
|
-
);
|
|
69
86
|
expect(openAlphaActionContract.removedBehavior).toContain('step mode');
|
|
70
87
|
expect(openAlphaActionContract.removedBehavior).toContain(
|
|
71
88
|
'aws, docker, and infra workflow concerns'
|
|
@@ -112,4 +112,157 @@ describe('PostmanAssetsClient', () => {
|
|
|
112
112
|
|
|
113
113
|
await expect(client.getSpecContent('spec-123')).resolves.toBeUndefined();
|
|
114
114
|
});
|
|
115
|
+
|
|
116
|
+
it('creates a workspace with targetTeamId in the payload for org-mode', async () => {
|
|
117
|
+
const fetchImpl = vi
|
|
118
|
+
.fn<typeof fetch>()
|
|
119
|
+
.mockResolvedValueOnce(
|
|
120
|
+
jsonResponse({
|
|
121
|
+
workspace: {
|
|
122
|
+
id: 'ws-org-123'
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
)
|
|
126
|
+
.mockResolvedValueOnce(
|
|
127
|
+
jsonResponse({
|
|
128
|
+
workspace: {
|
|
129
|
+
id: 'ws-org-123',
|
|
130
|
+
visibility: 'team'
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const client = new PostmanAssetsClient({
|
|
136
|
+
apiKey: 'pmak-test',
|
|
137
|
+
fetchImpl
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
await expect(client.createWorkspace('Org WS', 'desc', 132319)).resolves.toEqual({
|
|
141
|
+
id: 'ws-org-123'
|
|
142
|
+
});
|
|
143
|
+
expect(fetchImpl).toHaveBeenCalledTimes(2);
|
|
144
|
+
expect(fetchImpl).toHaveBeenNthCalledWith(
|
|
145
|
+
1,
|
|
146
|
+
'https://api.getpostman.com/workspaces',
|
|
147
|
+
expect.objectContaining({
|
|
148
|
+
method: 'POST',
|
|
149
|
+
body: JSON.stringify({
|
|
150
|
+
workspace: {
|
|
151
|
+
about: 'desc',
|
|
152
|
+
name: 'Org WS',
|
|
153
|
+
type: 'team',
|
|
154
|
+
teamId: 132319
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('creates a workspace without teamId when targetTeamId is not provided', async () => {
|
|
162
|
+
const fetchImpl = vi
|
|
163
|
+
.fn<typeof fetch>()
|
|
164
|
+
.mockResolvedValueOnce(
|
|
165
|
+
jsonResponse({
|
|
166
|
+
workspace: { id: 'ws-no-team' }
|
|
167
|
+
})
|
|
168
|
+
)
|
|
169
|
+
.mockResolvedValueOnce(
|
|
170
|
+
jsonResponse({
|
|
171
|
+
workspace: { id: 'ws-no-team', visibility: 'team' }
|
|
172
|
+
})
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const client = new PostmanAssetsClient({
|
|
176
|
+
apiKey: 'pmak-test',
|
|
177
|
+
fetchImpl
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
await expect(client.createWorkspace('Regular WS', 'desc')).resolves.toEqual({
|
|
181
|
+
id: 'ws-no-team'
|
|
182
|
+
});
|
|
183
|
+
expect(fetchImpl).toHaveBeenNthCalledWith(
|
|
184
|
+
1,
|
|
185
|
+
'https://api.getpostman.com/workspaces',
|
|
186
|
+
expect.objectContaining({
|
|
187
|
+
body: JSON.stringify({
|
|
188
|
+
workspace: {
|
|
189
|
+
about: 'desc',
|
|
190
|
+
name: 'Regular WS',
|
|
191
|
+
type: 'team'
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('throws actionable error for org-mode workspace creation failure', async () => {
|
|
199
|
+
const errorBody = JSON.stringify({
|
|
200
|
+
error: {
|
|
201
|
+
name: 'invalidParamError',
|
|
202
|
+
message: 'Only personal workspaces (internal) can be created outside team'
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
const fetchImpl = vi.fn<typeof fetch>().mockImplementation(
|
|
206
|
+
async () => new Response(errorBody, { status: 400 })
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const client = new PostmanAssetsClient({
|
|
210
|
+
apiKey: 'pmak-test',
|
|
211
|
+
fetchImpl
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
await expect(client.createWorkspace('Org WS', 'desc')).rejects.toThrow(
|
|
215
|
+
'workspace-team-id'
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('returns parsed sub-teams from getTeams', async () => {
|
|
220
|
+
const fetchImpl = vi.fn<typeof fetch>().mockResolvedValueOnce(
|
|
221
|
+
jsonResponse({
|
|
222
|
+
data: [
|
|
223
|
+
{ id: 132109, name: 'Field Services', handle: 'fs', organizationId: 13347347 },
|
|
224
|
+
{ id: 132118, name: 'Customer Education', handle: 'ce', organizationId: 13347347 },
|
|
225
|
+
{ id: 132272, name: 'RonCorp', handle: 'rc', organizationId: 13347347 }
|
|
226
|
+
]
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
const client = new PostmanAssetsClient({
|
|
231
|
+
apiKey: 'pmak-test',
|
|
232
|
+
fetchImpl
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const teams = await client.getTeams();
|
|
236
|
+
expect(teams).toEqual([
|
|
237
|
+
{ id: 132109, name: 'Field Services', handle: 'fs', organizationId: 13347347 },
|
|
238
|
+
{ id: 132118, name: 'Customer Education', handle: 'ce', organizationId: 13347347 },
|
|
239
|
+
{ id: 132272, name: 'RonCorp', handle: 'rc', organizationId: 13347347 }
|
|
240
|
+
]);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('returns empty array from getTeams when no teams exist', async () => {
|
|
244
|
+
const fetchImpl = vi.fn<typeof fetch>().mockResolvedValueOnce(
|
|
245
|
+
jsonResponse({ data: [] })
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
const client = new PostmanAssetsClient({
|
|
249
|
+
apiKey: 'pmak-test',
|
|
250
|
+
fetchImpl
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
await expect(client.getTeams()).resolves.toEqual([]);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('propagates errors from getTeams without swallowing', async () => {
|
|
257
|
+
const fetchImpl = vi.fn<typeof fetch>().mockResolvedValueOnce(
|
|
258
|
+
new Response('Forbidden', { status: 403 })
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
const client = new PostmanAssetsClient({
|
|
262
|
+
apiKey: 'pmak-test',
|
|
263
|
+
fetchImpl
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
await expect(client.getTeams()).rejects.toThrow();
|
|
267
|
+
});
|
|
115
268
|
});
|