Start of refactoring based on feedback
Signed-off-by: Andre Wanlin <awanlin@rapidrtc.com>
This commit is contained in:
@@ -34,7 +34,7 @@ import {
|
||||
EntityProvidingComponentsCard,
|
||||
} from '@backstage/plugin-api-docs';
|
||||
import {
|
||||
EntityAzureDevOpsContent,
|
||||
EntityAzurePipelinesContent,
|
||||
isAzureDevOpsAvailable,
|
||||
} from '@backstage/plugin-azure-devops';
|
||||
import { EntityBadgesDialog } from '@backstage/plugin-badges';
|
||||
@@ -188,7 +188,7 @@ export const cicdContent = (
|
||||
</EntitySwitch.Case>
|
||||
|
||||
<EntitySwitch.Case if={isAzureDevOpsAvailable}>
|
||||
<EntityAzureDevOpsContent />
|
||||
<EntityAzurePipelinesContent />
|
||||
</EntitySwitch.Case>
|
||||
|
||||
<EntitySwitch.Case>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Website: [https://dev.azure.com/](https://dev.azure.com/)
|
||||
|
||||

|
||||

|
||||
|
||||
## Setup
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
* 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.
|
||||
|
||||
|
Before Width: | Height: | Size: 173 KiB After Width: | Height: | Size: 173 KiB |
@@ -27,8 +27,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.9.3",
|
||||
"@backstage/core-components": "^0.6.0",
|
||||
"@backstage/core-plugin-api": "^0.1.9",
|
||||
"@backstage/core-components": "^0.6.1",
|
||||
"@backstage/core-plugin-api": "^0.1.10",
|
||||
"@backstage/plugin-catalog-react": "^0.5.1",
|
||||
"@backstage/theme": "^0.2.10",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
@@ -42,10 +42,10 @@
|
||||
"react-use": "^17.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.7.14",
|
||||
"@backstage/core-app-api": "^0.1.15",
|
||||
"@backstage/cli": "^0.7.15",
|
||||
"@backstage/core-app-api": "^0.1.16",
|
||||
"@backstage/dev-utils": "^0.2.11",
|
||||
"@backstage/test-utils": "^0.1.17",
|
||||
"@backstage/test-utils": "^0.1.18",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^11.2.5",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { AzureDevOpsApi } from './AzureDevOpsApi';
|
||||
import { RepoBuild } from './types';
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
import { AzureDevOpsClientError } from './AzureDevOpsClientError';
|
||||
|
||||
export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
@@ -39,7 +40,9 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
}
|
||||
|
||||
private async get(path: string): Promise<any> {
|
||||
const url = `${await this.discoveryApi.getBaseUrl('azure-devops')}${path}`;
|
||||
const baseUrl = await this.discoveryApi.getBaseUrl('azure-devops');
|
||||
const url = `${baseUrl}/${path}`;
|
||||
|
||||
const idToken = await this.identityApi.getIdToken();
|
||||
const response = await fetch(url, {
|
||||
headers: idToken ? { Authorization: `Bearer ${idToken}` } : {},
|
||||
@@ -47,8 +50,7 @@ export class AzureDevOpsClient implements AzureDevOpsApi {
|
||||
|
||||
if (!response.ok) {
|
||||
const payload = await response.text();
|
||||
const message = `Request failed with ${response.status} ${response.statusText}, ${payload}`;
|
||||
throw new Error(message);
|
||||
throw new AzureDevOpsClientError(response, payload);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export class AzureDevOpsClientError extends Error {
|
||||
public constructor({ status, statusText }: Response, payload: string) {
|
||||
super(`Request failed with ${status} ${statusText}, ${payload}`);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
export type RepoBuild = {
|
||||
id?: number;
|
||||
title: string;
|
||||
link: string;
|
||||
link?: string;
|
||||
status?: BuildStatus;
|
||||
result?: BuildResult;
|
||||
queueTime?: Date;
|
||||
|
||||
@@ -32,17 +32,19 @@ import {
|
||||
BuildStatus,
|
||||
} from 'azure-devops-node-api/interfaces/BuildInterfaces';
|
||||
|
||||
const getBuildResultComponent = (result: number | undefined = 0) => {
|
||||
const getBuildResultComponent = (
|
||||
result: number | undefined = BuildResult.None,
|
||||
) => {
|
||||
switch (result) {
|
||||
case 0: // None
|
||||
case BuildResult.None:
|
||||
return <StatusError />;
|
||||
case 2: // Succeeded
|
||||
case BuildResult.Succeeded:
|
||||
return <StatusOK />;
|
||||
case 4: // PartiallySucceeded
|
||||
case BuildResult.PartiallySucceeded:
|
||||
return <StatusWarning />;
|
||||
case 8: // Failed
|
||||
case BuildResult.Failed:
|
||||
return <StatusError />;
|
||||
case 32: // Canceled
|
||||
case BuildResult.Canceled:
|
||||
return <StatusAborted />;
|
||||
default:
|
||||
return <StatusWarning />;
|
||||
@@ -75,7 +77,9 @@ const columns: TableColumn[] = [
|
||||
render: (row: Partial<RepoBuild>) => (
|
||||
<Box display="flex" alignItems="center">
|
||||
<Box mr={1} />
|
||||
<Typography variant="button">{BuildStatus[row.status || 0]}</Typography>
|
||||
<Typography variant="button">
|
||||
{BuildStatus[row.status || BuildStatus.None]}
|
||||
</Typography>
|
||||
</Box>
|
||||
),
|
||||
},
|
||||
@@ -86,7 +90,9 @@ const columns: TableColumn[] = [
|
||||
<Box display="flex" alignItems="center">
|
||||
{getBuildResultComponent(row.result)}
|
||||
<Box mr={1} />
|
||||
<Typography variant="button">{BuildResult[row.result || 0]}</Typography>
|
||||
<Typography variant="button">
|
||||
{BuildResult[row.result || BuildResult.None]}
|
||||
</Typography>
|
||||
</Box>
|
||||
),
|
||||
},
|
||||
@@ -98,7 +104,7 @@ const columns: TableColumn[] = [
|
||||
];
|
||||
|
||||
type Props = {
|
||||
items: RepoBuild[];
|
||||
items?: RepoBuild[];
|
||||
loading: boolean;
|
||||
error?: any;
|
||||
};
|
||||
@@ -125,8 +131,8 @@ export const BuildTable = ({ items, loading, error }: Props) => {
|
||||
pageSize: 5,
|
||||
showEmptyDataSourceMessage: !loading,
|
||||
}}
|
||||
title={`Builds (${(items && items.length) || 0})`}
|
||||
data={items}
|
||||
title={`Builds (${items ? items.length : 0})`}
|
||||
data={items || []}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -29,5 +29,5 @@ export const EntityPageAzureDevOps = (_props: Props) => {
|
||||
const { entity } = useEntity();
|
||||
const { items, loading, error } = useRepoBuilds(entity);
|
||||
|
||||
return <BuildTable items={items || []} loading={loading} error={error} />;
|
||||
return <BuildTable items={items} loading={loading} error={error} />;
|
||||
};
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
export const AZURE_DEVOPS_ANNOTATION = 'dev.azure.com/project-repo';
|
||||
export const AZURE_DEVOPS_DEFAULT_TOP: number = 10;
|
||||
|
||||
@@ -17,7 +17,10 @@
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { AZURE_DEVOPS_ANNOTATION } from '../constants';
|
||||
|
||||
export function useProjectRepoFromEntity(entity: Entity) {
|
||||
export function useProjectRepoFromEntity(entity: Entity): {
|
||||
project: string;
|
||||
repo: string;
|
||||
} {
|
||||
const [project, repo] = (
|
||||
entity.metadata.annotations?.[AZURE_DEVOPS_ANNOTATION] ?? ''
|
||||
).split('/');
|
||||
|
||||
@@ -20,12 +20,16 @@ import { useApi, configApiRef } from '@backstage/core-plugin-api';
|
||||
import { azureDevOpsApiRef } from '../api';
|
||||
import { RepoBuild } from '../api/types';
|
||||
import { useProjectRepoFromEntity } from './useProjectRepoFromEntity';
|
||||
import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants';
|
||||
|
||||
const DEFAULT_TOP: number = 10;
|
||||
|
||||
export function useRepoBuilds(entity: Entity) {
|
||||
export function useRepoBuilds(entity: Entity): {
|
||||
items: RepoBuild[];
|
||||
loading: boolean;
|
||||
error: any;
|
||||
} {
|
||||
const config = useApi(configApiRef);
|
||||
const top = config.getOptionalNumber('azureDevOps.top') ?? DEFAULT_TOP;
|
||||
const top =
|
||||
config.getOptionalNumber('azureDevOps.top') ?? AZURE_DEVOPS_DEFAULT_TOP;
|
||||
const api = useApi(azureDevOpsApiRef);
|
||||
const { project, repo } = useProjectRepoFromEntity(entity);
|
||||
const { value, loading, error } = useAsync(() => {
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { azureDevOpsPlugin, EntityAzureDevOpsContent } from './plugin';
|
||||
export { azureDevOpsPlugin, EntityAzurePipelinesContent } from './plugin';
|
||||
export { isAzureDevOpsAvailable } from './components/Router';
|
||||
|
||||
@@ -20,15 +20,10 @@ import {
|
||||
createApiFactory,
|
||||
createPlugin,
|
||||
createRoutableExtension,
|
||||
createRouteRef,
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
path: '',
|
||||
title: 'AzureDevOps',
|
||||
});
|
||||
import { azureDevOpsRouteRef } from './routes';
|
||||
|
||||
export const azureDevOpsPlugin = createPlugin({
|
||||
id: 'azureDevOps',
|
||||
@@ -41,14 +36,14 @@ export const azureDevOpsPlugin = createPlugin({
|
||||
}),
|
||||
],
|
||||
routes: {
|
||||
entityContent: rootRouteRef,
|
||||
entityContent: azureDevOpsRouteRef,
|
||||
},
|
||||
});
|
||||
|
||||
export const EntityAzureDevOpsContent = azureDevOpsPlugin.provide(
|
||||
export const EntityAzurePipelinesContent = azureDevOpsPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'EntityAzureDevOpsContent',
|
||||
component: () => import('./components/Router').then(m => m.Router),
|
||||
mountPoint: rootRouteRef,
|
||||
mountPoint: azureDevOpsRouteRef,
|
||||
}),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user