@backstage/plugin-catalog-backend-module-azure 0.3.22 → 0.3.23-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,18 @@
1
1
  # @backstage/plugin-catalog-backend-module-azure
2
2
 
3
+ ## 0.3.23-next.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @backstage/integration@2.1.3-next.0
9
+ - @backstage/config@1.3.10-next.0
10
+ - @backstage/errors@1.3.2-next.0
11
+ - @backstage/backend-plugin-api@1.10.2-next.0
12
+ - @backstage/plugin-catalog-node@2.2.6-next.0
13
+ - @backstage/plugin-events-node@0.4.27-next.0
14
+ - @backstage/plugin-catalog-common@1.2.1-next.0
15
+
3
16
  ## 0.3.22
4
17
 
5
18
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.cjs.js","sources":["../src/alpha.ts"],"sourcesContent":["/*\n * Copyright 2023 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 analyzeAzureDevOpsWebhookEvent,\n type AnalyzeAzureDevOpsWebhookEventOptions,\n type AnalyzeAzureDevOpsWebhookEventResult,\n} from './events/analyzeAzureDevOpsWebhookEvent';\n"],"names":["feature"],"mappings":";;;;;;;AAmBA,MAAM,QAAA,GAAWA;;;;;"}
1
+ {"version":3,"file":"alpha.cjs.js","sources":["../src/alpha.ts"],"sourcesContent":["/*\n * Copyright 2023 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 analyzeAzureDevOpsWebhookEvent,\n type AnalyzeAzureDevOpsWebhookEventOptions,\n type AnalyzeAzureDevOpsWebhookEventResult,\n} from './events/analyzeAzureDevOpsWebhookEvent';\n"],"names":["feature"],"mappings":";;;;;;;AAmBA,MAAM,QAAA,GAAWA;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AzureDevOpsScmEventsBridge.cjs.js","sources":["../../src/events/AzureDevOpsScmEventsBridge.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 { analyzeAzureDevOpsWebhookEvent } from './analyzeAzureDevOpsWebhookEvent';\n\n/**\n * Takes Azure DevOps webhook events, analyzes them, and publishes them as\n * catalog SCM events that entity providers and others can subscribe to.\n */\nexport class AzureDevOpsScmEventsBridge {\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-azure-devops-scm-events-bridge',\n topics: ['azureDevOps'],\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 eventPayload = params.eventPayload as\n | { eventType?: string }\n | undefined;\n const eventType = eventPayload?.eventType;\n if (!eventType || !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 Azure DevOps 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 analyzeAzureDevOpsWebhookEvent(\n eventType,\n eventPayload,\n {\n isRelevantPath: path =>\n path.endsWith('.yaml') || path.endsWith('.yml'),\n },\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 Azure DevOps 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 Azure DevOps 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 Azure DevOps 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 Azure DevOps webhook event of type \"${eventType}\"`,\n error,\n );\n } finally {\n this.#pendingPublish = undefined;\n }\n });\n\n await this.#pendingPublish;\n }\n}\n"],"names":["analyzeAzureDevOpsWebhookEvent"],"mappings":"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"}
1
+ {"version":3,"file":"AzureDevOpsScmEventsBridge.cjs.js","sources":["../../src/events/AzureDevOpsScmEventsBridge.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 { analyzeAzureDevOpsWebhookEvent } from './analyzeAzureDevOpsWebhookEvent';\n\n/**\n * Takes Azure DevOps webhook events, analyzes them, and publishes them as\n * catalog SCM events that entity providers and others can subscribe to.\n */\nexport class AzureDevOpsScmEventsBridge {\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-azure-devops-scm-events-bridge',\n topics: ['azureDevOps'],\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 eventPayload = params.eventPayload as\n | { eventType?: string }\n | undefined;\n const eventType = eventPayload?.eventType;\n if (!eventType || !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 Azure DevOps 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 analyzeAzureDevOpsWebhookEvent(\n eventType,\n eventPayload,\n {\n isRelevantPath: path =>\n path.endsWith('.yaml') || path.endsWith('.yml'),\n },\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 Azure DevOps 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 Azure DevOps 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 Azure DevOps 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 Azure DevOps webhook event of type \"${eventType}\"`,\n error,\n );\n } finally {\n this.#pendingPublish = undefined;\n }\n });\n\n await this.#pendingPublish;\n }\n}\n"],"names":["analyzeAzureDevOpsWebhookEvent"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeAzureDevOpsWebhookEvent.cjs.js","sources":["../../src/events/analyzeAzureDevOpsWebhookEvent.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 * Options for {@link analyzeAzureDevOpsWebhookEvent}.\n * @alpha\n */\nexport interface AnalyzeAzureDevOpsWebhookEventOptions {\n /**\n * Predicate that returns true for file paths that are relevant to the\n * catalog (e.g. paths ending in `.yaml` or `.yml`).\n */\n isRelevantPath: (path: string) => boolean;\n}\n\n/**\n * The result of analyzing an Azure DevOps 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 AnalyzeAzureDevOpsWebhookEventResult =\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\ntype AzureRepository = {\n name?: string;\n defaultBranch?: string;\n remoteUrl?: string;\n};\n\ntype AzurePushRefUpdate = {\n name?: string;\n};\n\ntype AzurePushCommit = {\n commitId?: string;\n url?: string;\n changes?: AzurePushCommitChange[];\n added?: string[];\n removed?: string[];\n modified?: string[];\n};\n\ntype AzurePushCommitChange = {\n changeType?: string;\n item?: {\n path?: string;\n originalPath?: string;\n };\n path?: string;\n newPath?: string;\n oldPath?: string;\n originalPath?: string;\n sourceServerItem?: string;\n};\n\ntype PushPathState =\n | {\n type: 'added';\n commit: AzurePushCommit;\n }\n | {\n type: 'removed';\n commit: AzurePushCommit;\n }\n | {\n type: 'changed';\n commit: AzurePushCommit;\n }\n | {\n type: 'renamed';\n fromPath: string;\n commit: AzurePushCommit;\n };\n\ntype NormalizedPushChange =\n | {\n type: 'added';\n path: string;\n }\n | {\n type: 'removed';\n path: string;\n }\n | {\n type: 'changed';\n path: string;\n }\n | {\n type: 'renamed';\n fromPath: string;\n toPath: string;\n };\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 asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction normalizePath(path: string | undefined): string | undefined {\n if (!path) {\n return undefined;\n }\n return path.startsWith('/') ? path : `/${path}`;\n}\n\nfunction getRepository(resource: JsonObject | undefined): AzureRepository {\n const repository = asObject(resource?.repository);\n return {\n name: asString(repository?.name),\n defaultBranch: asString(repository?.defaultBranch),\n remoteUrl: asString(repository?.remoteUrl),\n };\n}\n\nfunction toLocationUrl(options: {\n remoteUrl: string | undefined;\n path: string;\n}): string | undefined {\n if (!options.remoteUrl) {\n return undefined;\n }\n\n // Match the URL format produced by AzureDevOpsEntityProvider.createObjectUrl\n // which uses encodeURI on the full URL string with path and version as raw\n // query parameter values.\n //\n // The version parameter is intentionally omitted here because the entity\n // provider only includes it when the user explicitly configures a `branch`\n // in the provider config. Since we cannot know at analysis time whether a\n // branch was configured, omitting version matches the default provider\n // behavior and avoids URL mismatches that would prevent SCM events from\n // triggering catalog refreshes.\n const fullUrl = `${options.remoteUrl}?path=${options.path}`;\n return encodeURI(fullUrl);\n}\n\nfunction toCommitUrl(\n repository: AzureRepository,\n commit: AzurePushCommit,\n): string | undefined {\n if (commit.url) {\n return commit.url;\n }\n if (repository.remoteUrl && commit.commitId) {\n return `${repository.remoteUrl}/commit/${commit.commitId}`;\n }\n return undefined;\n}\n\nfunction toCatalogScmEventForPathState(options: {\n repository: AzureRepository;\n path: string;\n pathState: PushPathState;\n isRelevantPath: (path: string) => boolean;\n}): CatalogScmEvent[] {\n const { repository, path, pathState, isRelevantPath } = options;\n const commitUrl = toCommitUrl(repository, pathState.commit);\n const context = commitUrl ? { commitUrl } : undefined;\n\n if (pathState.type === 'renamed') {\n const fromRelevant = isRelevantPath(pathState.fromPath);\n const toRelevant = isRelevantPath(path);\n const fromUrl = toLocationUrl({\n remoteUrl: repository.remoteUrl,\n path: pathState.fromPath,\n });\n const toUrl = toLocationUrl({\n remoteUrl: repository.remoteUrl,\n path,\n });\n\n if (fromRelevant && toRelevant && fromUrl && toUrl) {\n return [{ type: 'location.moved', fromUrl, toUrl, context }];\n }\n if (fromRelevant && !toRelevant && fromUrl) {\n return [{ type: 'location.deleted', url: fromUrl, context }];\n }\n if (!fromRelevant && toRelevant && toUrl) {\n return [{ type: 'location.created', url: toUrl, context }];\n }\n return [];\n }\n\n if (!isRelevantPath(path)) {\n return [];\n }\n\n const url = toLocationUrl({\n remoteUrl: repository.remoteUrl,\n path,\n });\n if (!url) {\n return [];\n }\n\n if (pathState.type === 'added') {\n return [{ type: 'location.created', url, context }];\n }\n if (pathState.type === 'removed') {\n return [{ type: 'location.deleted', url, context }];\n }\n\n return [{ type: 'location.updated', url, context }];\n}\n\nfunction normalizePushCommitChanges(\n commit: AzurePushCommit,\n): NormalizedPushChange[] {\n const normalized: NormalizedPushChange[] = [];\n\n for (const path of commit.added ?? []) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath) {\n normalized.push({ type: 'added', path: normalizedPath });\n }\n }\n\n for (const path of commit.removed ?? []) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath) {\n normalized.push({ type: 'removed', path: normalizedPath });\n }\n }\n\n for (const path of commit.modified ?? []) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath) {\n normalized.push({ type: 'changed', path: normalizedPath });\n }\n }\n\n for (const change of commit.changes ?? []) {\n const changeType = change.changeType?.toLowerCase() ?? '';\n const toPath = normalizePath(\n change.item?.path ?? change.path ?? change.newPath,\n );\n const fromPath = normalizePath(\n change.originalPath ??\n change.item?.originalPath ??\n change.oldPath ??\n change.sourceServerItem,\n );\n\n if (changeType.includes('rename') && fromPath && toPath) {\n normalized.push({ type: 'renamed', fromPath, toPath });\n continue;\n }\n\n if (changeType.includes('add') && toPath) {\n normalized.push({ type: 'added', path: toPath });\n continue;\n }\n\n if (changeType.includes('delete') && (toPath ?? fromPath)) {\n normalized.push({ type: 'removed', path: toPath ?? fromPath! });\n continue;\n }\n\n if (\n (changeType.includes('edit') ||\n changeType.includes('modify') ||\n changeType.includes('update')) &&\n (toPath ?? fromPath)\n ) {\n normalized.push({ type: 'changed', path: toPath ?? fromPath! });\n }\n }\n\n return normalized;\n}\n\nfunction applyPushChange(\n state: Map<string, PushPathState>,\n change: NormalizedPushChange,\n commit: AzurePushCommit,\n) {\n if (change.type === 'renamed') {\n const previous = state.get(change.fromPath);\n state.delete(change.fromPath);\n\n let next: PushPathState | undefined;\n if (!previous) {\n next = { type: 'renamed', fromPath: change.fromPath, commit };\n } else if (previous.type === 'added') {\n next = { type: 'added', commit };\n } else if (previous.type === 'changed') {\n next = { type: 'renamed', fromPath: change.fromPath, commit };\n } else if (previous.type === 'renamed') {\n next = { type: 'renamed', fromPath: previous.fromPath, commit };\n }\n\n if (next) {\n state.set(change.toPath, next);\n }\n return;\n }\n\n const previous = state.get(change.path);\n\n if (change.type === 'added') {\n if (!previous) {\n state.set(change.path, { type: 'added', commit });\n } else if (previous.type === 'removed') {\n state.set(change.path, { type: 'changed', commit });\n }\n return;\n }\n\n if (change.type === 'removed') {\n if (!previous) {\n state.set(change.path, { type: 'removed', commit });\n } else if (previous.type === 'added') {\n state.delete(change.path);\n } else if (previous.type === 'changed') {\n state.set(change.path, { type: 'removed', commit });\n } else if (previous.type === 'renamed') {\n state.delete(change.path);\n state.set(previous.fromPath, { type: 'removed', commit });\n }\n return;\n }\n\n if (!previous) {\n state.set(change.path, { type: 'changed', commit });\n }\n}\n\nfunction replaceRepoNameInRemoteUrl(\n remoteUrl: string | undefined,\n repoName: string | undefined,\n): string | undefined {\n if (!remoteUrl || !repoName) {\n return undefined;\n }\n const gitMarker = '/_git/';\n const gitIdx = remoteUrl.indexOf(gitMarker);\n if (gitIdx === -1) {\n return undefined;\n }\n const prefix = remoteUrl.slice(0, gitIdx + gitMarker.length);\n const rest = remoteUrl.slice(gitIdx + gitMarker.length);\n const endIdx = rest.search(/[/?#]/);\n const suffix = endIdx === -1 ? '' : rest.slice(endIdx);\n return `${prefix}${repoName}${suffix}`;\n}\n\nasync function onPushEvent(\n eventPayload: JsonObject,\n options: AnalyzeAzureDevOpsWebhookEventOptions,\n): Promise<AnalyzeAzureDevOpsWebhookEventResult> {\n const resource = asObject(eventPayload.resource);\n const repository = getRepository(resource);\n const refUpdates =\n (resource?.refUpdates as AzurePushRefUpdate[] | undefined) ?? [];\n const commits = (resource?.commits as AzurePushCommit[] | undefined) ?? [];\n const contextUrl =\n asString(resource?.url) ?? repository.remoteUrl ?? '<unknown>';\n\n if (commits.length === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event does not contain commits: ${contextUrl}`,\n };\n }\n\n if (repository.defaultBranch) {\n const updatesToDefaultBranch = refUpdates.filter(\n update => update.name === repository.defaultBranch,\n );\n if (updatesToDefaultBranch.length === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event did not target the default branch, expected \"${repository.defaultBranch}\": ${contextUrl}`,\n };\n }\n }\n\n const state = new Map<string, PushPathState>();\n\n for (const commit of commits) {\n const changes = normalizePushCommitChanges(commit);\n for (const change of changes) {\n applyPushChange(state, change, commit);\n }\n }\n\n if (state.size === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event did not affect any relevant paths: ${contextUrl}`,\n };\n }\n\n const events = Array.from(state.entries()).flatMap(([path, pathState]) =>\n toCatalogScmEventForPathState({\n repository,\n path,\n pathState,\n isRelevantPath: options.isRelevantPath,\n }),\n );\n\n if (events.length === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event did not affect any relevant paths: ${contextUrl}`,\n };\n }\n\n return { result: 'ok', events };\n}\n\nasync function onRepositoryEvent(\n eventType: string,\n eventPayload: JsonObject,\n): Promise<AnalyzeAzureDevOpsWebhookEventResult> {\n const resource = asObject(eventPayload.resource);\n const repository = getRepository(resource);\n const toUrl = repository.remoteUrl;\n\n if (eventType === 'git.repo.created' && toUrl) {\n return {\n result: 'ok',\n events: [{ type: 'repository.created', url: toUrl }],\n };\n }\n\n if (eventType === 'git.repo.deleted' && toUrl) {\n return {\n result: 'ok',\n events: [{ type: 'repository.deleted', url: toUrl }],\n };\n }\n\n if (eventType === 'git.repo.statuschanged' && toUrl) {\n return {\n result: 'ok',\n events: [{ type: 'repository.updated', url: toUrl }],\n };\n }\n\n if (eventType === 'git.repo.renamed' && toUrl) {\n const oldName = asString(resource?.oldName);\n const fromUrl = oldName\n ? replaceRepoNameInRemoteUrl(toUrl, oldName)\n : undefined;\n if (!fromUrl) {\n return {\n result: 'ignored',\n reason: oldName\n ? 'Azure DevOps repository renamed event has an unexpected repository.remoteUrl format'\n : 'Azure DevOps repository renamed event is missing oldName',\n };\n }\n\n return {\n result: 'ok',\n events: [{ type: 'repository.moved', fromUrl, toUrl }],\n };\n }\n\n if (eventType.startsWith('git.repo.')) {\n return {\n result: 'unsupported-event',\n event: eventType,\n };\n }\n\n return {\n result: 'unsupported-event',\n event: eventType,\n };\n}\n\n/**\n * Analyzes an Azure DevOps webhook event and translates it into zero or more\n * catalog SCM events that entity providers can act on.\n *\n * Supported event types:\n * - `git.push` — translates file-level adds, modifications, and deletions on\n * the default branch into catalog SCM events for paths matching\n * `isRelevantPath`.\n * - `git.repo.created` — emits a `repository.created` event.\n * - `git.repo.deleted` — emits a `repository.deleted` event.\n * - `git.repo.statuschanged` — emits a `repository.updated` event.\n * - `git.repo.renamed` — emits a `repository.moved` event with the old and\n * new repository URLs.\n *\n * @alpha\n */\nexport async function analyzeAzureDevOpsWebhookEvent(\n eventType: string,\n eventPayload: unknown,\n options: AnalyzeAzureDevOpsWebhookEventOptions,\n): Promise<AnalyzeAzureDevOpsWebhookEventResult> {\n const payload = asObject(eventPayload);\n if (!payload) {\n throw new InputError('Azure DevOps webhook event payload is not an object');\n }\n\n if (eventType === 'git.push') {\n return await onPushEvent(payload, options);\n }\n\n if (eventType.startsWith('git.repo.')) {\n return await onRepositoryEvent(eventType, payload);\n }\n\n return {\n result: 'unsupported-event',\n event: eventType,\n };\n}\n"],"names":["previous","InputError"],"mappings":"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"}
1
+ {"version":3,"file":"analyzeAzureDevOpsWebhookEvent.cjs.js","sources":["../../src/events/analyzeAzureDevOpsWebhookEvent.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 * Options for {@link analyzeAzureDevOpsWebhookEvent}.\n * @alpha\n */\nexport interface AnalyzeAzureDevOpsWebhookEventOptions {\n /**\n * Predicate that returns true for file paths that are relevant to the\n * catalog (e.g. paths ending in `.yaml` or `.yml`).\n */\n isRelevantPath: (path: string) => boolean;\n}\n\n/**\n * The result of analyzing an Azure DevOps 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 AnalyzeAzureDevOpsWebhookEventResult =\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\ntype AzureRepository = {\n name?: string;\n defaultBranch?: string;\n remoteUrl?: string;\n};\n\ntype AzurePushRefUpdate = {\n name?: string;\n};\n\ntype AzurePushCommit = {\n commitId?: string;\n url?: string;\n changes?: AzurePushCommitChange[];\n added?: string[];\n removed?: string[];\n modified?: string[];\n};\n\ntype AzurePushCommitChange = {\n changeType?: string;\n item?: {\n path?: string;\n originalPath?: string;\n };\n path?: string;\n newPath?: string;\n oldPath?: string;\n originalPath?: string;\n sourceServerItem?: string;\n};\n\ntype PushPathState =\n | {\n type: 'added';\n commit: AzurePushCommit;\n }\n | {\n type: 'removed';\n commit: AzurePushCommit;\n }\n | {\n type: 'changed';\n commit: AzurePushCommit;\n }\n | {\n type: 'renamed';\n fromPath: string;\n commit: AzurePushCommit;\n };\n\ntype NormalizedPushChange =\n | {\n type: 'added';\n path: string;\n }\n | {\n type: 'removed';\n path: string;\n }\n | {\n type: 'changed';\n path: string;\n }\n | {\n type: 'renamed';\n fromPath: string;\n toPath: string;\n };\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 asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction normalizePath(path: string | undefined): string | undefined {\n if (!path) {\n return undefined;\n }\n return path.startsWith('/') ? path : `/${path}`;\n}\n\nfunction getRepository(resource: JsonObject | undefined): AzureRepository {\n const repository = asObject(resource?.repository);\n return {\n name: asString(repository?.name),\n defaultBranch: asString(repository?.defaultBranch),\n remoteUrl: asString(repository?.remoteUrl),\n };\n}\n\nfunction toLocationUrl(options: {\n remoteUrl: string | undefined;\n path: string;\n}): string | undefined {\n if (!options.remoteUrl) {\n return undefined;\n }\n\n // Match the URL format produced by AzureDevOpsEntityProvider.createObjectUrl\n // which uses encodeURI on the full URL string with path and version as raw\n // query parameter values.\n //\n // The version parameter is intentionally omitted here because the entity\n // provider only includes it when the user explicitly configures a `branch`\n // in the provider config. Since we cannot know at analysis time whether a\n // branch was configured, omitting version matches the default provider\n // behavior and avoids URL mismatches that would prevent SCM events from\n // triggering catalog refreshes.\n const fullUrl = `${options.remoteUrl}?path=${options.path}`;\n return encodeURI(fullUrl);\n}\n\nfunction toCommitUrl(\n repository: AzureRepository,\n commit: AzurePushCommit,\n): string | undefined {\n if (commit.url) {\n return commit.url;\n }\n if (repository.remoteUrl && commit.commitId) {\n return `${repository.remoteUrl}/commit/${commit.commitId}`;\n }\n return undefined;\n}\n\nfunction toCatalogScmEventForPathState(options: {\n repository: AzureRepository;\n path: string;\n pathState: PushPathState;\n isRelevantPath: (path: string) => boolean;\n}): CatalogScmEvent[] {\n const { repository, path, pathState, isRelevantPath } = options;\n const commitUrl = toCommitUrl(repository, pathState.commit);\n const context = commitUrl ? { commitUrl } : undefined;\n\n if (pathState.type === 'renamed') {\n const fromRelevant = isRelevantPath(pathState.fromPath);\n const toRelevant = isRelevantPath(path);\n const fromUrl = toLocationUrl({\n remoteUrl: repository.remoteUrl,\n path: pathState.fromPath,\n });\n const toUrl = toLocationUrl({\n remoteUrl: repository.remoteUrl,\n path,\n });\n\n if (fromRelevant && toRelevant && fromUrl && toUrl) {\n return [{ type: 'location.moved', fromUrl, toUrl, context }];\n }\n if (fromRelevant && !toRelevant && fromUrl) {\n return [{ type: 'location.deleted', url: fromUrl, context }];\n }\n if (!fromRelevant && toRelevant && toUrl) {\n return [{ type: 'location.created', url: toUrl, context }];\n }\n return [];\n }\n\n if (!isRelevantPath(path)) {\n return [];\n }\n\n const url = toLocationUrl({\n remoteUrl: repository.remoteUrl,\n path,\n });\n if (!url) {\n return [];\n }\n\n if (pathState.type === 'added') {\n return [{ type: 'location.created', url, context }];\n }\n if (pathState.type === 'removed') {\n return [{ type: 'location.deleted', url, context }];\n }\n\n return [{ type: 'location.updated', url, context }];\n}\n\nfunction normalizePushCommitChanges(\n commit: AzurePushCommit,\n): NormalizedPushChange[] {\n const normalized: NormalizedPushChange[] = [];\n\n for (const path of commit.added ?? []) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath) {\n normalized.push({ type: 'added', path: normalizedPath });\n }\n }\n\n for (const path of commit.removed ?? []) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath) {\n normalized.push({ type: 'removed', path: normalizedPath });\n }\n }\n\n for (const path of commit.modified ?? []) {\n const normalizedPath = normalizePath(path);\n if (normalizedPath) {\n normalized.push({ type: 'changed', path: normalizedPath });\n }\n }\n\n for (const change of commit.changes ?? []) {\n const changeType = change.changeType?.toLowerCase() ?? '';\n const toPath = normalizePath(\n change.item?.path ?? change.path ?? change.newPath,\n );\n const fromPath = normalizePath(\n change.originalPath ??\n change.item?.originalPath ??\n change.oldPath ??\n change.sourceServerItem,\n );\n\n if (changeType.includes('rename') && fromPath && toPath) {\n normalized.push({ type: 'renamed', fromPath, toPath });\n continue;\n }\n\n if (changeType.includes('add') && toPath) {\n normalized.push({ type: 'added', path: toPath });\n continue;\n }\n\n if (changeType.includes('delete') && (toPath ?? fromPath)) {\n normalized.push({ type: 'removed', path: toPath ?? fromPath! });\n continue;\n }\n\n if (\n (changeType.includes('edit') ||\n changeType.includes('modify') ||\n changeType.includes('update')) &&\n (toPath ?? fromPath)\n ) {\n normalized.push({ type: 'changed', path: toPath ?? fromPath! });\n }\n }\n\n return normalized;\n}\n\nfunction applyPushChange(\n state: Map<string, PushPathState>,\n change: NormalizedPushChange,\n commit: AzurePushCommit,\n) {\n if (change.type === 'renamed') {\n const previous = state.get(change.fromPath);\n state.delete(change.fromPath);\n\n let next: PushPathState | undefined;\n if (!previous) {\n next = { type: 'renamed', fromPath: change.fromPath, commit };\n } else if (previous.type === 'added') {\n next = { type: 'added', commit };\n } else if (previous.type === 'changed') {\n next = { type: 'renamed', fromPath: change.fromPath, commit };\n } else if (previous.type === 'renamed') {\n next = { type: 'renamed', fromPath: previous.fromPath, commit };\n }\n\n if (next) {\n state.set(change.toPath, next);\n }\n return;\n }\n\n const previous = state.get(change.path);\n\n if (change.type === 'added') {\n if (!previous) {\n state.set(change.path, { type: 'added', commit });\n } else if (previous.type === 'removed') {\n state.set(change.path, { type: 'changed', commit });\n }\n return;\n }\n\n if (change.type === 'removed') {\n if (!previous) {\n state.set(change.path, { type: 'removed', commit });\n } else if (previous.type === 'added') {\n state.delete(change.path);\n } else if (previous.type === 'changed') {\n state.set(change.path, { type: 'removed', commit });\n } else if (previous.type === 'renamed') {\n state.delete(change.path);\n state.set(previous.fromPath, { type: 'removed', commit });\n }\n return;\n }\n\n if (!previous) {\n state.set(change.path, { type: 'changed', commit });\n }\n}\n\nfunction replaceRepoNameInRemoteUrl(\n remoteUrl: string | undefined,\n repoName: string | undefined,\n): string | undefined {\n if (!remoteUrl || !repoName) {\n return undefined;\n }\n const gitMarker = '/_git/';\n const gitIdx = remoteUrl.indexOf(gitMarker);\n if (gitIdx === -1) {\n return undefined;\n }\n const prefix = remoteUrl.slice(0, gitIdx + gitMarker.length);\n const rest = remoteUrl.slice(gitIdx + gitMarker.length);\n const endIdx = rest.search(/[/?#]/);\n const suffix = endIdx === -1 ? '' : rest.slice(endIdx);\n return `${prefix}${repoName}${suffix}`;\n}\n\nasync function onPushEvent(\n eventPayload: JsonObject,\n options: AnalyzeAzureDevOpsWebhookEventOptions,\n): Promise<AnalyzeAzureDevOpsWebhookEventResult> {\n const resource = asObject(eventPayload.resource);\n const repository = getRepository(resource);\n const refUpdates =\n (resource?.refUpdates as AzurePushRefUpdate[] | undefined) ?? [];\n const commits = (resource?.commits as AzurePushCommit[] | undefined) ?? [];\n const contextUrl =\n asString(resource?.url) ?? repository.remoteUrl ?? '<unknown>';\n\n if (commits.length === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event does not contain commits: ${contextUrl}`,\n };\n }\n\n if (repository.defaultBranch) {\n const updatesToDefaultBranch = refUpdates.filter(\n update => update.name === repository.defaultBranch,\n );\n if (updatesToDefaultBranch.length === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event did not target the default branch, expected \"${repository.defaultBranch}\": ${contextUrl}`,\n };\n }\n }\n\n const state = new Map<string, PushPathState>();\n\n for (const commit of commits) {\n const changes = normalizePushCommitChanges(commit);\n for (const change of changes) {\n applyPushChange(state, change, commit);\n }\n }\n\n if (state.size === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event did not affect any relevant paths: ${contextUrl}`,\n };\n }\n\n const events = Array.from(state.entries()).flatMap(([path, pathState]) =>\n toCatalogScmEventForPathState({\n repository,\n path,\n pathState,\n isRelevantPath: options.isRelevantPath,\n }),\n );\n\n if (events.length === 0) {\n return {\n result: 'ignored',\n reason: `Azure DevOps push event did not affect any relevant paths: ${contextUrl}`,\n };\n }\n\n return { result: 'ok', events };\n}\n\nasync function onRepositoryEvent(\n eventType: string,\n eventPayload: JsonObject,\n): Promise<AnalyzeAzureDevOpsWebhookEventResult> {\n const resource = asObject(eventPayload.resource);\n const repository = getRepository(resource);\n const toUrl = repository.remoteUrl;\n\n if (eventType === 'git.repo.created' && toUrl) {\n return {\n result: 'ok',\n events: [{ type: 'repository.created', url: toUrl }],\n };\n }\n\n if (eventType === 'git.repo.deleted' && toUrl) {\n return {\n result: 'ok',\n events: [{ type: 'repository.deleted', url: toUrl }],\n };\n }\n\n if (eventType === 'git.repo.statuschanged' && toUrl) {\n return {\n result: 'ok',\n events: [{ type: 'repository.updated', url: toUrl }],\n };\n }\n\n if (eventType === 'git.repo.renamed' && toUrl) {\n const oldName = asString(resource?.oldName);\n const fromUrl = oldName\n ? replaceRepoNameInRemoteUrl(toUrl, oldName)\n : undefined;\n if (!fromUrl) {\n return {\n result: 'ignored',\n reason: oldName\n ? 'Azure DevOps repository renamed event has an unexpected repository.remoteUrl format'\n : 'Azure DevOps repository renamed event is missing oldName',\n };\n }\n\n return {\n result: 'ok',\n events: [{ type: 'repository.moved', fromUrl, toUrl }],\n };\n }\n\n if (eventType.startsWith('git.repo.')) {\n return {\n result: 'unsupported-event',\n event: eventType,\n };\n }\n\n return {\n result: 'unsupported-event',\n event: eventType,\n };\n}\n\n/**\n * Analyzes an Azure DevOps webhook event and translates it into zero or more\n * catalog SCM events that entity providers can act on.\n *\n * Supported event types:\n * - `git.push` — translates file-level adds, modifications, and deletions on\n * the default branch into catalog SCM events for paths matching\n * `isRelevantPath`.\n * - `git.repo.created` — emits a `repository.created` event.\n * - `git.repo.deleted` — emits a `repository.deleted` event.\n * - `git.repo.statuschanged` — emits a `repository.updated` event.\n * - `git.repo.renamed` — emits a `repository.moved` event with the old and\n * new repository URLs.\n *\n * @alpha\n */\nexport async function analyzeAzureDevOpsWebhookEvent(\n eventType: string,\n eventPayload: unknown,\n options: AnalyzeAzureDevOpsWebhookEventOptions,\n): Promise<AnalyzeAzureDevOpsWebhookEventResult> {\n const payload = asObject(eventPayload);\n if (!payload) {\n throw new InputError('Azure DevOps webhook event payload is not an object');\n }\n\n if (eventType === 'git.push') {\n return await onPushEvent(payload, options);\n }\n\n if (eventType.startsWith('git.repo.')) {\n return await onRepositoryEvent(eventType, payload);\n }\n\n return {\n result: 'unsupported-event',\n event: eventType,\n };\n}\n"],"names":["previous","InputError"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"azure.cjs.js","sources":["../../src/lib/azure.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AzureDevOpsCredentialsProvider,\n AzureIntegrationConfig,\n} from '@backstage/integration';\n\nexport interface CodeSearchResponse {\n count: number;\n results: CodeSearchResultItem[];\n}\n\nexport interface CodeSearchResultItem {\n fileName: string;\n path: string;\n repository: {\n name: string;\n };\n project: {\n name: string;\n };\n branch?: string;\n}\n\ninterface CodeSearchRequest {\n searchText: string;\n $orderBy: Array<{ field: string; sortOrder: string }>;\n $skip: number;\n $top: number;\n filters?: {\n Branch: string[];\n };\n}\n\nconst isCloud = (host: string) => {\n if (host === 'dev.azure.com') {\n return true;\n }\n\n if (host.endsWith('.visualstudio.com')) {\n return true;\n }\n\n return false;\n};\n\nconst PAGE_SIZE = 1000;\n\n// codeSearch returns all files that matches the given search path.\nexport async function codeSearch(\n credentialsProvider: AzureDevOpsCredentialsProvider,\n azureConfig: AzureIntegrationConfig,\n org: string,\n project: string,\n repo: string,\n path: string,\n branch: string,\n): Promise<CodeSearchResultItem[]> {\n const searchBaseUrl = isCloud(azureConfig.host)\n ? 'https://almsearch.dev.azure.com'\n : `https://${azureConfig.host}`;\n const searchUrl = `${searchBaseUrl}/${org}/_apis/search/codesearchresults?api-version=6.0-preview.1`;\n\n const url = azureConfig.host.endsWith('.visualstudio.com')\n ? `https://${azureConfig.host}`\n : `https://${azureConfig.host}/${org}`;\n\n let items: CodeSearchResultItem[] = [];\n let hasMorePages = true;\n\n do {\n const credentials = await credentialsProvider.getCredentials({\n url,\n });\n\n const searchRequestBody: CodeSearchRequest = {\n searchText: `path:${path} repo:${repo || '*'} proj:${project || '*'}`,\n $orderBy: [\n {\n field: 'path',\n sortOrder: 'ASC',\n },\n ],\n $skip: items.length,\n $top: PAGE_SIZE,\n };\n\n if (branch) {\n searchRequestBody.filters = { Branch: [branch] };\n }\n\n const response = await fetch(searchUrl, {\n headers: {\n ...credentials?.headers,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n body: JSON.stringify(searchRequestBody),\n });\n\n if (response.status !== 200) {\n throw new Error(\n `Azure DevOps search failed with response status ${response.status}`,\n );\n }\n\n const body: CodeSearchResponse = await response.json();\n items = [...items, ...body.results];\n hasMorePages = body.count > items.length;\n } while (hasMorePages);\n\n return items;\n}\n"],"names":[],"mappings":";;AAgDA,MAAM,OAAA,GAAU,CAAC,IAAA,KAAiB;AAChC,EAAA,IAAI,SAAS,eAAA,EAAiB;AAC5B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,mBAAmB,CAAA,EAAG;AACtC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA;AACT,CAAA;AAEA,MAAM,SAAA,GAAY,GAAA;AAGlB,eAAsB,WACpB,mBAAA,EACA,WAAA,EACA,KACA,OAAA,EACA,IAAA,EACA,MACA,MAAA,EACiC;AACjC,EAAA,MAAM,aAAA,GAAgB,QAAQ,WAAA,CAAY,IAAI,IAC1C,iCAAA,GACA,CAAA,QAAA,EAAW,YAAY,IAAI,CAAA,CAAA;AAC/B,EAAA,MAAM,SAAA,GAAY,CAAA,EAAG,aAAa,CAAA,CAAA,EAAI,GAAG,CAAA,yDAAA,CAAA;AAEzC,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,IAAA,CAAK,QAAA,CAAS,mBAAmB,CAAA,GACrD,CAAA,QAAA,EAAW,WAAA,CAAY,IAAI,CAAA,CAAA,GAC3B,CAAA,QAAA,EAAW,WAAA,CAAY,IAAI,IAAI,GAAG,CAAA,CAAA;AAEtC,EAAA,IAAI,QAAgC,EAAC;AACrC,EAAA,IAAI,YAAA,GAAe,IAAA;AAEnB,EAAA,GAAG;AACD,IAAA,MAAM,WAAA,GAAc,MAAM,mBAAA,CAAoB,cAAA,CAAe;AAAA,MAC3D;AAAA,KACD,CAAA;AAED,IAAA,MAAM,iBAAA,GAAuC;AAAA,MAC3C,UAAA,EAAY,QAAQ,IAAI,CAAA,MAAA,EAAS,QAAQ,GAAG,CAAA,MAAA,EAAS,WAAW,GAAG,CAAA,CAAA;AAAA,MACnE,QAAA,EAAU;AAAA,QACR;AAAA,UACE,KAAA,EAAO,MAAA;AAAA,UACP,SAAA,EAAW;AAAA;AACb,OACF;AAAA,MACA,OAAO,KAAA,CAAM,MAAA;AAAA,MACb,IAAA,EAAM;AAAA,KACR;AAEA,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,iBAAA,CAAkB,OAAA,GAAU,EAAE,MAAA,EAAQ,CAAC,MAAM,CAAA,EAAE;AAAA,IACjD;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,SAAA,EAAW;AAAA,MACtC,OAAA,EAAS;AAAA,QACP,GAAG,WAAA,EAAa,OAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,iBAAiB;AAAA,KACvC,CAAA;AAED,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,gDAAA,EAAmD,SAAS,MAAM,CAAA;AAAA,OACpE;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAA2B,MAAM,QAAA,CAAS,IAAA,EAAK;AACrD,IAAA,KAAA,GAAQ,CAAC,GAAG,KAAA,EAAO,GAAG,KAAK,OAAO,CAAA;AAClC,IAAA,YAAA,GAAe,IAAA,CAAK,QAAQ,KAAA,CAAM,MAAA;AAAA,EACpC,CAAA,QAAS,YAAA;AAET,EAAA,OAAO,KAAA;AACT;;;;"}
1
+ {"version":3,"file":"azure.cjs.js","sources":["../../src/lib/azure.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AzureDevOpsCredentialsProvider,\n AzureIntegrationConfig,\n} from '@backstage/integration';\n\nexport interface CodeSearchResponse {\n count: number;\n results: CodeSearchResultItem[];\n}\n\nexport interface CodeSearchResultItem {\n fileName: string;\n path: string;\n repository: {\n name: string;\n };\n project: {\n name: string;\n };\n branch?: string;\n}\n\ninterface CodeSearchRequest {\n searchText: string;\n $orderBy: Array<{ field: string; sortOrder: string }>;\n $skip: number;\n $top: number;\n filters?: {\n Branch: string[];\n };\n}\n\nconst isCloud = (host: string) => {\n if (host === 'dev.azure.com') {\n return true;\n }\n\n if (host.endsWith('.visualstudio.com')) {\n return true;\n }\n\n return false;\n};\n\nconst PAGE_SIZE = 1000;\n\n// codeSearch returns all files that matches the given search path.\nexport async function codeSearch(\n credentialsProvider: AzureDevOpsCredentialsProvider,\n azureConfig: AzureIntegrationConfig,\n org: string,\n project: string,\n repo: string,\n path: string,\n branch: string,\n): Promise<CodeSearchResultItem[]> {\n const searchBaseUrl = isCloud(azureConfig.host)\n ? 'https://almsearch.dev.azure.com'\n : `https://${azureConfig.host}`;\n const searchUrl = `${searchBaseUrl}/${org}/_apis/search/codesearchresults?api-version=6.0-preview.1`;\n\n const url = azureConfig.host.endsWith('.visualstudio.com')\n ? `https://${azureConfig.host}`\n : `https://${azureConfig.host}/${org}`;\n\n let items: CodeSearchResultItem[] = [];\n let hasMorePages = true;\n\n do {\n const credentials = await credentialsProvider.getCredentials({\n url,\n });\n\n const searchRequestBody: CodeSearchRequest = {\n searchText: `path:${path} repo:${repo || '*'} proj:${project || '*'}`,\n $orderBy: [\n {\n field: 'path',\n sortOrder: 'ASC',\n },\n ],\n $skip: items.length,\n $top: PAGE_SIZE,\n };\n\n if (branch) {\n searchRequestBody.filters = { Branch: [branch] };\n }\n\n const response = await fetch(searchUrl, {\n headers: {\n ...credentials?.headers,\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n body: JSON.stringify(searchRequestBody),\n });\n\n if (response.status !== 200) {\n throw new Error(\n `Azure DevOps search failed with response status ${response.status}`,\n );\n }\n\n const body: CodeSearchResponse = await response.json();\n items = [...items, ...body.results];\n hasMorePages = body.count > items.length;\n } while (hasMorePages);\n\n return items;\n}\n"],"names":[],"mappings":";;AAgDA,MAAM,OAAA,GAAU,CAAC,IAAA,KAAiB;AAChC,EAAA,IAAI,SAAS,eAAA,EAAiB;AAC5B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,IAAA,CAAK,QAAA,CAAS,mBAAmB,CAAA,EAAG;AACtC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,KAAA;AACT,CAAA;AAEA,MAAM,SAAA,GAAY,GAAA;AAGlB,eAAsB,WACpB,mBAAA,EACA,WAAA,EACA,KACA,OAAA,EACA,IAAA,EACA,MACA,MAAA,EACiC;AACjC,EAAA,MAAM,aAAA,GAAgB,QAAQ,WAAA,CAAY,IAAI,IAC1C,iCAAA,GACA,CAAA,QAAA,EAAW,YAAY,IAAI,CAAA,CAAA;AAC/B,EAAA,MAAM,SAAA,GAAY,CAAA,EAAG,aAAa,CAAA,CAAA,EAAI,GAAG,CAAA,yDAAA,CAAA;AAEzC,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,IAAA,CAAK,QAAA,CAAS,mBAAmB,CAAA,GACrD,CAAA,QAAA,EAAW,WAAA,CAAY,IAAI,CAAA,CAAA,GAC3B,CAAA,QAAA,EAAW,WAAA,CAAY,IAAI,IAAI,GAAG,CAAA,CAAA;AAEtC,EAAA,IAAI,QAAgC,EAAC;AACrC,EAAA,IAAI,YAAA,GAAe,IAAA;AAEnB,EAAA,GAAG;AACD,IAAA,MAAM,WAAA,GAAc,MAAM,mBAAA,CAAoB,cAAA,CAAe;AAAA,MAC3D;AAAA,KACD,CAAA;AAED,IAAA,MAAM,iBAAA,GAAuC;AAAA,MAC3C,UAAA,EAAY,QAAQ,IAAI,CAAA,MAAA,EAAS,QAAQ,GAAG,CAAA,MAAA,EAAS,WAAW,GAAG,CAAA,CAAA;AAAA,MACnE,QAAA,EAAU;AAAA,QACR;AAAA,UACE,KAAA,EAAO,MAAA;AAAA,UACP,SAAA,EAAW;AAAA;AACb,OACF;AAAA,MACA,OAAO,KAAA,CAAM,MAAA;AAAA,MACb,IAAA,EAAM;AAAA,KACR;AAEA,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,iBAAA,CAAkB,OAAA,GAAU,EAAE,MAAA,EAAQ,CAAC,MAAM,CAAA,EAAE;AAAA,IACjD;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,SAAA,EAAW;AAAA,MACtC,OAAA,EAAS;AAAA,QACP,GAAG,WAAA,EAAa,OAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,iBAAiB;AAAA,KACvC,CAAA;AAED,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,gDAAA,EAAmD,SAAS,MAAM,CAAA;AAAA,OACpE;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAA2B,MAAM,QAAA,CAAS,IAAA,EAAK;AACrD,IAAA,KAAA,GAAQ,CAAC,GAAG,KAAA,EAAO,GAAG,KAAK,OAAO,CAAA;AAClC,IAAA,YAAA,GAAe,IAAA,CAAK,QAAQ,KAAA,CAAM,MAAA;AAAA,EACpC,CAAA,QAAS,YAAA;AAET,EAAA,OAAO,KAAA;AACT;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"catalogModuleAzureDevOpsEntityProvider.cjs.js","sources":["../../src/module/catalogModuleAzureDevOpsEntityProvider.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 { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\nimport { catalogScmEventsServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport {\n AzureBlobStorageEntityProvider,\n AzureDevOpsEntityProvider,\n} from '../providers';\nimport { AzureDevOpsScmEventsBridge } from '../events/AzureDevOpsScmEventsBridge';\n\n/**\n * Registers the AzureDevOpsEntityProvider with the catalog processing extension point.\n *\n * @public\n */\nexport const catalogModuleAzureEntityProvider = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'azure-providers',\n register(env) {\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n catalog: catalogProcessingExtensionPoint,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n events: eventsServiceRef,\n catalogScmEvents: catalogScmEventsServiceRef,\n lifecycle: coreServices.lifecycle,\n },\n async init({\n config,\n catalog,\n logger,\n scheduler,\n events,\n catalogScmEvents,\n lifecycle,\n }) {\n // Check for Azure Blob Storage provider configuration and register it\n if (config.has('catalog.providers.azureBlob')) {\n catalog.addEntityProvider(\n AzureBlobStorageEntityProvider.fromConfig(config, {\n logger,\n scheduler,\n }),\n );\n }\n\n // Check for Azure DevOps provider configuration and register it\n if (config.has('catalog.providers.azureDevOps')) {\n catalog.addEntityProvider(\n AzureDevOpsEntityProvider.fromConfig(config, {\n logger,\n scheduler,\n }),\n );\n }\n\n // Only wire up the SCM events bridge when Azure DevOps provider\n // configuration is present — Azure Blob Storage users should not be\n // required to handle Azure DevOps webhook events.\n if (config.has('catalog.providers.azureDevOps')) {\n const bridge = new AzureDevOpsScmEventsBridge({\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});\n"],"names":["createBackendModule","coreServices","catalogProcessingExtensionPoint","eventsServiceRef","catalogScmEventsServiceRef","AzureBlobStorageEntityProvider","AzureDevOpsEntityProvider","AzureDevOpsScmEventsBridge"],"mappings":";;;;;;;;;;AAkCO,MAAM,mCAAmCA,oCAAA,CAAoB;AAAA,EAClE,QAAA,EAAU,SAAA;AAAA,EACV,QAAA,EAAU,iBAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,QAAQC,6BAAA,CAAa,UAAA;AAAA,QACrB,OAAA,EAASC,iDAAA;AAAA,QACT,QAAQD,6BAAA,CAAa,MAAA;AAAA,QACrB,WAAWA,6BAAA,CAAa,SAAA;AAAA,QACxB,MAAA,EAAQE,iCAAA;AAAA,QACR,gBAAA,EAAkBC,gCAAA;AAAA,QAClB,WAAWH,6BAAA,CAAa;AAAA,OAC1B;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,QACT,MAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA;AAAA,QACA,gBAAA;AAAA,QACA;AAAA,OACF,EAAG;AAED,QAAA,IAAI,MAAA,CAAO,GAAA,CAAI,6BAA6B,CAAA,EAAG;AAC7C,UAAA,OAAA,CAAQ,iBAAA;AAAA,YACNI,6DAAA,CAA+B,WAAW,MAAA,EAAQ;AAAA,cAChD,MAAA;AAAA,cACA;AAAA,aACD;AAAA,WACH;AAAA,QACF;AAGA,QAAA,IAAI,MAAA,CAAO,GAAA,CAAI,+BAA+B,CAAA,EAAG;AAC/C,UAAA,OAAA,CAAQ,iBAAA;AAAA,YACNC,mDAAA,CAA0B,WAAW,MAAA,EAAQ;AAAA,cAC3C,MAAA;AAAA,cACA;AAAA,aACD;AAAA,WACH;AAAA,QACF;AAKA,QAAA,IAAI,MAAA,CAAO,GAAA,CAAI,+BAA+B,CAAA,EAAG;AAC/C,UAAA,MAAM,MAAA,GAAS,IAAIC,qDAAA,CAA2B;AAAA,YAC5C,MAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA,WACD,CAAA;AACD,UAAA,SAAA,CAAU,eAAe,YAAY;AACnC,YAAA,MAAM,OAAO,KAAA,EAAM;AAAA,UACrB,CAAC,CAAA;AACD,UAAA,SAAA,CAAU,gBAAgB,YAAY;AACpC,YAAA,MAAM,OAAO,IAAA,EAAK;AAAA,UACpB,CAAC,CAAA;AAAA,QACH;AAAA,MACF;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
1
+ {"version":3,"file":"catalogModuleAzureDevOpsEntityProvider.cjs.js","sources":["../../src/module/catalogModuleAzureDevOpsEntityProvider.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 { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node';\nimport { catalogScmEventsServiceRef } from '@backstage/plugin-catalog-node/alpha';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport {\n AzureBlobStorageEntityProvider,\n AzureDevOpsEntityProvider,\n} from '../providers';\nimport { AzureDevOpsScmEventsBridge } from '../events/AzureDevOpsScmEventsBridge';\n\n/**\n * Registers the AzureDevOpsEntityProvider with the catalog processing extension point.\n *\n * @public\n */\nexport const catalogModuleAzureEntityProvider = createBackendModule({\n pluginId: 'catalog',\n moduleId: 'azure-providers',\n register(env) {\n env.registerInit({\n deps: {\n config: coreServices.rootConfig,\n catalog: catalogProcessingExtensionPoint,\n logger: coreServices.logger,\n scheduler: coreServices.scheduler,\n events: eventsServiceRef,\n catalogScmEvents: catalogScmEventsServiceRef,\n lifecycle: coreServices.lifecycle,\n },\n async init({\n config,\n catalog,\n logger,\n scheduler,\n events,\n catalogScmEvents,\n lifecycle,\n }) {\n // Check for Azure Blob Storage provider configuration and register it\n if (config.has('catalog.providers.azureBlob')) {\n catalog.addEntityProvider(\n AzureBlobStorageEntityProvider.fromConfig(config, {\n logger,\n scheduler,\n }),\n );\n }\n\n // Check for Azure DevOps provider configuration and register it\n if (config.has('catalog.providers.azureDevOps')) {\n catalog.addEntityProvider(\n AzureDevOpsEntityProvider.fromConfig(config, {\n logger,\n scheduler,\n }),\n );\n }\n\n // Only wire up the SCM events bridge when Azure DevOps provider\n // configuration is present — Azure Blob Storage users should not be\n // required to handle Azure DevOps webhook events.\n if (config.has('catalog.providers.azureDevOps')) {\n const bridge = new AzureDevOpsScmEventsBridge({\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});\n"],"names":["createBackendModule","coreServices","catalogProcessingExtensionPoint","eventsServiceRef","catalogScmEventsServiceRef","AzureBlobStorageEntityProvider","AzureDevOpsEntityProvider","AzureDevOpsScmEventsBridge"],"mappings":";;;;;;;;;;AAkCO,MAAM,mCAAmCA,oCAAA,CAAoB;AAAA,EAClE,QAAA,EAAU,SAAA;AAAA,EACV,QAAA,EAAU,iBAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,QAAQC,6BAAA,CAAa,UAAA;AAAA,QACrB,OAAA,EAASC,iDAAA;AAAA,QACT,QAAQD,6BAAA,CAAa,MAAA;AAAA,QACrB,WAAWA,6BAAA,CAAa,SAAA;AAAA,QACxB,MAAA,EAAQE,iCAAA;AAAA,QACR,gBAAA,EAAkBC,gCAAA;AAAA,QAClB,WAAWH,6BAAA,CAAa;AAAA,OAC1B;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,QACT,MAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA;AAAA,QACA,gBAAA;AAAA,QACA;AAAA,OACF,EAAG;AAED,QAAA,IAAI,MAAA,CAAO,GAAA,CAAI,6BAA6B,CAAA,EAAG;AAC7C,UAAA,OAAA,CAAQ,iBAAA;AAAA,YACNI,6DAAA,CAA+B,WAAW,MAAA,EAAQ;AAAA,cAChD,MAAA;AAAA,cACA;AAAA,aACD;AAAA,WACH;AAAA,QACF;AAGA,QAAA,IAAI,MAAA,CAAO,GAAA,CAAI,+BAA+B,CAAA,EAAG;AAC/C,UAAA,OAAA,CAAQ,iBAAA;AAAA,YACNC,mDAAA,CAA0B,WAAW,MAAA,EAAQ;AAAA,cAC3C,MAAA;AAAA,cACA;AAAA,aACD;AAAA,WACH;AAAA,QACF;AAKA,QAAA,IAAI,MAAA,CAAO,GAAA,CAAI,+BAA+B,CAAA,EAAG;AAC/C,UAAA,MAAM,MAAA,GAAS,IAAIC,qDAAA,CAA2B;AAAA,YAC5C,MAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA,WACD,CAAA;AACD,UAAA,SAAA,CAAU,eAAe,YAAY;AACnC,YAAA,MAAM,OAAO,KAAA,EAAM;AAAA,UACrB,CAAC,CAAA;AACD,UAAA,SAAA,CAAU,gBAAgB,YAAY;AACpC,YAAA,MAAM,OAAO,IAAA,EAAK;AAAA,UACpB,CAAC,CAAA;AAAA,QACH;AAAA,MACF;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AzureDevOpsDiscoveryProcessor.cjs.js","sources":["../../src/processors/AzureDevOpsDiscoveryProcessor.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n AzureDevOpsCredentialsProvider,\n DefaultAzureDevOpsCredentialsProvider,\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { codeSearch } from '../lib';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Extracts repositories out of an Azure DevOps org.\n *\n * The following will create locations for all projects which have a catalog-info.yaml\n * on the default branch. The first is shorthand for the second.\n *\n * target: \"https://dev.azure.com/org/project\"\n * or\n * target: https://dev.azure.com/org/project?path=/catalog-info.yaml\n *\n * You may also explicitly specify a single repo:\n *\n * target: https://dev.azure.com/org/project/_git/repo\n *\n * @public\n */\nexport class AzureDevOpsDiscoveryProcessor implements CatalogProcessor {\n private readonly integrations: ScmIntegrationRegistry;\n private readonly credentialsProvider: AzureDevOpsCredentialsProvider;\n private readonly logger: LoggerService;\n\n static fromConfig(config: Config, options: { logger: LoggerService }) {\n const integrations = ScmIntegrations.fromConfig(config);\n\n return new AzureDevOpsDiscoveryProcessor({\n ...options,\n integrations,\n });\n }\n\n constructor(options: {\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n }) {\n this.integrations = options.integrations;\n this.logger = options.logger;\n this.credentialsProvider =\n DefaultAzureDevOpsCredentialsProvider.fromIntegrations(\n options.integrations,\n );\n }\n\n getProcessorName(): string {\n return 'AzureDevOpsDiscoveryProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'azure-discovery') {\n return false;\n }\n\n const azureConfig = this.integrations.azure.byUrl(location.target)?.config;\n if (!azureConfig) {\n throw new Error(\n `There is no Azure integration that matches ${location.target}. Please add a configuration entry for it under integrations.azure`,\n );\n }\n\n const { baseUrl, org, project, repo, catalogPath, branch } = parseUrl(\n location.target,\n );\n this.logger.info(\n `Reading Azure DevOps repositories from ${location.target}`,\n );\n\n const files = await codeSearch(\n this.credentialsProvider,\n azureConfig,\n org,\n project,\n repo,\n catalogPath,\n branch,\n );\n\n this.logger.debug(\n `Found ${files.length} files in Azure DevOps from ${location.target}.`,\n );\n\n for (const file of files) {\n let target = `${baseUrl}/${org}/${project}/_git/${file.repository.name}?path=${file.path}`;\n\n if (branch) {\n target += `&version=GB${branch}`;\n }\n\n emit(\n processingResult.location({\n type: 'url',\n target,\n // Not all locations may actually exist, since the user defined them as a wildcard pattern.\n // Thus, we emit them as optional and let the downstream processor find them while not outputting\n // an error if it couldn't.\n presence: 'optional',\n }),\n );\n }\n\n return true;\n }\n}\n\n/**\n * parseUrl extracts segments from the Azure DevOps URL.\n */\nexport function parseUrl(urlString: string): {\n baseUrl: string;\n org: string;\n project: string;\n repo: string;\n catalogPath: string;\n branch: string;\n} {\n const url = new URL(urlString);\n const path = url.pathname.slice(1).split('/');\n\n const catalogPath = url.searchParams.get('path') || '/catalog-info.yaml';\n let branch = url.searchParams.get('version') || '';\n\n if (branch.startsWith('GB')) {\n // DevOps prefixes branch names with 'GB' in URLs\n branch = branch.slice(2);\n }\n\n if (path.length === 2 && path[0].length && path[1].length) {\n return {\n baseUrl: url.origin,\n org: decodeURIComponent(path[0]),\n project: decodeURIComponent(path[1]),\n repo: '',\n catalogPath,\n branch,\n };\n } else if (\n path.length === 4 &&\n path[0].length &&\n path[1].length &&\n path[2].length &&\n path[3].length\n ) {\n return {\n baseUrl: url.origin,\n org: decodeURIComponent(path[0]),\n project: decodeURIComponent(path[1]),\n repo: decodeURIComponent(path[3]),\n catalogPath,\n branch,\n };\n }\n\n throw new Error(`Failed to parse ${urlString}`);\n}\n"],"names":["ScmIntegrations","DefaultAzureDevOpsCredentialsProvider","codeSearch","processingResult"],"mappings":"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"}
1
+ {"version":3,"file":"AzureDevOpsDiscoveryProcessor.cjs.js","sources":["../../src/processors/AzureDevOpsDiscoveryProcessor.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n AzureDevOpsCredentialsProvider,\n DefaultAzureDevOpsCredentialsProvider,\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n CatalogProcessor,\n CatalogProcessorEmit,\n processingResult,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { codeSearch } from '../lib';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\n/**\n * Extracts repositories out of an Azure DevOps org.\n *\n * The following will create locations for all projects which have a catalog-info.yaml\n * on the default branch. The first is shorthand for the second.\n *\n * target: \"https://dev.azure.com/org/project\"\n * or\n * target: https://dev.azure.com/org/project?path=/catalog-info.yaml\n *\n * You may also explicitly specify a single repo:\n *\n * target: https://dev.azure.com/org/project/_git/repo\n *\n * @public\n */\nexport class AzureDevOpsDiscoveryProcessor implements CatalogProcessor {\n private readonly integrations: ScmIntegrationRegistry;\n private readonly credentialsProvider: AzureDevOpsCredentialsProvider;\n private readonly logger: LoggerService;\n\n static fromConfig(config: Config, options: { logger: LoggerService }) {\n const integrations = ScmIntegrations.fromConfig(config);\n\n return new AzureDevOpsDiscoveryProcessor({\n ...options,\n integrations,\n });\n }\n\n constructor(options: {\n integrations: ScmIntegrationRegistry;\n logger: LoggerService;\n }) {\n this.integrations = options.integrations;\n this.logger = options.logger;\n this.credentialsProvider =\n DefaultAzureDevOpsCredentialsProvider.fromIntegrations(\n options.integrations,\n );\n }\n\n getProcessorName(): string {\n return 'AzureDevOpsDiscoveryProcessor';\n }\n\n async readLocation(\n location: LocationSpec,\n _optional: boolean,\n emit: CatalogProcessorEmit,\n ): Promise<boolean> {\n if (location.type !== 'azure-discovery') {\n return false;\n }\n\n const azureConfig = this.integrations.azure.byUrl(location.target)?.config;\n if (!azureConfig) {\n throw new Error(\n `There is no Azure integration that matches ${location.target}. Please add a configuration entry for it under integrations.azure`,\n );\n }\n\n const { baseUrl, org, project, repo, catalogPath, branch } = parseUrl(\n location.target,\n );\n this.logger.info(\n `Reading Azure DevOps repositories from ${location.target}`,\n );\n\n const files = await codeSearch(\n this.credentialsProvider,\n azureConfig,\n org,\n project,\n repo,\n catalogPath,\n branch,\n );\n\n this.logger.debug(\n `Found ${files.length} files in Azure DevOps from ${location.target}.`,\n );\n\n for (const file of files) {\n let target = `${baseUrl}/${org}/${project}/_git/${file.repository.name}?path=${file.path}`;\n\n if (branch) {\n target += `&version=GB${branch}`;\n }\n\n emit(\n processingResult.location({\n type: 'url',\n target,\n // Not all locations may actually exist, since the user defined them as a wildcard pattern.\n // Thus, we emit them as optional and let the downstream processor find them while not outputting\n // an error if it couldn't.\n presence: 'optional',\n }),\n );\n }\n\n return true;\n }\n}\n\n/**\n * parseUrl extracts segments from the Azure DevOps URL.\n */\nexport function parseUrl(urlString: string): {\n baseUrl: string;\n org: string;\n project: string;\n repo: string;\n catalogPath: string;\n branch: string;\n} {\n const url = new URL(urlString);\n const path = url.pathname.slice(1).split('/');\n\n const catalogPath = url.searchParams.get('path') || '/catalog-info.yaml';\n let branch = url.searchParams.get('version') || '';\n\n if (branch.startsWith('GB')) {\n // DevOps prefixes branch names with 'GB' in URLs\n branch = branch.slice(2);\n }\n\n if (path.length === 2 && path[0].length && path[1].length) {\n return {\n baseUrl: url.origin,\n org: decodeURIComponent(path[0]),\n project: decodeURIComponent(path[1]),\n repo: '',\n catalogPath,\n branch,\n };\n } else if (\n path.length === 4 &&\n path[0].length &&\n path[1].length &&\n path[2].length &&\n path[3].length\n ) {\n return {\n baseUrl: url.origin,\n org: decodeURIComponent(path[0]),\n project: decodeURIComponent(path[1]),\n repo: decodeURIComponent(path[3]),\n catalogPath,\n branch,\n };\n }\n\n throw new Error(`Failed to parse ${urlString}`);\n}\n"],"names":["ScmIntegrations","DefaultAzureDevOpsCredentialsProvider","codeSearch","processingResult"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AzureBlobStorageEntityProvider.cjs.js","sources":["../../src/providers/AzureBlobStorageEntityProvider.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 AnonymousCredential,\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { Config } from '@backstage/config';\nimport {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport {\n EntityProvider,\n EntityProviderConnection,\n locationSpecToLocationEntity,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { randomUUID } from 'node:crypto';\nimport { readAzureBlobStorageConfigs } from './config';\nimport {\n AzureBlobStorageIntegration,\n DefaultAzureCredentialsManager,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { TokenCredential } from '@azure/identity';\nimport { AzureBlobStorageConfig } from './types';\n\nfunction hasDotPathSegment(path: string): boolean {\n return path\n .split(/[\\\\/]/)\n .some(segment => segment === '.' || segment === '..');\n}\n\n/**\n * Provider which discovers catalog files within an Azure Storage accounts.\n *\n * Use `AzureBlobStorageEntityProvider.fromConfig(...)` to create instances.\n *\n * @public\n */\nexport class AzureBlobStorageEntityProvider implements EntityProvider {\n private readonly logger: LoggerService;\n private connection?: EntityProviderConnection;\n private blobServiceClient?: BlobServiceClient;\n private readonly scheduleFn: () => Promise<void>;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n schedule?: SchedulerServiceTaskRunner;\n scheduler?: SchedulerService;\n },\n ): AzureBlobStorageEntityProvider[] {\n const providerConfigs = readAzureBlobStorageConfigs(configRoot);\n\n const scmIntegration = ScmIntegrations.fromConfig(configRoot);\n const credentialsProvider =\n DefaultAzureCredentialsManager.fromIntegrations(scmIntegration);\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n return providerConfigs.map(providerConfig => {\n const integration = scmIntegration.azureBlobStorage\n .list()\n .filter(\n azureIntegration =>\n azureIntegration.config.accountName === providerConfig.accountName,\n )[0];\n\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for AzureBlobStorageEntityProvider:${providerConfig.id}.`,\n );\n }\n\n if (!integration) {\n throw new Error(\n `There is no Azure blob storage integration for account. Please add a configuration entry for it under integrations.azureBlobStorage`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n return new AzureBlobStorageEntityProvider(\n providerConfig,\n integration,\n credentialsProvider,\n options.logger,\n taskRunner,\n );\n });\n }\n private readonly config: AzureBlobStorageConfig;\n private readonly integration: AzureBlobStorageIntegration;\n private readonly credentialsProvider: DefaultAzureCredentialsManager;\n\n private constructor(\n config: AzureBlobStorageConfig,\n integration: AzureBlobStorageIntegration,\n credentialsProvider: DefaultAzureCredentialsManager,\n logger: LoggerService,\n schedule: SchedulerServiceTaskRunner,\n ) {\n this.config = config;\n this.integration = integration;\n this.credentialsProvider = credentialsProvider;\n this.logger = logger.child({ target: this.getProviderName() });\n this.scheduleFn = this.createScheduleFn(schedule);\n }\n\n private createScheduleFn(\n taskRunner: SchedulerServiceTaskRunner,\n ): () => Promise<void> {\n return async () => {\n const taskId = `${this.getProviderName()}:refresh`;\n return taskRunner.run({\n id: taskId,\n fn: async () => {\n const logger = this.logger.child({\n class: AzureBlobStorageEntityProvider.prototype.constructor.name,\n taskId,\n taskInstanceId: randomUUID(),\n });\n\n try {\n await this.refresh(logger);\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n\n getProviderName(): string {\n return `azureBlobStorage-provider:${this.config.id}`;\n }\n\n async connect(connection: EntityProviderConnection): Promise<void> {\n this.connection = connection;\n let credential:\n | TokenCredential\n | StorageSharedKeyCredential\n | AnonymousCredential;\n if (this.integration.config.accountKey) {\n credential = new StorageSharedKeyCredential(\n this.integration.config.accountName as string,\n this.integration.config.accountKey as string,\n ); // StorageSharedKeyCredential is only allowed in node.js runtime not in browser\n } else {\n credential = await this.credentialsProvider.getCredentials(\n this.integration.config.accountName as string,\n );\n }\n let blobServiceClientUrl: string;\n\n if (this.integration.config.endpoint) {\n if (this.integration.config.sasToken) {\n blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`;\n } else {\n blobServiceClientUrl = `${this.integration.config.endpoint}`;\n }\n } else {\n blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`;\n }\n\n this.blobServiceClient = new BlobServiceClient(\n blobServiceClientUrl,\n credential,\n );\n await this.scheduleFn();\n }\n\n async refresh(logger: LoggerService) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n logger.info('Discovering Azure Blob Storage blobs');\n\n const keys = await this.listAllBlobKeys();\n logger.info(`Discovered ${keys.length} Azure Blob Storage blobs`);\n\n const validKeys = keys.filter(key => !hasDotPathSegment(key));\n const skippedKeys = keys.length - validKeys.length;\n if (skippedKeys > 0) {\n logger.warn(\n `Skipped ${skippedKeys} Azure Blob Storage blobs with unsupported dot path segments`,\n );\n }\n\n const locations = validKeys.map(key => this.createLocationSpec(key));\n\n await this.connection.applyMutation({\n type: 'full',\n entities: locations.map(location => {\n return {\n locationKey: this.getProviderName(),\n entity: locationSpecToLocationEntity({ location }),\n };\n }),\n });\n\n logger.info(\n `Committed ${locations.length} Locations for Azure Blob Storage blobs`,\n );\n }\n\n private async listAllBlobKeys(): Promise<string[]> {\n const keys: string[] = [];\n const containerClient = this.blobServiceClient?.getContainerClient(\n this.config.containerName,\n );\n\n for await (const blob of (\n containerClient as ContainerClient\n ).listBlobsFlat()) {\n if (blob.name) {\n keys.push(blob.name);\n }\n }\n\n return keys;\n }\n\n private createLocationSpec(key: string): LocationSpec {\n return {\n type: 'url',\n target: this.createObjectUrl(key),\n presence: 'required',\n };\n }\n\n private createObjectUrl(key: string): string {\n if (!this.blobServiceClient) {\n throw new Error('Not initialized');\n }\n\n const objectUrl = new URL(\n this.blobServiceClient\n .getContainerClient(this.config.containerName)\n .getBlobClient(key).url,\n );\n objectUrl.search = '';\n objectUrl.hash = '';\n return objectUrl.toString();\n }\n}\n"],"names":["readAzureBlobStorageConfigs","ScmIntegrations","DefaultAzureCredentialsManager","randomUUID","StorageSharedKeyCredential","BlobServiceClient","locationSpecToLocationEntity"],"mappings":"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"}
1
+ {"version":3,"file":"AzureBlobStorageEntityProvider.cjs.js","sources":["../../src/providers/AzureBlobStorageEntityProvider.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 AnonymousCredential,\n BlobServiceClient,\n ContainerClient,\n StorageSharedKeyCredential,\n} from '@azure/storage-blob';\nimport { Config } from '@backstage/config';\nimport {\n LoggerService,\n SchedulerService,\n SchedulerServiceTaskRunner,\n} from '@backstage/backend-plugin-api';\nimport {\n EntityProvider,\n EntityProviderConnection,\n locationSpecToLocationEntity,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { randomUUID } from 'node:crypto';\nimport { readAzureBlobStorageConfigs } from './config';\nimport {\n AzureBlobStorageIntegration,\n DefaultAzureCredentialsManager,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { TokenCredential } from '@azure/identity';\nimport { AzureBlobStorageConfig } from './types';\n\nfunction hasDotPathSegment(path: string): boolean {\n return path\n .split(/[\\\\/]/)\n .some(segment => segment === '.' || segment === '..');\n}\n\n/**\n * Provider which discovers catalog files within an Azure Storage accounts.\n *\n * Use `AzureBlobStorageEntityProvider.fromConfig(...)` to create instances.\n *\n * @public\n */\nexport class AzureBlobStorageEntityProvider implements EntityProvider {\n private readonly logger: LoggerService;\n private connection?: EntityProviderConnection;\n private blobServiceClient?: BlobServiceClient;\n private readonly scheduleFn: () => Promise<void>;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n schedule?: SchedulerServiceTaskRunner;\n scheduler?: SchedulerService;\n },\n ): AzureBlobStorageEntityProvider[] {\n const providerConfigs = readAzureBlobStorageConfigs(configRoot);\n\n const scmIntegration = ScmIntegrations.fromConfig(configRoot);\n const credentialsProvider =\n DefaultAzureCredentialsManager.fromIntegrations(scmIntegration);\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n return providerConfigs.map(providerConfig => {\n const integration = scmIntegration.azureBlobStorage\n .list()\n .filter(\n azureIntegration =>\n azureIntegration.config.accountName === providerConfig.accountName,\n )[0];\n\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for AzureBlobStorageEntityProvider:${providerConfig.id}.`,\n );\n }\n\n if (!integration) {\n throw new Error(\n `There is no Azure blob storage integration for account. Please add a configuration entry for it under integrations.azureBlobStorage`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n return new AzureBlobStorageEntityProvider(\n providerConfig,\n integration,\n credentialsProvider,\n options.logger,\n taskRunner,\n );\n });\n }\n private readonly config: AzureBlobStorageConfig;\n private readonly integration: AzureBlobStorageIntegration;\n private readonly credentialsProvider: DefaultAzureCredentialsManager;\n\n private constructor(\n config: AzureBlobStorageConfig,\n integration: AzureBlobStorageIntegration,\n credentialsProvider: DefaultAzureCredentialsManager,\n logger: LoggerService,\n schedule: SchedulerServiceTaskRunner,\n ) {\n this.config = config;\n this.integration = integration;\n this.credentialsProvider = credentialsProvider;\n this.logger = logger.child({ target: this.getProviderName() });\n this.scheduleFn = this.createScheduleFn(schedule);\n }\n\n private createScheduleFn(\n taskRunner: SchedulerServiceTaskRunner,\n ): () => Promise<void> {\n return async () => {\n const taskId = `${this.getProviderName()}:refresh`;\n return taskRunner.run({\n id: taskId,\n fn: async () => {\n const logger = this.logger.child({\n class: AzureBlobStorageEntityProvider.prototype.constructor.name,\n taskId,\n taskInstanceId: randomUUID(),\n });\n\n try {\n await this.refresh(logger);\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n\n getProviderName(): string {\n return `azureBlobStorage-provider:${this.config.id}`;\n }\n\n async connect(connection: EntityProviderConnection): Promise<void> {\n this.connection = connection;\n let credential:\n | TokenCredential\n | StorageSharedKeyCredential\n | AnonymousCredential;\n if (this.integration.config.accountKey) {\n credential = new StorageSharedKeyCredential(\n this.integration.config.accountName as string,\n this.integration.config.accountKey as string,\n ); // StorageSharedKeyCredential is only allowed in node.js runtime not in browser\n } else {\n credential = await this.credentialsProvider.getCredentials(\n this.integration.config.accountName as string,\n );\n }\n let blobServiceClientUrl: string;\n\n if (this.integration.config.endpoint) {\n if (this.integration.config.sasToken) {\n blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`;\n } else {\n blobServiceClientUrl = `${this.integration.config.endpoint}`;\n }\n } else {\n blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`;\n }\n\n this.blobServiceClient = new BlobServiceClient(\n blobServiceClientUrl,\n credential,\n );\n await this.scheduleFn();\n }\n\n async refresh(logger: LoggerService) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n logger.info('Discovering Azure Blob Storage blobs');\n\n const keys = await this.listAllBlobKeys();\n logger.info(`Discovered ${keys.length} Azure Blob Storage blobs`);\n\n const validKeys = keys.filter(key => !hasDotPathSegment(key));\n const skippedKeys = keys.length - validKeys.length;\n if (skippedKeys > 0) {\n logger.warn(\n `Skipped ${skippedKeys} Azure Blob Storage blobs with unsupported dot path segments`,\n );\n }\n\n const locations = validKeys.map(key => this.createLocationSpec(key));\n\n await this.connection.applyMutation({\n type: 'full',\n entities: locations.map(location => {\n return {\n locationKey: this.getProviderName(),\n entity: locationSpecToLocationEntity({ location }),\n };\n }),\n });\n\n logger.info(\n `Committed ${locations.length} Locations for Azure Blob Storage blobs`,\n );\n }\n\n private async listAllBlobKeys(): Promise<string[]> {\n const keys: string[] = [];\n const containerClient = this.blobServiceClient?.getContainerClient(\n this.config.containerName,\n );\n\n for await (const blob of (\n containerClient as ContainerClient\n ).listBlobsFlat()) {\n if (blob.name) {\n keys.push(blob.name);\n }\n }\n\n return keys;\n }\n\n private createLocationSpec(key: string): LocationSpec {\n return {\n type: 'url',\n target: this.createObjectUrl(key),\n presence: 'required',\n };\n }\n\n private createObjectUrl(key: string): string {\n if (!this.blobServiceClient) {\n throw new Error('Not initialized');\n }\n\n const objectUrl = new URL(\n this.blobServiceClient\n .getContainerClient(this.config.containerName)\n .getBlobClient(key).url,\n );\n objectUrl.search = '';\n objectUrl.hash = '';\n return objectUrl.toString();\n }\n}\n"],"names":["readAzureBlobStorageConfigs","ScmIntegrations","DefaultAzureCredentialsManager","randomUUID","StorageSharedKeyCredential","BlobServiceClient","locationSpecToLocationEntity"],"mappings":";;;;;;;;AA4CA,SAAS,kBAAkB,IAAA,EAAuB;AAChD,EAAA,OAAO,IAAA,CACJ,MAAM,OAAO,CAAA,CACb,KAAK,CAAA,OAAA,KAAW,OAAA,KAAY,GAAA,IAAO,OAAA,KAAY,IAAI,CAAA;AACxD;AASO,MAAM,8BAAA,CAAyD;AAAA,EACnD,MAAA;AAAA,EACT,UAAA;AAAA,EACA,iBAAA;AAAA,EACS,UAAA;AAAA,EAEjB,OAAO,UAAA,CACL,UAAA,EACA,OAAA,EAKkC;AAClC,IAAA,MAAM,eAAA,GAAkBA,mCAA4B,UAAU,CAAA;AAE9D,IAAA,MAAM,cAAA,GAAiBC,2BAAA,CAAgB,UAAA,CAAW,UAAU,CAAA;AAC5D,IAAA,MAAM,mBAAA,GACJC,0CAAA,CAA+B,gBAAA,CAAiB,cAAc,CAAA;AAChE,IAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,IAAY,CAAC,QAAQ,SAAA,EAAW;AAC3C,MAAA,MAAM,IAAI,MAAM,gDAAgD,CAAA;AAAA,IAClE;AAEA,IAAA,OAAO,eAAA,CAAgB,IAAI,CAAA,cAAA,KAAkB;AAC3C,MAAA,MAAM,WAAA,GAAc,cAAA,CAAe,gBAAA,CAChC,IAAA,EAAK,CACL,MAAA;AAAA,QACC,CAAA,gBAAA,KACE,gBAAA,CAAiB,MAAA,CAAO,WAAA,KAAgB,cAAA,CAAe;AAAA,QACzD,CAAC,CAAA;AAEL,MAAA,IAAI,CAAC,OAAA,CAAQ,QAAA,IAAY,CAAC,eAAe,QAAA,EAAU;AACjD,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,oFAAA,EAAuF,eAAe,EAAE,CAAA,CAAA;AAAA,SAC1G;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,mIAAA;AAAA,SACF;AAAA,MACF;AAEA,MAAA,MAAM,aACJ,OAAA,CAAQ,QAAA,IACR,QAAQ,SAAA,CAAW,yBAAA,CAA0B,eAAe,QAAS,CAAA;AAEvE,MAAA,OAAO,IAAI,8BAAA;AAAA,QACT,cAAA;AAAA,QACA,WAAA;AAAA,QACA,mBAAA;AAAA,QACA,OAAA,CAAQ,MAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EACiB,MAAA;AAAA,EACA,WAAA;AAAA,EACA,mBAAA;AAAA,EAET,WAAA,CACN,MAAA,EACA,WAAA,EACA,mBAAA,EACA,QACA,QAAA,EACA;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA;AACnB,IAAA,IAAA,CAAK,mBAAA,GAAsB,mBAAA;AAC3B,IAAA,IAAA,CAAK,MAAA,GAAS,OAAO,KAAA,CAAM,EAAE,QAAQ,IAAA,CAAK,eAAA,IAAmB,CAAA;AAC7D,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,QAAQ,CAAA;AAAA,EAClD;AAAA,EAEQ,iBACN,UAAA,EACqB;AACrB,IAAA,OAAO,YAAY;AACjB,MAAA,MAAM,MAAA,GAAS,CAAA,EAAG,IAAA,CAAK,eAAA,EAAiB,CAAA,QAAA,CAAA;AACxC,MAAA,OAAO,WAAW,GAAA,CAAI;AAAA,QACpB,EAAA,EAAI,MAAA;AAAA,QACJ,IAAI,YAAY;AACd,UAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM;AAAA,YAC/B,KAAA,EAAO,8BAAA,CAA+B,SAAA,CAAU,WAAA,CAAY,IAAA;AAAA,YAC5D,MAAA;AAAA,YACA,gBAAgBC,sBAAA;AAAW,WAC5B,CAAA;AAED,UAAA,IAAI;AACF,YAAA,MAAM,IAAA,CAAK,QAAQ,MAAM,CAAA;AAAA,UAC3B,SAAS,KAAA,EAAO;AACd,YAAA,MAAA,CAAO,KAAA;AAAA,cACL,CAAA,EAAG,IAAA,CAAK,eAAA,EAAiB,oBAAoB,KAAK,CAAA,CAAA;AAAA,cAClD;AAAA,aACF;AAAA,UACF;AAAA,QACF;AAAA,OACD,CAAA;AAAA,IACH,CAAA;AAAA,EACF;AAAA,EAEA,eAAA,GAA0B;AACxB,IAAA,OAAO,CAAA,0BAAA,EAA6B,IAAA,CAAK,MAAA,CAAO,EAAE,CAAA,CAAA;AAAA,EACpD;AAAA,EAEA,MAAM,QAAQ,UAAA,EAAqD;AACjE,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAI,UAAA;AAIJ,IAAA,IAAI,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,UAAA,EAAY;AACtC,MAAA,UAAA,GAAa,IAAIC,sCAAA;AAAA,QACf,IAAA,CAAK,YAAY,MAAA,CAAO,WAAA;AAAA,QACxB,IAAA,CAAK,YAAY,MAAA,CAAO;AAAA,OAC1B;AAAA,IACF,CAAA,MAAO;AACL,MAAA,UAAA,GAAa,MAAM,KAAK,mBAAA,CAAoB,cAAA;AAAA,QAC1C,IAAA,CAAK,YAAY,MAAA,CAAO;AAAA,OAC1B;AAAA,IACF;AACA,IAAA,IAAI,oBAAA;AAEJ,IAAA,IAAI,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,QAAA,EAAU;AACpC,MAAA,IAAI,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,QAAA,EAAU;AACpC,QAAA,oBAAA,GAAuB,CAAA,EAAG,KAAK,WAAA,CAAY,MAAA,CAAO,QAAQ,CAAA,CAAA,EAAI,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,MAChG,CAAA,MAAO;AACL,QAAA,oBAAA,GAAuB,CAAA,EAAG,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,MAC5D;AAAA,IACF,CAAA,MAAO;AACL,MAAA,oBAAA,GAAuB,CAAA,QAAA,EAAW,KAAK,WAAA,CAAY,MAAA,CAAO,WAAW,CAAA,CAAA,EAAI,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,IAAI,CAAA,CAAA;AAAA,IACvG;AAEA,IAAA,IAAA,CAAK,oBAAoB,IAAIC,6BAAA;AAAA,MAC3B,oBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,MAAM,KAAK,UAAA,EAAW;AAAA,EACxB;AAAA,EAEA,MAAM,QAAQ,MAAA,EAAuB;AACnC,IAAA,IAAI,CAAC,KAAK,UAAA,EAAY;AACpB,MAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AAAA,IACnC;AAEA,IAAA,MAAA,CAAO,KAAK,sCAAsC,CAAA;AAElD,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,eAAA,EAAgB;AACxC,IAAA,MAAA,CAAO,IAAA,CAAK,CAAA,WAAA,EAAc,IAAA,CAAK,MAAM,CAAA,yBAAA,CAA2B,CAAA;AAEhE,IAAA,MAAM,YAAY,IAAA,CAAK,MAAA,CAAO,SAAO,CAAC,iBAAA,CAAkB,GAAG,CAAC,CAAA;AAC5D,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,MAAA,GAAS,SAAA,CAAU,MAAA;AAC5C,IAAA,IAAI,cAAc,CAAA,EAAG;AACnB,MAAA,MAAA,CAAO,IAAA;AAAA,QACL,WAAW,WAAW,CAAA,4DAAA;AAAA,OACxB;AAAA,IACF;AAEA,IAAA,MAAM,YAAY,SAAA,CAAU,GAAA,CAAI,SAAO,IAAA,CAAK,kBAAA,CAAmB,GAAG,CAAC,CAAA;AAEnE,IAAA,MAAM,IAAA,CAAK,WAAW,aAAA,CAAc;AAAA,MAClC,IAAA,EAAM,MAAA;AAAA,MACN,QAAA,EAAU,SAAA,CAAU,GAAA,CAAI,CAAA,QAAA,KAAY;AAClC,QAAA,OAAO;AAAA,UACL,WAAA,EAAa,KAAK,eAAA,EAAgB;AAAA,UAClC,MAAA,EAAQC,8CAAA,CAA6B,EAAE,QAAA,EAAU;AAAA,SACnD;AAAA,MACF,CAAC;AAAA,KACF,CAAA;AAED,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,CAAA,UAAA,EAAa,UAAU,MAAM,CAAA,uCAAA;AAAA,KAC/B;AAAA,EACF;AAAA,EAEA,MAAc,eAAA,GAAqC;AACjD,IAAA,MAAM,OAAiB,EAAC;AACxB,IAAA,MAAM,eAAA,GAAkB,KAAK,iBAAA,EAAmB,kBAAA;AAAA,MAC9C,KAAK,MAAA,CAAO;AAAA,KACd;AAEA,IAAA,WAAA,MAAiB,IAAA,IACf,eAAA,CACA,aAAA,EAAc,EAAG;AACjB,MAAA,IAAI,KAAK,IAAA,EAAM;AACb,QAAA,IAAA,CAAK,IAAA,CAAK,KAAK,IAAI,CAAA;AAAA,MACrB;AAAA,IACF;AAEA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEQ,mBAAmB,GAAA,EAA2B;AACpD,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,KAAA;AAAA,MACN,MAAA,EAAQ,IAAA,CAAK,eAAA,CAAgB,GAAG,CAAA;AAAA,MAChC,QAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEQ,gBAAgB,GAAA,EAAqB;AAC3C,IAAA,IAAI,CAAC,KAAK,iBAAA,EAAmB;AAC3B,MAAA,MAAM,IAAI,MAAM,iBAAiB,CAAA;AAAA,IACnC;AAEA,IAAA,MAAM,YAAY,IAAI,GAAA;AAAA,MACpB,IAAA,CAAK,kBACF,kBAAA,CAAmB,IAAA,CAAK,OAAO,aAAa,CAAA,CAC5C,aAAA,CAAc,GAAG,CAAA,CAAE;AAAA,KACxB;AACA,IAAA,SAAA,CAAU,MAAA,GAAS,EAAA;AACnB,IAAA,SAAA,CAAU,IAAA,GAAO,EAAA;AACjB,IAAA,OAAO,UAAU,QAAA,EAAS;AAAA,EAC5B;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AzureDevOpsEntityProvider.cjs.js","sources":["../../src/providers/AzureDevOpsEntityProvider.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 { Config } from '@backstage/config';\nimport {\n AzureDevOpsCredentialsProvider,\n AzureIntegration,\n DefaultAzureDevOpsCredentialsProvider,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n EntityProvider,\n EntityProviderConnection,\n locationSpecToLocationEntity,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { readAzureDevOpsConfigs } from './config';\nimport { AzureDevOpsConfig } from './types';\nimport { randomUUID } from 'node:crypto';\nimport { codeSearch, CodeSearchResultItem } from '../lib';\nimport {\n SchedulerService,\n SchedulerServiceTaskRunner,\n LoggerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Provider which discovers catalog files within an Azure DevOps repositories.\n *\n * Use `AzureDevOpsEntityProvider.fromConfig(...)` to create instances.\n *\n * @public\n */\nexport class AzureDevOpsEntityProvider implements EntityProvider {\n private readonly logger: LoggerService;\n private readonly scheduleFn: () => Promise<void>;\n private connection?: EntityProviderConnection;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n schedule?: SchedulerServiceTaskRunner;\n scheduler?: SchedulerService;\n },\n ): AzureDevOpsEntityProvider[] {\n const providerConfigs = readAzureDevOpsConfigs(configRoot);\n const scmIntegrations = ScmIntegrations.fromConfig(configRoot);\n const credentialsProvider =\n DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations);\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n return providerConfigs.map(providerConfig => {\n const integration = ScmIntegrations.fromConfig(configRoot).azure.byHost(\n providerConfig.host,\n );\n\n if (!integration) {\n throw new Error(\n `There is no Azure integration for host ${providerConfig.host}. Please add a configuration entry for it under integrations.azure`,\n );\n }\n\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for AzureDevOpsEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n return new AzureDevOpsEntityProvider(\n providerConfig,\n integration,\n credentialsProvider,\n options.logger,\n taskRunner,\n );\n });\n }\n\n private readonly config: AzureDevOpsConfig;\n private readonly integration: AzureIntegration;\n private readonly credentialsProvider: AzureDevOpsCredentialsProvider;\n\n private constructor(\n config: AzureDevOpsConfig,\n integration: AzureIntegration,\n credentialsProvider: AzureDevOpsCredentialsProvider,\n logger: LoggerService,\n taskRunner: SchedulerServiceTaskRunner,\n ) {\n this.config = config;\n this.integration = integration;\n this.credentialsProvider = credentialsProvider;\n this.logger = logger.child({\n target: this.getProviderName(),\n });\n\n this.scheduleFn = this.createScheduleFn(taskRunner);\n }\n\n private createScheduleFn(\n taskRunner: SchedulerServiceTaskRunner,\n ): () => Promise<void> {\n return async () => {\n const taskId = `${this.getProviderName()}:refresh`;\n return taskRunner.run({\n id: taskId,\n fn: async () => {\n const logger = this.logger.child({\n class: AzureDevOpsEntityProvider.prototype.constructor.name,\n taskId,\n taskInstanceId: randomUUID(),\n });\n\n try {\n await this.refresh(logger);\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.getProviderName} */\n getProviderName(): string {\n return `AzureDevOpsEntityProvider:${this.config.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection): Promise<void> {\n this.connection = connection;\n await this.scheduleFn();\n }\n\n async refresh(logger: LoggerService) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n logger.info('Discovering Azure DevOps catalog files');\n\n const files = await codeSearch(\n this.credentialsProvider,\n this.integration.config,\n this.config.organization,\n this.config.project,\n this.config.repository,\n this.config.path,\n this.config.branch || '',\n );\n\n logger.info(`Discovered ${files.length} catalog files`);\n\n const targets = files.map(key => this.createObjectUrl(key));\n const locations = Array.from(new Set(targets)).map(key =>\n this.createLocationSpec(key),\n );\n\n await this.connection.applyMutation({\n type: 'full',\n entities: locations.map(location => {\n return {\n locationKey: this.getProviderName(),\n entity: locationSpecToLocationEntity({ location }),\n };\n }),\n });\n\n logger.info(\n `Committed ${locations.length} locations for AzureDevOps catalog files`,\n );\n }\n\n private createLocationSpec(target: string): LocationSpec {\n return {\n type: 'url',\n target: target,\n presence: 'required',\n };\n }\n\n private createObjectUrl(file: CodeSearchResultItem): string {\n const baseUrl = `https://${this.config.host}/${this.config.organization}/${file.project.name}`;\n\n let fullUrl = `${baseUrl}/_git/${file.repository.name}?path=${file.path}`;\n if (this.config.branch) {\n fullUrl += `&version=GB${this.config.branch}`;\n }\n\n return encodeURI(fullUrl);\n }\n}\n"],"names":["readAzureDevOpsConfigs","ScmIntegrations","DefaultAzureDevOpsCredentialsProvider","integration","randomUUID","codeSearch","locationSpecToLocationEntity"],"mappings":"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"}
1
+ {"version":3,"file":"AzureDevOpsEntityProvider.cjs.js","sources":["../../src/providers/AzureDevOpsEntityProvider.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 { Config } from '@backstage/config';\nimport {\n AzureDevOpsCredentialsProvider,\n AzureIntegration,\n DefaultAzureDevOpsCredentialsProvider,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n EntityProvider,\n EntityProviderConnection,\n locationSpecToLocationEntity,\n} from '@backstage/plugin-catalog-node';\nimport { LocationSpec } from '@backstage/plugin-catalog-common';\nimport { readAzureDevOpsConfigs } from './config';\nimport { AzureDevOpsConfig } from './types';\nimport { randomUUID } from 'node:crypto';\nimport { codeSearch, CodeSearchResultItem } from '../lib';\nimport {\n SchedulerService,\n SchedulerServiceTaskRunner,\n LoggerService,\n} from '@backstage/backend-plugin-api';\n\n/**\n * Provider which discovers catalog files within an Azure DevOps repositories.\n *\n * Use `AzureDevOpsEntityProvider.fromConfig(...)` to create instances.\n *\n * @public\n */\nexport class AzureDevOpsEntityProvider implements EntityProvider {\n private readonly logger: LoggerService;\n private readonly scheduleFn: () => Promise<void>;\n private connection?: EntityProviderConnection;\n\n static fromConfig(\n configRoot: Config,\n options: {\n logger: LoggerService;\n schedule?: SchedulerServiceTaskRunner;\n scheduler?: SchedulerService;\n },\n ): AzureDevOpsEntityProvider[] {\n const providerConfigs = readAzureDevOpsConfigs(configRoot);\n const scmIntegrations = ScmIntegrations.fromConfig(configRoot);\n const credentialsProvider =\n DefaultAzureDevOpsCredentialsProvider.fromIntegrations(scmIntegrations);\n\n if (!options.schedule && !options.scheduler) {\n throw new Error('Either schedule or scheduler must be provided.');\n }\n\n return providerConfigs.map(providerConfig => {\n const integration = ScmIntegrations.fromConfig(configRoot).azure.byHost(\n providerConfig.host,\n );\n\n if (!integration) {\n throw new Error(\n `There is no Azure integration for host ${providerConfig.host}. Please add a configuration entry for it under integrations.azure`,\n );\n }\n\n if (!options.schedule && !providerConfig.schedule) {\n throw new Error(\n `No schedule provided neither via code nor config for AzureDevOpsEntityProvider:${providerConfig.id}.`,\n );\n }\n\n const taskRunner =\n options.schedule ??\n options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!);\n\n return new AzureDevOpsEntityProvider(\n providerConfig,\n integration,\n credentialsProvider,\n options.logger,\n taskRunner,\n );\n });\n }\n\n private readonly config: AzureDevOpsConfig;\n private readonly integration: AzureIntegration;\n private readonly credentialsProvider: AzureDevOpsCredentialsProvider;\n\n private constructor(\n config: AzureDevOpsConfig,\n integration: AzureIntegration,\n credentialsProvider: AzureDevOpsCredentialsProvider,\n logger: LoggerService,\n taskRunner: SchedulerServiceTaskRunner,\n ) {\n this.config = config;\n this.integration = integration;\n this.credentialsProvider = credentialsProvider;\n this.logger = logger.child({\n target: this.getProviderName(),\n });\n\n this.scheduleFn = this.createScheduleFn(taskRunner);\n }\n\n private createScheduleFn(\n taskRunner: SchedulerServiceTaskRunner,\n ): () => Promise<void> {\n return async () => {\n const taskId = `${this.getProviderName()}:refresh`;\n return taskRunner.run({\n id: taskId,\n fn: async () => {\n const logger = this.logger.child({\n class: AzureDevOpsEntityProvider.prototype.constructor.name,\n taskId,\n taskInstanceId: randomUUID(),\n });\n\n try {\n await this.refresh(logger);\n } catch (error) {\n logger.error(\n `${this.getProviderName()} refresh failed, ${error}`,\n error,\n );\n }\n },\n });\n };\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.getProviderName} */\n getProviderName(): string {\n return `AzureDevOpsEntityProvider:${this.config.id}`;\n }\n\n /** {@inheritdoc @backstage/plugin-catalog-node#EntityProvider.connect} */\n async connect(connection: EntityProviderConnection): Promise<void> {\n this.connection = connection;\n await this.scheduleFn();\n }\n\n async refresh(logger: LoggerService) {\n if (!this.connection) {\n throw new Error('Not initialized');\n }\n\n logger.info('Discovering Azure DevOps catalog files');\n\n const files = await codeSearch(\n this.credentialsProvider,\n this.integration.config,\n this.config.organization,\n this.config.project,\n this.config.repository,\n this.config.path,\n this.config.branch || '',\n );\n\n logger.info(`Discovered ${files.length} catalog files`);\n\n const targets = files.map(key => this.createObjectUrl(key));\n const locations = Array.from(new Set(targets)).map(key =>\n this.createLocationSpec(key),\n );\n\n await this.connection.applyMutation({\n type: 'full',\n entities: locations.map(location => {\n return {\n locationKey: this.getProviderName(),\n entity: locationSpecToLocationEntity({ location }),\n };\n }),\n });\n\n logger.info(\n `Committed ${locations.length} locations for AzureDevOps catalog files`,\n );\n }\n\n private createLocationSpec(target: string): LocationSpec {\n return {\n type: 'url',\n target: target,\n presence: 'required',\n };\n }\n\n private createObjectUrl(file: CodeSearchResultItem): string {\n const baseUrl = `https://${this.config.host}/${this.config.organization}/${file.project.name}`;\n\n let fullUrl = `${baseUrl}/_git/${file.repository.name}?path=${file.path}`;\n if (this.config.branch) {\n fullUrl += `&version=GB${this.config.branch}`;\n }\n\n return encodeURI(fullUrl);\n }\n}\n"],"names":["readAzureDevOpsConfigs","ScmIntegrations","DefaultAzureDevOpsCredentialsProvider","integration","randomUUID","codeSearch","locationSpecToLocationEntity"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.cjs.js","sources":["../../src/providers/config.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 { readSchedulerServiceTaskScheduleDefinitionFromConfig } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { AzureDevOpsConfig, AzureBlobStorageConfig } from './types';\n\nconst DEFAULT_PROVIDER_ID = 'default';\n\nexport function readAzureDevOpsConfigs(config: Config): AzureDevOpsConfig[] {\n const configs: AzureDevOpsConfig[] = [];\n\n const providerConfigs = config.getOptionalConfig(\n 'catalog.providers.azureDevOps',\n );\n\n if (!providerConfigs) {\n return configs;\n }\n\n for (const id of providerConfigs.keys()) {\n configs.push(readAzureDevOpsConfig(id, providerConfigs.getConfig(id)));\n }\n\n return configs;\n}\n\nfunction readAzureDevOpsConfig(id: string, config: Config): AzureDevOpsConfig {\n const organization = config.getString('organization');\n const project = config.getString('project');\n const host = config.getOptionalString('host') || 'dev.azure.com';\n const repository = config.getOptionalString('repository') || '*';\n const branch = config.getOptionalString('branch');\n const path = config.getOptionalString('path') || '/catalog-info.yaml';\n\n const schedule = config.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config.getConfig('schedule'),\n )\n : undefined;\n\n return {\n id,\n host,\n organization,\n project,\n repository,\n branch,\n path,\n schedule,\n };\n}\n\nexport function readAzureBlobStorageConfigs(\n config: Config,\n): AzureBlobStorageConfig[] {\n const configs: AzureBlobStorageConfig[] = [];\n\n const providerConfigs = config.getOptionalConfig(\n 'catalog.providers.azureBlob',\n );\n\n if (!providerConfigs) {\n return configs;\n }\n\n if (providerConfigs.has('containerName')) {\n // simple/single config variant\n configs.push(\n readAzureBlobStorageConfig(DEFAULT_PROVIDER_ID, providerConfigs),\n );\n\n return configs;\n }\n\n for (const id of providerConfigs.keys()) {\n configs.push(readAzureBlobStorageConfig(id, providerConfigs.getConfig(id)));\n }\n\n return configs;\n}\n\nfunction readAzureBlobStorageConfig(\n id: string,\n config: Config,\n): AzureBlobStorageConfig {\n const containerName = config.getString('containerName');\n const accountName = config.getString('accountName');\n const schedule = config.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config.getConfig('schedule'),\n )\n : undefined;\n\n return {\n id,\n containerName,\n accountName,\n schedule,\n };\n}\n"],"names":["readSchedulerServiceTaskScheduleDefinitionFromConfig"],"mappings":";;;;AAoBA,MAAM,mBAAA,GAAsB,SAAA;AAErB,SAAS,uBAAuB,MAAA,EAAqC;AAC1E,EAAA,MAAM,UAA+B,EAAC;AAEtC,EAAA,MAAM,kBAAkB,MAAA,CAAO,iBAAA;AAAA,IAC7B;AAAA,GACF;AAEA,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,EAAA,IAAM,eAAA,CAAgB,IAAA,EAAK,EAAG;AACvC,IAAA,OAAA,CAAQ,KAAK,qBAAA,CAAsB,EAAA,EAAI,gBAAgB,SAAA,CAAU,EAAE,CAAC,CAAC,CAAA;AAAA,EACvE;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,qBAAA,CAAsB,IAAY,MAAA,EAAmC;AAC5E,EAAA,MAAM,YAAA,GAAe,MAAA,CAAO,SAAA,CAAU,cAAc,CAAA;AACpD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,SAAA,CAAU,SAAS,CAAA;AAC1C,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,iBAAA,CAAkB,MAAM,CAAA,IAAK,eAAA;AACjD,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,iBAAA,CAAkB,YAAY,CAAA,IAAK,GAAA;AAC7D,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,iBAAA,CAAkB,QAAQ,CAAA;AAChD,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,iBAAA,CAAkB,MAAM,CAAA,IAAK,oBAAA;AAEjD,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,UAAU,CAAA,GAClCA,qEAAA;AAAA,IACE,MAAA,CAAO,UAAU,UAAU;AAAA,GAC7B,GACA,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,EAAA;AAAA,IACA,IAAA;AAAA,IACA,YAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,GACF;AACF;AAEO,SAAS,4BACd,MAAA,EAC0B;AAC1B,EAAA,MAAM,UAAoC,EAAC;AAE3C,EAAA,MAAM,kBAAkB,MAAA,CAAO,iBAAA;AAAA,IAC7B;AAAA,GACF;AAEA,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,eAAe,CAAA,EAAG;AAExC,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,0BAAA,CAA2B,qBAAqB,eAAe;AAAA,KACjE;AAEA,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,EAAA,IAAM,eAAA,CAAgB,IAAA,EAAK,EAAG;AACvC,IAAA,OAAA,CAAQ,KAAK,0BAAA,CAA2B,EAAA,EAAI,gBAAgB,SAAA,CAAU,EAAE,CAAC,CAAC,CAAA;AAAA,EAC5E;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,0BAAA,CACP,IACA,MAAA,EACwB;AACxB,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,SAAA,CAAU,eAAe,CAAA;AACtD,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,SAAA,CAAU,aAAa,CAAA;AAClD,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,UAAU,CAAA,GAClCA,qEAAA;AAAA,IACE,MAAA,CAAO,UAAU,UAAU;AAAA,GAC7B,GACA,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,EAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;;;;;"}
1
+ {"version":3,"file":"config.cjs.js","sources":["../../src/providers/config.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 { readSchedulerServiceTaskScheduleDefinitionFromConfig } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { AzureDevOpsConfig, AzureBlobStorageConfig } from './types';\n\nconst DEFAULT_PROVIDER_ID = 'default';\n\nexport function readAzureDevOpsConfigs(config: Config): AzureDevOpsConfig[] {\n const configs: AzureDevOpsConfig[] = [];\n\n const providerConfigs = config.getOptionalConfig(\n 'catalog.providers.azureDevOps',\n );\n\n if (!providerConfigs) {\n return configs;\n }\n\n for (const id of providerConfigs.keys()) {\n configs.push(readAzureDevOpsConfig(id, providerConfigs.getConfig(id)));\n }\n\n return configs;\n}\n\nfunction readAzureDevOpsConfig(id: string, config: Config): AzureDevOpsConfig {\n const organization = config.getString('organization');\n const project = config.getString('project');\n const host = config.getOptionalString('host') || 'dev.azure.com';\n const repository = config.getOptionalString('repository') || '*';\n const branch = config.getOptionalString('branch');\n const path = config.getOptionalString('path') || '/catalog-info.yaml';\n\n const schedule = config.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config.getConfig('schedule'),\n )\n : undefined;\n\n return {\n id,\n host,\n organization,\n project,\n repository,\n branch,\n path,\n schedule,\n };\n}\n\nexport function readAzureBlobStorageConfigs(\n config: Config,\n): AzureBlobStorageConfig[] {\n const configs: AzureBlobStorageConfig[] = [];\n\n const providerConfigs = config.getOptionalConfig(\n 'catalog.providers.azureBlob',\n );\n\n if (!providerConfigs) {\n return configs;\n }\n\n if (providerConfigs.has('containerName')) {\n // simple/single config variant\n configs.push(\n readAzureBlobStorageConfig(DEFAULT_PROVIDER_ID, providerConfigs),\n );\n\n return configs;\n }\n\n for (const id of providerConfigs.keys()) {\n configs.push(readAzureBlobStorageConfig(id, providerConfigs.getConfig(id)));\n }\n\n return configs;\n}\n\nfunction readAzureBlobStorageConfig(\n id: string,\n config: Config,\n): AzureBlobStorageConfig {\n const containerName = config.getString('containerName');\n const accountName = config.getString('accountName');\n const schedule = config.has('schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config.getConfig('schedule'),\n )\n : undefined;\n\n return {\n id,\n containerName,\n accountName,\n schedule,\n };\n}\n"],"names":["readSchedulerServiceTaskScheduleDefinitionFromConfig"],"mappings":";;;;AAoBA,MAAM,mBAAA,GAAsB,SAAA;AAErB,SAAS,uBAAuB,MAAA,EAAqC;AAC1E,EAAA,MAAM,UAA+B,EAAC;AAEtC,EAAA,MAAM,kBAAkB,MAAA,CAAO,iBAAA;AAAA,IAC7B;AAAA,GACF;AAEA,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,EAAA,IAAM,eAAA,CAAgB,IAAA,EAAK,EAAG;AACvC,IAAA,OAAA,CAAQ,KAAK,qBAAA,CAAsB,EAAA,EAAI,gBAAgB,SAAA,CAAU,EAAE,CAAC,CAAC,CAAA;AAAA,EACvE;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,qBAAA,CAAsB,IAAY,MAAA,EAAmC;AAC5E,EAAA,MAAM,YAAA,GAAe,MAAA,CAAO,SAAA,CAAU,cAAc,CAAA;AACpD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,SAAA,CAAU,SAAS,CAAA;AAC1C,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,iBAAA,CAAkB,MAAM,CAAA,IAAK,eAAA;AACjD,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,iBAAA,CAAkB,YAAY,CAAA,IAAK,GAAA;AAC7D,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,iBAAA,CAAkB,QAAQ,CAAA;AAChD,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,iBAAA,CAAkB,MAAM,CAAA,IAAK,oBAAA;AAEjD,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,UAAU,CAAA,GAClCA,qEAAA;AAAA,IACE,MAAA,CAAO,UAAU,UAAU;AAAA,GAC7B,GACA,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,EAAA;AAAA,IACA,IAAA;AAAA,IACA,YAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,GACF;AACF;AAEO,SAAS,4BACd,MAAA,EAC0B;AAC1B,EAAA,MAAM,UAAoC,EAAC;AAE3C,EAAA,MAAM,kBAAkB,MAAA,CAAO,iBAAA;AAAA,IAC7B;AAAA,GACF;AAEA,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,eAAe,CAAA,EAAG;AAExC,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,0BAAA,CAA2B,qBAAqB,eAAe;AAAA,KACjE;AAEA,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,KAAA,MAAW,EAAA,IAAM,eAAA,CAAgB,IAAA,EAAK,EAAG;AACvC,IAAA,OAAA,CAAQ,KAAK,0BAAA,CAA2B,EAAA,EAAI,gBAAgB,SAAA,CAAU,EAAE,CAAC,CAAC,CAAA;AAAA,EAC5E;AAEA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,0BAAA,CACP,IACA,MAAA,EACwB;AACxB,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,SAAA,CAAU,eAAe,CAAA;AACtD,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,SAAA,CAAU,aAAa,CAAA;AAClD,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,UAAU,CAAA,GAClCA,qEAAA;AAAA,IACE,MAAA,CAAO,UAAU,UAAU;AAAA,GAC7B,GACA,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,EAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend-module-azure",
3
- "version": "0.3.22",
3
+ "version": "0.3.23-next.0",
4
4
  "description": "A Backstage catalog backend module that helps integrate towards Azure",
5
5
  "backstage": {
6
6
  "role": "backend-plugin-module",
@@ -67,17 +67,17 @@
67
67
  "dependencies": {
68
68
  "@azure/identity": "^4.0.0",
69
69
  "@azure/storage-blob": "^12.5.0",
70
- "@backstage/backend-plugin-api": "^1.10.1",
71
- "@backstage/config": "^1.3.9",
72
- "@backstage/errors": "^1.3.1",
73
- "@backstage/integration": "^2.1.2",
74
- "@backstage/plugin-catalog-common": "^1.2.0",
75
- "@backstage/plugin-catalog-node": "^2.2.5",
76
- "@backstage/plugin-events-node": "^0.4.26"
70
+ "@backstage/backend-plugin-api": "1.10.2-next.0",
71
+ "@backstage/config": "1.3.10-next.0",
72
+ "@backstage/errors": "1.3.2-next.0",
73
+ "@backstage/integration": "2.1.3-next.0",
74
+ "@backstage/plugin-catalog-common": "1.2.1-next.0",
75
+ "@backstage/plugin-catalog-node": "2.2.6-next.0",
76
+ "@backstage/plugin-events-node": "0.4.27-next.0"
77
77
  },
78
78
  "devDependencies": {
79
- "@backstage/backend-test-utils": "^1.11.7",
80
- "@backstage/cli": "^0.36.6",
79
+ "@backstage/backend-test-utils": "1.11.8-next.0",
80
+ "@backstage/cli": "0.36.7-next.0",
81
81
  "msw": "^2.0.0"
82
82
  },
83
83
  "configSchema": "config.schema.json"