From 71336319ddb3a47af8fe3d923cd3f16b50e2bc4f Mon Sep 17 00:00:00 2001 From: Convly Date: Fri, 12 Jan 2024 15:14:28 +0100 Subject: [PATCH] feat: update commands' types, add a hidden "to" command with a codemod target option --- .../upgrade/src/cli/commands/codemods.ts | 9 ++-- .../utils/upgrade/src/cli/commands/upgrade.ts | 7 +-- packages/utils/upgrade/src/cli/errors.ts | 13 +++-- packages/utils/upgrade/src/cli/index.ts | 48 ++++++++++++++++--- packages/utils/upgrade/src/cli/types.ts | 42 ++++++++++++---- 5 files changed, 91 insertions(+), 28 deletions(-) diff --git a/packages/utils/upgrade/src/cli/commands/codemods.ts b/packages/utils/upgrade/src/cli/commands/codemods.ts index 5ec3d69cad..d85d59976d 100644 --- a/packages/utils/upgrade/src/cli/commands/codemods.ts +++ b/packages/utils/upgrade/src/cli/commands/codemods.ts @@ -1,12 +1,13 @@ import prompts from 'prompts'; import { loggerFactory } from '../../modules/logger'; +import { Version } from '../../modules/version'; import { handleError } from '../errors'; import * as tasks from '../../tasks'; -import type { Command } from '../types'; +import type { CodemodsCommand } from '../types'; import type { Codemod } from '../../modules/codemod'; -export const codemods: Command = async (options) => { +export const codemods: CodemodsCommand = async (options) => { try { const { silent, debug } = options; const logger = loggerFactory({ silent, debug }); @@ -66,9 +67,9 @@ export const codemods: Command = async (options) => { selectCodemods, dry: options.dry, cwd: options.projectPath, - target: options.target, + target: Version.ReleaseType.Major, }); } catch (err) { - handleError(err); + handleError(err, options.silent); } }; diff --git a/packages/utils/upgrade/src/cli/commands/upgrade.ts b/packages/utils/upgrade/src/cli/commands/upgrade.ts index 1c99a627e1..12fadb99b7 100644 --- a/packages/utils/upgrade/src/cli/commands/upgrade.ts +++ b/packages/utils/upgrade/src/cli/commands/upgrade.ts @@ -4,9 +4,9 @@ import { loggerFactory } from '../../modules/logger'; import { handleError } from '../errors'; import * as tasks from '../../tasks'; -import type { Command } from '../types'; +import type { UpgradeCommand } from '../types'; -export const upgrade: Command = async (options) => { +export const upgrade: UpgradeCommand = async (options) => { try { const { silent, debug, yes } = options; const logger = loggerFactory({ silent, debug }); @@ -36,8 +36,9 @@ export const upgrade: Command = async (options) => { dry: options.dry, cwd: options.projectPath, target: options.target, + codemodsTarget: options.codemodsTarget, }); } catch (err) { - handleError(err); + handleError(err, options.silent); } }; diff --git a/packages/utils/upgrade/src/cli/errors.ts b/packages/utils/upgrade/src/cli/errors.ts index 192ba37e40..ab503cc892 100644 --- a/packages/utils/upgrade/src/cli/errors.ts +++ b/packages/utils/upgrade/src/cli/errors.ts @@ -1,9 +1,12 @@ import chalk from 'chalk'; -export const handleError = (err: unknown) => { - console.error( - chalk.red(`[ERROR]\t[${new Date().toISOString()}]`), - err instanceof Error ? err.message : err - ); +export const handleError = (err: unknown, isSilent: boolean) => { + if (!isSilent) { + console.error( + chalk.red(`[ERROR]\t[${new Date().toISOString()}]`), + err instanceof Error ? err.message : err + ); + } + process.exit(1); }; diff --git a/packages/utils/upgrade/src/cli/index.ts b/packages/utils/upgrade/src/cli/index.ts index cfc69c018e..75ebcc1f9d 100644 --- a/packages/utils/upgrade/src/cli/index.ts +++ b/packages/utils/upgrade/src/cli/index.ts @@ -1,11 +1,11 @@ import os from 'os'; import chalk from 'chalk'; -import { Option, program } from 'commander'; +import { InvalidArgumentError, Option, program } from 'commander'; import { version as packageJSONVersion } from '../../package.json'; -import { Version } from '../modules/version'; +import { isLiteralSemVer, isValidSemVer, semVerFactory, Version } from '../modules/version'; -import type { CLIOptions } from './types'; +import type { CLICodemodsOptions, CLIUpgradeOptions, CLIUpgradeToOptions } from './types'; const projectPathOption = new Option( '-p, --project-path ', @@ -35,7 +35,7 @@ const addReleaseUpgradeCommand = (releaseType: Version.ReleaseType, description: .addOption(debugOption) .addOption(silentOption) .addOption(automaticConfirmationOption) - .action(async (options: CLIOptions) => { + .action(async (options: CLIUpgradeOptions) => { const { upgrade } = await import('./commands/upgrade.js'); return upgrade({ ...options, target: releaseType }); @@ -66,9 +66,45 @@ program .addOption(dryOption) .addOption(debugOption) .addOption(silentOption) - .action(async (options) => { + .action(async (options: CLICodemodsOptions) => { const { codemods } = await import('./commands/codemods.js'); - return codemods({ ...options, target: Version.ReleaseType.Major }); + return codemods(options); + }); + +// Defines the 'to' command to upgrade to a specific Strapi version, +// with various options including custom codemod target. +// This command is meant for internal use for now (and is thus hidden) +program + .command('to ', { hidden: true }) + .description('Upgrade to the specified version of Strapi') + .addOption(projectPathOption) + .addOption(dryOption) + .addOption(debugOption) + .addOption(silentOption) + .addOption(automaticConfirmationOption) + .addOption( + new Option( + '-c, --codemods-target ', + 'Use a custom target for the codemods execution. Useful when targeting pre-releases' + ).argParser((codemodsTarget) => { + if (!isLiteralSemVer(codemodsTarget)) { + throw new InvalidArgumentError( + `Expected a version with the following format: ".."` + ); + } + + return semVerFactory(codemodsTarget); + }) + ) + .action(async (target: string, options: CLIUpgradeToOptions) => { + if (!isValidSemVer(target)) { + console.error(`Invalid target supplied, expected a valid semver but got "${target}"`); + process.exit(1); + } + + const { upgrade } = await import('./commands/upgrade.js'); + + return upgrade({ ...options, target: semVerFactory(target) }); }); program diff --git a/packages/utils/upgrade/src/cli/types.ts b/packages/utils/upgrade/src/cli/types.ts index b7baf9272d..55bd9e971a 100644 --- a/packages/utils/upgrade/src/cli/types.ts +++ b/packages/utils/upgrade/src/cli/types.ts @@ -1,16 +1,38 @@ import type { Version } from '../modules/version'; import type { MaybePromise } from '../types'; -export interface CLIOptions { - dry: boolean; - debug: boolean; - silent: boolean; - yes?: boolean; - projectPath?: string; +// CLI + +type DryOption = { dry: boolean }; +type DebugOption = { debug: boolean }; +type SilentOption = { silent: boolean }; +type YesOption = { yes?: boolean }; +type ProjectPathOption = { projectPath?: string }; + +export type CLIUpgradeOptions = DryOption & + DebugOption & + SilentOption & + YesOption & + ProjectPathOption; + +export type CLIUpgradeToOptions = CLIUpgradeOptions & { + codemodsTarget?: Version.SemVer; +}; + +export type CLICodemodsOptions = DryOption & DebugOption & SilentOption & ProjectPathOption; + +// COMMANDS OPTIONS + +export interface UpgradeCommandOptions extends CLIUpgradeOptions { + target: Version.ReleaseType | Version.SemVer; + codemodsTarget?: Version.SemVer; } -export interface CommandOptions extends CLIOptions { - target: Version.ReleaseType; -} +export interface CodemodsCommandOptions extends CLICodemodsOptions {} -export type Command = (options: CommandOptions) => MaybePromise; +// COMMANDS + +export type Command = (options: TOptions) => MaybePromise; + +export type UpgradeCommand = Command; +export type CodemodsCommand = Command;