Skip to content

Commit 2911107

Browse files
committed
implement review suggestions
1 parent 2bc5850 commit 2911107

3 files changed

Lines changed: 55 additions & 36 deletions

File tree

workspaces/extensions/plugins/catalog-backend-module-extensions/src/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ export const catalogModuleExtensions = createBackendModule({
7373
const catalogApi = new CatalogClient({ discoveryApi: discovery });
7474

7575
catalog.addEntityProvider(
76-
new ExtensionsPackageProvider(taskRunner, config),
76+
new ExtensionsPackageProvider(taskRunner, config, logger),
7777
);
7878
catalog.addEntityProvider(
79-
new ExtensionsPluginProvider(delayedTaskRunner, config),
79+
new ExtensionsPluginProvider(delayedTaskRunner, config, logger),
8080
);
8181
// Disabling the collection provider as collections/all.yaml is already commented in RHDH 1.5 image.
8282
// catalog.addEntityProvider(

workspaces/extensions/plugins/catalog-backend-module-extensions/src/providers/BaseEntityProvider.test.ts

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

1717
import { Entity } from '@backstage/catalog-model';
18-
import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api';
18+
import {
19+
LoggerService,
20+
SchedulerServiceTaskRunner,
21+
} from '@backstage/backend-plugin-api';
1922
import { BaseEntityProvider } from './BaseEntityProvider';
2023
import { JsonFileData } from '../types';
2124

@@ -32,6 +35,13 @@ class TestEntityProvider extends BaseEntityProvider<Entity> {
3235
const taskRunner: SchedulerServiceTaskRunner = {
3336
run: jest.fn(async ({ fn }) => fn(new AbortController().signal)),
3437
};
38+
const logger: LoggerService = {
39+
warn: jest.fn(),
40+
error: jest.fn(),
41+
info: jest.fn(),
42+
debug: jest.fn(),
43+
child: jest.fn(),
44+
};
3545

3646
const createEntity = (overrides?: Partial<Entity>): Entity => ({
3747
apiVersion: 'extensions.backstage.io/v1alpha1',
@@ -57,15 +67,15 @@ const createFileData = (
5767

5868
describe('BaseEntityProvider collision policy', () => {
5969
beforeEach(() => {
60-
jest.spyOn(console, 'warn').mockImplementation(() => undefined);
70+
jest.clearAllMocks();
6171
});
6272

6373
afterEach(() => {
6474
jest.restoreAllMocks();
6575
});
6676

6777
it('keeps first definition when duplicate entities are equivalent', () => {
68-
const provider = new TestEntityProvider(taskRunner);
78+
const provider = new TestEntityProvider(taskRunner, undefined, logger);
6979
const duplicate = createEntity();
7080

7181
const entities = provider.getEntities([
@@ -74,34 +84,37 @@ describe('BaseEntityProvider collision policy', () => {
7484
]);
7585

7686
expect(entities).toHaveLength(1);
77-
expect(console.warn).toHaveBeenCalledWith(
87+
expect(logger.warn).toHaveBeenCalledWith(
7888
expect.stringContaining(
79-
"Skipping duplicate Extensions entity 'plugin/default/duplicate-plugin'",
89+
"Skipping duplicate Extensions entity 'plugin:default/duplicate-plugin'",
8090
),
8191
);
8292
});
8393

84-
it('throws when duplicate entities have conflicting definitions', () => {
85-
const provider = new TestEntityProvider(taskRunner);
94+
it('warns and skips when duplicate entities have conflicting definitions', () => {
95+
const provider = new TestEntityProvider(taskRunner, undefined, logger);
8696
const firstEntity = createEntity({
8797
spec: { owner: 'owner-a' },
8898
});
8999
const secondEntity = createEntity({
90100
spec: { owner: 'owner-b' },
91101
});
92102

93-
expect(() =>
94-
provider.getEntities([
95-
createFileData('/extensions/primary/plugin.yaml', firstEntity),
96-
createFileData('/extensions/extra/community/plugin.yaml', secondEntity),
97-
]),
98-
).toThrow(
99-
"Conflicting Extensions entities detected for 'plugin/default/duplicate-plugin'",
103+
const entities = provider.getEntities([
104+
createFileData('/extensions/primary/plugin.yaml', firstEntity),
105+
createFileData('/extensions/extra/community/plugin.yaml', secondEntity),
106+
]);
107+
108+
expect(entities).toHaveLength(1);
109+
expect(logger.warn).toHaveBeenCalledWith(
110+
expect.stringContaining(
111+
"Conflicting Extensions entities detected for 'plugin:default/duplicate-plugin'",
112+
),
100113
);
101114
});
102115

103116
it('keeps entities with same name when namespaces differ', () => {
104-
const provider = new TestEntityProvider(taskRunner);
117+
const provider = new TestEntityProvider(taskRunner, undefined, logger);
105118
const defaultNamespaceEntity = createEntity({
106119
metadata: { name: 'shared-name' },
107120
});

workspaces/extensions/plugins/catalog-backend-module-extensions/src/providers/BaseEntityProvider.ts

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api';
16+
import {
17+
LoggerService,
18+
SchedulerServiceTaskRunner,
19+
} from '@backstage/backend-plugin-api';
1720
import {
1821
ANNOTATION_LOCATION,
1922
ANNOTATION_ORIGIN_LOCATION,
2023
Entity,
24+
stringifyEntityRef,
2125
} from '@backstage/catalog-model';
2226
import {
2327
EntityProvider,
@@ -39,27 +43,24 @@ export abstract class BaseEntityProvider<T extends Entity>
3943
private connection?: EntityProviderConnection;
4044
private taskRunner: SchedulerServiceTaskRunner;
4145
private config?: Config;
46+
private logger?: LoggerService;
4247

4348
private static readonly EXTENSIONS_DIRECTORY = '/extensions';
4449
private static readonly DEPRECATED_MARKETPLACE_DIRECTORY = '/marketplace';
4550

46-
constructor(taskRunner: SchedulerServiceTaskRunner, config?: Config) {
51+
constructor(
52+
taskRunner: SchedulerServiceTaskRunner,
53+
config?: Config,
54+
logger?: LoggerService,
55+
) {
4756
this.taskRunner = taskRunner;
4857
this.config = config;
58+
this.logger = logger;
4959
}
5060

5161
abstract getProviderName(): string;
5262
abstract getKind(): string;
5363

54-
private getEntityIdentity(entity: Entity): string {
55-
const namespace = entity.metadata.namespace ?? 'default';
56-
return [
57-
entity.kind.toLocaleLowerCase('en-US'),
58-
namespace.toLocaleLowerCase('en-US'),
59-
entity.metadata.name.toLocaleLowerCase('en-US'),
60-
].join('/');
61-
}
62-
6364
private addProviderAnnotations(entity: T): T {
6465
return {
6566
...entity,
@@ -79,7 +80,7 @@ export abstract class BaseEntityProvider<T extends Entity>
7980
return [];
8081
}
8182

82-
const entitiesByIdentity = new Map<
83+
const entitiesByEntityRef = new Map<
8384
string,
8485
{ entity: T; filePath: string }
8586
>();
@@ -89,29 +90,34 @@ export abstract class BaseEntityProvider<T extends Entity>
8990
continue;
9091
}
9192

92-
const identity = this.getEntityIdentity(fileData.content);
93-
const existing = entitiesByIdentity.get(identity);
93+
const identity = stringifyEntityRef({
94+
kind: fileData.content.kind,
95+
namespace: fileData.content.metadata.namespace ?? 'default',
96+
name: fileData.content.metadata.name,
97+
}).toLocaleLowerCase('en-US');
98+
const existing = entitiesByEntityRef.get(identity);
9499
if (!existing) {
95-
entitiesByIdentity.set(identity, {
100+
entitiesByEntityRef.set(identity, {
96101
entity: fileData.content,
97102
filePath: fileData.filePath,
98103
});
99104
continue;
100105
}
101106

102107
if (isDeepStrictEqual(existing.entity, fileData.content)) {
103-
console.warn(
108+
this.logger?.warn(
104109
`Skipping duplicate Extensions entity '${identity}' from '${fileData.filePath}'. Keeping first definition from '${existing.filePath}'.`,
105110
);
106111
continue;
107112
}
108113

109-
throw new Error(
110-
`Conflicting Extensions entities detected for '${identity}' in '${existing.filePath}' and '${fileData.filePath}'.`,
114+
this.logger?.warn(
115+
`Conflicting Extensions entities detected for '${identity}' in '${existing.filePath}' and '${fileData.filePath}'. Skipping conflicting definition from '${fileData.filePath}'.`,
111116
);
117+
continue;
112118
}
113119

114-
return Array.from(entitiesByIdentity.values()).map(({ entity }) =>
120+
return Array.from(entitiesByEntityRef.values()).map(({ entity }) =>
115121
this.addProviderAnnotations(entity),
116122
);
117123
}

0 commit comments

Comments
 (0)