fix: refactored error handling

Signed-off-by: Andre Wanlin <awanlin@spotify.com>
This commit is contained in:
Andre Wanlin
2023-11-11 14:19:02 -06:00
parent 6f4160dee4
commit 2cf775e43a
7 changed files with 152 additions and 30 deletions
@@ -16,21 +16,13 @@
import { BuildTable } from '../BuildTable/BuildTable';
import React from 'react';
import { getAnnotationValuesFromEntity } from '../../utils/getAnnotationValuesFromEntity';
import { useBuildRuns } from '../../hooks/useBuildRuns';
import { useEntity } from '@backstage/plugin-catalog-react';
export const EntityPageAzurePipelines = (props: { defaultLimit?: number }) => {
const { entity } = useEntity();
const { project, repo, definition } = getAnnotationValuesFromEntity(entity);
const { items, loading, error } = useBuildRuns(
project,
props.defaultLimit,
repo,
definition,
);
const { items, loading, error } = useBuildRuns(entity, props.defaultLimit);
return <BuildTable items={items} loading={loading} error={error} />;
};
@@ -0,0 +1,126 @@
/*
* 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 React from 'react';
import { renderHook, waitFor } from '@testing-library/react';
import { Entity } from '@backstage/catalog-model';
import { BuildRun } from '@backstage/plugin-azure-devops-common';
import { TestApiProvider } from '@backstage/test-utils';
import { AzureDevOpsApi, azureDevOpsApiRef } from '../api';
import { useBuildRuns } from './useBuildRuns';
describe('useBuildRuns', () => {
const azureDevOpsApiMock = {
getBuildRuns: jest.fn(),
};
const azureDevOpsApi =
azureDevOpsApiMock as Partial<AzureDevOpsApi> as AzureDevOpsApi;
const Wrapper = (props: { children?: React.ReactNode }) => (
<TestApiProvider apis={[[azureDevOpsApiRef, azureDevOpsApi]]}>
{props.children}
</TestApiProvider>
);
it('should provide an array of BuildRun', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
namespace: 'default',
name: 'project-repo',
annotations: {
'dev.azure.com/project-repo': 'projectName/repoName',
},
},
};
const buildRuns: BuildRun[] = [
{
id: 1,
title: 'title-1',
source: 'awanlin',
link: 'https://dev.azure.com/org/project/repo',
},
{
id: 2,
title: 'title-2',
source: 'awanlin',
link: 'https://dev.azure.com/org/project/repo',
},
{
id: 3,
title: 'title-3',
source: 'awanlin',
link: 'https://dev.azure.com/org/project/repo',
},
];
azureDevOpsApiMock.getBuildRuns.mockResolvedValue({
items: buildRuns,
});
const { result } = renderHook(() => useBuildRuns(entity), {
wrapper: Wrapper,
});
expect(result.current.loading).toEqual(true);
await waitFor(() => {
expect(result.current).toEqual({
error: undefined,
items: buildRuns,
loading: false,
});
});
});
it('should return throw when annotation missing', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
namespace: 'default',
name: 'project-repo',
},
};
expect(() =>
renderHook(() => useBuildRuns(entity), {
wrapper: Wrapper,
}),
).toThrow('Value for annotation "dev.azure.com/project" was not found');
});
it('should return throw when annotation invalid', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
namespace: 'default',
name: 'project-repo',
annotations: {
'dev.azure.com/project-repo': 'fake',
},
},
};
expect(() =>
renderHook(() => useBuildRuns(entity), {
wrapper: Wrapper,
}),
).toThrow(
'Invalid value for annotation "dev.azure.com/project-repo"; expected format is: <project-name>/<repo-name>, found: "fake"',
);
});
});
@@ -23,12 +23,12 @@ import { AZURE_DEVOPS_DEFAULT_TOP } from '../constants';
import { azureDevOpsApiRef } from '../api';
import { useApi } from '@backstage/core-plugin-api';
import useAsync from 'react-use/lib/useAsync';
import { getAnnotationValuesFromEntity } from '../utils';
import { Entity } from '@backstage/catalog-model';
export function useBuildRuns(
projectName: string,
entity: Entity,
defaultLimit?: number,
repoName?: string,
definitionName?: string,
): {
items?: BuildRun[];
loading: boolean;
@@ -42,8 +42,9 @@ export function useBuildRuns(
const api = useApi(azureDevOpsApiRef);
const { value, loading, error } = useAsync(() => {
return api.getBuildRuns(projectName, repoName, definitionName, options);
}, [api, projectName, repoName, definitionName]);
const { project, repo, definition } = getAnnotationValuesFromEntity(entity);
return api.getBuildRuns(project, repo, definition, options);
}, [api]);
return {
items: value?.items,
+4 -4
View File
@@ -28,11 +28,11 @@ export function useGitTags(entity: Entity): {
error?: Error;
} {
const api = useApi(azureDevOpsApiRef);
const { project, repo } = getAnnotationValuesFromEntity(entity);
const { value, loading, error } = useAsync(async () => {
return await api.getGitTags(project, repo as string);
}, [api, project, repo]);
const { value, loading, error } = useAsync(() => {
const { project, repo } = getAnnotationValuesFromEntity(entity);
return api.getGitTags(project, repo as string);
}, [api]);
return {
items: value?.items,
@@ -44,11 +44,11 @@ export function usePullRequests(
};
const api = useApi(azureDevOpsApiRef);
const { project, repo } = getAnnotationValuesFromEntity(entity);
const { value, loading, error } = useAsync(async () => {
return await api.getPullRequests(project, repo as string, options);
}, [api, project, repo, top, status]);
const { value, loading, error } = useAsync(() => {
const { project, repo } = getAnnotationValuesFromEntity(entity);
return api.getPullRequests(project, repo as string, options);
}, [api, top, status]);
return {
items: value?.items,
+4 -4
View File
@@ -28,11 +28,11 @@ export function useReadme(entity: Entity): {
error?: Error;
} {
const api = useApi(azureDevOpsApiRef);
const { project, repo } = getAnnotationValuesFromEntity(entity);
const { value, loading, error } = useAsync(async () => {
return await api.getReadme({ project, repo: repo as string });
}, [api, project, repo]);
const { value, loading, error } = useAsync(() => {
const { project, repo } = getAnnotationValuesFromEntity(entity);
return api.getReadme({ project, repo: repo as string });
}, [api]);
return {
item: value,
@@ -26,6 +26,9 @@ import { useApi } from '@backstage/core-plugin-api';
import useAsync from 'react-use/lib/useAsync';
import { getAnnotationValuesFromEntity } from '../utils';
/**
* @deprecated Use `useBuildRuns` instead
*/
export function useRepoBuilds(
entity: Entity,
defaultLimit?: number,
@@ -40,11 +43,11 @@ export function useRepoBuilds(
};
const api = useApi(azureDevOpsApiRef);
const { project, repo } = getAnnotationValuesFromEntity(entity);
const { value, loading, error } = useAsync(async () => {
return await api.getRepoBuilds(project, repo as string, options);
}, [api, project, repo, entity]);
const { value, loading, error } = useAsync(() => {
const { project, repo } = getAnnotationValuesFromEntity(entity);
return api.getRepoBuilds(project, repo as string, options);
}, [api, entity]);
return {
items: value?.items,