Moved ScaffolderEntitiesProcessor and catalogModuleTemplateKind to a dedicated module

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Camila Belo <camilaibs@gmail.com>
Co-authored-by: Philipp Hugenroth <philipph@spotify.com>
Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
Co-authored-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Fredrik Adelöw
2023-09-11 14:44:38 +02:00
parent cef192ebe3
commit d5313ede35
23 changed files with 153 additions and 32 deletions
@@ -15,9 +15,6 @@ import { ResourcePermission } from '@backstage/plugin-permission-common';
import { TemplateEntityStepV1beta3 } from '@backstage/plugin-scaffolder-common';
import { TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common';
// @alpha
export const catalogModuleTemplateKind: () => BackendFeature;
// @alpha (undocumented)
export const createScaffolderActionConditionalDecision: (
permission: ResourcePermission<'scaffolder-action'>,
+3 -17
View File
@@ -5,12 +5,9 @@
```ts
import { ActionContext as ActionContext_2 } from '@backstage/plugin-scaffolder-node';
import { CatalogApi } from '@backstage/catalog-client';
import { CatalogProcessor } from '@backstage/plugin-catalog-node';
import { CatalogProcessorEmit } from '@backstage/plugin-catalog-node';
import { Config } from '@backstage/config';
import { createPullRequest } from 'octokit-plugin-create-pull-request';
import { Duration } from 'luxon';
import { Entity } from '@backstage/catalog-model';
import { executeShellCommand as executeShellCommand_2 } from '@backstage/plugin-scaffolder-node';
import { ExecuteShellCommandOptions } from '@backstage/plugin-scaffolder-node';
import express from 'express';
@@ -20,7 +17,6 @@ import { HumanDuration } from '@backstage/types';
import { IdentityApi } from '@backstage/plugin-auth-node';
import { JsonObject } from '@backstage/types';
import { Knex } from 'knex';
import { LocationSpec } from '@backstage/plugin-catalog-common';
import { Logger } from 'winston';
import { Octokit } from 'octokit';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
@@ -30,6 +26,7 @@ import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginTaskScheduler } from '@backstage/backend-tasks';
import { RESOURCE_TYPE_SCAFFOLDER_ACTION } from '@backstage/plugin-scaffolder-common/alpha';
import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE } from '@backstage/plugin-scaffolder-common/alpha';
import { ScaffolderEntitiesProcessor as ScaffolderEntitiesProcessor_2 } from '@backstage/plugin-catalog-backend-module-scaffolder-entities';
import { Schema } from 'jsonschema';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { ScmIntegrations } from '@backstage/integration';
@@ -881,19 +878,8 @@ export interface RouterOptions {
// @public @deprecated
export type RunCommandOptions = ExecuteShellCommandOptions;
// @public (undocumented)
export class ScaffolderEntitiesProcessor implements CatalogProcessor {
// (undocumented)
getProcessorName(): string;
// (undocumented)
postProcessEntity(
entity: Entity,
_location: LocationSpec,
emit: CatalogProcessorEmit,
): Promise<Entity>;
// (undocumented)
validateEntityKind(entity: Entity): Promise<boolean>;
}
// @public @deprecated
export const ScaffolderEntitiesProcessor: typeof ScaffolderEntitiesProcessor_2;
// @public @deprecated
export type SerializedTask = SerializedTask_2;
+1
View File
@@ -56,6 +56,7 @@
"@backstage/integration": "workspace:^",
"@backstage/plugin-auth-node": "workspace:^",
"@backstage/plugin-catalog-backend": "workspace:^",
"@backstage/plugin-catalog-backend-module-scaffolder-entities": "workspace:^",
"@backstage/plugin-catalog-common": "workspace:^",
"@backstage/plugin-catalog-node": "workspace:^",
"@backstage/plugin-permission-common": "workspace:^",
-1
View File
@@ -14,6 +14,5 @@
* limitations under the License.
*/
export * from './modules';
export * from './service';
export { scaffolderPlugin as default } from './ScaffolderPlugin';
@@ -24,6 +24,7 @@ import {
fetchContents as fetchContentsNode,
} from '@backstage/plugin-scaffolder-node';
import { JsonObject } from '@backstage/types';
import { ScaffolderEntitiesProcessor as ScaffolderEntitiesProcessorModule } from '@backstage/plugin-catalog-backend-module-scaffolder-entities';
/**
* @public
@@ -75,3 +76,11 @@ export const executeShellCommand = executeShellCommandNode;
* @deprecated Use `fetchContents` from `@backstage/plugin-scaffolder-node` instead
*/
export const fetchContents = fetchContentsNode;
/**
* Adds support for scaffolder specific entity kinds to the catalog.
*
* @public
* @deprecated Import from `@backstage/plugin-catalog-backend-module-scaffolder-entities` instead
*/
export const ScaffolderEntitiesProcessor = ScaffolderEntitiesProcessorModule;
-1
View File
@@ -23,6 +23,5 @@
export * from './scaffolder';
export * from './service/router';
export * from './lib';
export * from './processor';
export * from './deprecated';
@@ -1,34 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { ScaffolderEntitiesProcessor } from '../processor';
import { catalogModuleTemplateKind } from './catalogModuleTemplateKind';
import { startTestBackend } from '@backstage/backend-test-utils';
describe('catalogModuleTemplateKind', () => {
it('should register the extension point', async () => {
const extensionPoint = { addProcessor: jest.fn() };
await startTestBackend({
extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]],
features: [catalogModuleTemplateKind()],
});
expect(extensionPoint.addProcessor).toHaveBeenCalledWith(
new ScaffolderEntitiesProcessor(),
);
});
});
@@ -1,39 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createBackendModule } from '@backstage/backend-plugin-api';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { ScaffolderEntitiesProcessor } from '../processor';
/**
* Registers support for the Template kind to the catalog backend plugin.
*
* @alpha
*/
export const catalogModuleTemplateKind = createBackendModule({
moduleId: 'templateKind',
pluginId: 'catalog',
register(env) {
env.registerInit({
deps: {
catalog: catalogProcessingExtensionPoint,
},
async init({ catalog }) {
catalog.addProcessor(new ScaffolderEntitiesProcessor());
},
});
},
});
@@ -1,17 +0,0 @@
/*
* Copyright 2022 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { catalogModuleTemplateKind } from './catalogModuleTemplateKind';
@@ -1,80 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import { ScaffolderEntitiesProcessor } from './ScaffolderEntitiesProcessor';
const mockLocation = { type: 'a', target: 'b' };
const mockEntity: TemplateEntityV1beta3 = {
apiVersion: 'scaffolder.backstage.io/v1beta3',
kind: 'Template',
metadata: { name: 'n' },
spec: {
parameters: {},
steps: [],
type: 'service',
owner: 'o',
},
};
describe('ScaffolderEntitiesProcessor', () => {
describe('validateEntityKind', () => {
it('validates the entity kind', async () => {
const processor = new ScaffolderEntitiesProcessor();
await expect(processor.validateEntityKind(mockEntity)).resolves.toBe(
true,
);
await expect(
processor.validateEntityKind({
...mockEntity,
apiVersion: 'backstage.io/v1beta3',
}),
).resolves.toBe(false);
await expect(
processor.validateEntityKind({ ...mockEntity, kind: 'Component' }),
).resolves.toBe(false);
});
});
describe('postProcessEntity', () => {
it('generates relations for component entities', async () => {
const processor = new ScaffolderEntitiesProcessor();
const emit = jest.fn();
await processor.postProcessEntity(mockEntity, mockLocation, emit);
expect(emit).toHaveBeenCalledTimes(2);
expect(emit).toHaveBeenCalledWith({
type: 'relation',
relation: {
source: { kind: 'Group', namespace: 'default', name: 'o' },
type: 'ownerOf',
target: { kind: 'Template', namespace: 'default', name: 'n' },
},
});
expect(emit).toHaveBeenCalledWith({
type: 'relation',
relation: {
source: { kind: 'Template', namespace: 'default', name: 'n' },
type: 'ownedBy',
target: { kind: 'Group', namespace: 'default', name: 'o' },
},
});
});
});
});
@@ -1,99 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
Entity,
getCompoundEntityRef,
parseEntityRef,
RELATION_OWNED_BY,
RELATION_OWNER_OF,
} from '@backstage/catalog-model';
import {
CatalogProcessor,
CatalogProcessorEmit,
processingResult,
} from '@backstage/plugin-catalog-node';
import { LocationSpec } from '@backstage/plugin-catalog-common';
import {
TemplateEntityV1beta3,
templateEntityV1beta3Validator,
} from '@backstage/plugin-scaffolder-common';
/** @public */
export class ScaffolderEntitiesProcessor implements CatalogProcessor {
getProcessorName(): string {
return 'ScaffolderEntitiesProcessor';
}
private readonly validators = [templateEntityV1beta3Validator];
async validateEntityKind(entity: Entity): Promise<boolean> {
for (const validator of this.validators) {
if (await validator.check(entity)) {
return true;
}
}
return false;
}
async postProcessEntity(
entity: Entity,
_location: LocationSpec,
emit: CatalogProcessorEmit,
): Promise<Entity> {
const selfRef = getCompoundEntityRef(entity);
if (
entity.apiVersion === 'scaffolder.backstage.io/v1beta3' &&
entity.kind === 'Template'
) {
const template = entity as TemplateEntityV1beta3;
const target = template.spec.owner;
if (target) {
const targetRef = parseEntityRef(target, {
defaultKind: 'Group',
defaultNamespace: selfRef.namespace,
});
emit(
processingResult.relation({
source: selfRef,
type: RELATION_OWNED_BY,
target: {
kind: targetRef.kind,
namespace: targetRef.namespace,
name: targetRef.name,
},
}),
);
emit(
processingResult.relation({
source: {
kind: targetRef.kind,
namespace: targetRef.namespace,
name: targetRef.name,
},
type: RELATION_OWNER_OF,
target: selfRef,
}),
);
}
}
return entity;
}
}
@@ -1,17 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { ScaffolderEntitiesProcessor } from './ScaffolderEntitiesProcessor';