Add defaultLocationConflictStrategy config option for catalog locations
Adds a catalog config option to set the default conflict strategy when registering locations, so adopters can default to 'refresh' instead of 'reject' without requiring each caller to specify it explicitly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Fredrik Adelöw <freben@spotify.com>
This commit is contained in:
@@ -3,4 +3,4 @@
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
Add an `onConflict` option to location creation, that enables it to perform refreshes instead of throwing conflict errors when there's a pre-existing location already
|
||||
Add an `onConflict` option to location creation that can refresh an existing location instead of throwing a conflict error.
|
||||
|
||||
Vendored
+9
@@ -191,6 +191,15 @@ export interface Config {
|
||||
stitchTimeout?: HumanDuration | string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The strategy to use when there is a conflict with a location being registered.
|
||||
*
|
||||
* The default value is "reject".
|
||||
*
|
||||
* The "refresh" strategy will refresh the existing location instead of throwing a conflict error.
|
||||
*/
|
||||
defaultLocationConflictStrategy?: 'refresh' | 'reject';
|
||||
|
||||
/**
|
||||
* The interval at which the catalog should process its entities.
|
||||
* @remarks
|
||||
|
||||
@@ -594,6 +594,10 @@ export class CatalogBuilder {
|
||||
const locationService = new AuthorizedLocationService(
|
||||
new DefaultLocationService(locationStore, orchestrator, {
|
||||
allowedLocationTypes: this.allowedLocationType,
|
||||
defaultLocationConflictStrategy:
|
||||
(config.getOptionalString(
|
||||
'catalog.defaultLocationConflictStrategy',
|
||||
) as 'refresh' | 'reject') || 'reject',
|
||||
}),
|
||||
permissionsService,
|
||||
);
|
||||
|
||||
@@ -282,6 +282,7 @@ describe('DefaultLocationServiceTest', () => {
|
||||
orchestrator,
|
||||
{
|
||||
allowedLocationTypes: ['url', 'unknown'],
|
||||
defaultLocationConflictStrategy: 'reject',
|
||||
},
|
||||
);
|
||||
await expect(
|
||||
|
||||
@@ -33,6 +33,7 @@ import { BackstageCredentials } from '@backstage/backend-plugin-api';
|
||||
|
||||
export type DefaultLocationServiceOptions = {
|
||||
allowedLocationTypes: string[];
|
||||
defaultLocationConflictStrategy: 'refresh' | 'reject';
|
||||
};
|
||||
|
||||
export class DefaultLocationService implements LocationService {
|
||||
@@ -45,6 +46,7 @@ export class DefaultLocationService implements LocationService {
|
||||
orchestrator: CatalogProcessingOrchestrator,
|
||||
options: DefaultLocationServiceOptions = {
|
||||
allowedLocationTypes: ['url'],
|
||||
defaultLocationConflictStrategy: 'reject',
|
||||
},
|
||||
) {
|
||||
this.store = store;
|
||||
@@ -71,7 +73,8 @@ export class DefaultLocationService implements LocationService {
|
||||
return this.dryRunCreateLocation(input);
|
||||
}
|
||||
const location = await this.store.createLocation(input, {
|
||||
onConflict: options?.onConflict,
|
||||
onConflict:
|
||||
options?.onConflict ?? this.options.defaultLocationConflictStrategy,
|
||||
});
|
||||
return { location, entities: [] };
|
||||
}
|
||||
|
||||
@@ -1685,7 +1685,10 @@ describe('POST /locations/by-query works end to end', () => {
|
||||
const locationService = new DefaultLocationService(
|
||||
store,
|
||||
{ process: jest.fn() },
|
||||
{ allowedLocationTypes: ['url'] },
|
||||
{
|
||||
allowedLocationTypes: ['url'],
|
||||
defaultLocationConflictStrategy: 'reject',
|
||||
},
|
||||
);
|
||||
|
||||
const router = await createRouter({
|
||||
|
||||
@@ -88,7 +88,7 @@ export interface LocationStore {
|
||||
createLocation(
|
||||
location: LocationInput,
|
||||
options?: {
|
||||
onConflict?: 'refresh' | 'reject';
|
||||
onConflict: 'refresh' | 'reject';
|
||||
},
|
||||
): Promise<Location>;
|
||||
listLocations(): Promise<Location[]>;
|
||||
|
||||
Reference in New Issue
Block a user