diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index bf21b91746..d1fac931e5 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -654,6 +654,8 @@ how to use them in the Scaffolder templates. It's important to mention that Back native filters from the Nunjucks library. For a complete list of these native filters and their usage, refer to the [Nunjucks documentation](https://mozilla.github.io/nunjucks/templating.html#builtin-filters). +To create your own custom filters, look to the section [Custom Filters](#custom-filters) hereafter. + ### parseRepoUrl The `parseRepoUrl` filter parse a repository URL into @@ -739,6 +741,117 @@ The `projectSlug` filter generates a project slug from a repository URL - **Input**: `github.com?repo=backstage&org=backstage` - **Output**: `backstage/backstage` +## Custom Filters + +Whenever it is needed to extend the built-in filters with yours `${{ parameters.name | my-filter1 | my-filter2 | etc }}`, then you can add them +using the property `additionalTemplateFilters`. + +The `additionalTemplateFilters` property accepts as type a `Record` + +```ts title="plugins/scaffolder-backend/src/service/Router.ts" + additionalTemplateFilters?: Record; +``` + +where the first parameter is the name of the filter and the second receives a list of `JSON value` arguments. The `templateFilter()` function must return a JsonValue which is either a Json array, object or primitive. + +```ts title="plugins/scaffolder-node/src/types.ts" +export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined; +``` + +From a practical coding point of view, you will translate that into the following snippet code handling 2 filters: + +```ts" +... +additionalTemplateFilters: { + base64: (...args: JsonValue[]) => btoa(args.join("")), + betterFilter: (...args: JsonValue[]) => { return `This is a much better string than "${args}", don't you think?` } +} +``` + +And within your template, you will be able to use the filters using a parameter and the filter passed using the pipe symbol + +```yaml +apiVersion: scaffolder.backstage.io/v1beta3 +kind: Template +metadata: + name: test + title: Test +spec: + owner: user:guest + type: service + + parameters: + - title: Test custom filters + properties: + userName: + title: Name of the user + type: string + + steps: + - id: debug + name: debug + action: debug:log + input: + message: ${{ parameters.userName | betterFilter | base64 }} +``` + +Next, you will have to register the property `addTemplateFilters` using the `scaffolderTemplatingExtensionPoint` of a new `BackendModule` [created](../../backend-system/architecture/06-modules.md). + +Here is a very simplified example of how to do that: + +```ts title="packages/backend-next/src/index.ts" +/* highlight-add-start */ +import { scaffolderTemplatingExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; +import { createBackendModule } from '@backstage/backend-plugin-api'; +/* highlight-add-end */ + +/* highlight-add-start */ +const scaffolderModuleCustomFilters = createBackendModule({ + pluginId: 'scaffolder', // name of the plugin that the module is targeting + moduleId: 'custom-filters', + register(env) { + env.registerInit({ + deps: { + scaffolder: scaffolderTemplatingExtensionPoint, + // ... and other dependencies as needed + }, + async init({ scaffolder /* ..., other dependencies */ }) { + scaffolder.addTemplateFilters({ + base64: (...args: JsonValue[]) => btoa(args.join('')), + betterFilter: (...args: JsonValue[]) => { + return `This is a much better string than "${args}", don't you think?`; + }, + }); + }, + }); + }, +}); +/* highlight-add-end */ + +const backend = createBackend(); +backend.add(import('@backstage/plugin-scaffolder-backend/alpha')); +/* highlight-add-next-line */ +backend.add(scaffolderModuleCustomFilters()); +``` + +If you still use the legacy backend system, then you will use the `createRouter()` function of the `Scaffolder plugin` + +```ts title="packages/backend/src/plugins/scaffolder.ts" +export default async function createPlugin({ + logger, + config, +}: PluginEnvironment): Promise { + ... + return await createRouter({ + logger, + config, + + additionalTemplateFilters: { + + } + }); +``` + ## Template Editor Writing template is most of the times an iterative process. You will need to test your template to make sure it has a good user experience and that it works as expected. To help on this process the scaffolder comes with a build in template editor that allows you to test your template in a real environment for querying data and execute the actions on dry-run mode to see the results of those one.