@backstage/plugin-catalog-backend-module-bitbucket-cloud 0.1.5-next.0 → 0.1.5

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,74 @@
1
1
  # @backstage/plugin-catalog-backend-module-bitbucket-cloud
2
2
 
3
+ ## 0.1.5
4
+
5
+ ### Patch Changes
6
+
7
+ - d089fbe7dc: Handle Bitbucket Cloud `repo:push` events at the `BitbucketCloudEntityProvider`
8
+ by subscribing to the topic `bitbucketCloud.repo:push.`
9
+
10
+ Implements `EventSubscriber` to receive events for the topic `bitbucketCloud.repo:push`.
11
+
12
+ On `repo:push`, the affected repository will be refreshed.
13
+ This includes adding new Location entities, refreshing existing ones,
14
+ and removing obsolete ones.
15
+
16
+ To support this, a new annotation `bitbucket.org/repo-url` was added
17
+ to Location entities.
18
+
19
+ A full refresh will require 1 API call to Bitbucket Cloud to discover all catalog files.
20
+ When we handle one `repo:push` event, we also need 1 API call in order to know
21
+ which catalog files exist.
22
+ This may lead to more discovery-related API calls (code search).
23
+ The main cause for hitting the rate limits are Locations refresh-related operations.
24
+
25
+ A reduction of total API calls to reduce the rate limit issues can only be achieved in
26
+ combination with
27
+
28
+ 1. reducing the full refresh frequency (e.g., to monthly)
29
+ 2. reducing the frequency of general Location refresh operations by the processing loop
30
+
31
+ For (2.), it is not possible to reduce the frequency only for Bitbucket Cloud-related
32
+ Locations though.
33
+
34
+ Further optimizations might be required to resolve the rate limit issue.
35
+
36
+ **Installation and Migration**
37
+
38
+ Please find more information at
39
+ https://backstage.io/docs/integrations/bitbucketCloud/discovery,
40
+ in particular the section about "_Installation with Events Support_".
41
+
42
+ In case of the new backend-plugin-api _(alpha)_ the module will take care of
43
+ registering itself at both.
44
+
45
+ - Updated dependencies
46
+ - @backstage/backend-common@0.16.0
47
+ - @backstage/plugin-catalog-backend@1.5.1
48
+ - @backstage/integration@1.4.0
49
+ - @backstage/backend-tasks@0.3.7
50
+ - @backstage/catalog-model@1.1.3
51
+ - @backstage/plugin-events-node@0.1.0
52
+ - @backstage/plugin-bitbucket-cloud-common@0.2.1
53
+ - @backstage/backend-plugin-api@0.1.4
54
+ - @backstage/plugin-catalog-node@1.2.1
55
+ - @backstage/catalog-client@1.1.2
56
+ - @backstage/config@1.0.4
57
+ - @backstage/plugin-catalog-common@1.0.8
58
+
59
+ ## 0.1.5-next.1
60
+
61
+ ### Patch Changes
62
+
63
+ - Updated dependencies
64
+ - @backstage/backend-plugin-api@0.1.4-next.1
65
+ - @backstage/backend-tasks@0.3.7-next.1
66
+ - @backstage/plugin-catalog-backend@1.5.1-next.1
67
+ - @backstage/plugin-catalog-node@1.2.1-next.1
68
+ - @backstage/config@1.0.4-next.0
69
+ - @backstage/integration@1.4.0-next.0
70
+ - @backstage/plugin-bitbucket-cloud-common@0.2.1-next.0
71
+
3
72
  ## 0.1.5-next.0
4
73
 
5
74
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud",
3
- "version": "0.1.5-next.0",
3
+ "version": "0.1.5",
4
4
  "main": "../dist/index.cjs.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -5,12 +5,17 @@
5
5
  */
6
6
 
7
7
  import { BackendFeature } from '@backstage/backend-plugin-api';
8
+ import { CatalogApi } from '@backstage/catalog-client';
8
9
  import { Config } from '@backstage/config';
9
10
  import { EntityProvider } from '@backstage/plugin-catalog-backend';
10
11
  import { EntityProviderConnection } from '@backstage/plugin-catalog-backend';
12
+ import { EventParams } from '@backstage/plugin-events-node';
13
+ import { Events } from '@backstage/plugin-bitbucket-cloud-common';
14
+ import { EventSubscriber } from '@backstage/plugin-events-node';
11
15
  import { Logger } from 'winston';
12
16
  import { PluginTaskScheduler } from '@backstage/backend-tasks';
13
17
  import { TaskRunner } from '@backstage/backend-tasks';
18
+ import { TokenManager } from '@backstage/backend-common';
14
19
 
15
20
  /**
16
21
  * Discovers catalog files located in [Bitbucket Cloud](https://bitbucket.org).
@@ -20,16 +25,21 @@ import { TaskRunner } from '@backstage/backend-tasks';
20
25
  *
21
26
  * @public
22
27
  */
23
- export declare class BitbucketCloudEntityProvider implements EntityProvider {
28
+ export declare class BitbucketCloudEntityProvider implements EntityProvider, EventSubscriber {
24
29
  private readonly client;
25
30
  private readonly config;
26
31
  private readonly logger;
27
32
  private readonly scheduleFn;
33
+ private readonly catalogApi?;
34
+ private readonly tokenManager?;
28
35
  private connection?;
36
+ private eventConfigErrorThrown;
29
37
  static fromConfig(config: Config, options: {
38
+ catalogApi?: CatalogApi;
30
39
  logger: Logger;
31
40
  schedule?: TaskRunner;
32
41
  scheduler?: PluginTaskScheduler;
42
+ tokenManager?: TokenManager;
33
43
  }): BitbucketCloudEntityProvider[];
34
44
  private constructor();
35
45
  private createScheduleFn;
@@ -40,8 +50,16 @@ export declare class BitbucketCloudEntityProvider implements EntityProvider {
40
50
  /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */
41
51
  connect(connection: EntityProviderConnection): Promise<void>;
42
52
  refresh(logger: Logger): Promise<void>;
53
+ /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */
54
+ supportsEventTopics(): string[];
55
+ /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */
56
+ onEvent(params: EventParams): Promise<void>;
57
+ private canHandleEvents;
58
+ onRepoPush(event: Events.RepoPushEvent): Promise<void>;
59
+ private findExistingLocations;
43
60
  private findCatalogFiles;
44
61
  private matchesFilters;
62
+ private toDeferredEntities;
45
63
  private static toUrl;
46
64
  private static toLocationSpec;
47
65
  }
@@ -5,12 +5,17 @@
5
5
  */
6
6
 
7
7
  import { BackendFeature } from '@backstage/backend-plugin-api';
8
+ import { CatalogApi } from '@backstage/catalog-client';
8
9
  import { Config } from '@backstage/config';
9
10
  import { EntityProvider } from '@backstage/plugin-catalog-backend';
10
11
  import { EntityProviderConnection } from '@backstage/plugin-catalog-backend';
12
+ import { EventParams } from '@backstage/plugin-events-node';
13
+ import { Events } from '@backstage/plugin-bitbucket-cloud-common';
14
+ import { EventSubscriber } from '@backstage/plugin-events-node';
11
15
  import { Logger } from 'winston';
12
16
  import { PluginTaskScheduler } from '@backstage/backend-tasks';
13
17
  import { TaskRunner } from '@backstage/backend-tasks';
18
+ import { TokenManager } from '@backstage/backend-common';
14
19
 
15
20
  /**
16
21
  * Discovers catalog files located in [Bitbucket Cloud](https://bitbucket.org).
@@ -20,16 +25,21 @@ import { TaskRunner } from '@backstage/backend-tasks';
20
25
  *
21
26
  * @public
22
27
  */
23
- export declare class BitbucketCloudEntityProvider implements EntityProvider {
28
+ export declare class BitbucketCloudEntityProvider implements EntityProvider, EventSubscriber {
24
29
  private readonly client;
25
30
  private readonly config;
26
31
  private readonly logger;
27
32
  private readonly scheduleFn;
33
+ private readonly catalogApi?;
34
+ private readonly tokenManager?;
28
35
  private connection?;
36
+ private eventConfigErrorThrown;
29
37
  static fromConfig(config: Config, options: {
38
+ catalogApi?: CatalogApi;
30
39
  logger: Logger;
31
40
  schedule?: TaskRunner;
32
41
  scheduler?: PluginTaskScheduler;
42
+ tokenManager?: TokenManager;
33
43
  }): BitbucketCloudEntityProvider[];
34
44
  private constructor();
35
45
  private createScheduleFn;
@@ -40,8 +50,16 @@ export declare class BitbucketCloudEntityProvider implements EntityProvider {
40
50
  /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */
41
51
  connect(connection: EntityProviderConnection): Promise<void>;
42
52
  refresh(logger: Logger): Promise<void>;
53
+ /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */
54
+ supportsEventTopics(): string[];
55
+ /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */
56
+ onEvent(params: EventParams): Promise<void>;
57
+ private canHandleEvents;
58
+ onRepoPush(event: Events.RepoPushEvent): Promise<void>;
59
+ private findExistingLocations;
43
60
  private findCatalogFiles;
44
61
  private matchesFilters;
62
+ private toDeferredEntities;
45
63
  private static toUrl;
46
64
  private static toLocationSpec;
47
65
  }
package/dist/index.cjs.js CHANGED
@@ -2,13 +2,18 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var catalogModel = require('@backstage/catalog-model');
5
6
  var integration = require('@backstage/integration');
6
7
  var pluginBitbucketCloudCommon = require('@backstage/plugin-bitbucket-cloud-common');
7
8
  var pluginCatalogBackend = require('@backstage/plugin-catalog-backend');
8
9
  var backendTasks = require('@backstage/backend-tasks');
10
+ var limiterFactory = require('p-limit');
9
11
  var uuid = require('uuid');
10
12
  var backendPluginApi = require('@backstage/backend-plugin-api');
11
13
  var pluginCatalogNode = require('@backstage/plugin-catalog-node');
14
+ var pluginEventsNode = require('@backstage/plugin-events-node');
15
+
16
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
17
 
13
18
  function _interopNamespace(e) {
14
19
  if (e && e.__esModule) return e;
@@ -28,6 +33,7 @@ function _interopNamespace(e) {
28
33
  return Object.freeze(n);
29
34
  }
30
35
 
36
+ var limiterFactory__default = /*#__PURE__*/_interopDefaultLegacy(limiterFactory);
31
37
  var uuid__namespace = /*#__PURE__*/_interopNamespace(uuid);
32
38
 
33
39
  const DEFAULT_CATALOG_PATH = "/catalog-info.yaml";
@@ -77,7 +83,20 @@ function compileRegExp(pattern) {
77
83
  }
78
84
 
79
85
  const DEFAULT_BRANCH = "master";
86
+ const TOPIC_REPO_PUSH = "bitbucketCloud/repo:push";
87
+ const ANNOTATION_BITBUCKET_CLOUD_REPO_URL = "bitbucket.org/repo-url";
80
88
  class BitbucketCloudEntityProvider {
89
+ constructor(config, integration, logger, taskRunner, catalogApi, tokenManager) {
90
+ this.eventConfigErrorThrown = false;
91
+ this.client = pluginBitbucketCloudCommon.BitbucketCloudClient.fromConfig(integration.config);
92
+ this.config = config;
93
+ this.logger = logger.child({
94
+ target: this.getProviderName()
95
+ });
96
+ this.scheduleFn = this.createScheduleFn(taskRunner);
97
+ this.catalogApi = catalogApi;
98
+ this.tokenManager = tokenManager;
99
+ }
81
100
  static fromConfig(config, options) {
82
101
  const integrations = integration.ScmIntegrations.fromConfig(config);
83
102
  const integration$1 = integrations.bitbucketCloud.byHost("bitbucket.org");
@@ -99,18 +118,12 @@ class BitbucketCloudEntityProvider {
99
118
  providerConfig,
100
119
  integration$1,
101
120
  options.logger,
102
- taskRunner
121
+ taskRunner,
122
+ options.catalogApi,
123
+ options.tokenManager
103
124
  );
104
125
  });
105
126
  }
106
- constructor(config, integration, logger, taskRunner) {
107
- this.client = pluginBitbucketCloudCommon.BitbucketCloudClient.fromConfig(integration.config);
108
- this.config = config;
109
- this.logger = logger.child({
110
- target: this.getProviderName()
111
- });
112
- this.scheduleFn = this.createScheduleFn(taskRunner);
113
- }
114
127
  createScheduleFn(schedule) {
115
128
  return async () => {
116
129
  const taskId = this.getTaskId();
@@ -147,12 +160,7 @@ class BitbucketCloudEntityProvider {
147
160
  }
148
161
  logger.info("Discovering catalog files in Bitbucket Cloud repositories");
149
162
  const targets = await this.findCatalogFiles();
150
- const entities = targets.map(BitbucketCloudEntityProvider.toLocationSpec).map((location) => pluginCatalogBackend.locationSpecToLocationEntity({ location })).map((entity) => {
151
- return {
152
- locationKey: this.getProviderName(),
153
- entity
154
- };
155
- });
163
+ const entities = this.toDeferredEntities(targets);
156
164
  await this.connection.applyMutation({
157
165
  type: "full",
158
166
  entities
@@ -161,7 +169,95 @@ class BitbucketCloudEntityProvider {
161
169
  `Committed ${entities.length} Locations for catalog files in Bitbucket Cloud repositories`
162
170
  );
163
171
  }
164
- async findCatalogFiles() {
172
+ supportsEventTopics() {
173
+ return [TOPIC_REPO_PUSH];
174
+ }
175
+ async onEvent(params) {
176
+ var _a;
177
+ if (params.topic !== TOPIC_REPO_PUSH) {
178
+ return;
179
+ }
180
+ if (((_a = params.metadata) == null ? void 0 : _a["x-event-key"]) === "repo:push") {
181
+ await this.onRepoPush(params.eventPayload);
182
+ }
183
+ }
184
+ canHandleEvents() {
185
+ if (this.catalogApi && this.tokenManager) {
186
+ return true;
187
+ }
188
+ if (!this.eventConfigErrorThrown) {
189
+ this.eventConfigErrorThrown = true;
190
+ throw new Error(
191
+ `${this.getProviderName()} not well configured to handle repo:push. Missing CatalogApi and/or TokenManager.`
192
+ );
193
+ }
194
+ return false;
195
+ }
196
+ async onRepoPush(event) {
197
+ if (!this.canHandleEvents()) {
198
+ return;
199
+ }
200
+ if (!this.connection) {
201
+ throw new Error("Not initialized");
202
+ }
203
+ if (event.repository.workspace.slug !== this.config.workspace) {
204
+ return;
205
+ }
206
+ if (!this.matchesFilters(event.repository)) {
207
+ return;
208
+ }
209
+ const repoName = event.repository.slug;
210
+ const repoUrl = event.repository.links.html.href;
211
+ this.logger.info(`handle repo:push event for ${repoUrl}`);
212
+ const targets = await this.findCatalogFiles(repoName);
213
+ const { token } = await this.tokenManager.getToken();
214
+ const existing = await this.findExistingLocations(repoUrl, token);
215
+ const added = this.toDeferredEntities(
216
+ targets.filter(
217
+ (target) => !existing.find((item) => item.spec.target === target.fileUrl)
218
+ )
219
+ );
220
+ const limiter = limiterFactory__default["default"](10);
221
+ const stillExisting = [];
222
+ const removed = [];
223
+ existing.forEach((item) => {
224
+ if (targets.find((value) => value.fileUrl === item.spec.target)) {
225
+ stillExisting.push(item);
226
+ } else {
227
+ removed.push({
228
+ locationKey: this.getProviderName(),
229
+ entity: item
230
+ });
231
+ }
232
+ });
233
+ const promises = stillExisting.map(
234
+ (entity) => limiter(
235
+ async () => this.catalogApi.refreshEntity(catalogModel.stringifyEntityRef(entity), { token })
236
+ )
237
+ );
238
+ if (added.length > 0 || removed.length > 0) {
239
+ const connection = this.connection;
240
+ promises.push(
241
+ limiter(
242
+ async () => connection.applyMutation({
243
+ type: "delta",
244
+ added,
245
+ removed
246
+ })
247
+ )
248
+ );
249
+ }
250
+ await Promise.all(promises);
251
+ }
252
+ async findExistingLocations(repoUrl, token) {
253
+ const filter = {};
254
+ filter.kind = "Location";
255
+ filter[`metadata.annotations.${ANNOTATION_BITBUCKET_CLOUD_REPO_URL}`] = repoUrl;
256
+ return this.catalogApi.getEntities({ filter }, { token }).then(
257
+ (result) => result.items
258
+ );
259
+ }
260
+ async findCatalogFiles(repoName) {
165
261
  const workspace = this.config.workspace;
166
262
  const catalogPath = this.config.catalogPath;
167
263
  const catalogFilename = catalogPath.substring(
@@ -177,7 +273,8 @@ class BitbucketCloudEntityProvider {
177
273
  "-values.*.*.*.links",
178
274
  "+values.file.commit.repository.links.html.href"
179
275
  ].join(",");
180
- const query = `"${catalogFilename}" path:${catalogPath}`;
276
+ const optRepoFilter = repoName ? ` repo:${repoName}` : "";
277
+ const query = `"${catalogFilename}" path:${catalogPath}${optRepoFilter}`;
181
278
  const searchResults = this.client.searchCode(workspace, query, { fields }).iterateResults();
182
279
  const result = [];
183
280
  for await (const searchResult of searchResults) {
@@ -186,12 +283,13 @@ class BitbucketCloudEntityProvider {
186
283
  }
187
284
  const repository = searchResult.file.commit.repository;
188
285
  if (this.matchesFilters(repository)) {
189
- result.push(
190
- BitbucketCloudEntityProvider.toUrl(
286
+ result.push({
287
+ fileUrl: BitbucketCloudEntityProvider.toUrl(
191
288
  repository,
192
289
  searchResult.file.path
193
- )
194
- );
290
+ ),
291
+ repoUrl: repository.links.html.href
292
+ });
195
293
  }
196
294
  }
197
295
  return result;
@@ -200,6 +298,24 @@ class BitbucketCloudEntityProvider {
200
298
  const filters = this.config.filters;
201
299
  return !filters || (!filters.projectKey || filters.projectKey.test(repository.project.key)) && (!filters.repoSlug || filters.repoSlug.test(repository.slug));
202
300
  }
301
+ toDeferredEntities(targets) {
302
+ return targets.map((target) => {
303
+ const location = BitbucketCloudEntityProvider.toLocationSpec(
304
+ target.fileUrl
305
+ );
306
+ const entity = pluginCatalogBackend.locationSpecToLocationEntity({ location });
307
+ entity.metadata.annotations = {
308
+ ...entity.metadata.annotations,
309
+ [ANNOTATION_BITBUCKET_CLOUD_REPO_URL]: target.repoUrl
310
+ };
311
+ return entity;
312
+ }).map((entity) => {
313
+ return {
314
+ locationKey: this.getProviderName(),
315
+ entity
316
+ };
317
+ });
318
+ }
203
319
  static toUrl(repository, filePath) {
204
320
  var _a, _b;
205
321
  const repoUrl = repository.links.html.href;
@@ -222,17 +338,31 @@ const bitbucketCloudEntityProviderCatalogModule = backendPluginApi.createBackend
222
338
  env.registerInit({
223
339
  deps: {
224
340
  catalog: pluginCatalogNode.catalogProcessingExtensionPoint,
341
+ catalogApi: pluginCatalogNode.catalogServiceRef,
225
342
  config: backendPluginApi.configServiceRef,
343
+ events: pluginEventsNode.eventsExtensionPoint,
226
344
  logger: backendPluginApi.loggerServiceRef,
227
- scheduler: backendPluginApi.schedulerServiceRef
345
+ scheduler: backendPluginApi.schedulerServiceRef,
346
+ tokenManager: backendPluginApi.tokenManagerServiceRef
228
347
  },
229
- async init({ catalog, config, logger, scheduler }) {
348
+ async init({
349
+ catalog,
350
+ catalogApi,
351
+ config,
352
+ events,
353
+ logger,
354
+ scheduler,
355
+ tokenManager
356
+ }) {
230
357
  const winstonLogger = backendPluginApi.loggerToWinstonLogger(logger);
231
358
  const providers = BitbucketCloudEntityProvider.fromConfig(config, {
359
+ catalogApi,
232
360
  logger: winstonLogger,
233
- scheduler
361
+ scheduler,
362
+ tokenManager
234
363
  });
235
364
  catalog.addEntityProvider(providers);
365
+ events.addSubscribers(providers);
236
366
  }
237
367
  });
238
368
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/BitbucketCloudEntityProviderConfig.ts","../src/BitbucketCloudEntityProvider.ts","../src/service/BitbucketCloudEntityProviderCatalogModule.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 readTaskScheduleDefinitionFromConfig,\n TaskScheduleDefinition,\n} from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\n\nconst DEFAULT_CATALOG_PATH = '/catalog-info.yaml';\nconst DEFAULT_PROVIDER_ID = 'default';\n\nexport type BitbucketCloudEntityProviderConfig = {\n id: string;\n catalogPath: string;\n workspace: string;\n filters?: {\n projectKey?: RegExp;\n repoSlug?: RegExp;\n };\n schedule?: TaskScheduleDefinition;\n};\n\nexport function readProviderConfigs(\n config: Config,\n): BitbucketCloudEntityProviderConfig[] {\n const providersConfig = config.getOptionalConfig(\n 'catalog.providers.bitbucketCloud',\n );\n if (!providersConfig) {\n return [];\n }\n\n if (providersConfig.has('workspace')) {\n // simple/single config variant\n return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)];\n }\n\n return providersConfig.keys().map(id => {\n const providerConfig = providersConfig.getConfig(id);\n\n return readProviderConfig(id, providerConfig);\n });\n}\n\nfunction readProviderConfig(\n id: string,\n config: Config,\n): BitbucketCloudEntityProviderConfig {\n const workspace = config.getString('workspace');\n const catalogPath =\n config.getOptionalString('catalogPath') ?? DEFAULT_CATALOG_PATH;\n const projectKeyPattern = config.getOptionalString('filters.projectKey');\n const repoSlugPattern = config.getOptionalString('filters.repoSlug');\n\n const schedule = config.has('schedule')\n ? readTaskScheduleDefinitionFromConfig(config.getConfig('schedule'))\n : undefined;\n\n return {\n id,\n catalogPath,\n workspace,\n filters: {\n projectKey: projectKeyPattern\n ? compileRegExp(projectKeyPattern)\n : undefined,\n repoSlug: repoSlugPattern ? compileRegExp(repoSlugPattern) : undefined,\n },\n schedule,\n };\n}\n\n/**\n * Compiles a RegExp while enforcing the pattern to contain\n * the start-of-line and end-of-line anchors.\n *\n * @param pattern\n */\nfunction compileRegExp(pattern: string): RegExp {\n let fullLinePattern = pattern;\n if (!fullLinePattern.startsWith('^')) {\n fullLinePattern = `^${fullLinePattern}`;\n }\n if (!fullLinePattern.endsWith('$')) {\n fullLinePattern = `${fullLinePattern}$`;\n }\n\n return new RegExp(fullLinePattern);\n}\n","/*\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 { PluginTaskScheduler, TaskRunner } from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\nimport {\n BitbucketCloudIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n BitbucketCloudClient,\n Models,\n} from '@backstage/plugin-bitbucket-cloud-common';\nimport {\n EntityProvider,\n EntityProviderConnection,\n LocationSpec,\n locationSpecToLocationEntity,\n} from '@backstage/plugin-catalog-backend';\nimport {\n BitbucketCloudEntityProviderConfig,\n readProviderConfigs,\n} from './BitbucketCloudEntityProviderConfig';\nimport * as uuid from 'uuid';\nimport { Logger } from 'winston';\n\nconst DEFAULT_BRANCH = 'master';\n\n/**\n * Discovers catalog files located in [Bitbucket Cloud](https://bitbucket.org).\n * The provider will search your Bitbucket Cloud account and register catalog files matching the configured path\n * as Location entity and via following processing steps add all contained catalog entities.\n * This can be useful as an alternative to static locations or manually adding things to the catalog.\n *\n * @public\n */\nexport class BitbucketCloudEntityProvider implements EntityProvider {\n private readonly client: BitbucketCloudClient;\n private readonly config: BitbucketCloudEntityProviderConfig;\n private readonly logger: Logger;\n private readonly scheduleFn: () => Promise<void>;\n private connection?: EntityProviderConnection;\n\n static fromConfig(\n config: Config,\n options: {\n logger: Logger;\n schedule?: TaskRunner;\n scheduler?: PluginTaskScheduler;\n },\n ): BitbucketCloudEntityProvider[] {\n const integrations = ScmIntegrations.fromConfig(config);\n const integration = integrations.bitbucketCloud.byHost('bitbucket.org');\n if (!integration) {\n // this should never happen as we add a default integration,\n // but as a general safeguard, e.g. if this approach gets changed\n throw new Error('No integration for bitbucket.org available');\n }\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n return readProviderConfigs(config).map(providerConfig => {\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for bitbucketCloud-provider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n return new BitbucketCloudEntityProvider(\n providerConfig,\n integration,\n options.logger,\n taskRunner,\n );\n });\n }\n\n private constructor(\n config: BitbucketCloudEntityProviderConfig,\n integration: BitbucketCloudIntegration,\n logger: Logger,\n taskRunner: TaskRunner,\n ) {\n this.client = BitbucketCloudClient.fromConfig(integration.config);\n this.config = config;\n this.logger = logger.child({\n target: this.getProviderName(),\n });\n this.scheduleFn = this.createScheduleFn(taskRunner);\n }\n\n private createScheduleFn(schedule: TaskRunner): () => Promise<void> {\n return async () => {\n const taskId = this.getTaskId();\n return schedule.run({\n id: taskId,\n fn: async () => {\n const logger = this.logger.child({\n class: BitbucketCloudEntityProvider.prototype.constructor.name,\n taskId,\n taskInstanceId: uuid.v4(),\n });\n\n try {\n await this.refresh(logger);\n } catch (error) {\n logger.error(error);\n }\n },\n });\n };\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */\n getProviderName(): string {\n return `bitbucketCloud-provider:${this.config.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getTaskId} */\n getTaskId(): string {\n return `${this.getProviderName()}:refresh`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection): Promise<void> {\n this.connection = connection;\n await this.scheduleFn();\n }\n\n async refresh(logger: Logger) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n logger.info('Discovering catalog files in Bitbucket Cloud repositories');\n\n const targets = await this.findCatalogFiles();\n const entities = targets\n .map(BitbucketCloudEntityProvider.toLocationSpec)\n .map(location => locationSpecToLocationEntity({ location }))\n .map(entity => {\n return {\n locationKey: this.getProviderName(),\n entity: entity,\n };\n });\n\n await this.connection.applyMutation({\n type: 'full',\n entities: entities,\n });\n\n logger.info(\n `Committed ${entities.length} Locations for catalog files in Bitbucket Cloud repositories`,\n );\n }\n\n private async findCatalogFiles(): Promise<string[]> {\n const workspace = this.config.workspace;\n const catalogPath = this.config.catalogPath;\n\n const catalogFilename = catalogPath.substring(\n catalogPath.lastIndexOf('/') + 1,\n );\n\n // load all fields relevant for creating refs later, but not more\n const fields = [\n // exclude code/content match details\n '-values.content_matches',\n // include/add relevant repository details\n '+values.file.commit.repository.mainbranch.name',\n '+values.file.commit.repository.project.key',\n '+values.file.commit.repository.slug',\n // remove irrelevant links\n '-values.*.links',\n '-values.*.*.links',\n '-values.*.*.*.links',\n // ...except the one we need\n '+values.file.commit.repository.links.html.href',\n ].join(',');\n const query = `\"${catalogFilename}\" path:${catalogPath}`;\n const searchResults = this.client\n .searchCode(workspace, query, { fields })\n .iterateResults();\n\n const result: string[] = [];\n\n for await (const searchResult of searchResults) {\n // not a file match, but a code match\n if (searchResult.path_matches!.length === 0) {\n continue;\n }\n\n const repository = searchResult.file!.commit!.repository!;\n if (this.matchesFilters(repository)) {\n result.push(\n BitbucketCloudEntityProvider.toUrl(\n repository,\n searchResult.file!.path!,\n ),\n );\n }\n }\n\n return result;\n }\n\n private matchesFilters(repository: Models.Repository): boolean {\n const filters = this.config.filters;\n return (\n !filters ||\n ((!filters.projectKey ||\n filters.projectKey.test(repository.project!.key!)) &&\n (!filters.repoSlug || filters.repoSlug.test(repository.slug!)))\n );\n }\n\n private static toUrl(\n repository: Models.Repository,\n filePath: string,\n ): string {\n const repoUrl = repository.links!.html!.href;\n const branch = repository.mainbranch?.name ?? DEFAULT_BRANCH;\n\n return `${repoUrl}/src/${branch}/${filePath}`;\n }\n\n private static toLocationSpec(target: string): LocationSpec {\n return {\n type: 'url',\n target: target,\n presence: 'required',\n };\n }\n}\n","/*\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 configServiceRef,\n createBackendModule,\n loggerServiceRef,\n loggerToWinstonLogger,\n schedulerServiceRef,\n} from '@backstage/backend-plugin-api';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\nimport { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider';\n\n/**\n * @alpha\n */\nexport const bitbucketCloudEntityProviderCatalogModule = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'bitbucketCloudEntityProvider',\n register(env) {\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n config: configServiceRef,\n logger: loggerServiceRef,\n scheduler: schedulerServiceRef,\n },\n async init({ catalog, config, logger, scheduler }) {\n const winstonLogger = loggerToWinstonLogger(logger);\n const providers = BitbucketCloudEntityProvider.fromConfig(config, {\n logger: winstonLogger,\n scheduler,\n });\n\n catalog.addEntityProvider(providers);\n },\n });\n },\n});\n"],"names":["readTaskScheduleDefinitionFromConfig","ScmIntegrations","integration","BitbucketCloudClient","uuid","locationSpecToLocationEntity","createBackendModule","catalogProcessingExtensionPoint","configServiceRef","loggerServiceRef","schedulerServiceRef","loggerToWinstonLogger"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/BitbucketCloudEntityProviderConfig.ts","../src/BitbucketCloudEntityProvider.ts","../src/service/BitbucketCloudEntityProviderCatalogModule.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 readTaskScheduleDefinitionFromConfig,\n TaskScheduleDefinition,\n} from '@backstage/backend-tasks';\nimport { Config } from '@backstage/config';\n\nconst DEFAULT_CATALOG_PATH = '/catalog-info.yaml';\nconst DEFAULT_PROVIDER_ID = 'default';\n\nexport type BitbucketCloudEntityProviderConfig = {\n id: string;\n catalogPath: string;\n workspace: string;\n filters?: {\n projectKey?: RegExp;\n repoSlug?: RegExp;\n };\n schedule?: TaskScheduleDefinition;\n};\n\nexport function readProviderConfigs(\n config: Config,\n): BitbucketCloudEntityProviderConfig[] {\n const providersConfig = config.getOptionalConfig(\n 'catalog.providers.bitbucketCloud',\n );\n if (!providersConfig) {\n return [];\n }\n\n if (providersConfig.has('workspace')) {\n // simple/single config variant\n return [readProviderConfig(DEFAULT_PROVIDER_ID, providersConfig)];\n }\n\n return providersConfig.keys().map(id => {\n const providerConfig = providersConfig.getConfig(id);\n\n return readProviderConfig(id, providerConfig);\n });\n}\n\nfunction readProviderConfig(\n id: string,\n config: Config,\n): BitbucketCloudEntityProviderConfig {\n const workspace = config.getString('workspace');\n const catalogPath =\n config.getOptionalString('catalogPath') ?? DEFAULT_CATALOG_PATH;\n const projectKeyPattern = config.getOptionalString('filters.projectKey');\n const repoSlugPattern = config.getOptionalString('filters.repoSlug');\n\n const schedule = config.has('schedule')\n ? readTaskScheduleDefinitionFromConfig(config.getConfig('schedule'))\n : undefined;\n\n return {\n id,\n catalogPath,\n workspace,\n filters: {\n projectKey: projectKeyPattern\n ? compileRegExp(projectKeyPattern)\n : undefined,\n repoSlug: repoSlugPattern ? compileRegExp(repoSlugPattern) : undefined,\n },\n schedule,\n };\n}\n\n/**\n * Compiles a RegExp while enforcing the pattern to contain\n * the start-of-line and end-of-line anchors.\n *\n * @param pattern\n */\nfunction compileRegExp(pattern: string): RegExp {\n let fullLinePattern = pattern;\n if (!fullLinePattern.startsWith('^')) {\n fullLinePattern = `^${fullLinePattern}`;\n }\n if (!fullLinePattern.endsWith('$')) {\n fullLinePattern = `${fullLinePattern}$`;\n }\n\n return new RegExp(fullLinePattern);\n}\n","/*\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 { TokenManager } from '@backstage/backend-common';\nimport { PluginTaskScheduler, TaskRunner } from '@backstage/backend-tasks';\nimport { CatalogApi } from '@backstage/catalog-client';\nimport {\n Entity,\n LocationEntity,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n BitbucketCloudIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n BitbucketCloudClient,\n Events,\n Models,\n} from '@backstage/plugin-bitbucket-cloud-common';\nimport {\n DeferredEntity,\n EntityProvider,\n EntityProviderConnection,\n locationSpecToLocationEntity,\n} from '@backstage/plugin-catalog-backend';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { EventParams, EventSubscriber } from '@backstage/plugin-events-node';\nimport {\n BitbucketCloudEntityProviderConfig,\n readProviderConfigs,\n} from './BitbucketCloudEntityProviderConfig';\nimport limiterFactory from 'p-limit';\nimport * as uuid from 'uuid';\nimport { Logger } from 'winston';\n\nconst DEFAULT_BRANCH = 'master';\nconst TOPIC_REPO_PUSH = 'bitbucketCloud/repo:push';\n\n/** @public */\nexport const ANNOTATION_BITBUCKET_CLOUD_REPO_URL = 'bitbucket.org/repo-url';\n\ninterface IngestionTarget {\n fileUrl: string;\n repoUrl: string;\n}\n\n/**\n * Discovers catalog files located in [Bitbucket Cloud](https://bitbucket.org).\n * The provider will search your Bitbucket Cloud account and register catalog files matching the configured path\n * as Location entity and via following processing steps add all contained catalog entities.\n * This can be useful as an alternative to static locations or manually adding things to the catalog.\n *\n * @public\n */\nexport class BitbucketCloudEntityProvider\n implements EntityProvider, EventSubscriber\n{\n private readonly client: BitbucketCloudClient;\n private readonly config: BitbucketCloudEntityProviderConfig;\n private readonly logger: Logger;\n private readonly scheduleFn: () => Promise<void>;\n private readonly catalogApi?: CatalogApi;\n private readonly tokenManager?: TokenManager;\n private connection?: EntityProviderConnection;\n\n private eventConfigErrorThrown = false;\n\n static fromConfig(\n config: Config,\n options: {\n catalogApi?: CatalogApi;\n logger: Logger;\n schedule?: TaskRunner;\n scheduler?: PluginTaskScheduler;\n tokenManager?: TokenManager;\n },\n ): BitbucketCloudEntityProvider[] {\n const integrations = ScmIntegrations.fromConfig(config);\n const integration = integrations.bitbucketCloud.byHost('bitbucket.org');\n if (!integration) {\n // this should never happen as we add a default integration,\n // but as a general safeguard, e.g. if this approach gets changed\n throw new Error('No integration for bitbucket.org available');\n }\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n return readProviderConfigs(config).map(providerConfig => {\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for bitbucketCloud-provider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n return new BitbucketCloudEntityProvider(\n providerConfig,\n integration,\n options.logger,\n taskRunner,\n options.catalogApi,\n options.tokenManager,\n );\n });\n }\n\n private constructor(\n config: BitbucketCloudEntityProviderConfig,\n integration: BitbucketCloudIntegration,\n logger: Logger,\n taskRunner: TaskRunner,\n catalogApi?: CatalogApi,\n tokenManager?: TokenManager,\n ) {\n this.client = BitbucketCloudClient.fromConfig(integration.config);\n this.config = config;\n this.logger = logger.child({\n target: this.getProviderName(),\n });\n this.scheduleFn = this.createScheduleFn(taskRunner);\n this.catalogApi = catalogApi;\n this.tokenManager = tokenManager;\n }\n\n private createScheduleFn(schedule: TaskRunner): () => Promise<void> {\n return async () => {\n const taskId = this.getTaskId();\n return schedule.run({\n id: taskId,\n fn: async () => {\n const logger = this.logger.child({\n class: BitbucketCloudEntityProvider.prototype.constructor.name,\n taskId,\n taskInstanceId: uuid.v4(),\n });\n\n try {\n await this.refresh(logger);\n } catch (error) {\n logger.error(error);\n }\n },\n });\n };\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getProviderName} */\n getProviderName(): string {\n return `bitbucketCloud-provider:${this.config.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.getTaskId} */\n getTaskId(): string {\n return `${this.getProviderName()}:refresh`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection): Promise<void> {\n this.connection = connection;\n await this.scheduleFn();\n }\n\n async refresh(logger: Logger) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n logger.info('Discovering catalog files in Bitbucket Cloud repositories');\n\n const targets = await this.findCatalogFiles();\n const entities = this.toDeferredEntities(targets);\n\n await this.connection.applyMutation({\n type: 'full',\n entities: entities,\n });\n\n logger.info(\n `Committed ${entities.length} Locations for catalog files in Bitbucket Cloud repositories`,\n );\n }\n\n /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */\n supportsEventTopics(): string[] {\n return [TOPIC_REPO_PUSH];\n }\n\n /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */\n async onEvent(params: EventParams): Promise<void> {\n if (params.topic !== TOPIC_REPO_PUSH) {\n return;\n }\n\n if (params.metadata?.['x-event-key'] === 'repo:push') {\n await this.onRepoPush(params.eventPayload as Events.RepoPushEvent);\n }\n }\n\n private canHandleEvents(): boolean {\n if (this.catalogApi && this.tokenManager) {\n return true;\n }\n\n // throw only once\n if (!this.eventConfigErrorThrown) {\n this.eventConfigErrorThrown = true;\n throw new Error(\n `${this.getProviderName()} not well configured to handle repo:push. Missing CatalogApi and/or TokenManager.`,\n );\n }\n\n return false;\n }\n\n async onRepoPush(event: Events.RepoPushEvent): Promise<void> {\n if (!this.canHandleEvents()) {\n return;\n }\n\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n if (event.repository.workspace.slug !== this.config.workspace) {\n return;\n }\n\n if (!this.matchesFilters(event.repository)) {\n return;\n }\n\n const repoName = event.repository.slug;\n const repoUrl = event.repository.links!.html!.href!;\n this.logger.info(`handle repo:push event for ${repoUrl}`);\n\n // The commit information at the webhook only contains some high level metadata.\n // In order to understand whether relevant files have changed we would need to\n // look up all commits which would cost additional API calls.\n // The overall goal is to optimize the necessary amount of API calls.\n // Hence, we will just trigger a refresh for catalog file(s) within the repository\n // if we get notified about changes there.\n\n const targets = await this.findCatalogFiles(repoName);\n\n const { token } = await this.tokenManager!.getToken();\n const existing = await this.findExistingLocations(repoUrl, token);\n\n const added: DeferredEntity[] = this.toDeferredEntities(\n targets.filter(\n // All Locations are managed by this provider and only have `target`, never `targets`.\n // All URLs (fileUrl, target) are created using `BitbucketCloudEntityProvider.toUrl`.\n // Hence, we can keep the comparison simple and don't need to handle different\n // casing or encoding, etc.\n target => !existing.find(item => item.spec.target === target.fileUrl),\n ),\n );\n\n const limiter = limiterFactory(10);\n\n const stillExisting: Entity[] = [];\n const removed: DeferredEntity[] = [];\n existing.forEach(item => {\n if (targets.find(value => value.fileUrl === item.spec.target)) {\n stillExisting.push(item);\n } else {\n removed.push({\n locationKey: this.getProviderName(),\n entity: item,\n });\n }\n });\n\n const promises: Promise<void>[] = stillExisting.map(entity =>\n limiter(async () =>\n this.catalogApi!.refreshEntity(stringifyEntityRef(entity), { token }),\n ),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const connection = this.connection;\n promises.push(\n limiter(async () =>\n connection.applyMutation({\n type: 'delta',\n added: added,\n removed: removed,\n }),\n ),\n );\n }\n\n await Promise.all(promises);\n }\n\n private async findExistingLocations(\n repoUrl: string,\n token: string,\n ): Promise<LocationEntity[]> {\n const filter: Record<string, string> = {};\n filter.kind = 'Location';\n filter[`metadata.annotations.${ANNOTATION_BITBUCKET_CLOUD_REPO_URL}`] =\n repoUrl;\n\n return this.catalogApi!.getEntities({ filter }, { token }).then(\n result => result.items,\n ) as Promise<LocationEntity[]>;\n }\n\n private async findCatalogFiles(\n repoName?: string,\n ): Promise<IngestionTarget[]> {\n const workspace = this.config.workspace;\n const catalogPath = this.config.catalogPath;\n\n const catalogFilename = catalogPath.substring(\n catalogPath.lastIndexOf('/') + 1,\n );\n\n // load all fields relevant for creating refs later, but not more\n const fields = [\n // exclude code/content match details\n '-values.content_matches',\n // include/add relevant repository details\n '+values.file.commit.repository.mainbranch.name',\n '+values.file.commit.repository.project.key',\n '+values.file.commit.repository.slug',\n // remove irrelevant links\n '-values.*.links',\n '-values.*.*.links',\n '-values.*.*.*.links',\n // ...except the one we need\n '+values.file.commit.repository.links.html.href',\n ].join(',');\n const optRepoFilter = repoName ? ` repo:${repoName}` : '';\n const query = `\"${catalogFilename}\" path:${catalogPath}${optRepoFilter}`;\n const searchResults = this.client\n .searchCode(workspace, query, { fields })\n .iterateResults();\n\n const result: IngestionTarget[] = [];\n\n for await (const searchResult of searchResults) {\n // not a file match, but a code match\n if (searchResult.path_matches!.length === 0) {\n continue;\n }\n\n const repository = searchResult.file!.commit!.repository!;\n if (this.matchesFilters(repository)) {\n result.push({\n fileUrl: BitbucketCloudEntityProvider.toUrl(\n repository,\n searchResult.file!.path!,\n ),\n repoUrl: repository.links!.html!.href!,\n });\n }\n }\n\n return result;\n }\n\n private matchesFilters(repository: Models.Repository): boolean {\n const filters = this.config.filters;\n return (\n !filters ||\n ((!filters.projectKey ||\n filters.projectKey.test(repository.project!.key!)) &&\n (!filters.repoSlug || filters.repoSlug.test(repository.slug!)))\n );\n }\n\n private toDeferredEntities(targets: IngestionTarget[]): DeferredEntity[] {\n return targets\n .map(target => {\n const location = BitbucketCloudEntityProvider.toLocationSpec(\n target.fileUrl,\n );\n const entity = locationSpecToLocationEntity({ location });\n entity.metadata.annotations = {\n ...entity.metadata.annotations,\n [ANNOTATION_BITBUCKET_CLOUD_REPO_URL]: target.repoUrl,\n };\n return entity;\n })\n .map(entity => {\n return {\n locationKey: this.getProviderName(),\n entity: entity,\n };\n });\n }\n\n private static toUrl(\n repository: Models.Repository,\n filePath: string,\n ): string {\n const repoUrl = repository.links!.html!.href!;\n const branch = repository.mainbranch?.name ?? DEFAULT_BRANCH;\n\n return `${repoUrl}/src/${branch}/${filePath}`;\n }\n\n private static toLocationSpec(target: string): LocationSpec {\n return {\n type: 'url',\n target: target,\n presence: 'required',\n };\n }\n}\n","/*\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 configServiceRef,\n createBackendModule,\n loggerServiceRef,\n loggerToWinstonLogger,\n schedulerServiceRef,\n tokenManagerServiceRef,\n} from '@backstage/backend-plugin-api';\nimport {\n catalogProcessingExtensionPoint,\n catalogServiceRef,\n} from '@backstage/plugin-catalog-node';\nimport { eventsExtensionPoint } from '@backstage/plugin-events-node';\nimport { BitbucketCloudEntityProvider } from '../BitbucketCloudEntityProvider';\n\n/**\n * @alpha\n */\nexport const bitbucketCloudEntityProviderCatalogModule = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'bitbucketCloudEntityProvider',\n register(env) {\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n catalogApi: catalogServiceRef,\n config: configServiceRef,\n // TODO(pjungermann): How to make this optional for those which only want the provider without event support?\n // Do we even want to support this?\n events: eventsExtensionPoint,\n logger: loggerServiceRef,\n scheduler: schedulerServiceRef,\n tokenManager: tokenManagerServiceRef,\n },\n async init({\n catalog,\n catalogApi,\n config,\n events,\n logger,\n scheduler,\n tokenManager,\n }) {\n const winstonLogger = loggerToWinstonLogger(logger);\n const providers = BitbucketCloudEntityProvider.fromConfig(config, {\n catalogApi,\n logger: winstonLogger,\n scheduler,\n tokenManager,\n });\n\n catalog.addEntityProvider(providers);\n events.addSubscribers(providers);\n },\n });\n },\n});\n"],"names":["readTaskScheduleDefinitionFromConfig","BitbucketCloudClient","ScmIntegrations","integration","uuid","limiterFactory","stringifyEntityRef","locationSpecToLocationEntity","createBackendModule","catalogProcessingExtensionPoint","catalogServiceRef","configServiceRef","eventsExtensionPoint","loggerServiceRef","schedulerServiceRef","tokenManagerServiceRef","loggerToWinstonLogger"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -5,12 +5,17 @@
5
5
  */
6
6
 
7
7
  import { BackendFeature } from '@backstage/backend-plugin-api';
8
+ import { CatalogApi } from '@backstage/catalog-client';
8
9
  import { Config } from '@backstage/config';
9
10
  import { EntityProvider } from '@backstage/plugin-catalog-backend';
10
11
  import { EntityProviderConnection } from '@backstage/plugin-catalog-backend';
12
+ import { EventParams } from '@backstage/plugin-events-node';
13
+ import { Events } from '@backstage/plugin-bitbucket-cloud-common';
14
+ import { EventSubscriber } from '@backstage/plugin-events-node';
11
15
  import { Logger } from 'winston';
12
16
  import { PluginTaskScheduler } from '@backstage/backend-tasks';
13
17
  import { TaskRunner } from '@backstage/backend-tasks';
18
+ import { TokenManager } from '@backstage/backend-common';
14
19
 
15
20
  /**
16
21
  * Discovers catalog files located in [Bitbucket Cloud](https://bitbucket.org).
@@ -20,16 +25,21 @@ import { TaskRunner } from '@backstage/backend-tasks';
20
25
  *
21
26
  * @public
22
27
  */
23
- export declare class BitbucketCloudEntityProvider implements EntityProvider {
28
+ export declare class BitbucketCloudEntityProvider implements EntityProvider, EventSubscriber {
24
29
  private readonly client;
25
30
  private readonly config;
26
31
  private readonly logger;
27
32
  private readonly scheduleFn;
33
+ private readonly catalogApi?;
34
+ private readonly tokenManager?;
28
35
  private connection?;
36
+ private eventConfigErrorThrown;
29
37
  static fromConfig(config: Config, options: {
38
+ catalogApi?: CatalogApi;
30
39
  logger: Logger;
31
40
  schedule?: TaskRunner;
32
41
  scheduler?: PluginTaskScheduler;
42
+ tokenManager?: TokenManager;
33
43
  }): BitbucketCloudEntityProvider[];
34
44
  private constructor();
35
45
  private createScheduleFn;
@@ -40,8 +50,16 @@ export declare class BitbucketCloudEntityProvider implements EntityProvider {
40
50
  /** {@inheritdoc @backstage/plugin-catalog-backend#EntityProvider.connect} */
41
51
  connect(connection: EntityProviderConnection): Promise<void>;
42
52
  refresh(logger: Logger): Promise<void>;
53
+ /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.supportsEventTopics} */
54
+ supportsEventTopics(): string[];
55
+ /** {@inheritdoc @backstage/plugin-events-node#EventSubscriber.onEvent} */
56
+ onEvent(params: EventParams): Promise<void>;
57
+ private canHandleEvents;
58
+ onRepoPush(event: Events.RepoPushEvent): Promise<void>;
59
+ private findExistingLocations;
43
60
  private findCatalogFiles;
44
61
  private matchesFilters;
62
+ private toDeferredEntities;
45
63
  private static toUrl;
46
64
  private static toLocationSpec;
47
65
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-bitbucket-cloud",
3
3
  "description": "A Backstage catalog backend module that helps integrate towards Bitbucket Cloud",
4
- "version": "0.1.5-next.0",
4
+ "version": "0.1.5",
5
5
  "main": "dist/index.cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "license": "Apache-2.0",
@@ -33,22 +33,28 @@
33
33
  "clean": "backstage-cli package clean"
34
34
  },
35
35
  "dependencies": {
36
- "@backstage/backend-plugin-api": "^0.1.4-next.0",
37
- "@backstage/backend-tasks": "^0.3.7-next.0",
38
- "@backstage/config": "^1.0.4-next.0",
39
- "@backstage/integration": "^1.4.0-next.0",
40
- "@backstage/plugin-bitbucket-cloud-common": "^0.2.1-next.0",
41
- "@backstage/plugin-catalog-backend": "^1.5.1-next.0",
42
- "@backstage/plugin-catalog-node": "^1.2.1-next.0",
36
+ "@backstage/backend-common": "^0.16.0",
37
+ "@backstage/backend-plugin-api": "^0.1.4",
38
+ "@backstage/backend-tasks": "^0.3.7",
39
+ "@backstage/catalog-client": "^1.1.2",
40
+ "@backstage/catalog-model": "^1.1.3",
41
+ "@backstage/config": "^1.0.4",
42
+ "@backstage/integration": "^1.4.0",
43
+ "@backstage/plugin-bitbucket-cloud-common": "^0.2.1",
44
+ "@backstage/plugin-catalog-backend": "^1.5.1",
45
+ "@backstage/plugin-catalog-common": "^1.0.8",
46
+ "@backstage/plugin-catalog-node": "^1.2.1",
47
+ "@backstage/plugin-events-node": "^0.1.0",
48
+ "p-limit": "^3.1.0",
43
49
  "uuid": "^8.0.0",
44
50
  "winston": "^3.2.1"
45
51
  },
46
52
  "devDependencies": {
47
- "@backstage/backend-common": "^0.16.0-next.0",
48
- "@backstage/backend-test-utils": "^0.1.30-next.0",
49
- "@backstage/cli": "^0.21.0-next.0",
53
+ "@backstage/backend-common": "^0.16.0",
54
+ "@backstage/backend-test-utils": "^0.1.30",
55
+ "@backstage/cli": "^0.21.0",
50
56
  "luxon": "^3.0.0",
51
- "msw": "^0.47.0"
57
+ "msw": "^0.48.0"
52
58
  },
53
59
  "files": [
54
60
  "alpha",