diff --git a/plugins/azure-devops/src/constants.ts b/plugins/azure-devops/src/constants.ts index 765f5a965b..aba0ec093a 100644 --- a/plugins/azure-devops/src/constants.ts +++ b/plugins/azure-devops/src/constants.ts @@ -16,8 +16,7 @@ export const AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION = 'dev.azure.com/build-definition'; -export const AZURE_DEVOPS_ORGANIZATION_ANNOTATION = - 'dev.azure.com/organization'; +export const AZURE_DEVOPS_HOST_ORG_ANNOTATION = 'dev.azure.com/host-org'; export const AZURE_DEVOPS_PROJECT_ANNOTATION = 'dev.azure.com/project'; export const AZURE_DEVOPS_REPO_ANNOTATION = 'dev.azure.com/project-repo'; export const AZURE_DEVOPS_DEFAULT_TOP: number = 10; diff --git a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts index a34dab9db5..5584567188 100644 --- a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts +++ b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.test.ts @@ -31,11 +31,12 @@ describe('getAnnotationValuesFromEntity', () => { }, }, }; - const { project, repo, definition, org } = + const { project, repo, definition, host, org } = getAnnotationValuesFromEntity(entity); expect(project).toEqual('projectName'); expect(repo).toEqual('repoName'); expect(definition).toEqual(undefined); + expect(host).toEqual(undefined); expect(org).toEqual(undefined); }); }); @@ -126,17 +127,18 @@ describe('getAnnotationValuesFromEntity', () => { }, }, }; - const { project, repo, definition, org } = + const { project, repo, definition, host, org } = getAnnotationValuesFromEntity(entity); expect(project).toEqual('projectName'); expect(repo).toEqual(undefined); expect(definition).toEqual('buildDefinitionName'); + expect(host).toEqual(undefined); expect(org).toEqual(undefined); }); }); describe('with only project annotation', () => { - it('should return project and definition', () => { + it('should should throw annotation not found error', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -159,7 +161,7 @@ describe('getAnnotationValuesFromEntity', () => { }); describe('with only build-definition annotation', () => { - it('should return project and definition', () => { + it('should should throw annotation not found error', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -181,8 +183,8 @@ describe('getAnnotationValuesFromEntity', () => { }); }); - describe('with valid project-repo and org annotations', () => { - it('should return project, repo, and org', () => { + describe('with valid project-repo and host-org annotations', () => { + it('should return project, repo, host, and org', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -191,21 +193,22 @@ describe('getAnnotationValuesFromEntity', () => { name: 'project-repo', annotations: { 'dev.azure.com/project-repo': 'projectName/repoName', - 'dev.azure.com/organization': 'organizationName', + 'dev.azure.com/host-org': 'hostName/organizationName', }, }, }; - const { project, repo, definition, org } = + const { project, repo, definition, host, org } = getAnnotationValuesFromEntity(entity); expect(project).toEqual('projectName'); expect(repo).toEqual('repoName'); expect(definition).toEqual(undefined); + expect(host).toEqual('hostName'); expect(org).toEqual('organizationName'); }); }); - describe('with valid project, build-definition, and org annotations', () => { - it('should return project, definition, and org', () => { + describe('with valid project, build-definition, and host-org annotations', () => { + it('should return project, definition, host and org', () => { const entity: Entity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Component', @@ -215,16 +218,89 @@ describe('getAnnotationValuesFromEntity', () => { annotations: { 'dev.azure.com/project': 'projectName', 'dev.azure.com/build-definition': 'buildDefinitionName', - 'dev.azure.com/organization': 'organizationName', + 'dev.azure.com/host-org': 'hostName/organizationName', }, }, }; - const { project, repo, definition, org } = + const { project, repo, definition, host, org } = getAnnotationValuesFromEntity(entity); expect(project).toEqual('projectName'); expect(repo).toEqual(undefined); expect(definition).toEqual('buildDefinitionName'); + expect(host).toEqual('hostName'); expect(org).toEqual('organizationName'); }); }); + + describe('with invalid host-org annotation', () => { + it('should throw incorrect format error', () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'host-org', + annotations: { + 'dev.azure.com/host-org': 'host', + }, + }, + }; + + const test = () => { + return getAnnotationValuesFromEntity(entity); + }; + + expect(test).toThrow( + 'Value for annotation dev.azure.com/host-org was not in the correct format: /', + ); + }); + }); + + describe('with host-rg annotation missing host', () => { + it('should throw missing project error', () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'host-org', + annotations: { + 'dev.azure.com/host-org': '/org', + }, + }, + }; + + const test = () => { + return getAnnotationValuesFromEntity(entity); + }; + + expect(test).toThrow( + 'Host for annotation dev.azure.com/host-org was not found; expected format is: /', + ); + }); + }); + + describe('with host-org annotation missing org', () => { + it('should throw missing repo error', () => { + const entity: Entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + namespace: 'default', + name: 'host-org', + annotations: { + 'dev.azure.com/host-org': 'host/', + }, + }, + }; + + const test = () => { + return getAnnotationValuesFromEntity(entity); + }; + + expect(test).toThrow( + 'Organization for annotation dev.azure.com/host-org was not found; expected format is: /', + ); + }); + }); }); diff --git a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts index 1070983b27..8ce096d3c5 100644 --- a/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts +++ b/plugins/azure-devops/src/utils/getAnnotationValuesFromEntity.ts @@ -16,7 +16,7 @@ import { AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, - AZURE_DEVOPS_ORGANIZATION_ANNOTATION, + AZURE_DEVOPS_HOST_ORG_ANNOTATION, AZURE_DEVOPS_PROJECT_ANNOTATION, AZURE_DEVOPS_REPO_ANNOTATION, } from '../constants'; @@ -27,35 +27,39 @@ export function getAnnotationValuesFromEntity(entity: Entity): { project: string; repo?: string; definition?: string; + host?: string; org?: string; } { - const org = - entity.metadata.annotations?.[AZURE_DEVOPS_ORGANIZATION_ANNOTATION]; + const hostOrgAnnotation = + entity.metadata.annotations?.[AZURE_DEVOPS_HOST_ORG_ANNOTATION]; + const { host, org } = getHostOrg(hostOrgAnnotation); - const annotation = + const projectRepoAnnotation = entity.metadata.annotations?.[AZURE_DEVOPS_REPO_ANNOTATION]; - if (annotation) { - const { project, repo } = getProjectRepo(annotation); + if (projectRepoAnnotation) { + const { project, repo } = getProjectRepo(projectRepoAnnotation); const definition = undefined; - return { project, repo, definition, org }; + return { project, repo, definition, host, org }; } const project = entity.metadata.annotations?.[AZURE_DEVOPS_PROJECT_ANNOTATION]; if (!project) { - throw new Error('Value for annotation dev.azure.com/project was not found'); + throw new Error( + `Value for annotation ${AZURE_DEVOPS_PROJECT_ANNOTATION} was not found`, + ); } const definition = entity.metadata.annotations?.[AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION]; if (!definition) { throw new Error( - 'Value for annotation dev.azure.com/build-definition was not found', + `Value for annotation ${AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION} was not found`, ); } const repo = undefined; - return { project, repo, definition, org }; + return { project, repo, definition, host, org }; } function getProjectRepo(annotation: string): { @@ -64,7 +68,7 @@ function getProjectRepo(annotation: string): { } { if (!annotation.includes('/')) { throw new Error( - 'Value for annotation dev.azure.com/project-repo was not in the correct format: /', + `Value for annotation ${AZURE_DEVOPS_REPO_ANNOTATION} was not in the correct format: /`, ); } @@ -72,15 +76,46 @@ function getProjectRepo(annotation: string): { if (!project) { throw new Error( - 'Project Name for annotation dev.azure.com/project-repo was not found; expected format is: /', + `Project Name for annotation ${AZURE_DEVOPS_REPO_ANNOTATION} was not found; expected format is: /`, ); } if (!repo) { throw new Error( - 'Repo Name for annotation dev.azure.com/project-repo was not found; expected format is: /', + `Repo Name for annotation ${AZURE_DEVOPS_REPO_ANNOTATION} was not found; expected format is: /`, ); } return { project, repo }; } + +function getHostOrg(annotation?: string): { + host?: string; + org?: string; +} { + if (!annotation) { + return { host: undefined, org: undefined }; + } + + if (!annotation.includes('/')) { + throw new Error( + `Value for annotation ${AZURE_DEVOPS_HOST_ORG_ANNOTATION} was not in the correct format: /`, + ); + } + + const [host, org] = annotation.split('/'); + + if (!host) { + throw new Error( + `Host for annotation ${AZURE_DEVOPS_HOST_ORG_ANNOTATION} was not found; expected format is: /`, + ); + } + + if (!org) { + throw new Error( + `Organization for annotation ${AZURE_DEVOPS_HOST_ORG_ANNOTATION} was not found; expected format is: /`, + ); + } + + return { host, org }; +}