|
|
|
@@ -19,9 +19,11 @@ array when registering your custom actions, as seen below.
|
|
|
|
|
|
|
|
|
|
## Streamlining Custom Action Creation with Backstage CLI
|
|
|
|
|
|
|
|
|
|
The creation of custom actions in Backstage has never been easier thanks to the Backstage CLI. This tool streamlines the setup process, allowing you to focus on your actions' unique functionality.
|
|
|
|
|
The creation of custom actions in Backstage has never been easier thanks to the Backstage CLI. This tool streamlines the
|
|
|
|
|
setup process, allowing you to focus on your actions' unique functionality.
|
|
|
|
|
|
|
|
|
|
Start by using the `yarn backstage-cli new` command to generate a scaffolder module. This command sets up the necessary boilerplate code, providing a smooth start:
|
|
|
|
|
Start by using the `yarn backstage-cli new` command to generate a scaffolder module. This command sets up the necessary
|
|
|
|
|
boilerplate code, providing a smooth start:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
$ yarn backstage-cli new
|
|
|
|
@@ -34,13 +36,19 @@ $ yarn backstage-cli new
|
|
|
|
|
|
|
|
|
|
You can find a [list](../../tooling/cli/03-commands.md) of all commands provided by the Backstage CLI.
|
|
|
|
|
|
|
|
|
|
When prompted, select the option to generate a scaffolder module. This creates a solid foundation for your custom action. Enter the name of the module you wish to create, and the CLI will generate the required files and directory structure.
|
|
|
|
|
When prompted, select the option to generate a scaffolder module. This creates a solid foundation for your custom
|
|
|
|
|
action. Enter the name of the module you wish to create, and the CLI will generate the required files and directory
|
|
|
|
|
structure.
|
|
|
|
|
|
|
|
|
|
## Writing your Custom Action
|
|
|
|
|
|
|
|
|
|
After running the command, the CLI will create a new directory with your new scaffolder module. This directory will be the working directory for creating the custom action. It will contain all the necessary files and boilerplate code to get started.
|
|
|
|
|
After running the command, the CLI will create a new directory with your new scaffolder module. This directory will be
|
|
|
|
|
the working directory for creating the custom action. It will contain all the necessary files and boilerplate code to
|
|
|
|
|
get started.
|
|
|
|
|
|
|
|
|
|
Let's create a simple action that adds a new file and some contents that are passed as `input` to the function. Within the generated directory, locate the file at `src/actions/example/example.ts`. Feel free to rename this file along with its generated unit test. We will replace the existing placeholder code with our custom action code as follows:
|
|
|
|
|
Let's create a simple action that adds a new file and some contents that are passed as `input` to the function. Within
|
|
|
|
|
the generated directory, locate the file at `src/actions/example/example.ts`. Feel free to rename this file along with
|
|
|
|
|
its generated unit test. We will replace the existing placeholder code with our custom action code as follows:
|
|
|
|
|
|
|
|
|
|
```ts title="With Zod"
|
|
|
|
|
import { resolveSafeChildPath } from '@backstage/backend-plugin-api';
|
|
|
|
@@ -82,7 +90,8 @@ The `createTemplateAction` takes an object which specifies the following:
|
|
|
|
|
- `id` - A unique ID for your custom action. We encourage you to namespace these
|
|
|
|
|
in some way so that they won't collide with future built-in actions that we
|
|
|
|
|
may ship with the `scaffolder-backend` plugin.
|
|
|
|
|
- `description` - An optional field to describe the purpose of the action. This will populate in the `/create/actions` endpoint.
|
|
|
|
|
- `description` - An optional field to describe the purpose of the action. This will populate in the `/create/actions`
|
|
|
|
|
endpoint.
|
|
|
|
|
- `schema.input` - A `zod` or JSON schema object for input values to your function
|
|
|
|
|
- `schema.output` - A `zod` or JSON schema object for values which are output from the
|
|
|
|
|
function using `ctx.output`
|
|
|
|
@@ -132,18 +141,24 @@ export const createNewFileAction = () => {
|
|
|
|
|
|
|
|
|
|
### Naming Conventions
|
|
|
|
|
|
|
|
|
|
Try to keep names consistent for both your own custom actions, and any actions contributed to open source. We've found that a separation of `:` and using a verb as the last part of the name works well.
|
|
|
|
|
We follow `provider:entity:verb` or as close to this as possible for our built in actions. For example, `github:actions:create` or `github:repo:create`.
|
|
|
|
|
Try to keep names consistent for both your own custom actions, and any actions contributed to open source. We've found
|
|
|
|
|
that a separation of `:` and using a verb as the last part of the name works well.
|
|
|
|
|
We follow `provider:entity:verb` or as close to this as possible for our built in actions. For example,
|
|
|
|
|
`github:actions:create` or `github:repo:create`.
|
|
|
|
|
|
|
|
|
|
Also feel free to use your company name to namespace them if you prefer too, for example `acme:file:create` like above.
|
|
|
|
|
|
|
|
|
|
Prefer to use `camelCase` over `snake_case` or `kebab-case` for these actions if possible, which leads to better reading and writing of template entity definitions.
|
|
|
|
|
Prefer to use `camelCase` over `snake_case` or `kebab-case` for these actions if possible, which leads to better reading
|
|
|
|
|
and writing of template entity definitions.
|
|
|
|
|
|
|
|
|
|
> We're aware that there are some exceptions to this, but try to follow as close as possible. We'll be working on migrating these in the repository over time too.
|
|
|
|
|
> We're aware that there are some exceptions to this, but try to follow as close as possible. We'll be working on
|
|
|
|
|
> migrating these in the repository over time too.
|
|
|
|
|
|
|
|
|
|
### Adding a TemplateExample
|
|
|
|
|
|
|
|
|
|
A TemplateExample is a predefined structure that can be used to create custom actions in your software templates. It serves as a blueprint for users to understand how to use a specific action and its fields as well as to ensure consistency and standardization across different custom actions.
|
|
|
|
|
A TemplateExample is a predefined structure that can be used to create custom actions in your software templates. It
|
|
|
|
|
serves as a blueprint for users to understand how to use a specific action and its fields as well as to ensure
|
|
|
|
|
consistency and standardization across different custom actions.
|
|
|
|
|
|
|
|
|
|
#### Define a TemplateExample and add to your Custom Action
|
|
|
|
|
|
|
|
|
@@ -199,7 +214,8 @@ argument. It looks like the following:
|
|
|
|
|
|
|
|
|
|
## Registering Custom Actions
|
|
|
|
|
|
|
|
|
|
To register your new custom action in the Backend System you will need to create a backend module. Here is a very simplified example of how to do that:
|
|
|
|
|
To register your new custom action in the Backend System you will need to create a backend module. Here is a very
|
|
|
|
|
simplified example of how to do that:
|
|
|
|
|
|
|
|
|
|
```ts title="packages/backend/src/index.ts"
|
|
|
|
|
/* highlight-add-start */
|
|
|
|
@@ -233,7 +249,8 @@ backend.add(import('@backstage/plugin-scaffolder-backend'));
|
|
|
|
|
backend.add(scaffolderModuleCustomExtensions);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If your custom action requires core services such as `config` or `cache` they can be imported in the dependencies and passed to the custom action function.
|
|
|
|
|
If your custom action requires core services such as `config` or `cache` they can be imported in the dependencies and
|
|
|
|
|
passed to the custom action function.
|
|
|
|
|
|
|
|
|
|
```ts title="packages/backend/src/index.ts"
|
|
|
|
|
import {
|
|
|
|
@@ -243,17 +260,17 @@ import {
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
env.registerInit({
|
|
|
|
|
deps: {
|
|
|
|
|
scaffolder: scaffolderActionsExtensionPoint,
|
|
|
|
|
cache: coreServices.cache,
|
|
|
|
|
config: coreServices.rootConfig,
|
|
|
|
|
},
|
|
|
|
|
async init({ scaffolder, cache, config }) {
|
|
|
|
|
scaffolder.addActions(
|
|
|
|
|
customActionNeedingCacheAndConfig({ cache: cache, config: config }),
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
env.registerInit({
|
|
|
|
|
deps: {
|
|
|
|
|
scaffolder: scaffolderActionsExtensionPoint,
|
|
|
|
|
cache: coreServices.cache,
|
|
|
|
|
config: coreServices.rootConfig,
|
|
|
|
|
},
|
|
|
|
|
async init({scaffolder, cache, config}) {
|
|
|
|
|
scaffolder.addActions(
|
|
|
|
|
customActionNeedingCacheAndConfig({cache: cache, config: config}),
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Using Checkpoints in Custom Actions (Experimental)
|
|
|
|
@@ -281,6 +298,13 @@ You have to define the unique key in scope of the scaffolder task for your check
|
|
|
|
|
will check if the checkpoint with such key was already executed or not, if yes, and the run was successful, the callback
|
|
|
|
|
will be skipped and instead the stored value will be returned.
|
|
|
|
|
|
|
|
|
|
Whenever you change the return type of the checkpoint, we encourage you to change the ID.
|
|
|
|
|
For example, you can embed the versioning or another indicator for that (instead of using key `create.projects`, it can
|
|
|
|
|
be `create.projects.v1`).
|
|
|
|
|
If you'll preserve the same key, and you'll try to restart the affected task, it will fail on this checkpoint.
|
|
|
|
|
The cached result will not match with the expected updated return type.
|
|
|
|
|
By changing the key, you'll invalidate the cache of the checkpoint.
|
|
|
|
|
|
|
|
|
|
### Register Custom Actions with the Legacy Backend System
|
|
|
|
|
|
|
|
|
|
Once you have your Custom Action ready for usage with the scaffolder, you'll
|
|
|
|
|