cli/new: add support for templated template values
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -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<string, string>;
|
||||
templateDir: string;
|
||||
targetDir: string;
|
||||
values: Record<string, unknown>;
|
||||
@@ -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<string, string>,
|
||||
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,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ export type PortableTemplate = {
|
||||
role: PortableTemplateRole;
|
||||
prompts?: PortableTemplatePrompt[];
|
||||
additionalActions?: string[];
|
||||
templateValues: Record<string, string>;
|
||||
};
|
||||
|
||||
export type PortableTemplateParams = {
|
||||
|
||||
Reference in New Issue
Block a user