diff --git a/plugins/azure-devops/README.md b/plugins/azure-devops/README.md index 7eeae09813..5055180be1 100644 --- a/plugins/azure-devops/README.md +++ b/plugins/azure-devops/README.md @@ -61,6 +61,12 @@ spec: # ... ``` +```yaml +backstage.io/managed-by-location: https://dev.azure.com/{org}/{project}/_git/{repo}?path=/.catalog/component.yml +``` + +if `dev.azure.com/project-repo` annotation is not provided and `dev.azure.com/project` not exits then to extract the project and repo information we can use `backstage.io/managed-by-location` annotation if location contains `dev.azure.com` in url to enable CICD tab. + #### Azure Pipelines Only If you are only using Azure Pipelines along with a different SCM tool then you can use the following two annotations to see Builds: diff --git a/plugins/azure-devops/src/constants.ts b/plugins/azure-devops/src/constants.ts index 95e5be4930..128b593145 100644 --- a/plugins/azure-devops/src/constants.ts +++ b/plugins/azure-devops/src/constants.ts @@ -18,4 +18,5 @@ export const AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION = 'dev.azure.com/build-definition'; 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_PROJECT_LOCATION = 'backstage.io/managed-by-location'; export const AZURE_DEVOPS_DEFAULT_TOP: number = 10; diff --git a/plugins/azure-devops/src/plugin.ts b/plugins/azure-devops/src/plugin.ts index 4dd423f35a..e6eb0556f6 100644 --- a/plugins/azure-devops/src/plugin.ts +++ b/plugins/azure-devops/src/plugin.ts @@ -37,6 +37,7 @@ import { import { AzureDevOpsClient } from './api/AzureDevOpsClient'; import { Entity } from '@backstage/catalog-model'; import { azureDevOpsApiRef } from './api/AzureDevOpsApi'; +import { isDevAzureLocation } from './utils/isAzureLocation'; /** @public */ export const isAzureDevOpsAvailable = (entity: Entity) => @@ -45,6 +46,7 @@ export const isAzureDevOpsAvailable = (entity: Entity) => /** @public */ export const isAzurePipelinesAvailable = (entity: Entity) => Boolean(entity.metadata.annotations?.[AZURE_DEVOPS_REPO_ANNOTATION]) || + isDevAzureLocation(entity) || (Boolean(entity.metadata.annotations?.[AZURE_DEVOPS_PROJECT_ANNOTATION]) && Boolean( entity.metadata.annotations?.[AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION], diff --git a/plugins/azure-devops/src/utils/getAnnotationFromEntity.ts b/plugins/azure-devops/src/utils/getAnnotationFromEntity.ts index 41cc1e6628..14f19668f0 100644 --- a/plugins/azure-devops/src/utils/getAnnotationFromEntity.ts +++ b/plugins/azure-devops/src/utils/getAnnotationFromEntity.ts @@ -18,6 +18,7 @@ import { AZURE_DEVOPS_BUILD_DEFINITION_ANNOTATION, AZURE_DEVOPS_PROJECT_ANNOTATION, AZURE_DEVOPS_REPO_ANNOTATION, + AZURE_DEVOPS_PROJECT_LOCATION, } from '../constants'; import { Entity } from '@backstage/catalog-model'; @@ -37,6 +38,20 @@ export function getAnnotationFromEntity(entity: Entity): { const project = entity.metadata.annotations?.[AZURE_DEVOPS_PROJECT_ANNOTATION]; + + const location = entity.metadata.annotations?.[AZURE_DEVOPS_PROJECT_LOCATION]; + const isAzureDevUrl = location?.includes('dev.azure.com'); + + if (!project && location && isAzureDevUrl) { + const locInfoArr = location + .substring(location.indexOf('//') + 2) + .split('/'); + + const [proj, repo] = [locInfoArr[2], locInfoArr[4].split('?')[0]]; + const definition = undefined; + return { project: proj, repo, definition }; + } + if (!project) { throw new Error('Value for annotation dev.azure.com/project was not found'); } diff --git a/plugins/azure-devops/src/utils/isAzureLocation.ts b/plugins/azure-devops/src/utils/isAzureLocation.ts new file mode 100644 index 0000000000..6f0be835b7 --- /dev/null +++ b/plugins/azure-devops/src/utils/isAzureLocation.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Entity } from '@backstage/catalog-model'; +import { AZURE_DEVOPS_PROJECT_LOCATION } from '../constants'; + +export const isDevAzureLocation = (entity: Entity): boolean => { + return ( + entity.metadata.annotations?.[AZURE_DEVOPS_PROJECT_LOCATION].includes( + 'dev.azure.com', + ) || false + ); +};