cli/new: refactor template loading
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -23,7 +23,6 @@ import { paths } from '../paths';
|
||||
import { Task } from '../tasks';
|
||||
import { addCodeownersEntry, getCodeownersFilePath } from '../codeowners';
|
||||
|
||||
import { verifyTemplate } from './templateSelector';
|
||||
import { promptOptions } from './prompts';
|
||||
import { populateOptions, createDirName, resolvePackageName } from './utils';
|
||||
import { runAdditionalActions } from './additionalActions';
|
||||
@@ -47,12 +46,11 @@ export type CreateNewPackageOptions = {
|
||||
export async function createNewPackage(options: CreateNewPackageOptions) {
|
||||
const newConfig = await loadNewConfig();
|
||||
|
||||
const template = verifyTemplate(
|
||||
await NewTemplateLoader.selectTemplateInteractively(
|
||||
newConfig,
|
||||
options.preselectedTemplateId,
|
||||
),
|
||||
const selectedTemplate = await NewTemplateLoader.selectTemplateInteractively(
|
||||
newConfig,
|
||||
options.preselectedTemplateId,
|
||||
);
|
||||
const template = await NewTemplateLoader.loadTemplate(selectedTemplate);
|
||||
|
||||
const codeOwnersFilePath = await getCodeownersFilePath(paths.targetRoot);
|
||||
|
||||
|
||||
@@ -14,8 +14,41 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { z } from 'zod';
|
||||
import fs from 'fs-extra';
|
||||
import inquirer from 'inquirer';
|
||||
import { dirname } from 'node:path';
|
||||
import { parse as parseYaml } from 'yaml';
|
||||
import { paths } from '../../paths';
|
||||
import { NewConfig, NewTemplatePointer } from '../config/types';
|
||||
import { Template } from '../types';
|
||||
import { ForwardedError } from '@backstage/errors';
|
||||
import { fromZodError } from 'zod-validation-error';
|
||||
|
||||
const templateDefinitionSchema = z
|
||||
.object({
|
||||
description: z.string().optional(),
|
||||
template: z.string(),
|
||||
targetPath: z.string(),
|
||||
plugin: z.boolean().optional(),
|
||||
backendModulePrefix: z.boolean().optional(),
|
||||
suffix: z.string().optional(),
|
||||
prompts: z
|
||||
.array(
|
||||
z.union([
|
||||
z.string(),
|
||||
z.object({
|
||||
id: z.string(),
|
||||
prompt: z.string(),
|
||||
validate: z.string().optional(),
|
||||
default: z.union([z.string(), z.boolean(), z.number()]).optional(),
|
||||
}),
|
||||
]),
|
||||
)
|
||||
.optional(),
|
||||
additionalActions: z.array(z.string()).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export class NewTemplateLoader {
|
||||
static async selectTemplateInteractively(
|
||||
@@ -49,4 +82,40 @@ export class NewTemplateLoader {
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
static async loadTemplate({
|
||||
id,
|
||||
target,
|
||||
}: NewTemplatePointer): Promise<Template> {
|
||||
if (target.match(/https?:\/\//)) {
|
||||
throw new Error('Remote templates are not supported yet');
|
||||
}
|
||||
if (!fs.existsSync(paths.resolveTargetRoot(target))) {
|
||||
throw new Error(`Your CLI template does not exist: ${target}`);
|
||||
}
|
||||
const rawTemplate = parseYaml(
|
||||
fs.readFileSync(paths.resolveTargetRoot(target), 'utf-8'),
|
||||
);
|
||||
|
||||
const parsed = templateDefinitionSchema.safeParse(rawTemplate);
|
||||
if (!parsed.success) {
|
||||
throw new ForwardedError(
|
||||
`Invalid template definition at '${target}'`,
|
||||
fromZodError(parsed.error),
|
||||
);
|
||||
}
|
||||
|
||||
const template = parsed.data;
|
||||
|
||||
const templatePath = paths.resolveTargetRoot(
|
||||
dirname(target),
|
||||
template.template,
|
||||
);
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
throw new Error(
|
||||
`Your CLI template skeleton does not exist: ${templatePath}`,
|
||||
);
|
||||
}
|
||||
return { id, templatePath, ...template };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { dirname } from 'path';
|
||||
import { parse } from 'yaml';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import { paths } from '../paths';
|
||||
import { Template, TemplateLocation } from './types';
|
||||
|
||||
export function verifyTemplate({ id, target }: TemplateLocation): Template {
|
||||
if (target.startsWith('http')) {
|
||||
throw new Error('Remote templates are not supported yet');
|
||||
}
|
||||
if (!fs.existsSync(paths.resolveTargetRoot(target))) {
|
||||
throw new Error(`Your CLI template does not exist: ${target}`);
|
||||
}
|
||||
const template = parse(
|
||||
fs.readFileSync(paths.resolveTargetRoot(target), 'utf-8'),
|
||||
);
|
||||
const templatePath = paths.resolveTargetRoot(
|
||||
dirname(target),
|
||||
template.template,
|
||||
);
|
||||
if (!fs.existsSync(templatePath)) {
|
||||
throw new Error(
|
||||
`Your CLI template skeleton does not exist: ${templatePath}`,
|
||||
);
|
||||
}
|
||||
if (!template.targetPath) {
|
||||
throw new Error(`Your template, ${id}, is missing a targetPath`);
|
||||
}
|
||||
return { id, templatePath, ...template };
|
||||
}
|
||||
@@ -47,14 +47,13 @@ export type ConfigurablePrompt =
|
||||
id: string;
|
||||
prompt: string;
|
||||
validate?: string;
|
||||
default?: string | boolean;
|
||||
default?: string | boolean | number;
|
||||
}
|
||||
| string;
|
||||
|
||||
export interface Template {
|
||||
id: string;
|
||||
description?: string;
|
||||
template: string;
|
||||
templatePath: string;
|
||||
targetPath: string;
|
||||
plugin?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user