feat: Created PullRequestsDashboardProvider for resolving team and team member relations
Signed-off-by: Marley Powell <Marley.Powell@exclaimer.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
PullRequestOptions,
|
||||
RepoBuild,
|
||||
Team,
|
||||
TeamMember,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
import {
|
||||
GitPullRequest,
|
||||
@@ -40,9 +41,9 @@ import {
|
||||
getArtifactId,
|
||||
} from '../utils';
|
||||
|
||||
import { TeamMember as AdoTeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces';
|
||||
import { Logger } from 'winston';
|
||||
import { PolicyEvaluationRecord } from 'azure-devops-node-api/interfaces/PolicyInterfaces';
|
||||
import { TeamMember } from 'azure-devops-node-api/interfaces/common/VSSInterfaces';
|
||||
import { WebApi } from 'azure-devops-node-api';
|
||||
import { WebApiTeam } from 'azure-devops-node-api/interfaces/CoreInterfaces';
|
||||
|
||||
@@ -228,22 +229,19 @@ export class AzureDevOpsApi {
|
||||
const client = await this.webApi.getCoreApi();
|
||||
const webApiTeams: WebApiTeam[] = await client.getAllTeams();
|
||||
|
||||
const teams: Team[] = await Promise.all(
|
||||
webApiTeams.map(async team => ({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
memberIds: await this.getTeamMemberIds(team),
|
||||
})),
|
||||
);
|
||||
const teams: Team[] = webApiTeams.map(team => ({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
projectId: team.projectId,
|
||||
projectName: team.projectName,
|
||||
}));
|
||||
|
||||
return teams.sort((a, b) =>
|
||||
a.name && b.name ? a.name.localeCompare(b.name) : 0,
|
||||
);
|
||||
}
|
||||
|
||||
private async getTeamMemberIds(
|
||||
team: WebApiTeam,
|
||||
): Promise<string[] | undefined> {
|
||||
public async getTeamMembers(team: Team): Promise<TeamMember[] | undefined> {
|
||||
this.logger?.debug(`Getting team member ids for team '${team.name}'.`);
|
||||
|
||||
if (!team.projectId || !team.id) {
|
||||
@@ -252,15 +250,17 @@ export class AzureDevOpsApi {
|
||||
|
||||
const client = await this.webApi.getCoreApi();
|
||||
|
||||
const teamMembers: TeamMember[] =
|
||||
const teamMembers: AdoTeamMember[] =
|
||||
await client.getTeamMembersWithExtendedProperties(
|
||||
team.projectId,
|
||||
team.id,
|
||||
);
|
||||
|
||||
return teamMembers
|
||||
.map(teamMember => teamMember.identity?.id)
|
||||
.filter((id): id is string => Boolean(id));
|
||||
return teamMembers.map(teamMember => ({
|
||||
id: teamMember.identity?.id,
|
||||
displayName: teamMember.identity?.displayName,
|
||||
uniqueName: teamMember.identity?.uniqueName,
|
||||
}));
|
||||
}
|
||||
|
||||
public async getBuildDefinitions(
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2021 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 {
|
||||
DashboardPullRequest,
|
||||
PullRequestOptions,
|
||||
Team,
|
||||
TeamMember,
|
||||
} from '@backstage/plugin-azure-devops-common';
|
||||
|
||||
import { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
export class PullRequestsDashboardProvider {
|
||||
private teams = new Map<string, Team>();
|
||||
|
||||
private teamMembers = new Map<string, TeamMember>();
|
||||
|
||||
private constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly azureDevOpsApi: AzureDevOpsApi,
|
||||
) {}
|
||||
|
||||
public static async create(
|
||||
logger: Logger,
|
||||
azureDevOpsApi: AzureDevOpsApi,
|
||||
): Promise<PullRequestsDashboardProvider> {
|
||||
const provider = new PullRequestsDashboardProvider(logger, azureDevOpsApi);
|
||||
await provider.readTeams();
|
||||
return provider;
|
||||
}
|
||||
|
||||
public async readTeams(): Promise<void> {
|
||||
this.logger.info('Reading teams.');
|
||||
|
||||
let teams = await this.azureDevOpsApi.getAllTeams();
|
||||
|
||||
// This is used to filter out the default Azure Devops project teams.
|
||||
teams = teams.filter(team =>
|
||||
team.name && team.projectName
|
||||
? team.name !== `${team.projectName} Team`
|
||||
: true,
|
||||
);
|
||||
|
||||
this.teams = new Map<string, Team>();
|
||||
this.teamMembers = new Map<string, TeamMember>();
|
||||
|
||||
await Promise.all(
|
||||
teams.map(async team => {
|
||||
const teamId = team.id;
|
||||
|
||||
if (teamId) {
|
||||
const teamMembers = await this.azureDevOpsApi.getTeamMembers(team);
|
||||
|
||||
if (teamMembers) {
|
||||
team.members = teamMembers.reduce((arr, teamMember) => {
|
||||
const teamMemberId = teamMember.id;
|
||||
|
||||
if (teamMemberId) {
|
||||
arr.push(teamMemberId);
|
||||
const memberOf = [
|
||||
...(this.teamMembers.get(teamMemberId)?.memberOf ?? []),
|
||||
teamId,
|
||||
];
|
||||
this.teamMembers.set(teamMemberId, { ...teamMember, memberOf });
|
||||
}
|
||||
|
||||
return arr;
|
||||
}, [] as string[]);
|
||||
|
||||
this.teams.set(teamId, team);
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
public async getDashboardPullRequests(
|
||||
projectName: string,
|
||||
options: PullRequestOptions,
|
||||
): Promise<DashboardPullRequest[]> {
|
||||
const dashboardPullRequests =
|
||||
await this.azureDevOpsApi.getDashboardPullRequests(projectName, options);
|
||||
|
||||
return dashboardPullRequests.map(pr => {
|
||||
if (pr.createdBy?.id) {
|
||||
const teamIds = this.teamMembers.get(pr.createdBy.id)?.memberOf;
|
||||
pr.createdBy.teamIds = teamIds;
|
||||
pr.createdBy.teamNames = teamIds?.map(
|
||||
teamId => this.teams.get(teamId)?.name ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
return pr;
|
||||
});
|
||||
}
|
||||
|
||||
public getUserTeamIds(email: string): string[] {
|
||||
return (
|
||||
this.getTeamMembers().find(teamMember => teamMember.uniqueName === email)
|
||||
?.memberOf ?? []
|
||||
);
|
||||
}
|
||||
|
||||
public async getAllTeams(): Promise<Team[]> {
|
||||
if (!this.teams.size) {
|
||||
await this.readTeams();
|
||||
}
|
||||
|
||||
return Array.from(this.teams.values());
|
||||
}
|
||||
|
||||
public getTeamMembers(): TeamMember[] {
|
||||
return Array.from(this.teamMembers.values());
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import { WebApi, getPersonalAccessTokenHandler } from 'azure-devops-node-api';
|
||||
import { AzureDevOpsApi } from '../api';
|
||||
import { Config } from '@backstage/config';
|
||||
import { Logger } from 'winston';
|
||||
import { PullRequestsDashboardProvider } from '../api/PullRequestsDashboardProvider';
|
||||
import Router from 'express-promise-router';
|
||||
import { errorHandler } from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
@@ -52,6 +53,9 @@ export async function createRouter(
|
||||
const azureDevOpsApi =
|
||||
options.azureDevOpsApi || new AzureDevOpsApi(logger, webApi);
|
||||
|
||||
const pullRequestsDashboardProvider =
|
||||
await PullRequestsDashboardProvider.create(logger, azureDevOpsApi);
|
||||
|
||||
const router = Router();
|
||||
router.use(express.json());
|
||||
|
||||
@@ -131,7 +135,7 @@ export async function createRouter(
|
||||
};
|
||||
|
||||
const pullRequests: DashboardPullRequest[] =
|
||||
await azureDevOpsApi.getDashboardPullRequests(
|
||||
await pullRequestsDashboardProvider.getDashboardPullRequests(
|
||||
projectName,
|
||||
pullRequestOptions,
|
||||
);
|
||||
@@ -140,7 +144,7 @@ export async function createRouter(
|
||||
});
|
||||
|
||||
router.get('/all-teams', async (_req, res) => {
|
||||
const allTeams = await azureDevOpsApi.getAllTeams();
|
||||
const allTeams = await pullRequestsDashboardProvider.getAllTeams();
|
||||
res.status(200).json(allTeams);
|
||||
});
|
||||
|
||||
@@ -170,6 +174,12 @@ export async function createRouter(
|
||||
res.status(200).json(builds);
|
||||
});
|
||||
|
||||
router.get('/users/:userId/team-ids', async (req, res) => {
|
||||
const { userId } = req.params;
|
||||
const teamIds = pullRequestsDashboardProvider.getUserTeamIds(userId);
|
||||
res.status(200).json(teamIds);
|
||||
});
|
||||
|
||||
router.use(errorHandler());
|
||||
return router;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user