Skip to content

Commit 5bdd7df

Browse files
dreyfus9243081j
andauthored
feat: add --all flag to migrate command (#160)
* feat: add --all flag to migrate command * format * refactor: update migration command output messages * format * refactor: remove log message for no fixable replacements in migrate command * refactor: simplify test for migrate --all command by using a fixture * format --------- Co-authored-by: James Garbutt <43081j@users.noreply.github.com>
1 parent 73c194a commit 5bdd7df

File tree

3 files changed

+77
-19
lines changed

3 files changed

+77
-19
lines changed

src/commands/migrate.meta.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ export const meta = {
22
name: 'migrate',
33
description: 'Migrate from a package to a more performant alternative.',
44
args: {
5+
all: {
6+
type: 'boolean',
7+
default: false,
8+
description:
9+
'Migrate all fixable replacements that exist in project dependencies.'
10+
},
511
'dry-run': {
612
type: 'boolean',
713
default: false,

src/commands/migrate.ts

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {getPackageJson} from '../utils/package-json.js';
1111

1212
export async function run(ctx: CommandContext<typeof meta>) {
1313
const [_commandName, ...targetModules] = ctx.positionals;
14+
const all = ctx.values.all === true;
1415
const dryRun = ctx.values['dry-run'] === true;
1516
const interactive = ctx.values.interactive === true;
1617
const include = ctx.values.include;
@@ -37,7 +38,7 @@ export async function run(ctx: CommandContext<typeof meta>) {
3738
.map((rep) => rep.from)
3839
);
3940

40-
if (interactive) {
41+
if (interactive && !all) {
4142
const additionalTargets = await prompts.autocompleteMultiselect({
4243
message: 'Select packages to migrate',
4344
maxItems: 10,
@@ -60,34 +61,50 @@ export async function run(ctx: CommandContext<typeof meta>) {
6061
}
6162
}
6263

63-
if (targetModules.length === 0) {
64-
prompts.cancel(
65-
'Error: Please specify a package to migrate. For example, `migrate chalk`'
66-
);
67-
return;
68-
}
64+
let selectedReplacements: Replacement[];
6965

70-
const selectedReplacements: Replacement[] = [];
71-
72-
for (const targetModule of targetModules) {
73-
const replacement = fixableReplacements.find(
74-
(rep) => rep.from === targetModule
66+
if (all) {
67+
selectedReplacements = fixableReplacements.filter((rep) =>
68+
fixableReplacementsTargets.has(rep.from)
7569
);
76-
if (!replacement) {
70+
} else {
71+
if (targetModules.length === 0) {
7772
prompts.cancel(
78-
`Error: Target package has no available migrations (${targetModule})`
73+
'Error: Please specify a package to migrate. For example, `migrate chalk`'
7974
);
8075
return;
8176
}
8277

83-
selectedReplacements.push(replacement);
78+
selectedReplacements = [];
79+
80+
for (const targetModule of targetModules) {
81+
if (!fixableReplacementsTargets.has(targetModule)) {
82+
prompts.cancel(
83+
`Error: Target package is not in project dependencies (${targetModule})`
84+
);
85+
return;
86+
}
87+
88+
const replacement = fixableReplacements.find(
89+
(rep) => rep.from === targetModule
90+
);
91+
if (!replacement) {
92+
prompts.cancel(
93+
`Error: Target package has no available migrations (${targetModule})`
94+
);
95+
return;
96+
}
97+
98+
selectedReplacements.push(replacement);
99+
}
84100
}
85101

86102
if (!interactive) {
103+
const targetNames = selectedReplacements.map((r) => r.from);
87104
const targetModuleSummary =
88-
targetModules.length > 6
89-
? `${targetModules.slice(0, 6).join(', ')} and ${targetModules.length - 6} more`
90-
: targetModules.join(', ');
105+
targetNames.length > 6
106+
? `${targetNames.slice(0, 6).join(', ')} and ${targetNames.length - 6} more`
107+
: targetNames.join(', ');
91108
prompts.log.message(`Targets: ${styleText('dim', targetModuleSummary)}`);
92109
}
93110

@@ -106,6 +123,8 @@ export async function run(ctx: CommandContext<typeof meta>) {
106123
return;
107124
}
108125

126+
let filesMigratedCount = 0;
127+
109128
for (const filename of files) {
110129
const log = prompts.taskLog({
111130
title: `${filename}...`,
@@ -140,10 +159,13 @@ export async function run(ctx: CommandContext<typeof meta>) {
140159
}
141160
totalMigrations++;
142161
}
162+
if (totalMigrations > 0) {
163+
filesMigratedCount++;
164+
}
143165
log.success(
144166
`${filename} ${styleText('dim', `(${totalMigrations} migrated)`)}`
145167
);
146168
}
147169

148-
prompts.outro('Migration complete.');
170+
prompts.outro(`Migration complete - ${filesMigratedCount} files migrated.`);
149171
}

src/test/cli.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,33 @@ describe('CLI', () => {
9393
expect(normalizeStderr(stderr)).toMatchSnapshot();
9494
});
9595
});
96+
97+
const basicChalkFixture = path.join(
98+
__dirname,
99+
'../../test/fixtures/basic-chalk'
100+
);
101+
102+
describe('migrate --all', () => {
103+
it('should migrate all fixable replacements with --all --dry-run when project has fixable deps', async () => {
104+
const {stdout, stderr, code} = await runCliProcess(
105+
['migrate', '--all', '--dry-run'],
106+
basicChalkFixture
107+
);
108+
expect(code).toBe(0);
109+
const output = stdout + stderr;
110+
expect(output).toContain('Migration complete');
111+
expect(output).toContain('files migrated');
112+
expect(output).toContain('chalk');
113+
});
114+
115+
it('should run to completion and show Migration complete when --all has no fixable replacements', async () => {
116+
const {stdout, stderr, code} = await runCliProcess(
117+
['migrate', '--all'],
118+
tempDir
119+
);
120+
const output = stdout + stderr;
121+
expect(code).toBe(0);
122+
expect(output).toContain('Migration complete');
123+
expect(output).toContain('0 files migrated');
124+
});
125+
});

0 commit comments

Comments
 (0)