@postman-cse/onboarding-repo-sync 2.1.1 → 2.1.2
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 +2 -0
- package/dist/action.cjs +322 -128
- package/dist/cli.cjs +322 -128
- package/dist/index.cjs +322 -128
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -252,6 +252,8 @@ For `commit-and-push`, the push target is resolved from `current-ref`, then `GIT
|
|
|
252
252
|
|
|
253
253
|
Mocks and monitors: when `baseline-collection-id`, `workspace-id`, and at least one environment are available, the action creates or reuses a mock server. When `smoke-collection-id` is also available, it creates or reuses a cloud smoke monitor unless `monitor-type: cli` is set. With an empty `monitor-cron`, a new cloud monitor is created disabled and triggered once per workflow invocation.
|
|
254
254
|
|
|
255
|
+
Asset reuse priority is explicit inputs (`environment-uids-json`, `mock-url`, `monitor-id`), then live discovery by exact workspace-scoped name, collection UID, and environment UID, then create. Creates submit once and reconcile on ambiguous gateway errors; overlapping compatible creates inside one process share a single in-flight promise. Adopted environments are updated to the requested values. Mock environment assignment has no verified patch route, so a mock is reused only when its live environment already matches; mismatches are never claimed as converged. Concurrent jobs against the same workspace can still race because Postman does not expose create idempotency keys—serialize those workflows with GitHub Actions `concurrency` (or an equivalent CI lock) when duplicate mocks/monitors/environments would be harmful.
|
|
256
|
+
|
|
255
257
|
Deeper reference:
|
|
256
258
|
|
|
257
259
|
- [Artifact layout and Collection v3 format](docs/artifact-layout.md), including sync modes and versioned releases.
|
package/dist/action.cjs
CHANGED
|
@@ -127291,12 +127291,20 @@ async function retry(operation, options = {}) {
|
|
|
127291
127291
|
}
|
|
127292
127292
|
|
|
127293
127293
|
// src/lib/postman/postman-gateway-assets-client.ts
|
|
127294
|
+
var MAX_CREATE_FLIGHTS = 256;
|
|
127295
|
+
var createFlights = /* @__PURE__ */ new Map();
|
|
127294
127296
|
var PostmanGatewayAssetsClient = class {
|
|
127295
127297
|
gateway;
|
|
127296
127298
|
workspaceId;
|
|
127299
|
+
sleep;
|
|
127300
|
+
reconcileAttempts;
|
|
127301
|
+
reconcileDelayMs;
|
|
127297
127302
|
constructor(options) {
|
|
127298
127303
|
this.gateway = options.gateway;
|
|
127299
127304
|
this.workspaceId = String(options.workspaceId || "").trim();
|
|
127305
|
+
this.sleep = options.sleep ?? sleep;
|
|
127306
|
+
this.reconcileAttempts = Math.max(1, options.reconcileAttempts ?? 3);
|
|
127307
|
+
this.reconcileDelayMs = Math.max(0, options.reconcileDelayMs ?? 500);
|
|
127300
127308
|
}
|
|
127301
127309
|
asRecord(value) {
|
|
127302
127310
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
@@ -127326,8 +127334,64 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127326
127334
|
const parts = trimmed.split("-");
|
|
127327
127335
|
return parts.length >= 6 ? parts.slice(1).join("-") : trimmed;
|
|
127328
127336
|
}
|
|
127329
|
-
|
|
127330
|
-
|
|
127337
|
+
isAmbiguousCreateOutcome(error2) {
|
|
127338
|
+
if (error2 instanceof HttpError) {
|
|
127339
|
+
return error2.status === 408 || error2.status === 429 || error2.status >= 500;
|
|
127340
|
+
}
|
|
127341
|
+
return error2 instanceof Error;
|
|
127342
|
+
}
|
|
127343
|
+
isRetryableIdempotentWriteOutcome(error2) {
|
|
127344
|
+
if (error2 instanceof HttpError) {
|
|
127345
|
+
return error2.status === 408 || error2.status === 429 || error2.status >= 500;
|
|
127346
|
+
}
|
|
127347
|
+
return error2 instanceof Error;
|
|
127348
|
+
}
|
|
127349
|
+
selectExactMatch(kind, identity, matches) {
|
|
127350
|
+
if (matches.length > 1) {
|
|
127351
|
+
const ids = matches.map((match) => match.uid).join(", ");
|
|
127352
|
+
throw new Error(
|
|
127353
|
+
`Multiple ${kind}s match ${identity}: ${ids}. Refusing to choose one; remove duplicates or pass an explicit asset ID.`
|
|
127354
|
+
);
|
|
127355
|
+
}
|
|
127356
|
+
return matches[0] ?? null;
|
|
127357
|
+
}
|
|
127358
|
+
async singleFlight(key, fingerprint, kind, operation) {
|
|
127359
|
+
const existing = createFlights.get(key);
|
|
127360
|
+
if (existing) {
|
|
127361
|
+
if (existing.fingerprint !== fingerprint) {
|
|
127362
|
+
throw new Error(`Incompatible concurrent ${kind} create for ${key}`);
|
|
127363
|
+
}
|
|
127364
|
+
return existing.promise;
|
|
127365
|
+
}
|
|
127366
|
+
if (createFlights.size >= MAX_CREATE_FLIGHTS) {
|
|
127367
|
+
throw new Error(`Too many concurrent Postman asset creates (limit ${MAX_CREATE_FLIGHTS})`);
|
|
127368
|
+
}
|
|
127369
|
+
const pending = operation().finally(() => {
|
|
127370
|
+
if (createFlights.get(key)?.promise === pending) {
|
|
127371
|
+
createFlights.delete(key);
|
|
127372
|
+
}
|
|
127373
|
+
});
|
|
127374
|
+
createFlights.set(key, { fingerprint, promise: pending });
|
|
127375
|
+
return pending;
|
|
127376
|
+
}
|
|
127377
|
+
async discoverAfterAmbiguousCreate(discover, error2) {
|
|
127378
|
+
if (!this.isAmbiguousCreateOutcome(error2)) {
|
|
127379
|
+
return null;
|
|
127380
|
+
}
|
|
127381
|
+
for (let attempt = 0; attempt < this.reconcileAttempts; attempt += 1) {
|
|
127382
|
+
if (attempt > 0) {
|
|
127383
|
+
await this.sleep(this.reconcileDelayMs);
|
|
127384
|
+
}
|
|
127385
|
+
const found = await discover();
|
|
127386
|
+
if (found) {
|
|
127387
|
+
return found;
|
|
127388
|
+
}
|
|
127389
|
+
}
|
|
127390
|
+
return null;
|
|
127391
|
+
}
|
|
127392
|
+
publicEnvironmentUid(data, bareId) {
|
|
127393
|
+
const owner = String(data?.owner ?? "").trim();
|
|
127394
|
+
return owner && !bareId.startsWith(`${owner}-`) ? `${owner}-${bareId}` : bareId;
|
|
127331
127395
|
}
|
|
127332
127396
|
// --- environments (service: sync) ---
|
|
127333
127397
|
//
|
|
@@ -127338,9 +127402,10 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127338
127402
|
/**
|
|
127339
127403
|
* Create/upsert an environment through the sync service.
|
|
127340
127404
|
* POST /environment/import?workspace=:ws { id:<uuid>, name, values } ->
|
|
127341
|
-
* { data:{ id:<bare uuid>, owner } }. The id is generated once
|
|
127342
|
-
*
|
|
127343
|
-
*
|
|
127405
|
+
* { data:{ id:<bare uuid>, owner } }. The id is generated once for the
|
|
127406
|
+
* operation. Unsafe creates submit once (no blind retry); on an ambiguous
|
|
127407
|
+
* response the client discovers by exact workspace-scoped name before
|
|
127408
|
+
* failing.
|
|
127344
127409
|
*
|
|
127345
127410
|
* Returns the PUBLIC uid (`<owner>-<uuid>`), not the bare model id the sync
|
|
127346
127411
|
* import echoes: mock/monitor create reference the environment by its public
|
|
@@ -127350,33 +127415,54 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127350
127415
|
*/
|
|
127351
127416
|
async createEnvironment(workspaceId, name, values) {
|
|
127352
127417
|
const ws = workspaceId || this.workspaceId;
|
|
127353
|
-
const
|
|
127354
|
-
const
|
|
127355
|
-
|
|
127356
|
-
|
|
127357
|
-
|
|
127358
|
-
|
|
127359
|
-
|
|
127360
|
-
|
|
127361
|
-
|
|
127362
|
-
|
|
127363
|
-
|
|
127364
|
-
|
|
127365
|
-
|
|
127366
|
-
|
|
127367
|
-
|
|
127368
|
-
|
|
127369
|
-
|
|
127370
|
-
|
|
127371
|
-
|
|
127372
|
-
|
|
127373
|
-
|
|
127374
|
-
|
|
127375
|
-
|
|
127376
|
-
|
|
127377
|
-
|
|
127378
|
-
|
|
127379
|
-
|
|
127418
|
+
const envName = String(name ?? "").trim();
|
|
127419
|
+
const flightKey = `environment:${ws}:${envName}`;
|
|
127420
|
+
const normalizedValues = values.map((v) => ({
|
|
127421
|
+
key: v.key,
|
|
127422
|
+
value: v.value,
|
|
127423
|
+
type: v.type ?? "default",
|
|
127424
|
+
enabled: v.enabled ?? true
|
|
127425
|
+
}));
|
|
127426
|
+
return this.singleFlight(flightKey, JSON.stringify(normalizedValues), "environment", async () => {
|
|
127427
|
+
const existing = await this.findEnvironmentByName(ws, envName);
|
|
127428
|
+
if (existing?.uid) {
|
|
127429
|
+
await this.updateEnvironment(existing.uid, envName, values);
|
|
127430
|
+
return existing.uid;
|
|
127431
|
+
}
|
|
127432
|
+
const id = crypto.randomUUID();
|
|
127433
|
+
const body = {
|
|
127434
|
+
id,
|
|
127435
|
+
name: envName,
|
|
127436
|
+
values: normalizedValues
|
|
127437
|
+
};
|
|
127438
|
+
try {
|
|
127439
|
+
const response = await this.gateway.requestJson(
|
|
127440
|
+
{
|
|
127441
|
+
service: "sync",
|
|
127442
|
+
method: "post",
|
|
127443
|
+
path: `/environment/import?workspace=${ws}`,
|
|
127444
|
+
body
|
|
127445
|
+
},
|
|
127446
|
+
{ retryTransient: false }
|
|
127447
|
+
);
|
|
127448
|
+
const data = this.dataOf(response);
|
|
127449
|
+
const bareId = this.idOf(data);
|
|
127450
|
+
if (!bareId) {
|
|
127451
|
+
throw new Error("Environment import did not return a UID");
|
|
127452
|
+
}
|
|
127453
|
+
return this.publicEnvironmentUid(data, bareId);
|
|
127454
|
+
} catch (error2) {
|
|
127455
|
+
const adopted = await this.discoverAfterAmbiguousCreate(async () => {
|
|
127456
|
+
const match = await this.findEnvironmentByName(ws, envName);
|
|
127457
|
+
return match?.uid ?? null;
|
|
127458
|
+
}, error2);
|
|
127459
|
+
if (adopted) {
|
|
127460
|
+
await this.updateEnvironment(adopted, envName, values);
|
|
127461
|
+
return adopted;
|
|
127462
|
+
}
|
|
127463
|
+
throw error2;
|
|
127464
|
+
}
|
|
127465
|
+
});
|
|
127380
127466
|
}
|
|
127381
127467
|
/**
|
|
127382
127468
|
* Update an existing environment through the sync service.
|
|
@@ -127406,7 +127492,7 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127406
127492
|
path: `/environment/${id}`,
|
|
127407
127493
|
body
|
|
127408
127494
|
}),
|
|
127409
|
-
{ maxAttempts: 5, delayMs: 2e3, backoffMultiplier: 2, maxDelayMs: 15e3, shouldRetry: (e) => this.
|
|
127495
|
+
{ maxAttempts: 5, delayMs: 2e3, backoffMultiplier: 2, maxDelayMs: 15e3, shouldRetry: (e) => this.isRetryableIdempotentWriteOutcome(e) }
|
|
127410
127496
|
);
|
|
127411
127497
|
}
|
|
127412
127498
|
/**
|
|
@@ -127430,13 +127516,37 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127430
127516
|
*/
|
|
127431
127517
|
async listEnvironments(workspaceId) {
|
|
127432
127518
|
const ws = workspaceId || this.workspaceId;
|
|
127433
|
-
const response = await this.gateway.requestJson(
|
|
127434
|
-
|
|
127435
|
-
|
|
127436
|
-
|
|
127437
|
-
|
|
127519
|
+
const response = await this.gateway.requestJson(
|
|
127520
|
+
{
|
|
127521
|
+
service: "sync",
|
|
127522
|
+
method: "post",
|
|
127523
|
+
path: `/list/environment?workspace=${ws}`
|
|
127524
|
+
},
|
|
127525
|
+
{ retryTransient: true }
|
|
127526
|
+
);
|
|
127438
127527
|
const items = Array.isArray(response?.data) ? response.data : [];
|
|
127439
|
-
return items.map((raw) => this.asRecord(raw)).filter((e) => e !== null).map((e) =>
|
|
127528
|
+
return items.map((raw) => this.asRecord(raw)).filter((e) => e !== null).map((e) => {
|
|
127529
|
+
const bareOrPublic = this.idOf(e);
|
|
127530
|
+
return {
|
|
127531
|
+
name: String(e.name ?? ""),
|
|
127532
|
+
uid: this.publicEnvironmentUid(e, bareOrPublic)
|
|
127533
|
+
};
|
|
127534
|
+
});
|
|
127535
|
+
}
|
|
127536
|
+
/** Exact name match within a workspace. Prefer tracked UIDs before calling. */
|
|
127537
|
+
async findEnvironmentByName(workspaceId, name) {
|
|
127538
|
+
const want = String(name ?? "").trim();
|
|
127539
|
+
if (!want) {
|
|
127540
|
+
return null;
|
|
127541
|
+
}
|
|
127542
|
+
const environments = await this.listEnvironments(workspaceId);
|
|
127543
|
+
const matches = environments.filter((entry) => entry.name === want);
|
|
127544
|
+
const match = this.selectExactMatch(
|
|
127545
|
+
"environment",
|
|
127546
|
+
`workspace ${workspaceId} and name "${want}"`,
|
|
127547
|
+
matches
|
|
127548
|
+
);
|
|
127549
|
+
return match?.uid ? { uid: match.uid, name: match.name } : null;
|
|
127440
127550
|
}
|
|
127441
127551
|
// --- collection read (service: collection, v3 export) ---
|
|
127442
127552
|
//
|
|
@@ -127466,32 +127576,51 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127466
127576
|
// --- mocks (service: mock) ---
|
|
127467
127577
|
async createMock(workspaceId, name, collectionUid, environmentUid) {
|
|
127468
127578
|
const ws = workspaceId || this.workspaceId;
|
|
127579
|
+
const mockName = String(name ?? "").trim();
|
|
127469
127580
|
const collection = String(collectionUid ?? "").trim();
|
|
127470
127581
|
const environment = String(environmentUid ?? "").trim();
|
|
127471
|
-
const
|
|
127472
|
-
|
|
127473
|
-
collection,
|
|
127474
|
-
|
|
127475
|
-
|
|
127476
|
-
|
|
127477
|
-
|
|
127478
|
-
|
|
127479
|
-
|
|
127480
|
-
|
|
127481
|
-
|
|
127482
|
-
|
|
127483
|
-
|
|
127484
|
-
|
|
127485
|
-
|
|
127486
|
-
|
|
127487
|
-
|
|
127488
|
-
|
|
127489
|
-
|
|
127490
|
-
|
|
127491
|
-
|
|
127492
|
-
|
|
127493
|
-
|
|
127494
|
-
|
|
127582
|
+
const flightKey = `mock:${ws}:${collection}:${environment}:${mockName}`;
|
|
127583
|
+
return this.singleFlight(flightKey, flightKey, "mock", async () => {
|
|
127584
|
+
const existing = await this.findMockByCollection(collection, environment, mockName);
|
|
127585
|
+
if (existing) {
|
|
127586
|
+
return { uid: existing.uid, url: existing.mockUrl };
|
|
127587
|
+
}
|
|
127588
|
+
const body = {
|
|
127589
|
+
name: mockName,
|
|
127590
|
+
collection,
|
|
127591
|
+
private: false,
|
|
127592
|
+
...environment ? { environment } : {}
|
|
127593
|
+
};
|
|
127594
|
+
try {
|
|
127595
|
+
const response = await this.gateway.requestJson(
|
|
127596
|
+
{
|
|
127597
|
+
service: "mock",
|
|
127598
|
+
method: "post",
|
|
127599
|
+
path: `/mocks?workspace=${ws}`,
|
|
127600
|
+
body
|
|
127601
|
+
},
|
|
127602
|
+
{ retryTransient: false }
|
|
127603
|
+
);
|
|
127604
|
+
const record = this.dataOf(response);
|
|
127605
|
+
const uid = this.idOf(record);
|
|
127606
|
+
if (!uid) {
|
|
127607
|
+
throw new Error("Mock create did not return a UID");
|
|
127608
|
+
}
|
|
127609
|
+
return {
|
|
127610
|
+
uid,
|
|
127611
|
+
url: String(record?.url ?? record?.mockUrl ?? "").trim()
|
|
127612
|
+
};
|
|
127613
|
+
} catch (error2) {
|
|
127614
|
+
const adopted = await this.discoverAfterAmbiguousCreate(
|
|
127615
|
+
() => this.findMockByCollection(collection, environment, mockName),
|
|
127616
|
+
error2
|
|
127617
|
+
);
|
|
127618
|
+
if (adopted) {
|
|
127619
|
+
return { uid: adopted.uid, url: adopted.mockUrl };
|
|
127620
|
+
}
|
|
127621
|
+
throw error2;
|
|
127622
|
+
}
|
|
127623
|
+
});
|
|
127495
127624
|
}
|
|
127496
127625
|
async listMocks() {
|
|
127497
127626
|
const response = await this.gateway.requestJson({
|
|
@@ -127520,10 +127649,19 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127520
127649
|
return false;
|
|
127521
127650
|
}
|
|
127522
127651
|
}
|
|
127523
|
-
async findMockByCollection(collectionUid) {
|
|
127652
|
+
async findMockByCollection(collectionUid, environmentUid, name) {
|
|
127524
127653
|
const mocks = await this.listMocks();
|
|
127525
127654
|
const want = String(collectionUid ?? "").trim();
|
|
127526
|
-
const
|
|
127655
|
+
const environment = String(environmentUid ?? "").trim();
|
|
127656
|
+
const mockName = String(name ?? "").trim();
|
|
127657
|
+
const matches = mocks.filter(
|
|
127658
|
+
(mock) => mock.collection === want && mock.environment === environment && mock.name === mockName
|
|
127659
|
+
);
|
|
127660
|
+
const match = this.selectExactMatch(
|
|
127661
|
+
"mock",
|
|
127662
|
+
`workspace ${this.workspaceId}, name "${mockName}", collection ${want}, and environment ${environment || "(none)"}`,
|
|
127663
|
+
matches
|
|
127664
|
+
);
|
|
127527
127665
|
return match ? { uid: match.uid, mockUrl: match.mockUrl } : null;
|
|
127528
127666
|
}
|
|
127529
127667
|
// --- monitors (service: monitors; collection-based = jobTemplates) ---
|
|
@@ -127540,32 +127678,51 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127540
127678
|
async createMonitor(workspaceId, name, collectionUid, environmentUid, cronSchedule) {
|
|
127541
127679
|
const ws = workspaceId || this.workspaceId;
|
|
127542
127680
|
const effectiveCron = cronSchedule && cronSchedule.trim() ? cronSchedule.trim() : "0 0 * * 0";
|
|
127681
|
+
const monitorName = String(name ?? "").trim();
|
|
127543
127682
|
const collection = String(collectionUid ?? "").trim();
|
|
127544
127683
|
const environment = String(environmentUid ?? "").trim();
|
|
127545
|
-
const
|
|
127546
|
-
|
|
127547
|
-
collection,
|
|
127548
|
-
|
|
127549
|
-
|
|
127550
|
-
|
|
127551
|
-
|
|
127552
|
-
|
|
127553
|
-
|
|
127554
|
-
|
|
127555
|
-
|
|
127556
|
-
|
|
127557
|
-
|
|
127558
|
-
|
|
127559
|
-
|
|
127560
|
-
|
|
127561
|
-
|
|
127562
|
-
|
|
127563
|
-
|
|
127564
|
-
|
|
127565
|
-
|
|
127566
|
-
|
|
127567
|
-
|
|
127568
|
-
|
|
127684
|
+
const flightKey = `monitor:${ws}:${collection}:${environment}:${monitorName}`;
|
|
127685
|
+
return this.singleFlight(flightKey, effectiveCron, "monitor", async () => {
|
|
127686
|
+
const existing = await this.findMonitorByCollection(collection, environment, monitorName);
|
|
127687
|
+
if (existing?.uid) {
|
|
127688
|
+
return existing.uid;
|
|
127689
|
+
}
|
|
127690
|
+
const body = {
|
|
127691
|
+
name: monitorName,
|
|
127692
|
+
collection,
|
|
127693
|
+
options: { strictSSL: false, followRedirects: true, requestTimeout: null, requestDelay: 0 },
|
|
127694
|
+
notifications: { onFailure: [], onError: [] },
|
|
127695
|
+
retry: {},
|
|
127696
|
+
schedule: { cronPattern: effectiveCron, timeZone: "UTC" },
|
|
127697
|
+
distribution: null,
|
|
127698
|
+
...environment ? { environment } : {}
|
|
127699
|
+
};
|
|
127700
|
+
try {
|
|
127701
|
+
const response = await this.gateway.requestJson(
|
|
127702
|
+
{
|
|
127703
|
+
service: "monitors",
|
|
127704
|
+
method: "post",
|
|
127705
|
+
path: `/jobTemplates?workspace=${ws}`,
|
|
127706
|
+
body
|
|
127707
|
+
},
|
|
127708
|
+
{ retryTransient: false }
|
|
127709
|
+
);
|
|
127710
|
+
const uid = this.idOf(this.dataOf(response));
|
|
127711
|
+
if (!uid) {
|
|
127712
|
+
throw new Error("Monitor create did not return a UID");
|
|
127713
|
+
}
|
|
127714
|
+
return uid;
|
|
127715
|
+
} catch (error2) {
|
|
127716
|
+
const adopted = await this.discoverAfterAmbiguousCreate(
|
|
127717
|
+
() => this.findMonitorByCollection(collection, environment, monitorName),
|
|
127718
|
+
error2
|
|
127719
|
+
);
|
|
127720
|
+
if (adopted?.uid) {
|
|
127721
|
+
return adopted.uid;
|
|
127722
|
+
}
|
|
127723
|
+
throw error2;
|
|
127724
|
+
}
|
|
127725
|
+
});
|
|
127569
127726
|
}
|
|
127570
127727
|
async listMonitors() {
|
|
127571
127728
|
const response = await this.gateway.requestJson({
|
|
@@ -127588,24 +127745,30 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127588
127745
|
return false;
|
|
127589
127746
|
}
|
|
127590
127747
|
}
|
|
127591
|
-
async findMonitorByCollection(collectionUid) {
|
|
127748
|
+
async findMonitorByCollection(collectionUid, environmentUid, name) {
|
|
127592
127749
|
const want = String(collectionUid ?? "").trim();
|
|
127593
|
-
const
|
|
127594
|
-
|
|
127595
|
-
|
|
127596
|
-
|
|
127597
|
-
|
|
127598
|
-
|
|
127599
|
-
const
|
|
127600
|
-
|
|
127750
|
+
const environment = String(environmentUid ?? "").trim();
|
|
127751
|
+
const monitorName = String(name ?? "").trim();
|
|
127752
|
+
const monitors = await this.listMonitors();
|
|
127753
|
+
const matches = monitors.filter(
|
|
127754
|
+
(monitor) => monitor.collectionUid === want && monitor.environmentUid === environment && monitor.name === monitorName
|
|
127755
|
+
);
|
|
127756
|
+
const match = this.selectExactMatch(
|
|
127757
|
+
"monitor",
|
|
127758
|
+
`workspace ${this.workspaceId}, name "${monitorName}", collection ${want}, and environment ${environment || "(none)"}`,
|
|
127759
|
+
matches
|
|
127760
|
+
);
|
|
127601
127761
|
return match?.uid ? { uid: match.uid, name: match.name } : null;
|
|
127602
127762
|
}
|
|
127603
127763
|
async runMonitor(uid) {
|
|
127604
|
-
await this.gateway.requestJson(
|
|
127605
|
-
|
|
127606
|
-
|
|
127607
|
-
|
|
127608
|
-
|
|
127764
|
+
await this.gateway.requestJson(
|
|
127765
|
+
{
|
|
127766
|
+
service: "monitors",
|
|
127767
|
+
method: "post",
|
|
127768
|
+
path: `/jobTemplates/${uid}/jobs`
|
|
127769
|
+
},
|
|
127770
|
+
{ retryTransient: false }
|
|
127771
|
+
);
|
|
127609
127772
|
}
|
|
127610
127773
|
};
|
|
127611
127774
|
|
|
@@ -127771,12 +127934,8 @@ async function mintAccessTokenIfNeeded(inputs, log, setSecret2, fetchImpl = fetc
|
|
|
127771
127934
|
function isExpiredAuthError(status, body) {
|
|
127772
127935
|
return status === 401 || body.includes("UNAUTHENTICATED") || body.includes("authenticationError");
|
|
127773
127936
|
}
|
|
127774
|
-
function
|
|
127775
|
-
|
|
127776
|
-
if (status >= 500 && (body.includes("ESOCKETTIMEDOUT") || body.includes("ETIMEDOUT") || body.includes("ECONNRESET") || body.includes("serverError") || body.includes("downstream"))) {
|
|
127777
|
-
return true;
|
|
127778
|
-
}
|
|
127779
|
-
return false;
|
|
127937
|
+
function isRetryableSafeReadResponse(status) {
|
|
127938
|
+
return status === 408 || status === 429 || status >= 500;
|
|
127780
127939
|
}
|
|
127781
127940
|
function defaultSleep(ms) {
|
|
127782
127941
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
@@ -127835,14 +127994,28 @@ var AccessTokenGatewayClient = class {
|
|
|
127835
127994
|
}
|
|
127836
127995
|
/**
|
|
127837
127996
|
* Send a gateway request, refreshing the token once on an auth failure and
|
|
127838
|
-
* retrying transient downstream failures (5xx / Bifrost read
|
|
127839
|
-
* exponential backoff.
|
|
127840
|
-
*
|
|
127997
|
+
* optionally retrying transient downstream failures (5xx / Bifrost read
|
|
127998
|
+
* timeouts) with exponential backoff. Safe reads keep transient retries;
|
|
127999
|
+
* unsafe creates pass `{ retryTransient: false }` and reconcile after an
|
|
128000
|
+
* ambiguous response instead of re-POSTing. Auth refresh remains independent
|
|
128001
|
+
* of the transient-retry budget.
|
|
127841
128002
|
*/
|
|
127842
|
-
async request(request) {
|
|
128003
|
+
async request(request, options = {}) {
|
|
128004
|
+
const retryTransient = options.retryTransient ?? request.method === "get";
|
|
127843
128005
|
let attempt = 0;
|
|
127844
128006
|
for (; ; ) {
|
|
127845
|
-
let response
|
|
128007
|
+
let response;
|
|
128008
|
+
try {
|
|
128009
|
+
response = await this.send(request);
|
|
128010
|
+
} catch (error2) {
|
|
128011
|
+
if (retryTransient && attempt < this.maxRetries) {
|
|
128012
|
+
const delay = this.retryBaseDelayMs * 2 ** attempt;
|
|
128013
|
+
attempt += 1;
|
|
128014
|
+
await this.sleepImpl(delay);
|
|
128015
|
+
continue;
|
|
128016
|
+
}
|
|
128017
|
+
throw error2;
|
|
128018
|
+
}
|
|
127846
128019
|
if (response.ok) {
|
|
127847
128020
|
return response;
|
|
127848
128021
|
}
|
|
@@ -127856,7 +128029,7 @@ var AccessTokenGatewayClient = class {
|
|
|
127856
128029
|
const retryBody = await response.text().catch(() => "");
|
|
127857
128030
|
throw this.toHttpError(request, response, retryBody);
|
|
127858
128031
|
}
|
|
127859
|
-
if (
|
|
128032
|
+
if (retryTransient && isRetryableSafeReadResponse(response.status) && attempt < this.maxRetries) {
|
|
127860
128033
|
const delay = this.retryBaseDelayMs * 2 ** attempt;
|
|
127861
128034
|
attempt += 1;
|
|
127862
128035
|
await this.sleepImpl(delay);
|
|
@@ -127866,8 +128039,8 @@ var AccessTokenGatewayClient = class {
|
|
|
127866
128039
|
}
|
|
127867
128040
|
}
|
|
127868
128041
|
/** Send a gateway request and parse the JSON body, or null when empty. */
|
|
127869
|
-
async requestJson(request) {
|
|
127870
|
-
const response = await this.request(request);
|
|
128042
|
+
async requestJson(request, options = {}) {
|
|
128043
|
+
const response = await this.request(request, options);
|
|
127871
128044
|
const text = await response.text().catch(() => "");
|
|
127872
128045
|
if (!text.trim()) {
|
|
127873
128046
|
return null;
|
|
@@ -128459,18 +128632,28 @@ async function upsertEnvironments(inputs, dependencies, resourcesState) {
|
|
|
128459
128632
|
for (const envName of inputs.environments) {
|
|
128460
128633
|
const runtimeUrl = String(inputs.envRuntimeUrls[envName] || "").trim();
|
|
128461
128634
|
const values = buildEnvironmentValues(envName, runtimeUrl);
|
|
128462
|
-
const
|
|
128463
|
-
|
|
128464
|
-
|
|
128465
|
-
|
|
128466
|
-
|
|
128467
|
-
|
|
128635
|
+
const displayName = `${inputs.projectName} - ${envName}`;
|
|
128636
|
+
let existingUid = String(envUids[envName] || "").trim();
|
|
128637
|
+
if (!existingUid) {
|
|
128638
|
+
const discovered = await dependencies.postman.findEnvironmentByName(
|
|
128639
|
+
inputs.workspaceId,
|
|
128640
|
+
displayName
|
|
128468
128641
|
);
|
|
128642
|
+
if (discovered?.uid) {
|
|
128643
|
+
existingUid = discovered.uid;
|
|
128644
|
+
dependencies.core.info(
|
|
128645
|
+
`Discovered existing environment for ${displayName}: ${existingUid}`
|
|
128646
|
+
);
|
|
128647
|
+
}
|
|
128648
|
+
}
|
|
128649
|
+
if (existingUid) {
|
|
128650
|
+
await dependencies.postman.updateEnvironment(existingUid, displayName, values);
|
|
128651
|
+
envUids[envName] = existingUid;
|
|
128469
128652
|
continue;
|
|
128470
128653
|
}
|
|
128471
128654
|
envUids[envName] = await dependencies.postman.createEnvironment(
|
|
128472
128655
|
inputs.workspaceId,
|
|
128473
|
-
|
|
128656
|
+
displayName,
|
|
128474
128657
|
values
|
|
128475
128658
|
);
|
|
128476
128659
|
}
|
|
@@ -128841,12 +129024,17 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
128841
129024
|
const mockEnvUid = envUids.dev || envUids.prod || Object.values(envUids)[0];
|
|
128842
129025
|
if (mockEnvUid) {
|
|
128843
129026
|
let resolvedMockUrl = "";
|
|
129027
|
+
const mockName = `${assetProjectName} Mock`;
|
|
128844
129028
|
if (inputs.mockUrl) {
|
|
128845
129029
|
resolvedMockUrl = inputs.mockUrl;
|
|
128846
129030
|
dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
|
|
128847
129031
|
}
|
|
128848
129032
|
if (!resolvedMockUrl && inputs.baselineCollectionId) {
|
|
128849
|
-
const discovered = await dependencies.postman.findMockByCollection(
|
|
129033
|
+
const discovered = await dependencies.postman.findMockByCollection(
|
|
129034
|
+
inputs.baselineCollectionId,
|
|
129035
|
+
mockEnvUid,
|
|
129036
|
+
mockName
|
|
129037
|
+
);
|
|
128850
129038
|
if (discovered) {
|
|
128851
129039
|
resolvedMockUrl = discovered.mockUrl;
|
|
128852
129040
|
dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
|
|
@@ -128855,7 +129043,7 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
128855
129043
|
if (!resolvedMockUrl) {
|
|
128856
129044
|
const mock = await dependencies.postman.createMock(
|
|
128857
129045
|
inputs.workspaceId,
|
|
128858
|
-
|
|
129046
|
+
mockName,
|
|
128859
129047
|
inputs.baselineCollectionId,
|
|
128860
129048
|
mockEnvUid
|
|
128861
129049
|
);
|
|
@@ -128870,6 +129058,7 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
128870
129058
|
const effectiveCron = inputs.monitorCron && inputs.monitorCron.trim() ? inputs.monitorCron.trim() : "";
|
|
128871
129059
|
if (monitorEnvUid && inputs.monitorType !== "cli") {
|
|
128872
129060
|
let resolvedMonitorId = "";
|
|
129061
|
+
const monitorName = `${assetProjectName} - Smoke Monitor`;
|
|
128873
129062
|
if (inputs.monitorId) {
|
|
128874
129063
|
const valid = await dependencies.postman.monitorExists(inputs.monitorId);
|
|
128875
129064
|
if (valid) {
|
|
@@ -128880,7 +129069,11 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
128880
129069
|
}
|
|
128881
129070
|
}
|
|
128882
129071
|
if (!resolvedMonitorId && inputs.smokeCollectionId) {
|
|
128883
|
-
const discovered = await dependencies.postman.findMonitorByCollection(
|
|
129072
|
+
const discovered = await dependencies.postman.findMonitorByCollection(
|
|
129073
|
+
inputs.smokeCollectionId,
|
|
129074
|
+
monitorEnvUid,
|
|
129075
|
+
monitorName
|
|
129076
|
+
);
|
|
128884
129077
|
if (discovered) {
|
|
128885
129078
|
resolvedMonitorId = discovered.uid;
|
|
128886
129079
|
dependencies.core.info(`Discovered existing monitor for collection ${inputs.smokeCollectionId}: ${resolvedMonitorId}`);
|
|
@@ -128889,7 +129082,7 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
128889
129082
|
if (!resolvedMonitorId) {
|
|
128890
129083
|
resolvedMonitorId = await dependencies.postman.createMonitor(
|
|
128891
129084
|
inputs.workspaceId,
|
|
128892
|
-
|
|
129085
|
+
monitorName,
|
|
128893
129086
|
inputs.smokeCollectionId,
|
|
128894
129087
|
monitorEnvUid,
|
|
128895
129088
|
effectiveCron || void 0
|
|
@@ -129102,6 +129295,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
129102
129295
|
createEnvironment: gatewayAssets.createEnvironment.bind(gatewayAssets),
|
|
129103
129296
|
getEnvironment: gatewayAssets.getEnvironment.bind(gatewayAssets),
|
|
129104
129297
|
updateEnvironment: gatewayAssets.updateEnvironment.bind(gatewayAssets),
|
|
129298
|
+
findEnvironmentByName: gatewayAssets.findEnvironmentByName.bind(gatewayAssets),
|
|
129105
129299
|
// Collection read via the v3 export endpoint — returns canonical v3 IR,
|
|
129106
129300
|
// written to disk by `convertAndSplitAnyCollection`. PMAK is never used for
|
|
129107
129301
|
// collection reads.
|