@postman-cse/onboarding-bootstrap 0.9.1 → 0.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/.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 +133 -12
- package/action.yml +21 -18
- package/dist/cli.cjs +370 -518
- package/dist/index.cjs +364 -509
- package/package.json +3 -2
- package/src/cli.ts +6 -11
- package/src/contracts.ts +30 -24
- package/src/index.ts +302 -322
- package/src/lib/postman/internal-integration-adapter.ts +116 -30
- package/src/lib/postman/postman-assets-client.ts +27 -4
- package/tests/bootstrap-action.test.ts +647 -77
- package/tests/cli.test.ts +15 -6
- package/tests/contract.test.ts +28 -3
- package/tests/internal-integration-adapter.test.ts +69 -0
- package/tests/postman-assets-client.test.ts +153 -0
package/src/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as core from '@actions/core';
|
|
2
2
|
import * as exec from '@actions/exec';
|
|
3
3
|
import * as io from '@actions/io';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
4
5
|
import { parse, stringify } from 'yaml';
|
|
5
6
|
|
|
6
7
|
import { openAlphaActionContract } from './contracts.js';
|
|
7
|
-
import { GitHubApiClient, type GitHubApiClientAuthMode } from './lib/github/github-api-client.js';
|
|
8
8
|
import { createInternalIntegrationAdapter, type InternalIntegrationAdapter } from './lib/postman/internal-integration-adapter.js';
|
|
9
9
|
import { PostmanAssetsClient } from './lib/postman/postman-assets-client.js';
|
|
10
10
|
import { resolveCanonicalWorkspaceSelection } from './lib/postman/workspace-selection.js';
|
|
@@ -19,22 +19,26 @@ export interface ResolvedInputs {
|
|
|
19
19
|
baselineCollectionId?: string;
|
|
20
20
|
smokeCollectionId?: string;
|
|
21
21
|
contractCollectionId?: string;
|
|
22
|
+
syncExamples: boolean;
|
|
23
|
+
collectionSyncMode: 'reuse' | 'refresh' | 'version';
|
|
24
|
+
specSyncMode: 'update' | 'version';
|
|
25
|
+
releaseLabel?: string;
|
|
22
26
|
domain?: string;
|
|
23
27
|
domainCode?: string;
|
|
24
28
|
requesterEmail?: string;
|
|
25
29
|
workspaceAdminUserIds?: string;
|
|
30
|
+
workspaceTeamId?: string;
|
|
26
31
|
teamId?: string;
|
|
27
32
|
repoUrl?: string;
|
|
28
33
|
specUrl: string;
|
|
29
|
-
environmentsJson: string;
|
|
30
|
-
systemEnvMapJson: string;
|
|
31
34
|
governanceMappingJson: string;
|
|
32
35
|
postmanApiKey: string;
|
|
33
36
|
postmanAccessToken?: string;
|
|
34
|
-
githubToken?: string;
|
|
35
|
-
ghFallbackToken?: string;
|
|
36
|
-
githubAuthMode: string;
|
|
37
37
|
integrationBackend: string;
|
|
38
|
+
githubRefName?: string;
|
|
39
|
+
githubHeadRef?: string;
|
|
40
|
+
githubRef?: string;
|
|
41
|
+
githubSha?: string;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export interface PlannedOutputs {
|
|
@@ -61,13 +65,6 @@ export interface LintSummary {
|
|
|
61
65
|
warnings: number;
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
interface BootstrapRepositoryVariables {
|
|
65
|
-
lintErrors: number;
|
|
66
|
-
lintWarnings: number;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
type RepoVariableClient = Pick<GitHubApiClient, 'setRepositoryVariable' | 'getRepositoryVariable'>;
|
|
70
|
-
|
|
71
68
|
export interface CoreLike {
|
|
72
69
|
error(message: string): void;
|
|
73
70
|
getInput(name: string, options?: { required?: boolean }): string;
|
|
@@ -102,11 +99,10 @@ export interface BootstrapExecutionDependencies {
|
|
|
102
99
|
'error' | 'group' | 'info' | 'setOutput' | 'warning'
|
|
103
100
|
>;
|
|
104
101
|
exec: ExecLike;
|
|
105
|
-
github?: RepoVariableClient;
|
|
106
102
|
io: IOLike;
|
|
107
103
|
internalIntegration?: Pick<
|
|
108
104
|
InternalIntegrationAdapter,
|
|
109
|
-
'assignWorkspaceToGovernanceGroup'
|
|
105
|
+
'assignWorkspaceToGovernanceGroup' | 'linkCollectionsToSpecification' | 'syncCollection'
|
|
110
106
|
>;
|
|
111
107
|
postman: Pick<
|
|
112
108
|
PostmanAssetsClient,
|
|
@@ -116,6 +112,7 @@ export interface BootstrapExecutionDependencies {
|
|
|
116
112
|
| 'generateCollection'
|
|
117
113
|
| 'getAutoDerivedTeamId'
|
|
118
114
|
| 'getSpecContent'
|
|
115
|
+
| 'getTeams'
|
|
119
116
|
| 'getWorkspaceGitRepoUrl'
|
|
120
117
|
| 'injectTests'
|
|
121
118
|
| 'inviteRequesterToWorkspace'
|
|
@@ -185,16 +182,28 @@ function asStringArray(value: unknown, inputName: string): string[] {
|
|
|
185
182
|
return value.map((entry) => String(entry));
|
|
186
183
|
}
|
|
187
184
|
|
|
188
|
-
function
|
|
189
|
-
|
|
190
|
-
|
|
185
|
+
function parseBooleanInput(value: string | undefined, defaultValue: boolean): boolean {
|
|
186
|
+
const normalized = String(value || '').trim().toLowerCase();
|
|
187
|
+
if (!normalized) return defaultValue;
|
|
188
|
+
if (['true', '1', 'yes', 'on'].includes(normalized)) return true;
|
|
189
|
+
if (['false', '0', 'no', 'off'].includes(normalized)) return false;
|
|
190
|
+
return defaultValue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function parseCollectionSyncMode(
|
|
194
|
+
value: string | undefined
|
|
195
|
+
): 'reuse' | 'refresh' | 'version' {
|
|
196
|
+
if (value === 'reuse' || value === 'version') {
|
|
197
|
+
return value;
|
|
191
198
|
}
|
|
192
|
-
return
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
199
|
+
return 'refresh';
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function parseSpecSyncMode(value: string | undefined): 'update' | 'version' {
|
|
203
|
+
if (value === 'version') {
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
return 'update';
|
|
198
207
|
}
|
|
199
208
|
|
|
200
209
|
export function resolveInputs(
|
|
@@ -233,41 +242,39 @@ export function resolveInputs(
|
|
|
233
242
|
}
|
|
234
243
|
|
|
235
244
|
return {
|
|
236
|
-
projectName: getInput('project-name', env)
|
|
245
|
+
projectName: getInput('project-name', env)
|
|
246
|
+
?? env.GITHUB_REPOSITORY?.split('/').pop()
|
|
247
|
+
?? env.CI_PROJECT_NAME
|
|
248
|
+
?? '',
|
|
237
249
|
workspaceId: getInput('workspace-id', env),
|
|
238
250
|
specId: getInput('spec-id', env),
|
|
239
251
|
baselineCollectionId: getInput('baseline-collection-id', env),
|
|
240
252
|
smokeCollectionId: getInput('smoke-collection-id', env),
|
|
241
253
|
contractCollectionId: getInput('contract-collection-id', env),
|
|
254
|
+
syncExamples: parseBooleanInput(getInput('sync-examples', env), true),
|
|
255
|
+
collectionSyncMode: parseCollectionSyncMode(getInput('collection-sync-mode', env)),
|
|
256
|
+
specSyncMode: parseSpecSyncMode(getInput('spec-sync-mode', env)),
|
|
257
|
+
releaseLabel: getInput('release-label', env),
|
|
242
258
|
domain: getInput('domain', env),
|
|
243
259
|
domainCode: getInput('domain-code', env),
|
|
244
260
|
requesterEmail: getInput('requester-email', env),
|
|
245
261
|
workspaceAdminUserIds:
|
|
246
262
|
getInput('workspace-admin-user-ids', env) || env.WORKSPACE_ADMIN_USER_IDS || '',
|
|
263
|
+
workspaceTeamId: getInput('workspace-team-id', env) || env.POSTMAN_WORKSPACE_TEAM_ID,
|
|
247
264
|
teamId: getInput('team-id', env) || env.POSTMAN_TEAM_ID || '',
|
|
248
265
|
repoUrl: repoContext.repoUrl || '',
|
|
249
266
|
specUrl,
|
|
250
|
-
environmentsJson:
|
|
251
|
-
getInput('environments-json', env) ??
|
|
252
|
-
openAlphaActionContract.inputs['environments-json'].default ??
|
|
253
|
-
'["prod"]',
|
|
254
|
-
systemEnvMapJson:
|
|
255
|
-
getInput('system-env-map-json', env) ??
|
|
256
|
-
openAlphaActionContract.inputs['system-env-map-json'].default ??
|
|
257
|
-
'{}',
|
|
258
267
|
governanceMappingJson:
|
|
259
268
|
getInput('governance-mapping-json', env) ??
|
|
260
269
|
openAlphaActionContract.inputs['governance-mapping-json'].default ??
|
|
261
270
|
'{}',
|
|
262
271
|
postmanApiKey: getInput('postman-api-key', env) ?? '',
|
|
263
272
|
postmanAccessToken: getInput('postman-access-token', env),
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
'github_token_first',
|
|
270
|
-
integrationBackend
|
|
273
|
+
integrationBackend,
|
|
274
|
+
githubRefName: env.GITHUB_REF_NAME,
|
|
275
|
+
githubHeadRef: env.GITHUB_HEAD_REF,
|
|
276
|
+
githubRef: env.GITHUB_REF,
|
|
277
|
+
githubSha: env.GITHUB_SHA
|
|
271
278
|
};
|
|
272
279
|
}
|
|
273
280
|
|
|
@@ -305,13 +312,9 @@ export function readActionInputs(
|
|
|
305
312
|
const specUrl = requireInput(actionCore, 'spec-url');
|
|
306
313
|
const postmanApiKey = requireInput(actionCore, 'postman-api-key');
|
|
307
314
|
const postmanAccessToken = optionalInput(actionCore, 'postman-access-token');
|
|
308
|
-
const githubToken = optionalInput(actionCore, 'github-token');
|
|
309
|
-
const ghFallbackToken = optionalInput(actionCore, 'gh-fallback-token');
|
|
310
315
|
|
|
311
316
|
actionCore.setSecret(postmanApiKey);
|
|
312
317
|
if (postmanAccessToken) actionCore.setSecret(postmanAccessToken);
|
|
313
|
-
if (githubToken) actionCore.setSecret(githubToken);
|
|
314
|
-
if (ghFallbackToken) actionCore.setSecret(ghFallbackToken);
|
|
315
318
|
|
|
316
319
|
const inputs = resolveInputs({
|
|
317
320
|
...process.env,
|
|
@@ -321,6 +324,16 @@ export function readActionInputs(
|
|
|
321
324
|
INPUT_BASELINE_COLLECTION_ID: optionalInput(actionCore, 'baseline-collection-id'),
|
|
322
325
|
INPUT_SMOKE_COLLECTION_ID: optionalInput(actionCore, 'smoke-collection-id'),
|
|
323
326
|
INPUT_CONTRACT_COLLECTION_ID: optionalInput(actionCore, 'contract-collection-id'),
|
|
327
|
+
INPUT_SYNC_EXAMPLES:
|
|
328
|
+
optionalInput(actionCore, 'sync-examples') ??
|
|
329
|
+
openAlphaActionContract.inputs['sync-examples'].default,
|
|
330
|
+
INPUT_COLLECTION_SYNC_MODE:
|
|
331
|
+
optionalInput(actionCore, 'collection-sync-mode') ??
|
|
332
|
+
openAlphaActionContract.inputs['collection-sync-mode'].default,
|
|
333
|
+
INPUT_SPEC_SYNC_MODE:
|
|
334
|
+
optionalInput(actionCore, 'spec-sync-mode') ??
|
|
335
|
+
openAlphaActionContract.inputs['spec-sync-mode'].default,
|
|
336
|
+
INPUT_RELEASE_LABEL: optionalInput(actionCore, 'release-label'),
|
|
324
337
|
INPUT_DOMAIN: optionalInput(actionCore, 'domain'),
|
|
325
338
|
INPUT_DOMAIN_CODE: optionalInput(actionCore, 'domain-code'),
|
|
326
339
|
INPUT_REQUESTER_EMAIL: optionalInput(actionCore, 'requester-email'),
|
|
@@ -328,26 +341,17 @@ export function readActionInputs(
|
|
|
328
341
|
actionCore,
|
|
329
342
|
'workspace-admin-user-ids'
|
|
330
343
|
),
|
|
344
|
+
INPUT_WORKSPACE_TEAM_ID:
|
|
345
|
+
optionalInput(actionCore, 'workspace-team-id') || process.env.POSTMAN_WORKSPACE_TEAM_ID,
|
|
331
346
|
INPUT_TEAM_ID:
|
|
332
347
|
optionalInput(actionCore, 'postman-team-id') || process.env.POSTMAN_TEAM_ID,
|
|
333
348
|
INPUT_REPO_URL: optionalInput(actionCore, 'repo-url'),
|
|
334
349
|
INPUT_SPEC_URL: specUrl,
|
|
335
|
-
INPUT_ENVIRONMENTS_JSON:
|
|
336
|
-
optionalInput(actionCore, 'environments-json') ??
|
|
337
|
-
openAlphaActionContract.inputs['environments-json'].default,
|
|
338
|
-
INPUT_SYSTEM_ENV_MAP_JSON:
|
|
339
|
-
optionalInput(actionCore, 'system-env-map-json') ??
|
|
340
|
-
openAlphaActionContract.inputs['system-env-map-json'].default,
|
|
341
350
|
INPUT_GOVERNANCE_MAPPING_JSON:
|
|
342
351
|
optionalInput(actionCore, 'governance-mapping-json') ??
|
|
343
352
|
openAlphaActionContract.inputs['governance-mapping-json'].default,
|
|
344
353
|
INPUT_POSTMAN_API_KEY: postmanApiKey,
|
|
345
354
|
INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
|
|
346
|
-
INPUT_GITHUB_TOKEN: githubToken,
|
|
347
|
-
INPUT_GH_FALLBACK_TOKEN: ghFallbackToken,
|
|
348
|
-
INPUT_GITHUB_AUTH_MODE:
|
|
349
|
-
optionalInput(actionCore, 'github-auth-mode') ??
|
|
350
|
-
openAlphaActionContract.inputs['github-auth-mode'].default,
|
|
351
355
|
INPUT_INTEGRATION_BACKEND:
|
|
352
356
|
optionalInput(actionCore, 'integration-backend') ??
|
|
353
357
|
openAlphaActionContract.inputs['integration-backend'].default
|
|
@@ -456,6 +460,83 @@ async function fetchSpecDocument(
|
|
|
456
460
|
);
|
|
457
461
|
}
|
|
458
462
|
|
|
463
|
+
function normalizeReleaseLabel(value: string | undefined): string | undefined {
|
|
464
|
+
const trimmed = String(value || '').trim();
|
|
465
|
+
if (!trimmed) {
|
|
466
|
+
return undefined;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return trimmed
|
|
470
|
+
.replace(/^refs\/heads\//, '')
|
|
471
|
+
.replace(/^refs\/tags\//, '')
|
|
472
|
+
.replace(/^refs\/pull\//, 'pull-')
|
|
473
|
+
.replace(/[^a-zA-Z0-9._-]+/g, '-')
|
|
474
|
+
.replace(/^-+|-+$/g, '') || undefined;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function deriveReleaseLabel(inputs: ResolvedInputs): string | undefined {
|
|
478
|
+
if (inputs.releaseLabel) {
|
|
479
|
+
return normalizeReleaseLabel(inputs.releaseLabel);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return (
|
|
483
|
+
normalizeReleaseLabel(inputs.githubRefName) ??
|
|
484
|
+
normalizeReleaseLabel(inputs.githubHeadRef) ??
|
|
485
|
+
normalizeReleaseLabel(inputs.githubRef)
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function createAssetProjectName(
|
|
490
|
+
inputs: ResolvedInputs,
|
|
491
|
+
releaseLabel?: string
|
|
492
|
+
): string {
|
|
493
|
+
if (!releaseLabel) {
|
|
494
|
+
return inputs.projectName;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return `${inputs.projectName} ${releaseLabel}`;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
type CloudResourceMap = Record<string, string>;
|
|
501
|
+
|
|
502
|
+
type PostmanResourcesState = {
|
|
503
|
+
workspace?: {
|
|
504
|
+
id?: string;
|
|
505
|
+
};
|
|
506
|
+
cloudResources?: {
|
|
507
|
+
collections?: CloudResourceMap;
|
|
508
|
+
environments?: CloudResourceMap;
|
|
509
|
+
specs?: CloudResourceMap;
|
|
510
|
+
};
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
function readResourcesState(): PostmanResourcesState | null {
|
|
514
|
+
try {
|
|
515
|
+
return parse(readFileSync('.postman/resources.yaml', 'utf8')) as PostmanResourcesState;
|
|
516
|
+
} catch {
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function getFirstCloudResourceId(map: CloudResourceMap | undefined): string | undefined {
|
|
522
|
+
if (!map) {
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
525
|
+
return Object.values(map)[0];
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function findCloudResourceId(
|
|
529
|
+
map: CloudResourceMap | undefined,
|
|
530
|
+
matcher: (path: string) => boolean
|
|
531
|
+
): string | undefined {
|
|
532
|
+
if (!map) {
|
|
533
|
+
return undefined;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const match = Object.entries(map).find(([filePath]) => matcher(filePath));
|
|
537
|
+
return match?.[1];
|
|
538
|
+
}
|
|
539
|
+
|
|
459
540
|
const SPEC_SUMMARY_MAX_LEN = 200;
|
|
460
541
|
const SPEC_HTTP_METHODS = new Set([
|
|
461
542
|
'get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'
|
|
@@ -542,146 +623,19 @@ function validateSpecStructure(content: string): void {
|
|
|
542
623
|
}
|
|
543
624
|
}
|
|
544
625
|
|
|
545
|
-
function varName(projectName: string, baseName: string): string {
|
|
546
|
-
const slug = projectName.toUpperCase().replace(/[^A-Z0-9]/g, '_');
|
|
547
|
-
return `POSTMAN_${slug}_${baseName}`;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
async function readVariable(
|
|
551
|
-
github: RepoVariableClient | undefined,
|
|
552
|
-
projectName: string,
|
|
553
|
-
baseName: string
|
|
554
|
-
): Promise<string | undefined> {
|
|
555
|
-
if (!github) {
|
|
556
|
-
return undefined;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
const namespaced = await github
|
|
560
|
-
.getRepositoryVariable(varName(projectName, baseName))
|
|
561
|
-
.catch(() => undefined);
|
|
562
|
-
if (namespaced) {
|
|
563
|
-
return namespaced;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
const legacy = await github
|
|
567
|
-
.getRepositoryVariable(`POSTMAN_${baseName}`)
|
|
568
|
-
.catch(() => undefined);
|
|
569
|
-
return legacy || undefined;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
async function persistVariable(
|
|
573
|
-
github: RepoVariableClient | undefined,
|
|
574
|
-
name: string,
|
|
575
|
-
value: string,
|
|
576
|
-
actionCore: Pick<CoreLike, 'warning'>
|
|
577
|
-
): Promise<void> {
|
|
578
|
-
if (!github || !value) {
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
try {
|
|
583
|
-
await github.setRepositoryVariable(name, value);
|
|
584
|
-
} catch (err) {
|
|
585
|
-
actionCore.warning(
|
|
586
|
-
`Failed to persist ${name}: ${err instanceof Error ? err.message : String(err)}`
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
async function writeVariable(
|
|
592
|
-
github: RepoVariableClient | undefined,
|
|
593
|
-
projectName: string,
|
|
594
|
-
baseName: string,
|
|
595
|
-
value: string,
|
|
596
|
-
actionCore: Pick<CoreLike, 'warning'>
|
|
597
|
-
): Promise<void> {
|
|
598
|
-
if (!github || !value) {
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
await persistVariable(github, varName(projectName, baseName), value, actionCore);
|
|
603
|
-
await persistVariable(github, `POSTMAN_${baseName}`, value, actionCore);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
async function persistBootstrapRepositoryVariables(
|
|
607
|
-
github: RepoVariableClient,
|
|
608
|
-
projectName: string,
|
|
609
|
-
outputs: PlannedOutputs,
|
|
610
|
-
systemEnvMap: Record<string, string>,
|
|
611
|
-
environments: string[],
|
|
612
|
-
lintSummary: BootstrapRepositoryVariables,
|
|
613
|
-
actionCore: Pick<CoreLike, 'warning'>
|
|
614
|
-
): Promise<void> {
|
|
615
|
-
await persistVariable(
|
|
616
|
-
github,
|
|
617
|
-
'LINT_WARNINGS',
|
|
618
|
-
String(lintSummary.lintWarnings),
|
|
619
|
-
actionCore
|
|
620
|
-
);
|
|
621
|
-
await persistVariable(
|
|
622
|
-
github,
|
|
623
|
-
'LINT_ERRORS',
|
|
624
|
-
String(lintSummary.lintErrors),
|
|
625
|
-
actionCore
|
|
626
|
-
);
|
|
627
|
-
await writeVariable(
|
|
628
|
-
github,
|
|
629
|
-
projectName,
|
|
630
|
-
'WORKSPACE_ID',
|
|
631
|
-
outputs['workspace-id'],
|
|
632
|
-
actionCore
|
|
633
|
-
);
|
|
634
|
-
await writeVariable(github, projectName, 'SPEC_UID', outputs['spec-id'], actionCore);
|
|
635
|
-
await writeVariable(
|
|
636
|
-
github,
|
|
637
|
-
projectName,
|
|
638
|
-
'BASELINE_COLLECTION_UID',
|
|
639
|
-
outputs['baseline-collection-id'],
|
|
640
|
-
actionCore
|
|
641
|
-
);
|
|
642
|
-
await writeVariable(
|
|
643
|
-
github,
|
|
644
|
-
projectName,
|
|
645
|
-
'SMOKE_COLLECTION_UID',
|
|
646
|
-
outputs['smoke-collection-id'],
|
|
647
|
-
actionCore
|
|
648
|
-
);
|
|
649
|
-
await writeVariable(
|
|
650
|
-
github,
|
|
651
|
-
projectName,
|
|
652
|
-
'CONTRACT_COLLECTION_UID',
|
|
653
|
-
outputs['contract-collection-id'],
|
|
654
|
-
actionCore
|
|
655
|
-
);
|
|
656
|
-
|
|
657
|
-
for (const envName of environments) {
|
|
658
|
-
const systemEnvId = systemEnvMap[envName];
|
|
659
|
-
if (!systemEnvId) {
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
await writeVariable(
|
|
663
|
-
github,
|
|
664
|
-
projectName,
|
|
665
|
-
`SYSTEM_ENV_${envName.toUpperCase()}`,
|
|
666
|
-
systemEnvId,
|
|
667
|
-
actionCore
|
|
668
|
-
);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
626
|
export async function runBootstrap(
|
|
673
627
|
inputs: ResolvedInputs,
|
|
674
628
|
dependencies: BootstrapExecutionDependencies
|
|
675
629
|
): Promise<PlannedOutputs> {
|
|
676
630
|
const outputs = createPlannedOutputs(inputs);
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
)
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
631
|
+
const requiresReleaseLabel =
|
|
632
|
+
inputs.collectionSyncMode === 'version' || inputs.specSyncMode === 'version';
|
|
633
|
+
const releaseLabel = requiresReleaseLabel ? deriveReleaseLabel(inputs) : undefined;
|
|
634
|
+
if (requiresReleaseLabel && !releaseLabel) {
|
|
635
|
+
throw new Error(
|
|
636
|
+
'Versioned spec or collection sync requires a release-label or derivable GitHub ref metadata'
|
|
637
|
+
);
|
|
638
|
+
}
|
|
685
639
|
const workspaceName = createWorkspaceName(inputs);
|
|
686
640
|
const aboutText = `Auto-provisioned by Postman CS open-alpha for ${inputs.projectName}`;
|
|
687
641
|
|
|
@@ -689,19 +643,17 @@ export async function runBootstrap(
|
|
|
689
643
|
await ensurePostmanCli(dependencies, inputs.postmanApiKey);
|
|
690
644
|
});
|
|
691
645
|
|
|
646
|
+
const resourcesState = readResourcesState();
|
|
692
647
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
repoWorkspaceId = await readVariable(
|
|
698
|
-
dependencies.github,
|
|
699
|
-
inputs.projectName,
|
|
700
|
-
'WORKSPACE_ID'
|
|
701
|
-
);
|
|
702
|
-
workspaceId = repoWorkspaceId;
|
|
648
|
+
let explicitWorkspaceId = inputs.workspaceId;
|
|
649
|
+
if (!explicitWorkspaceId && resourcesState?.workspace?.id) {
|
|
650
|
+
explicitWorkspaceId = resourcesState.workspace.id;
|
|
651
|
+
dependencies.core.info('Resolved workspace-id from .postman/resources.yaml');
|
|
703
652
|
}
|
|
704
653
|
|
|
654
|
+
const repoWorkspaceId = explicitWorkspaceId;
|
|
655
|
+
let workspaceId = explicitWorkspaceId;
|
|
656
|
+
|
|
705
657
|
let teamId = inputs.teamId || '';
|
|
706
658
|
if (!teamId) {
|
|
707
659
|
teamId = await dependencies.postman.getAutoDerivedTeamId() || '';
|
|
@@ -738,11 +690,66 @@ export async function runBootstrap(
|
|
|
738
690
|
dependencies.core.info(`Using existing workspace: ${workspaceId}`);
|
|
739
691
|
}
|
|
740
692
|
|
|
693
|
+
// Parse workspace-team-id from already-resolved inputs
|
|
694
|
+
let workspaceTeamId: number | undefined;
|
|
695
|
+
if (inputs.workspaceTeamId) {
|
|
696
|
+
workspaceTeamId = parseInt(inputs.workspaceTeamId, 10);
|
|
697
|
+
if (Number.isNaN(workspaceTeamId)) {
|
|
698
|
+
throw new Error(`workspace-team-id must be a numeric sub-team ID, got: ${inputs.workspaceTeamId}`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// Org-mode detection: only check if we need to create a workspace (not reuse existing)
|
|
703
|
+
if (!workspaceId && !workspaceTeamId) {
|
|
704
|
+
try {
|
|
705
|
+
const teams = await dependencies.postman.getTeams();
|
|
706
|
+
if (teams.length > 1 && teams.every(t => t.organizationId == null)) {
|
|
707
|
+
dependencies.core.warning(
|
|
708
|
+
'GET /teams returned multiple teams but none include organizationId. ' +
|
|
709
|
+
'Org-mode detection may be degraded due to an upstream API change. ' +
|
|
710
|
+
'If workspace creation fails, set workspace-team-id explicitly.'
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
const orgIds = new Set(teams.filter(t => t.organizationId != null).map(t => t.organizationId));
|
|
714
|
+
const meTeamId = parseInt(teamId, 10);
|
|
715
|
+
const isOrgMode = teams.length > 1
|
|
716
|
+
&& orgIds.size === 1
|
|
717
|
+
&& orgIds.has(meTeamId);
|
|
718
|
+
|
|
719
|
+
if (isOrgMode) {
|
|
720
|
+
const teamList = teams
|
|
721
|
+
.map(t => ` ${t.id} ${t.name}`)
|
|
722
|
+
.join('\n');
|
|
723
|
+
throw new Error(
|
|
724
|
+
`Org-mode account detected. Workspace creation requires a specific sub-team ID.\n\n` +
|
|
725
|
+
`Available sub-teams:\n${teamList}\n\n` +
|
|
726
|
+
`To fix this, set the workspace-team-id input in your workflow:\n` +
|
|
727
|
+
` workspace-team-id: '<id>'\n\n` +
|
|
728
|
+
`Or for reuse across runs, create a repository variable and reference it:\n` +
|
|
729
|
+
` workspace-team-id: \${{ vars.POSTMAN_WORKSPACE_TEAM_ID }}\n\n` +
|
|
730
|
+
`For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID=<id>.`
|
|
731
|
+
);
|
|
732
|
+
} else if (teams.length > 1) {
|
|
733
|
+
dependencies.core.warning(
|
|
734
|
+
`API key has access to ${teams.length} teams but org-mode could not be confirmed. ` +
|
|
735
|
+
`Proceeding without teamId. If workspace creation fails, set workspace-team-id explicitly.`
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
} catch (err) {
|
|
739
|
+
if (err instanceof Error && err.message.includes('Org-mode account detected')) {
|
|
740
|
+
throw err;
|
|
741
|
+
}
|
|
742
|
+
dependencies.core.warning(
|
|
743
|
+
`Could not check for org-mode sub-teams: ${err instanceof Error ? err.message : String(err)}`
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
741
748
|
if (!workspaceId) {
|
|
742
749
|
const workspace = await runGroup(
|
|
743
750
|
dependencies.core,
|
|
744
751
|
'Create Postman Workspace',
|
|
745
|
-
async () => dependencies.postman.createWorkspace(workspaceName, aboutText)
|
|
752
|
+
async () => dependencies.postman.createWorkspace(workspaceName, aboutText, workspaceTeamId)
|
|
746
753
|
);
|
|
747
754
|
workspaceId = workspace.id;
|
|
748
755
|
}
|
|
@@ -750,14 +757,6 @@ export async function runBootstrap(
|
|
|
750
757
|
outputs['workspace-id'] = workspaceId || '';
|
|
751
758
|
outputs['workspace-url'] = `https://go.postman.co/workspace/${workspaceId}`;
|
|
752
759
|
outputs['workspace-name'] = workspaceName;
|
|
753
|
-
await writeVariable(
|
|
754
|
-
dependencies.github,
|
|
755
|
-
inputs.projectName,
|
|
756
|
-
'WORKSPACE_ID',
|
|
757
|
-
outputs['workspace-id'],
|
|
758
|
-
dependencies.core
|
|
759
|
-
);
|
|
760
|
-
|
|
761
760
|
|
|
762
761
|
if (inputs.domain && dependencies.internalIntegration) {
|
|
763
762
|
await runGroup(
|
|
@@ -818,37 +817,49 @@ export async function runBootstrap(
|
|
|
818
817
|
);
|
|
819
818
|
}
|
|
820
819
|
|
|
821
|
-
|
|
822
820
|
let specId = inputs.specId;
|
|
823
|
-
if (!specId
|
|
824
|
-
specId =
|
|
821
|
+
if (!specId) {
|
|
822
|
+
specId = getFirstCloudResourceId(resourcesState?.cloudResources?.specs);
|
|
823
|
+
if (specId) {
|
|
824
|
+
dependencies.core.info('Resolved spec-id from .postman/resources.yaml');
|
|
825
|
+
}
|
|
825
826
|
}
|
|
826
827
|
|
|
827
|
-
let baselineCollectionId =
|
|
828
|
-
|
|
829
|
-
let
|
|
828
|
+
let baselineCollectionId =
|
|
829
|
+
inputs.collectionSyncMode === 'refresh' ? undefined : inputs.baselineCollectionId;
|
|
830
|
+
let smokeCollectionId =
|
|
831
|
+
inputs.collectionSyncMode === 'refresh' ? undefined : inputs.smokeCollectionId;
|
|
832
|
+
let contractCollectionId =
|
|
833
|
+
inputs.collectionSyncMode === 'refresh' ? undefined : inputs.contractCollectionId;
|
|
830
834
|
|
|
831
|
-
if (
|
|
835
|
+
if (inputs.collectionSyncMode !== 'refresh') {
|
|
836
|
+
const cloudCollections = resourcesState?.cloudResources?.collections;
|
|
832
837
|
if (!baselineCollectionId) {
|
|
833
|
-
baselineCollectionId =
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
'BASELINE_COLLECTION_UID'
|
|
838
|
+
baselineCollectionId = findCloudResourceId(
|
|
839
|
+
cloudCollections,
|
|
840
|
+
(filePath) => filePath.includes('[Baseline]')
|
|
837
841
|
);
|
|
842
|
+
if (baselineCollectionId) {
|
|
843
|
+
dependencies.core.info('Resolved baseline-collection-id from .postman/resources.yaml');
|
|
844
|
+
}
|
|
838
845
|
}
|
|
839
846
|
if (!smokeCollectionId) {
|
|
840
|
-
smokeCollectionId =
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
'SMOKE_COLLECTION_UID'
|
|
847
|
+
smokeCollectionId = findCloudResourceId(
|
|
848
|
+
cloudCollections,
|
|
849
|
+
(filePath) => filePath.includes('[Smoke]')
|
|
844
850
|
);
|
|
851
|
+
if (smokeCollectionId) {
|
|
852
|
+
dependencies.core.info('Resolved smoke-collection-id from .postman/resources.yaml');
|
|
853
|
+
}
|
|
845
854
|
}
|
|
846
855
|
if (!contractCollectionId) {
|
|
847
|
-
contractCollectionId =
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
'CONTRACT_COLLECTION_UID'
|
|
856
|
+
contractCollectionId = findCloudResourceId(
|
|
857
|
+
cloudCollections,
|
|
858
|
+
(filePath) => filePath.includes('[Contract]')
|
|
851
859
|
);
|
|
860
|
+
if (contractCollectionId) {
|
|
861
|
+
dependencies.core.info('Resolved contract-collection-id from .postman/resources.yaml');
|
|
862
|
+
}
|
|
852
863
|
}
|
|
853
864
|
}
|
|
854
865
|
|
|
@@ -874,7 +885,10 @@ export async function runBootstrap(
|
|
|
874
885
|
} else {
|
|
875
886
|
specId = await dependencies.postman.uploadSpec(
|
|
876
887
|
workspaceId || '',
|
|
877
|
-
|
|
888
|
+
createAssetProjectName(
|
|
889
|
+
inputs,
|
|
890
|
+
inputs.specSyncMode === 'version' ? releaseLabel : undefined
|
|
891
|
+
),
|
|
878
892
|
document
|
|
879
893
|
);
|
|
880
894
|
}
|
|
@@ -884,13 +898,6 @@ export async function runBootstrap(
|
|
|
884
898
|
);
|
|
885
899
|
|
|
886
900
|
void specContent;
|
|
887
|
-
await writeVariable(
|
|
888
|
-
dependencies.github,
|
|
889
|
-
inputs.projectName,
|
|
890
|
-
'SPEC_UID',
|
|
891
|
-
outputs['spec-id'],
|
|
892
|
-
dependencies.core
|
|
893
|
-
);
|
|
894
901
|
|
|
895
902
|
const lintSummary = await runGroup(
|
|
896
903
|
dependencies.core,
|
|
@@ -936,14 +943,23 @@ export async function runBootstrap(
|
|
|
936
943
|
dependencies.core,
|
|
937
944
|
'Generate Collections from Spec',
|
|
938
945
|
async () => {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
946
|
+
const shouldReuseCollections = inputs.collectionSyncMode !== 'refresh';
|
|
947
|
+
const assetProjectName =
|
|
948
|
+
inputs.collectionSyncMode === 'version'
|
|
949
|
+
? createAssetProjectName(inputs, releaseLabel)
|
|
950
|
+
: inputs.projectName;
|
|
951
|
+
|
|
952
|
+
outputs['baseline-collection-id'] =
|
|
953
|
+
shouldReuseCollections ? baselineCollectionId || '' : '';
|
|
954
|
+
outputs['smoke-collection-id'] =
|
|
955
|
+
shouldReuseCollections ? smokeCollectionId || '' : '';
|
|
956
|
+
outputs['contract-collection-id'] =
|
|
957
|
+
shouldReuseCollections ? contractCollectionId || '' : '';
|
|
942
958
|
|
|
943
959
|
if (!outputs['baseline-collection-id']) {
|
|
944
960
|
outputs['baseline-collection-id'] = await dependencies.postman.generateCollection(
|
|
945
961
|
outputs['spec-id'],
|
|
946
|
-
|
|
962
|
+
assetProjectName,
|
|
947
963
|
'[Baseline]'
|
|
948
964
|
);
|
|
949
965
|
} else {
|
|
@@ -951,18 +967,10 @@ export async function runBootstrap(
|
|
|
951
967
|
`Using existing baseline collection: ${outputs['baseline-collection-id']}`
|
|
952
968
|
);
|
|
953
969
|
}
|
|
954
|
-
await writeVariable(
|
|
955
|
-
dependencies.github,
|
|
956
|
-
inputs.projectName,
|
|
957
|
-
'BASELINE_COLLECTION_UID',
|
|
958
|
-
outputs['baseline-collection-id'],
|
|
959
|
-
dependencies.core
|
|
960
|
-
);
|
|
961
|
-
|
|
962
970
|
if (!outputs['smoke-collection-id']) {
|
|
963
971
|
outputs['smoke-collection-id'] = await dependencies.postman.generateCollection(
|
|
964
972
|
outputs['spec-id'],
|
|
965
|
-
|
|
973
|
+
assetProjectName,
|
|
966
974
|
'[Smoke]'
|
|
967
975
|
);
|
|
968
976
|
} else {
|
|
@@ -970,18 +978,10 @@ export async function runBootstrap(
|
|
|
970
978
|
`Using existing smoke collection: ${outputs['smoke-collection-id']}`
|
|
971
979
|
);
|
|
972
980
|
}
|
|
973
|
-
await writeVariable(
|
|
974
|
-
dependencies.github,
|
|
975
|
-
inputs.projectName,
|
|
976
|
-
'SMOKE_COLLECTION_UID',
|
|
977
|
-
outputs['smoke-collection-id'],
|
|
978
|
-
dependencies.core
|
|
979
|
-
);
|
|
980
|
-
|
|
981
981
|
if (!outputs['contract-collection-id']) {
|
|
982
982
|
outputs['contract-collection-id'] = await dependencies.postman.generateCollection(
|
|
983
983
|
outputs['spec-id'],
|
|
984
|
-
|
|
984
|
+
assetProjectName,
|
|
985
985
|
'[Contract]'
|
|
986
986
|
);
|
|
987
987
|
} else {
|
|
@@ -989,13 +989,6 @@ export async function runBootstrap(
|
|
|
989
989
|
`Using existing contract collection: ${outputs['contract-collection-id']}`
|
|
990
990
|
);
|
|
991
991
|
}
|
|
992
|
-
await writeVariable(
|
|
993
|
-
dependencies.github,
|
|
994
|
-
inputs.projectName,
|
|
995
|
-
'CONTRACT_COLLECTION_UID',
|
|
996
|
-
outputs['contract-collection-id'],
|
|
997
|
-
dependencies.core
|
|
998
|
-
);
|
|
999
992
|
}
|
|
1000
993
|
);
|
|
1001
994
|
|
|
@@ -1037,26 +1030,49 @@ export async function runBootstrap(
|
|
|
1037
1030
|
}
|
|
1038
1031
|
);
|
|
1039
1032
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1033
|
+
const linkedCollectionIds = [
|
|
1034
|
+
outputs['baseline-collection-id'],
|
|
1035
|
+
outputs['smoke-collection-id'],
|
|
1036
|
+
outputs['contract-collection-id']
|
|
1037
|
+
].filter(Boolean);
|
|
1038
|
+
|
|
1039
|
+
if (linkedCollectionIds.length > 0) {
|
|
1040
|
+
if (dependencies.internalIntegration) {
|
|
1041
|
+
await runGroup(
|
|
1042
|
+
dependencies.core,
|
|
1043
|
+
'Link Collections to Specification',
|
|
1044
|
+
async () => {
|
|
1045
|
+
await dependencies.internalIntegration?.linkCollectionsToSpecification(
|
|
1046
|
+
outputs['spec-id'],
|
|
1047
|
+
linkedCollectionIds.map((collectionId) => ({
|
|
1048
|
+
collectionId,
|
|
1049
|
+
syncOptions: {
|
|
1050
|
+
syncExamples: inputs.syncExamples
|
|
1051
|
+
}
|
|
1052
|
+
}))
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
);
|
|
1056
|
+
|
|
1057
|
+
await runGroup(
|
|
1058
|
+
dependencies.core,
|
|
1059
|
+
'Sync Linked Collections',
|
|
1060
|
+
async () => {
|
|
1061
|
+
await Promise.all(
|
|
1062
|
+
linkedCollectionIds.map((collectionId) =>
|
|
1063
|
+
dependencies.internalIntegration!.syncCollection(
|
|
1064
|
+
outputs['spec-id'],
|
|
1065
|
+
collectionId
|
|
1066
|
+
)
|
|
1067
|
+
)
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
);
|
|
1071
|
+
} else {
|
|
1072
|
+
dependencies.core.warning(
|
|
1073
|
+
'Skipping cloud spec-to-collection linking and sync because postman-access-token is not configured'
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1060
1076
|
}
|
|
1061
1077
|
|
|
1062
1078
|
for (const [name, value] of Object.entries(outputs)) {
|
|
@@ -1079,9 +1095,6 @@ export async function runAction(
|
|
|
1079
1095
|
specFetcher: fetch
|
|
1080
1096
|
});
|
|
1081
1097
|
|
|
1082
|
-
if (!dependencies.github) {
|
|
1083
|
-
actionCore.info('GitHub repository variable persistence disabled for this run');
|
|
1084
|
-
}
|
|
1085
1098
|
if (inputs.domain && !dependencies.internalIntegration) {
|
|
1086
1099
|
actionCore.warning(
|
|
1087
1100
|
'Skipping governance assignment because postman-access-token is not configured'
|
|
@@ -1097,25 +1110,12 @@ export function createBootstrapDependencies(
|
|
|
1097
1110
|
): BootstrapExecutionDependencies {
|
|
1098
1111
|
const secretMasker = createSecretMasker([
|
|
1099
1112
|
inputs.postmanApiKey,
|
|
1100
|
-
inputs.postmanAccessToken
|
|
1101
|
-
inputs.githubToken,
|
|
1102
|
-
inputs.ghFallbackToken
|
|
1113
|
+
inputs.postmanAccessToken
|
|
1103
1114
|
]);
|
|
1104
1115
|
const postman = new PostmanAssetsClient({
|
|
1105
1116
|
apiKey: inputs.postmanApiKey,
|
|
1106
1117
|
secretMasker
|
|
1107
1118
|
});
|
|
1108
|
-
const repository = extractRepositorySlug(inputs.repoUrl);
|
|
1109
|
-
const github =
|
|
1110
|
-
inputs.githubToken && inputs.repoUrl && repository
|
|
1111
|
-
? new GitHubApiClient({
|
|
1112
|
-
authMode: inputs.githubAuthMode as GitHubApiClientAuthMode,
|
|
1113
|
-
fallbackToken: inputs.ghFallbackToken,
|
|
1114
|
-
repository,
|
|
1115
|
-
secretMasker,
|
|
1116
|
-
token: inputs.githubToken
|
|
1117
|
-
})
|
|
1118
|
-
: undefined;
|
|
1119
1119
|
const internalIntegration =
|
|
1120
1120
|
inputs.postmanAccessToken
|
|
1121
1121
|
? createInternalIntegrationAdapter({
|
|
@@ -1129,7 +1129,6 @@ export function createBootstrapDependencies(
|
|
|
1129
1129
|
return {
|
|
1130
1130
|
core: factories.core,
|
|
1131
1131
|
exec: factories.exec,
|
|
1132
|
-
github,
|
|
1133
1132
|
io: factories.io,
|
|
1134
1133
|
internalIntegration,
|
|
1135
1134
|
postman,
|
|
@@ -1137,25 +1136,6 @@ export function createBootstrapDependencies(
|
|
|
1137
1136
|
};
|
|
1138
1137
|
}
|
|
1139
1138
|
|
|
1140
|
-
export function extractRepositorySlug(repoUrl: string | undefined): string | undefined {
|
|
1141
|
-
const normalized = normalizeInputValue(repoUrl);
|
|
1142
|
-
if (!normalized) {
|
|
1143
|
-
return undefined;
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
try {
|
|
1147
|
-
const parsed = new URL(normalized);
|
|
1148
|
-
const pathname = parsed.pathname.replace(/^\/+|\/+$/g, '').replace(/\.git$/, '');
|
|
1149
|
-
const segments = pathname.split('/').filter(Boolean);
|
|
1150
|
-
if (segments.length >= 2) {
|
|
1151
|
-
return `${segments[0]}/${segments[1]}`;
|
|
1152
|
-
}
|
|
1153
|
-
return undefined;
|
|
1154
|
-
} catch {
|
|
1155
|
-
return undefined;
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
1139
|
const currentModulePath = typeof __filename === 'string' ? __filename : '';
|
|
1160
1140
|
const entrypoint = process.argv[1];
|
|
1161
1141
|
|