From 10c419cc0c0cb3a950a5a4073648851af5ccec23 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 11 Feb 2025 11:26:32 +0100 Subject: [PATCH] cli/new: merge parameters and templateValues Signed-off-by: Patrik Oldsberg --- docs/tooling/cli/04-templates.md | 5 +- .../execution/writeTemplateContents.test.ts | 6 +- .../new/execution/writeTemplateContents.ts | 2 +- .../collectPortableTemplateInput.test.ts | 109 +++++++++++++++--- .../collectPortableTemplateInput.ts | 13 ++- .../preparation/loadPortableTemplate.test.ts | 5 +- .../new/preparation/loadPortableTemplate.ts | 8 +- packages/cli/src/lib/new/types.ts | 3 +- 8 files changed, 110 insertions(+), 41 deletions(-) diff --git a/docs/tooling/cli/04-templates.md b/docs/tooling/cli/04-templates.md index 47a4f4d663..2ffb49c343 100644 --- a/docs/tooling/cli/04-templates.md +++ b/docs/tooling/cli/04-templates.md @@ -106,7 +106,7 @@ Your first step in creating your own CLI template is composing your yaml file: name: custom-plugin role: frontend-plugin description: Description of my CLI template # optional -templateValues: # optional +values: # optional pluginVar: '{{ camelCase pluginId }}Plugin' ``` @@ -115,8 +115,7 @@ The following properties are supported: - `name` **(required)** - The name of your template, used by the user to select it. - `role` **(required)** - The role of the template, similar to package role. See [Template Roles](#template-roles) for more details. - `description` - A description of the type of package that this template produces. -- `parameters` - A map of pre-filled parameters that will be used instead of prompting the user for input. -- `templateValues` - A map of additional values that will be present during templating. The values are themselves templated and can reference other values. +- `values` - A map of additional values that will be present during templating. The values are themselves templated and can reference other values. If the key matches any of the user prompts, such as `pluginId`, the value will be used directly instead of prompting the user. Once you have your composed template yaml file, [add your new template](#installing-custom-templates) to the CLI config in your root `package.json`: diff --git a/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts b/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts index 2d5804f4a6..7e0e81f137 100644 --- a/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts +++ b/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts @@ -42,8 +42,7 @@ describe('writeTemplateContents', () => { name: 'test', files: [], role: 'frontend-plugin', - parameters: {}, - templateValues: {}, + values: {}, }, { ...baseConfig, @@ -77,8 +76,7 @@ describe('writeTemplateContents', () => { }, ], role: 'frontend-plugin', - parameters: {}, - templateValues: {}, + values: {}, }, { ...baseConfig, diff --git a/packages/cli/src/lib/new/execution/writeTemplateContents.ts b/packages/cli/src/lib/new/execution/writeTemplateContents.ts index f4c90f7935..f54b2d73d6 100644 --- a/packages/cli/src/lib/new/execution/writeTemplateContents.ts +++ b/packages/cli/src/lib/new/execution/writeTemplateContents.ts @@ -43,7 +43,7 @@ export async function writeTemplateContents( ...roleValues, packageName: input.packageName, }, - templatedValues: template.templateValues, + templatedValues: template.values, }); if (!isMonoRepo) { diff --git a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts index d19bdc5778..905ec0b0c5 100644 --- a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts +++ b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts @@ -17,6 +17,7 @@ import inquirer from 'inquirer'; import { PortableTemplateConfig } from '../types'; import { collectPortableTemplateInput } from './collectPortableTemplateInput'; +import { withLogCollector } from '@backstage/test-utils'; describe('collectTemplateParams', () => { const baseOptions = { @@ -33,28 +34,13 @@ describe('collectTemplateParams', () => { name: 'test', role: 'frontend-plugin' as const, files: [], - parameters: {}, - templateValues: {}, - }, - prefilledParams: { - pluginId: 'test', - owner: 'me', + values: {}, }, + prefilledParams: {}, }; - it('should return default values if not provided', async () => { - await expect(collectPortableTemplateInput(baseOptions)).resolves.toEqual({ - roleParams: { - role: 'frontend-plugin', - pluginId: 'test', - }, - owner: 'me', - version: '0.1.0', - license: 'Apache-2.0', - private: true, - packageName: '@internal/plugin-test', - packagePath: 'plugins/test', - }); + beforeEach(() => { + jest.resetAllMocks(); }); it('should prompt for missing parameters', async () => { @@ -78,4 +64,89 @@ describe('collectTemplateParams', () => { packagePath: 'plugins/other', }); }); + + it('should pick up prefilled parameters', async () => { + await expect( + collectPortableTemplateInput({ + ...baseOptions, + prefilledParams: { + pluginId: 'test1', + owner: 'me', + }, + }), + ).resolves.toEqual({ + roleParams: { + role: 'frontend-plugin', + pluginId: 'test1', + }, + owner: 'me', + version: '0.1.0', + license: 'Apache-2.0', + private: true, + packageName: '@internal/plugin-test1', + packagePath: 'plugins/test1', + }); + }); + + it('should pick up template values', async () => { + await expect( + collectPortableTemplateInput({ + ...baseOptions, + template: { + ...baseOptions.template, + values: { + pluginId: 'test2', + owner: 'me', + }, + }, + }), + ).resolves.toEqual({ + roleParams: { + role: 'frontend-plugin', + pluginId: 'test2', + }, + owner: 'me', + version: '0.1.0', + license: 'Apache-2.0', + private: true, + packageName: '@internal/plugin-test2', + packagePath: 'plugins/test2', + }); + }); + + it('should map deprecated id param to pluginId', async () => { + const logs = await withLogCollector(async () => { + await expect( + collectPortableTemplateInput({ + ...baseOptions, + config: { + ...baseOptions.config, + isUsingDefaultTemplates: true, + }, + prefilledParams: { + id: 'test3', + owner: 'me', + }, + }), + ).resolves.toEqual({ + roleParams: { + role: 'frontend-plugin', + pluginId: 'test3', + }, + owner: 'me', + version: '0.1.0', + license: 'Apache-2.0', + private: true, + packageName: '@internal/plugin-test3', + packagePath: 'plugins/test3', + }); + }); + expect(logs).toEqual({ + error: [], + log: [], + warn: [ + `DEPRECATION WARNING: The 'id' parameter is deprecated, use 'pluginId' instead`, + ], + }); + }); }); diff --git a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts index 79dc508758..720993e25c 100644 --- a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts @@ -46,15 +46,20 @@ export async function collectPortableTemplateInput( prompts.push(ownerPrompt()); } - const parameters = { ...template.parameters, ...prefilledParams }; - - if (config.isUsingDefaultTemplates && parameters.id) { + const deprecatedParams: PortableTemplateParams = {}; + if (config.isUsingDefaultTemplates && prefilledParams.id) { console.warn( `DEPRECATION WARNING: The 'id' parameter is deprecated, use 'pluginId' instead`, ); - parameters.pluginId = parameters.id; + deprecatedParams.pluginId = prefilledParams.id; } + const parameters = { + ...template.values, + ...prefilledParams, + ...deprecatedParams, + }; + const needsAnswer = []; const prefilledAnswers = {} as PortableTemplateParams; for (const prompt of prompts) { diff --git a/packages/cli/src/lib/new/preparation/loadPortableTemplate.test.ts b/packages/cli/src/lib/new/preparation/loadPortableTemplate.test.ts index ad81862379..326c8203ec 100644 --- a/packages/cli/src/lib/new/preparation/loadPortableTemplate.test.ts +++ b/packages/cli/src/lib/new/preparation/loadPortableTemplate.test.ts @@ -29,7 +29,7 @@ describe('loadTemplate', () => { 'path/to/template.yaml': ` name: template1 role: frontend-plugin - parameters: + values: foo: bar `, 'path/to/hello.txt': 'hello world', @@ -44,8 +44,7 @@ describe('loadTemplate', () => { name: 'template1', role: 'frontend-plugin', files: [{ path: 'hello.txt', content: 'hello world' }], - parameters: { foo: 'bar' }, - templateValues: {}, + values: { foo: 'bar' }, }); }); diff --git a/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts b/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts index eaf6ecc90b..c792119ae6 100644 --- a/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts +++ b/packages/cli/src/lib/new/preparation/loadPortableTemplate.ts @@ -35,8 +35,7 @@ const templateDefinitionSchema = z name: z.string(), role: z.enum(TEMPLATE_ROLES), description: z.string().optional(), - parameters: z.record(z.string()).optional(), - templateValues: z.record(z.string()).optional(), + values: z.record(z.string()).optional(), }) .strict(); @@ -64,7 +63,7 @@ export async function loadPortableTemplate( ); } - const { role, parameters = {}, templateValues = {} } = parsed.data; + const { role, values = {} } = parsed.data; const templatePath = resolvePath(dirname(pointer.target)); const filePaths = await recursiveReaddir(templatePath).catch(error => { @@ -104,7 +103,6 @@ export async function loadPortableTemplate( name: pointer.name, role, files: loadedFiles, - parameters, - templateValues, + values, }; } diff --git a/packages/cli/src/lib/new/types.ts b/packages/cli/src/lib/new/types.ts index 009ab2a81b..61fd6110fd 100644 --- a/packages/cli/src/lib/new/types.ts +++ b/packages/cli/src/lib/new/types.ts @@ -69,8 +69,7 @@ export type PortableTemplate = { name: string; role: PortableTemplateRole; files: PortableTemplateFile[]; - parameters: Record; - templateValues: Record; + values: Record; }; export type PortableTemplateParams = {