Skip to content

Commit e30701e

Browse files
debsmita1Zaperex
andauthored
feat(scaffolder): create custom action for scaffolder templates (#1567)
* feat(scaffolder): create custom action for adding timestamp to templates * create generic action for annotating objects * chore: fix lint issues and dynamic plugin exporting Signed-off-by: Frank Kong <[email protected]> --------- Signed-off-by: Frank Kong <[email protected]> Co-authored-by: Frank Kong <[email protected]>
1 parent 5f73fdd commit e30701e

26 files changed

+2264
-20
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Annotator custom action for Scaffolder Backstage
2+
3+
The annotator module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend).
4+
5+
This module enables users to generate custom actions for annotating their entity object(s).
6+
7+
## Getting started
8+
9+
### Installing on the new backend system
10+
11+
To install the module into the [new backend system](https://backstage.io/docs/backend-system/), add the following into the `packages/backend/src/index.ts` file:
12+
13+
```ts title="packages/backend/src/index.ts
14+
const backend = createBackend();
15+
16+
// highlight-add-start
17+
backend.add(
18+
import('@janus-idp/backstage-scaffolder-backend-module-annotator/alpha'),
19+
);
20+
// highlight-add-end
21+
22+
backend.start();
23+
```
24+
25+
### Installing on the legacy backend system
26+
27+
1. Install the Annotator custom action plugin using the following command:
28+
29+
```console
30+
yarn workspace backend add @janus-idp/backstage-scaffolder-backend-module-annotator
31+
```
32+
33+
2. Integrate the custom actions in the `scaffolder-backend` `createRouter` function:
34+
35+
- Install the `@backstage/integration` package using the following command:
36+
37+
```console
38+
yarn workspace backend add @backstage/integration
39+
```
40+
41+
- Add the `createTimestampAction` and `createScaffoldedFromAction` actions with the other built-in actions:
42+
43+
```ts title="packages/backend/src/plugins/scaffolder.ts"
44+
45+
import { CatalogClient } from '@backstage/catalog-client';
46+
/* highlight-add-start */
47+
import { ScmIntegrations } from '@backstage/integration';
48+
import {
49+
createBuiltinActions,
50+
createRouter,
51+
} from '@backstage/plugin-scaffolder-backend';
52+
import { createTimestampAction, createScaffoldedFromAction } from '@janus-idp/backstage-scaffolder-backend-module-annotator';
53+
/* highlight-add-end */
54+
...
55+
56+
export default async function createPlugin(
57+
const catalogClient = new CatalogClient({
58+
discoveryApi: env.discovery,
59+
});
60+
61+
/* highlight-add-start */
62+
const integrations = ScmIntegrations.fromConfig(env.config);
63+
64+
const builtInActions = createBuiltinActions({
65+
integrations: integrations as any,
66+
catalogClient,
67+
config: env.config,
68+
reader: env.reader,
69+
});
70+
const actions = [...builtInActions, createTimestampAction(), createScaffoldedFromAction()];
71+
/* highlight-add-end */
72+
73+
74+
return await createRouter({
75+
/* highlight-add-next-line */
76+
actions,
77+
logger: env.logger,
78+
...
79+
});
80+
```
81+
82+
3. To annotate the catalog-info.yaml skeleton with the current timestamp, add the **catalog:timestamping** custom action in your template yaml after the `Fetch Skeleton + Template` step:
83+
84+
```yaml title="template.yaml"
85+
steps:
86+
- id: template
87+
name: Fetch Skeleton + Template
88+
action: fetch:template
89+
...
90+
91+
# highlight-add-start
92+
- id: timestamp
93+
name: Add Timestamp to catalog-info.yaml
94+
action: catalog:timestamping
95+
# highlight-add-end
96+
```
97+
98+
4. To annotate the catalog-info.yaml skeleton with the template entityRef, add the **catalog:scaffolded-from** custom action in your template yaml after the `Fetch Skeleton + Template` step:
99+
100+
```yaml "title=template.yaml"
101+
steps:
102+
- id: template
103+
name: Fetch Skeleton + Template
104+
action: fetch:template
105+
...
106+
# highlight-add-start
107+
- id: append-templateRef
108+
name: Append the entityRef of this template to the entityRef
109+
action: catalog:scaffolded-from
110+
# highlight-add-end
111+
112+
```
113+
114+
## Usage
115+
116+
To use the `createAnnotatorAction` to create a custom action
117+
118+
| Parameter Name | Type | Required | Description |
119+
| ---------------------------------- | :------: | :------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
120+
| `actionId` | `string` | Yes | A unique id for the action |
121+
| `actionDescription` | `string` | Yes | A description of what the action accomplishes |
122+
| `loggerInfoMsg` | `string` | No | A message that will be logged upon the execution of the action |
123+
| `annotateEntityObject.labels` | `object` | No | Key-value pairs to be added to the `metadata.labels` of the entity |
124+
| `annotateEntityObject.annotations` | `object` | No | Key-value pairs to be added to the `metadata.annotations` of the entity |
125+
| `annotateEntityObject.spec` | `object` | No | Key-value pairs to be added to the `metadata.spec` of the entity. The value for each key can either be a string or an object with the key `readFromContext`, enabling users to specify the path in the context from which the value should be retrieved. |
126+
127+
The annotator action accepts the following inputs
128+
129+
#### Input
130+
131+
| Parameter Name | Type | Required | Description |
132+
| ---------------- | :------: | :------: | ----------------------------------------------------------------------------- |
133+
| `labels` | `object` | No | Key-value pairs to be added to the `metadata.labels` of the entity |
134+
| `annotations` | `object` | No | Key-value pairs to be added to the `metadata.annotations` of the entity |
135+
| `entityFilePath` | `string` | No | The file path from which the YAML representation of the entity should be read |
136+
| `objectYaml` | `object` | No | The YAML representation of the object/entity |
137+
| `writeToFile` | `string` | No | The file path where the YAML representation of the entity should be stored |
138+
139+
#### Output
140+
141+
| Name | Type | Description |
142+
| ----------------- | :------: | -------------------------------------------------------------------------------------------- |
143+
| `annotatedObject` | `object` | The entity object marked with your specified annotation(s), label(s), and spec property(ies) |
144+
145+
Here are the custom actions currently available:
146+
147+
| Action | Description |
148+
| ------------------------- | :-------------------------------------------: |
149+
| `catalog:timestamping` | Adds current timestamp to your entity object |
150+
| `catalog:scaffolded-from` | Adds template entityRef to your entity object |
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"name": "@janus-idp/backstage-scaffolder-backend-module-annotator-dynamic",
3+
"description": "The annotator module for @backstage/plugin-scaffolder-backend",
4+
"version": "0.1.0",
5+
"main": "dist/index.cjs.js",
6+
"types": "dist/index.d.ts",
7+
"license": "Apache-2.0",
8+
"publishConfig": {
9+
"access": "public",
10+
"main": "dist/index.cjs.js",
11+
"types": "dist/index.d.ts"
12+
},
13+
"backstage": {
14+
"role": "backend-plugin-module"
15+
},
16+
"exports": {
17+
".": {
18+
"require": "./dist/index.cjs.js",
19+
"default": "./dist/index.cjs.js"
20+
},
21+
"./alpha": {
22+
"require": "./dist/alpha.cjs.js",
23+
"default": "./dist/alpha.cjs.js"
24+
},
25+
"./package.json": "./package.json"
26+
},
27+
"scripts": {},
28+
"dependencies": {
29+
"fs-extra": "^11.2.0",
30+
"lodash": "^4.17.21",
31+
"yaml": "^2.0.0"
32+
},
33+
"devDependencies": {},
34+
"files": [
35+
"dist",
36+
"config.d.ts",
37+
"app-config.janus-idp.yaml",
38+
"alpha"
39+
],
40+
"repository": "github:janus-idp/backstage-plugins",
41+
"keywords": [
42+
"backstage",
43+
"plugin"
44+
],
45+
"homepage": "https://janus-idp.io/",
46+
"bugs": "https://github.com/janus-idp/backstage-plugins/issues",
47+
"bundleDependencies": true,
48+
"peerDependencies": {
49+
"@backstage/backend-common": "^0.21.6",
50+
"@backstage/backend-dynamic-feature-service": "^0.2.9",
51+
"@backstage/backend-plugin-api": "^0.6.17",
52+
"@backstage/catalog-model": "^1.4.5",
53+
"@backstage/plugin-scaffolder-node": "^0.4.2"
54+
},
55+
"overrides": {
56+
"@aws-sdk/util-utf8-browser": {
57+
"@smithy/util-utf8": "^2.0.0"
58+
}
59+
},
60+
"resolutions": {
61+
"@aws-sdk/util-utf8-browser": "npm:@smithy/util-utf8@~2"
62+
}
63+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
"@aws-sdk/util-utf8-browser@npm:@smithy/util-utf8@~2":
6+
version "2.3.0"
7+
resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz#dd96d7640363259924a214313c3cf16e7dd329c5"
8+
integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==
9+
dependencies:
10+
"@smithy/util-buffer-from" "^2.2.0"
11+
tslib "^2.6.2"
12+
13+
"@smithy/is-array-buffer@^2.2.0":
14+
version "2.2.0"
15+
resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz#f84f0d9f9a36601a9ca9381688bd1b726fd39111"
16+
integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==
17+
dependencies:
18+
tslib "^2.6.2"
19+
20+
"@smithy/util-buffer-from@^2.2.0":
21+
version "2.2.0"
22+
resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz#6fc88585165ec73f8681d426d96de5d402021e4b"
23+
integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==
24+
dependencies:
25+
"@smithy/is-array-buffer" "^2.2.0"
26+
tslib "^2.6.2"
27+
28+
fs-extra@^11.2.0:
29+
version "11.2.0"
30+
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
31+
integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
32+
dependencies:
33+
graceful-fs "^4.2.0"
34+
jsonfile "^6.0.1"
35+
universalify "^2.0.0"
36+
37+
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
38+
version "4.2.11"
39+
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
40+
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
41+
42+
jsonfile@^6.0.1:
43+
version "6.1.0"
44+
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
45+
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
46+
dependencies:
47+
universalify "^2.0.0"
48+
optionalDependencies:
49+
graceful-fs "^4.1.6"
50+
51+
lodash@^4.17.21:
52+
version "4.17.21"
53+
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
54+
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
55+
56+
tslib@^2.6.2:
57+
version "2.6.2"
58+
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
59+
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
60+
61+
universalify@^2.0.0:
62+
version "2.0.1"
63+
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
64+
integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
65+
66+
yaml@^2.0.0:
67+
version "2.4.2"
68+
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.2.tgz#7a2b30f2243a5fc299e1f14ca58d475ed4bc5362"
69+
integrity sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
apiVersion: scaffolder.backstage.io/v1beta3
2+
kind: Template
3+
metadata:
4+
name: create-react-app-template-with-timestamp-entityRef
5+
title: Create React App Template
6+
description: Create a new CRA website project
7+
tags:
8+
- react
9+
- cra
10+
spec:
11+
12+
type: website
13+
parameters:
14+
- title: Provide some simple information
15+
required:
16+
- component_id
17+
- owner
18+
properties:
19+
component_id:
20+
title: Name
21+
type: string
22+
description: Unique name of the component
23+
ui:field: EntityNamePicker
24+
description:
25+
title: Description
26+
type: string
27+
description: Help others understand what this website is for.
28+
owner:
29+
title: Owner
30+
type: string
31+
description: Owner of the component
32+
ui:field: OwnerPicker
33+
ui:options:
34+
allowedKinds:
35+
- Group
36+
- title: Choose a location
37+
required:
38+
- repoUrl
39+
properties:
40+
repoUrl:
41+
title: Repository Location
42+
type: string
43+
ui:field: RepoUrlPicker
44+
ui:options:
45+
allowedHosts:
46+
- github.com
47+
steps:
48+
- id: template
49+
name: Fetch Skeleton + Template
50+
action: fetch:template
51+
input:
52+
url: https://github.com/backstage/software-templates/tree/main/scaffolder-templates/create-react-app/skeleton
53+
copyWithoutRender:
54+
- .github/workflows/*
55+
values:
56+
component_id: ${{ parameters.component_id }}
57+
description: ${{ parameters.description }}
58+
destination: ${{ parameters.repoUrl | parseRepoUrl }}
59+
owner: ${{ parameters.owner }}
60+
61+
- id: timestamp
62+
name: Add Timestamp to catalog-info.yaml
63+
action: catalog:timestamping
64+
65+
- id: append-templateRef
66+
name: Append the entityRef of this template to the entityRef
67+
action: catalog:scaffolded-from
68+
69+
- id: publish
70+
name: Publish
71+
action: publish:github
72+
input:
73+
allowedHosts:
74+
- github.com
75+
description: This is ${{ parameters.component_id }}
76+
repoUrl: ${{ parameters.repoUrl }}
77+
78+
- id: register
79+
name: Register
80+
action: catalog:register
81+
input:
82+
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
83+
catalogInfoPath: '/catalog-info.yaml'
84+
85+
output:
86+
links:
87+
- title: Repository
88+
url: ${{ steps.publish.output.remoteUrl }}
89+
- title: Open in catalog
90+
icon: catalog
91+
entityRef: ${{ steps.register.output.entityRef }}

0 commit comments

Comments
 (0)