From 7d1a522abc464a53b6f8fd6d2a27392c5ff383cf Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Sun, 31 Oct 2021 16:49:16 -0500 Subject: [PATCH] Added getting builds by definition name Signed-off-by: Andre Wanlin --- .../src/api/AzureDevOpsApi.ts | 72 ++++++++++++++-- .../src/service/router.test.ts | 85 ++++++++++++++++++- .../src/service/router.ts | 27 ++++++ 3 files changed, 175 insertions(+), 9 deletions(-) diff --git a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts index 53dc19c68d..7acc5fc066 100644 --- a/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts +++ b/plugins/azure-devops-backend/src/api/AzureDevOpsApi.ts @@ -35,7 +35,7 @@ import { getArtifactId, } from '../utils'; -import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { Build, BuildDefinitionReference } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { Logger } from 'winston'; import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces'; import { TeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces'; @@ -60,19 +60,46 @@ export class AzureDevOpsApi { return client.getRepository(repoName, projectName); } - public async getBuildList( + public async getBuildDefinitions( projectName: string, - repoId: string, - top: number, - ): Promise { + definitionName: string, + ): Promise { this.logger?.debug( - `Calling Azure DevOps REST API, getting up to ${top} Builds for Repository Id ${repoId} for Project ${projectName}`, + `Calling Azure DevOps REST API, getting Build Definitions for ${definitionName} in Project ${projectName}`, ); + const client = await this.webApi.getBuildApi(); + return client.getDefinitions( + projectName, + definitionName, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + ); + } + + public async getBuildList( + projectName: string, + definitions?: number[], + repoId?: string, + top?: number, + ): Promise { const client = await this.webApi.getBuildApi(); return client.getBuilds( projectName, - undefined, + definitions, undefined, undefined, undefined, @@ -91,7 +118,7 @@ export class AzureDevOpsApi { undefined, undefined, repoId, - 'TfsGit', + repoId ? 'TfsGit' : undefined, ); } @@ -107,6 +134,7 @@ export class AzureDevOpsApi { const gitRepository = await this.getGitRepository(projectName, repoName); const buildList = await this.getBuildList( projectName, + undefined, gitRepository.id as string, top, ); @@ -118,6 +146,34 @@ export class AzureDevOpsApi { return repoBuilds; } + public async getDefinitionBuilds( + projectName: string, + definitionName: string, + top: number, + ) { + this.logger?.debug( + `Calling Azure DevOps REST API, getting up to ${top} Builds for ${definitionName} in Project ${projectName}`, + ); + + const buildDefinitions = await this.getBuildDefinitions( + projectName, + definitionName, + ); + const definitions = buildDefinitions.map(bd => bd.id) as number[]; + const buildList = await this.getBuildList( + projectName, + definitions, + undefined, + top, + ); + + const repoBuilds: RepoBuild[] = buildList.map(build => { + return mappedRepoBuild(build); + }); + + return repoBuilds; + } + public async getPullRequests( projectName: string, repoName: string, diff --git a/plugins/azure-devops-backend/src/service/router.test.ts b/plugins/azure-devops-backend/src/service/router.test.ts index ce5f712392..82d4df1265 100644 --- a/plugins/azure-devops-backend/src/service/router.test.ts +++ b/plugins/azure-devops-backend/src/service/router.test.ts @@ -23,7 +23,7 @@ import { } from '@backstage/plugin-azure-devops-common'; import { AzureDevOpsApi } from '../api'; -import { Build } from 'azure-devops-node-api/interfaces/BuildInterfaces'; +import { Build, BuildDefinitionReference } from 'azure-devops-node-api/interfaces/BuildInterfaces'; import { ConfigReader } from '@backstage/config'; import { GitRepository } from 'azure-devops-node-api/interfaces/GitInterfaces'; import { createRouter } from './router'; @@ -39,7 +39,9 @@ describe('createRouter', () => { azureDevOpsApi = { getGitRepository: jest.fn(), getBuildList: jest.fn(), + getBuildDefinitions: jest.fn(), getRepoBuilds: jest.fn(), + getDefinitionBuilds: jest.fn(), getPullRequests: jest.fn(), } as any; const router = await createRouter({ @@ -136,6 +138,7 @@ describe('createRouter', () => { expect(azureDevOpsApi.getBuildList).toHaveBeenCalledWith( 'myProject', + undefined, 'af4ae3af-e747-4129-9bbc-d1329f6b0998', 40, ); @@ -144,6 +147,32 @@ describe('createRouter', () => { }); }); + describe('GET /build-definitions/:projectName/:definitionName', () => { + it('fetches a list of build definitions', async () => { + const inputDefinition: BuildDefinitionReference = { + id: 1, + name: 'myBuildDefinition', + }; + + const inputDefinitions: BuildDefinitionReference[] = [inputDefinition]; + + azureDevOpsApi.getBuildDefinitions.mockResolvedValueOnce( + inputDefinitions, + ); + + const response = await request(app).get( + '/build-definitions/myProject/myBuildDefinition', + ); + + expect(azureDevOpsApi.getBuildDefinitions).toHaveBeenCalledWith( + 'myProject', + 'myBuildDefinition', + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(inputDefinitions); + }); + }); + describe('GET /repo-builds/:projectName/:repoName', () => { it('fetches a list of repo builds', async () => { const firstRepoBuild: RepoBuild = { @@ -198,6 +227,60 @@ describe('createRouter', () => { }); }); + describe('GET /definition-builds/:projectName/:definitionName', () => { + it('fetches a list of repo builds', async () => { + const firstRepoBuild: RepoBuild = { + id: 1, + title: 'My Build Definition - Build 1', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=1', + status: BuildStatus.Completed, + result: BuildResult.PartiallySucceeded, + queueTime: undefined, + source: 'refs/heads/develop (f4f78b31)', + }; + + const secondRepoBuild: RepoBuild = { + id: 2, + title: 'My Build Definition - Build 2', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=2', + status: BuildStatus.InProgress, + result: BuildResult.None, + queueTime: undefined, + source: 'refs/heads/develop (13c988d4)', + }; + + const thirdRepoBuild: RepoBuild = { + id: 3, + title: 'My Build Definition - Build 3', + link: 'https://host.com/myOrg/0bcc0c0d-2d02/_build/results?buildId=3', + status: BuildStatus.Completed, + result: BuildResult.Succeeded, + queueTime: undefined, + source: 'refs/heads/develop (9bedf678)', + }; + + const repoBuilds: RepoBuild[] = [ + firstRepoBuild, + secondRepoBuild, + thirdRepoBuild, + ]; + + azureDevOpsApi.getDefinitionBuilds.mockResolvedValueOnce(repoBuilds); + + const response = await request(app) + .get('/definition-builds/myProject/myDefinition') + .query({ top: '30' }); + + expect(azureDevOpsApi.getDefinitionBuilds).toHaveBeenCalledWith( + 'myProject', + 'myDefinition', + 30, + ); + expect(response.status).toEqual(200); + expect(response.body).toEqual(repoBuilds); + }); + }); + describe('GET /pull-requests/:projectName/:repoName', () => { it('fetches a list of pull requests', async () => { const firstPullRequest: PullRequest = { diff --git a/plugins/azure-devops-backend/src/service/router.ts b/plugins/azure-devops-backend/src/service/router.ts index 57d54df18f..5e6369bb11 100644 --- a/plugins/azure-devops-backend/src/service/router.ts +++ b/plugins/azure-devops-backend/src/service/router.ts @@ -73,12 +73,25 @@ export async function createRouter( const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP; const buildList = await azureDevOpsApi.getBuildList( projectName, + undefined, repoId, top, ); res.status(200).json(buildList); }); + router.get( + '/build-definitions/:projectName/:definitionName', + async (req, res) => { + const { projectName, definitionName } = req.params; + const buildDefinitionList = await azureDevOpsApi.getBuildDefinitions( + projectName, + definitionName, + ); + res.status(200).json(buildDefinitionList); + }, + ); + router.get('/repo-builds/:projectName/:repoName', async (req, res) => { const { projectName, repoName } = req.params; @@ -93,6 +106,20 @@ export async function createRouter( res.status(200).json(gitRepository); }); + router.get( + '/definition-builds/:projectName/:definitionName', + async (req, res) => { + const { projectName, definitionName } = req.params; + const top = req.query.top ? Number(req.query.top) : DEFAULT_TOP; + const gitRepository = await azureDevOpsApi.getDefinitionBuilds( + projectName, + definitionName, + top, + ); + res.status(200).json(gitRepository); + }, + ); + router.get('/pull-requests/:projectName/:repoName', async (req, res) => { const { projectName, repoName } = req.params;