@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 +69 -0
- package/alpha/package.json +1 -1
- package/dist/index.alpha.d.ts +19 -1
- package/dist/index.beta.d.ts +19 -1
- package/dist/index.cjs.js +154 -24
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +19 -1
- package/package.json +18 -12
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
|
package/alpha/package.json
CHANGED
package/dist/index.alpha.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/dist/index.beta.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/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 =
|
|
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
|
-
|
|
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
|
|
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({
|
|
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
|
}
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -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
|
|
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-
|
|
37
|
-
"@backstage/backend-
|
|
38
|
-
"@backstage/
|
|
39
|
-
"@backstage/
|
|
40
|
-
"@backstage/
|
|
41
|
-
"@backstage/
|
|
42
|
-
"@backstage/
|
|
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
|
|
48
|
-
"@backstage/backend-test-utils": "^0.1.30
|
|
49
|
-
"@backstage/cli": "^0.21.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.
|
|
57
|
+
"msw": "^0.48.0"
|
|
52
58
|
},
|
|
53
59
|
"files": [
|
|
54
60
|
"alpha",
|