diff --git a/packages/cli/src/commands/new/new.ts b/packages/cli/src/commands/new/new.ts index aa38f05aa1..7c4d392a5b 100644 --- a/packages/cli/src/commands/new/new.ts +++ b/packages/cli/src/commands/new/new.ts @@ -49,10 +49,12 @@ export default async (opts: ArgOptions) => { await createNewPackage({ prefilledParams, preselectedTemplateId, - globals: { - ...otherGlobals, - packagePrefix, - pluginInfix, + configOverrides: { + license: otherGlobals.license, + version: otherGlobals.baseVersion, + private: otherGlobals.private, + packageNamePrefix: packagePrefix, + packageNamePluginInfix: pluginInfix, }, }); }; diff --git a/packages/cli/src/lib/new/createNewPackage.ts b/packages/cli/src/lib/new/createNewPackage.ts index 849adccf43..0b832c1d2b 100644 --- a/packages/cli/src/lib/new/createNewPackage.ts +++ b/packages/cli/src/lib/new/createNewPackage.ts @@ -21,17 +21,17 @@ import { selectTemplateInteractively, } from './preparation'; import { executePortableTemplate } from './execution'; -import { PortableTemplateGlobals, PortableTemplateParams } from './types'; +import { PortableTemplateConfig, PortableTemplateParams } from './types'; export type CreateNewPackageOptions = { preselectedTemplateId?: string; - globals: Partial; + configOverrides: Partial; prefilledParams: PortableTemplateParams; }; export async function createNewPackage(options: CreateNewPackageOptions) { const config = await loadPortableTemplateConfig({ - globalOverrides: options.globals, + overrides: options.configOverrides, }); const selectedTemplate = await selectTemplateInteractively( diff --git a/packages/cli/src/lib/new/execution/additionalActions.ts b/packages/cli/src/lib/new/execution/additionalActions.ts index 8190d96ce4..dbeb40f7bc 100644 --- a/packages/cli/src/lib/new/execution/additionalActions.ts +++ b/packages/cli/src/lib/new/execution/additionalActions.ts @@ -95,7 +95,7 @@ async function installFrontend(input: PortableTemplateInput) { paths.resolveTargetRoot('packages/app/package.json'), { dependencies: { - [input.packageParams.packageName]: `workspace:^`, + [input.packageName]: `workspace:^`, }, }, ); @@ -104,7 +104,7 @@ async function installFrontend(input: PortableTemplateInput) { } async function addFrontendLegacy(input: PortableTemplateInput) { - const { roleParams, packageParams } = input; + const { roleParams } = input; if (roleParams.role !== 'frontend-plugin') { throw new Error( 'add-frontend-legacy can only be used for frontend plugins', @@ -127,10 +127,8 @@ async function addFrontendLegacy(input: PortableTemplateInput) { ); if (lastImportIndex !== -1 && lastRouteIndex !== -1) { - const extensionName = upperFirst( - `${camelCase(packageParams.packageName)}Page`, - ); - const importLine = `import { ${extensionName} } from '${packageParams.packageName}';`; + const extensionName = upperFirst(`${camelCase(roleParams.pluginId)}Page`); + const importLine = `import { ${extensionName} } from '${input.packageName}';`; if (!content.includes(importLine)) { revLines.splice(lastImportIndex, 0, importLine); } @@ -154,7 +152,7 @@ async function installBackend(input: PortableTemplateInput) { paths.resolveTargetRoot('packages/backend/package.json'), { dependencies: { - [input.packageParams.packageName]: `workspace:^`, + [input.packageName]: `workspace:^`, }, }, ); @@ -164,33 +162,29 @@ async function installBackend(input: PortableTemplateInput) { async function addBackend(input: PortableTemplateInput) { if (await fs.pathExists(paths.resolveTargetRoot('packages/backend'))) { - await Task.forItem( - 'backend', - `adding ${input.packageParams.packageName}`, - async () => { - const backendFilePath = paths.resolveTargetRoot( - 'packages/backend/src/index.ts', - ); - if (!(await fs.pathExists(backendFilePath))) { - return; - } + await Task.forItem('backend', `adding ${input.packageName}`, async () => { + const backendFilePath = paths.resolveTargetRoot( + 'packages/backend/src/index.ts', + ); + if (!(await fs.pathExists(backendFilePath))) { + return; + } - const content = await fs.readFile(backendFilePath, 'utf8'); - const lines = content.split('\n'); - const backendAddLine = `backend.add(import('${input.packageParams.packageName}'));`; + const content = await fs.readFile(backendFilePath, 'utf8'); + const lines = content.split('\n'); + const backendAddLine = `backend.add(import('${input.packageName}'));`; - const backendStartIndex = lines.findIndex(line => - line.match(/backend.start/), - ); + const backendStartIndex = lines.findIndex(line => + line.match(/backend.start/), + ); - if (backendStartIndex !== -1) { - const [indentation] = lines[backendStartIndex].match(/^\s*/)!; - lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`); + if (backendStartIndex !== -1) { + const [indentation] = lines[backendStartIndex].match(/^\s*/)!; + lines.splice(backendStartIndex, 0, `${indentation}${backendAddLine}`); - const newContent = lines.join('\n'); - await fs.writeFile(backendFilePath, newContent, 'utf8'); - } - }, - ); + const newContent = lines.join('\n'); + await fs.writeFile(backendFilePath, newContent, 'utf8'); + } + }); } } diff --git a/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts b/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts index e1f9d3d420..183208b28c 100644 --- a/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts +++ b/packages/cli/src/lib/new/execution/writeTemplateContents.test.ts @@ -19,12 +19,10 @@ import { writeTemplateContents } from './writeTemplateContents'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { paths } from '../../paths'; -const mockGlobals = { - baseVersion: '0.1.0', +const baseConfig = { + version: '0.1.0', license: 'Apache-2.0', private: true, - packagePrefix: '@internal/', - pluginInfix: 'plugin-', }; describe('writeTemplateContents', () => { @@ -47,14 +45,12 @@ describe('writeTemplateContents', () => { templateValues: {}, }, { + ...baseConfig, roleParams: { role: 'frontend-plugin', pluginId: 'test' }, - globals: mockGlobals, builtInParams: {}, - packageParams: { - packageName: '@internal/plugin-test', - packagePath: 'plugins/plugin-test', - }, params: {}, + packageName: '@internal/plugin-test', + packagePath: 'plugins/plugin-test', }, ); @@ -85,16 +81,14 @@ describe('writeTemplateContents', () => { templateValues: {}, }, { + ...baseConfig, roleParams: { role: 'frontend-plugin', pluginId: 'test' }, - globals: mockGlobals, builtInParams: {}, - packageParams: { - packageName: '@internal/plugin-test', - packagePath: 'out', - }, params: { pluginId: 'test', }, + packageName: '@internal/plugin-test', + packagePath: 'out', }, ); diff --git a/packages/cli/src/lib/new/execution/writeTemplateContents.ts b/packages/cli/src/lib/new/execution/writeTemplateContents.ts index e380183958..0c60a1c9ee 100644 --- a/packages/cli/src/lib/new/execution/writeTemplateContents.ts +++ b/packages/cli/src/lib/new/execution/writeTemplateContents.ts @@ -27,12 +27,10 @@ export async function writeTemplateContents( template: PortableTemplate, input: PortableTemplateInput, ): Promise<{ targetDir: string }> { - const targetDir = paths.resolveTargetRoot(input.packageParams.packagePath); + const targetDir = paths.resolveTargetRoot(input.packagePath); if (await fs.pathExists(targetDir)) { - throw new InputError( - `Package '${input.packageParams.packagePath}' already exists`, - ); + throw new InputError(`Package '${input.packagePath}' already exists`); } try { diff --git a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts index e0ec8c8a28..8d44d4cc33 100644 --- a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts +++ b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.test.ts @@ -23,13 +23,11 @@ describe('collectTemplateParams', () => { config: { isUsingDefaultTemplates: false, templatePointers: [], - globals: { - baseVersion: '0.1.0', - license: 'Apache-2.0', - private: true, - packagePrefix: '@internal/', - pluginInfix: 'plugin-', - }, + version: '0.1.0', + license: 'Apache-2.0', + private: true, + packageNamePrefix: '@internal/', + packageNamePluginInfix: 'plugin-', } satisfies PortableTemplateConfig, template: { id: 'test', @@ -53,10 +51,6 @@ describe('collectTemplateParams', () => { builtInParams: { owner: 'me', }, - packageParams: { - packageName: '@internal/plugin-test', - packagePath: 'plugins/test', - }, params: { license: 'Apache-2.0', packageName: '@internal/plugin-test', @@ -65,7 +59,11 @@ describe('collectTemplateParams', () => { pluginId: 'test', owner: 'me', }, - globals: baseOptions.config.globals, + version: '0.1.0', + license: 'Apache-2.0', + private: true, + packageName: '@internal/plugin-test', + packagePath: 'plugins/test', }); }); @@ -85,10 +83,6 @@ describe('collectTemplateParams', () => { builtInParams: { owner: undefined, }, - packageParams: { - packageName: '@internal/plugin-other', - packagePath: 'plugins/other', - }, params: { license: 'Apache-2.0', packageName: '@internal/plugin-other', @@ -97,7 +91,11 @@ describe('collectTemplateParams', () => { pluginId: 'other', owner: undefined, }, - globals: baseOptions.config.globals, + version: '0.1.0', + license: 'Apache-2.0', + private: true, + packageName: '@internal/plugin-other', + packagePath: 'plugins/other', }); }); }); diff --git a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts index 3655933be9..920f038189 100644 --- a/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts +++ b/packages/cli/src/lib/new/preparation/collectPortableTemplateInput.ts @@ -73,22 +73,29 @@ export async function collectPortableTemplateInput( moduleId: answers.moduleId, } as PortableTemplateInputRoleParams; - const packageParams = resolvePackageParams(roleParams, config.globals); + const packageParams = resolvePackageParams({ + roleParams, + packagePrefix: config.packageNamePrefix, + pluginInfix: config.packageNamePluginInfix, + }); return { roleParams, - packageParams, builtInParams: { owner: answers.owner, } as PortableTemplateInputBuiltInParams, params: { ...answers, packageName: packageParams.packageName, - privatePackage: config.globals.private, - packageVersion: config.globals.baseVersion, - license: config.globals.license, + privatePackage: config.private, + packageVersion: config.version, + license: config.license, }, - globals: config.globals, + license: config.license, + version: config.version, + private: config.private, + packageName: packageParams.packageName, + packagePath: packageParams.packagePath, }; } diff --git a/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.test.ts b/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.test.ts index eed9e0cd6e..5646c03524 100644 --- a/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.test.ts +++ b/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.test.ts @@ -37,6 +37,8 @@ describe('loadPortableTemplateConfig', () => { globals: { license: 'MIT', private: true, + namePrefix: '@acme/', + namePluginInfix: 'backstage-plugin-', }, }, }, @@ -53,17 +55,17 @@ describe('loadPortableTemplateConfig', () => { { id: 'template1', target: 'path/to/template1' }, { id: 'template2', target: 'path/to/template2' }, ], - globals: { - license: 'MIT', - private: true, - baseVersion: '0.1.0', - }, + license: 'MIT', + private: true, + version: '0.1.0', + packageNamePrefix: '@acme/', + packageNamePluginInfix: 'backstage-plugin-', }); await expect( loadPortableTemplateConfig({ packagePath: mockDir.resolve('package.json'), - globalOverrides: { + overrides: { license: 'nope', private: false, }, @@ -74,11 +76,11 @@ describe('loadPortableTemplateConfig', () => { { id: 'template1', target: 'path/to/template1' }, { id: 'template2', target: 'path/to/template2' }, ], - globals: { - license: 'nope', - private: false, - baseVersion: '0.1.0', - }, + license: 'nope', + version: '0.1.0', + private: false, + packageNamePrefix: '@acme/', + packageNamePluginInfix: 'backstage-plugin-', }); }); @@ -103,11 +105,11 @@ describe('loadPortableTemplateConfig', () => { ).resolves.toEqual({ isUsingDefaultTemplates: true, templatePointers: defaultTemplates, - globals: { - license: 'MIT', - private: true, - baseVersion: '0.1.0', - }, + license: 'MIT', + private: true, + version: '0.1.0', + packageNamePrefix: '@internal/', + packageNamePluginInfix: 'plugin-', }); }); @@ -143,28 +145,28 @@ describe('loadPortableTemplateConfig', () => { ).resolves.toEqual({ isUsingDefaultTemplates: true, templatePointers: defaultTemplates, - globals: { - license: 'Apache-2.0', - baseVersion: '0.1.0', - private: true, - }, + license: 'Apache-2.0', + version: '0.1.0', + private: true, + packageNamePrefix: '@internal/', + packageNamePluginInfix: 'plugin-', }); await expect( loadPortableTemplateConfig({ packagePath: mockDir.resolve('package.json'), - globalOverrides: { + overrides: { license: 'nope', }, }), ).resolves.toEqual({ isUsingDefaultTemplates: true, templatePointers: defaultTemplates, - globals: { - license: 'nope', - baseVersion: '0.1.0', - private: true, - }, + license: 'nope', + version: '0.1.0', + private: true, + packageNamePrefix: '@internal/', + packageNamePluginInfix: 'plugin-', }); }); }); diff --git a/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.ts b/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.ts index d88f1fd0ea..15f971e154 100644 --- a/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.ts +++ b/packages/cli/src/lib/new/preparation/loadPortableTemplateConfig.ts @@ -17,17 +17,17 @@ import fs from 'fs-extra'; import { paths } from '../../paths'; import { defaultTemplates } from '../defaultTemplates'; -import { PortableTemplateConfig, PortableTemplateGlobals } from '../types'; +import { PortableTemplateConfig } from '../types'; import { z } from 'zod'; import { fromZodError } from 'zod-validation-error'; import { ForwardedError } from '@backstage/errors'; -const defaultGlobals = { +const defaults = { license: 'Apache-2.0', - baseVersion: '0.1.0', + version: '0.1.0', private: true, - packagePrefix: '@internal/', - pluginInfix: 'plugin-', + packageNamePrefix: '@internal/', + packageNamePluginInfix: 'plugin-', }; const pkgJsonWithNewConfigSchema = z.object({ @@ -48,10 +48,10 @@ const pkgJsonWithNewConfigSchema = z.object({ globals: z .object({ license: z.string().optional(), - baseVersion: z.string().optional(), + version: z.string().optional(), private: z.boolean().optional(), - packagePrefix: z.string().optional(), - pluginInfix: z.string().optional(), + namePrefix: z.string().optional(), + namePluginInfix: z.string().optional(), }) .optional(), }) @@ -63,12 +63,13 @@ const pkgJsonWithNewConfigSchema = z.object({ type LoadConfigOptions = { packagePath?: string; - globalOverrides?: Partial; + overrides?: Partial; }; export async function loadPortableTemplateConfig( options: LoadConfigOptions = {}, ): Promise { + const { overrides = {} } = options; const pkgPath = options.packagePath ?? paths.resolveTargetRoot('package.json'); const pkgJson = await fs.readJson(pkgPath); @@ -81,15 +82,21 @@ export async function loadPortableTemplateConfig( ); } - const newConfig = parsed.data.backstage?.new; + const config = parsed.data.backstage?.new; return { - isUsingDefaultTemplates: !newConfig?.templates, - templatePointers: newConfig?.templates ?? defaultTemplates, - globals: { - ...defaultGlobals, - ...newConfig?.globals, - ...options.globalOverrides, - }, + isUsingDefaultTemplates: !config?.templates, + templatePointers: config?.templates ?? defaultTemplates, + license: overrides.license ?? config?.globals?.license ?? defaults.license, + version: overrides.version ?? config?.globals?.version ?? defaults.version, + private: overrides.private ?? config?.globals?.private ?? defaults.private, + packageNamePrefix: + overrides.packageNamePrefix ?? + config?.globals?.namePrefix ?? + defaults.packageNamePrefix, + packageNamePluginInfix: + overrides.packageNamePluginInfix ?? + config?.globals?.namePluginInfix ?? + defaults.packageNamePluginInfix, }; } diff --git a/packages/cli/src/lib/new/preparation/resolvePackageParams.test.ts b/packages/cli/src/lib/new/preparation/resolvePackageParams.test.ts index 9f1fea056b..df128d4755 100644 --- a/packages/cli/src/lib/new/preparation/resolvePackageParams.test.ts +++ b/packages/cli/src/lib/new/preparation/resolvePackageParams.test.ts @@ -15,14 +15,6 @@ */ import { resolvePackageParams } from './resolvePackageParams'; -const baseGlobals = { - baseVersion: '0.0.0', - license: 'Apache-2.0', - private: true, - packagePrefix: '@internal/', - pluginInfix: 'plugin-', -}; - describe.each([ [ { role: 'web-library', name: 'test' }, @@ -96,6 +88,12 @@ describe.each([ ], ] as const)('resolvePackageInfo', (roleParams, packageInfo) => { it(`should generate correct info with default config for ${roleParams.role}`, () => { - expect(resolvePackageParams(roleParams, baseGlobals)).toEqual(packageInfo); + expect( + resolvePackageParams({ + roleParams, + packagePrefix: '@internal/', + pluginInfix: 'plugin-', + }), + ).toEqual(packageInfo); }); }); diff --git a/packages/cli/src/lib/new/preparation/resolvePackageParams.ts b/packages/cli/src/lib/new/preparation/resolvePackageParams.ts index aebd67eb04..8ec1ca3069 100644 --- a/packages/cli/src/lib/new/preparation/resolvePackageParams.ts +++ b/packages/cli/src/lib/new/preparation/resolvePackageParams.ts @@ -15,10 +15,13 @@ */ import { join as joinPath } from 'path'; -import { - PortableTemplateGlobals, - PortableTemplateInputRoleParams, -} from '../types'; +import { PortableTemplateInputRoleParams } from '../types'; + +export type ResolvePackageParamsOptions = { + roleParams: PortableTemplateInputRoleParams; + pluginInfix: string; + packagePrefix: string; +}; export type PortableTemplatePackageInfo = { packageName: string; @@ -26,14 +29,13 @@ export type PortableTemplatePackageInfo = { }; export function resolvePackageParams( - roleParams: PortableTemplateInputRoleParams, - globals: PortableTemplateGlobals, + options: ResolvePackageParamsOptions, ): PortableTemplatePackageInfo { - const baseName = getBaseNameForRole(roleParams); - const isPlugin = roleParams.role.includes('plugin'); - const pluginInfix = isPlugin ? globals.pluginInfix : ''; + const baseName = getBaseNameForRole(options.roleParams); + const isPlugin = options.roleParams.role.includes('plugin'); + const pluginInfix = isPlugin ? options.pluginInfix : ''; return { - packageName: `${globals.packagePrefix}${pluginInfix}${baseName}`, + packageName: `${options.packagePrefix}${pluginInfix}${baseName}`, packagePath: joinPath(isPlugin ? 'plugins' : 'packages', baseName), }; } diff --git a/packages/cli/src/lib/new/types.ts b/packages/cli/src/lib/new/types.ts index 317c1b30f2..ec6331ddd2 100644 --- a/packages/cli/src/lib/new/types.ts +++ b/packages/cli/src/lib/new/types.ts @@ -25,10 +25,15 @@ export type PortableTemplateConfig = { */ isUsingDefaultTemplates: boolean; - /** - * Templating globals that should apply to all templates. - */ - globals: PortableTemplateGlobals; + license: string; + + version: string; + + private: boolean; + + packageNamePrefix: string; + + packageNamePluginInfix: string; }; export type PortableTemplatePointer = { @@ -77,14 +82,6 @@ export type PortableTemplateParams = { [KName in string]?: string | number | boolean; }; -export type PortableTemplateGlobals = { - license: string; - baseVersion: string; - private: boolean; - packagePrefix: string; - pluginInfix: string; -}; - export type PortableTemplateInputRoleParams = | { role: 'web-library' | 'node-library' | 'common-library'; @@ -109,15 +106,18 @@ export type PortableTemplateInputBuiltInParams = { owner?: string; }; -export type PortableTemplateInputPackageParams = { - packageName: string; - packagePath: string; -}; - export type PortableTemplateInput = { roleParams: PortableTemplateInputRoleParams; builtInParams: PortableTemplateInputBuiltInParams; - packageParams: PortableTemplateInputPackageParams; params: PortableTemplateParams; - globals: PortableTemplateGlobals; + + license: string; + + version: string; + + private: boolean; + + packageName: string; + + packagePath: string; };