@backstage/plugin-catalog-backend-module-bitbucket-server 0.5.11 → 0.5.12

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,26 @@
1
1
  # @backstage/plugin-catalog-backend-module-bitbucket-server
2
2
 
3
+ ## 0.5.12
4
+
5
+ ### Patch Changes
6
+
7
+ - 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.
8
+ - Updated dependencies
9
+ - @backstage/integration@2.0.3
10
+ - @backstage/backend-plugin-api@1.9.2
11
+ - @backstage/plugin-catalog-node@2.2.2
12
+ - @backstage/plugin-events-node@0.4.23
13
+
14
+ ## 0.5.12-next.0
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies
19
+ - @backstage/integration@2.0.3-next.0
20
+ - @backstage/plugin-catalog-node@2.2.2-next.0
21
+ - @backstage/backend-plugin-api@1.9.2-next.0
22
+ - @backstage/plugin-events-node@0.4.23-next.0
23
+
3
24
  ## 0.5.11
4
25
 
5
26
  ### Patch Changes
@@ -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.11",
3
+ "version": "0.5.12",
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,12 +30,21 @@
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
  ]
@@ -54,19 +64,19 @@
54
64
  "test": "backstage-cli package test"
55
65
  },
56
66
  "dependencies": {
57
- "@backstage/backend-plugin-api": "^1.9.1",
67
+ "@backstage/backend-plugin-api": "^1.9.2",
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.2",
71
+ "@backstage/integration": "^2.0.3",
62
72
  "@backstage/plugin-catalog-common": "^1.1.10",
63
- "@backstage/plugin-catalog-node": "^2.2.1",
64
- "@backstage/plugin-events-node": "^0.4.22"
73
+ "@backstage/plugin-catalog-node": "^2.2.2",
74
+ "@backstage/plugin-events-node": "^0.4.23"
65
75
  },
66
76
  "devDependencies": {
67
- "@backstage/backend-test-utils": "^1.11.3",
68
- "@backstage/cli": "^0.36.2",
69
- "@backstage/plugin-events-backend-test-utils": "^0.1.55",
77
+ "@backstage/backend-test-utils": "^1.11.4",
78
+ "@backstage/cli": "^0.36.3",
79
+ "@backstage/plugin-events-backend-test-utils": "^0.1.56",
70
80
  "msw": "^1.0.0"
71
81
  },
72
82
  "configSchema": "config.d.ts"