@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.
Files changed (56) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +161 -0
  3. package/app-config.yaml +0 -0
  4. package/config.d.ts +17 -0
  5. package/dist/catalog/catalogHttpClient.cjs.js +284 -0
  6. package/dist/catalog/catalogHttpClient.cjs.js.map +1 -0
  7. package/dist/catalog/catalogInfoGenerator.cjs.js +60 -0
  8. package/dist/catalog/catalogInfoGenerator.cjs.js.map +1 -0
  9. package/dist/catalog/catalogUtils.cjs.js +34 -0
  10. package/dist/catalog/catalogUtils.cjs.js.map +1 -0
  11. package/dist/generated/openapidocument.cjs.js +1168 -0
  12. package/dist/generated/openapidocument.cjs.js.map +1 -0
  13. package/dist/github/GithubAppManager.cjs.js +395 -0
  14. package/dist/github/GithubAppManager.cjs.js.map +1 -0
  15. package/dist/github/githubApiService.cjs.js +659 -0
  16. package/dist/github/githubApiService.cjs.js.map +1 -0
  17. package/dist/github/types.cjs.js +8 -0
  18. package/dist/github/types.cjs.js.map +1 -0
  19. package/dist/github/utils/ghUtils.cjs.js +103 -0
  20. package/dist/github/utils/ghUtils.cjs.js.map +1 -0
  21. package/dist/github/utils/orgUtils.cjs.js +151 -0
  22. package/dist/github/utils/orgUtils.cjs.js.map +1 -0
  23. package/dist/github/utils/prUtils.cjs.js +85 -0
  24. package/dist/github/utils/prUtils.cjs.js.map +1 -0
  25. package/dist/github/utils/repoUtils.cjs.js +307 -0
  26. package/dist/github/utils/repoUtils.cjs.js.map +1 -0
  27. package/dist/github/utils/utils.cjs.js +206 -0
  28. package/dist/github/utils/utils.cjs.js.map +1 -0
  29. package/dist/helpers/auditLogUtils.cjs.js +112 -0
  30. package/dist/helpers/auditLogUtils.cjs.js.map +1 -0
  31. package/dist/helpers/auth.cjs.js +36 -0
  32. package/dist/helpers/auth.cjs.js.map +1 -0
  33. package/dist/helpers/loggingUtils.cjs.js +19 -0
  34. package/dist/helpers/loggingUtils.cjs.js.map +1 -0
  35. package/dist/helpers/pagination.cjs.js +19 -0
  36. package/dist/helpers/pagination.cjs.js.map +1 -0
  37. package/dist/index.cjs.js +12 -0
  38. package/dist/index.cjs.js.map +1 -0
  39. package/dist/index.d.ts +25 -0
  40. package/dist/plugin.cjs.js +54 -0
  41. package/dist/plugin.cjs.js.map +1 -0
  42. package/dist/service/handlers/handlers.cjs.js +8 -0
  43. package/dist/service/handlers/handlers.cjs.js.map +1 -0
  44. package/dist/service/handlers/import/bulkImports.cjs.js +551 -0
  45. package/dist/service/handlers/import/bulkImports.cjs.js.map +1 -0
  46. package/dist/service/handlers/import/importStatus.cjs.js +49 -0
  47. package/dist/service/handlers/import/importStatus.cjs.js.map +1 -0
  48. package/dist/service/handlers/organization/organizations.cjs.js +77 -0
  49. package/dist/service/handlers/organization/organizations.cjs.js.map +1 -0
  50. package/dist/service/handlers/ping/ping.cjs.js +12 -0
  51. package/dist/service/handlers/ping/ping.cjs.js.map +1 -0
  52. package/dist/service/handlers/repository/repositories.cjs.js +99 -0
  53. package/dist/service/handlers/repository/repositories.cjs.js.map +1 -0
  54. package/dist/service/router.cjs.js +324 -0
  55. package/dist/service/router.cjs.js.map +1 -0
  56. package/package.json +110 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapidocument.cjs.js","sources":["../../src/generated/openapidocument.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\n// eslint-disable\n// prettier-ignore\nconst OPENAPI = `\n{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"version\": \"1.0\",\n \"title\": \"Bulk Import Backend\",\n \"description\": \"The Bulk Import Backend APIs allow users to bulk import repositories into the Backstage catalog from remote sources such as Git.\"\n },\n \"servers\": [\n {\n \"url\": \"{protocol}://{host}:{port}/{basePath}\",\n \"variables\": {\n \"protocol\": {\n \"enum\": [\n \"http\",\n \"https\"\n ],\n \"default\": \"http\"\n },\n \"host\": {\n \"default\": \"localhost\"\n },\n \"port\": {\n \"default\": \"7007\"\n },\n \"basePath\": {\n \"default\": \"api/bulk-import\"\n }\n }\n }\n ],\n \"paths\": {\n \"/ping\": {\n \"get\": {\n \"operationId\": \"ping\",\n \"summary\": \"Check the health of the Bulk Import backend router\",\n \"tags\": [\n \"Management\"\n ],\n \"responses\": {\n \"200\": {\n \"description\": \"The backend router for the Bulk Import backend is up and running\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"status\": {\n \"enum\": [\n \"ok\"\n ]\n }\n }\n },\n \"example\": {\n \"status\": \"ok\"\n }\n }\n }\n }\n }\n }\n },\n \"/organizations\": {\n \"get\": {\n \"operationId\": \"findAllOrganizations\",\n \"summary\": \"Fetch Organizations accessible by Backstage Github Integrations\",\n \"security\": [\n {\n \"BearerAuth\": []\n }\n ],\n \"tags\": [\n \"Organization\"\n ],\n \"parameters\": [\n {\n \"$ref\": \"#/components/parameters/pagePerIntegrationQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/sizePerIntegrationQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/searchQueryParam\"\n }\n ],\n \"responses\": {\n \"200\": {\n \"description\": \"Organization list was fetched successfully with no errors\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/OrganizationList\"\n },\n \"examples\": {\n \"multipleRepos\": {\n \"$ref\": \"#/components/examples/multipleOrgs\"\n }\n }\n }\n }\n },\n \"500\": {\n \"description\": \"Generic error when there are errors and no Organization is returned\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/OrganizationList\"\n },\n \"examples\": {\n \"repositoryListErrors\": {\n \"$ref\": \"#/components/examples/orgListErrors\"\n }\n }\n }\n }\n }\n }\n }\n },\n \"/organizations/{organizationName}/repositories\": {\n \"get\": {\n \"operationId\": \"findRepositoriesByOrganization\",\n \"summary\": \"Fetch Repositories in the specified GitHub organization, provided it is accessible by any of the configured GitHub Integrations.\",\n \"security\": [\n {\n \"BearerAuth\": []\n }\n ],\n \"tags\": [\n \"Organization\"\n ],\n \"parameters\": [\n {\n \"in\": \"path\",\n \"name\": \"organizationName\",\n \"description\": \"Organization name\",\n \"required\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"in\": \"query\",\n \"name\": \"checkImportStatus\",\n \"description\": \"whether to return import status. Note that this might incur a performance penalty because the import status is computed for each repository.\",\n \"schema\": {\n \"type\": \"boolean\",\n \"default\": \"false\"\n }\n },\n {\n \"$ref\": \"#/components/parameters/pagePerIntegrationQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/sizePerIntegrationQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/searchQueryParam\"\n }\n ],\n \"responses\": {\n \"200\": {\n \"description\": \"Org Repository list was fetched successfully with no errors\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/RepositoryList\"\n },\n \"examples\": {\n \"multipleRepos\": {\n \"$ref\": \"#/components/examples/multipleRepos\"\n }\n }\n }\n }\n },\n \"500\": {\n \"description\": \"Generic error when there are errors and no Org Repository is returned\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/RepositoryList\"\n },\n \"examples\": {\n \"repositoryListErrors\": {\n \"$ref\": \"#/components/examples/repositoryListErrors\"\n }\n }\n }\n }\n }\n }\n }\n },\n \"/repositories\": {\n \"get\": {\n \"operationId\": \"findAllRepositories\",\n \"summary\": \"Fetch Organization Repositories accessible by Backstage Github Integrations\",\n \"security\": [\n {\n \"BearerAuth\": []\n }\n ],\n \"tags\": [\n \"Repository\"\n ],\n \"parameters\": [\n {\n \"in\": \"query\",\n \"name\": \"checkImportStatus\",\n \"description\": \"whether to return import status. Note that this might incur a performance penalty because the import status is computed for each repository.\",\n \"schema\": {\n \"type\": \"boolean\",\n \"default\": \"false\"\n }\n },\n {\n \"$ref\": \"#/components/parameters/pagePerIntegrationQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/sizePerIntegrationQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/searchQueryParam\"\n }\n ],\n \"responses\": {\n \"200\": {\n \"description\": \"Repository list was fetched successfully with no errors\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/RepositoryList\"\n },\n \"examples\": {\n \"multipleRepos\": {\n \"$ref\": \"#/components/examples/multipleRepos\"\n }\n }\n }\n }\n },\n \"500\": {\n \"description\": \"Generic error when there are errors and no repository is returned\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/RepositoryList\"\n },\n \"examples\": {\n \"repositoryListErrors\": {\n \"$ref\": \"#/components/examples/repositoryListErrors\"\n }\n }\n }\n }\n }\n }\n }\n },\n \"/imports\": {\n \"get\": {\n \"operationId\": \"findAllImports\",\n \"summary\": \"Fetch Import Jobs\",\n \"security\": [\n {\n \"BearerAuth\": []\n }\n ],\n \"tags\": [\n \"Import\"\n ],\n \"parameters\": [\n {\n \"$ref\": \"#/components/parameters/apiVersionHeaderParam\"\n },\n {\n \"$ref\": \"#/components/parameters/pagePerIntegrationQueryParamDeprecated\"\n },\n {\n \"$ref\": \"#/components/parameters/sizePerIntegrationQueryParamDeprecated\"\n },\n {\n \"$ref\": \"#/components/parameters/pageQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/sizeQueryParam\"\n },\n {\n \"$ref\": \"#/components/parameters/searchQueryParam\"\n }\n ],\n \"responses\": {\n \"200\": {\n \"description\": \"Import Job list was fetched successfully with no errors\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"oneOf\": [\n {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/Import\"\n }\n },\n {\n \"$ref\": \"#/components/schemas/ImportJobListV2\"\n }\n ]\n },\n \"examples\": {\n \"twoImports\": {\n \"$ref\": \"#/components/examples/twoImports\"\n },\n \"multipleImportJobsV2\": {\n \"$ref\": \"#/components/examples/multipleImportJobsV2\"\n }\n }\n }\n }\n },\n \"500\": {\n \"description\": \"Generic error when there are errors and no Import Job is returned\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"oneOf\": [\n {\n \"type\": \"string\",\n \"description\": \"Generic error\"\n },\n {\n \"$ref\": \"#/components/schemas/ImportJobListV2\"\n }\n ]\n },\n \"examples\": {\n \"repositoryListErrors\": {\n \"$ref\": \"#/components/examples/importJobListErrors\"\n }\n }\n }\n }\n }\n }\n },\n \"post\": {\n \"operationId\": \"createImportJobs\",\n \"summary\": \"Submit Import Jobs\",\n \"security\": [\n {\n \"BearerAuth\": []\n }\n ],\n \"tags\": [\n \"Import\"\n ],\n \"parameters\": [\n {\n \"in\": \"query\",\n \"name\": \"dryRun\",\n \"description\": \"whether to perform a dry-run to check if entity name collisions would occur in the catalog\",\n \"schema\": {\n \"type\": \"boolean\",\n \"default\": \"false\"\n }\n }\n ],\n \"requestBody\": {\n \"description\": \"List of Import jobs to create\",\n \"required\": true,\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/ImportRequest\"\n }\n },\n \"examples\": {\n \"multipleImportRequests\": {\n \"$ref\": \"#/components/examples/multipleImportRequests\"\n }\n }\n }\n }\n },\n \"responses\": {\n \"202\": {\n \"description\": \"Import Jobs request was submitted successfully to the API. Check the status in each item of the response body list to see their individual status.\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/Import\"\n }\n },\n \"examples\": {\n \"twoImports\": {\n \"$ref\": \"#/components/examples/twoImportJobs\"\n }\n }\n }\n }\n }\n }\n }\n },\n \"/import/by-repo\": {\n \"get\": {\n \"operationId\": \"findImportStatusByRepo\",\n \"summary\": \"Get Import Status by repository\",\n \"security\": [\n {\n \"BearerAuth\": []\n }\n ],\n \"tags\": [\n \"Import\"\n ],\n \"parameters\": [\n {\n \"in\": \"query\",\n \"name\": \"repo\",\n \"description\": \"the full URL to the repo\",\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"in\": \"query\",\n \"name\": \"defaultBranch\",\n \"description\": \"the name of the default branch\",\n \"schema\": {\n \"type\": \"string\",\n \"default\": \"main\"\n }\n }\n ],\n \"responses\": {\n \"200\": {\n \"description\": \"Import Job status was determined successfully with no errors\",\n \"content\": {\n \"application/json\": {\n \"schema\": {\n \"$ref\": \"#/components/schemas/Import\"\n },\n \"examples\": {\n \"singleImportStatusForRepo\": {\n \"$ref\": \"#/components/examples/singleImportStatusForRepo\"\n }\n }\n }\n }\n },\n \"500\": {\n \"description\": \"Generic error\"\n }\n }\n },\n \"delete\": {\n \"operationId\": \"deleteImportByRepo\",\n \"summary\": \"Delete Import by repository\",\n \"security\": [\n {\n \"BearerAuth\": []\n }\n ],\n \"tags\": [\n \"Import\"\n ],\n \"parameters\": [\n {\n \"in\": \"query\",\n \"name\": \"repo\",\n \"description\": \"the full URL to the repo\",\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"in\": \"query\",\n \"name\": \"defaultBranch\",\n \"description\": \"the name of the default branch\",\n \"schema\": {\n \"type\": \"string\",\n \"default\": \"main\"\n }\n }\n ],\n \"responses\": {\n \"204\": {\n \"description\": \"Import Job was successfully delete with no errors\"\n },\n \"500\": {\n \"description\": \"Generic error\"\n }\n }\n }\n }\n },\n \"components\": {\n \"parameters\": {\n \"apiVersionHeaderParam\": {\n \"in\": \"header\",\n \"name\": \"api-version\",\n \"description\": \"API version.\\\\n\\\\n## Changelog\\\\n\\\\n### v1 (default)\\\\nInitial version\\\\n#### Deprecations\\\\n* GET /imports\\\\n * Deprecation of 'pagePerIntegration' and 'sizePerIntegration' query parameters and introduction of new 'page' and 'size' parameters\\\\n * 'page' takes precedence over 'pagePerIntegration' if both are passed\\\\n * 'size' takes precedence over 'sizePerIntegration' if both are passed\\\\n\\\\n### v2\\\\n#### Breaking changes\\\\n* GET /imports\\\\n * Query parameters:\\\\n * 'pagePerIntegration' is ignored in favor of 'page'\\\\n * 'sizePerIntegration' is ignored in favor of 'size'\\\\n * Response structure changed to include pagination info: instead of returning a simple list of Imports, the response is now an object containing the following fields:\\\\n * 'imports': the list of Imports\\\\n * 'page': the page requested\\\\n * 'size': the requested number of Imports requested per page\\\\n * 'totalCount': the total count of Imports\\\\n\",\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"v1\",\n \"v2\"\n ],\n \"default\": \"v1\"\n }\n },\n \"pagePerIntegrationQueryParam\": {\n \"in\": \"query\",\n \"name\": \"pagePerIntegration\",\n \"description\": \"the page number for each Integration\",\n \"schema\": {\n \"type\": \"integer\",\n \"default\": 1\n }\n },\n \"sizePerIntegrationQueryParam\": {\n \"in\": \"query\",\n \"name\": \"sizePerIntegration\",\n \"description\": \"the number of items per Integration to return per page\",\n \"schema\": {\n \"type\": \"integer\",\n \"default\": 20\n }\n },\n \"pagePerIntegrationQueryParamDeprecated\": {\n \"in\": \"query\",\n \"name\": \"pagePerIntegration\",\n \"description\": \"the page number for each Integration. **Deprecated**. Use the 'page' query parameter instead.\",\n \"deprecated\": true,\n \"schema\": {\n \"type\": \"integer\",\n \"default\": 1\n }\n },\n \"sizePerIntegrationQueryParamDeprecated\": {\n \"in\": \"query\",\n \"name\": \"sizePerIntegration\",\n \"description\": \"the number of items per Integration to return per page. **Deprecated**. Use the 'size' query parameter instead.\",\n \"deprecated\": true,\n \"schema\": {\n \"type\": \"integer\",\n \"default\": 20\n }\n },\n \"searchQueryParam\": {\n \"in\": \"query\",\n \"name\": \"search\",\n \"description\": \"returns only the items that match the search string\",\n \"schema\": {\n \"type\": \"string\"\n }\n },\n \"pageQueryParam\": {\n \"in\": \"query\",\n \"name\": \"page\",\n \"description\": \"the requested page number\",\n \"schema\": {\n \"type\": \"integer\",\n \"default\": 1\n }\n },\n \"sizeQueryParam\": {\n \"in\": \"query\",\n \"name\": \"size\",\n \"description\": \"the number of items to return per page\",\n \"schema\": {\n \"type\": \"integer\",\n \"default\": 20\n }\n }\n },\n \"schemas\": {\n \"OrganizationList\": {\n \"title\": \"Organization List\",\n \"type\": \"object\",\n \"properties\": {\n \"organizations\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/Organization\"\n }\n },\n \"errors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\"\n },\n \"pagePerIntegration\": {\n \"type\": \"integer\"\n },\n \"sizePerIntegration\": {\n \"type\": \"integer\"\n }\n }\n },\n \"Organization\": {\n \"title\": \"Organization\",\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\",\n \"description\": \"unique identifier\"\n },\n \"name\": {\n \"type\": \"string\",\n \"description\": \"organization name\"\n },\n \"description\": {\n \"type\": \"string\",\n \"description\": \"organization description\"\n },\n \"url\": {\n \"type\": \"string\",\n \"description\": \"organization URL\"\n },\n \"totalRepoCount\": {\n \"type\": \"number\",\n \"description\": \"total number of repositories in this Organization\"\n },\n \"errors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"RepositoryList\": {\n \"title\": \"Repository List\",\n \"type\": \"object\",\n \"properties\": {\n \"repositories\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/Repository\"\n }\n },\n \"errors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\"\n },\n \"pagePerIntegration\": {\n \"type\": \"integer\"\n },\n \"sizePerIntegration\": {\n \"type\": \"integer\"\n }\n }\n },\n \"Repository\": {\n \"title\": \"Repository\",\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\",\n \"description\": \"unique identifier\"\n },\n \"name\": {\n \"type\": \"string\",\n \"description\": \"repository name\"\n },\n \"url\": {\n \"type\": \"string\",\n \"description\": \"repository URL\"\n },\n \"organization\": {\n \"type\": \"string\",\n \"description\": \"organization which the repository is part of\"\n },\n \"importStatus\": {\n \"$ref\": \"#/components/schemas/ImportStatus\"\n },\n \"defaultBranch\": {\n \"type\": \"string\",\n \"description\": \"default branch\"\n },\n \"lastUpdate\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"errors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"ApprovalTool\": {\n \"type\": \"string\",\n \"enum\": [\n \"GIT\",\n \"SERVICENOW\"\n ]\n },\n \"ImportStatus\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Import Job status\",\n \"enum\": [\n \"ADDED\",\n \"WAIT_PR_APPROVAL\",\n \"PR_ERROR\",\n null\n ]\n },\n \"ImportJobListV2\": {\n \"title\": \"Import Job List\",\n \"type\": \"object\",\n \"properties\": {\n \"imports\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/components/schemas/Import\"\n }\n },\n \"errors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"totalCount\": {\n \"type\": \"integer\"\n },\n \"page\": {\n \"type\": \"integer\"\n },\n \"size\": {\n \"type\": \"integer\"\n }\n }\n },\n \"Import\": {\n \"title\": \"Import Job\",\n \"type\": \"object\",\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"status\": {\n \"$ref\": \"#/components/schemas/ImportStatus\"\n },\n \"catalogEntityName\": {\n \"type\": \"string\",\n \"description\": \"Specified entity name in the catalog. Filled only in response for dry-run import requests.\"\n },\n \"lastUpdate\": {\n \"type\": \"string\",\n \"format\": \"date-time\"\n },\n \"errors\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"approvalTool\": {\n \"$ref\": \"#/components/schemas/ApprovalTool\"\n },\n \"repository\": {\n \"$ref\": \"#/components/schemas/Repository\"\n },\n \"github\": {\n \"type\": \"object\",\n \"description\": \"GitHub details. Applicable if approvalTool is git.\",\n \"properties\": {\n \"pullRequest\": {\n \"type\": \"object\",\n \"properties\": {\n \"url\": {\n \"type\": \"string\",\n \"description\": \"URL of the Pull Request\"\n },\n \"number\": {\n \"type\": \"number\",\n \"description\": \"Pull Request number\"\n },\n \"title\": {\n \"type\": \"string\",\n \"description\": \"title of the Pull Request\"\n },\n \"body\": {\n \"type\": \"string\",\n \"description\": \"body of the Pull Request\"\n },\n \"catalogInfoContent\": {\n \"type\": \"string\",\n \"description\": \"content of the catalog-info.yaml as fetched from the Pull Request.\"\n }\n }\n }\n }\n }\n }\n },\n \"ImportRequest\": {\n \"title\": \"Import Job request\",\n \"type\": \"object\",\n \"required\": [\n \"repository\"\n ],\n \"properties\": {\n \"approvalTool\": {\n \"$ref\": \"#/components/schemas/ApprovalTool\"\n },\n \"catalogEntityName\": {\n \"type\": \"string\",\n \"description\": \"Expected Entity name in the catalog. Relevant only if the 'dryRun' query parameter is set to 'true'.\"\n },\n \"codeOwnersFileAsEntityOwner\": {\n \"type\": \"boolean\",\n \"description\": \"Whether the CODEOWNERS file will be used as entity owner. Only relevant for dry-run requests. If set to 'false', the corresponding dry-run check will be skipped.\"\n },\n \"repository\": {\n \"type\": \"object\",\n \"required\": [\n \"url\"\n ],\n \"properties\": {\n \"name\": {\n \"type\": \"string\",\n \"description\": \"repository name\"\n },\n \"url\": {\n \"type\": \"string\",\n \"description\": \"repository URL\"\n },\n \"organization\": {\n \"type\": \"string\",\n \"description\": \"organization which the repository is part of\"\n },\n \"defaultBranch\": {\n \"type\": \"string\",\n \"description\": \"default branch\"\n }\n }\n },\n \"catalogInfoContent\": {\n \"type\": \"string\",\n \"description\": \"content of the catalog-info.yaml to include in the import Pull Request.\"\n },\n \"github\": {\n \"type\": \"object\",\n \"description\": \"GitHub details. Applicable if approvalTool is git.\",\n \"properties\": {\n \"pullRequest\": {\n \"type\": \"object\",\n \"description\": \"Pull Request details. Applicable if approvalTool is git.\",\n \"properties\": {\n \"title\": {\n \"type\": \"string\",\n \"description\": \"title of the Pull Request\"\n },\n \"body\": {\n \"type\": \"string\",\n \"description\": \"body of the Pull Request\"\n }\n }\n }\n }\n }\n }\n }\n },\n \"securitySchemes\": {\n \"BearerAuth\": {\n \"type\": \"http\",\n \"scheme\": \"bearer\",\n \"bearerFormat\": \"JWT\",\n \"description\": \"Backstage Permissions Framework JWT\"\n }\n },\n \"examples\": {\n \"multipleOrgs\": {\n \"summary\": \"Multiple organizations\",\n \"value\": {\n \"errors\": [],\n \"organizations\": [\n {\n \"id\": \"unique-org-id-1\",\n \"name\": \"pet-org\",\n \"url\": \"https://github.com/pet-org\",\n \"description\": \"A great Pet Org\",\n \"totalRepoCount\": 10\n },\n {\n \"id\": \"unique-org-id-2\",\n \"name\": \"org-zero\",\n \"url\": \"https://ghe.example.com/org-zero\",\n \"totalRepoCount\": 0\n },\n {\n \"id\": \"unique-id-2\",\n \"name\": \"org-one\",\n \"url\": \"https://ghe.example.com/org-one\",\n \"description\": \"Org One description\",\n \"totalRepoCount\": 1234\n }\n ]\n }\n },\n \"orgListErrors\": {\n \"summary\": \"Errors when listing organizations\",\n \"value\": {\n \"errors\": [\n \"Github App with ID 2 failed spectacularly\"\n ],\n \"organizations\": []\n }\n },\n \"multipleRepos\": {\n \"summary\": \"Multiple repositories\",\n \"value\": {\n \"errors\": [],\n \"repositories\": [\n {\n \"id\": \"unique-id-1\",\n \"name\": \"pet-app\",\n \"url\": \"https://github.com/my-org/pet-app\",\n \"organization\": \"my-org\",\n \"importStatus\": \"WAIT_PR_APPROVAL\",\n \"defaultBranch\": \"main\"\n },\n {\n \"id\": \"unique-id-2\",\n \"name\": \"project-zero\",\n \"url\": \"https://ghe.example.com/my-other-org/project-zero\",\n \"organization\": \"my-other-org\",\n \"importStatus\": \"PR_REJECTED\",\n \"defaultBranch\": \"dev\"\n },\n {\n \"id\": \"unique-id-2\",\n \"name\": \"project-one\",\n \"defaultBranch\": \"trunk\",\n \"url\": \"https://ghe.example.com/my-other-org-2/project-one\",\n \"organization\": \"my-other-org-2\"\n }\n ]\n }\n },\n \"repositoryListErrors\": {\n \"summary\": \"Errors when listing repositories\",\n \"value\": {\n \"errors\": [\n \"Github App with ID 2 failed spectacularly\"\n ],\n \"repositories\": []\n }\n },\n \"twoImports\": {\n \"summary\": \"Two import job requests (V1)\",\n \"value\": [\n {\n \"id\": \"bulk-import-id-1\",\n \"status\": \"WAIT_PR_APPROVAL\",\n \"errors\": [],\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app\",\n \"url\": \"https://github.com/my-org/pet-app\",\n \"organization\": \"my-org\"\n },\n \"github\": {\n \"pullRequest\": {\n \"url\": \"https://github.com/my-org/pet-app/pull/1\",\n \"number\": 1\n }\n }\n },\n {\n \"id\": \"bulk-import-id-2\",\n \"status\": \"PR_REJECTED\",\n \"errors\": [],\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app-test\",\n \"url\": \"https://github.com/my-org/pet-app-test\",\n \"organization\": \"my-org\"\n },\n \"github\": {\n \"pullRequest\": {\n \"url\": \"https://github.com/my-org/pet-app-test/pull/10\",\n \"number\": 10\n }\n }\n }\n ]\n },\n \"multipleImportJobsV2\": {\n \"summary\": \"Two import job requests (V2)\",\n \"value\": {\n \"errors\": [],\n \"page\": 1,\n \"size\": 2,\n \"totalCount\": 10,\n \"imports\": [\n {\n \"id\": \"bulk-import-id-1\",\n \"status\": \"WAIT_PR_APPROVAL\",\n \"errors\": [],\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app\",\n \"url\": \"https://github.com/my-org/pet-app\",\n \"organization\": \"my-org\"\n },\n \"github\": {\n \"pullRequest\": {\n \"url\": \"https://github.com/my-org/pet-app/pull/1\",\n \"number\": 1\n }\n }\n },\n {\n \"id\": \"bulk-import-id-2\",\n \"status\": \"PR_REJECTED\",\n \"errors\": [],\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app-test\",\n \"url\": \"https://github.com/my-org/pet-app-test\",\n \"organization\": \"my-org\"\n },\n \"github\": {\n \"pullRequest\": {\n \"url\": \"https://github.com/my-org/pet-app-test/pull/10\",\n \"number\": 10\n }\n }\n }\n ]\n }\n },\n \"importJobListErrors\": {\n \"summary\": \"Errors when listing import jobs\",\n \"value\": {\n \"errors\": [\n \"Github App with ID xyz-123 failed spectacularly\"\n ],\n \"imports\": []\n }\n },\n \"twoImportJobs\": {\n \"summary\": \"Two import jobs\",\n \"value\": [\n {\n \"id\": \"bulk-import-id-1\",\n \"status\": \"WAIT_PR_APPROVAL\",\n \"errors\": [],\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app\",\n \"url\": \"https://github.com/my-org/pet-app\",\n \"organization\": \"my-org\"\n },\n \"github\": {\n \"pullRequest\": {\n \"url\": \"https://github.com/my-org/pet-app/pull/1\",\n \"number\": 1\n }\n }\n },\n {\n \"id\": \"bulk-import-id-2\",\n \"status\": \"PR_REJECTED\",\n \"errors\": [],\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app-test\",\n \"url\": \"https://github.com/my-org/pet-app-test\",\n \"organization\": \"my-org\"\n },\n \"github\": {\n \"pullRequest\": {\n \"url\": \"https://github.com/my-org/pet-app-test/pull/10\",\n \"number\": 10\n }\n }\n }\n ]\n },\n \"singleImportStatusForRepo\": {\n \"summary\": \"Single import job status for given repo\",\n \"value\": {\n \"id\": \"bulk-import-id-1\",\n \"status\": \"WAIT_PR_APPROVAL\",\n \"errors\": [],\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app\",\n \"url\": \"https://github.com/my-org/pet-app\",\n \"organization\": \"my-org\"\n },\n \"github\": {\n \"pullRequest\": {\n \"url\": \"https://github.com/my-org/pet-app/pull/1\",\n \"number\": 1\n }\n }\n }\n },\n \"multipleImportRequests\": {\n \"summary\": \"Multiple import requests\",\n \"value\": [\n {\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"pet-app\",\n \"url\": \"https://github.com/my-org/pet-app\",\n \"organization\": \"my-org\",\n \"defaultBranch\": \"main\"\n },\n \"github\": {\n \"pullRequest\": {\n \"title\": \"Add default catalog-info.yaml to import to Red Hat Developer Hub\"\n }\n }\n },\n {\n \"approvalTool\": \"GIT\",\n \"repository\": {\n \"name\": \"project-zero\",\n \"url\": \"https://ghe.example.com/my-other-org/project-zero\",\n \"organization\": \"my-other-org\",\n \"defaultBranch\": \"dev\"\n },\n \"github\": {\n \"pullRequest\": {\n \"title\": \"Add custom catalog-info.yaml to import to Red Hat Developer Hub\",\n \"body\": \"This pull request adds a **Backstage entity metadata file** to this repository so that the component can be added to the Red Hat Developer Hub software catalog.\\\\n\\\\nAfter this pull request is merged, the component will become available.\\\\n\\\\nFor more information, read an [overview of the Backstage software catalog](https://backstage.io/docs/features/software-catalog/).\"\n }\n },\n \"catalogInfoContent\": \"apiVersion: backstage.io/v1alpha1\\\\nkind: Component\\\\nmetadata:\\\\n name: project-zero\\\\n annotations:\\\\n github.com/project-slug: my-other-org/project-zero\\\\n acme.com/custom-annotation: my-value\\\\nspec:\\\\n type: other\\\\n lifecycle: unknown\\\\n owner: my-other-org\"\n }\n ]\n }\n }\n }\n}`\nexport const openApiDocument = JSON.parse(OPENAPI);\n"],"names":[],"mappings":";;AAkBA,MAAM,OAAU,GAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA,CAAA,CAAA;AA0oCH,MAAA,eAAA,GAAkB,IAAK,CAAA,KAAA,CAAM,OAAO;;;;"}
@@ -0,0 +1,395 @@
1
+ 'use strict';
2
+
3
+ var authApp = require('@octokit/auth-app');
4
+ var rest = require('@octokit/rest');
5
+ var gitUrlParse = require('git-url-parse');
6
+ var luxon = require('luxon');
7
+
8
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
9
+
10
+ var gitUrlParse__default = /*#__PURE__*/_interopDefaultCompat(gitUrlParse);
11
+
12
+ class Cache {
13
+ tokenCache = /* @__PURE__ */ new Map();
14
+ isExpired(date) {
15
+ return luxon.DateTime.local() > date;
16
+ }
17
+ async getOrCreateToken(key, supplier) {
18
+ let existingInstallationData = this.tokenCache.get(key);
19
+ if (!existingInstallationData || this.isExpired(existingInstallationData.expiresAt)) {
20
+ existingInstallationData = await supplier();
21
+ existingInstallationData.expiresAt = existingInstallationData.expiresAt.minus({ minutes: 10 });
22
+ this.tokenCache.set(key, existingInstallationData);
23
+ }
24
+ return {
25
+ accessToken: existingInstallationData.token,
26
+ installationAccountLogin: existingInstallationData.installationAccountLogin
27
+ };
28
+ }
29
+ }
30
+ const HEADERS = {
31
+ Accept: "application/vnd.github.machine-man-preview+json"
32
+ };
33
+ class GithubAppManager {
34
+ appClient;
35
+ baseUrl;
36
+ baseAuthConfig;
37
+ cache = new Cache();
38
+ allowedInstallationOwners;
39
+ // undefined allows all installations
40
+ constructor(config, baseUrl) {
41
+ this.allowedInstallationOwners = config.allowedInstallationOwners;
42
+ this.baseUrl = baseUrl;
43
+ this.baseAuthConfig = {
44
+ appId: config.appId,
45
+ privateKey: config.privateKey.replace(/\\n/gm, "\n")
46
+ };
47
+ this.appClient = new rest.Octokit({
48
+ baseUrl,
49
+ headers: HEADERS,
50
+ authStrategy: authApp.createAppAuth,
51
+ auth: this.baseAuthConfig
52
+ });
53
+ }
54
+ getAppId() {
55
+ return this.baseAuthConfig.appId;
56
+ }
57
+ async getInstallationCredentials(host) {
58
+ const creds = [];
59
+ const installationData = await this.getInstallationData();
60
+ let installationDataFiltered = [];
61
+ if (this.allowedInstallationOwners) {
62
+ for (const installation of installationData) {
63
+ if (installation.accountLogin && !this.allowedInstallationOwners.includes(installation.accountLogin)) {
64
+ continue;
65
+ }
66
+ installationDataFiltered.push(installation);
67
+ }
68
+ } else {
69
+ installationDataFiltered = installationData;
70
+ }
71
+ if (installationDataFiltered.length === 0) {
72
+ return Array.of({ accessToken: void 0 });
73
+ }
74
+ for (const installation of installationDataFiltered) {
75
+ const installationId = installation.installationId;
76
+ if (installation.suspended) {
77
+ throw new Error(
78
+ `The GitHub application for ${installationId} is suspended`
79
+ );
80
+ }
81
+ const cred = await this.cache.getOrCreateToken(
82
+ `${host}-${installationId}`,
83
+ async () => {
84
+ const result = await this.appClient.apps.createInstallationAccessToken({
85
+ installation_id: installationId,
86
+ headers: HEADERS
87
+ });
88
+ if (!result) {
89
+ return {
90
+ token: "",
91
+ expiresAt: luxon.DateTime.now().plus({ minutes: 1 }),
92
+ repositories: [],
93
+ installationAccountLogin: installation.accountLogin
94
+ };
95
+ }
96
+ let repositoryNames;
97
+ if (result.data.repository_selection === "selected") {
98
+ const installationClient = new rest.Octokit({
99
+ baseUrl: this.baseUrl,
100
+ auth: result.data.token
101
+ });
102
+ const repos = await installationClient.paginate(
103
+ installationClient.apps.listReposAccessibleToInstallation
104
+ );
105
+ const repositories = repos.repositories ?? repos;
106
+ repositoryNames = repositories.map((repository) => repository.name);
107
+ }
108
+ return {
109
+ token: result.data.token,
110
+ expiresAt: luxon.DateTime.fromISO(result.data.expires_at),
111
+ repositories: repositoryNames,
112
+ installationAccountLogin: installation.accountLogin
113
+ };
114
+ }
115
+ );
116
+ creds.push(cred);
117
+ }
118
+ return creds;
119
+ }
120
+ getInstallations() {
121
+ return this.appClient.paginate(this.appClient.apps.listInstallations);
122
+ }
123
+ async getInstallationData() {
124
+ const allInstallations = await this.getInstallations();
125
+ return allInstallations.map((installation) => {
126
+ return {
127
+ installationId: installation.id,
128
+ accountLogin: installation.account?.login,
129
+ suspended: Boolean(installation.suspended_by)
130
+ };
131
+ });
132
+ }
133
+ }
134
+ class GithubAppsCredentialManager {
135
+ apps;
136
+ constructor(config) {
137
+ this.apps = config.apps?.map((ac) => new GithubAppManager(ac, config.apiBaseUrl)) ?? [];
138
+ }
139
+ async getAllInstallations() {
140
+ if (!this.apps.length) {
141
+ return [];
142
+ }
143
+ const installs = await Promise.all(
144
+ this.apps.map((app) => app.getInstallations())
145
+ );
146
+ return installs.flat();
147
+ }
148
+ async getAppToken(host) {
149
+ if (this.apps.length === 0) {
150
+ return void 0;
151
+ }
152
+ const results = await Promise.all(
153
+ this.apps.map(
154
+ (app) => app.getInstallationCredentials(host).then(
155
+ (credentials) => ({ credentials, error: void 0 }),
156
+ (error) => ({ credentials: void 0, error })
157
+ )
158
+ )
159
+ );
160
+ const result = results.find(
161
+ (resultItem) => resultItem.credentials && resultItem.credentials.length !== 0 && resultItem.credentials[0]?.accessToken
162
+ );
163
+ if (result?.credentials) {
164
+ return result.credentials[0].accessToken;
165
+ }
166
+ const errors = results.map((r) => r.error);
167
+ const notNotFoundError = errors.find((err) => err?.name !== "NotFoundError");
168
+ if (notNotFoundError) {
169
+ throw notNotFoundError;
170
+ }
171
+ return void 0;
172
+ }
173
+ /**
174
+ * Returns an array of app access tokens.
175
+ *
176
+ * Some values in the array might not contain a token and will have an error field instead. This will need to be resolved on the user side
177
+ */
178
+ async getAllAppTokens(host) {
179
+ if (this.apps.length === 0) return [];
180
+ const appCredentials = await Promise.all(
181
+ this.apps.map(
182
+ (app) => app.getInstallationCredentials(host).then(
183
+ (credentials2) => ({
184
+ appId: app.getAppId(),
185
+ credentials: credentials2,
186
+ error: void 0
187
+ }),
188
+ (error) => ({ appId: app.getAppId(), credentials: void 0, error })
189
+ )
190
+ )
191
+ );
192
+ const credentials = [];
193
+ for (const cred of appCredentials) {
194
+ if (cred.credentials) {
195
+ for (const credElement of cred.credentials) {
196
+ credentials.push({
197
+ appId: cred.appId,
198
+ accessToken: credElement.accessToken,
199
+ installationAccountLogin: credElement.installationAccountLogin
200
+ });
201
+ }
202
+ } else {
203
+ credentials.push({
204
+ appId: cred.appId,
205
+ error: cred.error
206
+ });
207
+ }
208
+ }
209
+ return credentials;
210
+ }
211
+ }
212
+ class CustomSingleInstanceGithubCredentialsProvider {
213
+ constructor(githubAppsCredentialManager, token) {
214
+ this.githubAppsCredentialManager = githubAppsCredentialManager;
215
+ this.token = token;
216
+ }
217
+ static create = (config) => {
218
+ return new CustomSingleInstanceGithubCredentialsProvider(
219
+ new GithubAppsCredentialManager(config),
220
+ config.token
221
+ );
222
+ };
223
+ /**
224
+ * Returns {@link GithubCredentials} for a given URL.
225
+ *
226
+ * @remarks
227
+ *
228
+ * Consecutive calls to this method with the same URL will return cached
229
+ * credentials.
230
+ *
231
+ * The shortest lifetime for a token returned is 10 minutes.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * const { token, headers } = await getCredentials({
236
+ * url: 'github.com/backstage/foobar'
237
+ * })
238
+ * ```
239
+ *
240
+ * @param opts - The organization or repository URL
241
+ * @returns A promise of {@link GithubCredentials}.
242
+ */
243
+ async getCredentials(opts) {
244
+ const parsed = gitUrlParse__default.default(opts.url);
245
+ const owner = parsed.owner || parsed.name;
246
+ let type = "app";
247
+ let token = await this.githubAppsCredentialManager.getAppToken(owner);
248
+ if (!token) {
249
+ type = "token";
250
+ token = this.token;
251
+ }
252
+ return {
253
+ headers: token ? { Authorization: `Bearer ${token}` } : void 0,
254
+ token,
255
+ type
256
+ };
257
+ }
258
+ /**
259
+ * Returns {@link ExtendedGithubCredentials[]} for a given URL.
260
+ *
261
+ * @remarks
262
+ *
263
+ * Consecutive calls to this method with the same URL will return cached
264
+ * credentials.
265
+ *
266
+ * The shortest lifetime for a token returned is 10 minutes.
267
+ *
268
+ * Errors may be included in the returned array if the app credentials could not be fetched
269
+ * These need to be dealt with by the user.
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * const credentialList = await getCredentials({
274
+ * url: 'github.com/backstage/foobar'
275
+ * })
276
+ * for (const credential of credentialList){
277
+ * if (credential.type === 'app'){
278
+ * // Deal with the error if it exists
279
+ * if (credentials.error){
280
+ * console.error(`Error generating credential for ${credential.appId}: ${credential.error}`)
281
+ * }
282
+ * else {
283
+ * // Do something with the token
284
+ * }
285
+ * }
286
+ * else{
287
+ * // Do something with the token
288
+ * }
289
+ *
290
+ * }
291
+ * ```
292
+ *
293
+ * @param opts - The organization or repository URL
294
+ * @returns A promise of {@link ExtendedGithubCredentials[]}.
295
+ */
296
+ async getAllCredentials(opts) {
297
+ const appCredentials = await this.githubAppsCredentialManager.getAllAppTokens(opts.host);
298
+ const credentials = [];
299
+ if (this.token) {
300
+ credentials.push({
301
+ headers: { Authorization: `Bearer ${this.token}` },
302
+ token: this.token,
303
+ type: "token"
304
+ });
305
+ }
306
+ for (const app of appCredentials) {
307
+ if ("accessToken" in app) {
308
+ credentials.push({
309
+ headers: { Authorization: `Bearer ${app.accessToken}` },
310
+ token: app.accessToken,
311
+ type: "app",
312
+ appId: app.appId,
313
+ accountLogin: app.installationAccountLogin
314
+ });
315
+ } else {
316
+ credentials.push({
317
+ type: "app",
318
+ error: app.error,
319
+ appId: app.appId
320
+ });
321
+ }
322
+ }
323
+ return credentials;
324
+ }
325
+ }
326
+ class CustomGithubCredentialsProvider {
327
+ constructor(providers) {
328
+ this.providers = providers;
329
+ }
330
+ static fromIntegrations(integrations) {
331
+ const credentialsProviders = /* @__PURE__ */ new Map();
332
+ integrations.github.list().forEach((integration) => {
333
+ const credentialsProvider = CustomSingleInstanceGithubCredentialsProvider.create(
334
+ integration.config
335
+ );
336
+ credentialsProviders.set(integration.config.host, credentialsProvider);
337
+ });
338
+ return new CustomGithubCredentialsProvider(credentialsProviders);
339
+ }
340
+ /**
341
+ * Returns {@link GithubCredentials} for a given URL.
342
+ *
343
+ * @remarks
344
+ *
345
+ * Consecutive calls to this method with the same URL will return cached
346
+ * credentials.
347
+ *
348
+ * The shortest lifetime for a token returned is 10 minutes.
349
+ *
350
+ * @example
351
+ * ```ts
352
+ * const { token, headers } = await getCredentials({
353
+ * url: 'https://github.com/backstage/foobar'
354
+ * })
355
+ *
356
+ * const { token, headers } = await getCredentials({
357
+ * url: 'https://github.com/backstage'
358
+ * })
359
+ * ```
360
+ *
361
+ * @param opts - The organization or repository URL
362
+ * @returns A promise of {@link GithubCredentials}.
363
+ */
364
+ async getCredentials(opts) {
365
+ const parsed = new URL(opts.url);
366
+ const provider = this.providers.get(parsed.host);
367
+ if (!provider) {
368
+ throw new Error(
369
+ `There is no GitHub integration that matches ${opts.url}. Please add a configuration for an integration.`
370
+ );
371
+ }
372
+ return provider.getCredentials(opts);
373
+ }
374
+ async getAllCredentials(opts) {
375
+ const provider = this.providers.get(opts.host);
376
+ if (!provider) {
377
+ throw new Error(
378
+ `There is no GitHub integration that matches ${opts.host}. Please add a configuration for an integration.`
379
+ );
380
+ }
381
+ return provider.getAllCredentials(opts);
382
+ }
383
+ async getAllAppInstallations(config) {
384
+ return new GithubAppsCredentialManager(config).getAllInstallations();
385
+ }
386
+ async getAppInstallationsForOrg(config, org) {
387
+ const all = await this.getAllAppInstallations(config);
388
+ return all.filter((install) => install.account?.login === org);
389
+ }
390
+ }
391
+
392
+ exports.CustomGithubCredentialsProvider = CustomGithubCredentialsProvider;
393
+ exports.CustomSingleInstanceGithubCredentialsProvider = CustomSingleInstanceGithubCredentialsProvider;
394
+ exports.GithubAppsCredentialManager = GithubAppsCredentialManager;
395
+ //# sourceMappingURL=GithubAppManager.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GithubAppManager.cjs.js","sources":["../../src/github/GithubAppManager.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\n/**\n * Base code taken from upstream https://github.com/backstage/backstage/blob/master/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts\n * due to them not exporting the `GithubAppManager` class. Modifications were made to grab access tokens from all apps scoped to a repository/organization/user\n */\nimport type {\n GithubAppConfig,\n GithubCredentials,\n GithubCredentialType,\n GithubIntegrationConfig,\n ScmIntegrationRegistry,\n} from '@backstage/integration';\n\nimport { createAppAuth } from '@octokit/auth-app';\nimport { Octokit, type RestEndpointMethodTypes } from '@octokit/rest';\nimport gitUrlParse from 'git-url-parse';\nimport { DateTime } from 'luxon';\n\nimport type {\n AppCredentialFetchResult,\n ExtendedGithubCredentials,\n ExtendedGithubCredentialsProvider,\n} from './types';\n\n/**\n * The Cache and GithubAppManager classes in this file were directly taken from the\n * upstream at https://github.com/backstage/backstage/blob/master/packages/integration/src/github/SingleInstanceGithubCredentialsProvider.ts\n * as they were not exported but were required when extending the GithubAppCredentialsMux.\n */\n\ntype InstallationData = {\n installationId: number;\n accountLogin?: string;\n suspended: boolean;\n};\n\ntype InstallationTokenData = {\n token: string;\n expiresAt: DateTime;\n repositories?: string[];\n installationAccountLogin?: string;\n};\nclass Cache {\n private readonly tokenCache = new Map<string, InstallationTokenData>();\n\n private isExpired(date: DateTime) {\n return DateTime.local() > date;\n }\n\n async getOrCreateToken(\n key: string,\n supplier: () => Promise<InstallationTokenData>,\n ): Promise<{ accessToken: string; installationAccountLogin?: string }> {\n let existingInstallationData = this.tokenCache.get(key);\n\n if (\n !existingInstallationData ||\n this.isExpired(existingInstallationData.expiresAt)\n ) {\n existingInstallationData = await supplier();\n // Allow 10 minutes grace to account for clock skew\n existingInstallationData.expiresAt =\n existingInstallationData.expiresAt.minus({ minutes: 10 });\n this.tokenCache.set(key, existingInstallationData);\n }\n\n return {\n accessToken: existingInstallationData.token,\n installationAccountLogin:\n existingInstallationData.installationAccountLogin,\n };\n }\n}\n\n/**\n * This accept header is required when calling App APIs in GitHub Enterprise.\n * It has no effect on calls to github.com and can probably be removed entirely\n * once GitHub Apps is out of preview.\n */\nconst HEADERS = {\n Accept: 'application/vnd.github.machine-man-preview+json',\n};\n\n/**\n * GithubAppManager issues and caches tokens for a specific GitHub App.\n */\nclass GithubAppManager {\n private readonly appClient: Octokit;\n private readonly baseUrl?: string;\n private readonly baseAuthConfig: { appId: number; privateKey: string };\n private readonly cache = new Cache();\n private readonly allowedInstallationOwners: string[] | undefined; // undefined allows all installations\n\n constructor(config: GithubAppConfig, baseUrl?: string) {\n this.allowedInstallationOwners = config.allowedInstallationOwners;\n this.baseUrl = baseUrl;\n this.baseAuthConfig = {\n appId: config.appId,\n privateKey: config.privateKey.replace(/\\\\n/gm, '\\n'),\n };\n this.appClient = new Octokit({\n baseUrl,\n headers: HEADERS,\n authStrategy: createAppAuth,\n auth: this.baseAuthConfig,\n });\n }\n getAppId(): number {\n return this.baseAuthConfig.appId;\n }\n\n async getInstallationCredentials(\n host: string,\n ): Promise<\n { accessToken: string | undefined; installationAccountLogin?: string }[]\n > {\n const creds: {\n accessToken: string | undefined;\n installationAccountLogin?: string;\n }[] = [];\n const installationData = await this.getInstallationData();\n let installationDataFiltered: InstallationData[] = [];\n if (this.allowedInstallationOwners) {\n for (const installation of installationData) {\n if (\n installation.accountLogin &&\n !this.allowedInstallationOwners.includes(installation.accountLogin)\n ) {\n continue;\n }\n installationDataFiltered.push(installation);\n }\n } else {\n installationDataFiltered = installationData;\n }\n\n if (installationDataFiltered.length === 0) {\n return Array.of({ accessToken: undefined }); // An empty token allows anonymous access to public repos\n }\n\n for (const installation of installationDataFiltered) {\n const installationId = installation.installationId;\n if (installation.suspended) {\n throw new Error(\n `The GitHub application for ${installationId} is suspended`,\n );\n }\n const cred = await this.cache.getOrCreateToken(\n `${host}-${installationId}`,\n async () => {\n const result =\n await this.appClient.apps.createInstallationAccessToken({\n installation_id: installationId,\n headers: HEADERS,\n });\n\n if (!result) {\n return {\n token: '',\n expiresAt: DateTime.now().plus({ minutes: 1 }),\n repositories: [],\n installationAccountLogin: installation.accountLogin,\n };\n }\n\n let repositoryNames;\n\n if (result.data.repository_selection === 'selected') {\n const installationClient = new Octokit({\n baseUrl: this.baseUrl,\n auth: result.data.token,\n });\n const repos = await installationClient.paginate(\n installationClient.apps.listReposAccessibleToInstallation,\n );\n // The return type of the paginate method is incorrect.\n const repositories: RestEndpointMethodTypes['apps']['listReposAccessibleToInstallation']['response']['data']['repositories'] =\n repos.repositories ?? repos;\n\n repositoryNames = repositories.map(repository => repository.name);\n }\n return {\n token: result.data.token,\n expiresAt: DateTime.fromISO(result.data.expires_at),\n repositories: repositoryNames,\n installationAccountLogin: installation.accountLogin,\n };\n },\n );\n creds.push(cred);\n }\n\n return creds;\n }\n\n getInstallations(): Promise<\n RestEndpointMethodTypes['apps']['listInstallations']['response']['data']\n > {\n return this.appClient.paginate(this.appClient.apps.listInstallations);\n }\n\n private async getInstallationData(): Promise<InstallationData[]> {\n const allInstallations = await this.getInstallations();\n return allInstallations.map(installation => {\n return {\n installationId: installation.id,\n accountLogin: installation.account?.login,\n suspended: Boolean(installation.suspended_by),\n } as InstallationData;\n });\n }\n}\n\n/**\n * Manages all the github apps in the github integration configurations\n */\nexport class GithubAppsCredentialManager {\n private readonly apps: GithubAppManager[];\n\n constructor(config: GithubIntegrationConfig) {\n this.apps =\n config.apps?.map(ac => new GithubAppManager(ac, config.apiBaseUrl)) ?? [];\n }\n\n async getAllInstallations(): Promise<\n RestEndpointMethodTypes['apps']['listInstallations']['response']['data']\n > {\n if (!this.apps.length) {\n return [];\n }\n\n const installs = await Promise.all(\n this.apps.map(app => app.getInstallations()),\n );\n\n return installs.flat();\n }\n\n async getAppToken(host: string): Promise<string | undefined> {\n if (this.apps.length === 0) {\n return undefined;\n }\n\n const results = await Promise.all(\n this.apps.map(app =>\n app.getInstallationCredentials(host).then(\n credentials => ({ credentials, error: undefined }),\n error => ({ credentials: undefined, error }),\n ),\n ),\n );\n\n const result = results.find(\n resultItem =>\n resultItem.credentials &&\n resultItem.credentials!.length !== 0 &&\n resultItem.credentials[0]?.accessToken,\n );\n if (result?.credentials) {\n return result.credentials[0].accessToken;\n }\n\n const errors = results.map(r => r.error);\n const notNotFoundError = errors.find(err => err?.name !== 'NotFoundError');\n if (notNotFoundError) {\n throw notNotFoundError;\n }\n\n return undefined;\n }\n\n /**\n * Returns an array of app access tokens.\n *\n * Some values in the array might not contain a token and will have an error field instead. This will need to be resolved on the user side\n */\n async getAllAppTokens(host: string): Promise<AppCredentialFetchResult[]> {\n if (this.apps.length === 0) return [];\n\n const appCredentials = await Promise.all(\n this.apps.map(app =>\n app.getInstallationCredentials(host).then(\n credentials => ({\n appId: app.getAppId(),\n credentials,\n error: undefined,\n }),\n error => ({ appId: app.getAppId(), credentials: undefined, error }),\n ),\n ),\n );\n const credentials: AppCredentialFetchResult[] = [];\n for (const cred of appCredentials) {\n if (cred.credentials) {\n for (const credElement of cred.credentials) {\n credentials.push({\n appId: cred.appId,\n accessToken: credElement.accessToken,\n installationAccountLogin: credElement.installationAccountLogin,\n });\n }\n } else {\n credentials.push({\n appId: cred.appId,\n error: cred.error,\n });\n }\n }\n return credentials;\n }\n}\n\nexport class CustomSingleInstanceGithubCredentialsProvider\n implements ExtendedGithubCredentialsProvider\n{\n static readonly create: (\n config: GithubIntegrationConfig,\n ) => ExtendedGithubCredentialsProvider = config => {\n return new CustomSingleInstanceGithubCredentialsProvider(\n new GithubAppsCredentialManager(config),\n config.token,\n );\n };\n\n private constructor(\n private readonly githubAppsCredentialManager: GithubAppsCredentialManager,\n private readonly token?: string,\n ) {}\n\n /**\n * Returns {@link GithubCredentials} for a given URL.\n *\n * @remarks\n *\n * Consecutive calls to this method with the same URL will return cached\n * credentials.\n *\n * The shortest lifetime for a token returned is 10 minutes.\n *\n * @example\n * ```ts\n * const { token, headers } = await getCredentials({\n * url: 'github.com/backstage/foobar'\n * })\n * ```\n *\n * @param opts - The organization or repository URL\n * @returns A promise of {@link GithubCredentials}.\n */\n async getCredentials(opts: { url: string }): Promise<GithubCredentials> {\n const parsed = gitUrlParse(opts.url);\n const owner = parsed.owner || parsed.name;\n\n let type: GithubCredentialType = 'app';\n let token = await this.githubAppsCredentialManager.getAppToken(owner);\n if (!token) {\n type = 'token';\n token = this.token;\n }\n\n return {\n headers: token ? { Authorization: `Bearer ${token}` } : undefined,\n token,\n type,\n };\n }\n\n /**\n * Returns {@link ExtendedGithubCredentials[]} for a given URL.\n *\n * @remarks\n *\n * Consecutive calls to this method with the same URL will return cached\n * credentials.\n *\n * The shortest lifetime for a token returned is 10 minutes.\n *\n * Errors may be included in the returned array if the app credentials could not be fetched\n * These need to be dealt with by the user.\n *\n * @example\n * ```ts\n * const credentialList = await getCredentials({\n * url: 'github.com/backstage/foobar'\n * })\n * for (const credential of credentialList){\n * if (credential.type === 'app'){\n * // Deal with the error if it exists\n * if (credentials.error){\n * console.error(`Error generating credential for ${credential.appId}: ${credential.error}`)\n * }\n * else {\n * // Do something with the token\n * }\n * }\n * else{\n * // Do something with the token\n * }\n *\n * }\n * ```\n *\n * @param opts - The organization or repository URL\n * @returns A promise of {@link ExtendedGithubCredentials[]}.\n */\n async getAllCredentials(opts: {\n host: string;\n }): Promise<ExtendedGithubCredentials[]> {\n const appCredentials =\n await this.githubAppsCredentialManager.getAllAppTokens(opts.host);\n\n const credentials: ExtendedGithubCredentials[] = [];\n if (this.token) {\n credentials.push({\n headers: { Authorization: `Bearer ${this.token}` },\n token: this.token,\n type: 'token',\n });\n }\n for (const app of appCredentials) {\n if ('accessToken' in app) {\n credentials.push({\n headers: { Authorization: `Bearer ${app.accessToken}` },\n token: app.accessToken,\n type: 'app',\n appId: app.appId,\n accountLogin: app.installationAccountLogin,\n });\n }\n // Add the app credentials with their errors as well so that user can deal with them\n else {\n credentials.push({\n type: 'app',\n error: app.error,\n appId: app.appId,\n });\n }\n }\n\n return credentials;\n }\n}\n\nexport class CustomGithubCredentialsProvider\n implements ExtendedGithubCredentialsProvider\n{\n static fromIntegrations(integrations: ScmIntegrationRegistry) {\n const credentialsProviders: Map<string, ExtendedGithubCredentialsProvider> =\n new Map<string, ExtendedGithubCredentialsProvider>();\n\n integrations.github.list().forEach(integration => {\n const credentialsProvider =\n CustomSingleInstanceGithubCredentialsProvider.create(\n integration.config,\n );\n credentialsProviders.set(integration.config.host, credentialsProvider);\n });\n return new CustomGithubCredentialsProvider(credentialsProviders);\n }\n\n private constructor(\n private readonly providers: Map<string, ExtendedGithubCredentialsProvider>,\n ) {}\n\n /**\n * Returns {@link GithubCredentials} for a given URL.\n *\n * @remarks\n *\n * Consecutive calls to this method with the same URL will return cached\n * credentials.\n *\n * The shortest lifetime for a token returned is 10 minutes.\n *\n * @example\n * ```ts\n * const { token, headers } = await getCredentials({\n * url: 'https://github.com/backstage/foobar'\n * })\n *\n * const { token, headers } = await getCredentials({\n * url: 'https://github.com/backstage'\n * })\n * ```\n *\n * @param opts - The organization or repository URL\n * @returns A promise of {@link GithubCredentials}.\n */\n async getCredentials(opts: { url: string }): Promise<GithubCredentials> {\n const parsed = new URL(opts.url);\n const provider = this.providers.get(parsed.host);\n\n if (!provider) {\n throw new Error(\n `There is no GitHub integration that matches ${opts.url}. Please add a configuration for an integration.`,\n );\n }\n\n return provider.getCredentials(opts);\n }\n\n async getAllCredentials(opts: {\n host: string;\n }): Promise<ExtendedGithubCredentials[]> {\n const provider = this.providers.get(opts.host);\n\n if (!provider) {\n throw new Error(\n `There is no GitHub integration that matches ${opts.host}. Please add a configuration for an integration.`,\n );\n }\n return provider.getAllCredentials(opts);\n }\n\n async getAllAppInstallations(config: GithubIntegrationConfig) {\n return new GithubAppsCredentialManager(config).getAllInstallations();\n }\n\n async getAppInstallationsForOrg(\n config: GithubIntegrationConfig,\n org: string,\n ) {\n const all = await this.getAllAppInstallations(config);\n return all.filter(install => install.account?.login === org);\n }\n}\n"],"names":["DateTime","Octokit","createAppAuth","credentials","gitUrlParse"],"mappings":"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"}