@backstage/plugin-catalog-backend-module-bitbucket-server 0.5.12-next.0 → 0.5.13-next.0

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,25 @@
1
1
  # @backstage/plugin-catalog-backend-module-bitbucket-server
2
2
 
3
+ ## 0.5.13-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/backend-plugin-api@1.9.3-next.0
9
+ - @backstage/plugin-catalog-node@2.2.3-next.0
10
+ - @backstage/plugin-events-node@0.4.24-next.0
11
+
12
+ ## 0.5.12
13
+
14
+ ### Patch Changes
15
+
16
+ - 9e2ff8c: Added a Bitbucket Server SCM event translation layer to the catalog backend module. The module now subscribes to Bitbucket Server webhook events and translates them into generic catalog SCM events, enabling instant catalog reprocessing when repositories are pushed to or renamed. The `analyzeBitbucketServerWebhookEvent` function is exported from the alpha entry point for custom integrations.
17
+ - Updated dependencies
18
+ - @backstage/integration@2.0.3
19
+ - @backstage/backend-plugin-api@1.9.2
20
+ - @backstage/plugin-catalog-node@2.2.2
21
+ - @backstage/plugin-events-node@0.4.23
22
+
3
23
  ## 0.5.12-next.0
4
24
 
5
25
  ### Patch Changes
@@ -0,0 +1,406 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "catalog": {
6
+ "type": "object",
7
+ "properties": {
8
+ "providers": {
9
+ "type": "object",
10
+ "properties": {
11
+ "bitbucketServer": {
12
+ "anyOf": [
13
+ {
14
+ "type": "object",
15
+ "properties": {
16
+ "catalogPath": {
17
+ "type": "string",
18
+ "description": "(Optional) Path to the catalog file. Default to \"/catalog-info.yaml\".",
19
+ "visibility": "frontend"
20
+ },
21
+ "filters": {
22
+ "type": "object",
23
+ "properties": {
24
+ "repoSlug": {
25
+ "type": "string",
26
+ "description": "(Optional) Regular expression filter for the repository slug.",
27
+ "visibility": "frontend"
28
+ },
29
+ "projectKey": {
30
+ "type": "string",
31
+ "description": "(Optional) Regular expression filter for the project key.",
32
+ "visibility": "frontend"
33
+ },
34
+ "skipArchivedRepos": {
35
+ "type": "boolean",
36
+ "description": "(Optional) Skip archived repositories"
37
+ }
38
+ },
39
+ "description": "(Optional) Filters applied to discovered catalog files in repositories.",
40
+ "visibility": "frontend"
41
+ },
42
+ "validateLocationsExist": {
43
+ "type": "boolean",
44
+ "description": "(Optional) Whether to validate locations that exist before emitting them. Default: `false`."
45
+ },
46
+ "schedule": {
47
+ "type": "object",
48
+ "properties": {
49
+ "frequency": {
50
+ "anyOf": [
51
+ {
52
+ "type": "object",
53
+ "properties": {
54
+ "cron": {
55
+ "type": "string",
56
+ "description": "A crontab style string."
57
+ }
58
+ },
59
+ "required": [
60
+ "cron"
61
+ ]
62
+ },
63
+ {
64
+ "type": "string"
65
+ },
66
+ {
67
+ "type": "object",
68
+ "properties": {
69
+ "years": {
70
+ "type": "number"
71
+ },
72
+ "months": {
73
+ "type": "number"
74
+ },
75
+ "weeks": {
76
+ "type": "number"
77
+ },
78
+ "days": {
79
+ "type": "number"
80
+ },
81
+ "hours": {
82
+ "type": "number"
83
+ },
84
+ "minutes": {
85
+ "type": "number"
86
+ },
87
+ "seconds": {
88
+ "type": "number"
89
+ },
90
+ "milliseconds": {
91
+ "type": "number"
92
+ }
93
+ },
94
+ "description": "Human friendly durations object."
95
+ },
96
+ {
97
+ "type": "object",
98
+ "properties": {
99
+ "trigger": {
100
+ "type": "string",
101
+ "const": "manual"
102
+ }
103
+ },
104
+ "required": [
105
+ "trigger"
106
+ ]
107
+ }
108
+ ],
109
+ "description": "How often you want the task to run. The system does its best to avoid overlapping invocations."
110
+ },
111
+ "timeout": {
112
+ "anyOf": [
113
+ {
114
+ "type": "string"
115
+ },
116
+ {
117
+ "type": "object",
118
+ "properties": {
119
+ "years": {
120
+ "type": "number"
121
+ },
122
+ "months": {
123
+ "type": "number"
124
+ },
125
+ "weeks": {
126
+ "type": "number"
127
+ },
128
+ "days": {
129
+ "type": "number"
130
+ },
131
+ "hours": {
132
+ "type": "number"
133
+ },
134
+ "minutes": {
135
+ "type": "number"
136
+ },
137
+ "seconds": {
138
+ "type": "number"
139
+ },
140
+ "milliseconds": {
141
+ "type": "number"
142
+ }
143
+ },
144
+ "description": "Human friendly durations object."
145
+ }
146
+ ],
147
+ "description": "The maximum amount of time that a single task invocation can take, before it's considered timed out and gets \"released\" such that a new invocation is permitted to take place (possibly, then, on a different worker)."
148
+ },
149
+ "initialDelay": {
150
+ "anyOf": [
151
+ {
152
+ "type": "string"
153
+ },
154
+ {
155
+ "type": "object",
156
+ "properties": {
157
+ "years": {
158
+ "type": "number"
159
+ },
160
+ "months": {
161
+ "type": "number"
162
+ },
163
+ "weeks": {
164
+ "type": "number"
165
+ },
166
+ "days": {
167
+ "type": "number"
168
+ },
169
+ "hours": {
170
+ "type": "number"
171
+ },
172
+ "minutes": {
173
+ "type": "number"
174
+ },
175
+ "seconds": {
176
+ "type": "number"
177
+ },
178
+ "milliseconds": {
179
+ "type": "number"
180
+ }
181
+ },
182
+ "description": "Human friendly durations object."
183
+ }
184
+ ],
185
+ "description": "The amount of time that should pass before the first invocation happens."
186
+ },
187
+ "scope": {
188
+ "type": "string",
189
+ "enum": [
190
+ "global",
191
+ "local"
192
+ ],
193
+ "description": "Sets the scope of concurrency control / locking to apply for invocations of this task."
194
+ }
195
+ },
196
+ "required": [
197
+ "frequency",
198
+ "timeout"
199
+ ],
200
+ "description": "(Optional) TaskScheduleDefinition for the refresh."
201
+ }
202
+ }
203
+ },
204
+ {
205
+ "type": "object",
206
+ "additionalProperties": {
207
+ "type": "object",
208
+ "properties": {
209
+ "catalogPath": {
210
+ "type": "string",
211
+ "description": "(Optional) Path to the catalog file. Default to \"/catalog-info.yaml\".",
212
+ "visibility": "frontend"
213
+ },
214
+ "filters": {
215
+ "type": "object",
216
+ "properties": {
217
+ "repoSlug": {
218
+ "type": "string",
219
+ "description": "(Optional) Regular expression filter for the repository slug.",
220
+ "visibility": "frontend"
221
+ },
222
+ "projectKey": {
223
+ "type": "string",
224
+ "description": "(Optional) Regular expression filter for the project key.",
225
+ "visibility": "frontend"
226
+ },
227
+ "skipArchivedRepos": {
228
+ "type": "boolean",
229
+ "description": "(Optional) Skip archived repositories"
230
+ }
231
+ },
232
+ "description": "(Optional) Filters applied to discovered catalog files in repositories.",
233
+ "visibility": "frontend"
234
+ },
235
+ "validateLocationsExist": {
236
+ "type": "boolean",
237
+ "description": "(Optional) Whether to validate locations that exist before emitting them. Default: `false`."
238
+ },
239
+ "schedule": {
240
+ "type": "object",
241
+ "properties": {
242
+ "frequency": {
243
+ "anyOf": [
244
+ {
245
+ "type": "object",
246
+ "properties": {
247
+ "cron": {
248
+ "type": "string",
249
+ "description": "A crontab style string."
250
+ }
251
+ },
252
+ "required": [
253
+ "cron"
254
+ ]
255
+ },
256
+ {
257
+ "type": "string"
258
+ },
259
+ {
260
+ "type": "object",
261
+ "properties": {
262
+ "years": {
263
+ "type": "number"
264
+ },
265
+ "months": {
266
+ "type": "number"
267
+ },
268
+ "weeks": {
269
+ "type": "number"
270
+ },
271
+ "days": {
272
+ "type": "number"
273
+ },
274
+ "hours": {
275
+ "type": "number"
276
+ },
277
+ "minutes": {
278
+ "type": "number"
279
+ },
280
+ "seconds": {
281
+ "type": "number"
282
+ },
283
+ "milliseconds": {
284
+ "type": "number"
285
+ }
286
+ },
287
+ "description": "Human friendly durations object."
288
+ },
289
+ {
290
+ "type": "object",
291
+ "properties": {
292
+ "trigger": {
293
+ "type": "string",
294
+ "const": "manual"
295
+ }
296
+ },
297
+ "required": [
298
+ "trigger"
299
+ ]
300
+ }
301
+ ],
302
+ "description": "How often you want the task to run. The system does its best to avoid overlapping invocations."
303
+ },
304
+ "timeout": {
305
+ "anyOf": [
306
+ {
307
+ "type": "string"
308
+ },
309
+ {
310
+ "type": "object",
311
+ "properties": {
312
+ "years": {
313
+ "type": "number"
314
+ },
315
+ "months": {
316
+ "type": "number"
317
+ },
318
+ "weeks": {
319
+ "type": "number"
320
+ },
321
+ "days": {
322
+ "type": "number"
323
+ },
324
+ "hours": {
325
+ "type": "number"
326
+ },
327
+ "minutes": {
328
+ "type": "number"
329
+ },
330
+ "seconds": {
331
+ "type": "number"
332
+ },
333
+ "milliseconds": {
334
+ "type": "number"
335
+ }
336
+ },
337
+ "description": "Human friendly durations object."
338
+ }
339
+ ],
340
+ "description": "The maximum amount of time that a single task invocation can take, before it's considered timed out and gets \"released\" such that a new invocation is permitted to take place (possibly, then, on a different worker)."
341
+ },
342
+ "initialDelay": {
343
+ "anyOf": [
344
+ {
345
+ "type": "string"
346
+ },
347
+ {
348
+ "type": "object",
349
+ "properties": {
350
+ "years": {
351
+ "type": "number"
352
+ },
353
+ "months": {
354
+ "type": "number"
355
+ },
356
+ "weeks": {
357
+ "type": "number"
358
+ },
359
+ "days": {
360
+ "type": "number"
361
+ },
362
+ "hours": {
363
+ "type": "number"
364
+ },
365
+ "minutes": {
366
+ "type": "number"
367
+ },
368
+ "seconds": {
369
+ "type": "number"
370
+ },
371
+ "milliseconds": {
372
+ "type": "number"
373
+ }
374
+ },
375
+ "description": "Human friendly durations object."
376
+ }
377
+ ],
378
+ "description": "The amount of time that should pass before the first invocation happens."
379
+ },
380
+ "scope": {
381
+ "type": "string",
382
+ "enum": [
383
+ "global",
384
+ "local"
385
+ ],
386
+ "description": "Sets the scope of concurrency control / locking to apply for invocations of this task."
387
+ }
388
+ },
389
+ "required": [
390
+ "frequency",
391
+ "timeout"
392
+ ],
393
+ "description": "(Optional) TaskScheduleDefinition for the refresh."
394
+ }
395
+ }
396
+ }
397
+ }
398
+ ],
399
+ "description": "BitbucketServerEntityProvider configuration\n\nUses \"default\" as default id for the single config variant."
400
+ }
401
+ }
402
+ }
403
+ }
404
+ }
405
+ }
406
+ }
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var catalogModuleBitbucketServerEntityProvider = require('./module/catalogModuleBitbucketServerEntityProvider.cjs.js');
6
+ var analyzeBitbucketServerWebhookEvent = require('./events/analyzeBitbucketServerWebhookEvent.cjs.js');
7
+
8
+ const _feature = catalogModuleBitbucketServerEntityProvider.catalogModuleBitbucketServerEntityProvider;
9
+
10
+ exports.analyzeBitbucketServerWebhookEvent = analyzeBitbucketServerWebhookEvent.analyzeBitbucketServerWebhookEvent;
11
+ exports.default = _feature;
12
+ //# sourceMappingURL=alpha.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alpha.cjs.js","sources":["../src/alpha.ts"],"sourcesContent":["/*\n * Copyright 2026 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 { default as feature } from './module';\n\n/** @alpha */\nconst _feature = feature;\nexport default _feature;\n\nexport {\n analyzeBitbucketServerWebhookEvent,\n type AnalyzeBitbucketServerWebhookEventResult,\n} from './events/analyzeBitbucketServerWebhookEvent';\n"],"names":["feature"],"mappings":";;;;;;;AAmBA,MAAM,QAAA,GAAWA;;;;;"}
@@ -0,0 +1,51 @@
1
+ import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
+ import { CatalogScmEvent } from '@backstage/plugin-catalog-node/alpha';
3
+
4
+ /**
5
+ * The result of analyzing a Bitbucket Server webhook event.
6
+ *
7
+ * - `ok` — one or more catalog SCM events were produced.
8
+ * - `ignored` — the event was valid but not relevant.
9
+ * - `aborted` — the event could not be fully processed due to missing data.
10
+ * - `unsupported-event` — the event type is not handled by this analyzer.
11
+ *
12
+ * @alpha
13
+ */
14
+ type AnalyzeBitbucketServerWebhookEventResult = {
15
+ result: 'unsupported-event';
16
+ event: string;
17
+ } | {
18
+ result: 'ignored';
19
+ reason: string;
20
+ } | {
21
+ result: 'aborted';
22
+ reason: string;
23
+ } | {
24
+ result: 'ok';
25
+ events: CatalogScmEvent[];
26
+ };
27
+ /**
28
+ * Analyzes a Bitbucket Server webhook event and translates it into zero or more
29
+ * catalog SCM events that entity providers can act on.
30
+ *
31
+ * Bitbucket Server push payloads do not include file-level change data, so only
32
+ * repository-level events are produced (unlike the GitLab and Azure DevOps
33
+ * analyzers which can emit fine-grained `location.*` events). Bitbucket Server
34
+ * does not emit a repository deletion webhook, so no `repository.deleted` event
35
+ * is produced.
36
+ *
37
+ * Supported event types:
38
+ * - `repo:refs_changed` — emits a `repository.updated` event to trigger catalog
39
+ * refresh for the repository.
40
+ * - `repo:modified` — translates repository renames into `repository.moved`
41
+ * events, or emits `repository.updated` for other metadata changes.
42
+ *
43
+ * @alpha
44
+ */
45
+ declare function analyzeBitbucketServerWebhookEvent(eventType: string, eventPayload: unknown): Promise<AnalyzeBitbucketServerWebhookEventResult>;
46
+
47
+ /** @alpha */
48
+ declare const _feature: _backstage_backend_plugin_api.BackendFeature;
49
+
50
+ export { analyzeBitbucketServerWebhookEvent, _feature as default };
51
+ export type { AnalyzeBitbucketServerWebhookEventResult };
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ var analyzeBitbucketServerWebhookEvent = require('./analyzeBitbucketServerWebhookEvent.cjs.js');
4
+
5
+ class BitbucketServerScmEventsBridge {
6
+ #logger;
7
+ #events;
8
+ #catalogScmEvents;
9
+ #shuttingDown;
10
+ #pendingPublish;
11
+ constructor(options) {
12
+ this.#logger = options.logger;
13
+ this.#events = options.events;
14
+ this.#catalogScmEvents = options.catalogScmEvents;
15
+ this.#shuttingDown = false;
16
+ }
17
+ async start() {
18
+ await this.#events.subscribe({
19
+ id: "catalog-bitbucket-server-scm-events-bridge",
20
+ topics: ["bitbucketServer"],
21
+ onEvent: this.#onEvent.bind(this)
22
+ });
23
+ }
24
+ async stop() {
25
+ this.#shuttingDown = true;
26
+ await this.#pendingPublish;
27
+ }
28
+ async #onEvent(params) {
29
+ const eventType = params.metadata?.["x-event-key"] ?? this.#extractEventTypeFromTopic(params.topic);
30
+ if (!eventType || !params.eventPayload) {
31
+ return;
32
+ }
33
+ while (this.#pendingPublish) {
34
+ await this.#pendingPublish;
35
+ }
36
+ if (this.#shuttingDown) {
37
+ this.#logger.warn(
38
+ `Skipping Bitbucket Server webhook event of type "${eventType}" on topic "${params.topic}" because the bridge is shutting down`
39
+ );
40
+ return;
41
+ }
42
+ this.#pendingPublish = Promise.resolve().then(async () => {
43
+ try {
44
+ const output = await analyzeBitbucketServerWebhookEvent.analyzeBitbucketServerWebhookEvent(
45
+ eventType,
46
+ params.eventPayload
47
+ );
48
+ if (output.result === "ok") {
49
+ await this.#catalogScmEvents.publish(output.events);
50
+ } else if (output.result === "ignored") {
51
+ this.#logger.debug(
52
+ `Skipping Bitbucket Server webhook event of type "${eventType}" on topic "${params.topic}" because it is ignored: ${output.reason}`
53
+ );
54
+ } else if (output.result === "aborted") {
55
+ this.#logger.warn(
56
+ `Skipping Bitbucket Server webhook event of type "${eventType}" on topic "${params.topic}" because it is aborted: ${output.reason}`
57
+ );
58
+ } else if (output.result === "unsupported-event") {
59
+ this.#logger.debug(
60
+ `Skipping Bitbucket Server webhook event of type "${eventType}" on topic "${params.topic}" because it is unsupported: ${output.event}`
61
+ );
62
+ }
63
+ } catch (error) {
64
+ this.#logger.warn(
65
+ `Failed to handle Bitbucket Server webhook event of type "${eventType}"`,
66
+ error
67
+ );
68
+ } finally {
69
+ this.#pendingPublish = void 0;
70
+ }
71
+ });
72
+ await this.#pendingPublish;
73
+ }
74
+ #extractEventTypeFromTopic(topic) {
75
+ if (topic.startsWith("bitbucketServer.")) {
76
+ return topic.slice("bitbucketServer.".length);
77
+ }
78
+ return void 0;
79
+ }
80
+ }
81
+
82
+ exports.BitbucketServerScmEventsBridge = BitbucketServerScmEventsBridge;
83
+ //# sourceMappingURL=BitbucketServerScmEventsBridge.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BitbucketServerScmEventsBridge.cjs.js","sources":["../../src/events/BitbucketServerScmEventsBridge.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { CatalogScmEventsService } from '@backstage/plugin-catalog-node/alpha';\nimport { EventParams, EventsService } from '@backstage/plugin-events-node';\nimport { analyzeBitbucketServerWebhookEvent } from './analyzeBitbucketServerWebhookEvent';\n\n/**\n * Takes Bitbucket Server webhook events, analyzes them, and publishes them as\n * catalog SCM events that entity providers and others can subscribe to.\n */\nexport class BitbucketServerScmEventsBridge {\n readonly #logger: LoggerService;\n readonly #events: EventsService;\n readonly #catalogScmEvents: CatalogScmEventsService;\n #shuttingDown: boolean;\n #pendingPublish: Promise<void> | undefined;\n\n constructor(options: {\n logger: LoggerService;\n events: EventsService;\n catalogScmEvents: CatalogScmEventsService;\n }) {\n this.#logger = options.logger;\n this.#events = options.events;\n this.#catalogScmEvents = options.catalogScmEvents;\n this.#shuttingDown = false;\n }\n\n async start() {\n await this.#events.subscribe({\n id: 'catalog-bitbucket-server-scm-events-bridge',\n topics: ['bitbucketServer'],\n onEvent: this.#onEvent.bind(this),\n });\n }\n\n async stop() {\n this.#shuttingDown = true;\n await this.#pendingPublish;\n }\n\n async #onEvent(params: EventParams): Promise<void> {\n const eventType =\n (params.metadata?.['x-event-key'] as string | undefined) ??\n this.#extractEventTypeFromTopic(params.topic);\n if (!eventType || !params.eventPayload) {\n return;\n }\n\n while (this.#pendingPublish) {\n await this.#pendingPublish;\n }\n\n if (this.#shuttingDown) {\n this.#logger.warn(\n `Skipping Bitbucket Server webhook event of type \"${eventType}\" on topic \"${params.topic}\" because the bridge is shutting down`,\n );\n return;\n }\n\n this.#pendingPublish = Promise.resolve().then(async () => {\n try {\n const output = await analyzeBitbucketServerWebhookEvent(\n eventType,\n params.eventPayload,\n );\n\n if (output.result === 'ok') {\n await this.#catalogScmEvents.publish(output.events);\n } else if (output.result === 'ignored') {\n this.#logger.debug(\n `Skipping Bitbucket Server webhook event of type \"${eventType}\" on topic \"${params.topic}\" because it is ignored: ${output.reason}`,\n );\n } else if (output.result === 'aborted') {\n this.#logger.warn(\n `Skipping Bitbucket Server webhook event of type \"${eventType}\" on topic \"${params.topic}\" because it is aborted: ${output.reason}`,\n );\n } else if (output.result === 'unsupported-event') {\n this.#logger.debug(\n `Skipping Bitbucket Server webhook event of type \"${eventType}\" on topic \"${params.topic}\" because it is unsupported: ${output.event}`,\n );\n }\n } catch (error) {\n this.#logger.warn(\n `Failed to handle Bitbucket Server webhook event of type \"${eventType}\"`,\n error,\n );\n } finally {\n this.#pendingPublish = undefined;\n }\n });\n\n await this.#pendingPublish;\n }\n\n #extractEventTypeFromTopic(topic: string): string | undefined {\n if (topic.startsWith('bitbucketServer.')) {\n return topic.slice('bitbucketServer.'.length);\n }\n return undefined;\n }\n}\n"],"names":["analyzeBitbucketServerWebhookEvent"],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ 'use strict';
2
+
3
+ var errors = require('@backstage/errors');
4
+
5
+ function asObject(value) {
6
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7
+ return void 0;
8
+ }
9
+ return value;
10
+ }
11
+ function asArray(value) {
12
+ return Array.isArray(value) ? value : void 0;
13
+ }
14
+ function asString(value) {
15
+ return typeof value === "string" ? value : void 0;
16
+ }
17
+ function getRepositoryUrl(repository) {
18
+ const links = asObject(repository?.links);
19
+ const self = asArray(links?.self);
20
+ const first = asObject(self?.[0]);
21
+ return asString(first?.href);
22
+ }
23
+ async function onRefsChangedEvent(payload) {
24
+ const repositoryUrl = getRepositoryUrl(asObject(payload.repository));
25
+ if (!repositoryUrl) {
26
+ return {
27
+ result: "aborted",
28
+ reason: "Bitbucket Server repo:refs_changed event did not include repository.links.self[0].href"
29
+ };
30
+ }
31
+ return {
32
+ result: "ok",
33
+ events: [{ type: "repository.updated", url: repositoryUrl }]
34
+ };
35
+ }
36
+ async function onModifiedEvent(payload) {
37
+ const repositoryUrl = getRepositoryUrl(asObject(payload.new));
38
+ const oldRepositoryUrl = getRepositoryUrl(asObject(payload.old));
39
+ if (!repositoryUrl) {
40
+ return {
41
+ result: "aborted",
42
+ reason: "Bitbucket Server repo:modified event did not include new.links.self[0].href"
43
+ };
44
+ }
45
+ if (oldRepositoryUrl && oldRepositoryUrl !== repositoryUrl) {
46
+ return {
47
+ result: "ok",
48
+ events: [
49
+ {
50
+ type: "repository.moved",
51
+ fromUrl: oldRepositoryUrl,
52
+ toUrl: repositoryUrl
53
+ }
54
+ ]
55
+ };
56
+ }
57
+ return {
58
+ result: "ok",
59
+ events: [{ type: "repository.updated", url: repositoryUrl }]
60
+ };
61
+ }
62
+ async function analyzeBitbucketServerWebhookEvent(eventType, eventPayload) {
63
+ const payload = asObject(eventPayload);
64
+ if (!payload) {
65
+ throw new errors.InputError(
66
+ "Bitbucket Server webhook event payload is not an object"
67
+ );
68
+ }
69
+ switch (eventType) {
70
+ case "repo:refs_changed":
71
+ return onRefsChangedEvent(payload);
72
+ case "repo:modified":
73
+ return onModifiedEvent(payload);
74
+ default:
75
+ return { result: "unsupported-event", event: eventType };
76
+ }
77
+ }
78
+
79
+ exports.analyzeBitbucketServerWebhookEvent = analyzeBitbucketServerWebhookEvent;
80
+ //# sourceMappingURL=analyzeBitbucketServerWebhookEvent.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzeBitbucketServerWebhookEvent.cjs.js","sources":["../../src/events/analyzeBitbucketServerWebhookEvent.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { InputError } from '@backstage/errors';\nimport { CatalogScmEvent } from '@backstage/plugin-catalog-node/alpha';\n\n/**\n * The result of analyzing a Bitbucket Server webhook event.\n *\n * - `ok` — one or more catalog SCM events were produced.\n * - `ignored` — the event was valid but not relevant.\n * - `aborted` — the event could not be fully processed due to missing data.\n * - `unsupported-event` — the event type is not handled by this analyzer.\n *\n * @alpha\n */\nexport type AnalyzeBitbucketServerWebhookEventResult =\n | {\n result: 'unsupported-event';\n event: string;\n }\n | {\n result: 'ignored';\n reason: string;\n }\n | {\n result: 'aborted';\n reason: string;\n }\n | {\n result: 'ok';\n events: CatalogScmEvent[];\n };\n\ntype JsonObject = Record<string, unknown>;\n\nfunction asObject(value: unknown): JsonObject | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n return value as JsonObject;\n}\n\nfunction asArray(value: unknown): unknown[] | undefined {\n return Array.isArray(value) ? value : undefined;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction getRepositoryUrl(\n repository: JsonObject | undefined,\n): string | undefined {\n const links = asObject(repository?.links);\n const self = asArray(links?.self);\n const first = asObject(self?.[0]);\n return asString(first?.href);\n}\n\nasync function onRefsChangedEvent(\n payload: JsonObject,\n): Promise<AnalyzeBitbucketServerWebhookEventResult> {\n const repositoryUrl = getRepositoryUrl(asObject(payload.repository));\n\n if (!repositoryUrl) {\n return {\n result: 'aborted',\n reason:\n 'Bitbucket Server repo:refs_changed event did not include repository.links.self[0].href',\n };\n }\n\n return {\n result: 'ok',\n events: [{ type: 'repository.updated', url: repositoryUrl }],\n };\n}\n\nasync function onModifiedEvent(\n payload: JsonObject,\n): Promise<AnalyzeBitbucketServerWebhookEventResult> {\n const repositoryUrl = getRepositoryUrl(asObject(payload.new));\n const oldRepositoryUrl = getRepositoryUrl(asObject(payload.old));\n\n if (!repositoryUrl) {\n return {\n result: 'aborted',\n reason:\n 'Bitbucket Server repo:modified event did not include new.links.self[0].href',\n };\n }\n\n if (oldRepositoryUrl && oldRepositoryUrl !== repositoryUrl) {\n return {\n result: 'ok',\n events: [\n {\n type: 'repository.moved',\n fromUrl: oldRepositoryUrl,\n toUrl: repositoryUrl,\n },\n ],\n };\n }\n\n return {\n result: 'ok',\n events: [{ type: 'repository.updated', url: repositoryUrl }],\n };\n}\n\n/**\n * Analyzes a Bitbucket Server webhook event and translates it into zero or more\n * catalog SCM events that entity providers can act on.\n *\n * Bitbucket Server push payloads do not include file-level change data, so only\n * repository-level events are produced (unlike the GitLab and Azure DevOps\n * analyzers which can emit fine-grained `location.*` events). Bitbucket Server\n * does not emit a repository deletion webhook, so no `repository.deleted` event\n * is produced.\n *\n * Supported event types:\n * - `repo:refs_changed` — emits a `repository.updated` event to trigger catalog\n * refresh for the repository.\n * - `repo:modified` — translates repository renames into `repository.moved`\n * events, or emits `repository.updated` for other metadata changes.\n *\n * @alpha\n */\nexport async function analyzeBitbucketServerWebhookEvent(\n eventType: string,\n eventPayload: unknown,\n): Promise<AnalyzeBitbucketServerWebhookEventResult> {\n const payload = asObject(eventPayload);\n if (!payload) {\n throw new InputError(\n 'Bitbucket Server webhook event payload is not an object',\n );\n }\n\n switch (eventType) {\n case 'repo:refs_changed':\n return onRefsChangedEvent(payload);\n case 'repo:modified':\n return onModifiedEvent(payload);\n default:\n return { result: 'unsupported-event', event: eventType };\n }\n}\n"],"names":["InputError"],"mappings":";;;;AAiDA,SAAS,SAAS,KAAA,EAAwC;AACxD,EAAA,IAAI,CAAC,SAAS,OAAO,KAAA,KAAU,YAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/D,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,QAAQ,KAAA,EAAuC;AACtD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,MAAA;AACxC;AAEA,SAAS,SAAS,KAAA,EAAoC;AACpD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,MAAA;AAC7C;AAEA,SAAS,iBACP,UAAA,EACoB;AACpB,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,UAAA,EAAY,KAAK,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA;AAChC,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,GAAO,CAAC,CAAC,CAAA;AAChC,EAAA,OAAO,QAAA,CAAS,OAAO,IAAI,CAAA;AAC7B;AAEA,eAAe,mBACb,OAAA,EACmD;AACnD,EAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,QAAA,CAAS,OAAA,CAAQ,UAAU,CAAC,CAAA;AAEnE,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EACE;AAAA,KACJ;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,IAAA;AAAA,IACR,QAAQ,CAAC,EAAE,MAAM,oBAAA,EAAsB,GAAA,EAAK,eAAe;AAAA,GAC7D;AACF;AAEA,eAAe,gBACb,OAAA,EACmD;AACnD,EAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,QAAA,CAAS,OAAA,CAAQ,GAAG,CAAC,CAAA;AAC5D,EAAA,MAAM,gBAAA,GAAmB,gBAAA,CAAiB,QAAA,CAAS,OAAA,CAAQ,GAAG,CAAC,CAAA;AAE/D,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EACE;AAAA,KACJ;AAAA,EACF;AAEA,EAAA,IAAI,gBAAA,IAAoB,qBAAqB,aAAA,EAAe;AAC1D,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,IAAA;AAAA,MACR,MAAA,EAAQ;AAAA,QACN;AAAA,UACE,IAAA,EAAM,kBAAA;AAAA,UACN,OAAA,EAAS,gBAAA;AAAA,UACT,KAAA,EAAO;AAAA;AACT;AACF,KACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,IAAA;AAAA,IACR,QAAQ,CAAC,EAAE,MAAM,oBAAA,EAAsB,GAAA,EAAK,eAAe;AAAA,GAC7D;AACF;AAoBA,eAAsB,kCAAA,CACpB,WACA,YAAA,EACmD;AACnD,EAAA,MAAM,OAAA,GAAU,SAAS,YAAY,CAAA;AACrC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAIA,iBAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAEA,EAAA,QAAQ,SAAA;AAAW,IACjB,KAAK,mBAAA;AACH,MAAA,OAAO,mBAAmB,OAAO,CAAA;AAAA,IACnC,KAAK,eAAA;AACH,MAAA,OAAO,gBAAgB,OAAO,CAAA;AAAA,IAChC;AACE,MAAA,OAAO,EAAE,MAAA,EAAQ,mBAAA,EAAqB,KAAA,EAAO,SAAA,EAAU;AAAA;AAE7D;;;;"}
@@ -2,8 +2,10 @@
2
2
 
3
3
  var backendPluginApi = require('@backstage/backend-plugin-api');
4
4
  var pluginCatalogNode = require('@backstage/plugin-catalog-node');
5
+ var alpha = require('@backstage/plugin-catalog-node/alpha');
5
6
  var pluginEventsNode = require('@backstage/plugin-events-node');
6
7
  var BitbucketServerEntityProvider = require('../providers/BitbucketServerEntityProvider.cjs.js');
8
+ var BitbucketServerScmEventsBridge = require('../events/BitbucketServerScmEventsBridge.cjs.js');
7
9
 
8
10
  const catalogModuleBitbucketServerEntityProvider = backendPluginApi.createBackendModule({
9
11
  pluginId: "catalog",
@@ -17,7 +19,9 @@ const catalogModuleBitbucketServerEntityProvider = backendPluginApi.createBacken
17
19
  events: pluginEventsNode.eventsServiceRef,
18
20
  logger: backendPluginApi.coreServices.logger,
19
21
  scheduler: backendPluginApi.coreServices.scheduler,
20
- auth: backendPluginApi.coreServices.auth
22
+ auth: backendPluginApi.coreServices.auth,
23
+ catalogScmEvents: alpha.catalogScmEventsServiceRef,
24
+ lifecycle: backendPluginApi.coreServices.lifecycle
21
25
  },
22
26
  async init({
23
27
  catalog,
@@ -26,7 +30,9 @@ const catalogModuleBitbucketServerEntityProvider = backendPluginApi.createBacken
26
30
  events,
27
31
  logger,
28
32
  scheduler,
29
- auth
33
+ auth,
34
+ catalogScmEvents,
35
+ lifecycle
30
36
  }) {
31
37
  const providers = BitbucketServerEntityProvider.BitbucketServerEntityProvider.fromConfig(config, {
32
38
  catalogApi,
@@ -36,6 +42,17 @@ const catalogModuleBitbucketServerEntityProvider = backendPluginApi.createBacken
36
42
  auth
37
43
  });
38
44
  catalog.addEntityProvider(providers);
45
+ const bridge = new BitbucketServerScmEventsBridge.BitbucketServerScmEventsBridge({
46
+ logger,
47
+ events,
48
+ catalogScmEvents
49
+ });
50
+ lifecycle.addStartupHook(async () => {
51
+ await bridge.start();
52
+ });
53
+ lifecycle.addShutdownHook(async () => {
54
+ await bridge.stop();
55
+ });
39
56
  }
40
57
  });
41
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"catalogModuleBitbucketServerEntityProvider.cjs.js","sources":["../../src/module/catalogModuleBitbucketServerEntityProvider.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport { BitbucketServerEntityProvider } from '../providers/BitbucketServerEntityProvider';\n\n/**\n * @public\n */\nexport const catalogModuleBitbucketServerEntityProvider = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'bitbucket-server-entity-provider',\n register(env) {\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n catalogApi: catalogServiceRef,\n config: coreServices.rootConfig,\n events: eventsServiceRef,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n auth: coreServices.auth,\n },\n async init({\n catalog,\n catalogApi,\n config,\n events,\n logger,\n scheduler,\n auth,\n }) {\n const providers = BitbucketServerEntityProvider.fromConfig(config, {\n catalogApi,\n events,\n logger,\n scheduler,\n auth,\n });\n\n catalog.addEntityProvider(providers);\n },\n });\n },\n});\n"],"names":["createBackendModule","catalogProcessingExtensionPoint","catalogServiceRef","coreServices","eventsServiceRef","BitbucketServerEntityProvider"],"mappings":";;;;;;;AA4BO,MAAM,6CAA6CA,oCAAA,CAAoB;AAAA,EAC5E,QAAA,EAAU,SAAA;AAAA,EACV,QAAA,EAAU,kCAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,OAAA,EAASC,iDAAA;AAAA,QACT,UAAA,EAAYC,mCAAA;AAAA,QACZ,QAAQC,6BAAA,CAAa,UAAA;AAAA,QACrB,MAAA,EAAQC,iCAAA;AAAA,QACR,QAAQD,6BAAA,CAAa,MAAA;AAAA,QACrB,WAAWA,6BAAA,CAAa,SAAA;AAAA,QACxB,MAAMA,6BAAA,CAAa;AAAA,OACrB;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,QACT,OAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA;AAAA,OACF,EAAG;AACD,QAAA,MAAM,SAAA,GAAYE,2DAAA,CAA8B,UAAA,CAAW,MAAA,EAAQ;AAAA,UACjE,UAAA;AAAA,UACA,MAAA;AAAA,UACA,MAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAA,OAAA,CAAQ,kBAAkB,SAAS,CAAA;AAAA,MACrC;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"catalogModuleBitbucketServerEntityProvider.cjs.js","sources":["../../src/module/catalogModuleBitbucketServerEntityProvider.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\nimport { catalogScmEventsServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport { BitbucketServerEntityProvider } from '../providers/BitbucketServerEntityProvider';\nimport { BitbucketServerScmEventsBridge } from '../events/BitbucketServerScmEventsBridge';\n\n/**\n * @public\n */\nexport const catalogModuleBitbucketServerEntityProvider = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'bitbucket-server-entity-provider',\n register(env) {\n env.registerInit({\n deps: {\n catalog: catalogProcessingExtensionPoint,\n catalogApi: catalogServiceRef,\n config: coreServices.rootConfig,\n events: eventsServiceRef,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n auth: coreServices.auth,\n catalogScmEvents: catalogScmEventsServiceRef,\n lifecycle: coreServices.lifecycle,\n },\n async init({\n catalog,\n catalogApi,\n config,\n events,\n logger,\n scheduler,\n auth,\n catalogScmEvents,\n lifecycle,\n }) {\n const providers = BitbucketServerEntityProvider.fromConfig(config, {\n catalogApi,\n events,\n logger,\n scheduler,\n auth,\n });\n\n catalog.addEntityProvider(providers);\n\n const bridge = new BitbucketServerScmEventsBridge({\n logger,\n events,\n catalogScmEvents,\n });\n lifecycle.addStartupHook(async () => {\n await bridge.start();\n });\n lifecycle.addShutdownHook(async () => {\n await bridge.stop();\n });\n },\n });\n },\n});\n"],"names":["createBackendModule","catalogProcessingExtensionPoint","catalogServiceRef","coreServices","eventsServiceRef","catalogScmEventsServiceRef","BitbucketServerEntityProvider","BitbucketServerScmEventsBridge"],"mappings":";;;;;;;;;AA8BO,MAAM,6CAA6CA,oCAAA,CAAoB;AAAA,EAC5E,QAAA,EAAU,SAAA;AAAA,EACV,QAAA,EAAU,kCAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,OAAA,EAASC,iDAAA;AAAA,QACT,UAAA,EAAYC,mCAAA;AAAA,QACZ,QAAQC,6BAAA,CAAa,UAAA;AAAA,QACrB,MAAA,EAAQC,iCAAA;AAAA,QACR,QAAQD,6BAAA,CAAa,MAAA;AAAA,QACrB,WAAWA,6BAAA,CAAa,SAAA;AAAA,QACxB,MAAMA,6BAAA,CAAa,IAAA;AAAA,QACnB,gBAAA,EAAkBE,gCAAA;AAAA,QAClB,WAAWF,6BAAA,CAAa;AAAA,OAC1B;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,QACT,OAAA;AAAA,QACA,UAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,IAAA;AAAA,QACA,gBAAA;AAAA,QACA;AAAA,OACF,EAAG;AACD,QAAA,MAAM,SAAA,GAAYG,2DAAA,CAA8B,UAAA,CAAW,MAAA,EAAQ;AAAA,UACjE,UAAA;AAAA,UACA,MAAA;AAAA,UACA,MAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAA,OAAA,CAAQ,kBAAkB,SAAS,CAAA;AAEnC,QAAA,MAAM,MAAA,GAAS,IAAIC,6DAAA,CAA+B;AAAA,UAChD,MAAA;AAAA,UACA,MAAA;AAAA,UACA;AAAA,SACD,CAAA;AACD,QAAA,SAAA,CAAU,eAAe,YAAY;AACnC,UAAA,MAAM,OAAO,KAAA,EAAM;AAAA,QACrB,CAAC,CAAA;AACD,QAAA,SAAA,CAAU,gBAAgB,YAAY;AACpC,UAAA,MAAM,OAAO,IAAA,EAAK;AAAA,QACpB,CAAC,CAAA;AAAA,MACH;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-bitbucket-server",
3
- "version": "0.5.12-next.0",
3
+ "version": "0.5.13-next.0",
4
4
  "backstage": {
5
5
  "role": "backend-plugin-module",
6
6
  "pluginId": "catalog",
7
7
  "pluginPackage": "@backstage/plugin-catalog-backend",
8
8
  "features": {
9
- ".": "@backstage/BackendFeature"
9
+ ".": "@backstage/BackendFeature",
10
+ "./alpha": "@backstage/BackendFeature"
10
11
  }
11
12
  },
12
13
  "publishConfig": {
@@ -29,19 +30,28 @@
29
30
  "types": "./dist/index.d.ts",
30
31
  "default": "./dist/index.cjs.js"
31
32
  },
33
+ "./alpha": {
34
+ "backstage": "@backstage/BackendFeature",
35
+ "require": "./dist/alpha.cjs.js",
36
+ "types": "./dist/alpha.d.ts",
37
+ "default": "./dist/alpha.cjs.js"
38
+ },
32
39
  "./package.json": "./package.json"
33
40
  },
34
41
  "main": "./dist/index.cjs.js",
35
42
  "types": "./dist/index.d.ts",
36
43
  "typesVersions": {
37
44
  "*": {
45
+ "alpha": [
46
+ "dist/alpha.d.ts"
47
+ ],
38
48
  "package.json": [
39
49
  "package.json"
40
50
  ]
41
51
  }
42
52
  },
43
53
  "files": [
44
- "config.d.ts",
54
+ "config.schema.json",
45
55
  "dist"
46
56
  ],
47
57
  "scripts": {
@@ -54,20 +64,20 @@
54
64
  "test": "backstage-cli package test"
55
65
  },
56
66
  "dependencies": {
57
- "@backstage/backend-plugin-api": "1.9.2-next.0",
67
+ "@backstage/backend-plugin-api": "1.9.3-next.0",
58
68
  "@backstage/catalog-model": "1.9.0",
59
69
  "@backstage/config": "1.3.8",
60
70
  "@backstage/errors": "1.3.1",
61
- "@backstage/integration": "2.0.3-next.0",
71
+ "@backstage/integration": "2.0.3",
62
72
  "@backstage/plugin-catalog-common": "1.1.10",
63
- "@backstage/plugin-catalog-node": "2.2.2-next.0",
64
- "@backstage/plugin-events-node": "0.4.23-next.0"
73
+ "@backstage/plugin-catalog-node": "2.2.3-next.0",
74
+ "@backstage/plugin-events-node": "0.4.24-next.0"
65
75
  },
66
76
  "devDependencies": {
67
- "@backstage/backend-test-utils": "1.11.4-next.0",
68
- "@backstage/cli": "0.36.3-next.0",
69
- "@backstage/plugin-events-backend-test-utils": "0.1.56-next.0",
77
+ "@backstage/backend-test-utils": "1.11.5-next.0",
78
+ "@backstage/cli": "0.36.4-next.0",
79
+ "@backstage/plugin-events-backend-test-utils": "0.1.57-next.0",
70
80
  "msw": "^1.0.0"
71
81
  },
72
- "configSchema": "config.d.ts"
82
+ "configSchema": "config.schema.json"
73
83
  }
package/config.d.ts DELETED
@@ -1,104 +0,0 @@
1
- /*
2
- * Copyright 2022 The Backstage Authors
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- import { SchedulerServiceTaskScheduleDefinitionConfig } from '@backstage/backend-plugin-api';
18
-
19
- export interface Config {
20
- catalog?: {
21
- providers?: {
22
- /**
23
- * BitbucketServerEntityProvider configuration
24
- *
25
- * Uses "default" as default id for the single config variant.
26
- */
27
- bitbucketServer?:
28
- | {
29
- /**
30
- * (Optional) Path to the catalog file. Default to "/catalog-info.yaml".
31
- * @visibility frontend
32
- */
33
- catalogPath?: string;
34
- /**
35
- * (Optional) Filters applied to discovered catalog files in repositories.
36
- * @visibility frontend
37
- */
38
- filters?: {
39
- /**
40
- * (Optional) Regular expression filter for the repository slug.
41
- * @visibility frontend
42
- */
43
- repoSlug?: string;
44
- /**
45
- * (Optional) Regular expression filter for the project key.
46
- * @visibility frontend
47
- */
48
- projectKey?: string;
49
- /**
50
- * (Optional) Skip archived repositories
51
- */
52
- skipArchivedRepos?: boolean;
53
- };
54
- /**
55
- * (Optional) Whether to validate locations that exist before emitting them.
56
- * Default: `false`.
57
- */
58
- validateLocationsExist?: boolean;
59
- /**
60
- * (Optional) TaskScheduleDefinition for the refresh.
61
- */
62
- schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
63
- }
64
- | {
65
- [name: string]: {
66
- /**
67
- * (Optional) Path to the catalog file. Default to "/catalog-info.yaml".
68
- * @visibility frontend
69
- */
70
- catalogPath?: string;
71
- /**
72
- * (Optional) Filters applied to discovered catalog files in repositories.
73
- * @visibility frontend
74
- */
75
- filters?: {
76
- /**
77
- * (Optional) Regular expression filter for the repository slug.
78
- * @visibility frontend
79
- */
80
- repoSlug?: string;
81
- /**
82
- * (Optional) Regular expression filter for the project key.
83
- * @visibility frontend
84
- */
85
- projectKey?: string;
86
- /**
87
- * (Optional) Skip archived repositories
88
- */
89
- skipArchivedRepos?: boolean;
90
- };
91
- /**
92
- * (Optional) Whether to validate locations that exist before emitting them.
93
- * Default: `false`.
94
- */
95
- validateLocationsExist?: boolean;
96
- /**
97
- * (Optional) TaskScheduleDefinition for the refresh.
98
- */
99
- schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
100
- };
101
- };
102
- };
103
- };
104
- }