@red-hat-developer-hub/backstage-plugin-bulk-import-backend 6.10.1 → 6.11.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 +11 -0
- package/README.md +115 -1
- package/config.d.ts +6 -1
- package/dist/database/repositoryDao.cjs.js +40 -9
- package/dist/database/repositoryDao.cjs.js.map +1 -1
- package/dist/generated/openapidocument.cjs.js +247 -1
- package/dist/generated/openapidocument.cjs.js.map +1 -1
- package/dist/github/githubApiService.cjs.js +14 -0
- package/dist/github/githubApiService.cjs.js.map +1 -1
- package/dist/gitlab/gitlabApiService.cjs.js +14 -0
- package/dist/gitlab/gitlabApiService.cjs.js.map +1 -1
- package/dist/service/handlers/import/bulkImports.cjs.js +139 -63
- package/dist/service/handlers/import/bulkImports.cjs.js.map +1 -1
- package/dist/service/handlers/import/execute-orchestrator-workflow.cjs.js +104 -0
- package/dist/service/handlers/import/execute-orchestrator-workflow.cjs.js.map +1 -0
- package/dist/service/handlers/import/execute-template.cjs.js +3 -7
- package/dist/service/handlers/import/execute-template.cjs.js.map +1 -1
- package/dist/service/handlers/repository/repositories.cjs.js +1 -0
- package/dist/service/handlers/repository/repositories.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +129 -10
- package/dist/service/router.cjs.js.map +1 -1
- package/migrations/20251107150603_migrations.js +58 -0
- package/package.json +4 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute-orchestrator-workflow.cjs.js","sources":["../../../../src/service/handlers/import/execute-orchestrator-workflow.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 */\nimport { DiscoveryApi } from '@backstage/plugin-permission-common';\n\nimport {\n AuthToken,\n Configuration,\n DefaultApi,\n ExecuteWorkflowRequestDTO,\n} from '@red-hat-developer-hub/backstage-plugin-orchestrator-common';\n\nimport {\n OrchestratorWorkflowDao,\n RepositoryDao,\n} from '../../../database/repositoryDao';\nimport { Components, ImportRequest } from '../../../generated/openapi';\nimport { GithubApiService } from '../../../github';\nimport { GitlabApiService } from '../../../gitlab';\nimport { HandlerResponse } from '../handlers';\nimport { sortImports } from './bulkImports';\n\nexport type CreateWorkflowImportJobsArgs = {\n orchestratorWorkflowId: string;\n discovery: DiscoveryApi;\n token?: string;\n requestBody: ImportRequest[];\n orchestratorWorkflowDao: OrchestratorWorkflowDao;\n orchestratorRepositoryDao: RepositoryDao<'orchestrator_repositories'>;\n githubApiService: GithubApiService;\n gitlabApiService: GitlabApiService;\n};\n\nexport async function createWorkflowImportJobs(\n args: CreateWorkflowImportJobsArgs,\n): Promise<HandlerResponse<Components.Schemas.Import[]>> {\n const {\n orchestratorWorkflowId,\n discovery,\n token,\n requestBody,\n orchestratorWorkflowDao,\n orchestratorRepositoryDao,\n githubApiService,\n gitlabApiService,\n } = args;\n\n if (requestBody.length === 0) {\n return {\n statusCode: 400,\n responseBody: [],\n };\n }\n\n const result: Components.Schemas.Import[] = [];\n const baseUrl = await discovery.getBaseUrl('orchestrator');\n const apiConfig = new Configuration();\n\n // Initialize the client\n const orchestratorApi = new DefaultApi(apiConfig, baseUrl);\n\n for (const repo of requestBody) {\n if (!repo.repository.url) {\n continue;\n }\n\n let workflowStatus: Components.Schemas.WorkflowImportStatus | undefined;\n try {\n const approvalTool = repo.approvalTool ?? 'GIT';\n\n const authTokens: AuthToken[] = [];\n if (approvalTool === 'GIT') {\n const creds = await githubApiService.getCredentials(\n repo.repository.url,\n );\n authTokens.push({ token: creds?.token, provider: 'github' });\n }\n if (approvalTool === 'GITLAB') {\n const creds = await gitlabApiService.getCredentials(\n repo.repository.url,\n );\n authTokens.push({ token: creds?.token, provider: 'gitlab' });\n }\n\n const requestDTO: ExecuteWorkflowRequestDTO = {\n inputData: {\n owner: repo.repository.organization,\n repo: repo.repository.name,\n baseBranch: repo.repository.defaultBranch,\n targetBranch: `bulk-import-orchestrator`,\n approvalTool: approvalTool,\n },\n authTokens,\n };\n\n // Execute a workflow\n const wfResult = await orchestratorApi.executeWorkflow(\n orchestratorWorkflowId,\n requestDTO,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n },\n );\n\n const repositoryId = await orchestratorRepositoryDao.insertRepository(\n repo.repository.url,\n wfResult.data.id,\n approvalTool,\n );\n await orchestratorWorkflowDao.insertWorkflow(\n wfResult.data.id,\n repositoryId,\n );\n\n const response = await orchestratorApi.getInstanceById(wfResult.data.id, {\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n });\n workflowStatus =\n `WORKFLOW_${(response.data.state as string)?.toLocaleUpperCase()}` as Components.Schemas.WorkflowImportStatus;\n\n result.push({\n repository: repo.repository,\n workflow: { workflowId: wfResult.data.id },\n status: workflowStatus,\n });\n } catch (error: any) {\n result.push({\n repository: repo.repository,\n status: workflowStatus ?? 'WORKFLOW_ABORTED',\n errors: [(error as Error).message],\n });\n }\n }\n\n sortImports(result);\n\n return {\n statusCode: 202,\n responseBody: result,\n };\n}\n"],"names":["Configuration","DefaultApi","sortImports"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var eventsourceClient = require('eventsource-client');
|
|
4
4
|
var gitUrlParse = require('git-url-parse');
|
|
5
5
|
var catalogUtils = require('../../../catalog/catalogUtils.cjs.js');
|
|
6
|
+
var bulkImports = require('./bulkImports.cjs.js');
|
|
6
7
|
|
|
7
8
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
8
9
|
|
|
@@ -96,7 +97,7 @@ const handlePullRequestUpdate = async (importReq, logger, config, githubApiServi
|
|
|
96
97
|
} catch (err) {
|
|
97
98
|
logger.error(`Failed to update pull request ${prUrl}`, err);
|
|
98
99
|
result.status = "PR_ERROR";
|
|
99
|
-
result.errors = [err];
|
|
100
|
+
result.errors = [err.message];
|
|
100
101
|
return result;
|
|
101
102
|
}
|
|
102
103
|
result.status = "WAIT_PR_APPROVAL";
|
|
@@ -216,12 +217,7 @@ const createTaskImportJobs = async (templateRef, discovery, logger, auth, config
|
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
219
|
}
|
|
219
|
-
|
|
220
|
-
return {
|
|
221
|
-
statusCode: 202,
|
|
222
|
-
responseBody: { errors: result.flatMap((r) => r.errors || []) }
|
|
223
|
-
};
|
|
224
|
-
}
|
|
220
|
+
bulkImports.sortImports(result);
|
|
225
221
|
return {
|
|
226
222
|
statusCode: 202,
|
|
227
223
|
responseBody: result
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute-template.cjs.js","sources":["../../../../src/service/handlers/import/execute-template.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 {\n AuthService,\n DiscoveryService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\n\nimport { createEventSource } from 'eventsource-client';\nimport gitUrlParse from 'git-url-parse';\n\nimport { getCatalogFilename } from '../../../catalog/catalogUtils';\nimport {\n RepositoryDao,\n ScaffolderTaskDao,\n TaskLocationsDao,\n} from '../../../database/repositoryDao';\nimport { Components } from '../../../generated/openapi';\nimport { GithubApiService } from '../../../github';\nimport { HandlerResponse } from '../handlers';\n\ninterface ScaffolderEvent {\n id: number;\n isTaskRecoverable: boolean;\n taskId: string;\n body: {\n message: string;\n stepId?: string;\n status?: string;\n [key: string]: any;\n };\n type: 'log' | 'completion' | 'error';\n createdAt: string;\n error?: any;\n}\n\nasync function* getEvents(\n taskId: string,\n scaffolderUrl: string,\n token: string,\n logger: LoggerService,\n): AsyncGenerator<ScaffolderEvent> {\n const url = `${scaffolderUrl}/v2/tasks/${taskId}/eventstream`;\n\n const eventSource = createEventSource({\n url,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n try {\n for await (const event of eventSource) {\n try {\n const data: ScaffolderEvent = JSON.parse(event.data);\n yield data;\n if (data.type === 'completion' || data.type === 'error') {\n break;\n }\n } catch (err) {\n logger.error('Failed to parse SSE event', err);\n }\n }\n } catch (err) {\n logger.error('SSE error', err);\n } finally {\n eventSource.close();\n }\n}\n\nexport async function processTaskEvents(\n taskId: string,\n scaffolderUrl: string,\n token: string,\n logger: LoggerService,\n taskLocationsDao: TaskLocationsDao,\n) {\n try {\n for await (const event of getEvents(taskId, scaffolderUrl, token, logger)) {\n if (event.type === 'log') {\n const message = event.body.message;\n const match = message.match(/Registering (.*) in the catalog/);\n if (match?.[1]) {\n await taskLocationsDao.addTaskLocation(taskId, match[1]);\n }\n }\n }\n } catch (e) {\n logger.error(`Failed to process events for task ${taskId}`, e);\n }\n}\n\nconst handlePullRequestUpdate = async (\n importReq: Components.Schemas.ImportRequest,\n logger: LoggerService,\n config: Config,\n githubApiService: GithubApiService,\n): Promise<Components.Schemas.Import> => {\n const url = importReq.repository.url;\n const owner = importReq.repository.organization;\n const repoName = importReq.repository.name;\n const prUrl = importReq.github?.pullRequest?.url;\n const prNumber = importReq.github?.pullRequest?.number;\n const prTitle = importReq.github?.pullRequest?.title;\n const prBody = importReq.github?.pullRequest?.body;\n const catalogInfoContent = importReq.catalogInfoContent;\n\n const result: Components.Schemas.Import = {\n repository: {\n organization: owner,\n url: url,\n name: repoName,\n },\n github: {\n pullRequest: {\n url: prUrl,\n number: prNumber,\n title: prTitle,\n body: prBody,\n catalogInfoContent: catalogInfoContent,\n },\n },\n approvalTool: importReq.approvalTool,\n };\n\n try {\n if (prNumber && prTitle && prBody) {\n await githubApiService.updatePullRequest(url, prNumber, prTitle, prBody);\n\n const prInfo = await githubApiService.getPullRequest(url, prNumber);\n\n // Update catalog info content in the pull request\n const gitUrl = gitUrlParse(url);\n const fileName = getCatalogFilename(config);\n if (catalogInfoContent && prInfo.prBranch) {\n await githubApiService.createOrUpdateFileInBranch(\n gitUrl.owner,\n gitUrl.name,\n prInfo.prBranch,\n fileName,\n catalogInfoContent,\n );\n }\n } else {\n logger.warn(`prNumber is undefined, skipping updatePullRequest`);\n }\n } catch (err) {\n logger.error(`Failed to update pull request ${prUrl}`, err);\n result.status = 'PR_ERROR';\n result.errors = [err];\n return result;\n }\n\n result.status = 'WAIT_PR_APPROVAL';\n return result;\n};\n\nexport const createTaskImportJobs = async (\n templateRef: string,\n discovery: DiscoveryService,\n logger: LoggerService,\n auth: AuthService,\n config: Config,\n repositoryDao: RepositoryDao,\n taskDao: ScaffolderTaskDao,\n taskLocationsDao: TaskLocationsDao,\n importRequests: Components.Schemas.ImportRequest[],\n githubApiService: GithubApiService,\n): Promise<\n HandlerResponse<Components.Schemas.Import[] | { errors: string[] }>\n> => {\n if (importRequests.length === 0) {\n logger.debug('Missing import requests from request body');\n return {\n statusCode: 400,\n responseBody: [],\n };\n }\n\n const result: Components.Schemas.Import[] = [];\n\n const scaffolderUrl = await discovery.getBaseUrl('scaffolder');\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'scaffolder',\n });\n\n const executeTask = async (\n values: Record<string, any>,\n ): Promise<{ taskId: string; status: string; createdAt: string }> => {\n const response = await fetch(`${scaffolderUrl}/v2/tasks`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n templateRef: `${templateRef}`,\n values: {\n repoUrl: values.repoUrl,\n owner: values.owner,\n ...values,\n },\n secrets: {},\n }),\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to start scaffolder task: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n const taskResp = await fetch(`${scaffolderUrl}/v2/tasks/${data.id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n const task = await taskResp.json();\n return { taskId: data.id, status: task.status, createdAt: task.createdAt };\n };\n\n for (const importReq of importRequests) {\n const url = importReq.repository.url;\n const owner = importReq.repository.organization;\n const repoName = importReq.repository.name;\n if (importReq.github?.pullRequest?.url) {\n const updatedImport = await handlePullRequestUpdate(\n importReq,\n logger,\n config,\n githubApiService,\n );\n result.push(updatedImport);\n } else {\n try {\n // Create new task\n const gitProviderHost = new URL(importReq.repository.url).hostname;\n const normalizedUrl = `${gitProviderHost}?owner=${owner}&repo=${repoName}`;\n\n const scaffolderOptions = {\n name: repoName,\n organization: owner,\n repoUrl: normalizedUrl,\n branchName: `bulk-import-catalog-entity`,\n targetBranchName: importReq.repository.defaultBranch,\n gitProviderHost,\n };\n const { taskId, status, createdAt } =\n await executeTask(scaffolderOptions);\n\n const repositoryId = await repositoryDao.insertRepository(\n url,\n taskId,\n importReq.approvalTool ?? 'GIT',\n );\n await taskDao.insertTask({\n repositoryId,\n scaffolderOptions,\n taskId,\n executedAt: new Date(),\n });\n result.push({\n repository: {\n organization: owner,\n url,\n name: repoName,\n },\n status:\n `TASK_${status.toLocaleUpperCase()}` as Components.Schemas.TaskImportStatus,\n task: { taskId },\n lastUpdate: createdAt,\n approvalTool: importReq.approvalTool,\n });\n\n processTaskEvents(\n taskId,\n scaffolderUrl,\n token,\n logger,\n taskLocationsDao,\n );\n } catch (error: any) {\n logger.error(`Error processing import request for ${url}`, error);\n result.push({\n repository: {\n organization: owner,\n url,\n name: repoName,\n },\n status: 'TASK_FAILED',\n errors: [error.message],\n approvalTool: importReq.approvalTool,\n });\n }\n }\n }\n\n if (result.some(r => r.errors)) {\n return {\n statusCode: 202,\n responseBody: { errors: result.flatMap(r => r.errors || []) },\n };\n }\n\n return {\n statusCode: 202,\n responseBody: result,\n };\n};\n"],"names":["createEventSource","gitUrlParse","getCatalogFilename"],"mappings":";;;;;;;;;;AAmDA,gBAAgB,SACd,CAAA,MAAA,EACA,aACA,EAAA,KAAA,EACA,MACiC,EAAA;AACjC,EAAA,MAAM,GAAM,GAAA,CAAA,EAAG,aAAa,CAAA,UAAA,EAAa,MAAM,CAAA,YAAA,CAAA;AAE/C,EAAA,MAAM,cAAcA,mCAAkB,CAAA;AAAA,IACpC,GAAA;AAAA,IACA,OAAS,EAAA;AAAA,MACP,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA;AAChC,GACD,CAAA;AACD,EAAI,IAAA;AACF,IAAA,WAAA,MAAiB,SAAS,WAAa,EAAA;AACrC,MAAI,IAAA;AACF,QAAA,MAAM,IAAwB,GAAA,IAAA,CAAK,KAAM,CAAA,KAAA,CAAM,IAAI,CAAA;AACnD,QAAM,MAAA,IAAA;AACN,QAAA,IAAI,IAAK,CAAA,IAAA,KAAS,YAAgB,IAAA,IAAA,CAAK,SAAS,OAAS,EAAA;AACvD,UAAA;AAAA;AACF,eACO,GAAK,EAAA;AACZ,QAAO,MAAA,CAAA,KAAA,CAAM,6BAA6B,GAAG,CAAA;AAAA;AAC/C;AACF,WACO,GAAK,EAAA;AACZ,IAAO,MAAA,CAAA,KAAA,CAAM,aAAa,GAAG,CAAA;AAAA,GAC7B,SAAA;AACA,IAAA,WAAA,CAAY,KAAM,EAAA;AAAA;AAEtB;AAEA,eAAsB,iBACpB,CAAA,MAAA,EACA,aACA,EAAA,KAAA,EACA,QACA,gBACA,EAAA;AACA,EAAI,IAAA;AACF,IAAA,WAAA,MAAiB,SAAS,SAAU,CAAA,MAAA,EAAQ,aAAe,EAAA,KAAA,EAAO,MAAM,CAAG,EAAA;AACzE,MAAI,IAAA,KAAA,CAAM,SAAS,KAAO,EAAA;AACxB,QAAM,MAAA,OAAA,GAAU,MAAM,IAAK,CAAA,OAAA;AAC3B,QAAM,MAAA,KAAA,GAAQ,OAAQ,CAAA,KAAA,CAAM,iCAAiC,CAAA;AAC7D,QAAI,IAAA,KAAA,GAAQ,CAAC,CAAG,EAAA;AACd,UAAA,MAAM,gBAAiB,CAAA,eAAA,CAAgB,MAAQ,EAAA,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA;AACzD;AACF;AACF,WACO,CAAG,EAAA;AACV,IAAA,MAAA,CAAO,KAAM,CAAA,CAAA,kCAAA,EAAqC,MAAM,CAAA,CAAA,EAAI,CAAC,CAAA;AAAA;AAEjE;AAEA,MAAM,uBAA0B,GAAA,OAC9B,SACA,EAAA,MAAA,EACA,QACA,gBACuC,KAAA;AACvC,EAAM,MAAA,GAAA,GAAM,UAAU,UAAW,CAAA,GAAA;AACjC,EAAM,MAAA,KAAA,GAAQ,UAAU,UAAW,CAAA,YAAA;AACnC,EAAM,MAAA,QAAA,GAAW,UAAU,UAAW,CAAA,IAAA;AACtC,EAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,MAAA,EAAQ,WAAa,EAAA,GAAA;AAC7C,EAAM,MAAA,QAAA,GAAW,SAAU,CAAA,MAAA,EAAQ,WAAa,EAAA,MAAA;AAChD,EAAM,MAAA,OAAA,GAAU,SAAU,CAAA,MAAA,EAAQ,WAAa,EAAA,KAAA;AAC/C,EAAM,MAAA,MAAA,GAAS,SAAU,CAAA,MAAA,EAAQ,WAAa,EAAA,IAAA;AAC9C,EAAA,MAAM,qBAAqB,SAAU,CAAA,kBAAA;AAErC,EAAA,MAAM,MAAoC,GAAA;AAAA,IACxC,UAAY,EAAA;AAAA,MACV,YAAc,EAAA,KAAA;AAAA,MACd,GAAA;AAAA,MACA,IAAM,EAAA;AAAA,KACR;AAAA,IACA,MAAQ,EAAA;AAAA,MACN,WAAa,EAAA;AAAA,QACX,GAAK,EAAA,KAAA;AAAA,QACL,MAAQ,EAAA,QAAA;AAAA,QACR,KAAO,EAAA,OAAA;AAAA,QACP,IAAM,EAAA,MAAA;AAAA,QACN;AAAA;AACF,KACF;AAAA,IACA,cAAc,SAAU,CAAA;AAAA,GAC1B;AAEA,EAAI,IAAA;AACF,IAAI,IAAA,QAAA,IAAY,WAAW,MAAQ,EAAA;AACjC,MAAA,MAAM,gBAAiB,CAAA,iBAAA,CAAkB,GAAK,EAAA,QAAA,EAAU,SAAS,MAAM,CAAA;AAEvE,MAAA,MAAM,MAAS,GAAA,MAAM,gBAAiB,CAAA,cAAA,CAAe,KAAK,QAAQ,CAAA;AAGlE,MAAM,MAAA,MAAA,GAASC,6BAAY,GAAG,CAAA;AAC9B,MAAM,MAAA,QAAA,GAAWC,gCAAmB,MAAM,CAAA;AAC1C,MAAI,IAAA,kBAAA,IAAsB,OAAO,QAAU,EAAA;AACzC,QAAA,MAAM,gBAAiB,CAAA,0BAAA;AAAA,UACrB,MAAO,CAAA,KAAA;AAAA,UACP,MAAO,CAAA,IAAA;AAAA,UACP,MAAO,CAAA,QAAA;AAAA,UACP,QAAA;AAAA,UACA;AAAA,SACF;AAAA;AACF,KACK,MAAA;AACL,MAAA,MAAA,CAAO,KAAK,CAAmD,iDAAA,CAAA,CAAA;AAAA;AACjE,WACO,GAAK,EAAA;AACZ,IAAA,MAAA,CAAO,KAAM,CAAA,CAAA,8BAAA,EAAiC,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA;AAC1D,IAAA,MAAA,CAAO,MAAS,GAAA,UAAA;AAChB,IAAO,MAAA,CAAA,MAAA,GAAS,CAAC,GAAG,CAAA;AACpB,IAAO,OAAA,MAAA;AAAA;AAGT,EAAA,MAAA,CAAO,MAAS,GAAA,kBAAA;AAChB,EAAO,OAAA,MAAA;AACT,CAAA;AAEa,MAAA,oBAAA,GAAuB,OAClC,WAAA,EACA,SACA,EAAA,MAAA,EACA,IACA,EAAA,MAAA,EACA,aACA,EAAA,OAAA,EACA,gBACA,EAAA,cAAA,EACA,gBAGG,KAAA;AACH,EAAI,IAAA,cAAA,CAAe,WAAW,CAAG,EAAA;AAC/B,IAAA,MAAA,CAAO,MAAM,2CAA2C,CAAA;AACxD,IAAO,OAAA;AAAA,MACL,UAAY,EAAA,GAAA;AAAA,MACZ,cAAc;AAAC,KACjB;AAAA;AAGF,EAAA,MAAM,SAAsC,EAAC;AAE7C,EAAA,MAAM,aAAgB,GAAA,MAAM,SAAU,CAAA,UAAA,CAAW,YAAY,CAAA;AAC7D,EAAA,MAAM,EAAE,KAAA,EAAU,GAAA,MAAM,KAAK,qBAAsB,CAAA;AAAA,IACjD,UAAA,EAAY,MAAM,IAAA,CAAK,wBAAyB,EAAA;AAAA,IAChD,cAAgB,EAAA;AAAA,GACjB,CAAA;AAED,EAAM,MAAA,WAAA,GAAc,OAClB,MACmE,KAAA;AACnE,IAAA,MAAM,QAAW,GAAA,MAAM,KAAM,CAAA,CAAA,EAAG,aAAa,CAAa,SAAA,CAAA,EAAA;AAAA,MACxD,MAAQ,EAAA,MAAA;AAAA,MACR,OAAS,EAAA;AAAA,QACP,cAAgB,EAAA,kBAAA;AAAA,QAChB,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA,OAChC;AAAA,MACA,IAAA,EAAM,KAAK,SAAU,CAAA;AAAA,QACnB,WAAA,EAAa,GAAG,WAAW,CAAA,CAAA;AAAA,QAC3B,MAAQ,EAAA;AAAA,UACN,SAAS,MAAO,CAAA,OAAA;AAAA,UAChB,OAAO,MAAO,CAAA,KAAA;AAAA,UACd,GAAG;AAAA,SACL;AAAA,QACA,SAAS;AAAC,OACX;AAAA,KACF,CAAA;AAED,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAoC,iCAAA,EAAA,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA;AAAA,OAC5E;AAAA;AAGF,IAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AACjC,IAAM,MAAA,QAAA,GAAW,MAAM,KAAM,CAAA,CAAA,EAAG,aAAa,CAAa,UAAA,EAAA,IAAA,CAAK,EAAE,CAAI,CAAA,EAAA;AAAA,MACnE,OAAS,EAAA;AAAA,QACP,aAAA,EAAe,UAAU,KAAK,CAAA;AAAA;AAChC,KACD,CAAA;AAED,IAAM,MAAA,IAAA,GAAO,MAAM,QAAA,CAAS,IAAK,EAAA;AACjC,IAAO,OAAA,EAAE,QAAQ,IAAK,CAAA,EAAA,EAAI,QAAQ,IAAK,CAAA,MAAA,EAAQ,SAAW,EAAA,IAAA,CAAK,SAAU,EAAA;AAAA,GAC3E;AAEA,EAAA,KAAA,MAAW,aAAa,cAAgB,EAAA;AACtC,IAAM,MAAA,GAAA,GAAM,UAAU,UAAW,CAAA,GAAA;AACjC,IAAM,MAAA,KAAA,GAAQ,UAAU,UAAW,CAAA,YAAA;AACnC,IAAM,MAAA,QAAA,GAAW,UAAU,UAAW,CAAA,IAAA;AACtC,IAAI,IAAA,SAAA,CAAU,MAAQ,EAAA,WAAA,EAAa,GAAK,EAAA;AACtC,MAAA,MAAM,gBAAgB,MAAM,uBAAA;AAAA,QAC1B,SAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,MAAA,CAAO,KAAK,aAAa,CAAA;AAAA,KACpB,MAAA;AACL,MAAI,IAAA;AAEF,QAAA,MAAM,kBAAkB,IAAI,GAAA,CAAI,SAAU,CAAA,UAAA,CAAW,GAAG,CAAE,CAAA,QAAA;AAC1D,QAAA,MAAM,gBAAgB,CAAG,EAAA,eAAe,CAAU,OAAA,EAAA,KAAK,SAAS,QAAQ,CAAA,CAAA;AAExE,QAAA,MAAM,iBAAoB,GAAA;AAAA,UACxB,IAAM,EAAA,QAAA;AAAA,UACN,YAAc,EAAA,KAAA;AAAA,UACd,OAAS,EAAA,aAAA;AAAA,UACT,UAAY,EAAA,CAAA,0BAAA,CAAA;AAAA,UACZ,gBAAA,EAAkB,UAAU,UAAW,CAAA,aAAA;AAAA,UACvC;AAAA,SACF;AACA,QAAA,MAAM,EAAE,MAAQ,EAAA,MAAA,EAAQ,WACtB,GAAA,MAAM,YAAY,iBAAiB,CAAA;AAErC,QAAM,MAAA,YAAA,GAAe,MAAM,aAAc,CAAA,gBAAA;AAAA,UACvC,GAAA;AAAA,UACA,MAAA;AAAA,UACA,UAAU,YAAgB,IAAA;AAAA,SAC5B;AACA,QAAA,MAAM,QAAQ,UAAW,CAAA;AAAA,UACvB,YAAA;AAAA,UACA,iBAAA;AAAA,UACA,MAAA;AAAA,UACA,UAAA,sBAAgB,IAAK;AAAA,SACtB,CAAA;AACD,QAAA,MAAA,CAAO,IAAK,CAAA;AAAA,UACV,UAAY,EAAA;AAAA,YACV,YAAc,EAAA,KAAA;AAAA,YACd,GAAA;AAAA,YACA,IAAM,EAAA;AAAA,WACR;AAAA,UACA,MACE,EAAA,CAAA,KAAA,EAAQ,MAAO,CAAA,iBAAA,EAAmB,CAAA,CAAA;AAAA,UACpC,IAAA,EAAM,EAAE,MAAO,EAAA;AAAA,UACf,UAAY,EAAA,SAAA;AAAA,UACZ,cAAc,SAAU,CAAA;AAAA,SACzB,CAAA;AAED,QAAA,iBAAA;AAAA,UACE,MAAA;AAAA,UACA,aAAA;AAAA,UACA,KAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACF;AAAA,eACO,KAAY,EAAA;AACnB,QAAA,MAAA,CAAO,KAAM,CAAA,CAAA,oCAAA,EAAuC,GAAG,CAAA,CAAA,EAAI,KAAK,CAAA;AAChE,QAAA,MAAA,CAAO,IAAK,CAAA;AAAA,UACV,UAAY,EAAA;AAAA,YACV,YAAc,EAAA,KAAA;AAAA,YACd,GAAA;AAAA,YACA,IAAM,EAAA;AAAA,WACR;AAAA,UACA,MAAQ,EAAA,aAAA;AAAA,UACR,MAAA,EAAQ,CAAC,KAAA,CAAM,OAAO,CAAA;AAAA,UACtB,cAAc,SAAU,CAAA;AAAA,SACzB,CAAA;AAAA;AACH;AACF;AAGF,EAAA,IAAI,MAAO,CAAA,IAAA,CAAK,CAAK,CAAA,KAAA,CAAA,CAAE,MAAM,CAAG,EAAA;AAC9B,IAAO,OAAA;AAAA,MACL,UAAY,EAAA,GAAA;AAAA,MACZ,YAAA,EAAc,EAAE,MAAA,EAAQ,MAAO,CAAA,OAAA,CAAQ,OAAK,CAAE,CAAA,MAAA,IAAU,EAAE,CAAE;AAAA,KAC9D;AAAA;AAGF,EAAO,OAAA;AAAA,IACL,UAAY,EAAA,GAAA;AAAA,IACZ,YAAc,EAAA;AAAA,GAChB;AACF;;;;;"}
|
|
1
|
+
{"version":3,"file":"execute-template.cjs.js","sources":["../../../../src/service/handlers/import/execute-template.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 {\n AuthService,\n DiscoveryService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\n\nimport { createEventSource } from 'eventsource-client';\nimport gitUrlParse from 'git-url-parse';\n\nimport { getCatalogFilename } from '../../../catalog/catalogUtils';\nimport {\n RepositoryDao,\n ScaffolderTaskDao,\n TaskLocationsDao,\n} from '../../../database/repositoryDao';\nimport { Components } from '../../../generated/openapi';\nimport { GithubApiService } from '../../../github';\nimport { HandlerResponse } from '../handlers';\nimport { sortImports } from './bulkImports';\n\ninterface ScaffolderEvent {\n id: number;\n isTaskRecoverable: boolean;\n taskId: string;\n body: {\n message: string;\n stepId?: string;\n status?: string;\n [key: string]: any;\n };\n type: 'log' | 'completion' | 'error';\n createdAt: string;\n error?: any;\n}\n\nasync function* getEvents(\n taskId: string,\n scaffolderUrl: string,\n token: string,\n logger: LoggerService,\n): AsyncGenerator<ScaffolderEvent> {\n const url = `${scaffolderUrl}/v2/tasks/${taskId}/eventstream`;\n\n const eventSource = createEventSource({\n url,\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n try {\n for await (const event of eventSource) {\n try {\n const data: ScaffolderEvent = JSON.parse(event.data);\n yield data;\n if (data.type === 'completion' || data.type === 'error') {\n break;\n }\n } catch (err) {\n logger.error('Failed to parse SSE event', err);\n }\n }\n } catch (err) {\n logger.error('SSE error', err);\n } finally {\n eventSource.close();\n }\n}\n\nexport async function processTaskEvents(\n taskId: string,\n scaffolderUrl: string,\n token: string,\n logger: LoggerService,\n taskLocationsDao: TaskLocationsDao,\n) {\n try {\n for await (const event of getEvents(taskId, scaffolderUrl, token, logger)) {\n if (event.type === 'log') {\n const message = event.body.message;\n const match = message.match(/Registering (.*) in the catalog/);\n if (match?.[1]) {\n await taskLocationsDao.addTaskLocation(taskId, match[1]);\n }\n }\n }\n } catch (e) {\n logger.error(`Failed to process events for task ${taskId}`, e);\n }\n}\n\nconst handlePullRequestUpdate = async (\n importReq: Components.Schemas.ImportRequest,\n logger: LoggerService,\n config: Config,\n githubApiService: GithubApiService,\n): Promise<Components.Schemas.Import> => {\n const url = importReq.repository.url;\n const owner = importReq.repository.organization;\n const repoName = importReq.repository.name;\n const prUrl = importReq.github?.pullRequest?.url;\n const prNumber = importReq.github?.pullRequest?.number;\n const prTitle = importReq.github?.pullRequest?.title;\n const prBody = importReq.github?.pullRequest?.body;\n const catalogInfoContent = importReq.catalogInfoContent;\n\n const result: Components.Schemas.Import = {\n repository: {\n organization: owner,\n url: url,\n name: repoName,\n },\n github: {\n pullRequest: {\n url: prUrl,\n number: prNumber,\n title: prTitle,\n body: prBody,\n catalogInfoContent: catalogInfoContent,\n },\n },\n approvalTool: importReq.approvalTool,\n };\n\n try {\n if (prNumber && prTitle && prBody) {\n await githubApiService.updatePullRequest(url, prNumber, prTitle, prBody);\n\n const prInfo = await githubApiService.getPullRequest(url, prNumber);\n\n // Update catalog info content in the pull request\n const gitUrl = gitUrlParse(url);\n const fileName = getCatalogFilename(config);\n if (catalogInfoContent && prInfo.prBranch) {\n await githubApiService.createOrUpdateFileInBranch(\n gitUrl.owner,\n gitUrl.name,\n prInfo.prBranch,\n fileName,\n catalogInfoContent,\n );\n }\n } else {\n logger.warn(`prNumber is undefined, skipping updatePullRequest`);\n }\n } catch (err) {\n logger.error(`Failed to update pull request ${prUrl}`, err);\n result.status = 'PR_ERROR';\n result.errors = [(err as Error).message];\n return result;\n }\n\n result.status = 'WAIT_PR_APPROVAL';\n return result;\n};\n\nexport const createTaskImportJobs = async (\n templateRef: string,\n discovery: DiscoveryService,\n logger: LoggerService,\n auth: AuthService,\n config: Config,\n repositoryDao: RepositoryDao<'repositories'>,\n taskDao: ScaffolderTaskDao,\n taskLocationsDao: TaskLocationsDao,\n importRequests: Components.Schemas.ImportRequest[],\n githubApiService: GithubApiService,\n): Promise<HandlerResponse<Components.Schemas.Import[]>> => {\n if (importRequests.length === 0) {\n logger.debug('Missing import requests from request body');\n return {\n statusCode: 400,\n responseBody: [],\n };\n }\n\n const result: Components.Schemas.Import[] = [];\n\n const scaffolderUrl = await discovery.getBaseUrl('scaffolder');\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'scaffolder',\n });\n\n const executeTask = async (\n values: Record<string, any>,\n ): Promise<{ taskId: string; status: string; createdAt: string }> => {\n const response = await fetch(`${scaffolderUrl}/v2/tasks`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n templateRef: `${templateRef}`,\n values: {\n repoUrl: values.repoUrl,\n owner: values.owner,\n ...values,\n },\n secrets: {},\n }),\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to start scaffolder task: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n const taskResp = await fetch(`${scaffolderUrl}/v2/tasks/${data.id}`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n const task = await taskResp.json();\n return { taskId: data.id, status: task.status, createdAt: task.createdAt };\n };\n\n for (const importReq of importRequests) {\n const url = importReq.repository.url;\n const owner = importReq.repository.organization;\n const repoName = importReq.repository.name;\n if (importReq.github?.pullRequest?.url) {\n const updatedImport = await handlePullRequestUpdate(\n importReq,\n logger,\n config,\n githubApiService,\n );\n result.push(updatedImport);\n } else {\n try {\n // Create new task\n const gitProviderHost = new URL(importReq.repository.url).hostname;\n const normalizedUrl = `${gitProviderHost}?owner=${owner}&repo=${repoName}`;\n\n const scaffolderOptions = {\n name: repoName,\n organization: owner,\n repoUrl: normalizedUrl,\n branchName: `bulk-import-catalog-entity`,\n targetBranchName: importReq.repository.defaultBranch,\n gitProviderHost,\n };\n const { taskId, status, createdAt } =\n await executeTask(scaffolderOptions);\n\n const repositoryId = await repositoryDao.insertRepository(\n url,\n taskId,\n importReq.approvalTool ?? 'GIT',\n );\n await taskDao.insertTask({\n repositoryId,\n scaffolderOptions,\n taskId,\n executedAt: new Date(),\n });\n result.push({\n repository: {\n organization: owner,\n url,\n name: repoName,\n },\n status:\n `TASK_${status.toLocaleUpperCase()}` as Components.Schemas.TaskImportStatus,\n task: { taskId },\n lastUpdate: createdAt,\n approvalTool: importReq.approvalTool,\n });\n\n processTaskEvents(\n taskId,\n scaffolderUrl,\n token,\n logger,\n taskLocationsDao,\n );\n } catch (error: any) {\n logger.error(`Error processing import request for ${url}`, error);\n result.push({\n repository: {\n organization: owner,\n url,\n name: repoName,\n },\n status: 'TASK_FAILED',\n errors: [error.message],\n approvalTool: importReq.approvalTool,\n });\n }\n }\n }\n\n sortImports(result);\n\n return {\n statusCode: 202,\n responseBody: result,\n };\n};\n"],"names":["createEventSource","gitUrlParse","getCatalogFilename","sortImports"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var gitUrlParse = require('git-url-parse');
|
|
4
4
|
var handlers = require('../handlers.cjs.js');
|
|
5
5
|
require('@backstage/errors');
|
|
6
|
+
require('@red-hat-developer-hub/backstage-plugin-orchestrator-common');
|
|
6
7
|
require('@backstage/plugin-permission-common');
|
|
7
8
|
require('@red-hat-developer-hub/backstage-plugin-bulk-import-common');
|
|
8
9
|
require('just-kebab-case');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repositories.cjs.js","sources":["../../../../src/service/handlers/repository/repositories.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { GitlabApiService, GitlabRepositoryResponse } from '../../../gitlab';\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 gitApiService: GithubApiService | GitlabApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n reqParams?: {\n approvalTool?: string;\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\n const repos = await deps.gitApiService\n .getRepositoriesFromIntegrations(search, pageNumber, pageSize)\n .then(response => formatResponse(deps, response, checkStatus));\n\n return repos;\n}\n\nexport async function findRepositoriesByOrganization(\n deps: {\n logger: LoggerService;\n config: Config;\n gitApiService: GithubApiService | GitlabApiService;\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\n const glReposByOrg = await deps.gitApiService\n .getOrgRepositoriesFromIntegrations(orgName, search, pageNumber, pageSize)\n .then(response => formatResponse(deps, response, checkStatus));\n\n return glReposByOrg;\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 gitApiService: GithubApiService | GitlabApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n allReposAccessible: GithubRepositoryResponse | GitlabRepositoryResponse,\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: Iterable<string> = [];\n if (checkStatus) {\n catalogLocations = (\n await deps.catalogHttpClient.listCatalogUrlLocations()\n ).uniqueCatalogUrlLocations.keys();\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":"
|
|
1
|
+
{"version":3,"file":"repositories.cjs.js","sources":["../../../../src/service/handlers/repository/repositories.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { GitlabApiService, GitlabRepositoryResponse } from '../../../gitlab';\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 gitApiService: GithubApiService | GitlabApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n reqParams?: {\n approvalTool?: string;\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\n const repos = await deps.gitApiService\n .getRepositoriesFromIntegrations(search, pageNumber, pageSize)\n .then(response => formatResponse(deps, response, checkStatus));\n\n return repos;\n}\n\nexport async function findRepositoriesByOrganization(\n deps: {\n logger: LoggerService;\n config: Config;\n gitApiService: GithubApiService | GitlabApiService;\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\n const glReposByOrg = await deps.gitApiService\n .getOrgRepositoriesFromIntegrations(orgName, search, pageNumber, pageSize)\n .then(response => formatResponse(deps, response, checkStatus));\n\n return glReposByOrg;\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 gitApiService: GithubApiService | GitlabApiService;\n catalogHttpClient: CatalogHttpClient;\n },\n allReposAccessible: GithubRepositoryResponse | GitlabRepositoryResponse,\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: Iterable<string> = [];\n if (checkStatus) {\n catalogLocations = (\n await deps.catalogHttpClient.listCatalogUrlLocations()\n ).uniqueCatalogUrlLocations.keys();\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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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
4
|
+
var errors = require('@backstage/errors');
|
|
4
5
|
var pluginPermissionNode = require('@backstage/plugin-permission-node');
|
|
5
6
|
var formats = require('ajv-formats/dist/formats');
|
|
6
7
|
var express = require('express');
|
|
@@ -18,10 +19,10 @@ require('luxon');
|
|
|
18
19
|
var githubApiService = require('../github/githubApiService.cjs.js');
|
|
19
20
|
var gitlabApiService = require('../gitlab/gitlabApiService.cjs.js');
|
|
20
21
|
var auth = require('../helpers/auth.cjs.js');
|
|
21
|
-
require('@backstage/errors');
|
|
22
22
|
var utils = require('../helpers/utils.cjs.js');
|
|
23
23
|
var auditorUtils = require('../helpers/auditorUtils.cjs.js');
|
|
24
24
|
var bulkImports = require('./handlers/import/bulkImports.cjs.js');
|
|
25
|
+
var executeOrchestratorWorkflow = require('./handlers/import/execute-orchestrator-workflow.cjs.js');
|
|
25
26
|
var executeTemplate = require('./handlers/import/execute-template.cjs.js');
|
|
26
27
|
var organizations = require('./handlers/organization/organizations.cjs.js');
|
|
27
28
|
var ping = require('./handlers/ping/ping.cjs.js');
|
|
@@ -39,12 +40,16 @@ var Operations;
|
|
|
39
40
|
Operations2.FIND_REPOSITORIES_BY_ORGANIZATION = "findRepositoriesByOrganization";
|
|
40
41
|
Operations2.FIND_ALL_IMPORTS = "findAllImports";
|
|
41
42
|
Operations2.FIND_ALL_TASK_IMPORTS = "findAllTaskImports";
|
|
43
|
+
Operations2.FIND_ALL_ORCHESTRATOR_WORKFLOW_IMPORTS = "findAllOrchestratorWorkflowImports";
|
|
42
44
|
Operations2.CREATE_IMPORT_JOBS = "createImportJobs";
|
|
43
45
|
Operations2.CREATE_TASK_IMPORT_JOBS = "createTaskImportJobs";
|
|
46
|
+
Operations2.CREATE_ORCHESTRATOR_WORKFLOW_JOBS = "createOrchestratorWorkflowJobs";
|
|
44
47
|
Operations2.FIND_IMPORT_STATUS_BY_REPO = "findImportStatusByRepo";
|
|
45
48
|
Operations2.FIND_TASK_IMPORT_STATUS_BY_REPO = "findTaskImportStatusByRepo";
|
|
49
|
+
Operations2.FIND_ORCHESTRATOR_IMPORT_STATUS_BY_REPO = "findOrchestratorImportStatusByRepo";
|
|
46
50
|
Operations2.DELETE_IMPORT_BY_REPO = "deleteImportByRepo";
|
|
47
51
|
Operations2.DELETE_TASK_IMPORT_BY_REPO = "deleteTaskImportByRepo";
|
|
52
|
+
Operations2.DELETE_ORCHESTRATOR_IMPORT_BY_REPO = "deleteOrchestratorImportByRepo";
|
|
48
53
|
})(Operations || (Operations = {}));
|
|
49
54
|
async function createRouter(options) {
|
|
50
55
|
const {
|
|
@@ -60,9 +65,15 @@ async function createRouter(options) {
|
|
|
60
65
|
database
|
|
61
66
|
} = options;
|
|
62
67
|
const knex = await migration.migrate(database);
|
|
63
|
-
const repositoryDao$1 = new repositoryDao.RepositoryDao(knex, logger);
|
|
68
|
+
const repositoryDao$1 = new repositoryDao.RepositoryDao(knex, logger, "repositories");
|
|
64
69
|
const taskDao = new repositoryDao.ScaffolderTaskDao(knex);
|
|
65
70
|
const taskLocationsDao = new repositoryDao.TaskLocationsDao(knex);
|
|
71
|
+
const orchestratorRepositoryDao = new repositoryDao.RepositoryDao(
|
|
72
|
+
knex,
|
|
73
|
+
logger,
|
|
74
|
+
"orchestrator_repositories"
|
|
75
|
+
);
|
|
76
|
+
const orchestratorWorkflowDao = new repositoryDao.OrchestratorWorkflowDao(knex);
|
|
66
77
|
const githubApiService$1 = new githubApiService.GithubApiService(logger, config, cache);
|
|
67
78
|
const gitlabApiService$1 = new gitlabApiService.GitlabApiService(logger, config, cache);
|
|
68
79
|
const catalogHttpClient$1 = new catalogHttpClient.CatalogHttpClient({
|
|
@@ -95,6 +106,9 @@ async function createRouter(options) {
|
|
|
95
106
|
if (templateRef) {
|
|
96
107
|
finalTemplateRef = utils.getImportTemplateRef(templateRef);
|
|
97
108
|
}
|
|
109
|
+
const orchestratorWorkflowId = config.getOptionalString(
|
|
110
|
+
"bulkImport.orchestratorWorkflow"
|
|
111
|
+
);
|
|
98
112
|
await api.init();
|
|
99
113
|
api.register(
|
|
100
114
|
Operations.PING,
|
|
@@ -270,6 +284,43 @@ async function createRouter(options) {
|
|
|
270
284
|
return res.status(200).json(responseBody);
|
|
271
285
|
}
|
|
272
286
|
);
|
|
287
|
+
api.register(
|
|
288
|
+
Operations.FIND_ALL_ORCHESTRATOR_WORKFLOW_IMPORTS,
|
|
289
|
+
async (c, req, res) => {
|
|
290
|
+
const { pageNumber, pageSize, search, sortColumn, sortOrder } = getFindImportsParams(c);
|
|
291
|
+
const imports = [];
|
|
292
|
+
const repositories = await orchestratorRepositoryDao.findRepositories(
|
|
293
|
+
pageNumber,
|
|
294
|
+
pageSize,
|
|
295
|
+
search
|
|
296
|
+
);
|
|
297
|
+
const token = getBearerTokenFromReq(req);
|
|
298
|
+
for (const repo of repositories.data) {
|
|
299
|
+
const response = await bulkImports.findOrchestratorImportStatusByRepo(
|
|
300
|
+
{
|
|
301
|
+
logger,
|
|
302
|
+
orchestratorRepositoryDao,
|
|
303
|
+
orchestratorWorkflowDao,
|
|
304
|
+
discovery
|
|
305
|
+
},
|
|
306
|
+
repo.url,
|
|
307
|
+
token,
|
|
308
|
+
true
|
|
309
|
+
);
|
|
310
|
+
if (response.responseBody) {
|
|
311
|
+
imports.push(response.responseBody);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
bulkImports.sortImports(imports, sortColumn, sortOrder);
|
|
315
|
+
const responseBody = {
|
|
316
|
+
imports,
|
|
317
|
+
totalCount: repositories.total,
|
|
318
|
+
page: pageNumber || 1,
|
|
319
|
+
size: pageSize || 5
|
|
320
|
+
};
|
|
321
|
+
return res.status(200).json(responseBody);
|
|
322
|
+
}
|
|
323
|
+
);
|
|
273
324
|
api.register(
|
|
274
325
|
Operations.CREATE_IMPORT_JOBS,
|
|
275
326
|
async (c, _req, res) => {
|
|
@@ -319,6 +370,28 @@ async function createRouter(options) {
|
|
|
319
370
|
return res.status(response.statusCode).json(response.responseBody);
|
|
320
371
|
}
|
|
321
372
|
);
|
|
373
|
+
api.register(
|
|
374
|
+
Operations.CREATE_ORCHESTRATOR_WORKFLOW_JOBS,
|
|
375
|
+
async (c, req, res) => {
|
|
376
|
+
if (!orchestratorWorkflowId) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`Missing required config value: 'bulkImport.orchestratorWorkflow'`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
const token = getBearerTokenFromReq(req);
|
|
382
|
+
const response = await executeOrchestratorWorkflow.createWorkflowImportJobs({
|
|
383
|
+
orchestratorWorkflowId,
|
|
384
|
+
discovery,
|
|
385
|
+
token,
|
|
386
|
+
requestBody: c.request.requestBody,
|
|
387
|
+
orchestratorWorkflowDao,
|
|
388
|
+
orchestratorRepositoryDao,
|
|
389
|
+
githubApiService: githubApiService$1,
|
|
390
|
+
gitlabApiService: gitlabApiService$1
|
|
391
|
+
});
|
|
392
|
+
res.status(response.statusCode).json(response.responseBody);
|
|
393
|
+
}
|
|
394
|
+
);
|
|
322
395
|
api.register(
|
|
323
396
|
Operations.FIND_TASK_IMPORT_STATUS_BY_REPO,
|
|
324
397
|
async (c, _req, res) => {
|
|
@@ -370,6 +443,29 @@ async function createRouter(options) {
|
|
|
370
443
|
return res.status(response.statusCode).json(response.responseBody);
|
|
371
444
|
}
|
|
372
445
|
);
|
|
446
|
+
api.register(
|
|
447
|
+
Operations.FIND_ORCHESTRATOR_IMPORT_STATUS_BY_REPO,
|
|
448
|
+
async (c, req, res) => {
|
|
449
|
+
const q = {
|
|
450
|
+
...c.request.query
|
|
451
|
+
};
|
|
452
|
+
if (!q.repo?.trim()) {
|
|
453
|
+
throw new Error("missing or blank parameter");
|
|
454
|
+
}
|
|
455
|
+
const token = getBearerTokenFromReq(req);
|
|
456
|
+
const response = await bulkImports.findOrchestratorImportStatusByRepo(
|
|
457
|
+
{
|
|
458
|
+
logger,
|
|
459
|
+
orchestratorRepositoryDao,
|
|
460
|
+
orchestratorWorkflowDao,
|
|
461
|
+
discovery
|
|
462
|
+
},
|
|
463
|
+
q.repo,
|
|
464
|
+
token
|
|
465
|
+
);
|
|
466
|
+
return res.status(response.statusCode).json(response.responseBody);
|
|
467
|
+
}
|
|
468
|
+
);
|
|
373
469
|
api.register(
|
|
374
470
|
Operations.DELETE_TASK_IMPORT_BY_REPO,
|
|
375
471
|
async (c, _req, res) => {
|
|
@@ -379,7 +475,7 @@ async function createRouter(options) {
|
|
|
379
475
|
if (!q.repo?.trim()) {
|
|
380
476
|
throw new Error('missing or blank "repo" parameter');
|
|
381
477
|
}
|
|
382
|
-
const response = await bulkImports.
|
|
478
|
+
const response = await bulkImports.deleteRepositoryRecord(
|
|
383
479
|
{
|
|
384
480
|
logger,
|
|
385
481
|
dao: repositoryDao$1
|
|
@@ -411,6 +507,25 @@ async function createRouter(options) {
|
|
|
411
507
|
return res.status(response.statusCode).json(response.responseBody);
|
|
412
508
|
}
|
|
413
509
|
);
|
|
510
|
+
api.register(
|
|
511
|
+
Operations.DELETE_ORCHESTRATOR_IMPORT_BY_REPO,
|
|
512
|
+
async (c, _req, res) => {
|
|
513
|
+
const q = {
|
|
514
|
+
...c.request.query
|
|
515
|
+
};
|
|
516
|
+
if (!q.repo?.trim()) {
|
|
517
|
+
throw new Error('missing or blank "repo" parameter');
|
|
518
|
+
}
|
|
519
|
+
const response = await bulkImports.deleteRepositoryRecord(
|
|
520
|
+
{
|
|
521
|
+
logger,
|
|
522
|
+
dao: orchestratorRepositoryDao
|
|
523
|
+
},
|
|
524
|
+
q.repo
|
|
525
|
+
);
|
|
526
|
+
return res.status(response.statusCode).json(response.responseBody);
|
|
527
|
+
}
|
|
528
|
+
);
|
|
414
529
|
const router = express.Router();
|
|
415
530
|
router.use(express__default.default.json());
|
|
416
531
|
const permissionIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
|
|
@@ -478,6 +593,7 @@ async function createAuditorEventByOperationId(operationId, req, auditor) {
|
|
|
478
593
|
}
|
|
479
594
|
case Operations.FIND_ALL_IMPORTS:
|
|
480
595
|
case Operations.FIND_ALL_TASK_IMPORTS:
|
|
596
|
+
case Operations.FIND_ALL_ORCHESTRATOR_WORKFLOW_IMPORTS:
|
|
481
597
|
auditorEvent = await auditorUtils.auditCreateEvent(auditor, "import-read", req, {
|
|
482
598
|
queryType: req.query.search ? "by-query" : "all",
|
|
483
599
|
search: req.query.search
|
|
@@ -485,19 +601,14 @@ async function createAuditorEventByOperationId(operationId, req, auditor) {
|
|
|
485
601
|
break;
|
|
486
602
|
case Operations.CREATE_IMPORT_JOBS:
|
|
487
603
|
case Operations.CREATE_TASK_IMPORT_JOBS:
|
|
604
|
+
case Operations.CREATE_ORCHESTRATOR_WORKFLOW_JOBS:
|
|
488
605
|
auditorEvent = await auditorUtils.auditCreateEvent(auditor, "import-write", req, {
|
|
489
606
|
actionType: "create"
|
|
490
607
|
});
|
|
491
608
|
break;
|
|
492
609
|
case Operations.FIND_IMPORT_STATUS_BY_REPO:
|
|
493
|
-
auditorEvent = await auditorUtils.auditCreateEvent(
|
|
494
|
-
auditor,
|
|
495
|
-
"import-status-read",
|
|
496
|
-
req,
|
|
497
|
-
{ queryType: "by-query", repo: req.query.repo }
|
|
498
|
-
);
|
|
499
|
-
break;
|
|
500
610
|
case Operations.FIND_TASK_IMPORT_STATUS_BY_REPO:
|
|
611
|
+
case Operations.FIND_ORCHESTRATOR_IMPORT_STATUS_BY_REPO:
|
|
501
612
|
auditorEvent = await auditorUtils.auditCreateEvent(
|
|
502
613
|
auditor,
|
|
503
614
|
"import-status-read",
|
|
@@ -507,6 +618,7 @@ async function createAuditorEventByOperationId(operationId, req, auditor) {
|
|
|
507
618
|
break;
|
|
508
619
|
case Operations.DELETE_IMPORT_BY_REPO:
|
|
509
620
|
case Operations.DELETE_TASK_IMPORT_BY_REPO:
|
|
621
|
+
case Operations.DELETE_ORCHESTRATOR_IMPORT_BY_REPO:
|
|
510
622
|
auditorEvent = await auditorUtils.auditCreateEvent(auditor, "import-write", req, {
|
|
511
623
|
actionType: "delete",
|
|
512
624
|
repository: req.query.repo
|
|
@@ -553,6 +665,13 @@ function getFindImportsParams(c) {
|
|
|
553
665
|
sortOrder: q.sortOrder
|
|
554
666
|
};
|
|
555
667
|
}
|
|
668
|
+
function getBearerTokenFromReq(req) {
|
|
669
|
+
const header = req.header("authorization") ?? req.headers.authorization;
|
|
670
|
+
if (header?.startsWith(`Bearer `)) {
|
|
671
|
+
return header.replace("Bearer ", "");
|
|
672
|
+
}
|
|
673
|
+
throw new errors.InputError(`Request provided without token`);
|
|
674
|
+
}
|
|
556
675
|
|
|
557
676
|
exports.createRouter = createRouter;
|
|
558
677
|
//# sourceMappingURL=router.cjs.js.map
|