@red-hat-developer-hub/backstage-plugin-bulk-import-backend 5.0.1
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 +115 -0
- package/README.md +161 -0
- package/app-config.yaml +0 -0
- package/config.d.ts +17 -0
- package/dist/catalog/catalogHttpClient.cjs.js +284 -0
- package/dist/catalog/catalogHttpClient.cjs.js.map +1 -0
- package/dist/catalog/catalogInfoGenerator.cjs.js +60 -0
- package/dist/catalog/catalogInfoGenerator.cjs.js.map +1 -0
- package/dist/catalog/catalogUtils.cjs.js +34 -0
- package/dist/catalog/catalogUtils.cjs.js.map +1 -0
- package/dist/generated/openapidocument.cjs.js +1168 -0
- package/dist/generated/openapidocument.cjs.js.map +1 -0
- package/dist/github/GithubAppManager.cjs.js +395 -0
- package/dist/github/GithubAppManager.cjs.js.map +1 -0
- package/dist/github/githubApiService.cjs.js +659 -0
- package/dist/github/githubApiService.cjs.js.map +1 -0
- package/dist/github/types.cjs.js +8 -0
- package/dist/github/types.cjs.js.map +1 -0
- package/dist/github/utils/ghUtils.cjs.js +103 -0
- package/dist/github/utils/ghUtils.cjs.js.map +1 -0
- package/dist/github/utils/orgUtils.cjs.js +151 -0
- package/dist/github/utils/orgUtils.cjs.js.map +1 -0
- package/dist/github/utils/prUtils.cjs.js +85 -0
- package/dist/github/utils/prUtils.cjs.js.map +1 -0
- package/dist/github/utils/repoUtils.cjs.js +307 -0
- package/dist/github/utils/repoUtils.cjs.js.map +1 -0
- package/dist/github/utils/utils.cjs.js +206 -0
- package/dist/github/utils/utils.cjs.js.map +1 -0
- package/dist/helpers/auditLogUtils.cjs.js +112 -0
- package/dist/helpers/auditLogUtils.cjs.js.map +1 -0
- package/dist/helpers/auth.cjs.js +36 -0
- package/dist/helpers/auth.cjs.js.map +1 -0
- package/dist/helpers/loggingUtils.cjs.js +19 -0
- package/dist/helpers/loggingUtils.cjs.js.map +1 -0
- package/dist/helpers/pagination.cjs.js +19 -0
- package/dist/helpers/pagination.cjs.js.map +1 -0
- package/dist/index.cjs.js +12 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/plugin.cjs.js +54 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/service/handlers/handlers.cjs.js +8 -0
- package/dist/service/handlers/handlers.cjs.js.map +1 -0
- package/dist/service/handlers/import/bulkImports.cjs.js +551 -0
- package/dist/service/handlers/import/bulkImports.cjs.js.map +1 -0
- package/dist/service/handlers/import/importStatus.cjs.js +49 -0
- package/dist/service/handlers/import/importStatus.cjs.js.map +1 -0
- package/dist/service/handlers/organization/organizations.cjs.js +77 -0
- package/dist/service/handlers/organization/organizations.cjs.js.map +1 -0
- package/dist/service/handlers/ping/ping.cjs.js +12 -0
- package/dist/service/handlers/ping/ping.cjs.js.map +1 -0
- package/dist/service/handlers/repository/repositories.cjs.js +99 -0
- package/dist/service/handlers/repository/repositories.cjs.js.map +1 -0
- package/dist/service/router.cjs.js +324 -0
- package/dist/service/router.cjs.js.map +1 -0
- package/package.json +110 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"importStatus.cjs.js","sources":["../../../../src/service/handlers/import/importStatus.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { LoggerService } from '@backstage/backend-plugin-api';\nimport type { Config } from '@backstage/config';\n\nimport { CatalogHttpClient } from '../../../catalog/catalogHttpClient';\nimport {\n getCatalogFilename,\n getCatalogUrl,\n} from '../../../catalog/catalogUtils';\nimport type { Components } from '../../../generated/openapi';\nimport type { GithubApiService } from '../../../github';\n\nexport async function getImportStatusFromLocations(\n deps: {\n logger: LoggerService;\n config: Config;\n githubApiService: GithubApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n repoUrl: string,\n catalogUrlLocations: string[],\n defaultBranch?: string,\n): Promise<{\n status: Components.Schemas.ImportStatus;\n lastUpdate?: string;\n} | null> {\n return getImportStatusWithCheckerFn(\n deps,\n repoUrl,\n async (catalogUrl: string) => {\n for (const loc of catalogUrlLocations) {\n if (catalogUrl === loc) {\n return true;\n }\n }\n return false;\n },\n defaultBranch,\n );\n}\n\nasync function getImportStatusWithCheckerFn(\n deps: {\n logger: LoggerService;\n config: Config;\n githubApiService: GithubApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n repoUrl: string,\n catalogExistenceCheckFn: (catalogUrl: string) => Promise<boolean>,\n defaultBranch?: string,\n): Promise<{\n status: Components.Schemas.ImportStatus;\n lastUpdate?: string;\n} | null> {\n // Check to see if there are any PR\n const openImportPr = await deps.githubApiService.findImportOpenPr(\n deps.logger,\n {\n repoUrl,\n },\n );\n if (!openImportPr.prUrl) {\n const existsInCatalog = await catalogExistenceCheckFn(\n getCatalogUrl(deps.config, repoUrl, defaultBranch),\n );\n const existsInRepo = await deps.githubApiService.hasFileInRepo({\n repoUrl,\n defaultBranch,\n fileName: getCatalogFilename(deps.config),\n });\n if (existsInCatalog && existsInRepo) {\n // Force a refresh of the Location, so that the entities from the catalog-info.yaml can show up quickly (not guaranteed however).\n await deps.catalogHttpClient.refreshLocationByRepoUrl(\n repoUrl,\n defaultBranch,\n );\n return { status: 'ADDED' };\n }\n return null;\n }\n return { status: 'WAIT_PR_APPROVAL', lastUpdate: openImportPr.lastUpdate };\n}\n"],"names":["getCatalogUrl","getCatalogFilename"],"mappings":";;;;AA2BA,eAAsB,4BACpB,CAAA,IAAA,EAMA,OACA,EAAA,mBAAA,EACA,aAIQ,EAAA;AACR,EAAO,OAAA,4BAAA;AAAA,IACL,IAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAO,UAAuB,KAAA;AAC5B,MAAA,KAAA,MAAW,OAAO,mBAAqB,EAAA;AACrC,QAAA,IAAI,eAAe,GAAK,EAAA;AACtB,UAAO,OAAA,IAAA,CAAA;AAAA,SACT;AAAA,OACF;AACA,MAAO,OAAA,KAAA,CAAA;AAAA,KACT;AAAA,IACA,aAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEA,eAAe,4BACb,CAAA,IAAA,EAMA,OACA,EAAA,uBAAA,EACA,aAIQ,EAAA;AAER,EAAM,MAAA,YAAA,GAAe,MAAM,IAAA,CAAK,gBAAiB,CAAA,gBAAA;AAAA,IAC/C,IAAK,CAAA,MAAA;AAAA,IACL;AAAA,MACE,OAAA;AAAA,KACF;AAAA,GACF,CAAA;AACA,EAAI,IAAA,CAAC,aAAa,KAAO,EAAA;AACvB,IAAA,MAAM,kBAAkB,MAAM,uBAAA;AAAA,MAC5BA,0BAAc,CAAA,IAAA,CAAK,MAAQ,EAAA,OAAA,EAAS,aAAa,CAAA;AAAA,KACnD,CAAA;AACA,IAAA,MAAM,YAAe,GAAA,MAAM,IAAK,CAAA,gBAAA,CAAiB,aAAc,CAAA;AAAA,MAC7D,OAAA;AAAA,MACA,aAAA;AAAA,MACA,QAAA,EAAUC,+BAAmB,CAAA,IAAA,CAAK,MAAM,CAAA;AAAA,KACzC,CAAA,CAAA;AACD,IAAA,IAAI,mBAAmB,YAAc,EAAA;AAEnC,MAAA,MAAM,KAAK,iBAAkB,CAAA,wBAAA;AAAA,QAC3B,OAAA;AAAA,QACA,aAAA;AAAA,OACF,CAAA;AACA,MAAO,OAAA,EAAE,QAAQ,OAAQ,EAAA,CAAA;AAAA,KAC3B;AACA,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AACA,EAAA,OAAO,EAAE,MAAA,EAAQ,kBAAoB,EAAA,UAAA,EAAY,aAAa,UAAW,EAAA,CAAA;AAC3E;;;;"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var handlers = require('../handlers.cjs.js');
|
|
4
|
+
|
|
5
|
+
async function findAllOrganizations(logger, githubApiService, search, pageNumber = handlers.DefaultPageNumber, pageSize = handlers.DefaultPageSize) {
|
|
6
|
+
logger.debug(
|
|
7
|
+
`Getting all organizations (search,page,size)=('${search ?? ""}',${pageNumber},${pageSize})..`
|
|
8
|
+
);
|
|
9
|
+
const allOrgsAccessible = await githubApiService.getOrganizationsFromIntegrations(
|
|
10
|
+
search,
|
|
11
|
+
pageNumber,
|
|
12
|
+
pageSize
|
|
13
|
+
);
|
|
14
|
+
const errorList = [];
|
|
15
|
+
for (const err of allOrgsAccessible.errors ?? []) {
|
|
16
|
+
if (err.error?.message) {
|
|
17
|
+
errorList.push(err.error.message);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (allOrgsAccessible.organizations?.length === 0 && errorList.length > 0) {
|
|
21
|
+
return {
|
|
22
|
+
statusCode: 500,
|
|
23
|
+
responseBody: {
|
|
24
|
+
errors: errorList
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const orgMap = extractOrgMap(allOrgsAccessible);
|
|
29
|
+
const organizations = sortOrgs(orgMap);
|
|
30
|
+
return {
|
|
31
|
+
statusCode: 200,
|
|
32
|
+
responseBody: {
|
|
33
|
+
errors: errorList,
|
|
34
|
+
organizations,
|
|
35
|
+
totalCount: allOrgsAccessible.totalCount,
|
|
36
|
+
pagePerIntegration: pageNumber,
|
|
37
|
+
sizePerIntegration: pageSize
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function extractOrgMap(allOrgsAccessible) {
|
|
42
|
+
const orgMap = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const org of allOrgsAccessible.organizations ?? []) {
|
|
44
|
+
let totalRepoCount;
|
|
45
|
+
if (org.public_repos !== void 0 || org.total_private_repos !== void 0 || org.owned_private_repos !== void 0) {
|
|
46
|
+
totalRepoCount = (org.public_repos ?? 0) + (org.owned_private_repos ?? org.total_private_repos ?? 0);
|
|
47
|
+
}
|
|
48
|
+
orgMap.set(org.name, {
|
|
49
|
+
id: `${org.id}`,
|
|
50
|
+
name: org.name,
|
|
51
|
+
description: org.description,
|
|
52
|
+
url: org.url,
|
|
53
|
+
totalRepoCount,
|
|
54
|
+
errors: []
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return orgMap;
|
|
58
|
+
}
|
|
59
|
+
function sortOrgs(orgMap) {
|
|
60
|
+
const organizations = Array.from(orgMap.values());
|
|
61
|
+
organizations.sort((a, b) => {
|
|
62
|
+
if (a.name === void 0 && b.name === void 0) {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
if (a.name === void 0) {
|
|
66
|
+
return -1;
|
|
67
|
+
}
|
|
68
|
+
if (b.name === void 0) {
|
|
69
|
+
return 1;
|
|
70
|
+
}
|
|
71
|
+
return a.name.localeCompare(b.name);
|
|
72
|
+
});
|
|
73
|
+
return organizations;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
exports.findAllOrganizations = findAllOrganizations;
|
|
77
|
+
//# sourceMappingURL=organizations.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organizations.cjs.js","sources":["../../../../src/service/handlers/organization/organizations.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { LoggerService } from '@backstage/backend-plugin-api';\n\nimport type { Components } from '../../../generated/openapi';\nimport type {\n GithubApiService,\n GithubOrganizationResponse,\n} from '../../../github';\nimport {\n DefaultPageNumber,\n DefaultPageSize,\n type HandlerResponse,\n} from '../handlers';\n\nexport async function findAllOrganizations(\n logger: LoggerService,\n githubApiService: GithubApiService,\n search?: string,\n pageNumber: number = DefaultPageNumber,\n pageSize: number = DefaultPageSize,\n): Promise<HandlerResponse<Components.Schemas.OrganizationList>> {\n logger.debug(\n `Getting all organizations (search,page,size)=('${\n search ?? ''\n }',${pageNumber},${pageSize})..`,\n );\n const allOrgsAccessible =\n await githubApiService.getOrganizationsFromIntegrations(\n search,\n pageNumber,\n pageSize,\n );\n const errorList: string[] = [];\n for (const err of allOrgsAccessible.errors ?? []) {\n if (err.error?.message) {\n errorList.push(err.error.message);\n }\n }\n if (allOrgsAccessible.organizations?.length === 0 && errorList.length > 0) {\n return {\n statusCode: 500,\n responseBody: {\n errors: errorList,\n },\n };\n }\n\n const orgMap = extractOrgMap(allOrgsAccessible);\n\n // sorting the output to make it deterministic and easy to navigate in the UI\n const organizations = sortOrgs(orgMap);\n\n return {\n statusCode: 200,\n responseBody: {\n errors: errorList,\n organizations,\n totalCount: allOrgsAccessible.totalCount,\n pagePerIntegration: pageNumber,\n sizePerIntegration: pageSize,\n },\n };\n}\n\nfunction extractOrgMap(allOrgsAccessible: GithubOrganizationResponse) {\n const orgMap = new Map<string, Components.Schemas.Organization>();\n for (const org of allOrgsAccessible.organizations ?? []) {\n let totalRepoCount: number | undefined;\n if (\n org.public_repos !== undefined ||\n org.total_private_repos !== undefined ||\n org.owned_private_repos !== undefined\n ) {\n totalRepoCount =\n (org.public_repos ?? 0) +\n (org.owned_private_repos ?? org.total_private_repos ?? 0);\n }\n orgMap.set(org.name, {\n id: `${org.id}`,\n name: org.name,\n description: org.description,\n url: org.url,\n totalRepoCount,\n errors: [],\n });\n }\n return orgMap;\n}\n\nfunction sortOrgs(orgMap: Map<string, Components.Schemas.Organization>) {\n const organizations = Array.from(orgMap.values());\n organizations.sort((a, b) => {\n if (a.name === undefined && b.name === undefined) {\n return 0;\n }\n if (a.name === undefined) {\n return -1;\n }\n if (b.name === undefined) {\n return 1;\n }\n return a.name.localeCompare(b.name);\n });\n return organizations;\n}\n"],"names":["DefaultPageNumber","DefaultPageSize"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ping.cjs.js","sources":["../../../../src/service/handlers/ping/ping.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { LoggerService } from '@backstage/backend-plugin-api';\n\nimport type { Paths } from '../../../generated/openapi';\nimport type { HandlerResponse } from '../handlers';\n\nexport async function ping(\n logger: LoggerService,\n): Promise<HandlerResponse<Paths.Ping.Responses.$200>> {\n logger.debug('PONG!');\n return {\n statusCode: 200,\n responseBody: { status: 'ok' },\n };\n}\n"],"names":[],"mappings":";;AAqBA,eAAsB,KACpB,MACqD,EAAA;AACrD,EAAA,MAAA,CAAO,MAAM,OAAO,CAAA,CAAA;AACpB,EAAO,OAAA;AAAA,IACL,UAAY,EAAA,GAAA;AAAA,IACZ,YAAA,EAAc,EAAE,MAAA,EAAQ,IAAK,EAAA;AAAA,GAC/B,CAAA;AACF;;;;"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var gitUrlParse = require('git-url-parse');
|
|
4
|
+
var handlers = require('../handlers.cjs.js');
|
|
5
|
+
require('@backstage/errors');
|
|
6
|
+
require('@backstage/plugin-permission-common');
|
|
7
|
+
require('@red-hat-developer-hub/backstage-plugin-bulk-import-common');
|
|
8
|
+
var importStatus = require('../import/importStatus.cjs.js');
|
|
9
|
+
|
|
10
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
11
|
+
|
|
12
|
+
var gitUrlParse__default = /*#__PURE__*/_interopDefaultCompat(gitUrlParse);
|
|
13
|
+
|
|
14
|
+
async function findAllRepositories(deps, reqParams) {
|
|
15
|
+
const search = reqParams?.search;
|
|
16
|
+
const checkStatus = reqParams?.checkStatus ?? false;
|
|
17
|
+
const pageNumber = reqParams?.pageNumber ?? handlers.DefaultPageNumber;
|
|
18
|
+
const pageSize = reqParams?.pageSize ?? handlers.DefaultPageSize;
|
|
19
|
+
deps.logger.debug(
|
|
20
|
+
`Getting all repositories - (search,page,size)=('${search ?? ""}',${pageNumber},${pageSize})..`
|
|
21
|
+
);
|
|
22
|
+
return deps.githubApiService.getRepositoriesFromIntegrations(search, pageNumber, pageSize).then((response) => formatResponse(deps, response, checkStatus));
|
|
23
|
+
}
|
|
24
|
+
async function findRepositoriesByOrganization(deps, orgName, search, checkStatus = false, pageNumber = handlers.DefaultPageNumber, pageSize = handlers.DefaultPageSize) {
|
|
25
|
+
deps.logger.debug(
|
|
26
|
+
`Getting all repositories for org "${orgName}" - (search,page,size)=(${search},${pageNumber},${pageSize})..`
|
|
27
|
+
);
|
|
28
|
+
return deps.githubApiService.getOrgRepositoriesFromIntegrations(orgName, search, pageNumber, pageSize).then((response) => formatResponse(deps, response, checkStatus));
|
|
29
|
+
}
|
|
30
|
+
function sortRepos(repoList) {
|
|
31
|
+
repoList.sort((a, b) => {
|
|
32
|
+
if (a.name === void 0 && b.name === void 0) {
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
if (a.name === void 0) {
|
|
36
|
+
return -1;
|
|
37
|
+
}
|
|
38
|
+
if (b.name === void 0) {
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
return a.name.localeCompare(b.name);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async function formatResponse(deps, allReposAccessible, checkStatus) {
|
|
45
|
+
const errorList = allReposAccessible.errors?.map((err) => err.error?.message)?.filter((msg) => msg) ?? [];
|
|
46
|
+
if (allReposAccessible.repositories?.length === 0 && errorList.length > 0) {
|
|
47
|
+
return {
|
|
48
|
+
statusCode: 500,
|
|
49
|
+
responseBody: {
|
|
50
|
+
errors: errorList
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
let catalogLocations = [];
|
|
55
|
+
if (checkStatus) {
|
|
56
|
+
catalogLocations = (await deps.catalogHttpClient.listCatalogUrlLocations()).targetUrls;
|
|
57
|
+
}
|
|
58
|
+
const repoList = [];
|
|
59
|
+
for (const repo of allReposAccessible.repositories) {
|
|
60
|
+
const gitUrl = gitUrlParse__default.default(repo.html_url);
|
|
61
|
+
const errors = [];
|
|
62
|
+
let importStatus$1;
|
|
63
|
+
if (checkStatus) {
|
|
64
|
+
importStatus$1 = await importStatus.getImportStatusFromLocations(
|
|
65
|
+
deps,
|
|
66
|
+
repo.html_url,
|
|
67
|
+
catalogLocations,
|
|
68
|
+
repo.default_branch
|
|
69
|
+
).catch((error) => {
|
|
70
|
+
errors.push(error.message);
|
|
71
|
+
return void 0;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const repoUpdatedAt = repo.updated_at ?? void 0;
|
|
75
|
+
repoList.push({
|
|
76
|
+
id: `${gitUrl.organization}/${repo.name}`,
|
|
77
|
+
name: repo.name,
|
|
78
|
+
organization: gitUrl.organization,
|
|
79
|
+
url: repo.html_url,
|
|
80
|
+
defaultBranch: repo.default_branch,
|
|
81
|
+
importStatus: importStatus$1?.status,
|
|
82
|
+
lastUpdate: importStatus$1?.lastUpdate ?? repoUpdatedAt,
|
|
83
|
+
errors
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
sortRepos(repoList);
|
|
87
|
+
return {
|
|
88
|
+
statusCode: 200,
|
|
89
|
+
responseBody: {
|
|
90
|
+
errors: errorList,
|
|
91
|
+
repositories: repoList,
|
|
92
|
+
totalCount: allReposAccessible.totalCount
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
exports.findAllRepositories = findAllRepositories;
|
|
98
|
+
exports.findRepositoriesByOrganization = findRepositoriesByOrganization;
|
|
99
|
+
//# sourceMappingURL=repositories.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositories.cjs.js","sources":["../../../../src/service/handlers/repository/repositories.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { LoggerService } from '@backstage/backend-plugin-api';\nimport type { Config } from '@backstage/config';\n\nimport gitUrlParse from 'git-url-parse';\n\nimport { CatalogHttpClient } from '../../../catalog/catalogHttpClient';\nimport type { Components } from '../../../generated/openapi';\nimport type {\n GithubApiService,\n GithubRepositoryResponse,\n} from '../../../github';\nimport {\n DefaultPageNumber,\n DefaultPageSize,\n type HandlerResponse,\n} from '../handlers';\nimport { getImportStatusFromLocations } from '../import';\n\nexport async function findAllRepositories(\n deps: {\n logger: LoggerService;\n config: Config;\n githubApiService: GithubApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n reqParams?: {\n search?: string;\n checkStatus?: boolean;\n pageNumber?: number;\n pageSize?: number;\n },\n): Promise<HandlerResponse<Components.Schemas.RepositoryList>> {\n const search = reqParams?.search;\n const checkStatus = reqParams?.checkStatus ?? false;\n const pageNumber = reqParams?.pageNumber ?? DefaultPageNumber;\n const pageSize = reqParams?.pageSize ?? DefaultPageSize;\n deps.logger.debug(\n `Getting all repositories - (search,page,size)=('${\n search ?? ''\n }',${pageNumber},${pageSize})..`,\n );\n return deps.githubApiService\n .getRepositoriesFromIntegrations(search, pageNumber, pageSize)\n .then(response => formatResponse(deps, response, checkStatus));\n}\n\nexport async function findRepositoriesByOrganization(\n deps: {\n logger: LoggerService;\n config: Config;\n githubApiService: GithubApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n orgName: string,\n search?: string,\n checkStatus: boolean = false,\n pageNumber: number = DefaultPageNumber,\n pageSize: number = DefaultPageSize,\n): Promise<HandlerResponse<Components.Schemas.RepositoryList>> {\n deps.logger.debug(\n `Getting all repositories for org \"${orgName}\" - (search,page,size)=(${search},${pageNumber},${pageSize})..`,\n );\n return deps.githubApiService\n .getOrgRepositoriesFromIntegrations(orgName, search, pageNumber, pageSize)\n .then(response => formatResponse(deps, response, checkStatus));\n}\n\nfunction sortRepos(repoList: Components.Schemas.Repository[]) {\n // sorting the output to make it deterministic and easy to navigate in the UI\n repoList.sort((a, b) => {\n if (a.name === undefined && b.name === undefined) {\n return 0;\n }\n if (a.name === undefined) {\n return -1;\n }\n if (b.name === undefined) {\n return 1;\n }\n return a.name.localeCompare(b.name);\n });\n}\n\ntype ImportStatus =\n | { status: Components.Schemas.ImportStatus; lastUpdate?: string }\n | null\n | undefined;\n\nasync function formatResponse(\n deps: {\n logger: LoggerService;\n config: Config;\n githubApiService: GithubApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n allReposAccessible: GithubRepositoryResponse,\n checkStatus: boolean,\n) {\n const errorList =\n allReposAccessible.errors\n ?.map(err => err.error?.message)\n ?.filter(msg => msg) ?? [];\n if (allReposAccessible.repositories?.length === 0 && errorList.length > 0) {\n return {\n statusCode: 500,\n responseBody: {\n errors: errorList,\n },\n };\n }\n\n let catalogLocations: string[] = [];\n if (checkStatus) {\n catalogLocations = (await deps.catalogHttpClient.listCatalogUrlLocations())\n .targetUrls;\n }\n const repoList: Components.Schemas.Repository[] = [];\n for (const repo of allReposAccessible.repositories) {\n const gitUrl = gitUrlParse(repo.html_url);\n const errors: string[] = [];\n let importStatus: ImportStatus;\n if (checkStatus) {\n importStatus = await getImportStatusFromLocations(\n deps,\n repo.html_url,\n catalogLocations,\n repo.default_branch,\n ).catch((error: any) => {\n errors.push(error.message);\n return undefined;\n });\n }\n const repoUpdatedAt = repo.updated_at ?? undefined;\n repoList.push({\n id: `${gitUrl.organization}/${repo.name}`,\n name: repo.name,\n organization: gitUrl.organization,\n url: repo.html_url,\n defaultBranch: repo.default_branch,\n importStatus: importStatus?.status,\n lastUpdate: importStatus?.lastUpdate ?? repoUpdatedAt,\n errors: errors,\n });\n }\n\n sortRepos(repoList);\n\n return {\n statusCode: 200,\n responseBody: {\n errors: errorList,\n repositories: repoList,\n totalCount: allReposAccessible.totalCount,\n },\n };\n}\n"],"names":["DefaultPageNumber","DefaultPageSize","gitUrlParse","importStatus","getImportStatusFromLocations"],"mappings":"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"}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
4
|
+
var pluginPermissionNode = require('@backstage/plugin-permission-node');
|
|
5
|
+
var backstagePluginAuditLogNode = require('@janus-idp/backstage-plugin-audit-log-node');
|
|
6
|
+
var formats = require('ajv-formats/dist/formats');
|
|
7
|
+
var express = require('express');
|
|
8
|
+
var openapiBackend = require('openapi-backend');
|
|
9
|
+
var backstagePluginBulkImportCommon = require('@red-hat-developer-hub/backstage-plugin-bulk-import-common');
|
|
10
|
+
var catalogHttpClient = require('../catalog/catalogHttpClient.cjs.js');
|
|
11
|
+
var catalogInfoGenerator = require('../catalog/catalogInfoGenerator.cjs.js');
|
|
12
|
+
var openapidocument = require('../generated/openapidocument.cjs.js');
|
|
13
|
+
require('@octokit/auth-app');
|
|
14
|
+
require('@octokit/rest');
|
|
15
|
+
require('git-url-parse');
|
|
16
|
+
require('luxon');
|
|
17
|
+
var githubApiService = require('../github/githubApiService.cjs.js');
|
|
18
|
+
var auth = require('../helpers/auth.cjs.js');
|
|
19
|
+
require('@backstage/errors');
|
|
20
|
+
var auditLogUtils = require('../helpers/auditLogUtils.cjs.js');
|
|
21
|
+
var bulkImports = require('./handlers/import/bulkImports.cjs.js');
|
|
22
|
+
var organizations = require('./handlers/organization/organizations.cjs.js');
|
|
23
|
+
var ping = require('./handlers/ping/ping.cjs.js');
|
|
24
|
+
var repositories = require('./handlers/repository/repositories.cjs.js');
|
|
25
|
+
|
|
26
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
27
|
+
|
|
28
|
+
var express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
29
|
+
|
|
30
|
+
async function createRouter(options) {
|
|
31
|
+
const {
|
|
32
|
+
logger,
|
|
33
|
+
httpAuth,
|
|
34
|
+
auth: auth$1,
|
|
35
|
+
permissions,
|
|
36
|
+
config,
|
|
37
|
+
cache,
|
|
38
|
+
discovery,
|
|
39
|
+
catalogApi
|
|
40
|
+
} = options;
|
|
41
|
+
const auditLogger = new backstagePluginAuditLogNode.DefaultAuditLogger({
|
|
42
|
+
logger,
|
|
43
|
+
authService: auth$1,
|
|
44
|
+
httpAuthService: httpAuth
|
|
45
|
+
});
|
|
46
|
+
const githubApiService$1 = new githubApiService.GithubApiService(logger, config, cache);
|
|
47
|
+
const catalogHttpClient$1 = new catalogHttpClient.CatalogHttpClient({
|
|
48
|
+
logger,
|
|
49
|
+
config,
|
|
50
|
+
discovery,
|
|
51
|
+
auth: auth$1,
|
|
52
|
+
catalogApi
|
|
53
|
+
});
|
|
54
|
+
const catalogInfoGenerator$1 = new catalogInfoGenerator.CatalogInfoGenerator(
|
|
55
|
+
logger,
|
|
56
|
+
catalogHttpClient$1
|
|
57
|
+
);
|
|
58
|
+
const api = new openapiBackend.OpenAPIBackend({
|
|
59
|
+
ajvOpts: {
|
|
60
|
+
verbose: true,
|
|
61
|
+
formats: formats.fullFormats
|
|
62
|
+
// open issue: https://github.com/openapistack/openapi-backend/issues/280
|
|
63
|
+
},
|
|
64
|
+
validate: true,
|
|
65
|
+
definition: openapidocument.openApiDocument,
|
|
66
|
+
handlers: {
|
|
67
|
+
validationFail: async (c, _req, res) => res.status(400).json({ err: c.validation.errors }),
|
|
68
|
+
notFound: async (_c, req, res) => res.status(404).json({ err: `'${req.method} ${req.path}' not found` }),
|
|
69
|
+
notImplemented: async (_c, req, res) => res.status(500).json({ err: `'${req.method} ${req.path}' not implemented` })
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
await api.init();
|
|
73
|
+
api.register("ping", async (_c, _req, res) => {
|
|
74
|
+
const result = await ping.ping(logger);
|
|
75
|
+
return res.status(result.statusCode).json(result.responseBody);
|
|
76
|
+
});
|
|
77
|
+
api.register(
|
|
78
|
+
"findAllOrganizations",
|
|
79
|
+
async (c, _req, res) => {
|
|
80
|
+
const q = {
|
|
81
|
+
...c.request.query
|
|
82
|
+
};
|
|
83
|
+
q.pagePerIntegration = stringToNumber(q.pagePerIntegration);
|
|
84
|
+
q.sizePerIntegration = stringToNumber(q.sizePerIntegration);
|
|
85
|
+
const response = await organizations.findAllOrganizations(
|
|
86
|
+
logger,
|
|
87
|
+
githubApiService$1,
|
|
88
|
+
q.search,
|
|
89
|
+
q.pagePerIntegration,
|
|
90
|
+
q.sizePerIntegration
|
|
91
|
+
);
|
|
92
|
+
return res.status(response.statusCode).json({
|
|
93
|
+
errors: response.responseBody?.errors,
|
|
94
|
+
organizations: response.responseBody?.organizations,
|
|
95
|
+
totalCount: response.responseBody?.totalCount,
|
|
96
|
+
pagePerIntegration: response.responseBody?.pagePerIntegration,
|
|
97
|
+
sizePerIntegration: response.responseBody?.sizePerIntegration
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
api.register(
|
|
102
|
+
"findAllRepositories",
|
|
103
|
+
async (c, _req, res) => {
|
|
104
|
+
const q = {
|
|
105
|
+
...c.request.query
|
|
106
|
+
};
|
|
107
|
+
q.pagePerIntegration = stringToNumber(q.pagePerIntegration);
|
|
108
|
+
q.sizePerIntegration = stringToNumber(q.sizePerIntegration);
|
|
109
|
+
q.checkImportStatus = stringToBoolean(q.checkImportStatus);
|
|
110
|
+
const response = await repositories.findAllRepositories(
|
|
111
|
+
{
|
|
112
|
+
logger,
|
|
113
|
+
config,
|
|
114
|
+
githubApiService: githubApiService$1,
|
|
115
|
+
catalogHttpClient: catalogHttpClient$1
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
search: q.search,
|
|
119
|
+
checkStatus: q.checkImportStatus,
|
|
120
|
+
pageNumber: q.pagePerIntegration,
|
|
121
|
+
pageSize: q.sizePerIntegration
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
const repos = response.responseBody?.repositories;
|
|
125
|
+
return res.status(response.statusCode).json({
|
|
126
|
+
errors: response.responseBody?.errors,
|
|
127
|
+
repositories: repos,
|
|
128
|
+
totalCount: response.responseBody?.totalCount,
|
|
129
|
+
pagePerIntegration: q.pagePerIntegration,
|
|
130
|
+
sizePerIntegration: q.sizePerIntegration
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
api.register(
|
|
135
|
+
"findRepositoriesByOrganization",
|
|
136
|
+
async (c, _req, res) => {
|
|
137
|
+
const q = {
|
|
138
|
+
...c.request.query
|
|
139
|
+
};
|
|
140
|
+
q.pagePerIntegration = stringToNumber(q.pagePerIntegration);
|
|
141
|
+
q.sizePerIntegration = stringToNumber(q.sizePerIntegration);
|
|
142
|
+
q.checkImportStatus = stringToBoolean(q.checkImportStatus);
|
|
143
|
+
const response = await repositories.findRepositoriesByOrganization(
|
|
144
|
+
{
|
|
145
|
+
logger,
|
|
146
|
+
config,
|
|
147
|
+
githubApiService: githubApiService$1,
|
|
148
|
+
catalogHttpClient: catalogHttpClient$1
|
|
149
|
+
},
|
|
150
|
+
c.request.params.organizationName?.toString(),
|
|
151
|
+
q.search,
|
|
152
|
+
q.checkImportStatus,
|
|
153
|
+
q.pagePerIntegration,
|
|
154
|
+
q.sizePerIntegration
|
|
155
|
+
);
|
|
156
|
+
const repos = response.responseBody?.repositories;
|
|
157
|
+
return res.status(response.statusCode).json({
|
|
158
|
+
errors: response.responseBody?.errors,
|
|
159
|
+
repositories: repos,
|
|
160
|
+
totalCount: response.responseBody?.totalCount,
|
|
161
|
+
pagePerIntegration: q.pagePerIntegration,
|
|
162
|
+
sizePerIntegration: q.sizePerIntegration
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
api.register(
|
|
167
|
+
"findAllImports",
|
|
168
|
+
async (c, _req, res) => {
|
|
169
|
+
const h = {
|
|
170
|
+
...c.request.headers
|
|
171
|
+
};
|
|
172
|
+
const apiVersion = h["api-version"];
|
|
173
|
+
const q = {
|
|
174
|
+
...c.request.query
|
|
175
|
+
};
|
|
176
|
+
let page;
|
|
177
|
+
let size;
|
|
178
|
+
if (apiVersion === void 0 || apiVersion === "v1") {
|
|
179
|
+
page = stringToNumber(q.page || q.pagePerIntegration);
|
|
180
|
+
size = stringToNumber(q.size || q.sizePerIntegration);
|
|
181
|
+
} else {
|
|
182
|
+
page = stringToNumber(q.page);
|
|
183
|
+
size = stringToNumber(q.size);
|
|
184
|
+
}
|
|
185
|
+
const response = await bulkImports.findAllImports(
|
|
186
|
+
{
|
|
187
|
+
logger,
|
|
188
|
+
config,
|
|
189
|
+
githubApiService: githubApiService$1,
|
|
190
|
+
catalogHttpClient: catalogHttpClient$1
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
apiVersion
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
search: q.search,
|
|
197
|
+
pageNumber: page,
|
|
198
|
+
pageSize: size
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
return res.status(response.statusCode).json(response.responseBody);
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
api.register(
|
|
205
|
+
"createImportJobs",
|
|
206
|
+
async (c, _req, res) => {
|
|
207
|
+
const q = {
|
|
208
|
+
...c.request.query
|
|
209
|
+
};
|
|
210
|
+
q.dryRun = stringToBoolean(q.dryRun);
|
|
211
|
+
const response = await bulkImports.createImportJobs(
|
|
212
|
+
{
|
|
213
|
+
logger,
|
|
214
|
+
config,
|
|
215
|
+
auth: auth$1,
|
|
216
|
+
catalogApi,
|
|
217
|
+
githubApiService: githubApiService$1,
|
|
218
|
+
catalogInfoGenerator: catalogInfoGenerator$1,
|
|
219
|
+
catalogHttpClient: catalogHttpClient$1
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
importRequests: c.request.requestBody,
|
|
223
|
+
dryRun: q.dryRun
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
return res.status(response.statusCode).json(response.responseBody);
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
api.register(
|
|
230
|
+
"findImportStatusByRepo",
|
|
231
|
+
async (c, _req, res) => {
|
|
232
|
+
const q = {
|
|
233
|
+
...c.request.query
|
|
234
|
+
};
|
|
235
|
+
if (!q.repo?.trim()) {
|
|
236
|
+
throw new Error("missing or blank parameter");
|
|
237
|
+
}
|
|
238
|
+
const response = await bulkImports.findImportStatusByRepo(
|
|
239
|
+
{
|
|
240
|
+
logger,
|
|
241
|
+
config,
|
|
242
|
+
githubApiService: githubApiService$1,
|
|
243
|
+
catalogHttpClient: catalogHttpClient$1
|
|
244
|
+
},
|
|
245
|
+
q.repo,
|
|
246
|
+
q.defaultBranch,
|
|
247
|
+
true
|
|
248
|
+
);
|
|
249
|
+
return res.status(response.statusCode).json(response.responseBody);
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
api.register(
|
|
253
|
+
"deleteImportByRepo",
|
|
254
|
+
async (c, _req, res) => {
|
|
255
|
+
const q = {
|
|
256
|
+
...c.request.query
|
|
257
|
+
};
|
|
258
|
+
if (!q.repo?.trim()) {
|
|
259
|
+
throw new Error('missing or blank "repo" parameter');
|
|
260
|
+
}
|
|
261
|
+
const response = await bulkImports.deleteImportByRepo(
|
|
262
|
+
{
|
|
263
|
+
logger,
|
|
264
|
+
config,
|
|
265
|
+
githubApiService: githubApiService$1,
|
|
266
|
+
catalogHttpClient: catalogHttpClient$1
|
|
267
|
+
},
|
|
268
|
+
q.repo,
|
|
269
|
+
q.defaultBranch
|
|
270
|
+
);
|
|
271
|
+
return res.status(response.statusCode).json(response.responseBody);
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
const router = express.Router();
|
|
275
|
+
router.use(express__default.default.json());
|
|
276
|
+
const permissionIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
|
|
277
|
+
permissions: [backstagePluginBulkImportCommon.bulkImportPermission]
|
|
278
|
+
});
|
|
279
|
+
router.use(permissionIntegrationRouter);
|
|
280
|
+
router.use(async (req, _res, next) => {
|
|
281
|
+
if (req.path !== "/ping") {
|
|
282
|
+
await auth.permissionCheck(
|
|
283
|
+
auditLogger,
|
|
284
|
+
api.matchOperation(req)?.operationId,
|
|
285
|
+
permissions,
|
|
286
|
+
httpAuth,
|
|
287
|
+
req
|
|
288
|
+
).catch(next);
|
|
289
|
+
}
|
|
290
|
+
next();
|
|
291
|
+
});
|
|
292
|
+
router.use(async (req, res, next) => {
|
|
293
|
+
const reqCast = req;
|
|
294
|
+
const operationId = api.matchOperation(reqCast)?.operationId;
|
|
295
|
+
try {
|
|
296
|
+
const response = await api.handleRequest(reqCast, req, res);
|
|
297
|
+
auditLogUtils.auditLogRequestSuccess(
|
|
298
|
+
auditLogger,
|
|
299
|
+
operationId,
|
|
300
|
+
req,
|
|
301
|
+
response.statusCode
|
|
302
|
+
);
|
|
303
|
+
next();
|
|
304
|
+
} catch (err) {
|
|
305
|
+
auditLogUtils.auditLogRequestError(auditLogger, operationId, req, err);
|
|
306
|
+
next(err);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
const middleware = rootHttpRouter.MiddlewareFactory.create({ logger, config });
|
|
310
|
+
router.use(middleware.error());
|
|
311
|
+
return router;
|
|
312
|
+
}
|
|
313
|
+
function stringToNumber(s) {
|
|
314
|
+
return s ? Number.parseInt(s.toString(), 10) : void 0;
|
|
315
|
+
}
|
|
316
|
+
function stringToBoolean(s) {
|
|
317
|
+
if (!s) {
|
|
318
|
+
return void 0;
|
|
319
|
+
}
|
|
320
|
+
return s.toString() === "true";
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
exports.createRouter = createRouter;
|
|
324
|
+
//# sourceMappingURL=router.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport type {\n AuthService,\n CacheService,\n DiscoveryService,\n HttpAuthService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport type { CatalogApi } from '@backstage/catalog-client';\nimport type { Config } from '@backstage/config';\nimport type { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';\n\nimport {\n DefaultAuditLogger,\n type AuditLogger,\n} from '@janus-idp/backstage-plugin-audit-log-node';\nimport { fullFormats } from 'ajv-formats/dist/formats';\nimport express, { Router, type Request, type Response } from 'express';\nimport {\n OpenAPIBackend,\n type Context,\n type Request as OpenAPIRequest,\n} from 'openapi-backend';\n\nimport { bulkImportPermission } from '@red-hat-developer-hub/backstage-plugin-bulk-import-common';\n\nimport { CatalogHttpClient } from '../catalog/catalogHttpClient';\nimport { CatalogInfoGenerator } from '../catalog/catalogInfoGenerator';\nimport type { Components, Paths } from '../generated/openapi.d';\nimport { openApiDocument } from '../generated/openapidocument';\nimport { GithubApiService } from '../github';\nimport { permissionCheck } from '../helpers';\nimport {\n auditLogRequestError,\n auditLogRequestSuccess,\n} from '../helpers/auditLogUtils';\nimport {\n createImportJobs,\n deleteImportByRepo,\n findAllImports,\n findImportStatusByRepo,\n} from './handlers/import';\nimport { findAllOrganizations } from './handlers/organization';\nimport { ping } from './handlers/ping';\nimport {\n findAllRepositories,\n findRepositoriesByOrganization,\n} from './handlers/repository';\n\nexport interface RouterOptions {\n logger: LoggerService;\n permissions: PermissionEvaluator;\n config: Config;\n cache: CacheService;\n discovery: DiscoveryService;\n httpAuth: HttpAuthService;\n auth: AuthService;\n catalogApi: CatalogApi;\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const {\n logger,\n httpAuth,\n auth,\n permissions,\n config,\n cache,\n discovery,\n catalogApi,\n } = options;\n\n const auditLogger: AuditLogger = new DefaultAuditLogger({\n logger: logger,\n authService: auth,\n httpAuthService: httpAuth,\n });\n\n const githubApiService = new GithubApiService(logger, config, cache);\n const catalogHttpClient = new CatalogHttpClient({\n logger,\n config,\n discovery,\n auth,\n catalogApi,\n });\n const catalogInfoGenerator = new CatalogInfoGenerator(\n logger,\n catalogHttpClient,\n );\n\n // create openapi requests handler\n const api = new OpenAPIBackend({\n ajvOpts: {\n verbose: true,\n formats: fullFormats, // open issue: https://github.com/openapistack/openapi-backend/issues/280\n },\n validate: true,\n definition: openApiDocument,\n handlers: {\n validationFail: async (c, _req: Request, res: Response) =>\n res.status(400).json({ err: c.validation.errors }),\n notFound: async (_c, req: Request, res: Response) =>\n res.status(404).json({ err: `'${req.method} ${req.path}' not found` }),\n notImplemented: async (_c, req: Request, res: Response) =>\n res\n .status(500)\n .json({ err: `'${req.method} ${req.path}' not implemented` }),\n },\n });\n\n await api.init();\n\n api.register('ping', async (_c: Context, _req: Request, res: Response) => {\n const result = await ping(logger);\n return res.status(result.statusCode).json(result.responseBody);\n });\n\n api.register(\n 'findAllOrganizations',\n async (c: Context, _req: Request, res: Response) => {\n const q: Paths.FindAllOrganizations.QueryParameters = {\n ...c.request.query,\n };\n // we need to convert strings to real types due to open PR https://github.com/openapistack/openapi-backend/pull/571\n q.pagePerIntegration = stringToNumber(q.pagePerIntegration);\n q.sizePerIntegration = stringToNumber(q.sizePerIntegration);\n const response = await findAllOrganizations(\n logger,\n githubApiService,\n q.search,\n q.pagePerIntegration,\n q.sizePerIntegration,\n );\n return res.status(response.statusCode).json({\n errors: response.responseBody?.errors,\n organizations: response.responseBody?.organizations,\n totalCount: response.responseBody?.totalCount,\n pagePerIntegration: response.responseBody?.pagePerIntegration,\n sizePerIntegration: response.responseBody?.sizePerIntegration,\n } as Components.Schemas.OrganizationList);\n },\n );\n\n api.register(\n 'findAllRepositories',\n async (c: Context, _req: Request, res: Response) => {\n const q: Paths.FindAllRepositories.QueryParameters = {\n ...c.request.query,\n };\n // we need to convert strings to real types due to open PR https://github.com/openapistack/openapi-backend/pull/571\n q.pagePerIntegration = stringToNumber(q.pagePerIntegration);\n q.sizePerIntegration = stringToNumber(q.sizePerIntegration);\n q.checkImportStatus = stringToBoolean(q.checkImportStatus);\n const response = await findAllRepositories(\n {\n logger,\n config,\n githubApiService,\n catalogHttpClient,\n },\n {\n search: q.search,\n checkStatus: q.checkImportStatus,\n pageNumber: q.pagePerIntegration,\n pageSize: q.sizePerIntegration,\n },\n );\n const repos = response.responseBody?.repositories;\n return res.status(response.statusCode).json({\n errors: response.responseBody?.errors,\n repositories: repos,\n totalCount: response.responseBody?.totalCount,\n pagePerIntegration: q.pagePerIntegration,\n sizePerIntegration: q.sizePerIntegration,\n } as Components.Schemas.RepositoryList);\n },\n );\n\n api.register(\n 'findRepositoriesByOrganization',\n async (c: Context, _req: Request, res: Response) => {\n const q: Paths.FindRepositoriesByOrganization.QueryParameters = {\n ...c.request.query,\n };\n // we need to convert strings to real types due to open PR https://github.com/openapistack/openapi-backend/pull/571\n q.pagePerIntegration = stringToNumber(q.pagePerIntegration);\n q.sizePerIntegration = stringToNumber(q.sizePerIntegration);\n q.checkImportStatus = stringToBoolean(q.checkImportStatus);\n const response = await findRepositoriesByOrganization(\n {\n logger,\n config,\n githubApiService,\n catalogHttpClient,\n },\n c.request.params.organizationName?.toString(),\n q.search,\n q.checkImportStatus,\n q.pagePerIntegration,\n q.sizePerIntegration,\n );\n const repos = response.responseBody?.repositories;\n return res.status(response.statusCode).json({\n errors: response.responseBody?.errors,\n repositories: repos,\n totalCount: response.responseBody?.totalCount,\n pagePerIntegration: q.pagePerIntegration,\n sizePerIntegration: q.sizePerIntegration,\n } as Components.Schemas.RepositoryList);\n },\n );\n\n api.register(\n 'findAllImports',\n async (c: Context, _req: Request, res: Response) => {\n const h: Paths.FindAllImports.HeaderParameters = {\n ...c.request.headers,\n };\n const apiVersion = h['api-version'];\n const q: Paths.FindAllImports.QueryParameters = {\n ...c.request.query,\n };\n // we need to convert strings to real types due to open PR https://github.com/openapistack/openapi-backend/pull/571\n let page: number | undefined;\n let size: number | undefined;\n if (apiVersion === undefined || apiVersion === 'v1') {\n // pagePerIntegration and sizePerIntegration deprecated in v1. 'page' and 'size' take precedence.\n page = stringToNumber(q.page || q.pagePerIntegration);\n size = stringToNumber(q.size || q.sizePerIntegration);\n } else {\n // pagePerIntegration and sizePerIntegration removed in v2+ and replaced by 'page' and 'size'.\n page = stringToNumber(q.page);\n size = stringToNumber(q.size);\n }\n const response = await findAllImports(\n {\n logger,\n config,\n githubApiService,\n catalogHttpClient,\n },\n {\n apiVersion,\n },\n {\n search: q.search,\n pageNumber: page,\n pageSize: size,\n },\n );\n return res.status(response.statusCode).json(response.responseBody);\n },\n );\n\n api.register(\n 'createImportJobs',\n async (\n c: Context<Paths.CreateImportJobs.RequestBody>,\n _req: Request,\n res: Response,\n ) => {\n const q: Paths.CreateImportJobs.QueryParameters = {\n ...c.request.query,\n };\n q.dryRun = stringToBoolean(q.dryRun);\n const response = await createImportJobs(\n {\n logger,\n config,\n auth,\n catalogApi,\n githubApiService,\n catalogInfoGenerator,\n catalogHttpClient,\n },\n {\n importRequests: c.request.requestBody,\n dryRun: q.dryRun,\n },\n );\n return res.status(response.statusCode).json(response.responseBody);\n },\n );\n\n api.register(\n 'findImportStatusByRepo',\n async (c: Context, _req: Request, res: Response) => {\n const q: Paths.FindImportStatusByRepo.QueryParameters = {\n ...c.request.query,\n };\n if (!q.repo?.trim()) {\n throw new Error('missing or blank parameter');\n }\n const response = await findImportStatusByRepo(\n {\n logger,\n config,\n githubApiService,\n catalogHttpClient,\n },\n q.repo,\n q.defaultBranch,\n true,\n );\n return res.status(response.statusCode).json(response.responseBody);\n },\n );\n\n api.register(\n 'deleteImportByRepo',\n async (c: Context, _req: Request, res: Response) => {\n const q: Paths.DeleteImportByRepo.QueryParameters = {\n ...c.request.query,\n };\n if (!q.repo?.trim()) {\n throw new Error('missing or blank \"repo\" parameter');\n }\n const response = await deleteImportByRepo(\n {\n logger,\n config,\n githubApiService,\n catalogHttpClient,\n },\n q.repo,\n q.defaultBranch,\n );\n return res.status(response.statusCode).json(response.responseBody);\n },\n );\n\n const router = Router();\n router.use(express.json());\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n permissions: [bulkImportPermission],\n });\n router.use(permissionIntegrationRouter);\n\n router.use(async (req, _res, next) => {\n if (req.path !== '/ping') {\n await permissionCheck(\n auditLogger,\n api.matchOperation(req as OpenAPIRequest)?.operationId,\n permissions,\n httpAuth,\n req,\n ).catch(next);\n }\n next();\n });\n\n router.use(async (req, res, next) => {\n const reqCast = req as OpenAPIRequest;\n const operationId = api.matchOperation(reqCast)?.operationId;\n try {\n const response = (await api.handleRequest(reqCast, req, res)) as Response;\n auditLogRequestSuccess(\n auditLogger,\n operationId,\n req,\n response.statusCode,\n );\n next();\n } catch (err: any) {\n auditLogRequestError(auditLogger, operationId, req, err);\n next(err);\n }\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n router.use(middleware.error());\n\n return router;\n}\n\nfunction stringToNumber(s: number | undefined): number | undefined {\n return s ? Number.parseInt(s.toString(), 10) : undefined;\n}\n\nfunction stringToBoolean(s: boolean | undefined): boolean | undefined {\n if (!s) {\n return undefined;\n }\n return s.toString() === 'true';\n}\n"],"names":["auth","DefaultAuditLogger","githubApiService","GithubApiService","catalogHttpClient","CatalogHttpClient","catalogInfoGenerator","CatalogInfoGenerator","OpenAPIBackend","fullFormats","openApiDocument","ping","findAllOrganizations","findAllRepositories","findRepositoriesByOrganization","findAllImports","createImportJobs","findImportStatusByRepo","deleteImportByRepo","Router","express","createPermissionIntegrationRouter","bulkImportPermission","permissionCheck","auditLogRequestSuccess","auditLogRequestError","MiddlewareFactory"],"mappings":"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"}
|