Skip to content

Commit

Permalink
Added a configuration option to fetch all entities from the catalog t…
Browse files Browse the repository at this point in the history
…o avoid "414 Request-URI Too Large" error (fix #184) (#196)

Author: @asokolov-a1
  • Loading branch information
asokolov-a1 authored Dec 9, 2023
1 parent e0448cb commit 7b37b37
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/silly-bottles-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@oriflame/backstage-plugin-score-card': patch
---

Added a configuration option to fetch all entities from the catalog to avoid "414 Request-URI Too Large" error (fix #184)
1 change: 1 addition & 0 deletions plugins/score-card/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Also the server providing the data needs to have correctly configured CORS polic
All configuration options:

- `jsonDataUrl`[optional]: url for the JSON data client, see [ScoringDataJsonClient](#scoringdatajsonclient).
- `fetchAllEntities`[optional]: if set to `true`, will fetch all the entities from the catalog and filter them afterwards. By default the entities are loaded from the catalog using a filter by name, which may result in `414 Request-URI Too Large`.
- `wikiLinkTemplate`[optional]: the template for the link to the wiki. You may use any existing properties from the `EntityScoreEntry`, e.g. `"https://TBD/XXX/_wiki/wikis/XXX.wiki/{id}"` or `"{scoreUrl}"`.

### How to use the plugin
Expand Down
62 changes: 62 additions & 0 deletions plugins/score-card/src/api/ScoringDataJsonClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ const getEntitiesMock = (
} as GetEntitiesResponse);
};

const getAllEntitiesMock = (
request?: GetEntitiesRequest,
): Promise<GetEntitiesResponse> => {
if (request?.filter && (request?.filter as Record<string, string[]>)["metadata.name"]) {
throw new Error("filter is not allowed")
}
const filterKinds =
Array.isArray(request?.filter) && Array.isArray(request?.filter[0].kind)
? request?.filter[0].kind ?? []
: [];
return Promise.resolve({
items: filterKinds.length? items.filter(item => filterKinds.find(k => k === item.kind)) : items,
} as GetEntitiesResponse);
};

describe('ScoringDataJsonClient-getAllScores', () => {
beforeEach(() => {
jest.spyOn(global, "fetch").mockImplementation(
Expand Down Expand Up @@ -158,6 +173,53 @@ describe('ScoringDataJsonClient-getAllScores', () => {
expect(entities).toEqual(expected);
});

it('should get all scores and fetch all entities', async () => {

const catalogApi: jest.Mocked<CatalogApi> = {
getEntities: jest.fn(),
} as any;

catalogApi.getEntities.mockImplementation(getAllEntitiesMock);

const mockConfig = new MockConfigApi({
app: { baseUrl: 'https://example.com' },
scorecards: { fetchAllEntities: true}
});
const mockFetch = new MockFetchApi();

const expected = [
{
"areaScores": [],
"entityRef": {"kind": "api", "name": "Api 1"},
"owner": {"kind": "group", "name": "team1", "namespace": "default"},
"reviewDate": new Date('2022-01-01T08:00:00.000Z'),
"reviewer": {"kind": "User", "name": "Reviewer 1", "namespace": "default"},
"scorePercent": 75,
"scoringReviewDate": "2022-01-01T08:00:00Z",
"scoringReviewer": "Reviewer 1"
},
{
"areaScores": [],
"entityRef": {"kind": "system", "name": "System 1"},
"owner": {"kind": "group", "name": "team2", "namespace": "default"},
"reviewDate": new Date('2022-01-01T08:00:00.000Z'),
"reviewer": {"kind": "User", "name": "Reviewer 2", "namespace": "default"},
"scorePercent": 80,
"scoringReviewDate": "2022-01-01T08:00:00Z",
"scoringReviewer": "Reviewer 2"
}
];

const api = new ScoringDataJsonClient({
configApi: mockConfig,
fetchApi: mockFetch,
catalogApi: catalogApi
});

const entities = await api.getAllScores();
expect(entities).toEqual(expected);
});

it('should filter entities by kind', async () => {

const catalogApi: jest.Mocked<CatalogApi> = {
Expand Down
18 changes: 10 additions & 8 deletions plugins/score-card/src/api/ScoringDataJsonClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,23 @@ export class ScoringDataJsonClient implements ScoringDataApi {
result = result.filter(entity => entityKindFilter.map(f => f.toLocaleLowerCase()).includes(entity.entityRef?.kind.toLowerCase() as string));
}

const entity_names: string[] = result.reduce((acc, a) => {
const entity_names: Set<string> = result.reduce((acc, a) => {
if (a.entityRef?.name) {
acc.push(a.entityRef.name);
acc.add(a.entityRef.name);
}
return acc;
}, [] as string[]);

}, new Set<string>);

const fetchAllEntities = this.configApi.getOptionalBoolean('scorecards.fetchAllEntities') ?? false
const response = await this.catalogApi.getEntities({
filter: {
'metadata.name': entity_names

filter: fetchAllEntities ? undefined: {
'metadata.name': Array.from(entity_names)
},
fields: ['kind', 'metadata.name', 'spec.owner', 'relations'],
});
const entities: Entity[] = response.items;
const entities: Entity[] = fetchAllEntities
? response.items.filter(i => entity_names.has(i.metadata.name))
: response.items;

return result.map<EntityScoreExtended>(score => {
return this.extendEntityScore(score, entities);
Expand Down

0 comments on commit 7b37b37

Please sign in to comment.