Configure DefaultCatalogCollator programmatically

Signed-off-by: Roy Jacobs <roy.jacobs@gmail.com>
This commit is contained in:
Roy Jacobs
2021-08-31 13:12:59 +02:00
parent ce17a16931
commit 2e4b768445
5 changed files with 54 additions and 36 deletions
-1
View File
@@ -1,5 +1,4 @@
---
'example-backend': patch
'@backstage/plugin-catalog-backend': patch
---
-12
View File
@@ -179,17 +179,5 @@ export interface Config {
};
};
};
/**
* Configuration for search collation
*/
search?: {
/**
* Request search to only index these particular kinds.
*
* E.g. ["Component", "API", "Template", "Location"]
*/
allow: Array<string>;
};
};
}
@@ -16,7 +16,10 @@
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { Entity } from '@backstage/catalog-model';
import { DefaultCatalogCollator } from './DefaultCatalogCollator';
import {
DefaultCatalogCollator,
mapFilterToQueryString,
} from './DefaultCatalogCollator';
import { setupServer } from 'msw/node';
import { rest } from 'msw';
import { ConfigReader } from '@backstage/config';
@@ -105,21 +108,35 @@ describe('DefaultCatalogCollator', () => {
});
it('allows filtering of the retrieved catalog entities', async () => {
const config = new ConfigReader({
catalog: {
search: {
allow: ['Foo', 'Bar'],
},
},
});
// Provide an alternate location template.
collator = DefaultCatalogCollator.fromConfig(config, {
collator = DefaultCatalogCollator.fromConfig(new ConfigReader({}), {
discovery: mockDiscoveryApi,
filter: {
kind: ['Foo', 'Bar'],
},
});
const documents = await collator.execute();
// The simulated 'Foo,Bar' filter should return in an empty list
expect(documents).toHaveLength(0);
});
it('can map filters to query strings', () => {
expect(
mapFilterToQueryString({
a: 'Foo',
}),
).toEqual('?filter=a=Foo');
expect(
mapFilterToQueryString({
a: ['Foo', 'Bar'],
}),
).toEqual('?filter=a=Foo,Bar');
expect(
mapFilterToQueryString({
a: ['Foo', 'Bar'],
b: ['Quu', 'Qux'],
}),
).toEqual('?filter=a=Foo,Bar,b=Quu,Qux');
});
});
@@ -19,6 +19,7 @@ import { Entity } from '@backstage/catalog-model';
import { IndexableDocument, DocumentCollator } from '@backstage/search-common';
import fetch from 'cross-fetch';
import { Config } from '@backstage/config';
import { CatalogEntitiesRequest } from '@backstage/catalog-client';
export interface CatalogEntityDocument extends IndexableDocument {
componentType: string;
@@ -31,36 +32,34 @@ export interface CatalogEntityDocument extends IndexableDocument {
export class DefaultCatalogCollator implements DocumentCollator {
protected discovery: PluginEndpointDiscovery;
protected locationTemplate: string;
protected filterUrl: string;
protected filterUrl?: string;
public readonly type: string = 'software-catalog';
static fromConfig(
config: Config,
options: { discovery: PluginEndpointDiscovery },
_config: Config,
options: {
discovery: PluginEndpointDiscovery;
filter?: CatalogEntitiesRequest['filter'];
},
) {
return new DefaultCatalogCollator({
...options,
allow: config.getOptionalStringArray('catalog.search.allow'),
});
}
constructor({
discovery,
locationTemplate,
allow,
filter,
}: {
discovery: PluginEndpointDiscovery;
locationTemplate?: string;
allow?: string[];
filter?: CatalogEntitiesRequest['filter'];
}) {
this.discovery = discovery;
this.locationTemplate =
locationTemplate || '/catalog/:namespace/:kind/:name';
if (allow && allow.length) {
this.filterUrl = `?filter=kind=${allow.join(',')}`;
} else {
this.filterUrl = '';
}
this.filterUrl = mapFilterToQueryString(filter);
}
protected applyArgsToFormat(
@@ -76,7 +75,7 @@ export class DefaultCatalogCollator implements DocumentCollator {
async execute() {
const baseUrl = await this.discovery.getBaseUrl('catalog');
const res = await fetch(`${baseUrl}/entities${this.filterUrl}`);
const res = await fetch(`${baseUrl}/entities${this.filterUrl || ''}`);
const entities: Entity[] = await res.json();
return entities.map((entity: Entity): CatalogEntityDocument => {
return {
@@ -96,3 +95,18 @@ export class DefaultCatalogCollator implements DocumentCollator {
});
}
}
export function mapFilterToQueryString(
filter: CatalogEntitiesRequest['filter'],
): string | undefined {
if (!filter) {
return undefined;
}
const mappedFilters = Object.entries(filter).map(kvp => {
const type = kvp[0];
const values = [].concat(kvp[1]);
return `${type}=${values.join(',')}`;
});
return `?filter=${mappedFilters.join(',')}`;
}
+1 -1
View File
@@ -14,4 +14,4 @@
* limitations under the License.
*/
export * from './DefaultCatalogCollator';
export { DefaultCatalogCollator } from './DefaultCatalogCollator';