Cheat notes · Module 07 · Golden paths and docs
Your own scaffolder action
A five-minute review for when you have done this module and want it back in your head. Open the full module for the steps and the lab, or the full text to print.
The idea
Company rules need your own code, and the smallest piece of backend code is a module: it plugs into one plugin (the scaffolder) through its extension point and gets services like the catalog injected.
Remember
- Backend module:
createBackendModule({ pluginId: 'scaffolder', moduleId }), added withbackend.add.yarn new --select scaffolder-backend-modulegenerates and wires it. - Extension point: what a plugin offers modules.
scaffolderActionsExtensionPoint.addActions(...)registers actions. - Service refs in
deps:catalogServiceRef,loggerServiceRef,databaseServiceRef; the backend injects them. - The action:
createTemplateAction({ id, description, schema: { input, output }, handler }). Schemas are Zod; the Installed Actions page shows them.ctx.output(...)feeds later steps. - On whose behalf: read the catalog with
ctx.getInitiatorCredentials(), so permissions apply to the user running the template. - Dry run:
supportsDryRun: trueonly for read-only actions. An action that writes checksctx.isDryRunand skips the write.
Pitfalls
- Deleting
supportsDryRun: true: tests and types still pass, but the dry run logsSkipping because acme:team:lookup does not support dry-runand the README saysOwned by ****. Test for it. - Throwing a generic
Errorfor bad input: useInputErrorso the user sees a clear message, and fail before anything is created (put the lookup step first).
Commands
yarn new --select scaffolder-backend-module --option moduleId=acme | Generate the module and wire it into the backend |
cd plugins/scaffolder-backend-module-acme && yarn test --watchAll=false | Run its tests |
yarn tsc | Type-check the whole repo |
A module that adds an action
export const scaffolderModuleAcme = createBackendModule({
pluginId: 'scaffolder',
moduleId: 'acme',
register({ registerInit }) {
registerInit({
deps: {
scaffolderActions: scaffolderActionsExtensionPoint,
catalog: catalogServiceRef,
},
async init({ scaffolderActions, catalog }) {
scaffolderActions.addActions(createTeamLookupAction({ catalog }));
},
});
},
});
Test yourself
Answer in your head first, then open the answer.
How does your module get the catalog client?
It lists catalogServiceRef in deps and the backend injects it.
Why is the action a module of the scaffolder and not its own plugin?
It extends the scaffolder through its extension point and has no API of its own.
Why read the catalog with ctx.getInitiatorCredentials()?
The read happens as the user who runs the template, so permissions apply to them.
Where module 07 leaves you: The scaffolder has your acme:team:lookup action with three passing tests. New services say "Owned by Team Checkout" in their README and docs.