From 68e87d7f4c6344e1eb167146f9961eb02730fc05 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 8 Feb 2025 13:49:57 +0100 Subject: [PATCH] cli/new: add support for templated template values Signed-off-by: Patrik Oldsberg --- .../execution/executePluginPackageTemplate.ts | 31 ++++++++++++++++++- .../new/execution/executePortableTemplate.ts | 23 ++++---------- .../new/preparation/loadPortableTemplate.ts | 5 +-- packages/cli/src/lib/new/types.ts | 1 + 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts b/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts index 6f7bf6b997..8acf02c593 100644 --- a/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts +++ b/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts @@ -24,12 +24,31 @@ import { resolve as resolvePath, relative as relativePath, } from 'path'; +import camelCase from 'lodash/camelCase'; +import kebabCase from 'lodash/kebabCase'; +import lowerCase from 'lodash/lowerCase'; +import snakeCase from 'lodash/snakeCase'; +import startCase from 'lodash/startCase'; +import upperCase from 'lodash/upperCase'; +import upperFirst from 'lodash/upperFirst'; +import lowerFirst from 'lodash/lowerFirst'; import { paths } from '../../paths'; import { Task } from '../../tasks'; import { Lockfile } from '../../versioning'; import { createPackageVersionProvider } from '../../version'; +const helpers = { + camelCase, + kebabCase, + lowerCase, + snakeCase, + startCase, + upperCase, + upperFirst, + lowerFirst, +}; + export interface CreateContext { /** Whether we are creating something in a monorepo or not */ isMonoRepo: boolean; @@ -44,6 +63,7 @@ export interface CreateContext { export async function executePluginPackageTemplate( ctx: CreateContext, options: { + templateValues: Record; templateDir: string; targetDir: string; values: Record; @@ -77,6 +97,7 @@ export async function executePluginPackageTemplate( Task.section('Executing Template'); await templatingTask( templateDir, + options.templateValues, tempDir, values, createPackageVersionProvider(lockfile), @@ -104,6 +125,7 @@ export async function executePluginPackageTemplate( export async function templatingTask( templateDir: string, + templateValues: Record, destinationDir: string, context: any, versionProvider: (name: string, versionHint?: string) => string, @@ -113,6 +135,12 @@ export async function templatingTask( throw new Error(`Failed to read template directory: ${error.message}`); }); + const templatedValues = Object.fromEntries( + Object.entries(templateValues).map(([name, tmpl]) => { + return [name, handlebars.compile(tmpl)(context, { helpers })]; + }), + ); + for (const file of files) { const destinationFile = file.replace(templateDir, destinationDir); await fs.ensureDir(dirname(destinationFile)); @@ -126,7 +154,7 @@ export async function templatingTask( strict: true, }); const contents = compiled( - { name: basename(destination), ...context }, + { name: basename(destination), ...context, ...templatedValues }, { helpers: { versionQuery(name: string, versionHint: string | unknown) { @@ -135,6 +163,7 @@ export async function templatingTask( typeof versionHint === 'string' ? versionHint : undefined, ); }, + ...helpers, }, }, ); diff --git a/packages/cli/src/lib/new/execution/executePortableTemplate.ts b/packages/cli/src/lib/new/execution/executePortableTemplate.ts index 31b9e1e53c..196637df18 100644 --- a/packages/cli/src/lib/new/execution/executePortableTemplate.ts +++ b/packages/cli/src/lib/new/execution/executePortableTemplate.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import camelCase from 'lodash/camelCase'; -import upperFirst from 'lodash/upperFirst'; import { isMonoRepo } from '@backstage/cli-node'; import { assertError } from '@backstage/errors'; @@ -47,14 +45,6 @@ export async function executePortableTemplate( const targetDir = paths.resolveTargetRoot(packageInfo.packagePath); - const moduleVar = - params.moduleId ?? - `${camelCase(params.id)}Module${camelCase( - params.moduleId, - )[0].toUpperCase()}${camelCase(params.moduleId).slice(1)}`; // used in default-backend-module template - const extensionName = `${upperFirst(camelCase(params.id))}Page`; // used in default-plugin template - const pluginVar = `${camelCase(params.id)}Plugin`; // used in default-backend-plugin and default-plugin template - let modified = false; try { await executePluginPackageTemplate( @@ -68,14 +58,13 @@ export async function executePortableTemplate( { targetDir, templateDir: template.templatePath, + templateValues: template.templateValues, values: { - name: packageName, - privatePackage: params.private, - pluginVersion: params.baseVersion, - moduleVar, - extensionName, - pluginVar, - ...params, + packageName: packageInfo.packageName, + privatePackage: input.globals.private, + packageVersion: input.globals.baseVersion, + license: input.globals.license, + ...input.params, }, }, ); diff --git a/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts b/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts index e308f9ba2d..dd0653a1c1 100644 --- a/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts +++ b/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts @@ -42,6 +42,7 @@ const templateDefinitionSchema = z ) .optional(), additionalActions: z.array(z.string()).optional(), + templateValues: z.record(z.string()).optional(), }) .strict(); @@ -70,11 +71,11 @@ export async function loadPortableTemplate({ ); } - const { template, ...templateData } = parsed.data; + const { template, templateValues = {}, ...templateData } = parsed.data; const templatePath = resolvePath(dirname(target), template); if (!fs.existsSync(templatePath)) { throw new Error(`Failed to load template contents from '${templatePath}'`); } - return { id, templatePath, ...templateData }; + return { id, templatePath, templateValues, ...templateData }; } diff --git a/packages/cli/src/lib/new/types.ts b/packages/cli/src/lib/new/types.ts index 33f56388fa..353caea1f6 100644 --- a/packages/cli/src/lib/new/types.ts +++ b/packages/cli/src/lib/new/types.ts @@ -66,6 +66,7 @@ export type PortableTemplate = { role: PortableTemplateRole; prompts?: PortableTemplatePrompt[]; additionalActions?: string[]; + templateValues: Record; }; export type PortableTemplateParams = {