@backstage/integration 1.2.2 → 1.3.0-next.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/CHANGELOG.md +12 -0
- package/config.d.ts +10 -0
- package/dist/index.cjs.js +214 -67
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.esm.js +214 -67
- package/dist/index.esm.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @backstage/integration
|
|
2
2
|
|
|
3
|
+
## 1.3.0-next.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 593dea6710: Add support for Basic Auth for Bitbucket Server.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 163243a4d1: Handle incorrect return type from Octokit paginate plugin to resolve reading URLs from GitHub
|
|
12
|
+
- c4b460a47d: Avoid double encoding of the file path in `getBitbucketDownloadUrl`
|
|
13
|
+
- 29f782eb37: Updated dependency `@types/luxon` to `^3.0.0`.
|
|
14
|
+
|
|
3
15
|
## 1.2.2
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/config.d.ts
CHANGED
|
@@ -92,6 +92,16 @@ export interface Config {
|
|
|
92
92
|
* @visibility secret
|
|
93
93
|
*/
|
|
94
94
|
token?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Username used to authenticate requests with Basic Auth.
|
|
97
|
+
* @visibility secret
|
|
98
|
+
*/
|
|
99
|
+
username?: string;
|
|
100
|
+
/**
|
|
101
|
+
* Password (or token as password) used to authenticate requests with Basic Auth.
|
|
102
|
+
* @visibility secret
|
|
103
|
+
*/
|
|
104
|
+
password?: string;
|
|
95
105
|
/**
|
|
96
106
|
* The base url for the Bitbucket Server API, for example https://<host>/rest/api/1.0
|
|
97
107
|
* @visibility frontend
|
package/dist/index.cjs.js
CHANGED
|
@@ -57,7 +57,10 @@ function defaultScmResolveUrl(options) {
|
|
|
57
57
|
if (url.startsWith("/")) {
|
|
58
58
|
const { filepath } = parseGitUrl__default["default"](base);
|
|
59
59
|
updated = new URL(base);
|
|
60
|
-
const repoRootPath = lodash.trimEnd(
|
|
60
|
+
const repoRootPath = lodash.trimEnd(
|
|
61
|
+
updated.pathname.substring(0, updated.pathname.length - filepath.length),
|
|
62
|
+
"/"
|
|
63
|
+
);
|
|
61
64
|
updated.pathname = `${repoRootPath}${url}`;
|
|
62
65
|
} else {
|
|
63
66
|
updated = new URL(url, base);
|
|
@@ -82,10 +85,14 @@ function readAwsS3IntegrationConfig(config) {
|
|
|
82
85
|
host = url.host;
|
|
83
86
|
pathname = url.pathname;
|
|
84
87
|
} catch {
|
|
85
|
-
throw new Error(
|
|
88
|
+
throw new Error(
|
|
89
|
+
`invalid awsS3 integration config, endpoint '${endpoint}' is not a valid URL`
|
|
90
|
+
);
|
|
86
91
|
}
|
|
87
92
|
if (pathname !== "/") {
|
|
88
|
-
throw new Error(
|
|
93
|
+
throw new Error(
|
|
94
|
+
`invalid awsS3 integration config, endpoints cannot contain path, got '${endpoint}'`
|
|
95
|
+
);
|
|
89
96
|
}
|
|
90
97
|
} else {
|
|
91
98
|
host = AMAZON_AWS_HOST;
|
|
@@ -138,8 +145,13 @@ const _AwsS3Integration = class {
|
|
|
138
145
|
let AwsS3Integration = _AwsS3Integration;
|
|
139
146
|
AwsS3Integration.factory = ({ config }) => {
|
|
140
147
|
var _a;
|
|
141
|
-
const configs = readAwsS3IntegrationConfigs(
|
|
142
|
-
|
|
148
|
+
const configs = readAwsS3IntegrationConfigs(
|
|
149
|
+
(_a = config.getOptionalConfigArray("integrations.awsS3")) != null ? _a : []
|
|
150
|
+
);
|
|
151
|
+
return basicIntegrations(
|
|
152
|
+
configs.map((c) => new _AwsS3Integration(c)),
|
|
153
|
+
(i) => i.config.host
|
|
154
|
+
);
|
|
143
155
|
};
|
|
144
156
|
|
|
145
157
|
var __accessCheck = (obj, member, msg) => {
|
|
@@ -233,7 +245,9 @@ const _AzureUrl = class {
|
|
|
233
245
|
}
|
|
234
246
|
toFileUrl() {
|
|
235
247
|
if (!__privateGet(this, _path)) {
|
|
236
|
-
throw new Error(
|
|
248
|
+
throw new Error(
|
|
249
|
+
"Azure URL must point to a specific path to be able to download a file"
|
|
250
|
+
);
|
|
237
251
|
}
|
|
238
252
|
const url = __privateGet(this, _baseUrl).call(this, __privateGet(this, _owner), __privateGet(this, _project), "_apis", "git", "repositories", __privateGet(this, _repo), "items");
|
|
239
253
|
url.searchParams.set("api-version", "6.0");
|
|
@@ -295,7 +309,9 @@ function readAzureIntegrationConfig(config) {
|
|
|
295
309
|
const host = (_a = config.getOptionalString("host")) != null ? _a : AZURE_HOST;
|
|
296
310
|
const token = config.getOptionalString("token");
|
|
297
311
|
if (!isValidHost(host)) {
|
|
298
|
-
throw new Error(
|
|
312
|
+
throw new Error(
|
|
313
|
+
`Invalid Azure integration config, '${host}' is not a valid host`
|
|
314
|
+
);
|
|
299
315
|
}
|
|
300
316
|
return { host, token };
|
|
301
317
|
}
|
|
@@ -350,8 +366,13 @@ const _AzureIntegration = class {
|
|
|
350
366
|
let AzureIntegration = _AzureIntegration;
|
|
351
367
|
AzureIntegration.factory = ({ config }) => {
|
|
352
368
|
var _a;
|
|
353
|
-
const configs = readAzureIntegrationConfigs(
|
|
354
|
-
|
|
369
|
+
const configs = readAzureIntegrationConfigs(
|
|
370
|
+
(_a = config.getOptionalConfigArray("integrations.azure")) != null ? _a : []
|
|
371
|
+
);
|
|
372
|
+
return basicIntegrations(
|
|
373
|
+
configs.map((c) => new _AzureIntegration(c)),
|
|
374
|
+
(i) => i.config.host
|
|
375
|
+
);
|
|
355
376
|
};
|
|
356
377
|
|
|
357
378
|
function getAzureFileFetchUrl(url) {
|
|
@@ -382,7 +403,9 @@ function readBitbucketIntegrationConfig(config) {
|
|
|
382
403
|
const username = config.getOptionalString("username");
|
|
383
404
|
const appPassword = config.getOptionalString("appPassword");
|
|
384
405
|
if (!isValidHost(host)) {
|
|
385
|
-
throw new Error(
|
|
406
|
+
throw new Error(
|
|
407
|
+
`Invalid Bitbucket integration config, '${host}' is not a valid host`
|
|
408
|
+
);
|
|
386
409
|
}
|
|
387
410
|
if (apiBaseUrl) {
|
|
388
411
|
apiBaseUrl = lodash.trimEnd(apiBaseUrl, "/");
|
|
@@ -450,11 +473,16 @@ BitbucketIntegration.factory = ({
|
|
|
450
473
|
config
|
|
451
474
|
}) => {
|
|
452
475
|
var _a, _b, _c;
|
|
453
|
-
const configs = readBitbucketIntegrationConfigs(
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
476
|
+
const configs = readBitbucketIntegrationConfigs(
|
|
477
|
+
(_c = config.getOptionalConfigArray("integrations.bitbucket")) != null ? _c : [
|
|
478
|
+
...(_a = config.getOptionalConfigArray("integrations.bitbucketCloud")) != null ? _a : [],
|
|
479
|
+
...(_b = config.getOptionalConfigArray("integrations.bitbucketServer")) != null ? _b : []
|
|
480
|
+
]
|
|
481
|
+
);
|
|
482
|
+
return basicIntegrations(
|
|
483
|
+
configs.map((c) => new _BitbucketIntegration(c)),
|
|
484
|
+
(i) => i.config.host
|
|
485
|
+
);
|
|
458
486
|
};
|
|
459
487
|
|
|
460
488
|
async function getBitbucketDefaultBranch(url, config) {
|
|
@@ -479,7 +507,9 @@ async function getBitbucketDefaultBranch(url, config) {
|
|
|
479
507
|
defaultBranch = displayId;
|
|
480
508
|
}
|
|
481
509
|
if (!defaultBranch) {
|
|
482
|
-
throw new Error(
|
|
510
|
+
throw new Error(
|
|
511
|
+
`Failed to read default branch from ${branchUrl}. Response ${response.status} ${response.json()}`
|
|
512
|
+
);
|
|
483
513
|
}
|
|
484
514
|
return defaultBranch;
|
|
485
515
|
}
|
|
@@ -497,7 +527,7 @@ async function getBitbucketDownloadUrl(url, config) {
|
|
|
497
527
|
if (!branch) {
|
|
498
528
|
branch = await getBitbucketDefaultBranch(url, config);
|
|
499
529
|
}
|
|
500
|
-
const path = filepath ? `&path=${encodeURIComponent(filepath)}` : "";
|
|
530
|
+
const path = filepath ? `&path=${encodeURIComponent(decodeURIComponent(filepath))}` : "";
|
|
501
531
|
const archiveUrl = isHosted ? `${protocol}://${resource}/${project}/${repoName}/get/${branch}.tar.gz` : `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/archive?format=tgz&at=${branch}&prefix=${project}-${repoName}${path}`;
|
|
502
532
|
return archiveUrl;
|
|
503
533
|
}
|
|
@@ -524,7 +554,10 @@ function getBitbucketRequestOptions(config) {
|
|
|
524
554
|
if (config.token) {
|
|
525
555
|
headers.Authorization = `Bearer ${config.token}`;
|
|
526
556
|
} else if (config.username && config.appPassword) {
|
|
527
|
-
const buffer = Buffer.from(
|
|
557
|
+
const buffer = Buffer.from(
|
|
558
|
+
`${config.username}:${config.appPassword}`,
|
|
559
|
+
"utf8"
|
|
560
|
+
);
|
|
528
561
|
headers.Authorization = `Basic ${buffer.toString("base64")}`;
|
|
529
562
|
}
|
|
530
563
|
return {
|
|
@@ -592,14 +625,22 @@ BitbucketCloudIntegration.factory = ({
|
|
|
592
625
|
config
|
|
593
626
|
}) => {
|
|
594
627
|
var _a;
|
|
595
|
-
const configs = readBitbucketCloudIntegrationConfigs(
|
|
596
|
-
|
|
628
|
+
const configs = readBitbucketCloudIntegrationConfigs(
|
|
629
|
+
(_a = config.getOptionalConfigArray("integrations.bitbucketCloud")) != null ? _a : []
|
|
630
|
+
);
|
|
631
|
+
return basicIntegrations(
|
|
632
|
+
configs.map((c) => new _BitbucketCloudIntegration(c)),
|
|
633
|
+
(i) => i.config.host
|
|
634
|
+
);
|
|
597
635
|
};
|
|
598
636
|
|
|
599
637
|
async function getBitbucketCloudDefaultBranch(url, config) {
|
|
600
638
|
const { name: repoName, owner: project } = parseGitUrl__default["default"](url);
|
|
601
639
|
const branchUrl = `${config.apiBaseUrl}/repositories/${project}/${repoName}`;
|
|
602
|
-
const response = await fetch__default["default"](
|
|
640
|
+
const response = await fetch__default["default"](
|
|
641
|
+
branchUrl,
|
|
642
|
+
getBitbucketCloudRequestOptions(config)
|
|
643
|
+
);
|
|
603
644
|
if (!response.ok) {
|
|
604
645
|
const message = `Failed to retrieve default branch from ${branchUrl}, ${response.status} ${response.statusText}`;
|
|
605
646
|
throw new Error(message);
|
|
@@ -607,7 +648,9 @@ async function getBitbucketCloudDefaultBranch(url, config) {
|
|
|
607
648
|
const repoInfo = await response.json();
|
|
608
649
|
const defaultBranch = repoInfo.mainbranch.name;
|
|
609
650
|
if (!defaultBranch) {
|
|
610
|
-
throw new Error(
|
|
651
|
+
throw new Error(
|
|
652
|
+
`Failed to read default branch from ${branchUrl}. Response ${response.status} ${response.json()}`
|
|
653
|
+
);
|
|
611
654
|
}
|
|
612
655
|
return defaultBranch;
|
|
613
656
|
}
|
|
@@ -643,7 +686,10 @@ function getBitbucketCloudFileFetchUrl(url, config) {
|
|
|
643
686
|
function getBitbucketCloudRequestOptions(config) {
|
|
644
687
|
const headers = {};
|
|
645
688
|
if (config.username && config.appPassword) {
|
|
646
|
-
const buffer = Buffer.from(
|
|
689
|
+
const buffer = Buffer.from(
|
|
690
|
+
`${config.username}:${config.appPassword}`,
|
|
691
|
+
"utf8"
|
|
692
|
+
);
|
|
647
693
|
headers.Authorization = `Basic ${buffer.toString("base64")}`;
|
|
648
694
|
}
|
|
649
695
|
return {
|
|
@@ -655,8 +701,12 @@ function readBitbucketServerIntegrationConfig(config) {
|
|
|
655
701
|
const host = config.getString("host");
|
|
656
702
|
let apiBaseUrl = config.getOptionalString("apiBaseUrl");
|
|
657
703
|
const token = config.getOptionalString("token");
|
|
704
|
+
const username = config.getOptionalString("username");
|
|
705
|
+
const password = config.getOptionalString("password");
|
|
658
706
|
if (!isValidHost(host)) {
|
|
659
|
-
throw new Error(
|
|
707
|
+
throw new Error(
|
|
708
|
+
`Invalid Bitbucket Server integration config, '${host}' is not a valid host`
|
|
709
|
+
);
|
|
660
710
|
}
|
|
661
711
|
if (apiBaseUrl) {
|
|
662
712
|
apiBaseUrl = lodash.trimEnd(apiBaseUrl, "/");
|
|
@@ -666,7 +716,9 @@ function readBitbucketServerIntegrationConfig(config) {
|
|
|
666
716
|
return {
|
|
667
717
|
host,
|
|
668
718
|
apiBaseUrl,
|
|
669
|
-
token
|
|
719
|
+
token,
|
|
720
|
+
username,
|
|
721
|
+
password
|
|
670
722
|
};
|
|
671
723
|
}
|
|
672
724
|
function readBitbucketServerIntegrationConfigs(configs) {
|
|
@@ -710,14 +762,22 @@ BitbucketServerIntegration.factory = ({
|
|
|
710
762
|
config
|
|
711
763
|
}) => {
|
|
712
764
|
var _a;
|
|
713
|
-
const configs = readBitbucketServerIntegrationConfigs(
|
|
714
|
-
|
|
765
|
+
const configs = readBitbucketServerIntegrationConfigs(
|
|
766
|
+
(_a = config.getOptionalConfigArray("integrations.bitbucketServer")) != null ? _a : []
|
|
767
|
+
);
|
|
768
|
+
return basicIntegrations(
|
|
769
|
+
configs.map((c) => new _BitbucketServerIntegration(c)),
|
|
770
|
+
(i) => i.config.host
|
|
771
|
+
);
|
|
715
772
|
};
|
|
716
773
|
|
|
717
774
|
async function getBitbucketServerDefaultBranch(url, config) {
|
|
718
775
|
const { name: repoName, owner: project } = parseGitUrl__default["default"](url);
|
|
719
776
|
let branchUrl = `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/default-branch`;
|
|
720
|
-
let response = await fetch__default["default"](
|
|
777
|
+
let response = await fetch__default["default"](
|
|
778
|
+
branchUrl,
|
|
779
|
+
getBitbucketServerRequestOptions(config)
|
|
780
|
+
);
|
|
721
781
|
if (response.status === 404) {
|
|
722
782
|
branchUrl = `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/branches/default`;
|
|
723
783
|
response = await fetch__default["default"](branchUrl, getBitbucketServerRequestOptions(config));
|
|
@@ -729,7 +789,9 @@ async function getBitbucketServerDefaultBranch(url, config) {
|
|
|
729
789
|
const { displayId } = await response.json();
|
|
730
790
|
const defaultBranch = displayId;
|
|
731
791
|
if (!defaultBranch) {
|
|
732
|
-
throw new Error(
|
|
792
|
+
throw new Error(
|
|
793
|
+
`Failed to read default branch from ${branchUrl}. Response ${response.status} ${response.json()}`
|
|
794
|
+
);
|
|
733
795
|
}
|
|
734
796
|
return defaultBranch;
|
|
735
797
|
}
|
|
@@ -759,6 +821,10 @@ function getBitbucketServerRequestOptions(config) {
|
|
|
759
821
|
if (config.token) {
|
|
760
822
|
headers.Authorization = `Bearer ${config.token}`;
|
|
761
823
|
}
|
|
824
|
+
if (config.username && config.password) {
|
|
825
|
+
const buffer = Buffer.from(`${config.username}:${config.password}`, "utf8");
|
|
826
|
+
headers.Authorization = `Basic ${buffer.toString("base64")}`;
|
|
827
|
+
}
|
|
762
828
|
return {
|
|
763
829
|
headers
|
|
764
830
|
};
|
|
@@ -772,13 +838,21 @@ function readGerritIntegrationConfig(config) {
|
|
|
772
838
|
const username = config.getOptionalString("username");
|
|
773
839
|
const password = config.getOptionalString("password");
|
|
774
840
|
if (!isValidHost(host)) {
|
|
775
|
-
throw new Error(
|
|
841
|
+
throw new Error(
|
|
842
|
+
`Invalid Gerrit integration config, '${host}' is not a valid host`
|
|
843
|
+
);
|
|
776
844
|
} else if (baseUrl && !isValidUrl(baseUrl)) {
|
|
777
|
-
throw new Error(
|
|
845
|
+
throw new Error(
|
|
846
|
+
`Invalid Gerrit integration config, '${baseUrl}' is not a valid baseUrl`
|
|
847
|
+
);
|
|
778
848
|
} else if (cloneUrl && !isValidUrl(cloneUrl)) {
|
|
779
|
-
throw new Error(
|
|
849
|
+
throw new Error(
|
|
850
|
+
`Invalid Gerrit integration config, '${cloneUrl}' is not a valid cloneUrl`
|
|
851
|
+
);
|
|
780
852
|
} else if (gitilesBaseUrl && !isValidUrl(gitilesBaseUrl)) {
|
|
781
|
-
throw new Error(
|
|
853
|
+
throw new Error(
|
|
854
|
+
`Invalid Gerrit integration config, '${gitilesBaseUrl}' is not a valid gitilesBaseUrl`
|
|
855
|
+
);
|
|
782
856
|
}
|
|
783
857
|
if (baseUrl) {
|
|
784
858
|
baseUrl = lodash.trimEnd(baseUrl, "/");
|
|
@@ -837,7 +911,9 @@ function getAuthenticationPrefix(config) {
|
|
|
837
911
|
}
|
|
838
912
|
function getGerritBranchApiUrl(config, url) {
|
|
839
913
|
const { branch, project } = parseGerritGitilesUrl(config, url);
|
|
840
|
-
return `${config.baseUrl}${getAuthenticationPrefix(
|
|
914
|
+
return `${config.baseUrl}${getAuthenticationPrefix(
|
|
915
|
+
config
|
|
916
|
+
)}projects/${encodeURIComponent(project)}/branches/${branch}`;
|
|
841
917
|
}
|
|
842
918
|
function getGerritCloneRepoUrl(config, url) {
|
|
843
919
|
const { project } = parseGerritGitilesUrl(config, url);
|
|
@@ -845,7 +921,11 @@ function getGerritCloneRepoUrl(config, url) {
|
|
|
845
921
|
}
|
|
846
922
|
function getGerritFileContentsApiUrl(config, url) {
|
|
847
923
|
const { branch, filePath, project } = parseGerritGitilesUrl(config, url);
|
|
848
|
-
return `${config.baseUrl}${getAuthenticationPrefix(
|
|
924
|
+
return `${config.baseUrl}${getAuthenticationPrefix(
|
|
925
|
+
config
|
|
926
|
+
)}projects/${encodeURIComponent(
|
|
927
|
+
project
|
|
928
|
+
)}/branches/${branch}/files/${encodeURIComponent(filePath)}/content`;
|
|
849
929
|
}
|
|
850
930
|
function getGerritProjectsApiUrl(config) {
|
|
851
931
|
return `${config.baseUrl}${getAuthenticationPrefix(config)}projects/`;
|
|
@@ -867,10 +947,14 @@ async function parseGerritJsonResponse(response) {
|
|
|
867
947
|
try {
|
|
868
948
|
return JSON.parse(responseBody.slice(GERRIT_BODY_PREFIX.length));
|
|
869
949
|
} catch (ex) {
|
|
870
|
-
throw new Error(
|
|
950
|
+
throw new Error(
|
|
951
|
+
`Invalid response from Gerrit: ${responseBody.slice(0, 10)} - ${ex}`
|
|
952
|
+
);
|
|
871
953
|
}
|
|
872
954
|
}
|
|
873
|
-
throw new Error(
|
|
955
|
+
throw new Error(
|
|
956
|
+
`Gerrit JSON body prefix missing. Found: ${responseBody.slice(0, 10)}`
|
|
957
|
+
);
|
|
874
958
|
}
|
|
875
959
|
|
|
876
960
|
const _GerritIntegration = class {
|
|
@@ -910,8 +994,13 @@ const _GerritIntegration = class {
|
|
|
910
994
|
let GerritIntegration = _GerritIntegration;
|
|
911
995
|
GerritIntegration.factory = ({ config }) => {
|
|
912
996
|
var _a;
|
|
913
|
-
const configs = readGerritIntegrationConfigs(
|
|
914
|
-
|
|
997
|
+
const configs = readGerritIntegrationConfigs(
|
|
998
|
+
(_a = config.getOptionalConfigArray("integrations.gerrit")) != null ? _a : []
|
|
999
|
+
);
|
|
1000
|
+
return basicIntegrations(
|
|
1001
|
+
configs.map((c) => new _GerritIntegration(c)),
|
|
1002
|
+
(i) => i.config.host
|
|
1003
|
+
);
|
|
915
1004
|
};
|
|
916
1005
|
|
|
917
1006
|
const GITHUB_HOST = "github.com";
|
|
@@ -929,10 +1018,14 @@ function readGitHubIntegrationConfig(config) {
|
|
|
929
1018
|
clientSecret: c.getString("clientSecret"),
|
|
930
1019
|
webhookSecret: c.getString("webhookSecret"),
|
|
931
1020
|
privateKey: c.getString("privateKey"),
|
|
932
|
-
allowedInstallationOwners: c.getOptionalStringArray(
|
|
1021
|
+
allowedInstallationOwners: c.getOptionalStringArray(
|
|
1022
|
+
"allowedInstallationOwners"
|
|
1023
|
+
)
|
|
933
1024
|
}));
|
|
934
1025
|
if (!isValidHost(host)) {
|
|
935
|
-
throw new Error(
|
|
1026
|
+
throw new Error(
|
|
1027
|
+
`Invalid GitHub integration config, '${host}' is not a valid host`
|
|
1028
|
+
);
|
|
936
1029
|
}
|
|
937
1030
|
if (apiBaseUrl) {
|
|
938
1031
|
apiBaseUrl = lodash.trimEnd(apiBaseUrl, "/");
|
|
@@ -1037,6 +1130,7 @@ class GithubAppManager {
|
|
|
1037
1130
|
}
|
|
1038
1131
|
const cacheKey = repo ? `${owner}/${repo}` : owner;
|
|
1039
1132
|
return this.cache.getOrCreateToken(cacheKey, async () => {
|
|
1133
|
+
var _a2;
|
|
1040
1134
|
const result = await this.appClient.apps.createInstallationAccessToken({
|
|
1041
1135
|
installation_id: installationId,
|
|
1042
1136
|
headers: HEADERS
|
|
@@ -1046,12 +1140,17 @@ class GithubAppManager {
|
|
|
1046
1140
|
baseUrl: this.baseUrl,
|
|
1047
1141
|
auth: result.data.token
|
|
1048
1142
|
});
|
|
1049
|
-
const repos = await installationClient.paginate(
|
|
1050
|
-
|
|
1143
|
+
const repos = await installationClient.paginate(
|
|
1144
|
+
installationClient.apps.listReposAccessibleToInstallation
|
|
1145
|
+
);
|
|
1146
|
+
const repositories = (_a2 = repos.repositories) != null ? _a2 : repos;
|
|
1147
|
+
const hasRepo = repositories.some((repository) => {
|
|
1051
1148
|
return repository.name === repo;
|
|
1052
1149
|
});
|
|
1053
1150
|
if (!hasRepo) {
|
|
1054
|
-
throw new Error(
|
|
1151
|
+
throw new Error(
|
|
1152
|
+
`The Backstage GitHub application used in the ${owner} organization does not have access to a repository with the name ${repo}`
|
|
1153
|
+
);
|
|
1055
1154
|
}
|
|
1056
1155
|
}
|
|
1057
1156
|
return {
|
|
@@ -1065,17 +1164,21 @@ class GithubAppManager {
|
|
|
1065
1164
|
}
|
|
1066
1165
|
async getInstallationData(owner) {
|
|
1067
1166
|
const allInstallations = await this.getInstallations();
|
|
1068
|
-
const installation = allInstallations.find(
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1167
|
+
const installation = allInstallations.find(
|
|
1168
|
+
(inst) => {
|
|
1169
|
+
var _a, _b;
|
|
1170
|
+
return ((_b = (_a = inst.account) == null ? void 0 : _a.login) == null ? void 0 : _b.toLocaleLowerCase("en-US")) === owner.toLocaleLowerCase("en-US");
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1072
1173
|
if (installation) {
|
|
1073
1174
|
return {
|
|
1074
1175
|
installationId: installation.id,
|
|
1075
1176
|
suspended: Boolean(installation.suspended_by)
|
|
1076
1177
|
};
|
|
1077
1178
|
}
|
|
1078
|
-
const notFoundError = new Error(
|
|
1179
|
+
const notFoundError = new Error(
|
|
1180
|
+
`No app installation found for ${owner} in ${this.baseAuthConfig.appId}`
|
|
1181
|
+
);
|
|
1079
1182
|
notFoundError.name = "NotFoundError";
|
|
1080
1183
|
throw notFoundError;
|
|
1081
1184
|
}
|
|
@@ -1089,14 +1192,23 @@ class GithubAppCredentialsMux {
|
|
|
1089
1192
|
if (!this.apps.length) {
|
|
1090
1193
|
return [];
|
|
1091
1194
|
}
|
|
1092
|
-
const installs = await Promise.all(
|
|
1195
|
+
const installs = await Promise.all(
|
|
1196
|
+
this.apps.map((app) => app.getInstallations())
|
|
1197
|
+
);
|
|
1093
1198
|
return installs.flat();
|
|
1094
1199
|
}
|
|
1095
1200
|
async getAppToken(owner, repo) {
|
|
1096
1201
|
if (this.apps.length === 0) {
|
|
1097
1202
|
return void 0;
|
|
1098
1203
|
}
|
|
1099
|
-
const results = await Promise.all(
|
|
1204
|
+
const results = await Promise.all(
|
|
1205
|
+
this.apps.map(
|
|
1206
|
+
(app) => app.getInstallationCredentials(owner, repo).then(
|
|
1207
|
+
(credentials) => ({ credentials, error: void 0 }),
|
|
1208
|
+
(error) => ({ credentials: void 0, error })
|
|
1209
|
+
)
|
|
1210
|
+
)
|
|
1211
|
+
);
|
|
1100
1212
|
const result = results.find((resultItem) => resultItem.credentials);
|
|
1101
1213
|
if (result) {
|
|
1102
1214
|
return result.credentials.accessToken;
|
|
@@ -1133,7 +1245,10 @@ const _SingleInstanceGithubCredentialsProvider = class {
|
|
|
1133
1245
|
};
|
|
1134
1246
|
let SingleInstanceGithubCredentialsProvider = _SingleInstanceGithubCredentialsProvider;
|
|
1135
1247
|
SingleInstanceGithubCredentialsProvider.create = (config) => {
|
|
1136
|
-
return new _SingleInstanceGithubCredentialsProvider(
|
|
1248
|
+
return new _SingleInstanceGithubCredentialsProvider(
|
|
1249
|
+
new GithubAppCredentialsMux(config),
|
|
1250
|
+
config.token
|
|
1251
|
+
);
|
|
1137
1252
|
};
|
|
1138
1253
|
|
|
1139
1254
|
class DefaultGithubCredentialsProvider {
|
|
@@ -1152,7 +1267,9 @@ class DefaultGithubCredentialsProvider {
|
|
|
1152
1267
|
const parsed = new URL(opts.url);
|
|
1153
1268
|
const provider = this.providers.get(parsed.host);
|
|
1154
1269
|
if (!provider) {
|
|
1155
|
-
throw new Error(
|
|
1270
|
+
throw new Error(
|
|
1271
|
+
`There is no GitHub integration that matches ${opts.url}. Please add a configuration for an integration.`
|
|
1272
|
+
);
|
|
1156
1273
|
}
|
|
1157
1274
|
return provider.getCredentials(opts);
|
|
1158
1275
|
}
|
|
@@ -1181,13 +1298,21 @@ const _GitHubIntegration = class {
|
|
|
1181
1298
|
let GitHubIntegration = _GitHubIntegration;
|
|
1182
1299
|
GitHubIntegration.factory = ({ config }) => {
|
|
1183
1300
|
var _a;
|
|
1184
|
-
const configs = readGitHubIntegrationConfigs(
|
|
1185
|
-
|
|
1301
|
+
const configs = readGitHubIntegrationConfigs(
|
|
1302
|
+
(_a = config.getOptionalConfigArray("integrations.github")) != null ? _a : []
|
|
1303
|
+
);
|
|
1304
|
+
return basicIntegrations(
|
|
1305
|
+
configs.map((c) => new _GitHubIntegration(c)),
|
|
1306
|
+
(i) => i.config.host
|
|
1307
|
+
);
|
|
1186
1308
|
};
|
|
1187
1309
|
function replaceGitHubUrlType(url, type) {
|
|
1188
|
-
return url.replace(
|
|
1189
|
-
|
|
1190
|
-
|
|
1310
|
+
return url.replace(
|
|
1311
|
+
/\/\/([^/]+)\/([^/]+)\/([^/]+)\/(blob|tree|edit)\//,
|
|
1312
|
+
(_, host, owner, repo) => {
|
|
1313
|
+
return `//${host}/${owner}/${repo}/${type}/`;
|
|
1314
|
+
}
|
|
1315
|
+
);
|
|
1191
1316
|
}
|
|
1192
1317
|
|
|
1193
1318
|
const GITLAB_HOST = "gitlab.com";
|
|
@@ -1208,11 +1333,17 @@ function readGitLabIntegrationConfig(config) {
|
|
|
1208
1333
|
baseUrl = `https://${host}`;
|
|
1209
1334
|
}
|
|
1210
1335
|
if (!isValidHost(host)) {
|
|
1211
|
-
throw new Error(
|
|
1336
|
+
throw new Error(
|
|
1337
|
+
`Invalid GitLab integration config, '${host}' is not a valid host`
|
|
1338
|
+
);
|
|
1212
1339
|
} else if (!apiBaseUrl || !isValidUrl(apiBaseUrl)) {
|
|
1213
|
-
throw new Error(
|
|
1340
|
+
throw new Error(
|
|
1341
|
+
`Invalid GitLab integration config, '${apiBaseUrl}' is not a valid apiBaseUrl`
|
|
1342
|
+
);
|
|
1214
1343
|
} else if (!isValidUrl(baseUrl)) {
|
|
1215
|
-
throw new Error(
|
|
1344
|
+
throw new Error(
|
|
1345
|
+
`Invalid GitLab integration config, '${baseUrl}' is not a valid baseUrl`
|
|
1346
|
+
);
|
|
1216
1347
|
}
|
|
1217
1348
|
return { host, token, apiBaseUrl, baseUrl };
|
|
1218
1349
|
}
|
|
@@ -1300,11 +1431,20 @@ async function getProjectId(target, config) {
|
|
|
1300
1431
|
if (relativePath) {
|
|
1301
1432
|
repo = repo.replace(relativePath, "");
|
|
1302
1433
|
}
|
|
1303
|
-
const repoIDLookup = new URL(
|
|
1304
|
-
|
|
1434
|
+
const repoIDLookup = new URL(
|
|
1435
|
+
`${url.origin}${relativePath}/api/v4/projects/${encodeURIComponent(
|
|
1436
|
+
repo.replace(/^\//, "")
|
|
1437
|
+
)}`
|
|
1438
|
+
);
|
|
1439
|
+
const response = await fetch__default["default"](
|
|
1440
|
+
repoIDLookup.toString(),
|
|
1441
|
+
getGitLabRequestOptions(config)
|
|
1442
|
+
);
|
|
1305
1443
|
const data = await response.json();
|
|
1306
1444
|
if (!response.ok) {
|
|
1307
|
-
throw new Error(
|
|
1445
|
+
throw new Error(
|
|
1446
|
+
`GitLab Error '${data.error}', ${data.error_description}`
|
|
1447
|
+
);
|
|
1308
1448
|
}
|
|
1309
1449
|
return Number(data.id);
|
|
1310
1450
|
} catch (e) {
|
|
@@ -1335,8 +1475,13 @@ const _GitLabIntegration = class {
|
|
|
1335
1475
|
let GitLabIntegration = _GitLabIntegration;
|
|
1336
1476
|
GitLabIntegration.factory = ({ config }) => {
|
|
1337
1477
|
var _a;
|
|
1338
|
-
const configs = readGitLabIntegrationConfigs(
|
|
1339
|
-
|
|
1478
|
+
const configs = readGitLabIntegrationConfigs(
|
|
1479
|
+
(_a = config.getOptionalConfigArray("integrations.gitlab")) != null ? _a : []
|
|
1480
|
+
);
|
|
1481
|
+
return basicIntegrations(
|
|
1482
|
+
configs.map((c) => new _GitLabIntegration(c)),
|
|
1483
|
+
(i) => i.config.host
|
|
1484
|
+
);
|
|
1340
1485
|
};
|
|
1341
1486
|
function replaceGitLabUrlType(url, type) {
|
|
1342
1487
|
return url.replace(/\/\-\/(blob|tree|edit)\//, `/-/${type}/`);
|
|
@@ -1395,7 +1540,9 @@ class ScmIntegrations {
|
|
|
1395
1540
|
return this.byType.gitlab;
|
|
1396
1541
|
}
|
|
1397
1542
|
list() {
|
|
1398
|
-
return Object.values(this.byType).flatMap(
|
|
1543
|
+
return Object.values(this.byType).flatMap(
|
|
1544
|
+
(i) => i.list()
|
|
1545
|
+
);
|
|
1399
1546
|
}
|
|
1400
1547
|
byUrl(url) {
|
|
1401
1548
|
return Object.values(this.byType).map((i) => i.byUrl(url)).find(Boolean);
|