Skip to content

Commit

Permalink
feat: add custom processor module to add ScaffoldedFrom relation (jan…
Browse files Browse the repository at this point in the history
…us-idp#1591)

* feat: add custom processor module to add ScaffoldedFrom relation

Signed-off-by: Frank Kong <frkong@redhat.com>

* chore: add dynamic plugins support

Signed-off-by: Frank Kong <frkong@redhat.com>

* chore: add legacy backend support

* chore: update the tsconfig.json

Signed-off-by: Frank Kong <frkong@redhat.com>

* chore: update turbo.json with the proper tsc output path

Signed-off-by: Frank Kong <frkong@redhat.com>

* chore: update yarn.lock

Signed-off-by: Frank Kong <frkong@redhat.com>

* chore: update yarn.lock

Signed-off-by: Frank Kong <frkong@redhat.com>

* chore: update yarn.lock

Signed-off-by: Frank Kong <frkong@redhat.com>

* docs: add usage instructions

Signed-off-by: Frank Kong <frkong@redhat.com>

---------

Signed-off-by: Frank Kong <frkong@redhat.com>
  • Loading branch information
Zaperex committed May 22, 2024
1 parent 44173fc commit 0b36164
Show file tree
Hide file tree
Showing 22 changed files with 2,147 additions and 2,404 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Catalog Backend Module for Scaffolder Relation Catalog Processor

This is an extension module to the catalog-backend plugin, providing an additional catalog entity processor that adds a new relation that depends on the `spec.scaffoldedFrom` field to link scaffolder templates and the catalog entities they generated.

## Getting Started

1. Install the scaffolder relation catalog processor module using the following command:

```console
yarn workspace backend add @janus-idp/backstage-plugin-catalog-backend-module-scaffolder-relation-processor
```

### Installing on the new backend system

To install this module into the [new backend system](https://backstage.io/docs/backend-system/), add the following into the `packages/backend/src/index.ts` file:

```ts title="packages/backend/src/index.ts
const backend = createBackend();

// highlight-add-start
backend.add(
import(
'@janus-idp/backstage-plugin-catalog-backend-module-scaffolder-relation-processor/alpha'
),
);
// highlight-add-end

backend.start();
```

### Installing on the legacy backend system

To install this module into the legacy backend system, add the following to the `packages/backend/src/plugins/catalog.ts` file:

```ts title=packages/backend/src/plugins/catalog.ts
// highlight-add-start
import { ScaffolderRelationEntityProcessor } from '@janus-idp/backstage-plugin-catalog-backend-module-scaffolder-relation-processor';

// highlight-add-end

export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const builder = await CatalogBuilder.create(env);

/* ... other processors and/or providers ... */
// highlight-add-start
builder.addProcessor(new ScaffolderRelationEntityProcessor());
// highlight-add-end

const { processingEngine, router } = await builder.build();
await processingEngine.start();

return router;
}
```

### Usage

Catalog entities containing the `spec.scaffoldedFrom` field will have a relation link be formed between it and the `template` corresponding to the entity ref in the `spec.scaffoldedFrom` field.

This link can be viewed in the `relations` field of the Raw YAML view of a catalog entity when inspecting an entity. In the entity with the `spec.scaffoldedFrom` field, the relation type is `scaffoldedFrom` with a target pointing to the value of the `spec.scaffoldedFrom` field. Conversely, for the target template, it will have a relation type of `ScaffolderOf` with a target pointing to the entity with the `spec.scaffoldedFrom` field.

These relations should also appear on the `EntityCatalogGraphView` component from the `@backstage/plugin-catalog-graph` package (only if the entity corresponding to the entity ref exists in the catalog).

#### Example graph view

![scaffoldedFrom Relation Graph View](./docs/example-images/scaffoldedFromGraphView.png)
![scaffolderOf Relation Graph View](./docs/example-images/scaffolderOfGraphView.png)

#### Example Raw YAML view

![scaffoldedFrom Relation YAML View](./docs/example-images/scaffoldedFromYAMLView.png)
![scaffoldedOf Relation YAML View](./docs/example-images/scaffolderOfYAMLView.png)
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export interface Config {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "@janus-idp/backstage-plugin-catalog-backend-module-scaffolder-relation-processor-dynamic",
"description": "The scaffolder-relation-processor backend module for the catalog plugin.",
"version": "0.1.0",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "backend-plugin-module"
},
"exports": {
".": {
"require": "./dist/index.cjs.js",
"default": "./dist/index.cjs.js"
},
"./alpha": {
"require": "./dist/alpha.cjs.js",
"default": "./dist/alpha.cjs.js"
},
"./package.json": "./package.json"
},
"scripts": {},
"dependencies": {},
"devDependencies": {},
"files": [
"dist",
"config.d.ts",
"app-config.janus-idp.yaml",
"alpha"
],
"configSchema": "config.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/janus-idp/backstage-plugins",
"directory": "plugins/catalog"
},
"keywords": [
"backstage",
"plugin"
],
"homepage": "https://janus-idp.io/",
"bugs": "https://github.com/janus-idp/backstage-plugins/issues",
"bundleDependencies": true,
"peerDependencies": {
"@backstage/backend-common": "^0.21.6",
"@backstage/backend-dynamic-feature-service": "^0.2.8",
"@backstage/backend-plugin-api": "^0.6.16",
"@backstage/catalog-model": "^1.4.5",
"@backstage/plugin-catalog-common": "^1.0.22",
"@backstage/plugin-catalog-node": "^1.11.1"
},
"overrides": {
"@aws-sdk/util-utf8-browser": {
"@smithy/util-utf8": "^2.0.0"
}
},
"resolutions": {
"@aws-sdk/util-utf8-browser": "npm:@smithy/util-utf8@~2"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@aws-sdk/util-utf8-browser@npm:@smithy/util-utf8@~2":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz#dd96d7640363259924a214313c3cf16e7dd329c5"
integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==
dependencies:
"@smithy/util-buffer-from" "^2.2.0"
tslib "^2.6.2"

"@smithy/is-array-buffer@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz#f84f0d9f9a36601a9ca9381688bd1b726fd39111"
integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==
dependencies:
tslib "^2.6.2"

"@smithy/util-buffer-from@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz#6fc88585165ec73f8681d426d96de5d402021e4b"
integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==
dependencies:
"@smithy/is-array-buffer" "^2.2.0"
tslib "^2.6.2"

tslib@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"name": "@janus-idp/backstage-plugin-catalog-backend-module-scaffolder-relation-processor",
"description": "The scaffolder-relation-processor backend module for the catalog plugin.",
"version": "0.1.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "backend-plugin-module"
},
"exports": {
".": "./src/index.ts",
"./alpha": "./src/alpha.ts",
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"alpha": [
"src/alpha.ts"
],
"package.json": [
"package.json"
]
}
},
"scripts": {
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"export-dynamic": "janus-cli package export-dynamic-plugin",
"lint": "backstage-cli package lint",
"postpack": "backstage-cli package postpack",
"postversion": "yarn run export-dynamic",
"prepack": "backstage-cli package prepack",
"start": "backstage-cli package start",
"test": "backstage-cli package test --passWithNoTests --coverage",
"tsc": "tsc"
},
"dependencies": {
"@backstage/backend-common": "^0.21.6",
"@backstage/backend-dynamic-feature-service": "^0.2.8",
"@backstage/backend-plugin-api": "^0.6.16",
"@backstage/catalog-model": "^1.4.5",
"@backstage/plugin-catalog-common": "^1.0.22",
"@backstage/plugin-catalog-node": "^1.11.1"
},
"devDependencies": {
"@backstage/backend-test-utils": "0.3.6",
"@backstage/cli": "0.26.2",
"@janus-idp/cli": "1.8.2"
},
"files": [
"dist",
"config.d.ts",
"dist-dynamic/*.*",
"dist-dynamic/dist/**",
"dist-dynamic/alpha/*",
"app-config.janus-idp.yaml"
],
"configSchema": "config.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/janus-idp/backstage-plugins",
"directory": "plugins/catalog"
},
"keywords": [
"backstage",
"plugin"
],
"homepage": "https://janus-idp.io/",
"bugs": "https://github.com/janus-idp/backstage-plugins/issues"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Entity } from '@backstage/catalog-model';

import { ScaffolderRelationEntityProcessor } from './ScaffolderRelationEntityProcessor';

describe('ScaffolderRelationEntityProcessor', () => {
describe('postProcessEntity', () => {
const processor = new ScaffolderRelationEntityProcessor();
const location = { type: 'url', target: 'test-url' };
const emit = jest.fn();

afterEach(() => jest.resetAllMocks());

it('generates relations for any arbitrary entity', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: { name: 'test-entity' },
spec: {
scaffoldedFrom: 'test-template',
},
};

await processor.postProcessEntity(entity, location, emit);
expect(emit).toHaveBeenCalledTimes(2);
expect(emit).toHaveBeenCalledWith({
type: 'relation',
relation: {
source: {
kind: 'Template',
namespace: 'default',
name: 'test-template',
},
type: 'scaffolderOf',
target: {
kind: 'Component',
namespace: 'default',
name: 'test-entity',
},
},
});
expect(emit).toHaveBeenCalledWith({
type: 'relation',
relation: {
source: {
kind: 'Component',
namespace: 'default',
name: 'test-entity',
},
type: 'scaffoldedFrom',
target: {
kind: 'Template',
namespace: 'default',
name: 'test-template',
},
},
});
});
it('generates no relations if the `spec.scaffoldedFrom` field is empty or does not exist', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: { name: 'n' },
spec: {
type: 'service',
},
};
await processor.postProcessEntity(entity, location, emit);
expect(emit).toHaveBeenCalledTimes(0);

const entity2: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: { name: 'n' },
spec: {
scaffoldedFrom: '',
},
};
await processor.postProcessEntity(entity2, location, emit);
expect(emit).toHaveBeenCalledTimes(0);
});
});
});
Loading

0 comments on commit 0b36164

Please sign in to comment.