mirror of
https://github.com/strapi/strapi.git
synced 2025-11-03 11:25:17 +00:00
Merge pull request #19053 from strapi/upgrade-tool/chores
This commit is contained in:
commit
9fbf22643f
@ -49,8 +49,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@strapi/pack-up": "4.15.5",
|
||||
"@strapi/plugin-upload": "4.15.5",
|
||||
"@types/jest": "29.5.2",
|
||||
"eslint-config-custom": "4.15.5",
|
||||
"memfs": "4.6.0",
|
||||
"tsconfig": "4.15.5"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@ -1,22 +1,20 @@
|
||||
/* eslint-disable import/first */
|
||||
import { fs } from 'memfs';
|
||||
|
||||
jest.mock('fs', () => fs);
|
||||
|
||||
import fse from 'fs-extra';
|
||||
|
||||
import type { File } from '@strapi/plugin-upload';
|
||||
|
||||
import localProvider from '../index';
|
||||
|
||||
jest.mock('fs', () => {
|
||||
return {
|
||||
writeFile: jest.fn((_path, _buffer, callback) => callback()),
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('fs-extra', () => {
|
||||
return {
|
||||
pathExistsSync: jest.fn(() => true),
|
||||
};
|
||||
});
|
||||
|
||||
describe('Local provider', () => {
|
||||
beforeAll(() => {
|
||||
globalThis.strapi = {};
|
||||
globalThis.strapi.dirs = { static: { public: '' } };
|
||||
|
||||
fse.ensureDirSync('uploads');
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
|
||||
@ -8,12 +8,28 @@ import type { Command } from '../types';
|
||||
|
||||
export const upgrade: Command = async (options) => {
|
||||
try {
|
||||
const logger = loggerFactory({ silent: options.silent, debug: options.debug });
|
||||
const { silent, debug, yes } = options;
|
||||
const logger = loggerFactory({ silent, debug });
|
||||
|
||||
logger.warn(
|
||||
"Please make sure you've created a backup of your codebase and files before upgrading"
|
||||
);
|
||||
|
||||
const confirm = async (message: string) => {
|
||||
if (yes) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { confirm } = await prompts({
|
||||
name: 'confirm',
|
||||
type: 'confirm',
|
||||
message,
|
||||
});
|
||||
|
||||
// If confirm is undefined (Ctrl + C), default to false
|
||||
return confirm ?? false;
|
||||
};
|
||||
|
||||
await tasks.upgrade({
|
||||
logger,
|
||||
confirm,
|
||||
@ -25,14 +41,3 @@ export const upgrade: Command = async (options) => {
|
||||
handleError(err);
|
||||
}
|
||||
};
|
||||
|
||||
const confirm = async (message: string) => {
|
||||
const { confirm } = await prompts({
|
||||
name: 'confirm',
|
||||
type: 'confirm',
|
||||
message,
|
||||
});
|
||||
|
||||
// If confirm is undefined (Ctrl + C), default to false
|
||||
return confirm ?? false;
|
||||
};
|
||||
|
||||
@ -15,6 +15,11 @@ const addReleaseUpgradeCommand = (releaseType: Version.ReleaseType, description:
|
||||
.option('-n, --dry', 'Simulate the upgrade without updating any files', false)
|
||||
.option('-d, --debug', 'Get more logs in debug mode', false)
|
||||
.option('-s, --silent', "Don't log anything", false)
|
||||
.option(
|
||||
'-y, --yes',
|
||||
'Automatically answer "yes" to any prompts that the CLI might print on the command line.',
|
||||
false
|
||||
)
|
||||
.action(async (options: CLIOptions) => {
|
||||
const { upgrade } = await import('./commands/upgrade.js');
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ export interface CLIOptions {
|
||||
dry: boolean;
|
||||
debug: boolean;
|
||||
silent: boolean;
|
||||
yes: boolean;
|
||||
|
||||
projectPath?: string;
|
||||
}
|
||||
|
||||
@ -5,19 +5,22 @@ import { constants as timerConstants } from '../timer';
|
||||
|
||||
import type { Version } from '../version';
|
||||
import type { Report } from '../report';
|
||||
import { isSemVer } from '../version';
|
||||
|
||||
export const path = (path: string) => chalk.blue(path);
|
||||
|
||||
export const version = (version: Version.LiteralVersion | Version.SemVer) => {
|
||||
return chalk.italic.yellow(isSemVer(version) ? version.raw : version);
|
||||
return chalk.italic.yellow(`v${version}`);
|
||||
};
|
||||
|
||||
export const versionRange = (range: string) => chalk.bold.green(range);
|
||||
export const versionRange = (range: Version.Range) => chalk.italic.yellow(range);
|
||||
|
||||
export const transform = (transformFilePath: string) => chalk.cyan(transformFilePath);
|
||||
|
||||
export const highlight = (text: string) => chalk.bold.underline(text);
|
||||
export const highlight = (arg: unknown) => chalk.bold.underline(arg);
|
||||
|
||||
export const upgradeStep = (text: string, step: [current: number, total: number]) => {
|
||||
return chalk.bold(`(${step[0]}/${step[1]}) ${text}...`);
|
||||
};
|
||||
|
||||
export const reports = (reports: Report.CodemodReport[]) => {
|
||||
const rows = reports.map(({ codemod, report }, i) => {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import assert from 'node:assert';
|
||||
import chalk from 'chalk';
|
||||
import { packageManager } from '@strapi/utils';
|
||||
|
||||
import {
|
||||
@ -21,9 +22,9 @@ import type { Project } from '../project';
|
||||
type DependenciesEntries = Array<[name: string, version: Version.LiteralSemVer]>;
|
||||
|
||||
export class Upgrader implements UpgraderInterface {
|
||||
private project: Project;
|
||||
private readonly project: Project;
|
||||
|
||||
private npmPackage: NPM.Package;
|
||||
private readonly npmPackage: NPM.Package;
|
||||
|
||||
private target: Version.SemVer;
|
||||
|
||||
@ -79,19 +80,37 @@ export class Upgrader implements UpgraderInterface {
|
||||
}
|
||||
|
||||
async upgrade(): Promise<UpgradeReport> {
|
||||
if (this.isDry) {
|
||||
this.logger?.warn(
|
||||
'Running the upgrade in dry mode. No files will be modified during the process.'
|
||||
);
|
||||
}
|
||||
this.logger?.debug(
|
||||
`Upgrading from ${f.version(this.project.strapiVersion)} to ${f.version(this.target)}`
|
||||
);
|
||||
|
||||
const range = rangeFromVersions(this.project.strapiVersion, this.target);
|
||||
const npmVersionsMatches = this.npmPackage?.findVersionsInRange(range) ?? [];
|
||||
|
||||
this.logger?.debug(
|
||||
`Found ${f.highlight(npmVersionsMatches.length)} versions satisfying ${f.versionRange(range)}`
|
||||
);
|
||||
|
||||
try {
|
||||
this.logger?.info(f.upgradeStep('Checking requirement', [1, 4]));
|
||||
await this.checkRequirements(this.requirements, {
|
||||
npmVersionsMatches,
|
||||
project: this.project,
|
||||
target: this.target,
|
||||
});
|
||||
|
||||
this.logger?.info(f.upgradeStep('Upgrading Strapi dependencies', [2, 4]));
|
||||
await this.updateDependencies();
|
||||
|
||||
this.logger?.info(f.upgradeStep('Installing dependencies', [3, 4]));
|
||||
await this.installDependencies();
|
||||
|
||||
this.logger?.info(f.upgradeStep('Applying the latest code modifications', [4, 4]));
|
||||
await this.runCodemods(range);
|
||||
} catch (e) {
|
||||
return erroredReport(unknownToError(e));
|
||||
@ -130,8 +149,11 @@ export class Upgrader implements UpgraderInterface {
|
||||
requirement: Requirement.Requirement,
|
||||
originalError: Error
|
||||
): Promise<void> {
|
||||
const errorMessage = `Upgrade requirement "${requirement.name}" failed: ${originalError.message}`;
|
||||
const confirmationMessage = `Optional requirement "${requirement.name}" failed with "${originalError.message}", do you want to proceed anyway?`;
|
||||
const errorMessage = `Requirement failed: ${originalError.message} (${f.highlight(
|
||||
requirement.name
|
||||
)})`;
|
||||
const warningMessage = originalError.message;
|
||||
const confirmationMessage = `Ignore optional requirement "${f.highlight(requirement.name)}" ?`;
|
||||
|
||||
const error = new Error(errorMessage);
|
||||
|
||||
@ -139,13 +161,13 @@ export class Upgrader implements UpgraderInterface {
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.logger?.warn(warningMessage);
|
||||
|
||||
const response = await this.confirmationCallback?.(confirmationMessage);
|
||||
|
||||
if (!response) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.logger?.warn(errorMessage);
|
||||
}
|
||||
|
||||
private async updateDependencies(): Promise<void> {
|
||||
@ -156,6 +178,11 @@ export class Upgrader implements UpgraderInterface {
|
||||
const dependencies = json.get<Record<string, string>>('dependencies', {});
|
||||
const strapiDependencies = this.getScopedStrapiDependencies(dependencies);
|
||||
|
||||
this.logger?.debug(`Found ${f.highlight(strapiDependencies.length)} dependency(ies) to update`);
|
||||
strapiDependencies.forEach((dependency) =>
|
||||
this.logger?.debug(`- ${dependency[0]} (${dependency[1]} -> ${this.target})`)
|
||||
);
|
||||
|
||||
if (strapiDependencies.length === 0) {
|
||||
return;
|
||||
}
|
||||
@ -164,9 +191,12 @@ export class Upgrader implements UpgraderInterface {
|
||||
|
||||
const updatedPackageJSON = json.root();
|
||||
|
||||
if (!this.isDry) {
|
||||
await saveJSON(packageJSONPath, updatedPackageJSON);
|
||||
if (this.isDry) {
|
||||
this.logger?.debug(`Skipping dependencies update (${chalk.italic('dry mode')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await saveJSON(packageJSONPath, updatedPackageJSON);
|
||||
}
|
||||
|
||||
private getScopedStrapiDependencies(dependencies: Record<string, string>): DependenciesEntries {
|
||||
@ -192,6 +222,13 @@ export class Upgrader implements UpgraderInterface {
|
||||
|
||||
const packageManagerName = await packageManager.getPreferred(projectPath);
|
||||
|
||||
this.logger?.debug(`Using ${f.highlight(packageManagerName)} as package manager`);
|
||||
|
||||
if (this.isDry) {
|
||||
this.logger?.debug(`Skipping dependencies installation (${chalk.italic('dry mode')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await packageManager.installDependencies(projectPath, packageManagerName, {
|
||||
stdout: this.logger?.stdout,
|
||||
stderr: this.logger?.stderr,
|
||||
@ -210,10 +247,15 @@ export class Upgrader implements UpgraderInterface {
|
||||
|
||||
const hasCodemodsToRun = versionedCodemods.length > 0;
|
||||
if (!hasCodemodsToRun) {
|
||||
this.logger?.debug(`Found no codemods to run for ${this.target}`);
|
||||
this.logger?.debug(`Found no codemods to run for ${f.version(this.target)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger?.debug(`Found codemods for ${f.highlight(versionedCodemods.length)} version(s)`);
|
||||
versionedCodemods.forEach(({ version, codemods }) =>
|
||||
this.logger?.debug(`- ${f.version(version)} (${codemods.length})`)
|
||||
);
|
||||
|
||||
// Flatten the collection to a single list of codemods, the original list should already be sorted
|
||||
const codemods = versionedCodemods.map(({ codemods }) => codemods).flat();
|
||||
|
||||
@ -234,12 +276,14 @@ export const upgraderFactory = (
|
||||
// The targeted version is the latest one that matches the given range
|
||||
const targetedNPMVersion = npmVersionsMatches.at(-1);
|
||||
|
||||
assert(targetedNPMVersion, `No available version found for ${range}`);
|
||||
assert(targetedNPMVersion, `Could not find any version in the range ${f.versionRange(range)}`);
|
||||
|
||||
// Make sure the latest version matched in the range is the same as the targeted one (only if target is a semver)
|
||||
if (isSemVer(target) && target.raw !== targetedNPMVersion.version) {
|
||||
throw new Error(
|
||||
`${target} doesn't exist on the registry. Closest one found is ${targetedNPMVersion.version}`
|
||||
`${f.version(target)} doesn't exist on the registry. Closest version found is ${
|
||||
targetedNPMVersion.version
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -28,8 +28,8 @@ export const upgrade = async (options: UpgradeOptions) => {
|
||||
|
||||
if (options.target === Version.ReleaseType.Major) {
|
||||
upgrader
|
||||
.addRequirement(requirements.major.REQUIRE_AVAILABLE_NEXT_MAJOR.asOptional())
|
||||
.addRequirement(requirements.major.REQUIRE_LATEST_FOR_CURRENT_MAJOR.asOptional());
|
||||
.addRequirement(requirements.major.REQUIRE_AVAILABLE_NEXT_MAJOR)
|
||||
.addRequirement(requirements.major.REQUIRE_LATEST_FOR_CURRENT_MAJOR);
|
||||
}
|
||||
|
||||
upgrader.addRequirement(requirements.common.REQUIRE_GIT.asOptional());
|
||||
|
||||
@ -9790,10 +9790,12 @@ __metadata:
|
||||
resolution: "@strapi/provider-upload-local@workspace:packages/providers/upload-local"
|
||||
dependencies:
|
||||
"@strapi/pack-up": "npm:4.15.5"
|
||||
"@strapi/plugin-upload": "npm:4.15.5"
|
||||
"@strapi/utils": "npm:4.15.5"
|
||||
"@types/jest": "npm:29.5.2"
|
||||
eslint-config-custom: "npm:4.15.5"
|
||||
fs-extra: "npm:10.1.0"
|
||||
memfs: "npm:4.6.0"
|
||||
tsconfig: "npm:4.15.5"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user