diff --git a/.changeset/eleven-donkeys-agree.md b/.changeset/eleven-donkeys-agree.md new file mode 100644 index 0000000000..978094095d --- /dev/null +++ b/.changeset/eleven-donkeys-agree.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Correctly add `/project-slug` annotation for new catalog-info.yaml PRs based on SCM integration. diff --git a/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts b/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts index bc81cf14f8..cacdf38ffd 100644 --- a/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts +++ b/plugins/catalog-backend/src/ingestion/LocationAnalyzer.ts @@ -16,6 +16,8 @@ import { Logger } from 'winston'; import parseGitUrl from 'git-url-parse'; +import { Entity } from '@backstage/catalog-model'; +import { ScmIntegrationRegistry } from '@backstage/integration'; import { AnalyzeLocationRequest, AnalyzeLocationResponse, @@ -24,25 +26,50 @@ import { export class RepoLocationAnalyzer implements LocationAnalyzer { private readonly logger: Logger; + private readonly scmIntegrations: ScmIntegrationRegistry; - constructor(logger: Logger) { + constructor(logger: Logger, scmIntegrations: ScmIntegrationRegistry) { this.logger = logger; + this.scmIntegrations = scmIntegrations; } async analyzeLocation( request: AnalyzeLocationRequest, ): Promise { - const { owner, name, source } = parseGitUrl(request.location.target); - const entity = { + const { owner, name } = parseGitUrl(request.location.target); + const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', metadata: { name: name, - // Probably won't handle properly self-hosted git providers with custom url - annotations: { [`${source}/project-slug`]: `${owner}/${name}` }, }, spec: { type: 'other', lifecycle: 'unknown' }, }; + const integration = this.scmIntegrations.byUrl(request.location.target); + let annotationPrefix; + switch (integration?.type) { + case 'azure': + annotationPrefix = 'dev.azure.com'; + break; + case 'bitbucket': + annotationPrefix = 'bitbucket.org'; + break; + case 'github': + annotationPrefix = 'github.com'; + break; + case 'gitlab': + annotationPrefix = 'gitlab.com'; + break; + default: + break; + } + + if (annotationPrefix) { + entity.metadata.annotations = { + [`${annotationPrefix}/project-slug`]: `${owner}/${name}`, + }; + } + this.logger.debug(`entity created for ${request.location.target}`); return { existingEntityFiles: [], diff --git a/plugins/catalog-backend/src/next/NextCatalogBuilder.ts b/plugins/catalog-backend/src/next/NextCatalogBuilder.ts index 43f321248e..e10d13c129 100644 --- a/plugins/catalog-backend/src/next/NextCatalogBuilder.ts +++ b/plugins/catalog-backend/src/next/NextCatalogBuilder.ts @@ -275,7 +275,7 @@ export class NextCatalogBuilder { ); const locationsCatalog = new DatabaseLocationsCatalog(db); - const locationAnalyzer = new RepoLocationAnalyzer(logger); + const locationAnalyzer = new RepoLocationAnalyzer(logger, integrations); const locationService = new DefaultLocationService( locationStore, orchestrator, diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index b8d8b3ee61..f742e3c0db 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -228,6 +228,7 @@ export class CatalogBuilder { locationAnalyzer: LocationAnalyzer; }> { const { config, database, logger } = this.env; + const integrations = ScmIntegrations.fromConfig(config); const policy = this.buildEntityPolicy(); const processors = this.buildProcessors(); @@ -255,7 +256,7 @@ export class CatalogBuilder { locationReader, logger, ); - const locationAnalyzer = new RepoLocationAnalyzer(logger); + const locationAnalyzer = new RepoLocationAnalyzer(logger, integrations); return { entitiesCatalog,