@postman-cse/onboarding-repo-sync 2.1.6 → 2.1.8
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/dist/action.cjs +281 -47
- package/dist/cli.cjs +281 -47
- package/dist/index.cjs +281 -47
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -123217,12 +123217,14 @@ var POSTMAN_ENDPOINT_PROFILES = {
|
|
|
123217
123217
|
prod: {
|
|
123218
123218
|
apiBaseUrl: "https://api.getpostman.com",
|
|
123219
123219
|
bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
|
|
123220
|
+
fallbackBaseUrl: "https://go.postman.co/_api",
|
|
123220
123221
|
cliInstallUrl: "https://dl-cli.pstmn.io/install/unix.sh",
|
|
123221
123222
|
iapubBaseUrl: "https://iapub.postman.co"
|
|
123222
123223
|
},
|
|
123223
123224
|
beta: {
|
|
123224
123225
|
apiBaseUrl: "https://api.getpostman-beta.com",
|
|
123225
123226
|
bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
|
|
123227
|
+
fallbackBaseUrl: "https://go.postman-beta.co/_api",
|
|
123226
123228
|
cliInstallUrl: "https://dl-cli.pstmn-beta.io/install/unix.sh",
|
|
123227
123229
|
iapubBaseUrl: "https://iapub.postman.co"
|
|
123228
123230
|
}
|
|
@@ -124996,7 +124998,85 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
124996
124998
|
throw advised ?? httpErr;
|
|
124997
124999
|
}
|
|
124998
125000
|
}
|
|
124999
|
-
|
|
125001
|
+
/**
|
|
125002
|
+
* Probe who (if anyone) already owns the global `(repo, path)` filesystem
|
|
125003
|
+
* link. Non-fatal: unexpected statuses / network errors yield `unknown` so
|
|
125004
|
+
* callers can proceed and rely on reactive POST conflict handling.
|
|
125005
|
+
*
|
|
125006
|
+
* Bifrost states (FileSystemController.fetchWorkspaceForFileSystem):
|
|
125007
|
+
* - 200 + data null -> free
|
|
125008
|
+
* - 200 + data -> linked-visible (workspace payload)
|
|
125009
|
+
* - 403 + error.meta.workspaceId -> linked-invisible
|
|
125010
|
+
* - 200 + error.meta.workspaceId -> linked-invisible (proxy envelope)
|
|
125011
|
+
*/
|
|
125012
|
+
async findWorkspaceForRepo(repoUrl, path5 = "/") {
|
|
125013
|
+
const fsPath = path5 && path5.trim() ? path5.trim() : "/";
|
|
125014
|
+
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
125015
|
+
const payload = {
|
|
125016
|
+
service: "workspaces",
|
|
125017
|
+
method: "GET",
|
|
125018
|
+
path: `/workspaces/filesystem?repo=${encodeURIComponent(repoUrl)}&path=${encodeURIComponent(fsPath)}`
|
|
125019
|
+
};
|
|
125020
|
+
try {
|
|
125021
|
+
const response = await this.fetchImpl(url, {
|
|
125022
|
+
method: "POST",
|
|
125023
|
+
headers: this.bifrostHeaders(),
|
|
125024
|
+
body: JSON.stringify(payload)
|
|
125025
|
+
});
|
|
125026
|
+
let parsed = {};
|
|
125027
|
+
try {
|
|
125028
|
+
parsed = await response.json();
|
|
125029
|
+
} catch {
|
|
125030
|
+
return {
|
|
125031
|
+
state: "unknown",
|
|
125032
|
+
reason: `filesystem lookup returned non-JSON body (HTTP ${response.status})`
|
|
125033
|
+
};
|
|
125034
|
+
}
|
|
125035
|
+
const errorMetaWorkspaceId = typeof parsed?.error?.meta?.workspaceId === "string" && parsed.error.meta.workspaceId.trim() ? parsed.error.meta.workspaceId.trim() : void 0;
|
|
125036
|
+
if (errorMetaWorkspaceId) {
|
|
125037
|
+
return { state: "linked-invisible", workspaceId: errorMetaWorkspaceId };
|
|
125038
|
+
}
|
|
125039
|
+
if (response.ok) {
|
|
125040
|
+
if (parsed?.data == null) {
|
|
125041
|
+
return { state: "free" };
|
|
125042
|
+
}
|
|
125043
|
+
const id = typeof parsed.data.id === "string" ? parsed.data.id.trim() : "";
|
|
125044
|
+
if (!id) {
|
|
125045
|
+
return {
|
|
125046
|
+
state: "unknown",
|
|
125047
|
+
reason: "filesystem lookup returned 200 without a workspace id"
|
|
125048
|
+
};
|
|
125049
|
+
}
|
|
125050
|
+
const name = typeof parsed.data.name === "string" && parsed.data.name.trim() ? parsed.data.name.trim() : void 0;
|
|
125051
|
+
return {
|
|
125052
|
+
state: "linked-visible",
|
|
125053
|
+
workspace: name ? { id, name } : { id }
|
|
125054
|
+
};
|
|
125055
|
+
}
|
|
125056
|
+
if (response.status === 403) {
|
|
125057
|
+
const workspaceId = extractDuplicateWorkspaceId(
|
|
125058
|
+
JSON.stringify(parsed)
|
|
125059
|
+
);
|
|
125060
|
+
if (workspaceId) {
|
|
125061
|
+
return { state: "linked-invisible", workspaceId };
|
|
125062
|
+
}
|
|
125063
|
+
return {
|
|
125064
|
+
state: "unknown",
|
|
125065
|
+
reason: "filesystem lookup returned 403 without error.meta.workspaceId"
|
|
125066
|
+
};
|
|
125067
|
+
}
|
|
125068
|
+
return {
|
|
125069
|
+
state: "unknown",
|
|
125070
|
+
reason: `filesystem lookup returned HTTP ${response.status}`
|
|
125071
|
+
};
|
|
125072
|
+
} catch (error) {
|
|
125073
|
+
return {
|
|
125074
|
+
state: "unknown",
|
|
125075
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
125076
|
+
};
|
|
125077
|
+
}
|
|
125078
|
+
}
|
|
125079
|
+
async connectWorkspaceToRepository(workspaceId, repoUrl, options) {
|
|
125000
125080
|
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
125001
125081
|
const payload = {
|
|
125002
125082
|
service: "workspaces",
|
|
@@ -125023,6 +125103,11 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
125023
125103
|
if (isDuplicate) {
|
|
125024
125104
|
const existingWorkspaceId = extractDuplicateWorkspaceId(body);
|
|
125025
125105
|
if (existingWorkspaceId && existingWorkspaceId !== workspaceId) {
|
|
125106
|
+
if (options?.preflightWasFree) {
|
|
125107
|
+
throw new Error(
|
|
125108
|
+
`REPOSITORY_LINK_CONFLICT_UNRESOLVED: Preflight found no active owner, but link creation reported workspace ${existingWorkspaceId}. Stop and contact Postman support; do not alter the repository URL.`
|
|
125109
|
+
);
|
|
125110
|
+
}
|
|
125026
125111
|
throw new Error(
|
|
125027
125112
|
await this.describeWorkspaceLinkConflict(existingWorkspaceId, workspaceId, repoUrl)
|
|
125028
125113
|
);
|
|
@@ -125690,6 +125775,14 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125690
125775
|
createFlights.set(key, { fingerprint, promise: pending });
|
|
125691
125776
|
return pending;
|
|
125692
125777
|
}
|
|
125778
|
+
/**
|
|
125779
|
+
* Reconcile an ambiguous create. Returns the adopted match, `undefined`
|
|
125780
|
+
* when every discovery read succeeded and found nothing (the create is
|
|
125781
|
+
* conclusively absent, so a fallback resend cannot duplicate), or `null`
|
|
125782
|
+
* when the outcome is inconclusive (non-ambiguous error, or a discovery
|
|
125783
|
+
* read itself failed — in that case a resend could duplicate a committed
|
|
125784
|
+
* twin and must not fire).
|
|
125785
|
+
*/
|
|
125693
125786
|
async discoverAfterAmbiguousCreate(discover, error) {
|
|
125694
125787
|
if (!this.isAmbiguousCreateOutcome(error)) {
|
|
125695
125788
|
return null;
|
|
@@ -125698,12 +125791,31 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125698
125791
|
if (attempt > 0) {
|
|
125699
125792
|
await this.sleep(this.reconcileDelayMs);
|
|
125700
125793
|
}
|
|
125701
|
-
|
|
125794
|
+
let found;
|
|
125795
|
+
try {
|
|
125796
|
+
found = await discover();
|
|
125797
|
+
} catch {
|
|
125798
|
+
return null;
|
|
125799
|
+
}
|
|
125702
125800
|
if (found) {
|
|
125703
125801
|
return found;
|
|
125704
125802
|
}
|
|
125705
125803
|
}
|
|
125706
|
-
return
|
|
125804
|
+
return void 0;
|
|
125805
|
+
}
|
|
125806
|
+
/**
|
|
125807
|
+
* After an ambiguous create failed AND discovery proved the asset absent,
|
|
125808
|
+
* re-attempt the create once with the cold `/_api` fallback enabled: the
|
|
125809
|
+
* reconcile above guarantees no committed twin, so the resend cannot
|
|
125810
|
+
* duplicate. Returns null when the resend also fails (caller rethrows the
|
|
125811
|
+
* original error).
|
|
125812
|
+
*/
|
|
125813
|
+
async resendAbsentCreate(operation) {
|
|
125814
|
+
try {
|
|
125815
|
+
return await operation();
|
|
125816
|
+
} catch {
|
|
125817
|
+
return null;
|
|
125818
|
+
}
|
|
125707
125819
|
}
|
|
125708
125820
|
publicEnvironmentUid(data, bareId) {
|
|
125709
125821
|
const owner = String(data?.owner ?? "").trim();
|
|
@@ -125751,17 +125863,18 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125751
125863
|
name: envName,
|
|
125752
125864
|
values: normalizedValues
|
|
125753
125865
|
};
|
|
125866
|
+
const send2 = (fallback) => this.gateway.requestJson(
|
|
125867
|
+
{
|
|
125868
|
+
service: "sync",
|
|
125869
|
+
method: "post",
|
|
125870
|
+
path: `/environment/import?workspace=${ws}`,
|
|
125871
|
+
body,
|
|
125872
|
+
...fallback ? { fallback } : {}
|
|
125873
|
+
},
|
|
125874
|
+
{ retryTransient: false }
|
|
125875
|
+
);
|
|
125754
125876
|
try {
|
|
125755
|
-
const
|
|
125756
|
-
{
|
|
125757
|
-
service: "sync",
|
|
125758
|
-
method: "post",
|
|
125759
|
-
path: `/environment/import?workspace=${ws}`,
|
|
125760
|
-
body
|
|
125761
|
-
},
|
|
125762
|
-
{ retryTransient: false }
|
|
125763
|
-
);
|
|
125764
|
-
const data = this.dataOf(response);
|
|
125877
|
+
const data = this.dataOf(await send2());
|
|
125765
125878
|
const bareId = this.idOf(data);
|
|
125766
125879
|
if (!bareId) {
|
|
125767
125880
|
throw new Error("Environment import did not return a UID");
|
|
@@ -125776,6 +125889,15 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125776
125889
|
await this.updateEnvironment(adopted, envName, values);
|
|
125777
125890
|
return adopted;
|
|
125778
125891
|
}
|
|
125892
|
+
if (adopted === void 0) {
|
|
125893
|
+
const retried = await this.resendAbsentCreate(async () => {
|
|
125894
|
+
const data = this.dataOf(await send2("auto"));
|
|
125895
|
+
const bareId = this.idOf(data);
|
|
125896
|
+
if (!bareId) throw new Error("Environment import did not return a UID");
|
|
125897
|
+
return this.publicEnvironmentUid(data, bareId);
|
|
125898
|
+
});
|
|
125899
|
+
if (retried) return retried;
|
|
125900
|
+
}
|
|
125779
125901
|
throw error;
|
|
125780
125902
|
}
|
|
125781
125903
|
});
|
|
@@ -125907,19 +126029,20 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125907
126029
|
private: false,
|
|
125908
126030
|
...environment ? { environment } : {}
|
|
125909
126031
|
};
|
|
125910
|
-
|
|
125911
|
-
|
|
125912
|
-
|
|
125913
|
-
|
|
125914
|
-
|
|
125915
|
-
|
|
125916
|
-
|
|
125917
|
-
|
|
125918
|
-
|
|
125919
|
-
|
|
125920
|
-
|
|
125921
|
-
|
|
125922
|
-
|
|
126032
|
+
const send2 = (fallback) => this.gateway.requestJson(
|
|
126033
|
+
{
|
|
126034
|
+
service: "mock",
|
|
126035
|
+
method: "post",
|
|
126036
|
+
path: `/mocks?workspace=${ws}`,
|
|
126037
|
+
body,
|
|
126038
|
+
...fallback ? { fallback } : {}
|
|
126039
|
+
},
|
|
126040
|
+
// Unsafe create: never blind re-POST. An ESOCKETTIMEDOUT after accept
|
|
126041
|
+
// may still have created the mock; reconcile via discovery below and
|
|
126042
|
+
// let the orchestrator retry the whole create-or-adopt cycle.
|
|
126043
|
+
{ retryTransient: false }
|
|
126044
|
+
);
|
|
126045
|
+
const parseMock = (response) => {
|
|
125923
126046
|
const record = this.dataOf(response);
|
|
125924
126047
|
const uid = this.idOf(record);
|
|
125925
126048
|
if (!uid) {
|
|
@@ -125929,6 +126052,9 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125929
126052
|
uid,
|
|
125930
126053
|
url: String(record?.url ?? record?.mockUrl ?? "").trim()
|
|
125931
126054
|
};
|
|
126055
|
+
};
|
|
126056
|
+
try {
|
|
126057
|
+
return parseMock(await send2());
|
|
125932
126058
|
} catch (error) {
|
|
125933
126059
|
const adopted = await this.discoverAfterAmbiguousCreate(
|
|
125934
126060
|
() => this.findMockByCollection(collection, environment, mockName),
|
|
@@ -125937,6 +126063,10 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125937
126063
|
if (adopted) {
|
|
125938
126064
|
return { uid: adopted.uid, url: adopted.mockUrl };
|
|
125939
126065
|
}
|
|
126066
|
+
if (adopted === void 0) {
|
|
126067
|
+
const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
|
|
126068
|
+
if (retried) return retried;
|
|
126069
|
+
}
|
|
125940
126070
|
throw error;
|
|
125941
126071
|
}
|
|
125942
126072
|
});
|
|
@@ -126043,21 +126173,25 @@ var PostmanGatewayAssetsClient = class {
|
|
|
126043
126173
|
distribution: null,
|
|
126044
126174
|
...environment ? { environment } : {}
|
|
126045
126175
|
};
|
|
126046
|
-
|
|
126047
|
-
|
|
126048
|
-
|
|
126049
|
-
|
|
126050
|
-
|
|
126051
|
-
|
|
126052
|
-
|
|
126053
|
-
|
|
126054
|
-
|
|
126055
|
-
|
|
126176
|
+
const send2 = (fallback) => this.gateway.requestJson(
|
|
126177
|
+
{
|
|
126178
|
+
service: "monitors",
|
|
126179
|
+
method: "post",
|
|
126180
|
+
path: `/jobTemplates?workspace=${ws}`,
|
|
126181
|
+
body,
|
|
126182
|
+
...fallback ? { fallback } : {}
|
|
126183
|
+
},
|
|
126184
|
+
{ retryTransient: false }
|
|
126185
|
+
);
|
|
126186
|
+
const parseMonitor = (response) => {
|
|
126056
126187
|
const uid = this.idOf(this.dataOf(response));
|
|
126057
126188
|
if (!uid) {
|
|
126058
126189
|
throw new Error("Monitor create did not return a UID");
|
|
126059
126190
|
}
|
|
126060
126191
|
return uid;
|
|
126192
|
+
};
|
|
126193
|
+
try {
|
|
126194
|
+
return parseMonitor(await send2());
|
|
126061
126195
|
} catch (error) {
|
|
126062
126196
|
const adopted = await this.discoverAfterAmbiguousCreate(
|
|
126063
126197
|
() => this.findMonitorByCollection(collection, environment, monitorName),
|
|
@@ -126066,6 +126200,10 @@ var PostmanGatewayAssetsClient = class {
|
|
|
126066
126200
|
if (adopted?.uid) {
|
|
126067
126201
|
return adopted.uid;
|
|
126068
126202
|
}
|
|
126203
|
+
if (adopted === void 0) {
|
|
126204
|
+
const retried = await this.resendAbsentCreate(async () => parseMonitor(await send2("auto")));
|
|
126205
|
+
if (retried) return retried;
|
|
126206
|
+
}
|
|
126069
126207
|
throw error;
|
|
126070
126208
|
}
|
|
126071
126209
|
});
|
|
@@ -126294,6 +126432,7 @@ var AccessTokenGatewayClient = class {
|
|
|
126294
126432
|
fetchImpl;
|
|
126295
126433
|
secretMasker;
|
|
126296
126434
|
maxRetries;
|
|
126435
|
+
fallbackBaseUrl;
|
|
126297
126436
|
retryBaseDelayMs;
|
|
126298
126437
|
sleepImpl;
|
|
126299
126438
|
constructor(options) {
|
|
@@ -126306,6 +126445,8 @@ var AccessTokenGatewayClient = class {
|
|
|
126306
126445
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
126307
126446
|
this.secretMasker = options.secretMasker ?? createSecretMasker([this.tokenProvider.current()]);
|
|
126308
126447
|
this.maxRetries = options.maxRetries ?? 3;
|
|
126448
|
+
const fallbackEnv = typeof process !== "undefined" ? process.env?.POSTMAN_ITEM_CREATE_FALLBACK : void 0;
|
|
126449
|
+
this.fallbackBaseUrl = fallbackEnv === "off" ? void 0 : options.fallbackBaseUrl?.replace(/\/+$/, "");
|
|
126309
126450
|
this.retryBaseDelayMs = options.retryBaseDelayMs ?? 400;
|
|
126310
126451
|
this.sleepImpl = options.sleepImpl ?? defaultSleep;
|
|
126311
126452
|
}
|
|
@@ -126324,8 +126465,8 @@ var AccessTokenGatewayClient = class {
|
|
|
126324
126465
|
}
|
|
126325
126466
|
return headers;
|
|
126326
126467
|
}
|
|
126327
|
-
async send(request) {
|
|
126328
|
-
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
126468
|
+
async send(request, baseUrl) {
|
|
126469
|
+
const url = `${baseUrl ?? this.bifrostBaseUrl}/ws/proxy`;
|
|
126329
126470
|
return this.fetchImpl(url, {
|
|
126330
126471
|
method: "POST",
|
|
126331
126472
|
headers: this.buildHeaders(request.headers),
|
|
@@ -126338,6 +126479,43 @@ var AccessTokenGatewayClient = class {
|
|
|
126338
126479
|
})
|
|
126339
126480
|
});
|
|
126340
126481
|
}
|
|
126482
|
+
/**
|
|
126483
|
+
* One cold, serial attempt against the fallback base URL after the primary
|
|
126484
|
+
* budget is exhausted on a transient failure. Never hedged in parallel with
|
|
126485
|
+
* the primary; only fires when the request would otherwise throw. Callers
|
|
126486
|
+
* with `retryTransient: false` still reconcile first — the fallback attempt
|
|
126487
|
+
* here is the resend, so it is only used for requests whose mutation is
|
|
126488
|
+
* known idempotent or already reconciled by the caller's adopt-on-ambiguous
|
|
126489
|
+
* loop.
|
|
126490
|
+
*/
|
|
126491
|
+
async tryFallback(request) {
|
|
126492
|
+
if (!this.fallbackBaseUrl) return null;
|
|
126493
|
+
try {
|
|
126494
|
+
return await this.send(request, this.fallbackBaseUrl);
|
|
126495
|
+
} catch {
|
|
126496
|
+
return null;
|
|
126497
|
+
}
|
|
126498
|
+
}
|
|
126499
|
+
/**
|
|
126500
|
+
* Run the fallback attempt and classify its response the same way the
|
|
126501
|
+
* primary path would. Returns the success response, or null when the
|
|
126502
|
+
* fallback also failed transiently (caller then throws the original error).
|
|
126503
|
+
* Non-transient fallback failures (4xx) surface as their own HttpError since
|
|
126504
|
+
* they are the freshest authoritative answer.
|
|
126505
|
+
*/
|
|
126506
|
+
fallbackEligible(request, retryTransient) {
|
|
126507
|
+
if (!this.fallbackBaseUrl) return false;
|
|
126508
|
+
return retryTransient || request.fallback === "auto";
|
|
126509
|
+
}
|
|
126510
|
+
async attemptFallback(request, retryTransient) {
|
|
126511
|
+
if (!this.fallbackEligible(request, retryTransient)) return null;
|
|
126512
|
+
const response = await this.tryFallback(request);
|
|
126513
|
+
if (!response) return null;
|
|
126514
|
+
if (response.ok) return response;
|
|
126515
|
+
const body = await response.text().catch(() => "");
|
|
126516
|
+
if (isRetryableSafeReadResponse(response.status)) return null;
|
|
126517
|
+
throw this.toHttpError(request, response, body);
|
|
126518
|
+
}
|
|
126341
126519
|
/**
|
|
126342
126520
|
* Send a gateway request, refreshing the token once on an auth failure and
|
|
126343
126521
|
* optionally retrying transient downstream failures (5xx / Bifrost read
|
|
@@ -126360,6 +126538,8 @@ var AccessTokenGatewayClient = class {
|
|
|
126360
126538
|
await this.sleepImpl(delay);
|
|
126361
126539
|
continue;
|
|
126362
126540
|
}
|
|
126541
|
+
const fallbackResponse2 = await this.attemptFallback(request, retryTransient);
|
|
126542
|
+
if (fallbackResponse2) return fallbackResponse2;
|
|
126363
126543
|
throw error;
|
|
126364
126544
|
}
|
|
126365
126545
|
if (response.ok) {
|
|
@@ -126381,6 +126561,8 @@ var AccessTokenGatewayClient = class {
|
|
|
126381
126561
|
await this.sleepImpl(delay);
|
|
126382
126562
|
continue;
|
|
126383
126563
|
}
|
|
126564
|
+
const fallbackResponse = await this.attemptFallback(request, retryTransient);
|
|
126565
|
+
if (fallbackResponse) return fallbackResponse;
|
|
126384
126566
|
throw this.toHttpError(request, response, body);
|
|
126385
126567
|
}
|
|
126386
126568
|
}
|
|
@@ -126952,6 +127134,7 @@ function resolveInputs(env = process.env) {
|
|
|
126952
127134
|
postmanStack,
|
|
126953
127135
|
postmanApiBase: endpointProfile.apiBaseUrl,
|
|
126954
127136
|
postmanBifrostBase: endpointProfile.bifrostBaseUrl,
|
|
127137
|
+
postmanFallbackBase: endpointProfile.fallbackBaseUrl,
|
|
126955
127138
|
postmanCliInstallUrl: endpointProfile.cliInstallUrl,
|
|
126956
127139
|
postmanIapubBase: endpointProfile.iapubBaseUrl
|
|
126957
127140
|
};
|
|
@@ -127658,6 +127841,39 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
127658
127841
|
}
|
|
127659
127842
|
}
|
|
127660
127843
|
}
|
|
127844
|
+
let skipRepositoryLinkPost = false;
|
|
127845
|
+
let repositoryLinkPreflightWasFree = false;
|
|
127846
|
+
if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
|
|
127847
|
+
const probe = await dependencies.internalIntegration.findWorkspaceForRepo(
|
|
127848
|
+
inputs.repoUrl,
|
|
127849
|
+
"/"
|
|
127850
|
+
);
|
|
127851
|
+
if (probe.state === "linked-visible") {
|
|
127852
|
+
if (probe.workspace.id === inputs.workspaceId) {
|
|
127853
|
+
skipRepositoryLinkPost = true;
|
|
127854
|
+
dependencies.core.info(
|
|
127855
|
+
`REPOSITORY_LINK_ALREADY_TARGET: Repository ${inputs.repoUrl} at path / is already linked to target workspace ${inputs.workspaceId}; continuing.`
|
|
127856
|
+
);
|
|
127857
|
+
} else {
|
|
127858
|
+
const ownerName = probe.workspace.name?.trim() || "unknown";
|
|
127859
|
+
throw new Error(
|
|
127860
|
+
`REPOSITORY_LINK_CONFLICT_VISIBLE: Repository ${inputs.repoUrl} at path / is already linked to workspace ${probe.workspace.id} ("${ownerName}"). No Postman assets were changed. Reuse that workspace or disconnect it in Workspace Settings, then rerun.`
|
|
127861
|
+
);
|
|
127862
|
+
}
|
|
127863
|
+
} else if (probe.state === "linked-invisible") {
|
|
127864
|
+
let message = `REPOSITORY_LINK_CONFLICT_INVISIBLE: Repository ${inputs.repoUrl} at path / is linked to workspace ${probe.workspaceId}, but these credentials cannot view it. No Postman assets were changed. Ask its owner or a team admin to disconnect it.`;
|
|
127865
|
+
if (inputs.orgMode) {
|
|
127866
|
+
message += " Verify workspace-team-id; if the owner is in another sub-team, ask that sub-team's admin to disconnect it.";
|
|
127867
|
+
}
|
|
127868
|
+
throw new Error(message);
|
|
127869
|
+
} else if (probe.state === "free") {
|
|
127870
|
+
repositoryLinkPreflightWasFree = true;
|
|
127871
|
+
} else {
|
|
127872
|
+
dependencies.core.warning(
|
|
127873
|
+
`REPOSITORY_LINK_PREFLIGHT_UNKNOWN: Unable to determine the existing repository link (${probe.reason}); continuing and relying on link creation conflict handling.`
|
|
127874
|
+
);
|
|
127875
|
+
}
|
|
127876
|
+
}
|
|
127661
127877
|
const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
|
|
127662
127878
|
const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
|
|
127663
127879
|
outputs["environment-uids-json"] = JSON.stringify(envUids);
|
|
@@ -127790,18 +128006,33 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
127790
128006
|
}
|
|
127791
128007
|
if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration) {
|
|
127792
128008
|
try {
|
|
127793
|
-
|
|
127794
|
-
|
|
127795
|
-
|
|
127796
|
-
|
|
127797
|
-
|
|
127798
|
-
|
|
127799
|
-
|
|
127800
|
-
|
|
128009
|
+
if (skipRepositoryLinkPost) {
|
|
128010
|
+
outputs["workspace-link-status"] = "success";
|
|
128011
|
+
dependencies.core.info(
|
|
128012
|
+
`workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl} (preflight already-target; link POST skipped)`
|
|
128013
|
+
);
|
|
128014
|
+
} else {
|
|
128015
|
+
await dependencies.internalIntegration.connectWorkspaceToRepository(
|
|
128016
|
+
inputs.workspaceId,
|
|
128017
|
+
inputs.repoUrl,
|
|
128018
|
+
repositoryLinkPreflightWasFree ? { preflightWasFree: true } : void 0
|
|
128019
|
+
);
|
|
128020
|
+
outputs["workspace-link-status"] = "success";
|
|
128021
|
+
dependencies.core.info(
|
|
128022
|
+
`workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
|
|
128023
|
+
);
|
|
128024
|
+
}
|
|
127801
128025
|
} catch (error) {
|
|
127802
128026
|
outputs["workspace-link-status"] = "failed";
|
|
127803
|
-
const
|
|
128027
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
128028
|
+
const isUnresolvedContract = rawMessage.startsWith(
|
|
128029
|
+
"REPOSITORY_LINK_CONFLICT_UNRESOLVED:"
|
|
128030
|
+
);
|
|
128031
|
+
const message = isUnresolvedContract ? rawMessage : `Workspace link failed: ${rawMessage}`;
|
|
127804
128032
|
if (branchDecision.tier === "canonical") {
|
|
128033
|
+
if (isUnresolvedContract && error instanceof Error) {
|
|
128034
|
+
throw error;
|
|
128035
|
+
}
|
|
127805
128036
|
throw new Error(message, { cause: error });
|
|
127806
128037
|
}
|
|
127807
128038
|
dependencies.core.warning(message);
|
|
@@ -127955,6 +128186,8 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
|
|
|
127955
128186
|
const gateway = new AccessTokenGatewayClient({
|
|
127956
128187
|
tokenProvider,
|
|
127957
128188
|
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
128189
|
+
// No fallback on the org-mode probe: the expected non-org 400 must
|
|
128190
|
+
// surface verbatim, not be re-fired against the /_api alias.
|
|
127958
128191
|
secretMasker: masker
|
|
127959
128192
|
});
|
|
127960
128193
|
const squads = await gateway.getSquads(teamId);
|
|
@@ -128010,6 +128243,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
128010
128243
|
const gateway = new AccessTokenGatewayClient({
|
|
128011
128244
|
tokenProvider,
|
|
128012
128245
|
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
128246
|
+
fallbackBaseUrl: inputs.postmanFallbackBase,
|
|
128013
128247
|
teamId: resolved.teamId,
|
|
128014
128248
|
orgMode: inputs.orgMode,
|
|
128015
128249
|
secretMasker: masker
|