Merge pull request #29612 from Parsifal-M/docs/software-templates-pt2

[Docs] Software Templates Part 2
This commit is contained in:
Ben Lambert
2025-05-06 12:10:57 +02:00
committed by GitHub
5 changed files with 83 additions and 115 deletions
@@ -10,15 +10,19 @@ git repository.
## Action Modules
There are also several modules available for various SCM tools:
There are several action modules that are available to be added:
- Azure DevOps: `@backstage/plugin-scaffolder-backend-module-azure`
- Bitbucket Cloud: `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud`
- Bitbucket Server: `@backstage/plugin-scaffolder-backend-module-bitbucket-server`
- Gerrit: `@backstage/plugin-scaffolder-backend-module-gerrit`
- Gitea: `@backstage/plugin-scaffolder-backend-module-gitea`
- GitHub: `@backstage/plugin-scaffolder-backend-module-github`
- GitLab: `@backstage/plugin-scaffolder-backend-module-gitlab`
- [Azure DevOps](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-azure): `@backstage/plugin-scaffolder-backend-module-azure`
- [Bitbucket Cloud](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-bitbucket-cloud): `@backstage/plugin-scaffolder-backend-module-bitbucket-cloud`
- [Bitbucket Server](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-bitbucket-server): `@backstage/plugin-scaffolder-backend-module-bitbucket-server`
- [Gerrit](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-gerrit): `@backstage/plugin-scaffolder-backend-module-gerrit`
- [Gitea](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-gitea): `@backstage/plugin-scaffolder-backend-module-gitea`
- [GitHub](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-github): `@backstage/plugin-scaffolder-backend-module-github`
- [GitLab](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-gitlab): `@backstage/plugin-scaffolder-backend-module-gitlab`
- [Rails](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-rails): `@backstage/plugin-scaffolder-backend-module-rails`
- [Yeoman](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-yeoman): `@backstage/plugin-scaffolder-backend-module-yeoman`
- [Sentry](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-sentry): `@backstage/plugin-scaffolder-backend-module-sentry`
- [Cookiecutter](https://github.com/backstage/backstage/tree/master/plugins/scaffolder-backend-module-cookiecutter): `@backstage/plugin-scaffolder-backend-module-cookiecutter`
## Installing Action Modules
@@ -37,7 +41,6 @@ const backend = createBackend();
backend.add(import('@backstage/plugin-app-backend'));
// catalog plugin
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
@@ -51,12 +54,6 @@ backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
backend.start();
```
:::note Note
This is a simplified example of what your backend may look like, you may have more code in here then this.
:::
## Listing Actions
A list of all registered actions can be found under `/create/actions`. For local
@@ -78,11 +78,11 @@ Once you have more than a few software templates you may want to customize your
accomplish this by creating `groups` and passing them to your `ScaffolderPage`
like below
```
```tsx
<ScaffolderPage
groups={[
{
title: "Recommended",
title: 'Recommended',
filter: entity =>
entity?.metadata?.tags?.includes('recommended') ?? false,
},
@@ -96,6 +96,7 @@ top of the page above any other templates not filtered by this group or others.
You can also further customize groups by passing in a `titleComponent` instead
of a `title` which will be a component to use as the header instead of just the
default `ContentHeader` with the `title` set as it's value.
![Grouped Templates](../../assets/software-templates/grouped-templates.png)
There is also an option to hide some templates.
@@ -12,6 +12,8 @@ It is important to remember that all examples are based on [react-jsonschema-for
### Simple input with basic validations
We can use a `pattern` to validate the input. The `pattern` is a regular expression that the input must match.
```yaml
parameters:
- title: Fill in some steps
@@ -28,6 +30,8 @@ parameters:
#### Custom validation error message
This example shows how to customize the error message shown when the `pattern` validation fails.
```yaml
parameters:
- title: Fill in some steps
@@ -47,6 +51,8 @@ parameters:
### Multi line text input
If you need to insert a multi-line string, you can use the `ui:widget: textarea` option. This will create a text area input instead of a single line input.
```yaml
parameters:
- title: Fill in some steps
@@ -74,6 +80,8 @@ parameters:
### Array with custom titles
In the example below the user will see the `enumNames` instead of the `enum` values, making it easier to read.
```yaml
parameters:
- title: Fill in some steps
@@ -103,6 +111,8 @@ parameters:
### A multiple choices list
This is a simple multiple choice list.
```yaml
parameters:
- title: Fill in some steps
@@ -122,6 +132,8 @@ parameters:
### Array with another types
In the example below, it will create an array of custom objects. Once you add one, you will see an object where each one contains 3 fields, "How are you?", "Is it sunny?" and "Anything else?".
```yaml
parameters:
- title: Fill in some steps
@@ -138,19 +150,19 @@ parameters:
type: object
properties:
array:
title: Array string with default value
title: How are you?
type: string
default: value3
default: good
enum:
- value1
- value2
- value3
- good
- okay
- great
flag:
title: Boolean flag
title: Is it sunny?
type: boolean
ui:widget: radio
someInput:
title: Simple text input
title: Anything else?
type: string
```
@@ -158,6 +170,8 @@ parameters:
### Boolean
This adds a simple checkbox to the form. The value will be `true` or `false`.
```yaml
parameters:
- title: Fill in some steps
@@ -169,6 +183,8 @@ parameters:
### Boolean Yes or No options
This example shows how to use a radio button instead of a checkbox with `Yes` or `No` options.
```yaml
parameters:
- title: Fill in some steps
@@ -181,6 +197,8 @@ parameters:
### Boolean multiple options
You can create multiple checkboxes with different options. The example below shows how to create a list of features that can be enabled or disabled for example.
```yaml
parameters:
- title: Fill in some steps
@@ -200,6 +218,8 @@ parameters:
## Markdown text blocks
Its possible to render markdown text blocks in the form. This is useful to add some help text or instructions for the user.
```yaml
parameters:
- title: Fill in some steps
@@ -217,7 +237,7 @@ parameters:
## Use parameters as condition in steps
Conditions use Javascript equality operators.
Its possible to conditionally run steps based on the value of a parameter. In the example below, we trigger the steps depending on the value of the `environment` parameter.
```yaml
- name: Only development environments
@@ -241,6 +261,8 @@ Conditions use Javascript equality operators.
## Use parameters as conditional for fields
Its also possible to conditionally show fields based on the value of a parameter. In the example below, we show the `lastName` field only if the `includeName` parameter is set to `true`.
```yaml
parameters:
- title: Fill in some steps
@@ -269,6 +291,9 @@ parameters:
### Multiple conditional fields with custom ordering
In this example, we show how to conditionally show multiple fields based on the value of a parameter. The `ui:order` property is used to control the order of the fields in the form.
In this case, we show the `lastName` and `address` fields only if the `includeName` and `includeAddress` parameters are set to `true`.
```yaml
parameters:
- title: Fill in some steps
@@ -349,12 +374,16 @@ Testing of this functionality is not yet supported using _create/edit_. In addit
:::
Its possible to use placeholders to reference remote files. This is useful when you have some standard parameters or actions that you want to reuse across multiple templates.
### template.yaml
In our template, we use the `$yaml` placeholder to reference the `parameters.yaml` and `action.yaml` files. The `parameters.yaml` file contains some parameters that we want to use in our template, and the `action.yaml` file contains the action that we want to run.
```yaml
spec:
parameters:
- $yaml: https://github.com/example/path/to/example.yaml
- $yaml: https://github.com/example/path/to/parameters.yaml # This would become the parameters as referenced in the parameters.yaml file
- title: Fill in some steps
properties:
path:
@@ -362,7 +391,7 @@ spec:
type: string
steps:
- $yaml: https://github.com/example/path/to/action.yaml
- $yaml: https://github.com/example/path/to/action.yaml # This would become the publish action as referenced in the action.yaml file
- id: fetch
name: Fetch template
@@ -371,7 +400,9 @@ spec:
url: ${{ parameters.path if parameters.path else '/root' }}
```
### example.yaml
### parameters.yaml
The `url` parameter will be added to the template.
```yaml
title: Provide simple information
@@ -385,6 +416,8 @@ properties:
### action.yaml
The `publish:github` action will be included in our template.
```yaml
id: publish
name: Publish files
@@ -25,7 +25,7 @@ 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:
```
```sh
$ yarn backstage-cli new
? What do you want to create?
plugin-common - A new isomorphic common plugin package
@@ -34,8 +34,6 @@ $ yarn backstage-cli new
> scaffolder-module - An module exporting custom actions for @backstage/plugin-scaffolder-backend
```
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.
@@ -87,7 +85,7 @@ for reference.
The `createTemplateAction` takes an object which specifies the following:
- `id` - A unique ID for your custom action. We encourage you to namespace these
- `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`
@@ -151,9 +149,6 @@ Also feel free to use your company name to namespace them if you prefer too, for
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.
### Adding a TemplateExample
A TemplateExample is a predefined structure that can be used to create custom actions in your software templates. It
@@ -185,9 +180,23 @@ export const examples: TemplateExample[] = [
];
```
Add the example to the `createTemplateAction` under the object property `examples`:
Add the example to `createTemplateAction` by including the `examples` property:
`return createTemplateAction<{ contents: string; filename: string }>({id: 'acme:file:create', description: 'Create an Acme file', examples, ...};`
```ts
return createTemplateAction({
id: 'acme:file:create',
description: 'Create an Acme file',
schema: {
input: {
contents: d => d.string().describe('The contents of the file'),
filename: d =>
d.string().describe('The filename of the file that will be created'),
},
},
examples,
// ...rest of the action configuration
});
```
### The context object
@@ -275,9 +284,7 @@ env.registerInit({
### Using Checkpoints in Custom Actions (Experimental)
Idempotent action could be achieved via the usage of checkpoints.
Example:
Idempotent action could be achieved via the usage of checkpoints, for example:
```ts title="plugins/my-company-scaffolder-actions-plugin/src/vendor/my-custom-action.ts"
const res = await ctx.checkpoint?.({
@@ -305,78 +312,9 @@ If you'll preserve the same key, and you'll try to restart the affected task, it
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
## Contributed Community Actions
Once you have your Custom Action ready for usage with the scaffolder, you'll
need to pass this into the `scaffolder-backend` `createRouter` function. You
should have something similar to the below in
`packages/backend/src/plugins/scaffolder.ts`
You can find a list of community-contributed and open-source actions by:
```ts
return await createRouter({
catalogClient,
logger: env.logger,
config: env.config,
database: env.database,
reader: env.reader,
});
```
There's another property you can pass here, which is an array of `actions` which
will set the available actions that the scaffolder has access to.
```ts
import { createBuiltinActions } from '@backstage/plugin-scaffolder-backend';
import { ScmIntegrations } from '@backstage/integration';
import { createNewFileAction } from './scaffolder/actions/custom';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const catalogClient = new CatalogClient({ discoveryApi: env.discovery });
const integrations = ScmIntegrations.fromConfig(env.config);
const builtInActions = createBuiltinActions({
integrations,
catalogClient,
config: env.config,
reader: env.reader,
});
const actions = [...builtInActions, createNewFileAction()];
return createRouter({
actions,
catalogClient: catalogClient,
logger: env.logger,
config: env.config,
database: env.database,
reader: env.reader,
});
}
```
## List of custom action packages
Here is a list of Open Source custom actions that you can add to your Backstage
scaffolder backend:
| Name | Package | Owner |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Yeoman | [plugin-scaffolder-backend-module-yeoman](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-yeoman) | [Backstage](https://backstage.io) |
| Cookiecutter | [plugin-scaffolder-backend-module-cookiecutter](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-cookiecutter) | [Backstage](https://backstage.io) |
| Rails | [plugin-scaffolder-backend-module-rails](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend-module-rails) | [Backstage](https://backstage.io) |
| HTTP requests | [scaffolder-backend-module-http-request](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-http-request) | [Roadie](https://roadie.io) |
| Utility actions | [scaffolder-backend-module-utils](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-utils) | [Roadie](https://roadie.io) |
| AWS cli actions | [scaffolder-backend-module-aws](https://www.npmjs.com/package/@roadiehq/scaffolder-backend-module-aws) | [Roadie](https://roadie.io) |
| Scaffolder .NET Actions | [plugin-scaffolder-dotnet-backend](https://www.npmjs.com/package/@plusultra/plugin-scaffolder-dotnet-backend) | [Alef Carlos](https://github.com/alefcarlos) |
| Scaffolder Git Actions | [plugin-scaffolder-git-actions](https://www.npmjs.com/package/@mdude2314/backstage-plugin-scaffolder-git-actions) | [Drew Hill](https://github.com/arhill05) |
| Azure Pipeline Actions | [scaffolder-backend-module-azure-pipelines](https://www.npmjs.com/package/@parfuemerie-douglas/scaffolder-backend-module-azure-pipelines) | [Parfümerie Douglas](https://github.com/Parfuemerie-Douglas) |
| Azure Repository Actions | [scaffolder-backend-module-azure-repositories](https://www.npmjs.com/package/@parfuemerie-douglas/scaffolder-backend-module-azure-repositories) | [Parfümerie Douglas](https://github.com/Parfuemerie-Douglas) |
| Snyk Import Project | [plugin-scaffolder-backend-module-snyk](https://www.npmjs.com/package/@ma11hewthomas/plugin-scaffolder-backend-module-snyk) | [Matthew Thomas](https://github.com/Ma11hewThomas) |
| JSON Merge Actions | [plugin-scaffolder-json-merge-actions](https://www.npmjs.com/package/@mdude2314/backstage-plugin-scaffolder-json-merge-actions) | [Drew Hill](https://github.com/arhill05) |
| NPM Actions | [plugin-scaffolder-npm-actions](https://www.npmjs.com/package/@mdude2314/backstage-plugin-scaffolder-npm-actions) | [Drew Hill](https://github.com/arhill05) |
| Slack Actions | [plugin-scaffolder-backend-module-slack](https://www.npmjs.com/package/@mdude2314/backstage-plugin-scaffolder-backend-module-slack) | [Drew Hill](https://github.com/arhill05) |
| Microsoft Teams Actions | [plugin-scaffolder-backend-module-ms-teams](https://www.npmjs.com/package/@grvpandey11/backstage-plugin-scaffolder-backend-module-ms-teams) | [Gaurav Pandey](https://github.com/grvpandey11) |
Have fun! 🚀
- Going to the [Backstage Plugin Directory](https://backstage.io/plugins/) and filter by `scaffolder`!
- Checking out the [Community Plugins Repo](https://github.com/backstage/community-plugins)!
@@ -4,8 +4,7 @@ title: Writing Templates
description: Details around creating your own custom Software Templates
---
Templates are stored in the **Software Catalog** under a kind `Template`. You
can create your own templates with a small `yaml` definition which describes the
You can create your own templates with a small `yaml` definition which describes the
template and its metadata, along with some input variables that your template
will need, and then a list of actions which are then executed by the scaffolding
service.