@backstage/backend-defaults 0.15.3-next.0 → 0.16.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @backstage/backend-defaults
2
2
 
3
+ ## 0.16.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - 0e7d8f9: The scheduler service now uses the metrics service to create metrics, providing plugin-scoped attribution.
8
+ - 527cf88: **BREAKING** Removed deprecated `BitbucketUrlReader`. Use the `BitbucketCloudUrlReader` or the `BitbucketServerUrlReader` instead.
9
+
10
+ ### Patch Changes
11
+
12
+ - 62f0a53: Fixed error forwarding in the actions registry so that known errors like `InputError` and `NotFoundError` thrown by actions preserve their original status codes and messages instead of being wrapped in `ForwardedError` and coerced to 500.
13
+ - Updated dependencies
14
+ - @backstage/cli-node@0.2.19-next.1
15
+ - @backstage/integration@2.0.0-next.1
16
+ - @backstage/plugin-auth-node@0.6.14-next.1
17
+ - @backstage/backend-app-api@1.5.1-next.0
18
+ - @backstage/backend-dev-utils@0.1.7
19
+ - @backstage/backend-plugin-api@1.7.1-next.0
20
+ - @backstage/config@1.3.6
21
+ - @backstage/config-loader@1.10.9-next.0
22
+ - @backstage/errors@1.2.7
23
+ - @backstage/integration-aws-node@0.1.20
24
+ - @backstage/types@1.2.2
25
+ - @backstage/plugin-events-node@0.4.20-next.0
26
+ - @backstage/plugin-permission-node@0.10.11-next.0
27
+
3
28
  ## 0.15.3-next.0
4
29
 
5
30
  ### Patch Changes
@@ -79,26 +79,19 @@ class DefaultActionsRegistryService {
79
79
  input.error
80
80
  );
81
81
  }
82
- try {
83
- const result = await action.action({
84
- input: input.data,
85
- credentials,
86
- logger: this.logger
87
- });
88
- const output = action.schema?.output ? action.schema.output(zod.z).safeParse(result?.output) : { success: true, data: result?.output };
89
- if (!output.success) {
90
- throw new errors.InputError(
91
- `Invalid output from action "${req.params.actionId}"`,
92
- output.error
93
- );
94
- }
95
- res.json({ output: output.data });
96
- } catch (error) {
97
- throw new errors.ForwardedError(
98
- `Failed execution of action "${req.params.actionId}"`,
99
- error
82
+ const result = await action.action({
83
+ input: input.data,
84
+ credentials,
85
+ logger: this.logger
86
+ });
87
+ const output = action.schema?.output ? action.schema.output(zod.z).safeParse(result?.output) : { success: true, data: result?.output };
88
+ if (!output.success) {
89
+ throw new errors.InputError(
90
+ `Invalid output from action "${req.params.actionId}"`,
91
+ output.error
100
92
  );
101
93
  }
94
+ res.json({ output: output.data });
102
95
  }
103
96
  );
104
97
  return router;
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultActionsRegistryService.cjs.js","sources":["../../../../src/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts"],"sourcesContent":["/*\n * Copyright 2025 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 AuthService,\n HttpAuthService,\n LoggerService,\n PluginMetadataService,\n} from '@backstage/backend-plugin-api';\nimport PromiseRouter from 'express-promise-router';\nimport { Router, json } from 'express';\nimport { z, AnyZodObject } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport {\n ActionsRegistryActionOptions,\n ActionsRegistryService,\n} from '@backstage/backend-plugin-api/alpha';\nimport {\n ForwardedError,\n InputError,\n NotAllowedError,\n NotFoundError,\n} from '@backstage/errors';\n\nexport class DefaultActionsRegistryService implements ActionsRegistryService {\n private actions: Map<string, ActionsRegistryActionOptions<any, any>> =\n new Map();\n\n private readonly logger: LoggerService;\n private readonly httpAuth: HttpAuthService;\n private readonly auth: AuthService;\n private readonly metadata: PluginMetadataService;\n\n private constructor(\n logger: LoggerService,\n httpAuth: HttpAuthService,\n auth: AuthService,\n metadata: PluginMetadataService,\n ) {\n this.logger = logger;\n this.httpAuth = httpAuth;\n this.auth = auth;\n this.metadata = metadata;\n }\n\n static create({\n httpAuth,\n logger,\n auth,\n metadata,\n }: {\n httpAuth: HttpAuthService;\n logger: LoggerService;\n auth: AuthService;\n metadata: PluginMetadataService;\n }): DefaultActionsRegistryService {\n return new DefaultActionsRegistryService(logger, httpAuth, auth, metadata);\n }\n\n createRouter(): Router {\n const router = PromiseRouter();\n router.use(json());\n\n router.get('/.backstage/actions/v1/actions', (_, res) => {\n return res.json({\n actions: Array.from(this.actions.entries()).map(([id, action]) => ({\n id,\n ...action,\n attributes: {\n // Inspired by the @modelcontextprotocol/sdk defaults for the hints.\n // https://github.com/modelcontextprotocol/typescript-sdk/blob/dd69efa1de8646bb6b195ff8d5f52e13739f4550/src/types.ts#L777-L812\n destructive: action.attributes?.destructive ?? true,\n idempotent: action.attributes?.idempotent ?? false,\n readOnly: action.attributes?.readOnly ?? false,\n },\n schema: {\n input: action.schema?.input\n ? zodToJsonSchema(action.schema.input(z))\n : zodToJsonSchema(z.object({})),\n output: action.schema?.output\n ? zodToJsonSchema(action.schema.output(z))\n : zodToJsonSchema(z.object({})),\n },\n })),\n });\n });\n\n router.post(\n '/.backstage/actions/v1/actions/:actionId/invoke',\n async (req, res) => {\n const credentials = await this.httpAuth.credentials(req);\n if (this.auth.isPrincipal(credentials, 'user')) {\n if (!credentials.principal.actor) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not a user`,\n );\n }\n } else if (this.auth.isPrincipal(credentials, 'none')) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not an anonymous request`,\n );\n }\n\n const action = this.actions.get(req.params.actionId);\n\n if (!action) {\n throw new NotFoundError(`Action \"${req.params.actionId}\" not found`);\n }\n\n const input = action.schema?.input\n ? action.schema.input(z).safeParse(req.body)\n : ({ success: true, data: undefined } as const);\n\n if (!input.success) {\n throw new InputError(\n `Invalid input to action \"${req.params.actionId}\"`,\n input.error,\n );\n }\n\n try {\n const result = await action.action({\n input: input.data,\n credentials,\n logger: this.logger,\n });\n\n const output = action.schema?.output\n ? action.schema.output(z).safeParse(result?.output)\n : ({ success: true, data: result?.output } as const);\n\n if (!output.success) {\n throw new InputError(\n `Invalid output from action \"${req.params.actionId}\"`,\n output.error,\n );\n }\n\n res.json({ output: output.data });\n } catch (error) {\n throw new ForwardedError(\n `Failed execution of action \"${req.params.actionId}\"`,\n error,\n );\n }\n },\n );\n return router;\n }\n\n register<\n TInputSchema extends AnyZodObject,\n TOutputSchema extends AnyZodObject,\n >(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void {\n const id = `${this.metadata.getId()}:${options.name}`;\n\n if (this.actions.has(id)) {\n throw new Error(`Action with id \"${id}\" is already registered`);\n }\n\n this.actions.set(id, options);\n }\n}\n"],"names":["PromiseRouter","json","zodToJsonSchema","z","NotAllowedError","NotFoundError","InputError","ForwardedError"],"mappings":"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"}
1
+ {"version":3,"file":"DefaultActionsRegistryService.cjs.js","sources":["../../../../src/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.ts"],"sourcesContent":["/*\n * Copyright 2025 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 AuthService,\n HttpAuthService,\n LoggerService,\n PluginMetadataService,\n} from '@backstage/backend-plugin-api';\nimport PromiseRouter from 'express-promise-router';\nimport { Router, json } from 'express';\nimport { z, AnyZodObject } from 'zod';\nimport zodToJsonSchema from 'zod-to-json-schema';\nimport {\n ActionsRegistryActionOptions,\n ActionsRegistryService,\n} from '@backstage/backend-plugin-api/alpha';\nimport { InputError, NotAllowedError, NotFoundError } from '@backstage/errors';\n\nexport class DefaultActionsRegistryService implements ActionsRegistryService {\n private actions: Map<string, ActionsRegistryActionOptions<any, any>> =\n new Map();\n\n private readonly logger: LoggerService;\n private readonly httpAuth: HttpAuthService;\n private readonly auth: AuthService;\n private readonly metadata: PluginMetadataService;\n\n private constructor(\n logger: LoggerService,\n httpAuth: HttpAuthService,\n auth: AuthService,\n metadata: PluginMetadataService,\n ) {\n this.logger = logger;\n this.httpAuth = httpAuth;\n this.auth = auth;\n this.metadata = metadata;\n }\n\n static create({\n httpAuth,\n logger,\n auth,\n metadata,\n }: {\n httpAuth: HttpAuthService;\n logger: LoggerService;\n auth: AuthService;\n metadata: PluginMetadataService;\n }): DefaultActionsRegistryService {\n return new DefaultActionsRegistryService(logger, httpAuth, auth, metadata);\n }\n\n createRouter(): Router {\n const router = PromiseRouter();\n router.use(json());\n\n router.get('/.backstage/actions/v1/actions', (_, res) => {\n return res.json({\n actions: Array.from(this.actions.entries()).map(([id, action]) => ({\n id,\n ...action,\n attributes: {\n // Inspired by the @modelcontextprotocol/sdk defaults for the hints.\n // https://github.com/modelcontextprotocol/typescript-sdk/blob/dd69efa1de8646bb6b195ff8d5f52e13739f4550/src/types.ts#L777-L812\n destructive: action.attributes?.destructive ?? true,\n idempotent: action.attributes?.idempotent ?? false,\n readOnly: action.attributes?.readOnly ?? false,\n },\n schema: {\n input: action.schema?.input\n ? zodToJsonSchema(action.schema.input(z))\n : zodToJsonSchema(z.object({})),\n output: action.schema?.output\n ? zodToJsonSchema(action.schema.output(z))\n : zodToJsonSchema(z.object({})),\n },\n })),\n });\n });\n\n router.post(\n '/.backstage/actions/v1/actions/:actionId/invoke',\n async (req, res) => {\n const credentials = await this.httpAuth.credentials(req);\n if (this.auth.isPrincipal(credentials, 'user')) {\n if (!credentials.principal.actor) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not a user`,\n );\n }\n } else if (this.auth.isPrincipal(credentials, 'none')) {\n throw new NotAllowedError(\n `Actions must be invoked by a service, not an anonymous request`,\n );\n }\n\n const action = this.actions.get(req.params.actionId);\n\n if (!action) {\n throw new NotFoundError(`Action \"${req.params.actionId}\" not found`);\n }\n\n const input = action.schema?.input\n ? action.schema.input(z).safeParse(req.body)\n : ({ success: true, data: undefined } as const);\n\n if (!input.success) {\n throw new InputError(\n `Invalid input to action \"${req.params.actionId}\"`,\n input.error,\n );\n }\n\n const result = await action.action({\n input: input.data,\n credentials,\n logger: this.logger,\n });\n\n const output = action.schema?.output\n ? action.schema.output(z).safeParse(result?.output)\n : ({ success: true, data: result?.output } as const);\n\n if (!output.success) {\n throw new InputError(\n `Invalid output from action \"${req.params.actionId}\"`,\n output.error,\n );\n }\n\n res.json({ output: output.data });\n },\n );\n return router;\n }\n\n register<\n TInputSchema extends AnyZodObject,\n TOutputSchema extends AnyZodObject,\n >(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void {\n const id = `${this.metadata.getId()}:${options.name}`;\n\n if (this.actions.has(id)) {\n throw new Error(`Action with id \"${id}\" is already registered`);\n }\n\n this.actions.set(id, options);\n }\n}\n"],"names":["PromiseRouter","json","zodToJsonSchema","z","NotAllowedError","NotFoundError","InputError"],"mappings":"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"}
@@ -29,6 +29,7 @@ class DefaultSchedulerService {
29
29
  options.pluginMetadata.getId(),
30
30
  databaseFactory,
31
31
  options.logger,
32
+ options.metrics,
32
33
  options.rootLifecycle
33
34
  );
34
35
  options.httpRouter.use(scheduler.getRouter());
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultSchedulerService.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/DefaultSchedulerService.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 DatabaseService,\n HttpRouterService,\n LoggerService,\n PluginMetadataService,\n RootLifecycleService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport { once } from 'lodash';\nimport { Duration } from 'luxon';\nimport { migrateBackendTasks } from '../database/migrateBackendTasks';\nimport { PluginTaskSchedulerImpl } from './PluginTaskSchedulerImpl';\nimport { PluginTaskSchedulerJanitor } from './PluginTaskSchedulerJanitor';\n\n/**\n * Default implementation of the task scheduler service.\n *\n * @public\n */\nexport class DefaultSchedulerService {\n static create(options: {\n database: DatabaseService;\n logger: LoggerService;\n rootLifecycle: RootLifecycleService;\n httpRouter: HttpRouterService;\n pluginMetadata: PluginMetadataService;\n }): SchedulerService {\n const databaseFactory = once(async () => {\n const knex = await options.database.getClient();\n\n if (!options.database.migrations?.skip) {\n await migrateBackendTasks(knex);\n }\n\n if (process.env.NODE_ENV !== 'test') {\n const abortController = new AbortController();\n const janitor = new PluginTaskSchedulerJanitor({\n knex,\n waitBetweenRuns: Duration.fromObject({ minutes: 1 }),\n logger: options.logger,\n });\n\n options.rootLifecycle.addShutdownHook(() => abortController.abort());\n janitor.start(abortController.signal);\n }\n\n return knex;\n });\n\n const scheduler = new PluginTaskSchedulerImpl(\n options.pluginMetadata.getId(),\n databaseFactory,\n options.logger,\n options.rootLifecycle,\n );\n\n options.httpRouter.use(scheduler.getRouter());\n\n return scheduler;\n }\n}\n"],"names":["once","migrateBackendTasks","PluginTaskSchedulerJanitor","Duration","PluginTaskSchedulerImpl"],"mappings":";;;;;;;;AAmCO,MAAM,uBAAA,CAAwB;AAAA,EACnC,OAAO,OAAO,OAAA,EAMO;AACnB,IAAA,MAAM,eAAA,GAAkBA,YAAK,YAAY;AACvC,MAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,QAAA,CAAS,SAAA,EAAU;AAE9C,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,CAAS,UAAA,EAAY,IAAA,EAAM;AACtC,QAAA,MAAMC,wCAAoB,IAAI,CAAA;AAAA,MAChC;AAEA,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,MAAA,EAAQ;AACnC,QAAA,MAAM,eAAA,GAAkB,IAAI,eAAA,EAAgB;AAC5C,QAAA,MAAM,OAAA,GAAU,IAAIC,qDAAA,CAA2B;AAAA,UAC7C,IAAA;AAAA,UACA,iBAAiBC,cAAA,CAAS,UAAA,CAAW,EAAE,OAAA,EAAS,GAAG,CAAA;AAAA,UACnD,QAAQ,OAAA,CAAQ;AAAA,SACjB,CAAA;AAED,QAAA,OAAA,CAAQ,aAAA,CAAc,eAAA,CAAgB,MAAM,eAAA,CAAgB,OAAO,CAAA;AACnE,QAAA,OAAA,CAAQ,KAAA,CAAM,gBAAgB,MAAM,CAAA;AAAA,MACtC;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAED,IAAA,MAAM,YAAY,IAAIC,+CAAA;AAAA,MACpB,OAAA,CAAQ,eAAe,KAAA,EAAM;AAAA,MAC7B,eAAA;AAAA,MACA,OAAA,CAAQ,MAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACV;AAEA,IAAA,OAAA,CAAQ,UAAA,CAAW,GAAA,CAAI,SAAA,CAAU,SAAA,EAAW,CAAA;AAE5C,IAAA,OAAO,SAAA;AAAA,EACT;AACF;;;;"}
1
+ {"version":3,"file":"DefaultSchedulerService.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/DefaultSchedulerService.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 DatabaseService,\n HttpRouterService,\n LoggerService,\n PluginMetadataService,\n RootLifecycleService,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport { once } from 'lodash';\nimport { Duration } from 'luxon';\nimport { migrateBackendTasks } from '../database/migrateBackendTasks';\nimport { PluginTaskSchedulerImpl } from './PluginTaskSchedulerImpl';\nimport { PluginTaskSchedulerJanitor } from './PluginTaskSchedulerJanitor';\nimport { MetricsService } from '@backstage/backend-plugin-api/alpha';\n\n/**\n * Default implementation of the task scheduler service.\n *\n * @public\n */\nexport class DefaultSchedulerService {\n static create(options: {\n database: DatabaseService;\n logger: LoggerService;\n metrics: MetricsService;\n rootLifecycle: RootLifecycleService;\n httpRouter: HttpRouterService;\n pluginMetadata: PluginMetadataService;\n }): SchedulerService {\n const databaseFactory = once(async () => {\n const knex = await options.database.getClient();\n\n if (!options.database.migrations?.skip) {\n await migrateBackendTasks(knex);\n }\n\n if (process.env.NODE_ENV !== 'test') {\n const abortController = new AbortController();\n const janitor = new PluginTaskSchedulerJanitor({\n knex,\n waitBetweenRuns: Duration.fromObject({ minutes: 1 }),\n logger: options.logger,\n });\n\n options.rootLifecycle.addShutdownHook(() => abortController.abort());\n janitor.start(abortController.signal);\n }\n\n return knex;\n });\n\n const scheduler = new PluginTaskSchedulerImpl(\n options.pluginMetadata.getId(),\n databaseFactory,\n options.logger,\n options.metrics,\n options.rootLifecycle,\n );\n\n options.httpRouter.use(scheduler.getRouter());\n\n return scheduler;\n }\n}\n"],"names":["once","migrateBackendTasks","PluginTaskSchedulerJanitor","Duration","PluginTaskSchedulerImpl"],"mappings":";;;;;;;;AAoCO,MAAM,uBAAA,CAAwB;AAAA,EACnC,OAAO,OAAO,OAAA,EAOO;AACnB,IAAA,MAAM,eAAA,GAAkBA,YAAK,YAAY;AACvC,MAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,QAAA,CAAS,SAAA,EAAU;AAE9C,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,CAAS,UAAA,EAAY,IAAA,EAAM;AACtC,QAAA,MAAMC,wCAAoB,IAAI,CAAA;AAAA,MAChC;AAEA,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,MAAA,EAAQ;AACnC,QAAA,MAAM,eAAA,GAAkB,IAAI,eAAA,EAAgB;AAC5C,QAAA,MAAM,OAAA,GAAU,IAAIC,qDAAA,CAA2B;AAAA,UAC7C,IAAA;AAAA,UACA,iBAAiBC,cAAA,CAAS,UAAA,CAAW,EAAE,OAAA,EAAS,GAAG,CAAA;AAAA,UACnD,QAAQ,OAAA,CAAQ;AAAA,SACjB,CAAA;AAED,QAAA,OAAA,CAAQ,aAAA,CAAc,eAAA,CAAgB,MAAM,eAAA,CAAgB,OAAO,CAAA;AACnE,QAAA,OAAA,CAAQ,KAAA,CAAM,gBAAgB,MAAM,CAAA;AAAA,MACtC;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAED,IAAA,MAAM,YAAY,IAAIC,+CAAA;AAAA,MACpB,OAAA,CAAQ,eAAe,KAAA,EAAM;AAAA,MAC7B,eAAA;AAAA,MACA,OAAA,CAAQ,MAAA;AAAA,MACR,OAAA,CAAQ,OAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACV;AAEA,IAAA,OAAA,CAAQ,UAAA,CAAW,GAAA,CAAI,SAAA,CAAU,SAAA,EAAW,CAAA;AAE5C,IAAA,OAAO,SAAA;AAAA,EACT;AACF;;;;"}
@@ -24,23 +24,25 @@ class PluginTaskSchedulerImpl {
24
24
  pluginId;
25
25
  databaseFactory;
26
26
  logger;
27
- constructor(pluginId, databaseFactory, logger, rootLifecycle) {
27
+ constructor(pluginId, databaseFactory, logger, metrics, rootLifecycle) {
28
28
  this.pluginId = pluginId;
29
29
  this.databaseFactory = databaseFactory;
30
30
  this.logger = logger;
31
- const meter = api.metrics.getMeter("default");
32
- this.counter = meter.createCounter("backend_tasks.task.runs.count", {
31
+ this.counter = metrics.createCounter("backend_tasks.task.runs.count", {
33
32
  description: "Total number of times a task has been run"
34
33
  });
35
- this.duration = meter.createHistogram("backend_tasks.task.runs.duration", {
36
- description: "Histogram of task run durations",
37
- unit: "seconds"
38
- });
39
- this.lastStarted = meter.createGauge("backend_tasks.task.runs.started", {
34
+ this.duration = metrics.createHistogram(
35
+ "backend_tasks.task.runs.duration",
36
+ {
37
+ description: "Histogram of task run durations",
38
+ unit: "seconds"
39
+ }
40
+ );
41
+ this.lastStarted = metrics.createGauge("backend_tasks.task.runs.started", {
40
42
  description: "Epoch timestamp seconds when the task was last started",
41
43
  unit: "seconds"
42
44
  });
43
- this.lastCompleted = meter.createGauge(
45
+ this.lastCompleted = metrics.createGauge(
44
46
  "backend_tasks.task.runs.completed",
45
47
  {
46
48
  description: "Epoch timestamp seconds when the task was last completed",
@@ -1 +1 @@
1
- {"version":3,"file":"PluginTaskSchedulerImpl.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.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 LoggerService,\n RootLifecycleService,\n SchedulerService,\n SchedulerServiceTaskDescriptor,\n SchedulerServiceTaskFunction,\n SchedulerServiceTaskInvocationDefinition,\n SchedulerServiceTaskRunner,\n SchedulerServiceTaskScheduleDefinition,\n} from '@backstage/backend-plugin-api';\nimport { Counter, Histogram, Gauge, metrics, trace } from '@opentelemetry/api';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { LocalTaskWorker } from './LocalTaskWorker';\nimport { TaskWorker } from './TaskWorker';\nimport { TaskSettingsV2, TaskApiTasksResponse } from './types';\nimport { delegateAbortController, TRACER_ID, validateId } from './util';\n\nconst tracer = trace.getTracer(TRACER_ID);\n\n/**\n * Implements the actual task management.\n */\nexport class PluginTaskSchedulerImpl implements SchedulerService {\n private readonly localWorkersById = new Map<string, LocalTaskWorker>();\n private readonly globalWorkersById = new Map<string, TaskWorker>();\n private readonly allScheduledTasks: SchedulerServiceTaskDescriptor[] = [];\n private readonly shutdownInitiated: Promise<boolean>;\n\n private readonly counter: Counter;\n private readonly duration: Histogram;\n private readonly lastStarted: Gauge;\n private readonly lastCompleted: Gauge;\n\n private readonly pluginId: string;\n private readonly databaseFactory: () => Promise<Knex>;\n private readonly logger: LoggerService;\n\n constructor(\n pluginId: string,\n databaseFactory: () => Promise<Knex>,\n logger: LoggerService,\n rootLifecycle: RootLifecycleService,\n ) {\n this.pluginId = pluginId;\n this.databaseFactory = databaseFactory;\n this.logger = logger;\n const meter = metrics.getMeter('default');\n this.counter = meter.createCounter('backend_tasks.task.runs.count', {\n description: 'Total number of times a task has been run',\n });\n this.duration = meter.createHistogram('backend_tasks.task.runs.duration', {\n description: 'Histogram of task run durations',\n unit: 'seconds',\n });\n this.lastStarted = meter.createGauge('backend_tasks.task.runs.started', {\n description: 'Epoch timestamp seconds when the task was last started',\n unit: 'seconds',\n });\n this.lastCompleted = meter.createGauge(\n 'backend_tasks.task.runs.completed',\n {\n description: 'Epoch timestamp seconds when the task was last completed',\n unit: 'seconds',\n },\n );\n this.shutdownInitiated = new Promise(shutdownInitiated => {\n rootLifecycle.addShutdownHook(() => shutdownInitiated(true));\n });\n }\n\n async triggerTask(id: string): Promise<void> {\n const localTask = this.localWorkersById.get(id);\n if (localTask) {\n localTask.trigger();\n return;\n }\n\n const knex = await this.databaseFactory();\n await TaskWorker.trigger(knex, id);\n }\n\n async scheduleTask(\n task: SchedulerServiceTaskScheduleDefinition &\n SchedulerServiceTaskInvocationDefinition,\n ): Promise<void> {\n validateId(task.id);\n const scope = task.scope ?? 'global';\n\n const settings: TaskSettingsV2 = {\n version: 2,\n cadence: parseDuration(task.frequency),\n initialDelayDuration:\n task.initialDelay && parseDuration(task.initialDelay),\n timeoutAfterDuration: parseDuration(task.timeout),\n };\n\n // Delegated abort controller that will abort either when the provided\n // controller aborts, or when a root lifecycle shutdown happens\n const abortController = delegateAbortController(task.signal);\n this.shutdownInitiated.then(() => abortController.abort());\n\n if (scope === 'global') {\n const knex = await this.databaseFactory();\n const worker = new TaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n knex,\n this.logger.child({ task: task.id }),\n );\n await worker.start(settings, { signal: abortController.signal });\n this.globalWorkersById.set(task.id, worker);\n } else {\n const worker = new LocalTaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n this.logger.child({ task: task.id }),\n );\n worker.start(settings, { signal: abortController.signal });\n this.localWorkersById.set(task.id, worker);\n }\n\n this.allScheduledTasks.push({\n id: task.id,\n scope: scope,\n settings: settings,\n });\n }\n\n createScheduledTaskRunner(\n schedule: SchedulerServiceTaskScheduleDefinition,\n ): SchedulerServiceTaskRunner {\n return {\n run: async task => {\n await this.scheduleTask({ ...task, ...schedule });\n },\n };\n }\n\n async getScheduledTasks(): Promise<SchedulerServiceTaskDescriptor[]> {\n return this.allScheduledTasks;\n }\n\n getRouter(): express.Router {\n const router = Router();\n\n router.get('/.backstage/scheduler/v1/tasks', async (_, res) => {\n const globalState = await TaskWorker.taskStates(\n await this.databaseFactory(),\n );\n\n const tasks = new Array<TaskApiTasksResponse>();\n for (const task of this.allScheduledTasks) {\n tasks.push({\n taskId: task.id,\n pluginId: this.pluginId,\n scope: task.scope,\n settings: task.settings,\n taskState:\n this.localWorkersById.get(task.id)?.taskState() ??\n globalState.get(task.id) ??\n null,\n workerState:\n this.localWorkersById.get(task.id)?.workerState() ??\n this.globalWorkersById.get(task.id)?.workerState() ??\n null,\n });\n }\n\n res.json({ tasks });\n });\n\n router.post(\n '/.backstage/scheduler/v1/tasks/:id/trigger',\n async (req, res) => {\n const { id } = req.params;\n await this.triggerTask(id);\n res.status(200).end();\n },\n );\n\n return router;\n }\n\n private instrumentedFunction(\n task: SchedulerServiceTaskInvocationDefinition,\n scope: string,\n ): SchedulerServiceTaskFunction {\n return async abort => {\n const labels: Record<string, string> = {\n taskId: task.id,\n scope,\n };\n this.counter.add(1, { ...labels, result: 'started' });\n this.lastStarted.record(Date.now() / 1000, { taskId: task.id });\n\n const startTime = process.hrtime();\n\n try {\n await tracer.startActiveSpan(`task ${task.id}`, async span => {\n try {\n span.setAttributes(labels);\n await task.fn(abort);\n } catch (error) {\n if (error instanceof Error) {\n span.recordException(error);\n }\n throw error;\n } finally {\n span.end();\n }\n });\n labels.result = 'completed';\n } catch (ex) {\n labels.result = 'failed';\n throw ex;\n } finally {\n const delta = process.hrtime(startTime);\n const endTime = delta[0] + delta[1] / 1e9;\n this.counter.add(1, labels);\n this.duration.record(endTime, labels);\n this.lastCompleted.record(Date.now() / 1000, labels);\n }\n };\n }\n}\n\nexport function parseDuration(\n frequency: SchedulerServiceTaskScheduleDefinition['frequency'],\n): string {\n if (typeof frequency === 'object' && 'cron' in frequency) {\n return frequency.cron;\n }\n if (typeof frequency === 'object' && 'trigger' in frequency) {\n return frequency.trigger;\n }\n\n const parsed = Duration.isDuration(frequency)\n ? frequency\n : Duration.fromObject(frequency);\n\n if (!parsed.isValid) {\n throw new Error(\n `Invalid duration, ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n\n return parsed.toISO()!;\n}\n"],"names":["trace","TRACER_ID","metrics","TaskWorker","validateId","delegateAbortController","LocalTaskWorker","Router","Duration"],"mappings":"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"}
1
+ {"version":3,"file":"PluginTaskSchedulerImpl.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.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 LoggerService,\n RootLifecycleService,\n SchedulerService,\n SchedulerServiceTaskDescriptor,\n SchedulerServiceTaskFunction,\n SchedulerServiceTaskInvocationDefinition,\n SchedulerServiceTaskRunner,\n SchedulerServiceTaskScheduleDefinition,\n} from '@backstage/backend-plugin-api';\nimport { trace } from '@opentelemetry/api';\nimport {\n MetricsService,\n MetricsServiceCounter,\n MetricsServiceGauge,\n MetricsServiceHistogram,\n} from '@backstage/backend-plugin-api/alpha';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { LocalTaskWorker } from './LocalTaskWorker';\nimport { TaskWorker } from './TaskWorker';\nimport { TaskSettingsV2, TaskApiTasksResponse } from './types';\nimport { delegateAbortController, TRACER_ID, validateId } from './util';\n\nconst tracer = trace.getTracer(TRACER_ID);\n\n/**\n * Implements the actual task management.\n */\nexport class PluginTaskSchedulerImpl implements SchedulerService {\n private readonly localWorkersById = new Map<string, LocalTaskWorker>();\n private readonly globalWorkersById = new Map<string, TaskWorker>();\n private readonly allScheduledTasks: SchedulerServiceTaskDescriptor[] = [];\n private readonly shutdownInitiated: Promise<boolean>;\n\n private readonly counter: MetricsServiceCounter;\n private readonly duration: MetricsServiceHistogram;\n private readonly lastStarted: MetricsServiceGauge;\n private readonly lastCompleted: MetricsServiceGauge;\n\n private readonly pluginId: string;\n private readonly databaseFactory: () => Promise<Knex>;\n private readonly logger: LoggerService;\n\n constructor(\n pluginId: string,\n databaseFactory: () => Promise<Knex>,\n logger: LoggerService,\n metrics: MetricsService,\n rootLifecycle: RootLifecycleService,\n ) {\n this.pluginId = pluginId;\n this.databaseFactory = databaseFactory;\n this.logger = logger;\n this.counter = metrics.createCounter('backend_tasks.task.runs.count', {\n description: 'Total number of times a task has been run',\n });\n this.duration = metrics.createHistogram(\n 'backend_tasks.task.runs.duration',\n {\n description: 'Histogram of task run durations',\n unit: 'seconds',\n },\n );\n this.lastStarted = metrics.createGauge('backend_tasks.task.runs.started', {\n description: 'Epoch timestamp seconds when the task was last started',\n unit: 'seconds',\n });\n this.lastCompleted = metrics.createGauge(\n 'backend_tasks.task.runs.completed',\n {\n description: 'Epoch timestamp seconds when the task was last completed',\n unit: 'seconds',\n },\n );\n this.shutdownInitiated = new Promise(shutdownInitiated => {\n rootLifecycle.addShutdownHook(() => shutdownInitiated(true));\n });\n }\n\n async triggerTask(id: string): Promise<void> {\n const localTask = this.localWorkersById.get(id);\n if (localTask) {\n localTask.trigger();\n return;\n }\n\n const knex = await this.databaseFactory();\n await TaskWorker.trigger(knex, id);\n }\n\n async scheduleTask(\n task: SchedulerServiceTaskScheduleDefinition &\n SchedulerServiceTaskInvocationDefinition,\n ): Promise<void> {\n validateId(task.id);\n const scope = task.scope ?? 'global';\n\n const settings: TaskSettingsV2 = {\n version: 2,\n cadence: parseDuration(task.frequency),\n initialDelayDuration:\n task.initialDelay && parseDuration(task.initialDelay),\n timeoutAfterDuration: parseDuration(task.timeout),\n };\n\n // Delegated abort controller that will abort either when the provided\n // controller aborts, or when a root lifecycle shutdown happens\n const abortController = delegateAbortController(task.signal);\n this.shutdownInitiated.then(() => abortController.abort());\n\n if (scope === 'global') {\n const knex = await this.databaseFactory();\n const worker = new TaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n knex,\n this.logger.child({ task: task.id }),\n );\n await worker.start(settings, { signal: abortController.signal });\n this.globalWorkersById.set(task.id, worker);\n } else {\n const worker = new LocalTaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n this.logger.child({ task: task.id }),\n );\n worker.start(settings, { signal: abortController.signal });\n this.localWorkersById.set(task.id, worker);\n }\n\n this.allScheduledTasks.push({\n id: task.id,\n scope: scope,\n settings: settings,\n });\n }\n\n createScheduledTaskRunner(\n schedule: SchedulerServiceTaskScheduleDefinition,\n ): SchedulerServiceTaskRunner {\n return {\n run: async task => {\n await this.scheduleTask({ ...task, ...schedule });\n },\n };\n }\n\n async getScheduledTasks(): Promise<SchedulerServiceTaskDescriptor[]> {\n return this.allScheduledTasks;\n }\n\n getRouter(): express.Router {\n const router = Router();\n\n router.get('/.backstage/scheduler/v1/tasks', async (_, res) => {\n const globalState = await TaskWorker.taskStates(\n await this.databaseFactory(),\n );\n\n const tasks = new Array<TaskApiTasksResponse>();\n for (const task of this.allScheduledTasks) {\n tasks.push({\n taskId: task.id,\n pluginId: this.pluginId,\n scope: task.scope,\n settings: task.settings,\n taskState:\n this.localWorkersById.get(task.id)?.taskState() ??\n globalState.get(task.id) ??\n null,\n workerState:\n this.localWorkersById.get(task.id)?.workerState() ??\n this.globalWorkersById.get(task.id)?.workerState() ??\n null,\n });\n }\n\n res.json({ tasks });\n });\n\n router.post(\n '/.backstage/scheduler/v1/tasks/:id/trigger',\n async (req, res) => {\n const { id } = req.params;\n await this.triggerTask(id);\n res.status(200).end();\n },\n );\n\n return router;\n }\n\n private instrumentedFunction(\n task: SchedulerServiceTaskInvocationDefinition,\n scope: string,\n ): SchedulerServiceTaskFunction {\n return async abort => {\n const labels: Record<string, string> = {\n taskId: task.id,\n scope,\n };\n this.counter.add(1, { ...labels, result: 'started' });\n this.lastStarted.record(Date.now() / 1000, { taskId: task.id });\n\n const startTime = process.hrtime();\n\n try {\n await tracer.startActiveSpan(`task ${task.id}`, async span => {\n try {\n span.setAttributes(labels);\n await task.fn(abort);\n } catch (error) {\n if (error instanceof Error) {\n span.recordException(error);\n }\n throw error;\n } finally {\n span.end();\n }\n });\n labels.result = 'completed';\n } catch (ex) {\n labels.result = 'failed';\n throw ex;\n } finally {\n const delta = process.hrtime(startTime);\n const endTime = delta[0] + delta[1] / 1e9;\n this.counter.add(1, labels);\n this.duration.record(endTime, labels);\n this.lastCompleted.record(Date.now() / 1000, labels);\n }\n };\n }\n}\n\nexport function parseDuration(\n frequency: SchedulerServiceTaskScheduleDefinition['frequency'],\n): string {\n if (typeof frequency === 'object' && 'cron' in frequency) {\n return frequency.cron;\n }\n if (typeof frequency === 'object' && 'trigger' in frequency) {\n return frequency.trigger;\n }\n\n const parsed = Duration.isDuration(frequency)\n ? frequency\n : Duration.fromObject(frequency);\n\n if (!parsed.isValid) {\n throw new Error(\n `Invalid duration, ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n\n return parsed.toISO()!;\n}\n"],"names":["trace","TRACER_ID","TaskWorker","validateId","delegateAbortController","LocalTaskWorker","Router","Duration"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var backendPluginApi = require('@backstage/backend-plugin-api');
4
+ var alpha = require('@backstage/backend-plugin-api/alpha');
4
5
  var DefaultSchedulerService = require('./lib/DefaultSchedulerService.cjs.js');
5
6
 
6
7
  const schedulerServiceFactory = backendPluginApi.createServiceFactory({
@@ -10,21 +11,24 @@ const schedulerServiceFactory = backendPluginApi.createServiceFactory({
10
11
  logger: backendPluginApi.coreServices.logger,
11
12
  rootLifecycle: backendPluginApi.coreServices.rootLifecycle,
12
13
  httpRouter: backendPluginApi.coreServices.httpRouter,
13
- pluginMetadata: backendPluginApi.coreServices.pluginMetadata
14
+ pluginMetadata: backendPluginApi.coreServices.pluginMetadata,
15
+ metrics: alpha.metricsServiceRef
14
16
  },
15
17
  async factory({
16
18
  database,
17
19
  logger,
18
20
  rootLifecycle,
19
21
  httpRouter,
20
- pluginMetadata
22
+ pluginMetadata,
23
+ metrics
21
24
  }) {
22
25
  return DefaultSchedulerService.DefaultSchedulerService.create({
23
26
  database,
24
27
  logger,
25
28
  rootLifecycle,
26
29
  httpRouter,
27
- pluginMetadata
30
+ pluginMetadata,
31
+ metrics
28
32
  });
29
33
  }
30
34
  });
@@ -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 httpRouter: coreServices.httpRouter,\n pluginMetadata: coreServices.pluginMetadata,\n },\n async factory({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n }) {\n return DefaultSchedulerService.create({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n });\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultSchedulerService"],"mappings":";;;;;AA+BO,MAAM,0BAA0BA,qCAAA,CAAqB;AAAA,EAC1D,SAASC,6BAAA,CAAa,SAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,UAAUA,6BAAA,CAAa,QAAA;AAAA,IACvB,QAAQA,6BAAA,CAAa,MAAA;AAAA,IACrB,eAAeA,6BAAA,CAAa,aAAA;AAAA,IAC5B,YAAYA,6BAAA,CAAa,UAAA;AAAA,IACzB,gBAAgBA,6BAAA,CAAa;AAAA,GAC/B;AAAA,EACA,MAAM,OAAA,CAAQ;AAAA,IACZ,QAAA;AAAA,IACA,MAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF,EAAG;AACD,IAAA,OAAOC,gDAAwB,MAAA,CAAO;AAAA,MACpC,QAAA;AAAA,MACA,MAAA;AAAA,MACA,aAAA;AAAA,MACA,UAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
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 { metricsServiceRef } from '@backstage/backend-plugin-api/alpha';\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 httpRouter: coreServices.httpRouter,\n pluginMetadata: coreServices.pluginMetadata,\n metrics: metricsServiceRef,\n },\n async factory({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n metrics,\n }) {\n return DefaultSchedulerService.create({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n metrics,\n });\n },\n});\n"],"names":["createServiceFactory","coreServices","metricsServiceRef","DefaultSchedulerService"],"mappings":";;;;;;AAgCO,MAAM,0BAA0BA,qCAAA,CAAqB;AAAA,EAC1D,SAASC,6BAAA,CAAa,SAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,UAAUA,6BAAA,CAAa,QAAA;AAAA,IACvB,QAAQA,6BAAA,CAAa,MAAA;AAAA,IACrB,eAAeA,6BAAA,CAAa,aAAA;AAAA,IAC5B,YAAYA,6BAAA,CAAa,UAAA;AAAA,IACzB,gBAAgBA,6BAAA,CAAa,cAAA;AAAA,IAC7B,OAAA,EAASC;AAAA,GACX;AAAA,EACA,MAAM,OAAA,CAAQ;AAAA,IACZ,QAAA;AAAA,IACA,MAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACF,EAAG;AACD,IAAA,OAAOC,gDAAwB,MAAA,CAAO;AAAA,MACpC,QAAA;AAAA,MACA,MAAA;AAAA,MACA,aAAA;AAAA,MACA,UAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
@@ -4,7 +4,6 @@ var UrlReaderPredicateMux = require('./UrlReaderPredicateMux.cjs.js');
4
4
  var AzureUrlReader = require('./AzureUrlReader.cjs.js');
5
5
  var BitbucketCloudUrlReader = require('./BitbucketCloudUrlReader.cjs.js');
6
6
  var BitbucketServerUrlReader = require('./BitbucketServerUrlReader.cjs.js');
7
- var BitbucketUrlReader = require('./BitbucketUrlReader.cjs.js');
8
7
  var GerritUrlReader = require('./GerritUrlReader.cjs.js');
9
8
  var GithubUrlReader = require('./GithubUrlReader.cjs.js');
10
9
  var GitlabUrlReader = require('./GitlabUrlReader.cjs.js');
@@ -50,7 +49,6 @@ class UrlReaders {
50
49
  AzureUrlReader.AzureUrlReader.factory,
51
50
  BitbucketCloudUrlReader.BitbucketCloudUrlReader.factory,
52
51
  BitbucketServerUrlReader.BitbucketServerUrlReader.factory,
53
- BitbucketUrlReader.BitbucketUrlReader.factory,
54
52
  GerritUrlReader.GerritUrlReader.factory,
55
53
  GithubUrlReader.GithubUrlReader.factory,
56
54
  GiteaUrlReader.GiteaUrlReader.factory,
@@ -1 +1 @@
1
- {"version":3,"file":"UrlReaders.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/UrlReaders.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 LoggerService,\n RootConfigService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { ReaderFactory } from './types';\nimport { UrlReaderPredicateMux } from './UrlReaderPredicateMux';\nimport { AzureUrlReader } from './AzureUrlReader';\nimport { BitbucketCloudUrlReader } from './BitbucketCloudUrlReader';\nimport { BitbucketServerUrlReader } from './BitbucketServerUrlReader';\nimport { BitbucketUrlReader } from './BitbucketUrlReader';\nimport { GerritUrlReader } from './GerritUrlReader';\nimport { GithubUrlReader } from './GithubUrlReader';\nimport { GitlabUrlReader } from './GitlabUrlReader';\nimport { DefaultReadTreeResponseFactory } from './tree';\nimport { FetchUrlReader } from './FetchUrlReader';\nimport { GoogleGcsUrlReader } from './GoogleGcsUrlReader';\nimport { AwsS3UrlReader } from './AwsS3UrlReader';\nimport { GiteaUrlReader } from './GiteaUrlReader';\nimport { AwsCodeCommitUrlReader } from './AwsCodeCommitUrlReader';\nimport { HarnessUrlReader } from './HarnessUrlReader';\nimport { AzureBlobStorageUrlReader } from './AzureBlobStorageUrlReader';\n\n/**\n * Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}.\n *\n * @public\n */\nexport type UrlReadersOptions = {\n /** Root config object */\n config: RootConfigService;\n /** Logger used by all the readers */\n logger: LoggerService;\n /** A list of factories used to construct individual readers that match on URLs */\n factories?: ReaderFactory[];\n};\n\n/**\n * Helps construct {@link @backstage/backend-plugin-api#UrlReaderService}s.\n *\n * @public\n */\nexport class UrlReaders {\n /**\n * Creates a custom {@link @backstage/backend-plugin-api#UrlReaderService} wrapper for your own set of factories.\n */\n static create(options: UrlReadersOptions): UrlReaderService {\n const { logger, config, factories } = options;\n const mux = new UrlReaderPredicateMux();\n const treeResponseFactory = DefaultReadTreeResponseFactory.create({\n config,\n });\n for (const factory of factories ?? []) {\n const tuples = factory({ config, logger: logger, treeResponseFactory });\n\n for (const tuple of tuples) {\n mux.register(tuple);\n }\n }\n\n return mux;\n }\n\n /**\n * Creates a {@link @backstage/backend-plugin-api#UrlReaderService} wrapper that includes all the default factories\n * from this package.\n *\n * Any additional factories passed will be loaded before the default ones.\n */\n static default(options: UrlReadersOptions) {\n const { logger, config, factories = [] } = options;\n return UrlReaders.create({\n logger,\n config,\n factories: factories.concat([\n AzureUrlReader.factory,\n BitbucketCloudUrlReader.factory,\n BitbucketServerUrlReader.factory,\n BitbucketUrlReader.factory,\n GerritUrlReader.factory,\n GithubUrlReader.factory,\n GiteaUrlReader.factory,\n GitlabUrlReader.factory,\n GoogleGcsUrlReader.factory,\n HarnessUrlReader.factory,\n AwsS3UrlReader.factory,\n AzureBlobStorageUrlReader.factory,\n AwsCodeCommitUrlReader.factory,\n FetchUrlReader.factory,\n ]),\n });\n }\n}\n"],"names":["UrlReaderPredicateMux","DefaultReadTreeResponseFactory","AzureUrlReader","BitbucketCloudUrlReader","BitbucketServerUrlReader","BitbucketUrlReader","GerritUrlReader","GithubUrlReader","GiteaUrlReader","GitlabUrlReader","GoogleGcsUrlReader","HarnessUrlReader","AwsS3UrlReader","AzureBlobStorageUrlReader","AwsCodeCommitUrlReader","FetchUrlReader"],"mappings":";;;;;;;;;;;;;;;;;;;AA0DO,MAAM,UAAA,CAAW;AAAA;AAAA;AAAA;AAAA,EAItB,OAAO,OAAO,OAAA,EAA8C;AAC1D,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,SAAA,EAAU,GAAI,OAAA;AACtC,IAAA,MAAM,GAAA,GAAM,IAAIA,2CAAA,EAAsB;AACtC,IAAA,MAAM,mBAAA,GAAsBC,uDAA+B,MAAA,CAAO;AAAA,MAChE;AAAA,KACD,CAAA;AACD,IAAA,KAAA,MAAW,OAAA,IAAW,SAAA,IAAa,EAAC,EAAG;AACrC,MAAA,MAAM,SAAS,OAAA,CAAQ,EAAE,MAAA,EAAQ,MAAA,EAAgB,qBAAqB,CAAA;AAEtE,MAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,QAAA,GAAA,CAAI,SAAS,KAAK,CAAA;AAAA,MACpB;AAAA,IACF;AAEA,IAAA,OAAO,GAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,QAAQ,OAAA,EAA4B;AACzC,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,SAAA,GAAY,IAAG,GAAI,OAAA;AAC3C,IAAA,OAAO,WAAW,MAAA,CAAO;AAAA,MACvB,MAAA;AAAA,MACA,MAAA;AAAA,MACA,SAAA,EAAW,UAAU,MAAA,CAAO;AAAA,QAC1BC,6BAAA,CAAe,OAAA;AAAA,QACfC,+CAAA,CAAwB,OAAA;AAAA,QACxBC,iDAAA,CAAyB,OAAA;AAAA,QACzBC,qCAAA,CAAmB,OAAA;AAAA,QACnBC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,6BAAA,CAAe,OAAA;AAAA,QACfC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,qCAAA,CAAmB,OAAA;AAAA,QACnBC,iCAAA,CAAiB,OAAA;AAAA,QACjBC,6BAAA,CAAe,OAAA;AAAA,QACfC,mDAAA,CAA0B,OAAA;AAAA,QAC1BC,6CAAA,CAAuB,OAAA;AAAA,QACvBC,6BAAA,CAAe;AAAA,OAChB;AAAA,KACF,CAAA;AAAA,EACH;AACF;;;;"}
1
+ {"version":3,"file":"UrlReaders.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/UrlReaders.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 LoggerService,\n RootConfigService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { ReaderFactory } from './types';\nimport { UrlReaderPredicateMux } from './UrlReaderPredicateMux';\nimport { AzureUrlReader } from './AzureUrlReader';\nimport { BitbucketCloudUrlReader } from './BitbucketCloudUrlReader';\nimport { BitbucketServerUrlReader } from './BitbucketServerUrlReader';\nimport { GerritUrlReader } from './GerritUrlReader';\nimport { GithubUrlReader } from './GithubUrlReader';\nimport { GitlabUrlReader } from './GitlabUrlReader';\nimport { DefaultReadTreeResponseFactory } from './tree';\nimport { FetchUrlReader } from './FetchUrlReader';\nimport { GoogleGcsUrlReader } from './GoogleGcsUrlReader';\nimport { AwsS3UrlReader } from './AwsS3UrlReader';\nimport { GiteaUrlReader } from './GiteaUrlReader';\nimport { AwsCodeCommitUrlReader } from './AwsCodeCommitUrlReader';\nimport { HarnessUrlReader } from './HarnessUrlReader';\nimport { AzureBlobStorageUrlReader } from './AzureBlobStorageUrlReader';\n\n/**\n * Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}.\n *\n * @public\n */\nexport type UrlReadersOptions = {\n /** Root config object */\n config: RootConfigService;\n /** Logger used by all the readers */\n logger: LoggerService;\n /** A list of factories used to construct individual readers that match on URLs */\n factories?: ReaderFactory[];\n};\n\n/**\n * Helps construct {@link @backstage/backend-plugin-api#UrlReaderService}s.\n *\n * @public\n */\nexport class UrlReaders {\n /**\n * Creates a custom {@link @backstage/backend-plugin-api#UrlReaderService} wrapper for your own set of factories.\n */\n static create(options: UrlReadersOptions): UrlReaderService {\n const { logger, config, factories } = options;\n const mux = new UrlReaderPredicateMux();\n const treeResponseFactory = DefaultReadTreeResponseFactory.create({\n config,\n });\n for (const factory of factories ?? []) {\n const tuples = factory({ config, logger: logger, treeResponseFactory });\n\n for (const tuple of tuples) {\n mux.register(tuple);\n }\n }\n\n return mux;\n }\n\n /**\n * Creates a {@link @backstage/backend-plugin-api#UrlReaderService} wrapper that includes all the default factories\n * from this package.\n *\n * Any additional factories passed will be loaded before the default ones.\n */\n static default(options: UrlReadersOptions) {\n const { logger, config, factories = [] } = options;\n return UrlReaders.create({\n logger,\n config,\n factories: factories.concat([\n AzureUrlReader.factory,\n BitbucketCloudUrlReader.factory,\n BitbucketServerUrlReader.factory,\n GerritUrlReader.factory,\n GithubUrlReader.factory,\n GiteaUrlReader.factory,\n GitlabUrlReader.factory,\n GoogleGcsUrlReader.factory,\n HarnessUrlReader.factory,\n AwsS3UrlReader.factory,\n AzureBlobStorageUrlReader.factory,\n AwsCodeCommitUrlReader.factory,\n FetchUrlReader.factory,\n ]),\n });\n }\n}\n"],"names":["UrlReaderPredicateMux","DefaultReadTreeResponseFactory","AzureUrlReader","BitbucketCloudUrlReader","BitbucketServerUrlReader","GerritUrlReader","GithubUrlReader","GiteaUrlReader","GitlabUrlReader","GoogleGcsUrlReader","HarnessUrlReader","AwsS3UrlReader","AzureBlobStorageUrlReader","AwsCodeCommitUrlReader","FetchUrlReader"],"mappings":";;;;;;;;;;;;;;;;;;AAyDO,MAAM,UAAA,CAAW;AAAA;AAAA;AAAA;AAAA,EAItB,OAAO,OAAO,OAAA,EAA8C;AAC1D,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,SAAA,EAAU,GAAI,OAAA;AACtC,IAAA,MAAM,GAAA,GAAM,IAAIA,2CAAA,EAAsB;AACtC,IAAA,MAAM,mBAAA,GAAsBC,uDAA+B,MAAA,CAAO;AAAA,MAChE;AAAA,KACD,CAAA;AACD,IAAA,KAAA,MAAW,OAAA,IAAW,SAAA,IAAa,EAAC,EAAG;AACrC,MAAA,MAAM,SAAS,OAAA,CAAQ,EAAE,MAAA,EAAQ,MAAA,EAAgB,qBAAqB,CAAA;AAEtE,MAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,QAAA,GAAA,CAAI,SAAS,KAAK,CAAA;AAAA,MACpB;AAAA,IACF;AAEA,IAAA,OAAO,GAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,QAAQ,OAAA,EAA4B;AACzC,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,SAAA,GAAY,IAAG,GAAI,OAAA;AAC3C,IAAA,OAAO,WAAW,MAAA,CAAO;AAAA,MACvB,MAAA;AAAA,MACA,MAAA;AAAA,MACA,SAAA,EAAW,UAAU,MAAA,CAAO;AAAA,QAC1BC,6BAAA,CAAe,OAAA;AAAA,QACfC,+CAAA,CAAwB,OAAA;AAAA,QACxBC,iDAAA,CAAyB,OAAA;AAAA,QACzBC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,6BAAA,CAAe,OAAA;AAAA,QACfC,+BAAA,CAAgB,OAAA;AAAA,QAChBC,qCAAA,CAAmB,OAAA;AAAA,QACnBC,iCAAA,CAAiB,OAAA;AAAA,QACjBC,6BAAA,CAAe,OAAA;AAAA,QACfC,mDAAA,CAA0B,OAAA;AAAA,QAC1BC,6CAAA,CAAuB,OAAA;AAAA,QACvBC,6BAAA,CAAe;AAAA,OAChB;AAAA,KACF,CAAA;AAAA,EACH;AACF;;;;"}
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = "0.15.3-next.0";
5
+ var version = "0.16.0-next.1";
6
6
  var packageinfo = {
7
7
  version: version};
8
8
 
@@ -1,5 +1,6 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
2
  import { DatabaseService, LoggerService, RootLifecycleService, HttpRouterService, PluginMetadataService, SchedulerService } from '@backstage/backend-plugin-api';
3
+ import { MetricsService } from '@backstage/backend-plugin-api/alpha';
3
4
 
4
5
  /**
5
6
  * Default implementation of the task scheduler service.
@@ -10,6 +11,7 @@ declare class DefaultSchedulerService {
10
11
  static create(options: {
11
12
  database: DatabaseService;
12
13
  logger: LoggerService;
14
+ metrics: MetricsService;
13
15
  rootLifecycle: RootLifecycleService;
14
16
  httpRouter: HttpRouterService;
15
17
  pluginMetadata: PluginMetadataService;
@@ -2,7 +2,6 @@
2
2
 
3
3
  var AzureUrlReader = require('./entrypoints/urlReader/lib/AzureUrlReader.cjs.js');
4
4
  var BitbucketCloudUrlReader = require('./entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js');
5
- var BitbucketUrlReader = require('./entrypoints/urlReader/lib/BitbucketUrlReader.cjs.js');
6
5
  var BitbucketServerUrlReader = require('./entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js');
7
6
  var GerritUrlReader = require('./entrypoints/urlReader/lib/GerritUrlReader.cjs.js');
8
7
  var GithubUrlReader = require('./entrypoints/urlReader/lib/GithubUrlReader.cjs.js');
@@ -20,7 +19,6 @@ var urlReaderServiceFactory = require('./entrypoints/urlReader/urlReaderServiceF
20
19
 
21
20
  exports.AzureUrlReader = AzureUrlReader.AzureUrlReader;
22
21
  exports.BitbucketCloudUrlReader = BitbucketCloudUrlReader.BitbucketCloudUrlReader;
23
- exports.BitbucketUrlReader = BitbucketUrlReader.BitbucketUrlReader;
24
22
  exports.BitbucketServerUrlReader = BitbucketServerUrlReader.BitbucketServerUrlReader;
25
23
  exports.GerritUrlReader = GerritUrlReader.GerritUrlReader;
26
24
  exports.GithubUrlReader = GithubUrlReader.GithubUrlReader;
@@ -1 +1 @@
1
- {"version":3,"file":"urlReader.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"urlReader.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,6 +1,6 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
2
  import { RootConfigService, LoggerService, UrlReaderServiceReadTreeResponse, UrlReaderService, UrlReaderServiceReadUrlOptions, UrlReaderServiceReadUrlResponse, UrlReaderServiceReadTreeOptions, UrlReaderServiceSearchOptions, UrlReaderServiceSearchResponse } from '@backstage/backend-plugin-api';
3
- import { AzureIntegration, AzureDevOpsCredentialsProvider, BitbucketCloudIntegration, BitbucketIntegration, BitbucketServerIntegration, GerritIntegration, GithubIntegration, GithubCredentialsProvider, GitLabIntegration, GiteaIntegration, HarnessIntegration, AwsS3Integration, AzureCredentialsManager, AzureBlobStorageIntergation } from '@backstage/integration';
3
+ import { AzureIntegration, AzureDevOpsCredentialsProvider, BitbucketCloudIntegration, BitbucketServerIntegration, GerritIntegration, GithubIntegration, GithubCredentialsProvider, GitLabIntegration, GiteaIntegration, HarnessIntegration, AwsS3Integration, AzureCredentialsManager, AzureBlobStorageIntergation } from '@backstage/integration';
4
4
  import { Readable } from 'node:stream';
5
5
  import { AwsCredentialsManager } from '@backstage/integration-aws-node';
6
6
  import { Config } from '@backstage/config';
@@ -137,29 +137,6 @@ declare class BitbucketCloudUrlReader implements UrlReaderService {
137
137
  private getLastCommitShortHash;
138
138
  }
139
139
 
140
- /**
141
- * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket v1 and v2 APIs, such
142
- * as the one exposed by Bitbucket Cloud itself.
143
- *
144
- * @public
145
- * @deprecated in favor of BitbucketCloudUrlReader and BitbucketServerUrlReader
146
- */
147
- declare class BitbucketUrlReader implements UrlReaderService {
148
- static factory: ReaderFactory;
149
- private readonly integration;
150
- private readonly deps;
151
- constructor(integration: BitbucketIntegration, logger: LoggerService, deps: {
152
- treeResponseFactory: ReadTreeResponseFactory;
153
- });
154
- read(url: string): Promise<Buffer>;
155
- private getCredentials;
156
- readUrl(url: string, options?: UrlReaderServiceReadUrlOptions): Promise<UrlReaderServiceReadUrlResponse>;
157
- readTree(url: string, options?: UrlReaderServiceReadTreeOptions): Promise<UrlReaderServiceReadTreeResponse>;
158
- search(url: string, options?: UrlReaderServiceSearchOptions): Promise<UrlReaderServiceSearchResponse>;
159
- toString(): string;
160
- private getLastCommitShortHash;
161
- }
162
-
163
140
  /**
164
141
  * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Server APIs.
165
142
  *
@@ -478,5 +455,5 @@ declare const urlReaderFactoriesServiceRef: _backstage_backend_plugin_api.Servic
478
455
  */
479
456
  declare const urlReaderServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.UrlReaderService, "plugin", "singleton">;
480
457
 
481
- export { AwsS3UrlReader, AzureBlobStorageUrlReader, AzureUrlReader, BitbucketCloudUrlReader, BitbucketServerUrlReader, BitbucketUrlReader, FetchUrlReader, GerritUrlReader, GiteaUrlReader, GithubUrlReader, GitlabUrlReader, HarnessUrlReader, ReadUrlResponseFactory, UrlReaders, urlReaderFactoriesServiceRef, urlReaderServiceFactory };
458
+ export { AwsS3UrlReader, AzureBlobStorageUrlReader, AzureUrlReader, BitbucketCloudUrlReader, BitbucketServerUrlReader, FetchUrlReader, GerritUrlReader, GiteaUrlReader, GithubUrlReader, GitlabUrlReader, HarnessUrlReader, ReadUrlResponseFactory, UrlReaders, urlReaderFactoriesServiceRef, urlReaderServiceFactory };
482
459
  export type { FromReadableArrayOptions, ReadTreeResponseFactory, ReadTreeResponseFactoryOptions, ReadUrlResponseFactoryFromStreamOptions, ReaderFactory, UrlReaderPredicateTuple, UrlReadersOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-defaults",
3
- "version": "0.15.3-next.0",
3
+ "version": "0.16.0-next.1",
4
4
  "description": "Backend defaults used by Backstage backend apps",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -220,13 +220,13 @@
220
220
  "@backstage/backend-app-api": "1.5.1-next.0",
221
221
  "@backstage/backend-dev-utils": "0.1.7",
222
222
  "@backstage/backend-plugin-api": "1.7.1-next.0",
223
- "@backstage/cli-node": "0.2.19-next.0",
223
+ "@backstage/cli-node": "0.2.19-next.1",
224
224
  "@backstage/config": "1.3.6",
225
225
  "@backstage/config-loader": "1.10.9-next.0",
226
226
  "@backstage/errors": "1.2.7",
227
- "@backstage/integration": "1.21.0-next.0",
227
+ "@backstage/integration": "2.0.0-next.1",
228
228
  "@backstage/integration-aws-node": "0.1.20",
229
- "@backstage/plugin-auth-node": "0.6.14-next.0",
229
+ "@backstage/plugin-auth-node": "0.6.14-next.1",
230
230
  "@backstage/plugin-events-node": "0.4.20-next.0",
231
231
  "@backstage/plugin-permission-node": "0.10.11-next.0",
232
232
  "@backstage/types": "1.2.2",
@@ -285,8 +285,8 @@
285
285
  "devDependencies": {
286
286
  "@aws-sdk/util-stream-node": "^3.350.0",
287
287
  "@backstage/backend-plugin-api": "1.7.1-next.0",
288
- "@backstage/backend-test-utils": "1.11.1-next.0",
289
- "@backstage/cli": "0.35.5-next.0",
288
+ "@backstage/backend-test-utils": "1.11.1-next.1",
289
+ "@backstage/cli": "0.36.0-next.1",
290
290
  "@google-cloud/cloud-sql-connector": "^1.4.0",
291
291
  "@types/archiver": "^7.0.0",
292
292
  "@types/base64-stream": "^1.0.2",
@@ -1,209 +0,0 @@
1
- 'use strict';
2
-
3
- var errors = require('@backstage/errors');
4
- var integration = require('@backstage/integration');
5
- var parseGitUrl = require('git-url-parse');
6
- var lodash = require('lodash');
7
- var minimatch = require('minimatch');
8
- var ReadUrlResponseFactory = require('./ReadUrlResponseFactory.cjs.js');
9
-
10
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
11
-
12
- var parseGitUrl__default = /*#__PURE__*/_interopDefaultCompat(parseGitUrl);
13
-
14
- class BitbucketUrlReader {
15
- static factory = ({ config, logger, treeResponseFactory }) => {
16
- const integrations = integration.ScmIntegrations.fromConfig(config);
17
- return integrations.bitbucket.list().filter(
18
- (item) => !integrations.bitbucketCloud.byHost(item.config.host) && !integrations.bitbucketServer.byHost(item.config.host)
19
- ).map((integration) => {
20
- const reader = new BitbucketUrlReader(integration, logger, {
21
- treeResponseFactory
22
- });
23
- const predicate = (url) => url.host === integration.config.host;
24
- return { reader, predicate };
25
- });
26
- };
27
- integration;
28
- deps;
29
- constructor(integration, logger, deps) {
30
- this.integration = integration;
31
- this.deps = deps;
32
- const { host, token, username, appPassword } = integration.config;
33
- const replacement = host === "bitbucket.org" ? "bitbucketCloud" : "bitbucketServer";
34
- logger.warn(
35
- `[Deprecated] Please migrate from "integrations.bitbucket" to "integrations.${replacement}".`
36
- );
37
- if (!token && username && !appPassword) {
38
- throw new Error(
39
- `Bitbucket integration for '${host}' has configured a username but is missing a required appPassword.`
40
- );
41
- }
42
- }
43
- async read(url) {
44
- const response = await this.readUrl(url);
45
- return response.buffer();
46
- }
47
- getCredentials = async (options) => {
48
- if (options?.token) {
49
- return {
50
- headers: {
51
- Authorization: `Bearer ${options.token}`
52
- }
53
- };
54
- }
55
- return await integration.getBitbucketRequestOptions(this.integration.config);
56
- };
57
- async readUrl(url, options) {
58
- const { etag, lastModifiedAfter, signal } = options ?? {};
59
- const bitbucketUrl = integration.getBitbucketFileFetchUrl(url, this.integration.config);
60
- const requestOptions = await this.getCredentials(options);
61
- let response;
62
- try {
63
- response = await fetch(bitbucketUrl.toString(), {
64
- headers: {
65
- ...requestOptions.headers,
66
- ...etag && { "If-None-Match": etag },
67
- ...lastModifiedAfter && {
68
- "If-Modified-Since": lastModifiedAfter.toUTCString()
69
- }
70
- },
71
- // TODO(freben): The signal cast is there because pre-3.x versions of
72
- // node-fetch have a very slightly deviating AbortSignal type signature.
73
- // The difference does not affect us in practice however. The cast can be
74
- // removed after we support ESM for CLI dependencies and migrate to
75
- // version 3 of node-fetch.
76
- // https://github.com/backstage/backstage/issues/8242
77
- ...signal && { signal }
78
- });
79
- } catch (e) {
80
- throw new Error(`Unable to read ${url}, ${e}`);
81
- }
82
- if (response.status === 304) {
83
- throw new errors.NotModifiedError();
84
- }
85
- if (response.ok) {
86
- return ReadUrlResponseFactory.ReadUrlResponseFactory.fromResponse(response);
87
- }
88
- const message = `${url} could not be read as ${bitbucketUrl}, ${response.status} ${response.statusText}`;
89
- if (response.status === 404) {
90
- throw new errors.NotFoundError(message);
91
- }
92
- throw new Error(message);
93
- }
94
- async readTree(url, options) {
95
- const { filepath } = parseGitUrl__default.default(url);
96
- const lastCommitShortHash = await this.getLastCommitShortHash(url);
97
- if (options?.etag && options.etag === lastCommitShortHash) {
98
- throw new errors.NotModifiedError();
99
- }
100
- const downloadUrl = await integration.getBitbucketDownloadUrl(
101
- url,
102
- this.integration.config
103
- );
104
- const archiveBitbucketResponse = await fetch(
105
- downloadUrl,
106
- integration.getBitbucketRequestOptions(this.integration.config)
107
- );
108
- if (!archiveBitbucketResponse.ok) {
109
- const message = `Failed to read tree from ${url}, ${archiveBitbucketResponse.status} ${archiveBitbucketResponse.statusText}`;
110
- if (archiveBitbucketResponse.status === 404) {
111
- throw new errors.NotFoundError(message);
112
- }
113
- throw new Error(message);
114
- }
115
- return await this.deps.treeResponseFactory.fromTarArchive({
116
- response: archiveBitbucketResponse,
117
- subpath: filepath,
118
- etag: lastCommitShortHash,
119
- filter: options?.filter
120
- });
121
- }
122
- async search(url, options) {
123
- const { filepath } = parseGitUrl__default.default(url);
124
- if (!filepath?.match(/[*?]/)) {
125
- try {
126
- const data = await this.readUrl(url, options);
127
- return {
128
- files: [
129
- {
130
- url,
131
- content: data.buffer,
132
- lastModifiedAt: data.lastModifiedAt
133
- }
134
- ],
135
- etag: data.etag ?? ""
136
- };
137
- } catch (error) {
138
- errors.assertError(error);
139
- if (error.name === "NotFoundError") {
140
- return {
141
- files: [],
142
- etag: ""
143
- };
144
- }
145
- throw error;
146
- }
147
- }
148
- const matcher = new minimatch.Minimatch(filepath);
149
- const treeUrl = lodash.trimEnd(url.replace(filepath, ""), "/");
150
- const tree = await this.readTree(treeUrl, {
151
- etag: options?.etag,
152
- filter: (path) => matcher.match(path)
153
- });
154
- const files = await tree.files();
155
- return {
156
- etag: tree.etag,
157
- files: files.map((file) => ({
158
- url: this.integration.resolveUrl({
159
- url: `/${file.path}`,
160
- base: url
161
- }),
162
- content: file.content,
163
- lastModifiedAt: file.lastModifiedAt
164
- }))
165
- };
166
- }
167
- toString() {
168
- const { host, token, username, appPassword } = this.integration.config;
169
- let authed = Boolean(token);
170
- if (!authed) {
171
- authed = Boolean(username && appPassword);
172
- }
173
- return `bitbucket{host=${host},authed=${authed}}`;
174
- }
175
- async getLastCommitShortHash(url) {
176
- const { resource, name: repoName, owner: project, ref } = parseGitUrl__default.default(url);
177
- let branch = ref;
178
- if (!branch) {
179
- branch = await integration.getBitbucketDefaultBranch(url, this.integration.config);
180
- }
181
- const isHosted = resource === "bitbucket.org";
182
- const commitsApiUrl = isHosted ? `${this.integration.config.apiBaseUrl}/repositories/${project}/${repoName}/commits/${branch}` : `${this.integration.config.apiBaseUrl}/projects/${project}/repos/${repoName}/commits`;
183
- const commitsResponse = await fetch(
184
- commitsApiUrl,
185
- integration.getBitbucketRequestOptions(this.integration.config)
186
- );
187
- if (!commitsResponse.ok) {
188
- const message = `Failed to retrieve commits from ${commitsApiUrl}, ${commitsResponse.status} ${commitsResponse.statusText}`;
189
- if (commitsResponse.status === 404) {
190
- throw new errors.NotFoundError(message);
191
- }
192
- throw new Error(message);
193
- }
194
- const commits = await commitsResponse.json();
195
- if (isHosted) {
196
- if (commits && commits.values && commits.values.length > 0 && commits.values[0].hash) {
197
- return commits.values[0].hash.substring(0, 12);
198
- }
199
- } else {
200
- if (commits && commits.values && commits.values.length > 0 && commits.values[0].id) {
201
- return commits.values[0].id.substring(0, 12);
202
- }
203
- }
204
- throw new Error(`Failed to read response from ${commitsApiUrl}`);
205
- }
206
- }
207
-
208
- exports.BitbucketUrlReader = BitbucketUrlReader;
209
- //# sourceMappingURL=BitbucketUrlReader.cjs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BitbucketUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/BitbucketUrlReader.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 assertError,\n NotFoundError,\n NotModifiedError,\n} from '@backstage/errors';\nimport {\n BitbucketIntegration,\n getBitbucketDefaultBranch,\n getBitbucketDownloadUrl,\n getBitbucketFileFetchUrl,\n getBitbucketRequestOptions,\n ScmIntegrations,\n} from '@backstage/integration';\nimport parseGitUrl from 'git-url-parse';\nimport { trimEnd } from 'lodash';\nimport { Minimatch } from 'minimatch';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket v1 and v2 APIs, such\n * as the one exposed by Bitbucket Cloud itself.\n *\n * @public\n * @deprecated in favor of BitbucketCloudUrlReader and BitbucketServerUrlReader\n */\nexport class BitbucketUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, logger, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n return integrations.bitbucket\n .list()\n .filter(\n item =>\n !integrations.bitbucketCloud.byHost(item.config.host) &&\n !integrations.bitbucketServer.byHost(item.config.host),\n )\n .map(integration => {\n const reader = new BitbucketUrlReader(integration, logger, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => url.host === integration.config.host;\n return { reader, predicate };\n });\n };\n\n private readonly integration: BitbucketIntegration;\n private readonly deps: { treeResponseFactory: ReadTreeResponseFactory };\n\n constructor(\n integration: BitbucketIntegration,\n logger: LoggerService,\n deps: { treeResponseFactory: ReadTreeResponseFactory },\n ) {\n this.integration = integration;\n this.deps = deps;\n const { host, token, username, appPassword } = integration.config;\n const replacement =\n host === 'bitbucket.org' ? 'bitbucketCloud' : 'bitbucketServer';\n logger.warn(\n `[Deprecated] Please migrate from \"integrations.bitbucket\" to \"integrations.${replacement}\".`,\n );\n\n if (!token && username && !appPassword) {\n throw new Error(\n `Bitbucket 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 private getCredentials = async (options?: {\n token?: string;\n }): Promise<{ headers: Record<string, string> }> => {\n if (options?.token) {\n return {\n headers: {\n Authorization: `Bearer ${options.token}`,\n },\n };\n }\n\n return await getBitbucketRequestOptions(this.integration.config);\n };\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const { etag, lastModifiedAfter, signal } = options ?? {};\n const bitbucketUrl = getBitbucketFileFetchUrl(url, this.integration.config);\n const requestOptions = await this.getCredentials(options);\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.fromResponse(response);\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 getBitbucketDownloadUrl(\n url,\n this.integration.config,\n );\n const archiveBitbucketResponse = await fetch(\n downloadUrl,\n getBitbucketRequestOptions(this.integration.config),\n );\n if (!archiveBitbucketResponse.ok) {\n const message = `Failed to read tree from ${url}, ${archiveBitbucketResponse.status} ${archiveBitbucketResponse.statusText}`;\n if (archiveBitbucketResponse.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n return await this.deps.treeResponseFactory.fromTarArchive({\n response: archiveBitbucketResponse,\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\n // If it's a direct URL we use readUrl instead\n if (!filepath?.match(/[*?]/)) {\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (error) {\n assertError(error);\n if (error.name === 'NotFoundError') {\n return {\n files: [],\n etag: '',\n };\n }\n throw error;\n }\n }\n\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, token, username, appPassword } = this.integration.config;\n let authed = Boolean(token);\n if (!authed) {\n authed = Boolean(username && appPassword);\n }\n return `bitbucket{host=${host},authed=${authed}}`;\n }\n\n private async getLastCommitShortHash(url: string): Promise<string> {\n const { resource, name: repoName, owner: project, ref } = parseGitUrl(url);\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketDefaultBranch(url, this.integration.config);\n }\n\n const isHosted = resource === 'bitbucket.org';\n // Bitbucket Server https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp222\n const commitsApiUrl = isHosted\n ? `${this.integration.config.apiBaseUrl}/repositories/${project}/${repoName}/commits/${branch}`\n : `${this.integration.config.apiBaseUrl}/projects/${project}/repos/${repoName}/commits`;\n\n const commitsResponse = await fetch(\n commitsApiUrl,\n getBitbucketRequestOptions(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 (isHosted) {\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 } else {\n if (\n commits &&\n commits.values &&\n commits.values.length > 0 &&\n commits.values[0].id\n ) {\n return commits.values[0].id.substring(0, 12);\n }\n }\n\n throw new Error(`Failed to read response from ${commitsApiUrl}`);\n }\n}\n"],"names":["ScmIntegrations","getBitbucketRequestOptions","getBitbucketFileFetchUrl","NotModifiedError","ReadUrlResponseFactory","NotFoundError","parseGitUrl","getBitbucketDownloadUrl","assertError","Minimatch","trimEnd","getBitbucketDefaultBranch"],"mappings":"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"}