Skip to content

Commit 8db5951

Browse files
authored
feat(rollbar): allow custom environment names with annotation (#4777)
Add an optional annotation to override the default project "production" environment name. Signed-off-by: James Andrew Vaughn <[email protected]>
1 parent 10cfc05 commit 8db5951

File tree

10 files changed

+120
-3
lines changed

10 files changed

+120
-3
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@backstage-community/plugin-rollbar': patch
3+
---
4+
5+
Allow custom project environment name

workspaces/rollbar/plugins/rollbar/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ metadata:
4747
rollbar.com/project-slug: organization-name/project-name
4848
# -- or just ---
4949
rollbar.com/project-slug: project-name
50+
# -- optional (default: production) ---
51+
rollbar.com/environment: environment-name
5052
```
5153

5254
6. Run app with `yarn start` and navigate to `/rollbar` or a catalog entity

workspaces/rollbar/plugins/rollbar/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"@testing-library/dom": "^10.0.0",
6262
"@testing-library/jest-dom": "^6.0.0",
6363
"@testing-library/react": "^15.0.0",
64+
"@testing-library/react-hooks": "8.0.1",
6465
"@types/lodash": "^4.14.151",
6566
"@types/react-dom": "^18.2.19",
6667
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",

workspaces/rollbar/plugins/rollbar/report.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface RollbarApi {
3737
getTopActiveItems(
3838
project: string,
3939
hours?: number,
40+
environment?: string,
4041
): Promise<RollbarTopActiveItem[]>;
4142
}
4243

workspaces/rollbar/plugins/rollbar/src/api/RollbarApi.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface RollbarApi {
3333
getTopActiveItems(
3434
project: string,
3535
hours?: number,
36+
environment?: string,
3637
): Promise<RollbarTopActiveItem[]>;
3738
getProjectItems(project: string): Promise<RollbarItemsResponse>;
3839
}

workspaces/rollbar/plugins/rollbar/src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616

1717
/** @public */
1818
export const ROLLBAR_ANNOTATION = 'rollbar.com/project-slug';
19+
export const ROLLBAR_ENVIRONMENT_ANNOTATION = 'rollbar.com/environment';

workspaces/rollbar/plugins/rollbar/src/hooks/useProject.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616

1717
import { Entity } from '@backstage/catalog-model';
18-
import { ROLLBAR_ANNOTATION } from '../constants';
18+
import {
19+
ROLLBAR_ANNOTATION,
20+
ROLLBAR_ENVIRONMENT_ANNOTATION,
21+
} from '../constants';
1922
import { useApi, configApiRef } from '@backstage/core-plugin-api';
2023

2124
export function useProjectSlugFromEntity(entity: Entity) {
@@ -33,5 +36,6 @@ export function useProjectSlugFromEntity(entity: Entity) {
3336
organization ??
3437
configApi.getOptionalString('rollbar.organization') ??
3538
configApi.getString('organization.name'),
39+
environment: entity?.metadata.annotations?.[ROLLBAR_ENVIRONMENT_ANNOTATION],
3640
};
3741
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2025 The Backstage Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { default as React } from 'react';
18+
import { renderHook } from '@testing-library/react-hooks';
19+
import { useTopActiveItems } from './useTopActiveItems';
20+
import { rollbarApiRef } from '../api';
21+
import { TestApiProvider } from '@backstage/test-utils';
22+
import { Entity } from '@backstage/catalog-model';
23+
import { configApiRef } from '@backstage/core-plugin-api';
24+
25+
describe('useTopActiveItems', () => {
26+
const mockApi = {
27+
getTopActiveItems: jest.fn(),
28+
};
29+
30+
const entity: Entity = {
31+
apiVersion: 'backstage.io/v1alpha1',
32+
kind: 'Component',
33+
metadata: {
34+
name: 'test-service',
35+
annotations: {
36+
'rollbar.com/project-slug': 'foo/bar',
37+
'rollbar.com/environment': 'qa',
38+
},
39+
},
40+
spec: {},
41+
};
42+
43+
it('should use the environment annotation', async () => {
44+
mockApi.getTopActiveItems.mockResolvedValueOnce([
45+
{ item: { occurrences: 2 } },
46+
{ item: { occurrences: 5 } },
47+
]);
48+
const wrapper = ({ children }: { children: React.ReactNode }) => (
49+
<TestApiProvider
50+
apis={[
51+
[rollbarApiRef, mockApi],
52+
[configApiRef, {}],
53+
]}
54+
>
55+
{children}
56+
</TestApiProvider>
57+
);
58+
const { result, waitForNextUpdate } = renderHook(
59+
() => useTopActiveItems(entity),
60+
{ wrapper },
61+
);
62+
await waitForNextUpdate();
63+
expect(mockApi.getTopActiveItems).toHaveBeenCalledWith('bar', 168, 'qa');
64+
expect(result.current.items[0].item.occurrences).toBe(5);
65+
expect(result.current.items[1].item.occurrences).toBe(2);
66+
});
67+
});

workspaces/rollbar/plugins/rollbar/src/hooks/useTopActiveItems.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@ import { useApi } from '@backstage/core-plugin-api';
2323

2424
export function useTopActiveItems(entity: Entity) {
2525
const api = useApi(rollbarApiRef);
26-
const { organization, project } = useProjectSlugFromEntity(entity);
26+
const { organization, project, environment } =
27+
useProjectSlugFromEntity(entity);
2728
const { value, loading, error } = useAsync(() => {
2829
if (!project) {
2930
return Promise.resolve([]);
3031
}
3132

3233
return api
33-
.getTopActiveItems(project, 168)
34+
.getTopActiveItems(project, 168, environment)
3435
.then(data =>
3536
data.sort((a, b) => b.item.occurrences - a.item.occurrences),
3637
);

workspaces/rollbar/yarn.lock

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,6 +2629,7 @@ __metadata:
26292629
"@testing-library/dom": "npm:^10.0.0"
26302630
"@testing-library/jest-dom": "npm:^6.0.0"
26312631
"@testing-library/react": "npm:^15.0.0"
2632+
"@testing-library/react-hooks": "npm:8.0.1"
26322633
"@types/lodash": "npm:^4.14.151"
26332634
"@types/react": "npm:^16.13.1 || ^17.0.0 || ^18.0.0"
26342635
"@types/react-dom": "npm:^18.2.19"
@@ -8295,6 +8296,28 @@ __metadata:
82958296
languageName: node
82968297
linkType: hard
82978298

8299+
"@testing-library/react-hooks@npm:8.0.1":
8300+
version: 8.0.1
8301+
resolution: "@testing-library/react-hooks@npm:8.0.1"
8302+
dependencies:
8303+
"@babel/runtime": "npm:^7.12.5"
8304+
react-error-boundary: "npm:^3.1.0"
8305+
peerDependencies:
8306+
"@types/react": ^16.9.0 || ^17.0.0
8307+
react: ^16.9.0 || ^17.0.0
8308+
react-dom: ^16.9.0 || ^17.0.0
8309+
react-test-renderer: ^16.9.0 || ^17.0.0
8310+
peerDependenciesMeta:
8311+
"@types/react":
8312+
optional: true
8313+
react-dom:
8314+
optional: true
8315+
react-test-renderer:
8316+
optional: true
8317+
checksum: 10/f7b69373feebe99bc7d60595822cc5c00a1a5a4801bc4f99b597256a5c1d23c45a51f359051dd8a7bdffcc23b26f324c582e9433c25804934fd351a886812790
8318+
languageName: node
8319+
linkType: hard
8320+
82988321
"@testing-library/react@npm:^15.0.0":
82998322
version: 15.0.2
83008323
resolution: "@testing-library/react@npm:15.0.2"
@@ -21767,6 +21790,17 @@ __metadata:
2176721790
languageName: node
2176821791
linkType: hard
2176921792

21793+
"react-error-boundary@npm:^3.1.0":
21794+
version: 3.1.4
21795+
resolution: "react-error-boundary@npm:3.1.4"
21796+
dependencies:
21797+
"@babel/runtime": "npm:^7.12.5"
21798+
peerDependencies:
21799+
react: ">=16.13.1"
21800+
checksum: 10/7418637bf352b88f35ff3798e6faa094ee046df9d422fc08f54c017892c3c0738dac661ba3d64d97209464e7a60e7fbbeffdbeaee5edc38f3aaf5f1f4a8bf610
21801+
languageName: node
21802+
linkType: hard
21803+
2177021804
"react-error-overlay@npm:^6.0.11":
2177121805
version: 6.0.11
2177221806
resolution: "react-error-overlay@npm:6.0.11"

0 commit comments

Comments
 (0)