mirror of
https://github.com/strapi/strapi.git
synced 2025-11-04 11:54:10 +00:00
Merge pull request #19053 from strapi/upgrade-tool/chores
This commit is contained in:
commit
9fbf22643f
@ -49,8 +49,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@strapi/pack-up": "4.15.5",
|
"@strapi/pack-up": "4.15.5",
|
||||||
|
"@strapi/plugin-upload": "4.15.5",
|
||||||
"@types/jest": "29.5.2",
|
"@types/jest": "29.5.2",
|
||||||
"eslint-config-custom": "4.15.5",
|
"eslint-config-custom": "4.15.5",
|
||||||
|
"memfs": "4.6.0",
|
||||||
"tsconfig": "4.15.5"
|
"tsconfig": "4.15.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"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 type { File } from '@strapi/plugin-upload';
|
||||||
|
|
||||||
import localProvider from '../index';
|
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', () => {
|
describe('Local provider', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
globalThis.strapi = {};
|
globalThis.strapi = {};
|
||||||
globalThis.strapi.dirs = { static: { public: '' } };
|
globalThis.strapi.dirs = { static: { public: '' } };
|
||||||
|
|
||||||
|
fse.ensureDirSync('uploads');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
|
|||||||
@ -8,12 +8,28 @@ import type { Command } from '../types';
|
|||||||
|
|
||||||
export const upgrade: Command = async (options) => {
|
export const upgrade: Command = async (options) => {
|
||||||
try {
|
try {
|
||||||
const logger = loggerFactory({ silent: options.silent, debug: options.debug });
|
const { silent, debug, yes } = options;
|
||||||
|
const logger = loggerFactory({ silent, debug });
|
||||||
|
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"Please make sure you've created a backup of your codebase and files before upgrading"
|
"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({
|
await tasks.upgrade({
|
||||||
logger,
|
logger,
|
||||||
confirm,
|
confirm,
|
||||||
@ -25,14 +41,3 @@ export const upgrade: Command = async (options) => {
|
|||||||
handleError(err);
|
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('-n, --dry', 'Simulate the upgrade without updating any files', false)
|
||||||
.option('-d, --debug', 'Get more logs in debug mode', false)
|
.option('-d, --debug', 'Get more logs in debug mode', false)
|
||||||
.option('-s, --silent', "Don't log anything", 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) => {
|
.action(async (options: CLIOptions) => {
|
||||||
const { upgrade } = await import('./commands/upgrade.js');
|
const { upgrade } = await import('./commands/upgrade.js');
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ export interface CLIOptions {
|
|||||||
dry: boolean;
|
dry: boolean;
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
silent: boolean;
|
silent: boolean;
|
||||||
|
yes: boolean;
|
||||||
|
|
||||||
projectPath?: string;
|
projectPath?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,19 +5,22 @@ import { constants as timerConstants } from '../timer';
|
|||||||
|
|
||||||
import type { Version } from '../version';
|
import type { Version } from '../version';
|
||||||
import type { Report } from '../report';
|
import type { Report } from '../report';
|
||||||
import { isSemVer } from '../version';
|
|
||||||
|
|
||||||
export const path = (path: string) => chalk.blue(path);
|
export const path = (path: string) => chalk.blue(path);
|
||||||
|
|
||||||
export const version = (version: Version.LiteralVersion | Version.SemVer) => {
|
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 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[]) => {
|
export const reports = (reports: Report.CodemodReport[]) => {
|
||||||
const rows = reports.map(({ codemod, report }, i) => {
|
const rows = reports.map(({ codemod, report }, i) => {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
|
import chalk from 'chalk';
|
||||||
import { packageManager } from '@strapi/utils';
|
import { packageManager } from '@strapi/utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -21,9 +22,9 @@ import type { Project } from '../project';
|
|||||||
type DependenciesEntries = Array<[name: string, version: Version.LiteralSemVer]>;
|
type DependenciesEntries = Array<[name: string, version: Version.LiteralSemVer]>;
|
||||||
|
|
||||||
export class Upgrader implements UpgraderInterface {
|
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;
|
private target: Version.SemVer;
|
||||||
|
|
||||||
@ -79,19 +80,37 @@ export class Upgrader implements UpgraderInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async upgrade(): Promise<UpgradeReport> {
|
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 range = rangeFromVersions(this.project.strapiVersion, this.target);
|
||||||
const npmVersionsMatches = this.npmPackage?.findVersionsInRange(range) ?? [];
|
const npmVersionsMatches = this.npmPackage?.findVersionsInRange(range) ?? [];
|
||||||
|
|
||||||
|
this.logger?.debug(
|
||||||
|
`Found ${f.highlight(npmVersionsMatches.length)} versions satisfying ${f.versionRange(range)}`
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
this.logger?.info(f.upgradeStep('Checking requirement', [1, 4]));
|
||||||
await this.checkRequirements(this.requirements, {
|
await this.checkRequirements(this.requirements, {
|
||||||
npmVersionsMatches,
|
npmVersionsMatches,
|
||||||
project: this.project,
|
project: this.project,
|
||||||
target: this.target,
|
target: this.target,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.logger?.info(f.upgradeStep('Upgrading Strapi dependencies', [2, 4]));
|
||||||
await this.updateDependencies();
|
await this.updateDependencies();
|
||||||
|
|
||||||
|
this.logger?.info(f.upgradeStep('Installing dependencies', [3, 4]));
|
||||||
await this.installDependencies();
|
await this.installDependencies();
|
||||||
|
|
||||||
|
this.logger?.info(f.upgradeStep('Applying the latest code modifications', [4, 4]));
|
||||||
await this.runCodemods(range);
|
await this.runCodemods(range);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return erroredReport(unknownToError(e));
|
return erroredReport(unknownToError(e));
|
||||||
@ -130,8 +149,11 @@ export class Upgrader implements UpgraderInterface {
|
|||||||
requirement: Requirement.Requirement,
|
requirement: Requirement.Requirement,
|
||||||
originalError: Error
|
originalError: Error
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const errorMessage = `Upgrade requirement "${requirement.name}" failed: ${originalError.message}`;
|
const errorMessage = `Requirement failed: ${originalError.message} (${f.highlight(
|
||||||
const confirmationMessage = `Optional requirement "${requirement.name}" failed with "${originalError.message}", do you want to proceed anyway?`;
|
requirement.name
|
||||||
|
)})`;
|
||||||
|
const warningMessage = originalError.message;
|
||||||
|
const confirmationMessage = `Ignore optional requirement "${f.highlight(requirement.name)}" ?`;
|
||||||
|
|
||||||
const error = new Error(errorMessage);
|
const error = new Error(errorMessage);
|
||||||
|
|
||||||
@ -139,13 +161,13 @@ export class Upgrader implements UpgraderInterface {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger?.warn(warningMessage);
|
||||||
|
|
||||||
const response = await this.confirmationCallback?.(confirmationMessage);
|
const response = await this.confirmationCallback?.(confirmationMessage);
|
||||||
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger?.warn(errorMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateDependencies(): Promise<void> {
|
private async updateDependencies(): Promise<void> {
|
||||||
@ -156,6 +178,11 @@ export class Upgrader implements UpgraderInterface {
|
|||||||
const dependencies = json.get<Record<string, string>>('dependencies', {});
|
const dependencies = json.get<Record<string, string>>('dependencies', {});
|
||||||
const strapiDependencies = this.getScopedStrapiDependencies(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) {
|
if (strapiDependencies.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -164,9 +191,12 @@ export class Upgrader implements UpgraderInterface {
|
|||||||
|
|
||||||
const updatedPackageJSON = json.root();
|
const updatedPackageJSON = json.root();
|
||||||
|
|
||||||
if (!this.isDry) {
|
if (this.isDry) {
|
||||||
await saveJSON(packageJSONPath, updatedPackageJSON);
|
this.logger?.debug(`Skipping dependencies update (${chalk.italic('dry mode')}`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await saveJSON(packageJSONPath, updatedPackageJSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getScopedStrapiDependencies(dependencies: Record<string, string>): DependenciesEntries {
|
private getScopedStrapiDependencies(dependencies: Record<string, string>): DependenciesEntries {
|
||||||
@ -192,6 +222,13 @@ export class Upgrader implements UpgraderInterface {
|
|||||||
|
|
||||||
const packageManagerName = await packageManager.getPreferred(projectPath);
|
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, {
|
await packageManager.installDependencies(projectPath, packageManagerName, {
|
||||||
stdout: this.logger?.stdout,
|
stdout: this.logger?.stdout,
|
||||||
stderr: this.logger?.stderr,
|
stderr: this.logger?.stderr,
|
||||||
@ -210,10 +247,15 @@ export class Upgrader implements UpgraderInterface {
|
|||||||
|
|
||||||
const hasCodemodsToRun = versionedCodemods.length > 0;
|
const hasCodemodsToRun = versionedCodemods.length > 0;
|
||||||
if (!hasCodemodsToRun) {
|
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;
|
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
|
// Flatten the collection to a single list of codemods, the original list should already be sorted
|
||||||
const codemods = versionedCodemods.map(({ codemods }) => codemods).flat();
|
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
|
// The targeted version is the latest one that matches the given range
|
||||||
const targetedNPMVersion = npmVersionsMatches.at(-1);
|
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)
|
// 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) {
|
if (isSemVer(target) && target.raw !== targetedNPMVersion.version) {
|
||||||
throw new Error(
|
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) {
|
if (options.target === Version.ReleaseType.Major) {
|
||||||
upgrader
|
upgrader
|
||||||
.addRequirement(requirements.major.REQUIRE_AVAILABLE_NEXT_MAJOR.asOptional())
|
.addRequirement(requirements.major.REQUIRE_AVAILABLE_NEXT_MAJOR)
|
||||||
.addRequirement(requirements.major.REQUIRE_LATEST_FOR_CURRENT_MAJOR.asOptional());
|
.addRequirement(requirements.major.REQUIRE_LATEST_FOR_CURRENT_MAJOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
upgrader.addRequirement(requirements.common.REQUIRE_GIT.asOptional());
|
upgrader.addRequirement(requirements.common.REQUIRE_GIT.asOptional());
|
||||||
|
|||||||
@ -9790,10 +9790,12 @@ __metadata:
|
|||||||
resolution: "@strapi/provider-upload-local@workspace:packages/providers/upload-local"
|
resolution: "@strapi/provider-upload-local@workspace:packages/providers/upload-local"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@strapi/pack-up": "npm:4.15.5"
|
"@strapi/pack-up": "npm:4.15.5"
|
||||||
|
"@strapi/plugin-upload": "npm:4.15.5"
|
||||||
"@strapi/utils": "npm:4.15.5"
|
"@strapi/utils": "npm:4.15.5"
|
||||||
"@types/jest": "npm:29.5.2"
|
"@types/jest": "npm:29.5.2"
|
||||||
eslint-config-custom: "npm:4.15.5"
|
eslint-config-custom: "npm:4.15.5"
|
||||||
fs-extra: "npm:10.1.0"
|
fs-extra: "npm:10.1.0"
|
||||||
|
memfs: "npm:4.6.0"
|
||||||
tsconfig: "npm:4.15.5"
|
tsconfig: "npm:4.15.5"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user