Skip to content

Commit

Permalink
Merge pull request #1096 from fhp/bugsnag-fix-error
Browse files Browse the repository at this point in the history
Improvements to Bugsnag plugin
  • Loading branch information
Xantier authored Sep 12, 2023
2 parents 34e0a9f + 5b4f418 commit 4697896
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 29 deletions.
17 changes: 17 additions & 0 deletions .changeset/nice-yaks-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@roadiehq/backstage-plugin-bugsnag': minor
---

**BREAKING** Change the `bugsnag.com/project-key` annotation from `OrganizationName/projectApiKey` to `OrganizationName/ProjectName`.

This change allows (optionally) changing the content of the `bugsnag.com/project-key` annotation to `Organization name/Project name`. As this already contains the project name, the `bugsnag.com/project-name` annotation becomes deprecated. Configuring the plugin this way makes more sense, as the secret api-key can be kept out of the repositories. The plugin will detect if the plugin is configured with an old annotation, and revert to the old behaviour if needed.

Improve the display of data in the table:

- It adds the description and the status to the table.
- It adds filtering options to the table.

Bugfixes:

- Don't throw an error if the annotation is missing.
- If there are multiple stages, they are now joined with a comma.
3 changes: 2 additions & 1 deletion ADOPTERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
| ----------------------------------------- | -------------------------------------------- | ----------------------------- |
| [Roadie](https://roadie.io) | [@dtuite](https://github.com/dtuite) | Development |
| [Hopin](https://hopin.com) | [@vglafirov](https://github.com/vglafirov) | Development experience portal |
| [OVO Energy](https://www.ovoenergy.com/) | [@dlaird-ovo](https://github.com/dlaird-ovo) | Developer Portal |
| [OVO Energy](https://www.ovoenergy.com/) | [@dlaird-ovo](https://github.com/dlaird-ovo) | Developer Portal |
| [Gynzy](https://www.gynzy.com/) | [@fhp](https://github.com/fhp) | Developer Portal |
8 changes: 6 additions & 2 deletions packages/app/cypress/fixtures/Bugsnag/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
"first_seen": "2021-09-05T09:17:17.384804Z",
"last_seen": "2021-09-20T09:17:17.384804Z",
"events": 3,
"release_stages": "Development",
"release_stages": ["Development"],
"message": "Something went wrong",
"error_class": "Error",
"status": "open",
"users": 5
},
{
Expand All @@ -17,8 +19,10 @@
"first_seen": "2021-09-11T09:17:17.384804Z",
"last_seen": "2021-09-20T09:17:17.384804Z",
"events": 3,
"release_stages": "Development",
"release_stages": ["Development", "Test"],
"message": "This is a test error",
"error_class": "Error",
"status": "open",
"users": 5
}
]
6 changes: 4 additions & 2 deletions packages/app/cypress/integration/bugsnag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Bugsnag', () => {
).as('getOrganizations');
cy.intercept(
'GET',
'http://localhost:7007/api/proxy/bugsnag/api/organizations/129876sdfgh/projects?per_page=50',
'http://localhost:7007/api/proxy/bugsnag/api/organizations/129876sdfgh/projects?q=Test%20bugsnag%20application&per_page=50',
{ fixture: 'Bugsnag/projects.json' },
).as('getProjects');
cy.intercept(
Expand All @@ -43,7 +43,9 @@ describe('Bugsnag', () => {

describe('Navigating to Bugsnag', () => {
it('should show Bugsnag when navigating to Bugsnag tab', () => {
cy.contains('Errors overview');
cy.contains('Description');
cy.contains('This is a test error');
cy.contains('Development, Test');
});
});
});
2 changes: 1 addition & 1 deletion packages/entities/test-entity.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ metadata:
datadoghq.com/dashboard-url: https://p.datadoghq.eu/sb/test-datadog-link
datadoghq.com/graph-token: qwertytoken1234
argocd/app-name: test-app
bugsnag.com/project-key: RoadieHQTest/qwerty12345
bugsnag.com/project-key: RoadieHQTest/Test bugsnag application
spec:
type: service
owner: roadie
Expand Down
8 changes: 2 additions & 6 deletions plugins/frontend/backstage-plugin-bugsnag/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,10 @@ const serviceEntityPage = (
1. Add annotations to the yaml config file of a component:

```yml
bugsnag.com/project-key: <organization-name>/<project-notifier-api-key>
bugsnag.com/project-key: <organization-name>/<project-name>
```
Please note that if your organisation has more projects than results returned by page and defined under 'bugsnag.resultsPerPage' you need to provide additional annotations where you will provide the name of the project:
```yml
bugsnag.com/project-name: <project-name>
```
Note that you must use the full names, not the slugs.
These values can be found in Bugsnag settings dashboard, under organization and project settings.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion plugins/frontend/backstage-plugin-bugsnag/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ export type BugsnagError = {
first_seen: string;
last_seen: string;
events: number;
release_stages: string;
release_stages: string[];
error_class: string;
users: number;
message: string;
status: string;
};

export type Organisation = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ import {
useProjectName,
} from '../../hooks/useBugsnagData';

export const ErrorsOverview = () => {
const { entity } = useEntity();
export const ErrorsOverviewComponent = () => {
const organisationName = useBugsnagData()[0];
const projectApiKey = useBugsnagData()[1];
const projectName = useProjectName();
const projectNameOrKey = useBugsnagData()[1];
const projectNameAnnotation = useProjectName();
const isKey = /^[0-9a-fA-F]{32}$/i.test(projectNameOrKey);
const projectName = isKey ? projectNameAnnotation : projectNameOrKey;
const api = useApi(bugsnagApiRef);
const configApi = useApi(configApiRef);
const [slug, setOrganisationSlug] = useState('');
Expand All @@ -61,7 +62,9 @@ export const ErrorsOverview = () => {
});

const filteredProject = projects.find(proj =>
proj.api_key.includes(projectApiKey),
isKey
? proj.api_key.includes(projectNameOrKey)
: proj.name.includes(projectNameOrKey),
);
return filteredProject;
});
Expand All @@ -72,7 +75,7 @@ export const ErrorsOverview = () => {
return <Alert severity="error">{error.message}</Alert>;
}

return isBugsnagAvailable(entity) ? (
return (
<Page themeId="tool">
<Content>
<ContentHeader title="Bugsnag logs">
Expand All @@ -87,7 +90,13 @@ export const ErrorsOverview = () => {
</Grid>
</Content>
</Page>
) : (
<MissingAnnotationEmptyState annotation={BUGSNAG_ANNOTATION} />
);
};

export const ErrorsOverview = () => {
const { entity } = useEntity();
if (!isBugsnagAvailable(entity)) {
return <MissingAnnotationEmptyState annotation={BUGSNAG_ANNOTATION} />;
}
return <ErrorsOverviewComponent />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ describe('BugsnagErrorsTable', () => {
</TestApiProvider>,
),
);
expect(await rendered.findByText('Errors overview')).toBeInTheDocument();
expect(await rendered.findByText('Description')).toBeInTheDocument();
expect(await rendered.findByText('SyntaxError')).toBeInTheDocument();
expect(await rendered.findByText('Development, Test')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ export const DenseTable = ({
}) => {
const columns: TableColumn[] = [
{ title: '', field: 'class' },
{ title: 'Description', field: 'message', width: '40%' },
{ title: 'Events', field: 'events' },
{ title: 'Users', field: 'users' },
{ title: 'Stage', field: 'stage' },
{ title: 'First seen', field: 'first_seen' },
{ title: 'Last seen', field: 'last_seen' },
{ title: 'Severity', field: 'severity' },
{ title: 'Status', field: 'status' },
];

const data = errors.map(error => {
Expand All @@ -81,7 +83,9 @@ export const DenseTable = ({
organisationName,
projectName,
),
stage: error.release_stages,
message: error.message,
status: error.status,
stage: error.release_stages.join(', '),
events: error.events,
id: error.id,
project_id: error.project_id,
Expand All @@ -93,10 +97,23 @@ export const DenseTable = ({

return (
<Table
title="Errors overview"
options={{ search: true, paging: true }}
columns={columns}
data={data}
filters={[
{
column: 'Severity',
type: 'multiple-select',
},
{
column: 'Status',
type: 'multiple-select',
},
{
column: 'Stage',
type: 'multiple-select',
},
]}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const ErrorsMock = [
first_seen: '2021-09-05T09:17:17.384804Z',
last_seen: '2021-09-20T09:17:17.384804Z',
events: 3,
release_stages: 'Development',
release_stages: ['Development', 'Test'],
error_class: 'Error',
users: 5,
},
Expand All @@ -33,7 +33,7 @@ export const ErrorsMock = [
first_seen: '2021-09-11T09:17:17.384804Z',
last_seen: '2021-09-20T09:17:17.384804Z',
events: 3,
release_stages: 'Development',
release_stages: ['Development'],
error_class: 'Error',
users: 5,
},
Expand All @@ -44,7 +44,7 @@ export const ErrorsMock = [
first_seen: '2021-09-06T09:17:17.384804Z',
last_seen: '2021-09-10T09:17:17.384804Z',
events: 3,
release_stages: 'Development',
release_stages: ['Development'],
error_class: 'Error',
users: 5,
},
Expand All @@ -55,7 +55,7 @@ export const ErrorsMock = [
first_seen: '2021-09-15T09:17:17.384804Z',
last_seen: '2021-09-20T09:17:17.384804Z',
events: 3,
release_stages: 'Development',
release_stages: ['Development'],
error_class: 'SyntaxError',
users: 5,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { entityMock } from '../../mocks/mocks';
import PullRequestsStatsCard from './PullRequestsStatsCard';
import { EntityProvider } from '@backstage/plugin-catalog-react';
import { handlers } from '../../mocks/handlers';
import { Duration } from 'luxon';

const mockGithubAuth = {
getAccessToken: async (_: string[]) => 'test-token',
Expand Down Expand Up @@ -65,7 +66,11 @@ describe('PullRequestsCard', () => {
</TestApiProvider>,
);
expect(
await screen.findByText('1 month, 26 days, 16 hours'),
await screen.findByText(
Duration.fromObject({ months: 1, days: 26, hours: 16 }).toHuman({
notation: 'compact',
}),
),
).toBeInTheDocument();
expect(await screen.findByText('67%')).toBeInTheDocument();
expect(await screen.findByText('3309 lines')).toBeInTheDocument();
Expand Down

0 comments on commit 4697896

Please sign in to comment.