@backstage/backend-defaults 0.5.3-next.1 → 0.5.3-next.2
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 +21 -0
- package/auth/package.json +1 -1
- package/cache/package.json +1 -1
- package/database/package.json +1 -1
- package/discovery/package.json +1 -1
- package/dist/CreateBackend.cjs.js.map +1 -1
- package/dist/PackageDiscoveryService.cjs.js.map +1 -1
- package/dist/discoveryFeatureLoader.cjs.js.map +1 -1
- package/dist/entrypoints/auth/DefaultAuthService.cjs.js.map +1 -1
- package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -1
- package/dist/entrypoints/auth/authServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/ExternalTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/jwks.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/legacy.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/static.cjs.js.map +1 -1
- package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/DatabaseKeyStore.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/DatabasePluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/createPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheManager.cjs.js.map +1 -1
- package/dist/entrypoints/cache/cacheServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/cache/types.cjs.js.map +1 -1
- package/dist/entrypoints/database/DatabaseManager.cjs.js +1 -3
- package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/defaultNameOverride.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/defaultSchemaOverride.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/mergeDatabaseConfig.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/mysql.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -1
- package/dist/entrypoints/database/databaseServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/httpAuth/httpAuthServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/createAuthIntegrationRouter.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/createCredentialsBarrier.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/createLifecycleMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/lifecycle/lifecycleServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/logger/loggerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/permissions/permissionsServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootConfig/createConfigSecretEnumerator.cjs.js.map +1 -1
- package/dist/entrypoints/rootConfig/rootConfigServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHealth/rootHealthServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/DefaultRootHttpRouter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/createHealthRouter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/config.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/readCorsOptions.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLifecycle/rootLifecycleServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/database/migrateBackendTasks.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/database/tables.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/DefaultSchedulerService.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/LocalTaskWorker.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/TaskWorker.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/types.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/util.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/schedulerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AzureUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/UrlReaderPredicateMux.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/UrlReaders.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/urlReaderServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/userInfo/DefaultUserInfoService.cjs.js.map +1 -1
- package/dist/entrypoints/userInfo/userInfoServiceFactory.cjs.js.map +1 -1
- package/dist/lib/escapeRegExp.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +1 -1
- package/httpAuth/package.json +1 -1
- package/httpRouter/package.json +1 -1
- package/lifecycle/package.json +1 -1
- package/logger/package.json +1 -1
- package/package.json +9 -9
- package/permissions/package.json +1 -1
- package/rootConfig/package.json +1 -1
- package/rootHealth/package.json +1 -1
- package/rootHttpRouter/package.json +1 -1
- package/rootLifecycle/package.json +1 -1
- package/rootLogger/package.json +1 -1
- package/scheduler/package.json +1 -1
- package/urlReader/package.json +1 -1
- package/userInfo/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { CronTime } from 'cron';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\nimport { v4 as uuid } from 'uuid';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport { TaskSettingsV2, taskSettingsV2Schema } from './types';\nimport { delegateAbortController, nowPlus, sleep } from './util';\nimport { SchedulerServiceTaskFunction } from '@backstage/backend-plugin-api';\n\nconst DEFAULT_WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 });\n\n/**\n * Implements tasks that run across worker hosts, with collaborative locking.\n *\n * @private\n */\nexport class TaskWorker {\n constructor(\n private readonly taskId: string,\n private readonly fn: SchedulerServiceTaskFunction,\n private readonly knex: Knex,\n private readonly logger: LoggerService,\n private readonly workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY,\n ) {}\n\n async start(settings: TaskSettingsV2, options: { signal: AbortSignal }) {\n try {\n await this.persistTask(settings);\n } catch (e) {\n throw new Error(`Failed to persist task, ${e}`);\n }\n\n this.logger.info(\n `Task worker starting: ${this.taskId}, ${JSON.stringify(settings)}`,\n );\n\n let workCheckFrequency = this.workCheckFrequency;\n const isDuration = settings?.cadence.startsWith('P');\n if (isDuration) {\n const cadence = Duration.fromISO(settings.cadence);\n if (cadence < workCheckFrequency) {\n workCheckFrequency = cadence;\n }\n }\n\n let attemptNum = 1;\n (async () => {\n for (;;) {\n try {\n if (settings.initialDelayDuration) {\n await sleep(\n Duration.fromISO(settings.initialDelayDuration),\n options.signal,\n );\n }\n\n while (!options.signal.aborted) {\n const runResult = await this.runOnce(options.signal);\n\n if (runResult.result === 'abort') {\n break;\n }\n\n await sleep(workCheckFrequency, options.signal);\n }\n\n this.logger.info(`Task worker finished: ${this.taskId}`);\n attemptNum = 0;\n break;\n } catch (e) {\n attemptNum += 1;\n this.logger.warn(\n `Task worker failed unexpectedly, attempt number ${attemptNum}, ${e}`,\n );\n await sleep(Duration.fromObject({ seconds: 1 }));\n }\n }\n })();\n }\n\n static async trigger(knex: Knex, taskId: string): Promise<void> {\n // check if task exists\n const rows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .select(knex.raw(1))\n .where('id', '=', taskId);\n if (rows.length !== 1) {\n throw new NotFoundError(`Task ${taskId} does not exist`);\n }\n\n const updatedRows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .whereNull('current_run_ticket')\n .update({\n next_run_start_at: knex.fn.now(),\n });\n if (updatedRows < 1) {\n throw new ConflictError(`Task ${taskId} is currently running`);\n }\n }\n\n /**\n * Makes a single attempt at running the task to completion, if ready.\n *\n * @returns The outcome of the attempt\n */\n private async runOnce(\n signal: AbortSignal,\n ): Promise<\n | { result: 'not-ready-yet' }\n | { result: 'abort' }\n | { result: 'failed' }\n | { result: 'completed' }\n > {\n const findResult = await this.findReadyTask();\n if (\n findResult.result === 'not-ready-yet' ||\n findResult.result === 'abort'\n ) {\n return findResult;\n }\n\n const taskSettings = findResult.settings;\n const ticket = uuid();\n\n const claimed = await this.tryClaimTask(ticket, taskSettings);\n if (!claimed) {\n return { result: 'not-ready-yet' };\n }\n\n // Abort the task execution either if the worker is stopped, or if the\n // task timeout is hit\n const taskAbortController = delegateAbortController(signal);\n const timeoutHandle = setTimeout(() => {\n taskAbortController.abort();\n }, Duration.fromISO(taskSettings.timeoutAfterDuration).as('milliseconds'));\n\n try {\n await this.fn(taskAbortController.signal);\n taskAbortController.abort(); // releases resources\n } catch (e) {\n this.logger.error(e);\n await this.tryReleaseTask(ticket, taskSettings);\n return { result: 'failed' };\n } finally {\n clearTimeout(timeoutHandle);\n }\n\n await this.tryReleaseTask(ticket, taskSettings);\n return { result: 'completed' };\n }\n\n /**\n * Perform the initial store of the task info\n */\n async persistTask(settings: TaskSettingsV2) {\n // Perform an initial parse to ensure that we will definitely be able to\n // read it back again.\n taskSettingsV2Schema.parse(settings);\n\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n let startAt: Knex.Raw | undefined;\n let nextStartAt: Knex.Raw | undefined;\n if (settings.initialDelayDuration) {\n startAt = nowPlus(\n Duration.fromISO(settings.initialDelayDuration),\n this.knex,\n );\n }\n\n if (isCron) {\n const time = new CronTime(settings.cadence)\n .sendAt()\n .minus({ seconds: 1 }) // immediately, if \"* * * * * *\"\n .toUTC();\n\n nextStartAt = this.nextRunAtRaw(time);\n startAt ||= nextStartAt;\n } else if (isManual) {\n nextStartAt = this.knex.raw('null');\n startAt ||= nextStartAt;\n } else {\n startAt ||= this.knex.fn.now();\n nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex);\n }\n\n this.logger.debug(`task: ${this.taskId} configured to run at: ${startAt}`);\n\n // It's OK if the task already exists; if it does, just replace its\n // settings with the new value and start the loop as usual.\n const settingsJson = JSON.stringify(settings);\n await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .insert({\n id: this.taskId,\n settings_json: settingsJson,\n next_run_start_at: startAt,\n })\n .onConflict('id')\n .merge(\n this.knex.client.config.client.includes('mysql')\n ? {\n settings_json: settingsJson,\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`,\n [\n nextStartAt,\n 'next_run_start_at',\n nextStartAt,\n 'next_run_start_at',\n ],\n ),\n }\n : {\n settings_json: this.knex.ref('excluded.settings_json'),\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`,\n [\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n ],\n ),\n },\n );\n }\n\n /**\n * Check if the task is ready to run\n */\n async findReadyTask(): Promise<\n | { result: 'not-ready-yet' }\n | { result: 'abort' }\n | { result: 'ready'; settings: TaskSettingsV2 }\n > {\n const [row] = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .select({\n settingsJson: 'settings_json',\n ready: this.knex.raw(\n `CASE\n WHEN next_run_start_at <= ? AND current_run_ticket IS NULL THEN TRUE\n ELSE FALSE\n END`,\n [this.knex.fn.now()],\n ),\n });\n\n if (!row) {\n this.logger.info(\n 'No longer able to find task; aborting and assuming that it has been unregistered or expired',\n );\n return { result: 'abort' };\n } else if (!row.ready) {\n return { result: 'not-ready-yet' };\n }\n\n try {\n const obj = JSON.parse(row.settingsJson);\n const settings = taskSettingsV2Schema.parse(obj);\n return { result: 'ready', settings };\n } catch (e) {\n this.logger.info(\n `Task \"${this.taskId}\" is no longer able to parse task settings; aborting and assuming that a ` +\n `newer version of the task has been issued and being handled by other workers, ${e}`,\n );\n return { result: 'abort' };\n }\n }\n\n /**\n * Attempts to claim a task that's ready for execution, on this worker's\n * behalf. We should not attempt to perform the work unless the claim really\n * goes through.\n *\n * @param ticket - A globally unique string that changes for each invocation\n * @param settings - The settings of the task to claim\n * @returns True if it was successfully claimed\n */\n async tryClaimTask(\n ticket: string,\n settings: TaskSettingsV2,\n ): Promise<boolean> {\n const startedAt = this.knex.fn.now();\n const expiresAt = settings.timeoutAfterDuration\n ? nowPlus(Duration.fromISO(settings.timeoutAfterDuration), this.knex)\n : this.knex.raw('null');\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .whereNull('current_run_ticket')\n .update({\n current_run_ticket: ticket,\n current_run_started_at: startedAt,\n current_run_expires_at: expiresAt,\n });\n\n return rows === 1;\n }\n\n async tryReleaseTask(\n ticket: string,\n settings: TaskSettingsV2,\n ): Promise<boolean> {\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n let nextRun: Knex.Raw;\n if (isCron) {\n const time = new CronTime(settings.cadence).sendAt().toUTC();\n this.logger.debug(`task: ${this.taskId} will next occur around ${time}`);\n\n nextRun = this.nextRunAtRaw(time);\n } else if (isManual) {\n nextRun = this.knex.raw('null');\n } else {\n const dt = Duration.fromISO(settings.cadence).as('seconds');\n this.logger.debug(\n `task: ${this.taskId} will next occur around ${DateTime.now().plus({\n seconds: dt,\n })}`,\n );\n\n if (this.knex.client.config.client.includes('sqlite3')) {\n nextRun = this.knex.raw(\n `max(datetime(next_run_start_at, ?), datetime('now'))`,\n [`+${dt} seconds`],\n );\n } else if (this.knex.client.config.client.includes('mysql')) {\n nextRun = this.knex.raw(\n `greatest(next_run_start_at + interval ${dt} second, now())`,\n );\n } else {\n nextRun = this.knex.raw(\n `greatest(next_run_start_at + interval '${dt} seconds', now())`,\n );\n }\n }\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .where('current_run_ticket', '=', ticket)\n .update({\n next_run_start_at: nextRun,\n current_run_ticket: this.knex.raw('null'),\n current_run_started_at: this.knex.raw('null'),\n current_run_expires_at: this.knex.raw('null'),\n });\n\n return rows === 1;\n }\n\n private nextRunAtRaw(time: DateTime): Knex.Raw {\n if (this.knex.client.config.client.includes('sqlite3')) {\n return this.knex.raw('datetime(?)', [time.toISO()]);\n } else if (this.knex.client.config.client.includes('mysql')) {\n return this.knex.raw(`?`, [time.toSQL({ includeOffset: false })]);\n }\n return this.knex.raw(`?`, [time.toISO()]);\n }\n}\n"],"names":["Duration","sleep","DB_TASKS_TABLE","NotFoundError","ConflictError","uuid","delegateAbortController","taskSettingsV2Schema","nowPlus","CronTime","DateTime"],"mappings":";;;;;;;;;;AA2BA,MAAM,+BAA+BA,cAAS,CAAA,UAAA,CAAW,EAAE,OAAA,EAAS,GAAG,CAAA,CAAA;AAOhE,MAAM,UAAW,CAAA;AAAA,EACtB,YACmB,MACA,EAAA,EAAA,EACA,IACA,EAAA,MAAA,EACA,qBAA+B,4BAChD,EAAA;AALiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA,CAAA;AACA,IAAA,IAAA,CAAA,kBAAA,GAAA,kBAAA,CAAA;AAAA,GAChB;AAAA,EAEH,MAAM,KAAM,CAAA,QAAA,EAA0B,OAAkC,EAAA;AACtE,IAAI,IAAA;AACF,MAAM,MAAA,IAAA,CAAK,YAAY,QAAQ,CAAA,CAAA;AAAA,aACxB,CAAG,EAAA;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAA2B,wBAAA,EAAA,CAAC,CAAE,CAAA,CAAA,CAAA;AAAA,KAChD;AAEA,IAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,MACV,yBAAyB,IAAK,CAAA,MAAM,KAAK,IAAK,CAAA,SAAA,CAAU,QAAQ,CAAC,CAAA,CAAA;AAAA,KACnE,CAAA;AAEA,IAAA,IAAI,qBAAqB,IAAK,CAAA,kBAAA,CAAA;AAC9B,IAAA,MAAM,UAAa,GAAA,QAAA,EAAU,OAAQ,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AACnD,IAAA,IAAI,UAAY,EAAA;AACd,MAAA,MAAM,OAAU,GAAAA,cAAA,CAAS,OAAQ,CAAA,QAAA,CAAS,OAAO,CAAA,CAAA;AACjD,MAAA,IAAI,UAAU,kBAAoB,EAAA;AAChC,QAAqB,kBAAA,GAAA,OAAA,CAAA;AAAA,OACvB;AAAA,KACF;AAEA,IAAA,IAAI,UAAa,GAAA,CAAA,CAAA;AACjB,IAAA,CAAC,YAAY;AACX,MAAS,WAAA;AACP,QAAI,IAAA;AACF,UAAA,IAAI,SAAS,oBAAsB,EAAA;AACjC,YAAM,MAAAC,UAAA;AAAA,cACJD,cAAA,CAAS,OAAQ,CAAA,QAAA,CAAS,oBAAoB,CAAA;AAAA,cAC9C,OAAQ,CAAA,MAAA;AAAA,aACV,CAAA;AAAA,WACF;AAEA,UAAO,OAAA,CAAC,OAAQ,CAAA,MAAA,CAAO,OAAS,EAAA;AAC9B,YAAA,MAAM,SAAY,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA,CAAA;AAEnD,YAAI,IAAA,SAAA,CAAU,WAAW,OAAS,EAAA;AAChC,cAAA,MAAA;AAAA,aACF;AAEA,YAAM,MAAAC,UAAA,CAAM,kBAAoB,EAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AAAA,WAChD;AAEA,UAAA,IAAA,CAAK,MAAO,CAAA,IAAA,CAAK,CAAyB,sBAAA,EAAA,IAAA,CAAK,MAAM,CAAE,CAAA,CAAA,CAAA;AACvD,UAAa,UAAA,GAAA,CAAA,CAAA;AACb,UAAA,MAAA;AAAA,iBACO,CAAG,EAAA;AACV,UAAc,UAAA,IAAA,CAAA,CAAA;AACd,UAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,YACV,CAAA,gDAAA,EAAmD,UAAU,CAAA,EAAA,EAAK,CAAC,CAAA,CAAA;AAAA,WACrE,CAAA;AACA,UAAA,MAAMA,WAAMD,cAAS,CAAA,UAAA,CAAW,EAAE,OAAS,EAAA,CAAA,EAAG,CAAC,CAAA,CAAA;AAAA,SACjD;AAAA,OACF;AAAA,KACC,GAAA,CAAA;AAAA,GACL;AAAA,EAEA,aAAa,OAAQ,CAAA,IAAA,EAAY,MAA+B,EAAA;AAE9D,IAAA,MAAM,IAAO,GAAA,MAAM,IAAiB,CAAAE,qBAAc,EAC/C,MAAO,CAAA,IAAA,CAAK,GAAI,CAAA,CAAC,CAAC,CAAA,CAClB,KAAM,CAAA,IAAA,EAAM,KAAK,MAAM,CAAA,CAAA;AAC1B,IAAI,IAAA,IAAA,CAAK,WAAW,CAAG,EAAA;AACrB,MAAA,MAAM,IAAIC,oBAAA,CAAc,CAAQ,KAAA,EAAA,MAAM,CAAiB,eAAA,CAAA,CAAA,CAAA;AAAA,KACzD;AAEA,IAAA,MAAM,WAAc,GAAA,MAAM,IAAiB,CAAAD,qBAAc,CACtD,CAAA,KAAA,CAAM,IAAM,EAAA,GAAA,EAAK,MAAM,CAAA,CACvB,SAAU,CAAA,oBAAoB,EAC9B,MAAO,CAAA;AAAA,MACN,iBAAA,EAAmB,IAAK,CAAA,EAAA,CAAG,GAAI,EAAA;AAAA,KAChC,CAAA,CAAA;AACH,IAAA,IAAI,cAAc,CAAG,EAAA;AACnB,MAAA,MAAM,IAAIE,oBAAA,CAAc,CAAQ,KAAA,EAAA,MAAM,CAAuB,qBAAA,CAAA,CAAA,CAAA;AAAA,KAC/D;AAAA,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,QACZ,MAMA,EAAA;AACA,IAAM,MAAA,UAAA,GAAa,MAAM,IAAA,CAAK,aAAc,EAAA,CAAA;AAC5C,IAAA,IACE,UAAW,CAAA,MAAA,KAAW,eACtB,IAAA,UAAA,CAAW,WAAW,OACtB,EAAA;AACA,MAAO,OAAA,UAAA,CAAA;AAAA,KACT;AAEA,IAAA,MAAM,eAAe,UAAW,CAAA,QAAA,CAAA;AAChC,IAAA,MAAM,SAASC,OAAK,EAAA,CAAA;AAEpB,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,QAAQ,YAAY,CAAA,CAAA;AAC5D,IAAA,IAAI,CAAC,OAAS,EAAA;AACZ,MAAO,OAAA,EAAE,QAAQ,eAAgB,EAAA,CAAA;AAAA,KACnC;AAIA,IAAM,MAAA,mBAAA,GAAsBC,6BAAwB,MAAM,CAAA,CAAA;AAC1D,IAAM,MAAA,aAAA,GAAgB,WAAW,MAAM;AACrC,MAAA,mBAAA,CAAoB,KAAM,EAAA,CAAA;AAAA,KAC5B,EAAGN,eAAS,OAAQ,CAAA,YAAA,CAAa,oBAAoB,CAAE,CAAA,EAAA,CAAG,cAAc,CAAC,CAAA,CAAA;AAEzE,IAAI,IAAA;AACF,MAAM,MAAA,IAAA,CAAK,EAAG,CAAA,mBAAA,CAAoB,MAAM,CAAA,CAAA;AACxC,MAAA,mBAAA,CAAoB,KAAM,EAAA,CAAA;AAAA,aACnB,CAAG,EAAA;AACV,MAAK,IAAA,CAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AACnB,MAAM,MAAA,IAAA,CAAK,cAAe,CAAA,MAAA,EAAQ,YAAY,CAAA,CAAA;AAC9C,MAAO,OAAA,EAAE,QAAQ,QAAS,EAAA,CAAA;AAAA,KAC1B,SAAA;AACA,MAAA,YAAA,CAAa,aAAa,CAAA,CAAA;AAAA,KAC5B;AAEA,IAAM,MAAA,IAAA,CAAK,cAAe,CAAA,MAAA,EAAQ,YAAY,CAAA,CAAA;AAC9C,IAAO,OAAA,EAAE,QAAQ,WAAY,EAAA,CAAA;AAAA,GAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,QAA0B,EAAA;AAG1C,IAAAO,0BAAA,CAAqB,MAAM,QAAQ,CAAA,CAAA;AAEnC,IAAM,MAAA,QAAA,GAAW,UAAU,OAAY,KAAA,QAAA,CAAA;AACvC,IAAA,MAAM,UAAa,GAAA,QAAA,EAAU,OAAQ,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AACnD,IAAM,MAAA,MAAA,GAAS,CAAC,QAAA,IAAY,CAAC,UAAA,CAAA;AAE7B,IAAI,IAAA,OAAA,CAAA;AACJ,IAAI,IAAA,WAAA,CAAA;AACJ,IAAA,IAAI,SAAS,oBAAsB,EAAA;AACjC,MAAU,OAAA,GAAAC,YAAA;AAAA,QACRR,cAAA,CAAS,OAAQ,CAAA,QAAA,CAAS,oBAAoB,CAAA;AAAA,QAC9C,IAAK,CAAA,IAAA;AAAA,OACP,CAAA;AAAA,KACF;AAEA,IAAA,IAAI,MAAQ,EAAA;AACV,MAAA,MAAM,IAAO,GAAA,IAAIS,aAAS,CAAA,QAAA,CAAS,OAAO,CACvC,CAAA,MAAA,EACA,CAAA,KAAA,CAAM,EAAE,OAAA,EAAS,CAAE,EAAC,EACpB,KAAM,EAAA,CAAA;AAET,MAAc,WAAA,GAAA,IAAA,CAAK,aAAa,IAAI,CAAA,CAAA;AACpC,MAAY,OAAA,KAAA,WAAA,CAAA;AAAA,eACH,QAAU,EAAA;AACnB,MAAc,WAAA,GAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAClC,MAAY,OAAA,KAAA,WAAA,CAAA;AAAA,KACP,MAAA;AACL,MAAY,OAAA,KAAA,IAAA,CAAK,IAAK,CAAA,EAAA,CAAG,GAAI,EAAA,CAAA;AAC7B,MAAA,WAAA,GAAcD,aAAQR,cAAS,CAAA,OAAA,CAAQ,SAAS,OAAO,CAAA,EAAG,KAAK,IAAI,CAAA,CAAA;AAAA,KACrE;AAEA,IAAA,IAAA,CAAK,OAAO,KAAM,CAAA,CAAA,MAAA,EAAS,KAAK,MAAM,CAAA,uBAAA,EAA0B,OAAO,CAAE,CAAA,CAAA,CAAA;AAIzE,IAAM,MAAA,YAAA,GAAe,IAAK,CAAA,SAAA,CAAU,QAAQ,CAAA,CAAA;AAC5C,IAAA,MAAM,IAAK,CAAA,IAAA,CAAiBE,qBAAc,CAAA,CACvC,MAAO,CAAA;AAAA,MACN,IAAI,IAAK,CAAA,MAAA;AAAA,MACT,aAAe,EAAA,YAAA;AAAA,MACf,iBAAmB,EAAA,OAAA;AAAA,KACpB,CAAA,CACA,UAAW,CAAA,IAAI,CACf,CAAA,KAAA;AAAA,MACC,KAAK,IAAK,CAAA,MAAA,CAAO,OAAO,MAAO,CAAA,QAAA,CAAS,OAAO,CAC3C,GAAA;AAAA,QACE,aAAe,EAAA,YAAA;AAAA,QACf,iBAAA,EAAmB,KAAK,IAAK,CAAA,GAAA;AAAA,UAC3B,CAAA,qCAAA,CAAA;AAAA,UACA;AAAA,YACE,WAAA;AAAA,YACA,mBAAA;AAAA,YACA,WAAA;AAAA,YACA,mBAAA;AAAA,WACF;AAAA,SACF;AAAA,OAEF,GAAA;AAAA,QACE,aAAe,EAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,wBAAwB,CAAA;AAAA,QACrD,iBAAA,EAAmB,KAAK,IAAK,CAAA,GAAA;AAAA,UAC3B,CAAA,qCAAA,CAAA;AAAA,UACA;AAAA,YACE,WAAA;AAAA,YACA,GAAGA,qBAAc,CAAA,kBAAA,CAAA;AAAA,YACjB,WAAA;AAAA,YACA,GAAGA,qBAAc,CAAA,kBAAA,CAAA;AAAA,WACnB;AAAA,SACF;AAAA,OACF;AAAA,KACN,CAAA;AAAA,GACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAIJ,GAAA;AACA,IAAA,MAAM,CAAC,GAAG,CAAI,GAAA,MAAM,KAAK,IAAiB,CAAAA,qBAAc,CACrD,CAAA,KAAA,CAAM,IAAM,EAAA,GAAA,EAAK,IAAK,CAAA,MAAM,EAC5B,MAAO,CAAA;AAAA,MACN,YAAc,EAAA,eAAA;AAAA,MACd,KAAA,EAAO,KAAK,IAAK,CAAA,GAAA;AAAA,QACf,CAAA;AAAA;AAAA;AAAA,aAAA,CAAA;AAAA,QAIA,CAAC,IAAA,CAAK,IAAK,CAAA,EAAA,CAAG,KAAK,CAAA;AAAA,OACrB;AAAA,KACD,CAAA,CAAA;AAEH,IAAA,IAAI,CAAC,GAAK,EAAA;AACR,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,QACV,6FAAA;AAAA,OACF,CAAA;AACA,MAAO,OAAA,EAAE,QAAQ,OAAQ,EAAA,CAAA;AAAA,KAC3B,MAAA,IAAW,CAAC,GAAA,CAAI,KAAO,EAAA;AACrB,MAAO,OAAA,EAAE,QAAQ,eAAgB,EAAA,CAAA;AAAA,KACnC;AAEA,IAAI,IAAA;AACF,MAAA,MAAM,GAAM,GAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAI,YAAY,CAAA,CAAA;AACvC,MAAM,MAAA,QAAA,GAAWK,0BAAqB,CAAA,KAAA,CAAM,GAAG,CAAA,CAAA;AAC/C,MAAO,OAAA,EAAE,MAAQ,EAAA,OAAA,EAAS,QAAS,EAAA,CAAA;AAAA,aAC5B,CAAG,EAAA;AACV,MAAA,IAAA,CAAK,MAAO,CAAA,IAAA;AAAA,QACV,CAAS,MAAA,EAAA,IAAA,CAAK,MAAM,CAAA,uJAAA,EAC+D,CAAC,CAAA,CAAA;AAAA,OACtF,CAAA;AACA,MAAO,OAAA,EAAE,QAAQ,OAAQ,EAAA,CAAA;AAAA,KAC3B;AAAA,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,YACJ,CAAA,MAAA,EACA,QACkB,EAAA;AAClB,IAAA,MAAM,SAAY,GAAA,IAAA,CAAK,IAAK,CAAA,EAAA,CAAG,GAAI,EAAA,CAAA;AACnC,IAAA,MAAM,SAAY,GAAA,QAAA,CAAS,oBACvB,GAAAC,YAAA,CAAQR,eAAS,OAAQ,CAAA,QAAA,CAAS,oBAAoB,CAAA,EAAG,KAAK,IAAI,CAAA,GAClE,IAAK,CAAA,IAAA,CAAK,IAAI,MAAM,CAAA,CAAA;AAExB,IAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,IAAA,CAAiBE,qBAAc,CACpD,CAAA,KAAA,CAAM,IAAM,EAAA,GAAA,EAAK,KAAK,MAAM,CAAA,CAC5B,SAAU,CAAA,oBAAoB,EAC9B,MAAO,CAAA;AAAA,MACN,kBAAoB,EAAA,MAAA;AAAA,MACpB,sBAAwB,EAAA,SAAA;AAAA,MACxB,sBAAwB,EAAA,SAAA;AAAA,KACzB,CAAA,CAAA;AAEH,IAAA,OAAO,IAAS,KAAA,CAAA,CAAA;AAAA,GAClB;AAAA,EAEA,MAAM,cACJ,CAAA,MAAA,EACA,QACkB,EAAA;AAClB,IAAM,MAAA,QAAA,GAAW,UAAU,OAAY,KAAA,QAAA,CAAA;AACvC,IAAA,MAAM,UAAa,GAAA,QAAA,EAAU,OAAQ,CAAA,UAAA,CAAW,GAAG,CAAA,CAAA;AACnD,IAAM,MAAA,MAAA,GAAS,CAAC,QAAA,IAAY,CAAC,UAAA,CAAA;AAE7B,IAAI,IAAA,OAAA,CAAA;AACJ,IAAA,IAAI,MAAQ,EAAA;AACV,MAAM,MAAA,IAAA,GAAO,IAAIO,aAAS,CAAA,QAAA,CAAS,OAAO,CAAE,CAAA,MAAA,GAAS,KAAM,EAAA,CAAA;AAC3D,MAAA,IAAA,CAAK,OAAO,KAAM,CAAA,CAAA,MAAA,EAAS,KAAK,MAAM,CAAA,wBAAA,EAA2B,IAAI,CAAE,CAAA,CAAA,CAAA;AAEvE,MAAU,OAAA,GAAA,IAAA,CAAK,aAAa,IAAI,CAAA,CAAA;AAAA,eACvB,QAAU,EAAA;AACnB,MAAU,OAAA,GAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAAA,KACzB,MAAA;AACL,MAAA,MAAM,KAAKT,cAAS,CAAA,OAAA,CAAQ,SAAS,OAAO,CAAA,CAAE,GAAG,SAAS,CAAA,CAAA;AAC1D,MAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,QACV,SAAS,IAAK,CAAA,MAAM,2BAA2BU,cAAS,CAAA,GAAA,GAAM,IAAK,CAAA;AAAA,UACjE,OAAS,EAAA,EAAA;AAAA,SACV,CAAC,CAAA,CAAA;AAAA,OACJ,CAAA;AAEA,MAAA,IAAI,KAAK,IAAK,CAAA,MAAA,CAAO,OAAO,MAAO,CAAA,QAAA,CAAS,SAAS,CAAG,EAAA;AACtD,QAAA,OAAA,GAAU,KAAK,IAAK,CAAA,GAAA;AAAA,UAClB,CAAA,oDAAA,CAAA;AAAA,UACA,CAAC,CAAI,CAAA,EAAA,EAAE,CAAU,QAAA,CAAA,CAAA;AAAA,SACnB,CAAA;AAAA,OACF,MAAA,IAAW,KAAK,IAAK,CAAA,MAAA,CAAO,OAAO,MAAO,CAAA,QAAA,CAAS,OAAO,CAAG,EAAA;AAC3D,QAAA,OAAA,GAAU,KAAK,IAAK,CAAA,GAAA;AAAA,UAClB,yCAAyC,EAAE,CAAA,eAAA,CAAA;AAAA,SAC7C,CAAA;AAAA,OACK,MAAA;AACL,QAAA,OAAA,GAAU,KAAK,IAAK,CAAA,GAAA;AAAA,UAClB,0CAA0C,EAAE,CAAA,iBAAA,CAAA;AAAA,SAC9C,CAAA;AAAA,OACF;AAAA,KACF;AAEA,IAAA,MAAM,OAAO,MAAM,IAAA,CAAK,IAAiB,CAAAR,qBAAc,EACpD,KAAM,CAAA,IAAA,EAAM,GAAK,EAAA,IAAA,CAAK,MAAM,CAC5B,CAAA,KAAA,CAAM,sBAAsB,GAAK,EAAA,MAAM,EACvC,MAAO,CAAA;AAAA,MACN,iBAAmB,EAAA,OAAA;AAAA,MACnB,kBAAoB,EAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,MAAM,CAAA;AAAA,MACxC,sBAAwB,EAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,MAAM,CAAA;AAAA,MAC5C,sBAAwB,EAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAI,MAAM,CAAA;AAAA,KAC7C,CAAA,CAAA;AAEH,IAAA,OAAO,IAAS,KAAA,CAAA,CAAA;AAAA,GAClB;AAAA,EAEQ,aAAa,IAA0B,EAAA;AAC7C,IAAA,IAAI,KAAK,IAAK,CAAA,MAAA,CAAO,OAAO,MAAO,CAAA,QAAA,CAAS,SAAS,CAAG,EAAA;AACtD,MAAO,OAAA,IAAA,CAAK,KAAK,GAAI,CAAA,aAAA,EAAe,CAAC,IAAK,CAAA,KAAA,EAAO,CAAC,CAAA,CAAA;AAAA,KACpD,MAAA,IAAW,KAAK,IAAK,CAAA,MAAA,CAAO,OAAO,MAAO,CAAA,QAAA,CAAS,OAAO,CAAG,EAAA;AAC3D,MAAA,OAAO,IAAK,CAAA,IAAA,CAAK,GAAI,CAAA,CAAA,CAAA,CAAA,EAAK,CAAC,IAAA,CAAK,KAAM,CAAA,EAAE,aAAe,EAAA,KAAA,EAAO,CAAC,CAAC,CAAA,CAAA;AAAA,KAClE;AACA,IAAO,OAAA,IAAA,CAAK,KAAK,GAAI,CAAA,CAAA,CAAA,CAAA,EAAK,CAAC,IAAK,CAAA,KAAA,EAAO,CAAC,CAAA,CAAA;AAAA,GAC1C;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { CronTime } from 'cron';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\nimport { v4 as uuid } from 'uuid';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport { TaskSettingsV2, taskSettingsV2Schema } from './types';\nimport { delegateAbortController, nowPlus, sleep } from './util';\nimport { SchedulerServiceTaskFunction } from '@backstage/backend-plugin-api';\n\nconst DEFAULT_WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 });\n\n/**\n * Implements tasks that run across worker hosts, with collaborative locking.\n *\n * @private\n */\nexport class TaskWorker {\n constructor(\n private readonly taskId: string,\n private readonly fn: SchedulerServiceTaskFunction,\n private readonly knex: Knex,\n private readonly logger: LoggerService,\n private readonly workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY,\n ) {}\n\n async start(settings: TaskSettingsV2, options: { signal: AbortSignal }) {\n try {\n await this.persistTask(settings);\n } catch (e) {\n throw new Error(`Failed to persist task, ${e}`);\n }\n\n this.logger.info(\n `Task worker starting: ${this.taskId}, ${JSON.stringify(settings)}`,\n );\n\n let workCheckFrequency = this.workCheckFrequency;\n const isDuration = settings?.cadence.startsWith('P');\n if (isDuration) {\n const cadence = Duration.fromISO(settings.cadence);\n if (cadence < workCheckFrequency) {\n workCheckFrequency = cadence;\n }\n }\n\n let attemptNum = 1;\n (async () => {\n for (;;) {\n try {\n if (settings.initialDelayDuration) {\n await sleep(\n Duration.fromISO(settings.initialDelayDuration),\n options.signal,\n );\n }\n\n while (!options.signal.aborted) {\n const runResult = await this.runOnce(options.signal);\n\n if (runResult.result === 'abort') {\n break;\n }\n\n await sleep(workCheckFrequency, options.signal);\n }\n\n this.logger.info(`Task worker finished: ${this.taskId}`);\n attemptNum = 0;\n break;\n } catch (e) {\n attemptNum += 1;\n this.logger.warn(\n `Task worker failed unexpectedly, attempt number ${attemptNum}, ${e}`,\n );\n await sleep(Duration.fromObject({ seconds: 1 }));\n }\n }\n })();\n }\n\n static async trigger(knex: Knex, taskId: string): Promise<void> {\n // check if task exists\n const rows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .select(knex.raw(1))\n .where('id', '=', taskId);\n if (rows.length !== 1) {\n throw new NotFoundError(`Task ${taskId} does not exist`);\n }\n\n const updatedRows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .whereNull('current_run_ticket')\n .update({\n next_run_start_at: knex.fn.now(),\n });\n if (updatedRows < 1) {\n throw new ConflictError(`Task ${taskId} is currently running`);\n }\n }\n\n /**\n * Makes a single attempt at running the task to completion, if ready.\n *\n * @returns The outcome of the attempt\n */\n private async runOnce(\n signal: AbortSignal,\n ): Promise<\n | { result: 'not-ready-yet' }\n | { result: 'abort' }\n | { result: 'failed' }\n | { result: 'completed' }\n > {\n const findResult = await this.findReadyTask();\n if (\n findResult.result === 'not-ready-yet' ||\n findResult.result === 'abort'\n ) {\n return findResult;\n }\n\n const taskSettings = findResult.settings;\n const ticket = uuid();\n\n const claimed = await this.tryClaimTask(ticket, taskSettings);\n if (!claimed) {\n return { result: 'not-ready-yet' };\n }\n\n // Abort the task execution either if the worker is stopped, or if the\n // task timeout is hit\n const taskAbortController = delegateAbortController(signal);\n const timeoutHandle = setTimeout(() => {\n taskAbortController.abort();\n }, Duration.fromISO(taskSettings.timeoutAfterDuration).as('milliseconds'));\n\n try {\n await this.fn(taskAbortController.signal);\n taskAbortController.abort(); // releases resources\n } catch (e) {\n this.logger.error(e);\n await this.tryReleaseTask(ticket, taskSettings);\n return { result: 'failed' };\n } finally {\n clearTimeout(timeoutHandle);\n }\n\n await this.tryReleaseTask(ticket, taskSettings);\n return { result: 'completed' };\n }\n\n /**\n * Perform the initial store of the task info\n */\n async persistTask(settings: TaskSettingsV2) {\n // Perform an initial parse to ensure that we will definitely be able to\n // read it back again.\n taskSettingsV2Schema.parse(settings);\n\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n let startAt: Knex.Raw | undefined;\n let nextStartAt: Knex.Raw | undefined;\n if (settings.initialDelayDuration) {\n startAt = nowPlus(\n Duration.fromISO(settings.initialDelayDuration),\n this.knex,\n );\n }\n\n if (isCron) {\n const time = new CronTime(settings.cadence)\n .sendAt()\n .minus({ seconds: 1 }) // immediately, if \"* * * * * *\"\n .toUTC();\n\n nextStartAt = this.nextRunAtRaw(time);\n startAt ||= nextStartAt;\n } else if (isManual) {\n nextStartAt = this.knex.raw('null');\n startAt ||= nextStartAt;\n } else {\n startAt ||= this.knex.fn.now();\n nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex);\n }\n\n this.logger.debug(`task: ${this.taskId} configured to run at: ${startAt}`);\n\n // It's OK if the task already exists; if it does, just replace its\n // settings with the new value and start the loop as usual.\n const settingsJson = JSON.stringify(settings);\n await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .insert({\n id: this.taskId,\n settings_json: settingsJson,\n next_run_start_at: startAt,\n })\n .onConflict('id')\n .merge(\n this.knex.client.config.client.includes('mysql')\n ? {\n settings_json: settingsJson,\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`,\n [\n nextStartAt,\n 'next_run_start_at',\n nextStartAt,\n 'next_run_start_at',\n ],\n ),\n }\n : {\n settings_json: this.knex.ref('excluded.settings_json'),\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? < ?? THEN ?? ELSE ?? END`,\n [\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n ],\n ),\n },\n );\n }\n\n /**\n * Check if the task is ready to run\n */\n async findReadyTask(): Promise<\n | { result: 'not-ready-yet' }\n | { result: 'abort' }\n | { result: 'ready'; settings: TaskSettingsV2 }\n > {\n const [row] = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .select({\n settingsJson: 'settings_json',\n ready: this.knex.raw(\n `CASE\n WHEN next_run_start_at <= ? AND current_run_ticket IS NULL THEN TRUE\n ELSE FALSE\n END`,\n [this.knex.fn.now()],\n ),\n });\n\n if (!row) {\n this.logger.info(\n 'No longer able to find task; aborting and assuming that it has been unregistered or expired',\n );\n return { result: 'abort' };\n } else if (!row.ready) {\n return { result: 'not-ready-yet' };\n }\n\n try {\n const obj = JSON.parse(row.settingsJson);\n const settings = taskSettingsV2Schema.parse(obj);\n return { result: 'ready', settings };\n } catch (e) {\n this.logger.info(\n `Task \"${this.taskId}\" is no longer able to parse task settings; aborting and assuming that a ` +\n `newer version of the task has been issued and being handled by other workers, ${e}`,\n );\n return { result: 'abort' };\n }\n }\n\n /**\n * Attempts to claim a task that's ready for execution, on this worker's\n * behalf. We should not attempt to perform the work unless the claim really\n * goes through.\n *\n * @param ticket - A globally unique string that changes for each invocation\n * @param settings - The settings of the task to claim\n * @returns True if it was successfully claimed\n */\n async tryClaimTask(\n ticket: string,\n settings: TaskSettingsV2,\n ): Promise<boolean> {\n const startedAt = this.knex.fn.now();\n const expiresAt = settings.timeoutAfterDuration\n ? nowPlus(Duration.fromISO(settings.timeoutAfterDuration), this.knex)\n : this.knex.raw('null');\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .whereNull('current_run_ticket')\n .update({\n current_run_ticket: ticket,\n current_run_started_at: startedAt,\n current_run_expires_at: expiresAt,\n });\n\n return rows === 1;\n }\n\n async tryReleaseTask(\n ticket: string,\n settings: TaskSettingsV2,\n ): Promise<boolean> {\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n let nextRun: Knex.Raw;\n if (isCron) {\n const time = new CronTime(settings.cadence).sendAt().toUTC();\n this.logger.debug(`task: ${this.taskId} will next occur around ${time}`);\n\n nextRun = this.nextRunAtRaw(time);\n } else if (isManual) {\n nextRun = this.knex.raw('null');\n } else {\n const dt = Duration.fromISO(settings.cadence).as('seconds');\n this.logger.debug(\n `task: ${this.taskId} will next occur around ${DateTime.now().plus({\n seconds: dt,\n })}`,\n );\n\n if (this.knex.client.config.client.includes('sqlite3')) {\n nextRun = this.knex.raw(\n `max(datetime(next_run_start_at, ?), datetime('now'))`,\n [`+${dt} seconds`],\n );\n } else if (this.knex.client.config.client.includes('mysql')) {\n nextRun = this.knex.raw(\n `greatest(next_run_start_at + interval ${dt} second, now())`,\n );\n } else {\n nextRun = this.knex.raw(\n `greatest(next_run_start_at + interval '${dt} seconds', now())`,\n );\n }\n }\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .where('current_run_ticket', '=', ticket)\n .update({\n next_run_start_at: nextRun,\n current_run_ticket: this.knex.raw('null'),\n current_run_started_at: this.knex.raw('null'),\n current_run_expires_at: this.knex.raw('null'),\n });\n\n return rows === 1;\n }\n\n private nextRunAtRaw(time: DateTime): Knex.Raw {\n if (this.knex.client.config.client.includes('sqlite3')) {\n return this.knex.raw('datetime(?)', [time.toISO()]);\n } else if (this.knex.client.config.client.includes('mysql')) {\n return this.knex.raw(`?`, [time.toSQL({ includeOffset: false })]);\n }\n return this.knex.raw(`?`, [time.toISO()]);\n }\n}\n"],"names":["Duration","sleep","DB_TASKS_TABLE","NotFoundError","ConflictError","uuid","delegateAbortController","taskSettingsV2Schema","nowPlus","CronTime","DateTime"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/types.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CronTime } from 'cron';\nimport { Duration } from 'luxon';\nimport { z } from 'zod';\n\nfunction isValidOptionalDurationString(d: string | undefined): boolean {\n try {\n return !d || Duration.fromISO(d).isValid;\n } catch {\n return false;\n }\n}\n\nfunction isValidCronFormat(c: string | undefined): boolean {\n try {\n if (!c) {\n return false;\n }\n // parse cron format to ensure it's a valid format.\n // eslint-disable-next-line no-new\n new CronTime(c);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidTrigger(t: string): boolean {\n return t === 'manual';\n}\n\nexport const taskSettingsV1Schema = z.object({\n version: z.literal(1),\n initialDelayDuration: z\n .string()\n .optional()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n recurringAtMostEveryDuration: z\n .string()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n});\n\n/**\n * The properties that control a scheduled task (version 1).\n */\nexport type TaskSettingsV1 = z.infer<typeof taskSettingsV1Schema>;\n\nexport const taskSettingsV2Schema = z.object({\n version: z.literal(2),\n cadence: z\n .string()\n .refine(isValidCronFormat, { message: 'Invalid cron' })\n .or(\n z.string().refine(isValidTrigger, {\n message: \"Invalid trigger, expecting 'manual'\",\n }),\n )\n .or(\n z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n ),\n timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n initialDelayDuration: z\n .string()\n .optional()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n});\n\n/**\n * The properties that control a scheduled task (version 2).\n */\nexport type TaskSettingsV2 = z.infer<typeof taskSettingsV2Schema>;\n"],"names":["Duration","CronTime","z"],"mappings":";;;;;;AAoBA,SAAS,8BAA8B,CAAgC,EAAA;AACrE,EAAI,IAAA;AACF,IAAA,OAAO,CAAC,CAAA,IAAKA,cAAS,CAAA,OAAA,CAAQ,CAAC,CAAE,CAAA,OAAA
|
|
1
|
+
{"version":3,"file":"types.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/types.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CronTime } from 'cron';\nimport { Duration } from 'luxon';\nimport { z } from 'zod';\n\nfunction isValidOptionalDurationString(d: string | undefined): boolean {\n try {\n return !d || Duration.fromISO(d).isValid;\n } catch {\n return false;\n }\n}\n\nfunction isValidCronFormat(c: string | undefined): boolean {\n try {\n if (!c) {\n return false;\n }\n // parse cron format to ensure it's a valid format.\n // eslint-disable-next-line no-new\n new CronTime(c);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidTrigger(t: string): boolean {\n return t === 'manual';\n}\n\nexport const taskSettingsV1Schema = z.object({\n version: z.literal(1),\n initialDelayDuration: z\n .string()\n .optional()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n recurringAtMostEveryDuration: z\n .string()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n});\n\n/**\n * The properties that control a scheduled task (version 1).\n */\nexport type TaskSettingsV1 = z.infer<typeof taskSettingsV1Schema>;\n\nexport const taskSettingsV2Schema = z.object({\n version: z.literal(2),\n cadence: z\n .string()\n .refine(isValidCronFormat, { message: 'Invalid cron' })\n .or(\n z.string().refine(isValidTrigger, {\n message: \"Invalid trigger, expecting 'manual'\",\n }),\n )\n .or(\n z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n ),\n timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n initialDelayDuration: z\n .string()\n .optional()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n});\n\n/**\n * The properties that control a scheduled task (version 2).\n */\nexport type TaskSettingsV2 = z.infer<typeof taskSettingsV2Schema>;\n"],"names":["Duration","CronTime","z"],"mappings":";;;;;;AAoBA,SAAS,8BAA8B,CAAgC,EAAA;AACrE,EAAI,IAAA;AACF,IAAA,OAAO,CAAC,CAAA,IAAKA,cAAS,CAAA,OAAA,CAAQ,CAAC,CAAE,CAAA,OAAA;AAAA,GAC3B,CAAA,MAAA;AACN,IAAO,OAAA,KAAA;AAAA;AAEX;AAEA,SAAS,kBAAkB,CAAgC,EAAA;AACzD,EAAI,IAAA;AACF,IAAA,IAAI,CAAC,CAAG,EAAA;AACN,MAAO,OAAA,KAAA;AAAA;AAIT,IAAA,IAAIC,cAAS,CAAC,CAAA;AACd,IAAO,OAAA,IAAA;AAAA,GACD,CAAA,MAAA;AACN,IAAO,OAAA,KAAA;AAAA;AAEX;AAEA,SAAS,eAAe,CAAoB,EAAA;AAC1C,EAAA,OAAO,CAAM,KAAA,QAAA;AACf;AAEoCC,MAAE,MAAO,CAAA;AAAA,EAC3C,OAAA,EAASA,KAAE,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,EACpB,sBAAsBA,KACnB,CAAA,MAAA,GACA,QAAS,EAAA,CACT,OAAO,6BAA+B,EAAA;AAAA,IACrC,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACH,4BAA8B,EAAAA,KAAA,CAC3B,MAAO,EAAA,CACP,OAAO,6BAA+B,EAAA;AAAA,IACrC,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACH,oBAAsB,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,OAAO,6BAA+B,EAAA;AAAA,IACrE,OAAS,EAAA;AAAA,GACV;AACH,CAAC;AAOY,MAAA,oBAAA,GAAuBA,MAAE,MAAO,CAAA;AAAA,EAC3C,OAAA,EAASA,KAAE,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,EACpB,OAAA,EAASA,KACN,CAAA,MAAA,EACA,CAAA,MAAA,CAAO,mBAAmB,EAAE,OAAA,EAAS,cAAe,EAAC,CACrD,CAAA,EAAA;AAAA,IACCA,KAAE,CAAA,MAAA,EAAS,CAAA,MAAA,CAAO,cAAgB,EAAA;AAAA,MAChC,OAAS,EAAA;AAAA,KACV;AAAA,GAEF,CAAA,EAAA;AAAA,IACCA,KAAE,CAAA,MAAA,EAAS,CAAA,MAAA,CAAO,6BAA+B,EAAA;AAAA,MAC/C,OAAS,EAAA;AAAA,KACV;AAAA,GACH;AAAA,EACF,oBAAsB,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,OAAO,6BAA+B,EAAA;AAAA,IACrE,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,sBAAsBA,KACnB,CAAA,MAAA,GACA,QAAS,EAAA,CACT,OAAO,6BAA+B,EAAA;AAAA,IACrC,OAAS,EAAA;AAAA,GACV;AACL,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/util.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\n\nexport const TRACER_ID = 'backstage-service-scheduler';\n\n// Keep the IDs compatible with e.g. Prometheus labels\nexport function validateId(id: string) {\n if (typeof id !== 'string' || !id.trim()) {\n throw new InputError(`${id} is not a valid ID, expected non-empty string`);\n }\n}\n\nexport function dbTime(t: Date | string): DateTime {\n if (typeof t === 'string') {\n return DateTime.fromSQL(t);\n }\n return DateTime.fromJSDate(t);\n}\n\nexport function nowPlus(duration: Duration | undefined, knex: Knex) {\n const seconds = duration?.as('seconds') ?? 0;\n if (!seconds) {\n return knex.fn.now();\n }\n\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]);\n }\n\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`now() + interval ${seconds} second`);\n }\n\n return knex.raw(`now() + interval '${seconds} seconds'`);\n}\n\n/**\n * Sleep for the given duration, but return sooner if the abort signal\n * triggers.\n *\n * @param duration - The amount of time to sleep, at most\n * @param abortSignal - An optional abort signal that short circuits the wait\n */\nexport async function sleep(\n duration: Duration,\n abortSignal?: AbortSignal,\n): Promise<void> {\n if (abortSignal?.aborted) {\n return;\n }\n\n await new Promise<void>(resolve => {\n let timeoutHandle: NodeJS.Timeout | undefined = undefined;\n\n const done = () => {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n abortSignal?.removeEventListener('abort', done);\n resolve();\n };\n\n timeoutHandle = setTimeout(done, duration.as('milliseconds'));\n abortSignal?.addEventListener('abort', done);\n });\n}\n\n/**\n * Creates a new AbortController that, in addition to working as a regular\n * standalone controller, also gets aborted if the given parent signal\n * reaches aborted state.\n *\n * @param parent - The \"parent\" signal that can trigger the delegate\n */\nexport function delegateAbortController(parent?: AbortSignal): AbortController {\n const delegate = new AbortController();\n\n if (parent) {\n if (parent.aborted) {\n delegate.abort();\n } else {\n const onParentAborted = () => {\n delegate.abort();\n };\n\n const onChildAborted = () => {\n parent.removeEventListener('abort', onParentAborted);\n };\n\n parent.addEventListener('abort', onParentAborted, { once: true });\n delegate.signal.addEventListener('abort', onChildAborted, { once: true });\n }\n }\n\n return delegate;\n}\n"],"names":["InputError"],"mappings":";;;;;AAoBO,MAAM,SAAY,GAAA
|
|
1
|
+
{"version":3,"file":"util.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/util.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\n\nexport const TRACER_ID = 'backstage-service-scheduler';\n\n// Keep the IDs compatible with e.g. Prometheus labels\nexport function validateId(id: string) {\n if (typeof id !== 'string' || !id.trim()) {\n throw new InputError(`${id} is not a valid ID, expected non-empty string`);\n }\n}\n\nexport function dbTime(t: Date | string): DateTime {\n if (typeof t === 'string') {\n return DateTime.fromSQL(t);\n }\n return DateTime.fromJSDate(t);\n}\n\nexport function nowPlus(duration: Duration | undefined, knex: Knex) {\n const seconds = duration?.as('seconds') ?? 0;\n if (!seconds) {\n return knex.fn.now();\n }\n\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]);\n }\n\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`now() + interval ${seconds} second`);\n }\n\n return knex.raw(`now() + interval '${seconds} seconds'`);\n}\n\n/**\n * Sleep for the given duration, but return sooner if the abort signal\n * triggers.\n *\n * @param duration - The amount of time to sleep, at most\n * @param abortSignal - An optional abort signal that short circuits the wait\n */\nexport async function sleep(\n duration: Duration,\n abortSignal?: AbortSignal,\n): Promise<void> {\n if (abortSignal?.aborted) {\n return;\n }\n\n await new Promise<void>(resolve => {\n let timeoutHandle: NodeJS.Timeout | undefined = undefined;\n\n const done = () => {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n abortSignal?.removeEventListener('abort', done);\n resolve();\n };\n\n timeoutHandle = setTimeout(done, duration.as('milliseconds'));\n abortSignal?.addEventListener('abort', done);\n });\n}\n\n/**\n * Creates a new AbortController that, in addition to working as a regular\n * standalone controller, also gets aborted if the given parent signal\n * reaches aborted state.\n *\n * @param parent - The \"parent\" signal that can trigger the delegate\n */\nexport function delegateAbortController(parent?: AbortSignal): AbortController {\n const delegate = new AbortController();\n\n if (parent) {\n if (parent.aborted) {\n delegate.abort();\n } else {\n const onParentAborted = () => {\n delegate.abort();\n };\n\n const onChildAborted = () => {\n parent.removeEventListener('abort', onParentAborted);\n };\n\n parent.addEventListener('abort', onParentAborted, { once: true });\n delegate.signal.addEventListener('abort', onChildAborted, { once: true });\n }\n }\n\n return delegate;\n}\n"],"names":["InputError"],"mappings":";;;;;AAoBO,MAAM,SAAY,GAAA;AAGlB,SAAS,WAAW,EAAY,EAAA;AACrC,EAAA,IAAI,OAAO,EAAO,KAAA,QAAA,IAAY,CAAC,EAAA,CAAG,MAAQ,EAAA;AACxC,IAAA,MAAM,IAAIA,iBAAA,CAAW,CAAG,EAAA,EAAE,CAA+C,6CAAA,CAAA,CAAA;AAAA;AAE7E;AASgB,SAAA,OAAA,CAAQ,UAAgC,IAAY,EAAA;AAClE,EAAA,MAAM,OAAU,GAAA,QAAA,EAAU,EAAG,CAAA,SAAS,CAAK,IAAA,CAAA;AAC3C,EAAA,IAAI,CAAC,OAAS,EAAA;AACZ,IAAO,OAAA,IAAA,CAAK,GAAG,GAAI,EAAA;AAAA;AAGrB,EAAA,IAAI,KAAK,MAAO,CAAA,MAAA,CAAO,MAAO,CAAA,QAAA,CAAS,SAAS,CAAG,EAAA;AACjD,IAAA,OAAO,KAAK,GAAI,CAAA,CAAA,kBAAA,CAAA,EAAsB,CAAC,CAAG,EAAA,OAAO,UAAU,CAAC,CAAA;AAAA;AAG9D,EAAA,IAAI,KAAK,MAAO,CAAA,MAAA,CAAO,MAAO,CAAA,QAAA,CAAS,OAAO,CAAG,EAAA;AAC/C,IAAA,OAAO,IAAK,CAAA,GAAA,CAAI,CAAoB,iBAAA,EAAA,OAAO,CAAS,OAAA,CAAA,CAAA;AAAA;AAGtD,EAAA,OAAO,IAAK,CAAA,GAAA,CAAI,CAAqB,kBAAA,EAAA,OAAO,CAAW,SAAA,CAAA,CAAA;AACzD;AASsB,eAAA,KAAA,CACpB,UACA,WACe,EAAA;AACf,EAAA,IAAI,aAAa,OAAS,EAAA;AACxB,IAAA;AAAA;AAGF,EAAM,MAAA,IAAI,QAAc,CAAW,OAAA,KAAA;AACjC,IAAA,IAAI,aAA4C,GAAA,KAAA,CAAA;AAEhD,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,IAAI,aAAe,EAAA;AACjB,QAAA,YAAA,CAAa,aAAa,CAAA;AAAA;AAE5B,MAAa,WAAA,EAAA,mBAAA,CAAoB,SAAS,IAAI,CAAA;AAC9C,MAAQ,OAAA,EAAA;AAAA,KACV;AAEA,IAAA,aAAA,GAAgB,UAAW,CAAA,IAAA,EAAM,QAAS,CAAA,EAAA,CAAG,cAAc,CAAC,CAAA;AAC5D,IAAa,WAAA,EAAA,gBAAA,CAAiB,SAAS,IAAI,CAAA;AAAA,GAC5C,CAAA;AACH;AASO,SAAS,wBAAwB,MAAuC,EAAA;AAC7E,EAAM,MAAA,QAAA,GAAW,IAAI,eAAgB,EAAA;AAErC,EAAA,IAAI,MAAQ,EAAA;AACV,IAAA,IAAI,OAAO,OAAS,EAAA;AAClB,MAAA,QAAA,CAAS,KAAM,EAAA;AAAA,KACV,MAAA;AACL,MAAA,MAAM,kBAAkB,MAAM;AAC5B,QAAA,QAAA,CAAS,KAAM,EAAA;AAAA,OACjB;AAEA,MAAA,MAAM,iBAAiB,MAAM;AAC3B,QAAO,MAAA,CAAA,mBAAA,CAAoB,SAAS,eAAe,CAAA;AAAA,OACrD;AAEA,MAAA,MAAA,CAAO,iBAAiB,OAAS,EAAA,eAAA,EAAiB,EAAE,IAAA,EAAM,MAAM,CAAA;AAChE,MAAA,QAAA,CAAS,OAAO,gBAAiB,CAAA,OAAA,EAAS,gBAAgB,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA;AAC1E;AAGF,EAAO,OAAA,QAAA;AACT;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedulerServiceFactory.cjs.js","sources":["../../../src/entrypoints/scheduler/schedulerServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultSchedulerService } from './lib/DefaultSchedulerService';\n\n/**\n * Scheduling of distributed background tasks.\n *\n * See {@link @backstage/code-plugin-api#SchedulerService}\n * and {@link https://backstage.io/docs/backend-system/core-services/scheduler | the service docs}\n * for more information.\n *\n * @public\n */\nexport const schedulerServiceFactory = createServiceFactory({\n service: coreServices.scheduler,\n deps: {\n database: coreServices.database,\n logger: coreServices.logger,\n rootLifecycle: coreServices.rootLifecycle,\n },\n async factory({ database, logger, rootLifecycle }) {\n return DefaultSchedulerService.create({ database, logger, rootLifecycle });\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultSchedulerService"],"mappings":";;;;;AA+BO,MAAM,0BAA0BA,qCAAqB,CAAA;AAAA,EAC1D,SAASC,6BAAa,CAAA,SAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,eAAeA,6BAAa,CAAA
|
|
1
|
+
{"version":3,"file":"schedulerServiceFactory.cjs.js","sources":["../../../src/entrypoints/scheduler/schedulerServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultSchedulerService } from './lib/DefaultSchedulerService';\n\n/**\n * Scheduling of distributed background tasks.\n *\n * See {@link @backstage/code-plugin-api#SchedulerService}\n * and {@link https://backstage.io/docs/backend-system/core-services/scheduler | the service docs}\n * for more information.\n *\n * @public\n */\nexport const schedulerServiceFactory = createServiceFactory({\n service: coreServices.scheduler,\n deps: {\n database: coreServices.database,\n logger: coreServices.logger,\n rootLifecycle: coreServices.rootLifecycle,\n },\n async factory({ database, logger, rootLifecycle }) {\n return DefaultSchedulerService.create({ database, logger, rootLifecycle });\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultSchedulerService"],"mappings":";;;;;AA+BO,MAAM,0BAA0BA,qCAAqB,CAAA;AAAA,EAC1D,SAASC,6BAAa,CAAA,SAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,eAAeA,6BAAa,CAAA;AAAA,GAC9B;AAAA,EACA,MAAM,OAAQ,CAAA,EAAE,QAAU,EAAA,MAAA,EAAQ,eAAiB,EAAA;AACjD,IAAA,OAAOC,gDAAwB,MAAO,CAAA,EAAE,QAAU,EAAA,MAAA,EAAQ,eAAe,CAAA;AAAA;AAE7E,CAAC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AwsCodeCommitUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsCodeCommitIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport {\n CodeCommitClient,\n GetFileCommand,\n GetFileCommandInput,\n GetFileCommandOutput,\n GetFolderCommand,\n} from '@aws-sdk/client-codecommit';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { Readable } from 'stream';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { relative } from 'path/posix';\nimport { AbortController } from '@aws-sdk/abort-controller';\n\nexport function parseUrl(\n url: string,\n requireGitPath: boolean = false,\n): {\n path: string;\n repositoryName: string;\n region: string;\n commitSpecifier?: string;\n} {\n const parsedUrl = new URL(url);\n\n if (parsedUrl.pathname.includes('/files/edit/')) {\n throw new Error(\n 'Please provide the view url to yaml file from CodeCommit, not the edit url',\n );\n }\n if (requireGitPath && !parsedUrl.pathname.includes('/browse/')) {\n throw new Error('Please provide full path to yaml file from CodeCommit');\n }\n\n const hostMatch = parsedUrl.host.match(\n /^([^\\.]+)\\.console\\.aws\\.amazon\\.com$/,\n );\n if (!hostMatch) {\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected host format): ${url}`,\n );\n }\n const [, region] = hostMatch;\n\n const pathMatch = parsedUrl.pathname.match(\n /^\\/codesuite\\/codecommit\\/repositories\\/([^\\/]+)\\/browse\\/((.*)\\/)?--\\/(.*)$/,\n );\n\n if (!pathMatch) {\n if (!requireGitPath) {\n const pathname = parsedUrl.pathname\n .split('/--/')[0]\n .replace('/codesuite/codecommit/repositories/', '');\n const [repositoryName, commitSpecifier] = pathname.split('/browse');\n\n return {\n region,\n repositoryName: repositoryName.replace(/^\\/|\\/$/g, ''),\n path: '/',\n commitSpecifier:\n commitSpecifier === ''\n ? undefined\n : commitSpecifier?.replace(/^\\/|\\/$/g, ''),\n };\n }\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected path format): ${url}`,\n );\n }\n const [, repositoryName, , commitSpecifier, path] = pathMatch;\n\n return {\n region,\n repositoryName,\n path,\n // the commitSpecifier is passed to AWS SDK which does not allow empty strings so replace empty string with undefined\n commitSpecifier: commitSpecifier === '' ? undefined : commitSpecifier,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS CodeCommit.\n *\n * @public\n */\nexport class AwsCodeCommitUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsCodeCommit.list().map(integration => {\n const reader = new AwsCodeCommitUrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return (\n url.host.endsWith(integration.config.host) &&\n url.pathname.startsWith('/codesuite/codecommit')\n );\n };\n\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly credsManager: AwsCredentialsManager,\n private readonly integration: AwsCodeCommitIntegration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsCodeCommitIntegration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n let explicitCredentials: AwsCredentialIdentityProvider;\n if (accessKeyId && secretAccessKey) {\n explicitCredentials = AwsCodeCommitUrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n } else {\n explicitCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n\n const roleArn = integration.config.roleArn;\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n private async buildCodeCommitClient(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsCodeCommitIntegration,\n ): Promise<CodeCommitClient> {\n const credentials = await AwsCodeCommitUrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const codeCommit = new CodeCommitClient({\n customUserAgent: 'backstage-aws-codecommit-url-reader',\n region: region,\n credentials: credentials,\n });\n return codeCommit;\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // etag and lastModifiedAfter are not supported by the CodeCommit API\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(\n url,\n true,\n );\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const input: GetFileCommandInput = {\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n filePath: path,\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetFileCommand(input);\n const response: GetFileCommandOutput = await codeCommitClient.send(\n getObjectCommand,\n {\n abortSignal: abortController.signal,\n },\n );\n\n if (options?.etag && options.etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n return ReadUrlResponseFactory.fromReadable(\n Readable.from([response?.fileContent] || []),\n {\n etag: response.commitId,\n },\n );\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from CodeCommit', e);\n }\n }\n\n async readTreePath(\n codeCommitClient: CodeCommitClient,\n abortSignal: any,\n path: string,\n repositoryName: string,\n commitSpecifier?: string,\n etag?: string,\n ): Promise<string[]> {\n const getFolderCommand = new GetFolderCommand({\n folderPath: path,\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFolderCommand, {\n abortSignal: abortSignal,\n });\n\n if (etag && etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n const output: string[] = [];\n if (response.files) {\n response.files.forEach(file => {\n if (file.absolutePath) {\n output.push(file.absolutePath);\n }\n });\n }\n if (!response.subFolders) {\n return output;\n }\n\n for (const subFolder of response.subFolders) {\n if (subFolder.absolutePath) {\n output.push(\n ...(await this.readTreePath(\n codeCommitClient,\n abortSignal,\n subFolder.absolutePath,\n repositoryName,\n commitSpecifier,\n etag,\n )),\n );\n }\n }\n return output;\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n // url: https://eu-west-1.console.aws.amazon.com/codesuite/codecommit/repositories/test-stijn-delete-techdocs/browse?region=eu-west-1\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(url);\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n\n const abortController = new AbortController();\n options?.signal?.addEventListener('abort', () => abortController.abort());\n\n const allFiles: string[] = await this.readTreePath(\n codeCommitClient,\n abortController.signal,\n path,\n repositoryName,\n commitSpecifier,\n options?.etag,\n );\n const responses = [];\n\n for (let i = 0; i < allFiles.length; i++) {\n const getFileCommand = new GetFileCommand({\n repositoryName: repositoryName,\n filePath: String(allFiles[i]),\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFileCommand);\n const objectData = await Readable.from([response?.fileContent] || []);\n\n responses.push({\n data: objectData,\n path: relative(\n path.startsWith('/') ? path : `/${path}`,\n allFiles[i].startsWith('/') ? allFiles[i] : `/${allFiles[i]}`,\n ),\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n throw new ForwardedError(\n 'Could not retrieve file tree from CodeCommit',\n e,\n );\n }\n }\n\n async search(): Promise<UrlReaderServiceSearchResponse> {\n throw new Error('AwsCodeCommitReader does not implement search');\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsCodeCommit{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["repositoryName","commitSpecifier","ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","CodeCommitClient","abortController","AbortController","GetFileCommand","NotModifiedError","ReadUrlResponseFactory","Readable","ForwardedError","GetFolderCommand","relative"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AwsCodeCommitUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsCodeCommitIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport {\n CodeCommitClient,\n GetFileCommand,\n GetFileCommandInput,\n GetFileCommandOutput,\n GetFolderCommand,\n} from '@aws-sdk/client-codecommit';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { Readable } from 'stream';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { relative } from 'path/posix';\nimport { AbortController } from '@aws-sdk/abort-controller';\n\nexport function parseUrl(\n url: string,\n requireGitPath: boolean = false,\n): {\n path: string;\n repositoryName: string;\n region: string;\n commitSpecifier?: string;\n} {\n const parsedUrl = new URL(url);\n\n if (parsedUrl.pathname.includes('/files/edit/')) {\n throw new Error(\n 'Please provide the view url to yaml file from CodeCommit, not the edit url',\n );\n }\n if (requireGitPath && !parsedUrl.pathname.includes('/browse/')) {\n throw new Error('Please provide full path to yaml file from CodeCommit');\n }\n\n const hostMatch = parsedUrl.host.match(\n /^([^\\.]+)\\.console\\.aws\\.amazon\\.com$/,\n );\n if (!hostMatch) {\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected host format): ${url}`,\n );\n }\n const [, region] = hostMatch;\n\n const pathMatch = parsedUrl.pathname.match(\n /^\\/codesuite\\/codecommit\\/repositories\\/([^\\/]+)\\/browse\\/((.*)\\/)?--\\/(.*)$/,\n );\n\n if (!pathMatch) {\n if (!requireGitPath) {\n const pathname = parsedUrl.pathname\n .split('/--/')[0]\n .replace('/codesuite/codecommit/repositories/', '');\n const [repositoryName, commitSpecifier] = pathname.split('/browse');\n\n return {\n region,\n repositoryName: repositoryName.replace(/^\\/|\\/$/g, ''),\n path: '/',\n commitSpecifier:\n commitSpecifier === ''\n ? undefined\n : commitSpecifier?.replace(/^\\/|\\/$/g, ''),\n };\n }\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected path format): ${url}`,\n );\n }\n const [, repositoryName, , commitSpecifier, path] = pathMatch;\n\n return {\n region,\n repositoryName,\n path,\n // the commitSpecifier is passed to AWS SDK which does not allow empty strings so replace empty string with undefined\n commitSpecifier: commitSpecifier === '' ? undefined : commitSpecifier,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS CodeCommit.\n *\n * @public\n */\nexport class AwsCodeCommitUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsCodeCommit.list().map(integration => {\n const reader = new AwsCodeCommitUrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return (\n url.host.endsWith(integration.config.host) &&\n url.pathname.startsWith('/codesuite/codecommit')\n );\n };\n\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly credsManager: AwsCredentialsManager,\n private readonly integration: AwsCodeCommitIntegration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsCodeCommitIntegration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n let explicitCredentials: AwsCredentialIdentityProvider;\n if (accessKeyId && secretAccessKey) {\n explicitCredentials = AwsCodeCommitUrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n } else {\n explicitCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n\n const roleArn = integration.config.roleArn;\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n private async buildCodeCommitClient(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsCodeCommitIntegration,\n ): Promise<CodeCommitClient> {\n const credentials = await AwsCodeCommitUrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const codeCommit = new CodeCommitClient({\n customUserAgent: 'backstage-aws-codecommit-url-reader',\n region: region,\n credentials: credentials,\n });\n return codeCommit;\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // etag and lastModifiedAfter are not supported by the CodeCommit API\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(\n url,\n true,\n );\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const input: GetFileCommandInput = {\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n filePath: path,\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetFileCommand(input);\n const response: GetFileCommandOutput = await codeCommitClient.send(\n getObjectCommand,\n {\n abortSignal: abortController.signal,\n },\n );\n\n if (options?.etag && options.etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n return ReadUrlResponseFactory.fromReadable(\n Readable.from([response?.fileContent] || []),\n {\n etag: response.commitId,\n },\n );\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from CodeCommit', e);\n }\n }\n\n async readTreePath(\n codeCommitClient: CodeCommitClient,\n abortSignal: any,\n path: string,\n repositoryName: string,\n commitSpecifier?: string,\n etag?: string,\n ): Promise<string[]> {\n const getFolderCommand = new GetFolderCommand({\n folderPath: path,\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFolderCommand, {\n abortSignal: abortSignal,\n });\n\n if (etag && etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n const output: string[] = [];\n if (response.files) {\n response.files.forEach(file => {\n if (file.absolutePath) {\n output.push(file.absolutePath);\n }\n });\n }\n if (!response.subFolders) {\n return output;\n }\n\n for (const subFolder of response.subFolders) {\n if (subFolder.absolutePath) {\n output.push(\n ...(await this.readTreePath(\n codeCommitClient,\n abortSignal,\n subFolder.absolutePath,\n repositoryName,\n commitSpecifier,\n etag,\n )),\n );\n }\n }\n return output;\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n // url: https://eu-west-1.console.aws.amazon.com/codesuite/codecommit/repositories/test-stijn-delete-techdocs/browse?region=eu-west-1\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(url);\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n\n const abortController = new AbortController();\n options?.signal?.addEventListener('abort', () => abortController.abort());\n\n const allFiles: string[] = await this.readTreePath(\n codeCommitClient,\n abortController.signal,\n path,\n repositoryName,\n commitSpecifier,\n options?.etag,\n );\n const responses = [];\n\n for (let i = 0; i < allFiles.length; i++) {\n const getFileCommand = new GetFileCommand({\n repositoryName: repositoryName,\n filePath: String(allFiles[i]),\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFileCommand);\n const objectData = await Readable.from([response?.fileContent] || []);\n\n responses.push({\n data: objectData,\n path: relative(\n path.startsWith('/') ? path : `/${path}`,\n allFiles[i].startsWith('/') ? allFiles[i] : `/${allFiles[i]}`,\n ),\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n throw new ForwardedError(\n 'Could not retrieve file tree from CodeCommit',\n e,\n );\n }\n }\n\n async search(): Promise<UrlReaderServiceSearchResponse> {\n throw new Error('AwsCodeCommitReader does not implement search');\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsCodeCommit{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["repositoryName","commitSpecifier","ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","CodeCommitClient","abortController","AbortController","GetFileCommand","NotModifiedError","ReadUrlResponseFactory","Readable","ForwardedError","GetFolderCommand","relative"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AwsS3UrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsS3UrlReader.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsS3Integration,\n ScmIntegrations,\n AwsS3IntegrationConfig,\n} from '@backstage/integration';\nimport { ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport {\n S3Client,\n ListObjectsV2Command,\n ListObjectsV2CommandOutput,\n GetObjectCommand,\n GetObjectCommandInput,\n} from '@aws-sdk/client-s3';\nimport { AbortController } from '@aws-sdk/abort-controller';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { Readable } from 'stream';\nimport { relative } from 'path/posix';\n\nexport const DEFAULT_REGION = 'us-east-1';\n\n/**\n * Path style URLs: https://s3.(region).amazonaws.com/(bucket)/(key)\n * The region can also be on the old form: https://s3-(region).amazonaws.com/(bucket)/(key)\n * Virtual hosted style URLs: https://(bucket).s3.(region).amazonaws.com/(key)\n * See https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access\n */\nexport function parseUrl(\n url: string,\n config: AwsS3IntegrationConfig,\n): { path: string; bucket: string; region: string } {\n const parsedUrl = new URL(url);\n\n /**\n * Removes the leading '/' from the pathname to be processed\n * as a parameter by AWS S3 SDK getObject method.\n */\n const pathname = parsedUrl.pathname.substring(1);\n const host = parsedUrl.host;\n\n // Treat Amazon hosted separately because it has special region logic\n if (config.host === 'amazonaws.com' || config.host === 'amazonaws.com.cn') {\n const match = host.match(\n /^(?:([a-z0-9.-]+)\\.)?s3(?:[.-]([a-z0-9-]+))?\\.amazonaws\\.com(\\.cn)?$/,\n );\n if (!match) {\n throw new Error(`Invalid AWS S3 URL ${url}`);\n }\n\n const [, hostBucket, hostRegion] = match;\n\n if (config.s3ForcePathStyle || !hostBucket) {\n const slashIndex = pathname.indexOf('/');\n if (slashIndex < 0) {\n throw new Error(\n `Invalid path-style AWS S3 URL ${url}, does not contain bucket in the path`,\n );\n }\n\n return {\n path: pathname.substring(slashIndex + 1),\n bucket: pathname.substring(0, slashIndex),\n region: hostRegion ?? DEFAULT_REGION,\n };\n }\n\n return {\n path: pathname,\n bucket: hostBucket,\n region: hostRegion ?? DEFAULT_REGION,\n };\n }\n\n const usePathStyle =\n config.s3ForcePathStyle || host.length === config.host.length;\n\n if (usePathStyle) {\n const slashIndex = pathname.indexOf('/');\n if (slashIndex < 0) {\n throw new Error(\n `Invalid path-style AWS S3 URL ${url}, does not contain bucket in the path`,\n );\n }\n\n return {\n path: pathname.substring(slashIndex + 1),\n bucket: pathname.substring(0, slashIndex),\n region: DEFAULT_REGION,\n };\n }\n\n return {\n path: pathname,\n bucket: host.substring(0, host.length - config.host.length - 1),\n region: DEFAULT_REGION,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS S3 buckets.\n *\n * @public\n */\nexport class AwsS3UrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsS3.list().map(integration => {\n const reader = new AwsS3UrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) =>\n url.host.endsWith(integration.config.host);\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly credsManager: AwsCredentialsManager,\n private readonly integration: AwsS3Integration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsS3Integration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n let explicitCredentials: AwsCredentialIdentityProvider;\n if (accessKeyId && secretAccessKey) {\n explicitCredentials = AwsS3UrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n } else {\n explicitCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n\n const roleArn = integration.config.roleArn;\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-s3-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n private async buildS3Client(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsS3Integration,\n ): Promise<S3Client> {\n const credentials = await AwsS3UrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const s3 = new S3Client({\n customUserAgent: 'backstage-aws-s3-url-reader',\n region: region,\n credentials: credentials,\n endpoint: integration.config.endpoint,\n forcePathStyle: integration.config.s3ForcePathStyle,\n });\n return s3;\n }\n\n private async retrieveS3ObjectData(stream: Readable): Promise<Readable> {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', (e: Error) =>\n reject(new ForwardedError('Unable to read stream', e)),\n );\n stream.on('end', () => resolve(Readable.from(Buffer.concat(chunks))));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n }\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const { etag, lastModifiedAfter } = options ?? {};\n\n try {\n const { path, bucket, region } = parseUrl(url, this.integration.config);\n const s3Client = await this.buildS3Client(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const params: GetObjectCommandInput = {\n Bucket: bucket,\n Key: path,\n ...(etag && { IfNoneMatch: etag }),\n ...(lastModifiedAfter && {\n IfModifiedSince: lastModifiedAfter,\n }),\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetObjectCommand(params);\n const response = await s3Client.send(getObjectCommand, {\n abortSignal: abortController.signal,\n });\n\n const s3ObjectData = await this.retrieveS3ObjectData(\n response.Body as Readable,\n );\n\n return ReadUrlResponseFactory.fromReadable(s3ObjectData, {\n etag: response.ETag,\n lastModifiedAt: response.LastModified,\n });\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from S3', e);\n }\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n try {\n const { path, bucket, region } = parseUrl(url, this.integration.config);\n const s3Client = await this.buildS3Client(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n const allObjects: String[] = [];\n const responses = [];\n let continuationToken: string | undefined;\n let output: ListObjectsV2CommandOutput;\n do {\n const listObjectsV2Command = new ListObjectsV2Command({\n Bucket: bucket,\n ContinuationToken: continuationToken,\n Prefix: path,\n });\n options?.signal?.addEventListener('abort', () =>\n abortController.abort(),\n );\n output = await s3Client.send(listObjectsV2Command, {\n abortSignal: abortController.signal,\n });\n if (output.Contents) {\n output.Contents.forEach(contents => {\n allObjects.push(contents.Key!);\n });\n }\n continuationToken = output.NextContinuationToken;\n } while (continuationToken);\n\n for (let i = 0; i < allObjects.length; i++) {\n const getObjectCommand = new GetObjectCommand({\n Bucket: bucket,\n Key: String(allObjects[i]),\n });\n const response = await s3Client.send(getObjectCommand);\n const s3ObjectData = await this.retrieveS3ObjectData(\n response.Body as Readable,\n );\n\n responses.push({\n data: s3ObjectData,\n path: relative(path, String(allObjects[i])),\n lastModifiedAt: response?.LastModified ?? undefined,\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n throw new ForwardedError('Could not retrieve file tree from S3', e);\n }\n }\n\n async search(): Promise<UrlReaderServiceSearchResponse> {\n throw new Error('AwsS3Reader does not implement search');\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsS3{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","S3Client","stream","ForwardedError","Readable","abortController","AbortController","GetObjectCommand","ReadUrlResponseFactory","NotModifiedError","ListObjectsV2Command","relative"],"mappings":";;;;;;;;;;;;AAiDO,MAAM,cAAiB,GAAA,YAAA;AAQd,SAAA,QAAA,CACd,KACA,MACkD,EAAA;AAClD,EAAM,MAAA,SAAA,GAAY,IAAI,GAAA,CAAI,GAAG,CAAA,CAAA;AAM7B,EAAA,MAAM,QAAW,GAAA,SAAA,CAAU,QAAS,CAAA,SAAA,CAAU,CAAC,CAAA,CAAA;AAC/C,EAAA,MAAM,OAAO,SAAU,CAAA,IAAA,CAAA;AAGvB,EAAA,IAAI,MAAO,CAAA,IAAA,KAAS,eAAmB,IAAA,MAAA,CAAO,SAAS,kBAAoB,EAAA;AACzE,IAAA,MAAM,QAAQ,IAAK,CAAA,KAAA;AAAA,MACjB,sEAAA;AAAA,KACF,CAAA;AACA,IAAA,IAAI,CAAC,KAAO,EAAA;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAsB,mBAAA,EAAA,GAAG,CAAE,CAAA,CAAA,CAAA;AAAA,KAC7C;AAEA,IAAA,MAAM,GAAG,UAAY,EAAA,UAAU,CAAI,GAAA,KAAA,CAAA;AAEnC,IAAI,IAAA,MAAA,CAAO,gBAAoB,IAAA,CAAC,UAAY,EAAA;AAC1C,MAAM,MAAA,UAAA,GAAa,QAAS,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AACvC,MAAA,IAAI,aAAa,CAAG,EAAA;AAClB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,iCAAiC,GAAG,CAAA,qCAAA,CAAA;AAAA,SACtC,CAAA;AAAA,OACF;AAEA,MAAO,OAAA;AAAA,QACL,IAAM,EAAA,QAAA,CAAS,SAAU,CAAA,UAAA,GAAa,CAAC,CAAA;AAAA,QACvC,MAAQ,EAAA,QAAA,CAAS,SAAU,CAAA,CAAA,EAAG,UAAU,CAAA;AAAA,QACxC,QAAQ,UAAc,IAAA,cAAA;AAAA,OACxB,CAAA;AAAA,KACF;AAEA,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,QAAA;AAAA,MACN,MAAQ,EAAA,UAAA;AAAA,MACR,QAAQ,UAAc,IAAA,cAAA;AAAA,KACxB,CAAA;AAAA,GACF;AAEA,EAAA,MAAM,eACJ,MAAO,CAAA,gBAAA,IAAoB,IAAK,CAAA,MAAA,KAAW,OAAO,IAAK,CAAA,MAAA,CAAA;AAEzD,EAAA,IAAI,YAAc,EAAA;AAChB,IAAM,MAAA,UAAA,GAAa,QAAS,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AACvC,IAAA,IAAI,aAAa,CAAG,EAAA;AAClB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,iCAAiC,GAAG,CAAA,qCAAA,CAAA;AAAA,OACtC,CAAA;AAAA,KACF;AAEA,IAAO,OAAA;AAAA,MACL,IAAM,EAAA,QAAA,CAAS,SAAU,CAAA,UAAA,GAAa,CAAC,CAAA;AAAA,MACvC,MAAQ,EAAA,QAAA,CAAS,SAAU,CAAA,CAAA,EAAG,UAAU,CAAA;AAAA,MACxC,MAAQ,EAAA,cAAA;AAAA,KACV,CAAA;AAAA,GACF;AAEA,EAAO,OAAA;AAAA,IACL,IAAM,EAAA,QAAA;AAAA,IACN,MAAA,EAAQ,KAAK,SAAU,CAAA,CAAA,EAAG,KAAK,MAAS,GAAA,MAAA,CAAO,IAAK,CAAA,MAAA,GAAS,CAAC,CAAA;AAAA,IAC9D,MAAQ,EAAA,cAAA;AAAA,GACV,CAAA;AACF,CAAA;AAOO,MAAM,cAA2C,CAAA;AAAA,EAetD,WAAA,CACmB,YACA,EAAA,WAAA,EACA,IAGjB,EAAA;AALiB,IAAA,IAAA,CAAA,YAAA,GAAA,YAAA,CAAA;AACA,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA,CAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA,CAAA;AAAA,GAGhB;AAAA,EApBH,OAAO,OAAyB,GAAA,CAAC,EAAE,MAAA,EAAQ,qBAA0B,KAAA;AACnE,IAAM,MAAA,YAAA,GAAeA,2BAAgB,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AACtD,IAAM,MAAA,YAAA,GAAeC,+CAA6B,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AAEnE,IAAA,OAAO,YAAa,CAAA,KAAA,CAAM,IAAK,EAAA,CAAE,IAAI,CAAe,WAAA,KAAA;AAClD,MAAA,MAAM,MAAS,GAAA,IAAI,cAAe,CAAA,YAAA,EAAc,WAAa,EAAA;AAAA,QAC3D,mBAAA;AAAA,OACD,CAAA,CAAA;AACD,MAAM,MAAA,SAAA,GAAY,CAAC,GACjB,KAAA,GAAA,CAAI,KAAK,QAAS,CAAA,WAAA,CAAY,OAAO,IAAI,CAAA,CAAA;AAC3C,MAAO,OAAA,EAAE,QAAQ,SAAU,EAAA,CAAA;AAAA,KAC5B,CAAA,CAAA;AAAA,GACH,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,OAAe,sBACb,CAAA,WAAA,EACA,eAC+B,EAAA;AAC/B,IAAA,OAAO,YAAY;AACjB,MAAO,OAAA;AAAA,QACL,WAAA;AAAA,QACA,eAAA;AAAA,OACF,CAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,aAAqB,gBAAA,CACnB,YACA,EAAA,MAAA,EACA,WACwC,EAAA;AAGxC,IAAA,IAAI,CAAC,WAAa,EAAA;AAChB,MAAQ,OAAA,CAAA,MAAM,YAAa,CAAA,qBAAA,EAAyB,EAAA,qBAAA,CAAA;AAAA,KACtD;AAEA,IAAM,MAAA,WAAA,GAAc,YAAY,MAAO,CAAA,WAAA,CAAA;AACvC,IAAM,MAAA,eAAA,GAAkB,YAAY,MAAO,CAAA,eAAA,CAAA;AAC3C,IAAI,IAAA,mBAAA,CAAA;AACJ,IAAA,IAAI,eAAe,eAAiB,EAAA;AAClC,MAAA,mBAAA,GAAsB,cAAe,CAAA,sBAAA;AAAA,QACnC,WAAA;AAAA,QACA,eAAA;AAAA,OACF,CAAA;AAAA,KACK,MAAA;AACL,MAAuB,mBAAA,GAAA,CAAA,MAAM,YAAa,CAAA,qBAAA,EACvC,EAAA,qBAAA,CAAA;AAAA,KACL;AAEA,IAAM,MAAA,OAAA,GAAU,YAAY,MAAO,CAAA,OAAA,CAAA;AACnC,IAAA,IAAI,OAAS,EAAA;AACX,MAAA,OAAOC,4CAAyB,CAAA;AAAA,QAC9B,iBAAmB,EAAA,mBAAA;AAAA,QACnB,MAAQ,EAAA;AAAA,UACN,eAAiB,EAAA,6BAAA;AAAA,UACjB,OAAS,EAAA,OAAA;AAAA,UACT,UAAA,EAAY,YAAY,MAAO,CAAA,UAAA;AAAA,SACjC;AAAA,QACA,YAAA,EAAc,EAAE,MAAO,EAAA;AAAA,OACxB,CAAA,CAAA;AAAA,KACH;AAEA,IAAO,OAAA,mBAAA,CAAA;AAAA,GACT;AAAA,EAEA,MAAc,aAAA,CACZ,YACA,EAAA,MAAA,EACA,WACmB,EAAA;AACnB,IAAM,MAAA,WAAA,GAAc,MAAM,cAAe,CAAA,gBAAA;AAAA,MACvC,YAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,KACF,CAAA;AAEA,IAAM,MAAA,EAAA,GAAK,IAAIC,iBAAS,CAAA;AAAA,MACtB,eAAiB,EAAA,6BAAA;AAAA,MACjB,MAAA;AAAA,MACA,WAAA;AAAA,MACA,QAAA,EAAU,YAAY,MAAO,CAAA,QAAA;AAAA,MAC7B,cAAA,EAAgB,YAAY,MAAO,CAAA,gBAAA;AAAA,KACpC,CAAA,CAAA;AACD,IAAO,OAAA,EAAA,CAAA;AAAA,GACT;AAAA,EAEA,MAAc,qBAAqBC,QAAqC,EAAA;AACtE,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAW,KAAA;AACtC,MAAI,IAAA;AACF,QAAA,MAAM,SAAgB,EAAC,CAAA;AACvB,QAAAA,QAAA,CAAO,GAAG,MAAQ,EAAA,CAAA,KAAA,KAAS,MAAO,CAAA,IAAA,CAAK,KAAK,CAAC,CAAA,CAAA;AAC7C,QAAOA,QAAA,CAAA,EAAA;AAAA,UAAG,OAAA;AAAA,UAAS,CAAC,CAClB,KAAA,MAAA,CAAO,IAAIC,qBAAe,CAAA,uBAAA,EAAyB,CAAC,CAAC,CAAA;AAAA,SACvD,CAAA;AACA,QAAOD,QAAA,CAAA,EAAA,CAAG,KAAO,EAAA,MAAM,OAAQ,CAAAE,eAAA,CAAS,IAAK,CAAA,MAAA,CAAO,MAAO,CAAA,MAAM,CAAC,CAAC,CAAC,CAAA,CAAA;AAAA,eAC7D,CAAG,EAAA;AACV,QAAM,MAAA,IAAID,qBAAe,CAAA,mCAAA,EAAqC,CAAC,CAAA,CAAA;AAAA,OACjE;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAM,KAAK,GAA8B,EAAA;AACvC,IAAA,MAAM,QAAW,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,GAAG,CAAA,CAAA;AACvC,IAAA,OAAO,SAAS,MAAO,EAAA,CAAA;AAAA,GACzB;AAAA,EAEA,MAAM,OACJ,CAAA,GAAA,EACA,OAC0C,EAAA;AAC1C,IAAA,MAAM,EAAE,IAAA,EAAM,iBAAkB,EAAA,GAAI,WAAW,EAAC,CAAA;AAEhD,IAAI,IAAA;AACF,MAAM,MAAA,EAAE,MAAM,MAAQ,EAAA,MAAA,KAAW,QAAS,CAAA,GAAA,EAAK,IAAK,CAAA,WAAA,CAAY,MAAM,CAAA,CAAA;AACtE,MAAM,MAAA,QAAA,GAAW,MAAM,IAAK,CAAA,aAAA;AAAA,QAC1B,IAAK,CAAA,YAAA;AAAA,QACL,MAAA;AAAA,QACA,IAAK,CAAA,WAAA;AAAA,OACP,CAAA;AACA,MAAM,MAAAE,iBAAA,GAAkB,IAAIC,+BAAgB,EAAA,CAAA;AAE5C,MAAA,MAAM,MAAgC,GAAA;AAAA,QACpC,MAAQ,EAAA,MAAA;AAAA,QACR,GAAK,EAAA,IAAA;AAAA,QACL,GAAI,IAAA,IAAQ,EAAE,WAAA,EAAa,IAAK,EAAA;AAAA,QAChC,GAAI,iBAAqB,IAAA;AAAA,UACvB,eAAiB,EAAA,iBAAA;AAAA,SACnB;AAAA,OACF,CAAA;AAEA,MAAA,OAAA,EAAS,QAAQ,gBAAiB,CAAA,OAAA,EAAS,MAAMD,iBAAA,CAAgB,OAAO,CAAA,CAAA;AACxE,MAAM,MAAA,gBAAA,GAAmB,IAAIE,yBAAA,CAAiB,MAAM,CAAA,CAAA;AACpD,MAAA,MAAM,QAAW,GAAA,MAAM,QAAS,CAAA,IAAA,CAAK,gBAAkB,EAAA;AAAA,QACrD,aAAaF,iBAAgB,CAAA,MAAA;AAAA,OAC9B,CAAA,CAAA;AAED,MAAM,MAAA,YAAA,GAAe,MAAM,IAAK,CAAA,oBAAA;AAAA,QAC9B,QAAS,CAAA,IAAA;AAAA,OACX,CAAA;AAEA,MAAO,OAAAG,6CAAA,CAAuB,aAAa,YAAc,EAAA;AAAA,QACvD,MAAM,QAAS,CAAA,IAAA;AAAA,QACf,gBAAgB,QAAS,CAAA,YAAA;AAAA,OAC1B,CAAA,CAAA;AAAA,aACM,CAAG,EAAA;AACV,MAAA,IAAI,CAAE,CAAA,SAAA,IAAa,CAAE,CAAA,SAAA,CAAU,mBAAmB,GAAK,EAAA;AACrD,QAAA,MAAM,IAAIC,uBAAiB,EAAA,CAAA;AAAA,OAC7B;AAEA,MAAM,MAAA,IAAIN,qBAAe,CAAA,iCAAA,EAAmC,CAAC,CAAA,CAAA;AAAA,KAC/D;AAAA,GACF;AAAA,EAEA,MAAM,QACJ,CAAA,GAAA,EACA,OAC2C,EAAA;AAC3C,IAAI,IAAA;AACF,MAAM,MAAA,EAAE,MAAM,MAAQ,EAAA,MAAA,KAAW,QAAS,CAAA,GAAA,EAAK,IAAK,CAAA,WAAA,CAAY,MAAM,CAAA,CAAA;AACtE,MAAM,MAAA,QAAA,GAAW,MAAM,IAAK,CAAA,aAAA;AAAA,QAC1B,IAAK,CAAA,YAAA;AAAA,QACL,MAAA;AAAA,QACA,IAAK,CAAA,WAAA;AAAA,OACP,CAAA;AACA,MAAM,MAAAE,iBAAA,GAAkB,IAAIC,+BAAgB,EAAA,CAAA;AAC5C,MAAA,MAAM,aAAuB,EAAC,CAAA;AAC9B,MAAA,MAAM,YAAY,EAAC,CAAA;AACnB,MAAI,IAAA,iBAAA,CAAA;AACJ,MAAI,IAAA,MAAA,CAAA;AACJ,MAAG,GAAA;AACD,QAAM,MAAA,oBAAA,GAAuB,IAAII,6BAAqB,CAAA;AAAA,UACpD,MAAQ,EAAA,MAAA;AAAA,UACR,iBAAmB,EAAA,iBAAA;AAAA,UACnB,MAAQ,EAAA,IAAA;AAAA,SACT,CAAA,CAAA;AACD,QAAA,OAAA,EAAS,MAAQ,EAAA,gBAAA;AAAA,UAAiB,OAAA;AAAA,UAAS,MACzCL,kBAAgB,KAAM,EAAA;AAAA,SACxB,CAAA;AACA,QAAS,MAAA,GAAA,MAAM,QAAS,CAAA,IAAA,CAAK,oBAAsB,EAAA;AAAA,UACjD,aAAaA,iBAAgB,CAAA,MAAA;AAAA,SAC9B,CAAA,CAAA;AACD,QAAA,IAAI,OAAO,QAAU,EAAA;AACnB,UAAO,MAAA,CAAA,QAAA,CAAS,QAAQ,CAAY,QAAA,KAAA;AAClC,YAAW,UAAA,CAAA,IAAA,CAAK,SAAS,GAAI,CAAA,CAAA;AAAA,WAC9B,CAAA,CAAA;AAAA,SACH;AACA,QAAA,iBAAA,GAAoB,MAAO,CAAA,qBAAA,CAAA;AAAA,OACpB,QAAA,iBAAA,EAAA;AAET,MAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,CAAW,QAAQ,CAAK,EAAA,EAAA;AAC1C,QAAM,MAAA,gBAAA,GAAmB,IAAIE,yBAAiB,CAAA;AAAA,UAC5C,MAAQ,EAAA,MAAA;AAAA,UACR,GAAK,EAAA,MAAA,CAAO,UAAW,CAAA,CAAC,CAAC,CAAA;AAAA,SAC1B,CAAA,CAAA;AACD,QAAA,MAAM,QAAW,GAAA,MAAM,QAAS,CAAA,IAAA,CAAK,gBAAgB,CAAA,CAAA;AACrD,QAAM,MAAA,YAAA,GAAe,MAAM,IAAK,CAAA,oBAAA;AAAA,UAC9B,QAAS,CAAA,IAAA;AAAA,SACX,CAAA;AAEA,QAAA,SAAA,CAAU,IAAK,CAAA;AAAA,UACb,IAAM,EAAA,YAAA;AAAA,UACN,MAAMI,cAAS,CAAA,IAAA,EAAM,OAAO,UAAW,CAAA,CAAC,CAAC,CAAC,CAAA;AAAA,UAC1C,cAAA,EAAgB,UAAU,YAAgB,IAAA,KAAA,CAAA;AAAA,SAC3C,CAAA,CAAA;AAAA,OACH;AAEA,MAAA,OAAO,MAAM,IAAA,CAAK,IAAK,CAAA,mBAAA,CAAoB,kBAAkB,SAAS,CAAA,CAAA;AAAA,aAC/D,CAAG,EAAA;AACV,MAAM,MAAA,IAAIR,qBAAe,CAAA,sCAAA,EAAwC,CAAC,CAAA,CAAA;AAAA,KACpE;AAAA,GACF;AAAA,EAEA,MAAM,MAAkD,GAAA;AACtD,IAAM,MAAA,IAAI,MAAM,uCAAuC,CAAA,CAAA;AAAA,GACzD;AAAA,EAEA,QAAW,GAAA;AACT,IAAM,MAAA,eAAA,GAAkB,IAAK,CAAA,WAAA,CAAY,MAAO,CAAA,eAAA,CAAA;AAChD,IAAA,OAAO,CAAc,WAAA,EAAA,IAAA,CAAK,WAAY,CAAA,MAAA,CAAO,IAAI,CAAW,QAAA,EAAA,OAAA;AAAA,MAC1D,eAAA;AAAA,KACD,CAAA,CAAA,CAAA,CAAA;AAAA,GACH;AACF;;;;;;"}
|
|
1
|
+
{"version":3,"file":"AwsS3UrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsS3UrlReader.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsS3Integration,\n ScmIntegrations,\n AwsS3IntegrationConfig,\n} from '@backstage/integration';\nimport { ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport {\n S3Client,\n ListObjectsV2Command,\n ListObjectsV2CommandOutput,\n GetObjectCommand,\n GetObjectCommandInput,\n} from '@aws-sdk/client-s3';\nimport { AbortController } from '@aws-sdk/abort-controller';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { Readable } from 'stream';\nimport { relative } from 'path/posix';\n\nexport const DEFAULT_REGION = 'us-east-1';\n\n/**\n * Path style URLs: https://s3.(region).amazonaws.com/(bucket)/(key)\n * The region can also be on the old form: https://s3-(region).amazonaws.com/(bucket)/(key)\n * Virtual hosted style URLs: https://(bucket).s3.(region).amazonaws.com/(key)\n * See https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html#path-style-access\n */\nexport function parseUrl(\n url: string,\n config: AwsS3IntegrationConfig,\n): { path: string; bucket: string; region: string } {\n const parsedUrl = new URL(url);\n\n /**\n * Removes the leading '/' from the pathname to be processed\n * as a parameter by AWS S3 SDK getObject method.\n */\n const pathname = parsedUrl.pathname.substring(1);\n const host = parsedUrl.host;\n\n // Treat Amazon hosted separately because it has special region logic\n if (config.host === 'amazonaws.com' || config.host === 'amazonaws.com.cn') {\n const match = host.match(\n /^(?:([a-z0-9.-]+)\\.)?s3(?:[.-]([a-z0-9-]+))?\\.amazonaws\\.com(\\.cn)?$/,\n );\n if (!match) {\n throw new Error(`Invalid AWS S3 URL ${url}`);\n }\n\n const [, hostBucket, hostRegion] = match;\n\n if (config.s3ForcePathStyle || !hostBucket) {\n const slashIndex = pathname.indexOf('/');\n if (slashIndex < 0) {\n throw new Error(\n `Invalid path-style AWS S3 URL ${url}, does not contain bucket in the path`,\n );\n }\n\n return {\n path: pathname.substring(slashIndex + 1),\n bucket: pathname.substring(0, slashIndex),\n region: hostRegion ?? DEFAULT_REGION,\n };\n }\n\n return {\n path: pathname,\n bucket: hostBucket,\n region: hostRegion ?? DEFAULT_REGION,\n };\n }\n\n const usePathStyle =\n config.s3ForcePathStyle || host.length === config.host.length;\n\n if (usePathStyle) {\n const slashIndex = pathname.indexOf('/');\n if (slashIndex < 0) {\n throw new Error(\n `Invalid path-style AWS S3 URL ${url}, does not contain bucket in the path`,\n );\n }\n\n return {\n path: pathname.substring(slashIndex + 1),\n bucket: pathname.substring(0, slashIndex),\n region: DEFAULT_REGION,\n };\n }\n\n return {\n path: pathname,\n bucket: host.substring(0, host.length - config.host.length - 1),\n region: DEFAULT_REGION,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS S3 buckets.\n *\n * @public\n */\nexport class AwsS3UrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsS3.list().map(integration => {\n const reader = new AwsS3UrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) =>\n url.host.endsWith(integration.config.host);\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly credsManager: AwsCredentialsManager,\n private readonly integration: AwsS3Integration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {}\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsS3Integration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n let explicitCredentials: AwsCredentialIdentityProvider;\n if (accessKeyId && secretAccessKey) {\n explicitCredentials = AwsS3UrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n } else {\n explicitCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n\n const roleArn = integration.config.roleArn;\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-s3-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return explicitCredentials;\n }\n\n private async buildS3Client(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsS3Integration,\n ): Promise<S3Client> {\n const credentials = await AwsS3UrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const s3 = new S3Client({\n customUserAgent: 'backstage-aws-s3-url-reader',\n region: region,\n credentials: credentials,\n endpoint: integration.config.endpoint,\n forcePathStyle: integration.config.s3ForcePathStyle,\n });\n return s3;\n }\n\n private async retrieveS3ObjectData(stream: Readable): Promise<Readable> {\n return new Promise((resolve, reject) => {\n try {\n const chunks: any[] = [];\n stream.on('data', chunk => chunks.push(chunk));\n stream.on('error', (e: Error) =>\n reject(new ForwardedError('Unable to read stream', e)),\n );\n stream.on('end', () => resolve(Readable.from(Buffer.concat(chunks))));\n } catch (e) {\n throw new ForwardedError('Unable to parse the response data', e);\n }\n });\n }\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const { etag, lastModifiedAfter } = options ?? {};\n\n try {\n const { path, bucket, region } = parseUrl(url, this.integration.config);\n const s3Client = await this.buildS3Client(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const params: GetObjectCommandInput = {\n Bucket: bucket,\n Key: path,\n ...(etag && { IfNoneMatch: etag }),\n ...(lastModifiedAfter && {\n IfModifiedSince: lastModifiedAfter,\n }),\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetObjectCommand(params);\n const response = await s3Client.send(getObjectCommand, {\n abortSignal: abortController.signal,\n });\n\n const s3ObjectData = await this.retrieveS3ObjectData(\n response.Body as Readable,\n );\n\n return ReadUrlResponseFactory.fromReadable(s3ObjectData, {\n etag: response.ETag,\n lastModifiedAt: response.LastModified,\n });\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from S3', e);\n }\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n try {\n const { path, bucket, region } = parseUrl(url, this.integration.config);\n const s3Client = await this.buildS3Client(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n const allObjects: String[] = [];\n const responses = [];\n let continuationToken: string | undefined;\n let output: ListObjectsV2CommandOutput;\n do {\n const listObjectsV2Command = new ListObjectsV2Command({\n Bucket: bucket,\n ContinuationToken: continuationToken,\n Prefix: path,\n });\n options?.signal?.addEventListener('abort', () =>\n abortController.abort(),\n );\n output = await s3Client.send(listObjectsV2Command, {\n abortSignal: abortController.signal,\n });\n if (output.Contents) {\n output.Contents.forEach(contents => {\n allObjects.push(contents.Key!);\n });\n }\n continuationToken = output.NextContinuationToken;\n } while (continuationToken);\n\n for (let i = 0; i < allObjects.length; i++) {\n const getObjectCommand = new GetObjectCommand({\n Bucket: bucket,\n Key: String(allObjects[i]),\n });\n const response = await s3Client.send(getObjectCommand);\n const s3ObjectData = await this.retrieveS3ObjectData(\n response.Body as Readable,\n );\n\n responses.push({\n data: s3ObjectData,\n path: relative(path, String(allObjects[i])),\n lastModifiedAt: response?.LastModified ?? undefined,\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n throw new ForwardedError('Could not retrieve file tree from S3', e);\n }\n }\n\n async search(): Promise<UrlReaderServiceSearchResponse> {\n throw new Error('AwsS3Reader does not implement search');\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsS3{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","S3Client","stream","ForwardedError","Readable","abortController","AbortController","GetObjectCommand","ReadUrlResponseFactory","NotModifiedError","ListObjectsV2Command","relative"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AzureUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AzureUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n getAzureCommitsUrl,\n getAzureDownloadUrl,\n getAzureFileFetchUrl,\n AzureDevOpsCredentialsProvider,\n DefaultAzureDevOpsCredentialsProvider,\n ScmIntegrations,\n AzureIntegration,\n} from '@backstage/integration';\nimport fetch, { Response } from 'node-fetch';\nimport { Minimatch } from 'minimatch';\nimport { Readable } from 'stream';\nimport { NotFoundError, NotModifiedError } from '@backstage/errors';\nimport { ReadTreeResponseFactory, ReaderFactory } from './types';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure repos.\n *\n * @public\n */\nexport class AzureUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credentialProvider =\n DefaultAzureDevOpsCredentialsProvider.fromIntegrations(integrations);\n return integrations.azure.list().map(integration => {\n const reader = new AzureUrlReader(integration, {\n treeResponseFactory,\n credentialsProvider: credentialProvider,\n });\n const predicate = (url: URL) => url.host === integration.config.host;\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly integration: AzureIntegration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n credentialsProvider: AzureDevOpsCredentialsProvider;\n },\n ) {}\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // TODO: etag is not implemented yet.\n const { signal } = options ?? {};\n\n const builtUrl = getAzureFileFetchUrl(url);\n let response: Response;\n try {\n const credentials = await this.deps.credentialsProvider.getCredentials({\n url: builtUrl,\n });\n response = await fetch(builtUrl, {\n headers: credentials?.headers,\n // TODO(freben): The signal cast is there because pre-3.x versions of\n // node-fetch have a very slightly deviating AbortSignal type signature.\n // The difference does not affect us in practice however. The cast can\n // be removed after we support ESM for CLI dependencies and migrate to\n // version 3 of node-fetch.\n // https://github.com/backstage/backstage/issues/8242\n ...(signal && { signal: signal as any }),\n });\n } catch (e) {\n throw new Error(`Unable to read ${url}, ${e}`);\n }\n\n // for private repos when PAT is not valid, Azure API returns a http status code 203 with sign in page html\n if (response.ok && response.status !== 203) {\n return ReadUrlResponseFactory.fromNodeJSReadable(response.body);\n }\n\n const message = `${url} could not be read as ${builtUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const { etag, filter, signal } = options ?? {};\n\n // TODO: Support filepath based reading tree feature like other providers\n\n // Get latest commit SHA\n\n const credentials = await this.deps.credentialsProvider.getCredentials({\n url: url,\n });\n\n const commitsAzureResponse = await fetch(getAzureCommitsUrl(url), {\n headers: credentials?.headers,\n });\n if (!commitsAzureResponse.ok) {\n const message = `Failed to read tree from ${url}, ${commitsAzureResponse.status} ${commitsAzureResponse.statusText}`;\n if (commitsAzureResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n const commitSha = (await commitsAzureResponse.json()).value[0].commitId;\n if (etag && etag === commitSha) {\n throw new NotModifiedError();\n }\n\n const archiveAzureResponse = await fetch(getAzureDownloadUrl(url), {\n headers: {\n ...credentials?.headers,\n Accept: 'application/zip',\n },\n // TODO(freben): The signal cast is there because pre-3.x versions of\n // node-fetch have a very slightly deviating AbortSignal type signature.\n // The difference does not affect us in practice however. The cast can be\n // removed after we support ESM for CLI dependencies and migrate to\n // version 3 of node-fetch.\n // https://github.com/backstage/backstage/issues/8242\n ...(signal && { signal: signal as any }),\n });\n if (!archiveAzureResponse.ok) {\n const message = `Failed to read tree from ${url}, ${archiveAzureResponse.status} ${archiveAzureResponse.statusText}`;\n if (archiveAzureResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n // When downloading a zip archive from azure on a subpath we get an extra directory\n // layer added at the top. With for example the file /a/b/c.txt and a download of\n // /a/b, we'll see /b/c.txt in the zip archive. This picks out /b so that we can remove it.\n let subpath;\n const path = new URL(url).searchParams.get('path');\n if (path) {\n subpath = path.split('/').filter(Boolean).slice(-1)[0];\n }\n\n return await this.deps.treeResponseFactory.fromZipArchive({\n stream: Readable.from(archiveAzureResponse.body),\n etag: commitSha,\n filter,\n subpath,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const treeUrl = new URL(url);\n\n const path = treeUrl.searchParams.get('path');\n const matcher = path && new Minimatch(path.replace(/^\\/+/, ''));\n\n // TODO(freben): For now, read the entire repo and filter through that. In\n // a future improvement, we could be smart and try to deduce that non-glob\n // prefixes (like for filepaths such as some-prefix/**/a.yaml) can be used\n // to get just that part of the repo.\n treeUrl.searchParams.delete('path');\n\n const tree = await this.readTree(treeUrl.toString(), {\n etag: options?.etag,\n signal: options?.signal,\n filter: p => (matcher ? matcher.match(p) : true),\n });\n const files = await tree.files();\n\n return {\n etag: tree.etag,\n files: files.map(file => ({\n url: this.integration.resolveUrl({\n url: `/${file.path}`,\n base: url,\n }),\n content: file.content,\n lastModifiedAt: file.lastModifiedAt,\n })),\n };\n }\n\n toString() {\n const { host, credentials } = this.integration.config;\n return `azure{host=${host},authed=${Boolean(\n credentials !== undefined && credentials.length > 0,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAzureDevOpsCredentialsProvider","getAzureFileFetchUrl","fetch","ReadUrlResponseFactory","NotFoundError","getAzureCommitsUrl","NotModifiedError","getAzureDownloadUrl","Readable","Minimatch"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AzureUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AzureUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n getAzureCommitsUrl,\n getAzureDownloadUrl,\n getAzureFileFetchUrl,\n AzureDevOpsCredentialsProvider,\n DefaultAzureDevOpsCredentialsProvider,\n ScmIntegrations,\n AzureIntegration,\n} from '@backstage/integration';\nimport fetch, { Response } from 'node-fetch';\nimport { Minimatch } from 'minimatch';\nimport { Readable } from 'stream';\nimport { NotFoundError, NotModifiedError } from '@backstage/errors';\nimport { ReadTreeResponseFactory, ReaderFactory } from './types';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure repos.\n *\n * @public\n */\nexport class AzureUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credentialProvider =\n DefaultAzureDevOpsCredentialsProvider.fromIntegrations(integrations);\n return integrations.azure.list().map(integration => {\n const reader = new AzureUrlReader(integration, {\n treeResponseFactory,\n credentialsProvider: credentialProvider,\n });\n const predicate = (url: URL) => url.host === integration.config.host;\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly integration: AzureIntegration,\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n credentialsProvider: AzureDevOpsCredentialsProvider;\n },\n ) {}\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // TODO: etag is not implemented yet.\n const { signal } = options ?? {};\n\n const builtUrl = getAzureFileFetchUrl(url);\n let response: Response;\n try {\n const credentials = await this.deps.credentialsProvider.getCredentials({\n url: builtUrl,\n });\n response = await fetch(builtUrl, {\n headers: credentials?.headers,\n // TODO(freben): The signal cast is there because pre-3.x versions of\n // node-fetch have a very slightly deviating AbortSignal type signature.\n // The difference does not affect us in practice however. The cast can\n // be removed after we support ESM for CLI dependencies and migrate to\n // version 3 of node-fetch.\n // https://github.com/backstage/backstage/issues/8242\n ...(signal && { signal: signal as any }),\n });\n } catch (e) {\n throw new Error(`Unable to read ${url}, ${e}`);\n }\n\n // for private repos when PAT is not valid, Azure API returns a http status code 203 with sign in page html\n if (response.ok && response.status !== 203) {\n return ReadUrlResponseFactory.fromNodeJSReadable(response.body);\n }\n\n const message = `${url} could not be read as ${builtUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const { etag, filter, signal } = options ?? {};\n\n // TODO: Support filepath based reading tree feature like other providers\n\n // Get latest commit SHA\n\n const credentials = await this.deps.credentialsProvider.getCredentials({\n url: url,\n });\n\n const commitsAzureResponse = await fetch(getAzureCommitsUrl(url), {\n headers: credentials?.headers,\n });\n if (!commitsAzureResponse.ok) {\n const message = `Failed to read tree from ${url}, ${commitsAzureResponse.status} ${commitsAzureResponse.statusText}`;\n if (commitsAzureResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n const commitSha = (await commitsAzureResponse.json()).value[0].commitId;\n if (etag && etag === commitSha) {\n throw new NotModifiedError();\n }\n\n const archiveAzureResponse = await fetch(getAzureDownloadUrl(url), {\n headers: {\n ...credentials?.headers,\n Accept: 'application/zip',\n },\n // TODO(freben): The signal cast is there because pre-3.x versions of\n // node-fetch have a very slightly deviating AbortSignal type signature.\n // The difference does not affect us in practice however. The cast can be\n // removed after we support ESM for CLI dependencies and migrate to\n // version 3 of node-fetch.\n // https://github.com/backstage/backstage/issues/8242\n ...(signal && { signal: signal as any }),\n });\n if (!archiveAzureResponse.ok) {\n const message = `Failed to read tree from ${url}, ${archiveAzureResponse.status} ${archiveAzureResponse.statusText}`;\n if (archiveAzureResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n // When downloading a zip archive from azure on a subpath we get an extra directory\n // layer added at the top. With for example the file /a/b/c.txt and a download of\n // /a/b, we'll see /b/c.txt in the zip archive. This picks out /b so that we can remove it.\n let subpath;\n const path = new URL(url).searchParams.get('path');\n if (path) {\n subpath = path.split('/').filter(Boolean).slice(-1)[0];\n }\n\n return await this.deps.treeResponseFactory.fromZipArchive({\n stream: Readable.from(archiveAzureResponse.body),\n etag: commitSha,\n filter,\n subpath,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const treeUrl = new URL(url);\n\n const path = treeUrl.searchParams.get('path');\n const matcher = path && new Minimatch(path.replace(/^\\/+/, ''));\n\n // TODO(freben): For now, read the entire repo and filter through that. In\n // a future improvement, we could be smart and try to deduce that non-glob\n // prefixes (like for filepaths such as some-prefix/**/a.yaml) can be used\n // to get just that part of the repo.\n treeUrl.searchParams.delete('path');\n\n const tree = await this.readTree(treeUrl.toString(), {\n etag: options?.etag,\n signal: options?.signal,\n filter: p => (matcher ? matcher.match(p) : true),\n });\n const files = await tree.files();\n\n return {\n etag: tree.etag,\n files: files.map(file => ({\n url: this.integration.resolveUrl({\n url: `/${file.path}`,\n base: url,\n }),\n content: file.content,\n lastModifiedAt: file.lastModifiedAt,\n })),\n };\n }\n\n toString() {\n const { host, credentials } = this.integration.config;\n return `azure{host=${host},authed=${Boolean(\n credentials !== undefined && credentials.length > 0,\n )}}`;\n }\n}\n"],"names":["ScmIntegrations","DefaultAzureDevOpsCredentialsProvider","getAzureFileFetchUrl","fetch","ReadUrlResponseFactory","NotFoundError","getAzureCommitsUrl","NotModifiedError","getAzureDownloadUrl","Readable","Minimatch"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitbucketCloudUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport { NotFoundError, NotModifiedError } from '@backstage/errors';\nimport {\n BitbucketCloudIntegration,\n getBitbucketCloudDefaultBranch,\n getBitbucketCloudDownloadUrl,\n getBitbucketCloudFileFetchUrl,\n getBitbucketCloudRequestOptions,\n ScmIntegrations,\n} from '@backstage/integration';\nimport fetch, { Response } from 'node-fetch';\nimport parseGitUrl from 'git-url-parse';\nimport { trimEnd } from 'lodash';\nimport { Minimatch } from 'minimatch';\nimport { Readable } from 'stream';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { parseLastModified } from './util';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Cloud.\n *\n * @public\n */\nexport class BitbucketCloudUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n return integrations.bitbucketCloud.list().map(integration => {\n const reader = new BitbucketCloudUrlReader(integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => url.host === integration.config.host;\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly integration: BitbucketCloudIntegration,\n private readonly deps: { treeResponseFactory: ReadTreeResponseFactory },\n ) {\n const { host, username, appPassword } = integration.config;\n\n if (username && !appPassword) {\n throw new Error(\n `Bitbucket Cloud integration for '${host}' has configured a username but is missing a required appPassword.`,\n );\n }\n }\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const { etag, lastModifiedAfter, signal } = options ?? {};\n const bitbucketUrl = getBitbucketCloudFileFetchUrl(\n url,\n this.integration.config,\n );\n const requestOptions = getBitbucketCloudRequestOptions(\n this.integration.config,\n );\n\n let response: Response;\n try {\n response = await fetch(bitbucketUrl.toString(), {\n headers: {\n ...requestOptions.headers,\n ...(etag && { 'If-None-Match': etag }),\n ...(lastModifiedAfter && {\n 'If-Modified-Since': lastModifiedAfter.toUTCString(),\n }),\n },\n // TODO(freben): The signal cast is there because pre-3.x versions of\n // node-fetch have a very slightly deviating AbortSignal type signature.\n // The difference does not affect us in practice however. The cast can be\n // removed after we support ESM for CLI dependencies and migrate to\n // version 3 of node-fetch.\n // https://github.com/backstage/backstage/issues/8242\n ...(signal && { signal: signal as any }),\n });\n } catch (e) {\n throw new Error(`Unable to read ${url}, ${e}`);\n }\n\n if (response.status === 304) {\n throw new NotModifiedError();\n }\n\n if (response.ok) {\n return ReadUrlResponseFactory.fromNodeJSReadable(response.body, {\n etag: response.headers.get('ETag') ?? undefined,\n lastModifiedAt: parseLastModified(\n response.headers.get('Last-Modified'),\n ),\n });\n }\n\n const message = `${url} could not be read as ${bitbucketUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const { filepath } = parseGitUrl(url);\n\n const lastCommitShortHash = await this.getLastCommitShortHash(url);\n if (options?.etag && options.etag === lastCommitShortHash) {\n throw new NotModifiedError();\n }\n\n const downloadUrl = await getBitbucketCloudDownloadUrl(\n url,\n this.integration.config,\n );\n const archiveResponse = await fetch(\n downloadUrl,\n getBitbucketCloudRequestOptions(this.integration.config),\n );\n if (!archiveResponse.ok) {\n const message = `Failed to read tree from ${url}, ${archiveResponse.status} ${archiveResponse.statusText}`;\n if (archiveResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n return await this.deps.treeResponseFactory.fromTarArchive({\n stream: Readable.from(archiveResponse.body),\n subpath: filepath,\n etag: lastCommitShortHash,\n filter: options?.filter,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { filepath } = parseGitUrl(url);\n const matcher = new Minimatch(filepath);\n\n // TODO(freben): For now, read the entire repo and filter through that. In\n // a future improvement, we could be smart and try to deduce that non-glob\n // prefixes (like for filepaths such as some-prefix/**/a.yaml) can be used\n // to get just that part of the repo.\n const treeUrl = trimEnd(url.replace(filepath, ''), '/');\n\n const tree = await this.readTree(treeUrl, {\n etag: options?.etag,\n filter: path => matcher.match(path),\n });\n const files = await tree.files();\n\n return {\n etag: tree.etag,\n files: files.map(file => ({\n url: this.integration.resolveUrl({\n url: `/${file.path}`,\n base: url,\n }),\n content: file.content,\n lastModifiedAt: file.lastModifiedAt,\n })),\n };\n }\n\n toString() {\n const { host, username, appPassword } = this.integration.config;\n const authed = Boolean(username && appPassword);\n return `bitbucketCloud{host=${host},authed=${authed}}`;\n }\n\n private async getLastCommitShortHash(url: string): Promise<string> {\n const { name: repoName, owner: project, ref } = parseGitUrl(url);\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketCloudDefaultBranch(\n url,\n this.integration.config,\n );\n }\n\n const commitsApiUrl = `${this.integration.config.apiBaseUrl}/repositories/${project}/${repoName}/commits/${branch}`;\n\n const commitsResponse = await fetch(\n commitsApiUrl,\n getBitbucketCloudRequestOptions(this.integration.config),\n );\n if (!commitsResponse.ok) {\n const message = `Failed to retrieve commits from ${commitsApiUrl}, ${commitsResponse.status} ${commitsResponse.statusText}`;\n if (commitsResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n const commits = await commitsResponse.json();\n if (\n commits &&\n commits.values &&\n commits.values.length > 0 &&\n commits.values[0].hash\n ) {\n return commits.values[0].hash.substring(0, 12);\n }\n\n throw new Error(`Failed to read response from ${commitsApiUrl}`);\n }\n}\n"],"names":["ScmIntegrations","getBitbucketCloudFileFetchUrl","getBitbucketCloudRequestOptions","fetch","NotModifiedError","ReadUrlResponseFactory","parseLastModified","NotFoundError","parseGitUrl","getBitbucketCloudDownloadUrl","Readable","Minimatch","trimEnd","getBitbucketCloudDefaultBranch"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BitbucketCloudUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport { NotFoundError, NotModifiedError } from '@backstage/errors';\nimport {\n BitbucketCloudIntegration,\n getBitbucketCloudDefaultBranch,\n getBitbucketCloudDownloadUrl,\n getBitbucketCloudFileFetchUrl,\n getBitbucketCloudRequestOptions,\n ScmIntegrations,\n} from '@backstage/integration';\nimport fetch, { Response } from 'node-fetch';\nimport parseGitUrl from 'git-url-parse';\nimport { trimEnd } from 'lodash';\nimport { Minimatch } from 'minimatch';\nimport { Readable } from 'stream';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { parseLastModified } from './util';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Cloud.\n *\n * @public\n */\nexport class BitbucketCloudUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n return integrations.bitbucketCloud.list().map(integration => {\n const reader = new BitbucketCloudUrlReader(integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => url.host === integration.config.host;\n return { reader, predicate };\n });\n };\n\n constructor(\n private readonly integration: BitbucketCloudIntegration,\n private readonly deps: { treeResponseFactory: ReadTreeResponseFactory },\n ) {\n const { host, username, appPassword } = integration.config;\n\n if (username && !appPassword) {\n throw new Error(\n `Bitbucket Cloud integration for '${host}' has configured a username but is missing a required appPassword.`,\n );\n }\n }\n\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const { etag, lastModifiedAfter, signal } = options ?? {};\n const bitbucketUrl = getBitbucketCloudFileFetchUrl(\n url,\n this.integration.config,\n );\n const requestOptions = getBitbucketCloudRequestOptions(\n this.integration.config,\n );\n\n let response: Response;\n try {\n response = await fetch(bitbucketUrl.toString(), {\n headers: {\n ...requestOptions.headers,\n ...(etag && { 'If-None-Match': etag }),\n ...(lastModifiedAfter && {\n 'If-Modified-Since': lastModifiedAfter.toUTCString(),\n }),\n },\n // TODO(freben): The signal cast is there because pre-3.x versions of\n // node-fetch have a very slightly deviating AbortSignal type signature.\n // The difference does not affect us in practice however. The cast can be\n // removed after we support ESM for CLI dependencies and migrate to\n // version 3 of node-fetch.\n // https://github.com/backstage/backstage/issues/8242\n ...(signal && { signal: signal as any }),\n });\n } catch (e) {\n throw new Error(`Unable to read ${url}, ${e}`);\n }\n\n if (response.status === 304) {\n throw new NotModifiedError();\n }\n\n if (response.ok) {\n return ReadUrlResponseFactory.fromNodeJSReadable(response.body, {\n etag: response.headers.get('ETag') ?? undefined,\n lastModifiedAt: parseLastModified(\n response.headers.get('Last-Modified'),\n ),\n });\n }\n\n const message = `${url} could not be read as ${bitbucketUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const { filepath } = parseGitUrl(url);\n\n const lastCommitShortHash = await this.getLastCommitShortHash(url);\n if (options?.etag && options.etag === lastCommitShortHash) {\n throw new NotModifiedError();\n }\n\n const downloadUrl = await getBitbucketCloudDownloadUrl(\n url,\n this.integration.config,\n );\n const archiveResponse = await fetch(\n downloadUrl,\n getBitbucketCloudRequestOptions(this.integration.config),\n );\n if (!archiveResponse.ok) {\n const message = `Failed to read tree from ${url}, ${archiveResponse.status} ${archiveResponse.statusText}`;\n if (archiveResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n return await this.deps.treeResponseFactory.fromTarArchive({\n stream: Readable.from(archiveResponse.body),\n subpath: filepath,\n etag: lastCommitShortHash,\n filter: options?.filter,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { filepath } = parseGitUrl(url);\n const matcher = new Minimatch(filepath);\n\n // TODO(freben): For now, read the entire repo and filter through that. In\n // a future improvement, we could be smart and try to deduce that non-glob\n // prefixes (like for filepaths such as some-prefix/**/a.yaml) can be used\n // to get just that part of the repo.\n const treeUrl = trimEnd(url.replace(filepath, ''), '/');\n\n const tree = await this.readTree(treeUrl, {\n etag: options?.etag,\n filter: path => matcher.match(path),\n });\n const files = await tree.files();\n\n return {\n etag: tree.etag,\n files: files.map(file => ({\n url: this.integration.resolveUrl({\n url: `/${file.path}`,\n base: url,\n }),\n content: file.content,\n lastModifiedAt: file.lastModifiedAt,\n })),\n };\n }\n\n toString() {\n const { host, username, appPassword } = this.integration.config;\n const authed = Boolean(username && appPassword);\n return `bitbucketCloud{host=${host},authed=${authed}}`;\n }\n\n private async getLastCommitShortHash(url: string): Promise<string> {\n const { name: repoName, owner: project, ref } = parseGitUrl(url);\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketCloudDefaultBranch(\n url,\n this.integration.config,\n );\n }\n\n const commitsApiUrl = `${this.integration.config.apiBaseUrl}/repositories/${project}/${repoName}/commits/${branch}`;\n\n const commitsResponse = await fetch(\n commitsApiUrl,\n getBitbucketCloudRequestOptions(this.integration.config),\n );\n if (!commitsResponse.ok) {\n const message = `Failed to retrieve commits from ${commitsApiUrl}, ${commitsResponse.status} ${commitsResponse.statusText}`;\n if (commitsResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n const commits = await commitsResponse.json();\n if (\n commits &&\n commits.values &&\n commits.values.length > 0 &&\n commits.values[0].hash\n ) {\n return commits.values[0].hash.substring(0, 12);\n }\n\n throw new Error(`Failed to read response from ${commitsApiUrl}`);\n }\n}\n"],"names":["ScmIntegrations","getBitbucketCloudFileFetchUrl","getBitbucketCloudRequestOptions","fetch","NotModifiedError","ReadUrlResponseFactory","parseLastModified","NotFoundError","parseGitUrl","getBitbucketCloudDownloadUrl","Readable","Minimatch","trimEnd","getBitbucketCloudDefaultBranch"],"mappings":"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"}
|