@backstage/integration 1.2.2-next.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 +45 -0
- package/config.d.ts +10 -0
- package/dist/index.cjs.js +233 -72
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.esm.js +233 -73
- package/dist/index.esm.js.map +1 -1
- package/package.json +11 -11
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
|
}
|
|
@@ -739,7 +801,7 @@ async function getBitbucketServerDownloadUrl(url, config) {
|
|
|
739
801
|
if (!branch) {
|
|
740
802
|
branch = await getBitbucketServerDefaultBranch(url, config);
|
|
741
803
|
}
|
|
742
|
-
const path = filepath ? `&path=${encodeURIComponent(filepath)}` : "";
|
|
804
|
+
const path = filepath ? `&path=${encodeURIComponent(decodeURIComponent(filepath))}` : "";
|
|
743
805
|
return `${config.apiBaseUrl}/projects/${project}/repos/${repoName}/archive?format=tgz&at=${branch}&prefix=${project}-${repoName}${path}`;
|
|
744
806
|
}
|
|
745
807
|
function getBitbucketServerFileFetchUrl(url, config) {
|
|
@@ -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
|
}
|
|
@@ -1227,11 +1358,18 @@ function readGitLabIntegrationConfigs(configs) {
|
|
|
1227
1358
|
}
|
|
1228
1359
|
return result;
|
|
1229
1360
|
}
|
|
1361
|
+
function getGitLabIntegrationRelativePath(config) {
|
|
1362
|
+
let relativePath = "";
|
|
1363
|
+
if (config.host !== GITLAB_HOST) {
|
|
1364
|
+
relativePath = new URL(config.baseUrl).pathname;
|
|
1365
|
+
}
|
|
1366
|
+
return lodash.trimEnd(relativePath, "/");
|
|
1367
|
+
}
|
|
1230
1368
|
|
|
1231
1369
|
async function getGitLabFileFetchUrl(url, config) {
|
|
1232
1370
|
if (url.includes("/-/blob/")) {
|
|
1233
1371
|
const projectID = await getProjectId(url, config);
|
|
1234
|
-
return buildProjectUrl(url, projectID).toString();
|
|
1372
|
+
return buildProjectUrl(url, projectID, config).toString();
|
|
1235
1373
|
}
|
|
1236
1374
|
return buildRawUrl(url).toString();
|
|
1237
1375
|
}
|
|
@@ -1262,13 +1400,15 @@ function buildRawUrl(target) {
|
|
|
1262
1400
|
throw new errors.InputError(`Incorrect url: ${target}, ${e}`);
|
|
1263
1401
|
}
|
|
1264
1402
|
}
|
|
1265
|
-
function buildProjectUrl(target, projectID) {
|
|
1403
|
+
function buildProjectUrl(target, projectID, config) {
|
|
1266
1404
|
try {
|
|
1267
1405
|
const url = new URL(target);
|
|
1268
1406
|
const branchAndFilePath = url.pathname.split("/-/blob/")[1];
|
|
1269
1407
|
const [branch, ...filePath] = branchAndFilePath.split("/");
|
|
1408
|
+
const relativePath = getGitLabIntegrationRelativePath(config);
|
|
1270
1409
|
url.pathname = [
|
|
1271
|
-
|
|
1410
|
+
...relativePath ? [relativePath] : [],
|
|
1411
|
+
"api/v4/projects",
|
|
1272
1412
|
projectID,
|
|
1273
1413
|
"repository/files",
|
|
1274
1414
|
encodeURIComponent(decodeURIComponent(filePath.join("/"))),
|
|
@@ -1286,12 +1426,25 @@ async function getProjectId(target, config) {
|
|
|
1286
1426
|
throw new Error("Please provide full path to yaml file from GitLab");
|
|
1287
1427
|
}
|
|
1288
1428
|
try {
|
|
1289
|
-
|
|
1290
|
-
const
|
|
1291
|
-
|
|
1429
|
+
let repo = url.pathname.split("/-/blob/")[0];
|
|
1430
|
+
const relativePath = getGitLabIntegrationRelativePath(config);
|
|
1431
|
+
if (relativePath) {
|
|
1432
|
+
repo = repo.replace(relativePath, "");
|
|
1433
|
+
}
|
|
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
|
+
);
|
|
1292
1443
|
const data = await response.json();
|
|
1293
1444
|
if (!response.ok) {
|
|
1294
|
-
throw new Error(
|
|
1445
|
+
throw new Error(
|
|
1446
|
+
`GitLab Error '${data.error}', ${data.error_description}`
|
|
1447
|
+
);
|
|
1295
1448
|
}
|
|
1296
1449
|
return Number(data.id);
|
|
1297
1450
|
} catch (e) {
|
|
@@ -1322,8 +1475,13 @@ const _GitLabIntegration = class {
|
|
|
1322
1475
|
let GitLabIntegration = _GitLabIntegration;
|
|
1323
1476
|
GitLabIntegration.factory = ({ config }) => {
|
|
1324
1477
|
var _a;
|
|
1325
|
-
const configs = readGitLabIntegrationConfigs(
|
|
1326
|
-
|
|
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
|
+
);
|
|
1327
1485
|
};
|
|
1328
1486
|
function replaceGitLabUrlType(url, type) {
|
|
1329
1487
|
return url.replace(/\/\-\/(blob|tree|edit)\//, `/-/${type}/`);
|
|
@@ -1382,7 +1540,9 @@ class ScmIntegrations {
|
|
|
1382
1540
|
return this.byType.gitlab;
|
|
1383
1541
|
}
|
|
1384
1542
|
list() {
|
|
1385
|
-
return Object.values(this.byType).flatMap(
|
|
1543
|
+
return Object.values(this.byType).flatMap(
|
|
1544
|
+
(i) => i.list()
|
|
1545
|
+
);
|
|
1386
1546
|
}
|
|
1387
1547
|
byUrl(url) {
|
|
1388
1548
|
return Object.values(this.byType).map((i) => i.byUrl(url)).find(Boolean);
|
|
@@ -1443,6 +1603,7 @@ exports.getGerritRequestOptions = getGerritRequestOptions;
|
|
|
1443
1603
|
exports.getGitHubFileFetchUrl = getGitHubFileFetchUrl;
|
|
1444
1604
|
exports.getGitHubRequestOptions = getGitHubRequestOptions;
|
|
1445
1605
|
exports.getGitLabFileFetchUrl = getGitLabFileFetchUrl;
|
|
1606
|
+
exports.getGitLabIntegrationRelativePath = getGitLabIntegrationRelativePath;
|
|
1446
1607
|
exports.getGitLabRequestOptions = getGitLabRequestOptions;
|
|
1447
1608
|
exports.parseGerritGitilesUrl = parseGerritGitilesUrl;
|
|
1448
1609
|
exports.parseGerritJsonResponse = parseGerritJsonResponse;
|