cli/new: refactor types
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import { NewConfig } from '../config/types';
|
||||
import { NewConfig } from '../types';
|
||||
import { collectTemplateParams } from './collectTemplateParams';
|
||||
|
||||
describe('collectTemplateParams', () => {
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
import { getCodeownersFilePath } from '../../codeowners';
|
||||
import { paths } from '../../paths';
|
||||
import { NewConfig } from '../config/types';
|
||||
import { NewConfig } from '../types';
|
||||
import { promptOptions } from './prompts';
|
||||
import { Template } from '../types';
|
||||
import { NewTemplate } from '../types';
|
||||
import { Options } from '../execution/utils';
|
||||
|
||||
type CollectTemplateParamsOptions = {
|
||||
config: NewConfig;
|
||||
template: Template;
|
||||
template: NewTemplate;
|
||||
globals: Record<string, string | number | boolean>;
|
||||
prefilledParams: Record<string, string | number | boolean>;
|
||||
};
|
||||
|
||||
@@ -14,10 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import inquirer from 'inquirer';
|
||||
import { Prompt, ConfigurablePrompt } from '../types';
|
||||
import inquirer, { Answers, DistinctQuestion } from 'inquirer';
|
||||
import { NewTemplatePrompt } from '../types';
|
||||
import { parseOwnerIds } from '../../codeowners';
|
||||
|
||||
export type Prompt<TOptions extends Answers> = DistinctQuestion<TOptions> & {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export function pluginIdPrompt(): Prompt<{ id: string }> {
|
||||
return {
|
||||
type: 'input',
|
||||
@@ -94,12 +98,12 @@ export async function promptOptions({
|
||||
globals,
|
||||
codeOwnersFilePath,
|
||||
}: {
|
||||
prompts: ConfigurablePrompt[];
|
||||
prompts: NewTemplatePrompt[];
|
||||
globals: { [name in string]?: string | boolean | number };
|
||||
codeOwnersFilePath: string | undefined;
|
||||
}): Promise<Record<string, string>> {
|
||||
const answers = await inquirer.prompt(
|
||||
prompts.map((prompt: ConfigurablePrompt) => {
|
||||
prompts.map((prompt: NewTemplatePrompt) => {
|
||||
if (typeof prompt === 'string') {
|
||||
switch (prompt) {
|
||||
case 'id':
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import fs from 'fs-extra';
|
||||
import { paths } from '../../paths';
|
||||
import { defaultTemplates } from '../defaultTemplates';
|
||||
import { NewConfig } from './types';
|
||||
import { NewConfig } from '../types';
|
||||
import { z } from 'zod';
|
||||
import { fromZodError } from 'zod-validation-error';
|
||||
import { ForwardedError } from '@backstage/errors';
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
export type NewConfig = {
|
||||
/**
|
||||
* The pointers to templates that can be used.
|
||||
*/
|
||||
templatePointers: NewTemplatePointer[];
|
||||
|
||||
/**
|
||||
* Whether the default set of templates are being used or not.
|
||||
*/
|
||||
isUsingDefaultTemplates: boolean;
|
||||
|
||||
/**
|
||||
* Templating globals that should apply to all templates.
|
||||
*/
|
||||
globals: {
|
||||
[KName in string]?: number | string | boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type NewTemplatePointer = {
|
||||
id: string;
|
||||
target: string;
|
||||
};
|
||||
@@ -29,7 +29,17 @@ import { paths } from '../../paths';
|
||||
import { Task } from '../../tasks';
|
||||
import { Lockfile } from '../../versioning';
|
||||
import { createPackageVersionProvider } from '../../version';
|
||||
import { CreateContext } from '../types';
|
||||
|
||||
export interface CreateContext {
|
||||
/** Whether we are creating something in a monorepo or not */
|
||||
isMonoRepo: boolean;
|
||||
|
||||
/** Creates a temporary directory. This will always be deleted after creation is done. */
|
||||
createTemporaryDirectory(name: string): Promise<string>;
|
||||
|
||||
/** Signal that the creation process got to a point where permanent modifications were made */
|
||||
markAsModified(): void;
|
||||
}
|
||||
|
||||
export async function executePluginPackageTemplate(
|
||||
ctx: CreateContext,
|
||||
|
||||
@@ -27,13 +27,13 @@ import { createDirName, resolvePackageName } from './utils';
|
||||
import { runAdditionalActions } from './additionalActions';
|
||||
import { executePluginPackageTemplate } from './executePluginPackageTemplate';
|
||||
import { TemporaryDirectoryManager } from './TemporaryDirectoryManager';
|
||||
import { NewConfig } from '../config/types';
|
||||
import { Template } from '../types';
|
||||
import { NewConfig } from '../types';
|
||||
import { NewTemplate } from '../types';
|
||||
import { Options } from './utils';
|
||||
|
||||
type ExecuteNewTemplateOptions = {
|
||||
config: NewConfig;
|
||||
template: Template;
|
||||
template: NewTemplate;
|
||||
params: Options;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { resolvePackageName, createDirName, Options } from './utils';
|
||||
import { Template } from '../types';
|
||||
import { NewTemplate } from '../types';
|
||||
|
||||
describe('resolvePackageName', () => {
|
||||
it('should generate correct name without scope', () => {
|
||||
@@ -82,7 +82,7 @@ describe('createDirName', () => {
|
||||
it('should return name in the backend-module format if backendModulePrefix is set to true', () => {
|
||||
expect(
|
||||
createDirName(
|
||||
{ backendModulePrefix: true } as Template,
|
||||
{ backendModulePrefix: true } as NewTemplate,
|
||||
{
|
||||
id: 'foo',
|
||||
moduleId: 'bar',
|
||||
@@ -94,7 +94,7 @@ describe('createDirName', () => {
|
||||
it('should throw an error if backendModulePrefix is configured as true but is missing moduleId', () => {
|
||||
expect(() =>
|
||||
createDirName(
|
||||
{ backendModulePrefix: true } as Template,
|
||||
{ backendModulePrefix: true } as NewTemplate,
|
||||
{
|
||||
id: 'foo',
|
||||
moduleId: '',
|
||||
@@ -105,12 +105,12 @@ describe('createDirName', () => {
|
||||
|
||||
it('should append the suffix value if one is provided', () => {
|
||||
expect(
|
||||
createDirName({ suffix: 'foo' } as Template, { id: 'bar' } as Options),
|
||||
createDirName({ suffix: 'foo' } as NewTemplate, { id: 'bar' } as Options),
|
||||
).toEqual('bar-foo');
|
||||
});
|
||||
|
||||
it('should return id if neither backendModulePrefix nor suffix is specified', () => {
|
||||
expect(createDirName({} as Template, { id: 'foo' } as Options)).toEqual(
|
||||
expect(createDirName({} as NewTemplate, { id: 'foo' } as Options)).toEqual(
|
||||
'foo',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Template } from '../types';
|
||||
import { NewTemplate } from '../types';
|
||||
|
||||
export interface Options extends Record<string, string | boolean> {
|
||||
id: string;
|
||||
@@ -49,7 +49,7 @@ export const resolvePackageName = (options: {
|
||||
return plugin ? `backstage-plugin-${baseName}` : baseName;
|
||||
};
|
||||
|
||||
export function createDirName(template: Template, options: Options) {
|
||||
export function createDirName(template: NewTemplate, options: Options) {
|
||||
if (!options.id) {
|
||||
throw new Error(`id prompt is mandatory for all cli templates`);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import { resolve as resolvePath } from 'path';
|
||||
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 { NewConfig, NewTemplatePointer } from '../types';
|
||||
import { NewTemplate } from '../types';
|
||||
import { ForwardedError } from '@backstage/errors';
|
||||
import { fromZodError } from 'zod-validation-error';
|
||||
|
||||
@@ -87,7 +87,7 @@ export class NewTemplateLoader {
|
||||
static async loadTemplate({
|
||||
id,
|
||||
target,
|
||||
}: NewTemplatePointer): Promise<Template> {
|
||||
}: NewTemplatePointer): Promise<NewTemplate> {
|
||||
if (target.match(/https?:\/\//)) {
|
||||
throw new Error('Remote templates are not supported yet');
|
||||
}
|
||||
|
||||
@@ -14,35 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Answers, DistinctQuestion } from 'inquirer';
|
||||
export type NewConfig = {
|
||||
/**
|
||||
* The pointers to templates that can be used.
|
||||
*/
|
||||
templatePointers: NewTemplatePointer[];
|
||||
|
||||
export type CliConfig =
|
||||
| {
|
||||
/** Setting this to false will omit default backstage-cli new templates */
|
||||
defaults?: boolean;
|
||||
/** Where you can explicitly declare templates */
|
||||
templates?: TemplateLocation[];
|
||||
/** For configuring global values that applies to all new plugins/packages */
|
||||
globals?: Record<string, string>;
|
||||
}
|
||||
| undefined;
|
||||
/**
|
||||
* Whether the default set of templates are being used or not.
|
||||
*/
|
||||
isUsingDefaultTemplates: boolean;
|
||||
|
||||
export interface CreateContext {
|
||||
/** Whether we are creating something in a monorepo or not */
|
||||
isMonoRepo: boolean;
|
||||
|
||||
/** Creates a temporary directory. This will always be deleted after creation is done. */
|
||||
createTemporaryDirectory(name: string): Promise<string>;
|
||||
|
||||
/** Signal that the creation process got to a point where permanent modifications were made */
|
||||
markAsModified(): void;
|
||||
}
|
||||
|
||||
export type Prompt<TOptions extends Answers> = DistinctQuestion<TOptions> & {
|
||||
name: string;
|
||||
/**
|
||||
* Templating globals that should apply to all templates.
|
||||
*/
|
||||
globals: {
|
||||
[KName in string]?: number | string | boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type ConfigurablePrompt =
|
||||
export type NewTemplatePointer = {
|
||||
id: string;
|
||||
target: string;
|
||||
};
|
||||
|
||||
export type NewTemplatePrompt =
|
||||
| {
|
||||
id: string;
|
||||
prompt: string;
|
||||
@@ -51,7 +47,7 @@ export type ConfigurablePrompt =
|
||||
}
|
||||
| string;
|
||||
|
||||
export interface Template {
|
||||
export interface NewTemplate {
|
||||
id: string;
|
||||
description?: string;
|
||||
templatePath: string;
|
||||
@@ -59,11 +55,6 @@ export interface Template {
|
||||
plugin?: boolean;
|
||||
backendModulePrefix?: boolean;
|
||||
suffix?: string;
|
||||
prompts?: ConfigurablePrompt[];
|
||||
prompts?: NewTemplatePrompt[];
|
||||
additionalActions?: string[];
|
||||
}
|
||||
|
||||
export interface TemplateLocation {
|
||||
id: string;
|
||||
target: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user