@grafana/create-plugin 6.2.0-canary.2233.19133609453.0 → 6.2.0-canary.2233.19368311379.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/CONTRIBUTING.md +3 -0
- package/dist/codemods/additions/additions.js +8 -8
- package/dist/codemods/additions/scripts/example-addition.js +19 -33
- package/dist/codemods/migrations/manager.js +13 -40
- package/dist/codemods/migrations/migrations.js +34 -25
- package/dist/codemods/migrations/scripts/004-eslint9-flat-config.js +1 -2
- package/dist/codemods/migrations/scripts/005-react-18-3.js +20 -0
- package/dist/codemods/migrations/scripts/example-migration.js +7 -3
- package/dist/codemods/runner.js +38 -0
- package/dist/codemods/schema-parser.js +20 -0
- package/dist/codemods/utils.js +15 -6
- package/dist/commands/add.command.js +24 -55
- package/dist/commands/update.command.js +7 -41
- package/dist/utils/utils.checks.js +40 -0
- package/dist/utils/utils.config.js +1 -16
- package/package.json +3 -2
- package/src/codemods/additions/additions.test.ts +12 -0
- package/src/codemods/additions/additions.ts +9 -22
- package/src/codemods/additions/scripts/example-addition.test.ts +14 -33
- package/src/codemods/additions/scripts/example-addition.ts +27 -44
- package/src/codemods/migrations/fixtures/migrations.ts +19 -18
- package/src/codemods/migrations/manager.test.ts +67 -73
- package/src/codemods/migrations/manager.ts +17 -50
- package/src/codemods/migrations/migrations.test.ts +8 -5
- package/src/codemods/migrations/migrations.ts +38 -34
- package/src/codemods/migrations/scripts/004-eslint9-flat-config.ts +2 -2
- package/src/codemods/migrations/scripts/005-react-18-3.test.ts +145 -0
- package/src/codemods/migrations/scripts/005-react-18-3.ts +19 -0
- package/src/codemods/migrations/scripts/example-migration.test.ts +1 -1
- package/src/codemods/migrations/scripts/example-migration.ts +20 -3
- package/src/codemods/runner.ts +57 -0
- package/src/codemods/schema-parser.ts +27 -0
- package/src/codemods/types.ts +9 -14
- package/src/codemods/{migrations/utils.test.ts → utils.test.ts} +8 -7
- package/src/codemods/utils.ts +28 -36
- package/src/commands/add.command.ts +26 -62
- package/src/commands/update.command.ts +8 -47
- package/src/migrations/migrations.ts +44 -0
- package/src/utils/utils.checks.ts +47 -0
- package/src/utils/utils.config.ts +1 -28
- package/templates/common/_package.json +7 -5
- package/templates/github/workflows/bundle-stats.yml +1 -1
- package/templates/github/workflows/ci.yml +11 -11
- package/templates/github/workflows/cp-update.yml +9 -14
- package/templates/github/workflows/is-compatible.yml +3 -3
- package/templates/github/workflows/release.yml +1 -1
- package/vitest.config.ts +12 -0
- package/dist/codemods/additions/manager.js +0 -115
- package/dist/codemods/additions/utils.js +0 -10
- package/dist/codemods/migrations/utils.js +0 -10
- package/src/codemods/additions/manager.ts +0 -145
- package/src/codemods/additions/utils.ts +0 -12
- package/src/codemods/migrations/utils.ts +0 -12
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import { flushChanges, formatFiles } from '../utils.js';
|
|
2
|
-
import { getMigrationsToRun,
|
|
1
|
+
import { flushChanges, formatFiles, printChanges } from '../utils.js';
|
|
2
|
+
import { getMigrationsToRun, runMigrations } from './manager.js';
|
|
3
3
|
|
|
4
4
|
import { Context } from '../context.js';
|
|
5
|
-
import {
|
|
5
|
+
import { Migration } from './migrations.js';
|
|
6
6
|
import { gitCommitNoVerify } from '../../utils/utils.git.js';
|
|
7
7
|
import migrationFixtures from './fixtures/migrations.js';
|
|
8
|
-
import { printChanges } from './utils.js';
|
|
9
8
|
import { setRootConfig } from '../../utils/utils.config.js';
|
|
10
9
|
import { vi } from 'vitest';
|
|
11
10
|
|
|
12
|
-
vi.mock('
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
vi.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
})
|
|
11
|
+
vi.mock('../utils.js', async (importOriginal) => {
|
|
12
|
+
const actual = (await importOriginal()) as any;
|
|
13
|
+
return {
|
|
14
|
+
...actual,
|
|
15
|
+
flushChanges: vi.fn(),
|
|
16
|
+
formatFiles: vi.fn(),
|
|
17
|
+
installNPMDependencies: vi.fn(),
|
|
18
|
+
printChanges: vi.fn(),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
22
21
|
|
|
23
22
|
// Silence terminal output during tests.
|
|
24
23
|
vi.mock('../../utils/utils.console.js', () => ({
|
|
@@ -50,92 +49,83 @@ describe('Migrations', () => {
|
|
|
50
49
|
it('should return the migrations that need to be run', () => {
|
|
51
50
|
const fromVersion = '3.0.0';
|
|
52
51
|
const toVersion = '5.0.0';
|
|
53
|
-
const migrations = getMigrationsToRun(fromVersion, toVersion, migrationFixtures
|
|
54
|
-
expect(migrations).toEqual(
|
|
55
|
-
|
|
52
|
+
const migrations = getMigrationsToRun(fromVersion, toVersion, migrationFixtures);
|
|
53
|
+
expect(migrations).toEqual([
|
|
54
|
+
{
|
|
55
|
+
name: 'migration-key1',
|
|
56
56
|
version: '5.0.0',
|
|
57
57
|
description: 'Update project to use new cache directory',
|
|
58
|
-
|
|
58
|
+
scriptPath: './5-0-0-cache-directory.js',
|
|
59
59
|
},
|
|
60
|
-
|
|
60
|
+
]);
|
|
61
61
|
|
|
62
62
|
const fromVersion2 = '5.0.0';
|
|
63
63
|
const toVersion2 = '5.5.0';
|
|
64
|
-
const migrations2 = getMigrationsToRun(fromVersion2, toVersion2, migrationFixtures
|
|
65
|
-
expect(migrations2).toEqual(
|
|
66
|
-
|
|
64
|
+
const migrations2 = getMigrationsToRun(fromVersion2, toVersion2, migrationFixtures);
|
|
65
|
+
expect(migrations2).toEqual([
|
|
66
|
+
{
|
|
67
|
+
name: 'migration-key1',
|
|
67
68
|
version: '5.0.0',
|
|
68
69
|
description: 'Update project to use new cache directory',
|
|
69
|
-
|
|
70
|
+
scriptPath: './5-0-0-cache-directory.js',
|
|
70
71
|
},
|
|
71
|
-
|
|
72
|
+
{
|
|
73
|
+
name: 'migration-key2',
|
|
72
74
|
version: '5.4.0',
|
|
73
75
|
description: 'Update project to use new cache directory',
|
|
74
|
-
|
|
76
|
+
scriptPath: './5-4-0-cache-directory.js',
|
|
75
77
|
},
|
|
76
|
-
|
|
78
|
+
]);
|
|
77
79
|
|
|
78
80
|
const fromVersion3 = '5.5.0';
|
|
79
81
|
const toVersion3 = '6.0.0';
|
|
80
|
-
const migrations3 = getMigrationsToRun(fromVersion3, toVersion3, migrationFixtures
|
|
81
|
-
expect(migrations3).toEqual(
|
|
82
|
-
|
|
82
|
+
const migrations3 = getMigrationsToRun(fromVersion3, toVersion3, migrationFixtures);
|
|
83
|
+
expect(migrations3).toEqual([
|
|
84
|
+
{
|
|
85
|
+
name: 'migration-key3',
|
|
83
86
|
version: '6.0.0',
|
|
84
87
|
description: 'Update project to use new cache directory',
|
|
85
|
-
|
|
88
|
+
scriptPath: './5-4-0-cache-directory.js',
|
|
86
89
|
},
|
|
87
|
-
|
|
90
|
+
]);
|
|
88
91
|
});
|
|
89
92
|
|
|
90
93
|
it('should sort migrations by version', () => {
|
|
91
94
|
const fromVersion = '2.0.0';
|
|
92
95
|
const toVersion = '6.0.0';
|
|
93
|
-
const migrations = getMigrationsToRun(fromVersion, toVersion,
|
|
94
|
-
|
|
96
|
+
const migrations = getMigrationsToRun(fromVersion, toVersion, [
|
|
97
|
+
{
|
|
98
|
+
name: 'migration-key1',
|
|
95
99
|
version: '5.3.0',
|
|
96
100
|
description: 'Update project to use new cache directory',
|
|
97
|
-
|
|
101
|
+
scriptPath: './5.3.0-migration.js',
|
|
98
102
|
},
|
|
99
|
-
|
|
103
|
+
{
|
|
104
|
+
name: 'migration-key2',
|
|
100
105
|
version: '2.3.0',
|
|
101
106
|
description: 'Update project to use new cache directory',
|
|
102
|
-
|
|
107
|
+
scriptPath: './2.3.0-migration.js',
|
|
103
108
|
},
|
|
104
|
-
|
|
109
|
+
{
|
|
110
|
+
name: 'migration-key3',
|
|
105
111
|
version: '2.0.0',
|
|
106
112
|
description: 'Update project to use new cache directory',
|
|
107
|
-
|
|
113
|
+
scriptPath: './2.0.0-migration.js',
|
|
108
114
|
},
|
|
109
|
-
|
|
115
|
+
{
|
|
116
|
+
name: 'migration-key4',
|
|
110
117
|
version: '2.0.0',
|
|
111
118
|
description: 'Update project to use new cache directory',
|
|
112
|
-
|
|
119
|
+
scriptPath: './2.0.0-migration.js',
|
|
113
120
|
},
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
expect(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const mockContext = new Context('/virtual');
|
|
123
|
-
const migrationFn = vi.fn().mockResolvedValue(mockContext);
|
|
124
|
-
|
|
125
|
-
vi.doMock('./test-migration.js', () => ({
|
|
126
|
-
default: migrationFn,
|
|
127
|
-
}));
|
|
128
|
-
|
|
129
|
-
const migration: MigrationMeta = {
|
|
130
|
-
version: '1.0.0',
|
|
131
|
-
description: 'test migration',
|
|
132
|
-
migrationScript: './test-migration.js',
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const result = await runMigration(migration, mockContext);
|
|
136
|
-
|
|
137
|
-
expect(migrationFn).toHaveBeenCalledWith(mockContext);
|
|
138
|
-
expect(result).toBe(mockContext);
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
expect(migrations.map((m) => m.name)).toEqual([
|
|
124
|
+
'migration-key3',
|
|
125
|
+
'migration-key4',
|
|
126
|
+
'migration-key2',
|
|
127
|
+
'migration-key1',
|
|
128
|
+
]);
|
|
139
129
|
});
|
|
140
130
|
});
|
|
141
131
|
|
|
@@ -144,25 +134,27 @@ describe('Migrations', () => {
|
|
|
144
134
|
const migrationTwoFn = vi.fn();
|
|
145
135
|
const consoleMock = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
146
136
|
|
|
147
|
-
vi.doMock('
|
|
137
|
+
vi.doMock('virtual-test-migration.js', async () => ({
|
|
148
138
|
default: migrationOneFn,
|
|
149
139
|
}));
|
|
150
|
-
vi.doMock('
|
|
140
|
+
vi.doMock('virtual-test-migration2.js', async () => ({
|
|
151
141
|
default: migrationTwoFn,
|
|
152
142
|
}));
|
|
153
143
|
|
|
154
|
-
const migrations:
|
|
155
|
-
|
|
144
|
+
const migrations: Migration[] = [
|
|
145
|
+
{
|
|
146
|
+
name: 'migration-one',
|
|
156
147
|
version: '1.0.0',
|
|
157
148
|
description: '...',
|
|
158
|
-
|
|
149
|
+
scriptPath: 'virtual-test-migration.js',
|
|
159
150
|
},
|
|
160
|
-
|
|
151
|
+
{
|
|
152
|
+
name: 'migration-two',
|
|
161
153
|
version: '1.2.0',
|
|
162
154
|
description: '...',
|
|
163
|
-
|
|
155
|
+
scriptPath: 'virtual-test-migration2.js',
|
|
164
156
|
},
|
|
165
|
-
|
|
157
|
+
];
|
|
166
158
|
|
|
167
159
|
beforeEach(() => {
|
|
168
160
|
migrationOneFn.mockImplementation(async (context: Context) => {
|
|
@@ -208,6 +200,7 @@ describe('Migrations', () => {
|
|
|
208
200
|
it('should commit the changes for each migration if the CLI arg is present', async () => {
|
|
209
201
|
await runMigrations(migrations, { commitEachMigration: true });
|
|
210
202
|
|
|
203
|
+
// 2 migration commits + 1 version update commit = 3 total
|
|
211
204
|
expect(gitCommitNoVerify).toHaveBeenCalledTimes(3);
|
|
212
205
|
});
|
|
213
206
|
|
|
@@ -216,6 +209,7 @@ describe('Migrations', () => {
|
|
|
216
209
|
|
|
217
210
|
await runMigrations(migrations, { commitEachMigration: true });
|
|
218
211
|
|
|
212
|
+
// 1 migration commit (only migration-one has changes) + 1 version update commit = 2 total
|
|
219
213
|
expect(gitCommitNoVerify).toHaveBeenCalledTimes(2);
|
|
220
214
|
});
|
|
221
215
|
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import defaultMigrations, {
|
|
2
|
-
import {
|
|
1
|
+
import defaultMigrations, { Migration } from './migrations.js';
|
|
2
|
+
import { runCodemod } from '../runner.js';
|
|
3
3
|
import { gte, satisfies } from 'semver';
|
|
4
|
-
import { migrationsDebug, printChanges } from './utils.js';
|
|
5
|
-
|
|
6
4
|
import { CURRENT_APP_VERSION } from '../../utils/utils.version.js';
|
|
7
|
-
import { Context } from '../context.js';
|
|
8
|
-
import type { MigrationModule } from '../types.js';
|
|
9
5
|
import { gitCommitNoVerify } from '../../utils/utils.git.js';
|
|
10
6
|
import { output } from '../../utils/utils.console.js';
|
|
11
7
|
import { setRootConfig } from '../../utils/utils.config.js';
|
|
@@ -13,59 +9,36 @@ import { setRootConfig } from '../../utils/utils.config.js';
|
|
|
13
9
|
export function getMigrationsToRun(
|
|
14
10
|
fromVersion: string,
|
|
15
11
|
toVersion: string,
|
|
16
|
-
migrations:
|
|
17
|
-
):
|
|
12
|
+
migrations: Migration[] = defaultMigrations
|
|
13
|
+
): Migration[] {
|
|
18
14
|
const semverRange = `${fromVersion} - ${toVersion}`;
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
return migrations
|
|
17
|
+
.filter((meta) => satisfies(meta.version, semverRange))
|
|
21
18
|
.sort((a, b) => {
|
|
22
|
-
return gte(a
|
|
23
|
-
})
|
|
24
|
-
.reduce<Record<string, MigrationMeta>>((acc, [key, meta]) => {
|
|
25
|
-
if (satisfies(meta.version, semverRange)) {
|
|
26
|
-
acc[key] = meta;
|
|
27
|
-
}
|
|
28
|
-
return acc;
|
|
29
|
-
}, {});
|
|
30
|
-
|
|
31
|
-
return migrationsToRun;
|
|
19
|
+
return gte(a.version, b.version) ? 1 : -1;
|
|
20
|
+
});
|
|
32
21
|
}
|
|
33
22
|
|
|
34
23
|
type RunMigrationsOptions = {
|
|
35
24
|
commitEachMigration?: boolean;
|
|
25
|
+
codemodOptions?: Record<string, any>;
|
|
36
26
|
};
|
|
37
27
|
|
|
38
|
-
export async function runMigrations(migrations:
|
|
39
|
-
const
|
|
40
|
-
const migrationList = Object.entries(migrations).map(
|
|
41
|
-
([key, migrationMeta]) => `${key} (${migrationMeta.description})`
|
|
42
|
-
);
|
|
28
|
+
export async function runMigrations(migrations: Migration[], options: RunMigrationsOptions = {}) {
|
|
29
|
+
const migrationList = migrations.map((meta) => `${meta.name} (${meta.description})`);
|
|
43
30
|
|
|
44
31
|
const migrationListBody = migrationList.length > 0 ? output.bulletList(migrationList) : ['No migrations to run.'];
|
|
45
32
|
|
|
46
33
|
output.log({ title: 'Running the following migrations:', body: migrationListBody });
|
|
47
34
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
migrationsDebug(`context for "${key} (${migration.migrationScript})":`);
|
|
54
|
-
migrationsDebug('%O', context.listChanges());
|
|
55
|
-
|
|
56
|
-
await formatFiles(context);
|
|
57
|
-
flushChanges(context);
|
|
58
|
-
printChanges(context, key, migration);
|
|
35
|
+
// run migrations sequentially in version order where lowest version runs first
|
|
36
|
+
for (const migration of migrations) {
|
|
37
|
+
const context = await runCodemod(migration, options.codemodOptions);
|
|
38
|
+
const shouldCommit = options.commitEachMigration && context.hasChanges();
|
|
59
39
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (shouldCommit) {
|
|
63
|
-
await gitCommitNoVerify(`chore: run create-plugin migration - ${key} (${migration.migrationScript})`);
|
|
64
|
-
}
|
|
65
|
-
} catch (error) {
|
|
66
|
-
if (error instanceof Error) {
|
|
67
|
-
throw new Error(`Error running migration "${key} (${migration.migrationScript})": ${error.message}`);
|
|
68
|
-
}
|
|
40
|
+
if (shouldCommit) {
|
|
41
|
+
await gitCommitNoVerify(`chore: run create-plugin migration - ${migration.name} (${migration.scriptPath})`);
|
|
69
42
|
}
|
|
70
43
|
}
|
|
71
44
|
|
|
@@ -75,9 +48,3 @@ export async function runMigrations(migrations: Record<string, MigrationMeta>, o
|
|
|
75
48
|
await gitCommitNoVerify(`chore: update .config/.cprc.json to version ${CURRENT_APP_VERSION}.`);
|
|
76
49
|
}
|
|
77
50
|
}
|
|
78
|
-
|
|
79
|
-
export async function runMigration(migration: MigrationMeta, context: Context): Promise<Context> {
|
|
80
|
-
const module = (await import(migration.migrationScript)) as MigrationModule;
|
|
81
|
-
|
|
82
|
-
return module.default(context);
|
|
83
|
-
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
1
2
|
import defaultMigrations from './migrations.js';
|
|
2
3
|
|
|
3
4
|
describe('migrations json', () => {
|
|
4
5
|
// As migration scripts are imported dynamically when update is run we assert the path is valid
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
// Vitest 4 reimplemented its workers, which caused the previous dynamic import tests to fail.
|
|
7
|
+
// This test now only asserts that the migration script source file exists.
|
|
8
|
+
defaultMigrations.forEach((migration) => {
|
|
9
|
+
it(`should have a valid migration script path for ${migration.name}`, () => {
|
|
10
|
+
// ensure migration script exists
|
|
11
|
+
const sourceFilePath = migration.scriptPath.replace('.js', '.ts');
|
|
12
|
+
expect(existsSync(sourceFilePath)).toBe(true);
|
|
10
13
|
});
|
|
11
14
|
});
|
|
12
15
|
});
|
|
@@ -1,39 +1,43 @@
|
|
|
1
1
|
import { LEGACY_UPDATE_CUTOFF_VERSION } from '../../constants.js';
|
|
2
|
+
import { Codemod } from '../types.js';
|
|
3
|
+
import { resolveScriptPath } from '../utils.js';
|
|
2
4
|
|
|
3
|
-
export
|
|
5
|
+
export interface Migration extends Codemod {
|
|
4
6
|
version: string;
|
|
5
|
-
|
|
6
|
-
migrationScript: string;
|
|
7
|
-
};
|
|
7
|
+
}
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
9
|
+
export default [
|
|
10
|
+
{
|
|
11
|
+
name: '001-update-grafana-compose-extend',
|
|
12
|
+
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
13
|
+
description: 'Update ./docker-compose.yaml to extend from ./.config/docker-compose-base.yaml.',
|
|
14
|
+
scriptPath: resolveScriptPath(import.meta.url, './scripts/001-update-grafana-compose-extend.js'),
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: '002-update-is-compatible-workflow',
|
|
18
|
+
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
19
|
+
description:
|
|
20
|
+
'Update ./.github/workflows/is-compatible.yml to use is-compatible github action instead of calling levitate directly',
|
|
21
|
+
scriptPath: resolveScriptPath(import.meta.url, './scripts/002-update-is-compatible-workflow.js'),
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: '003-update-eslint-deprecation-rule',
|
|
25
|
+
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
26
|
+
description: 'Replace deprecated eslint-plugin-deprecation with @typescript-eslint/no-deprecated rule.',
|
|
27
|
+
scriptPath: resolveScriptPath(import.meta.url, './scripts/003-update-eslint-deprecation-rule.js'),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: '004-eslint9-flat-config',
|
|
31
|
+
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
32
|
+
description: 'Migrate eslint config to flat config format and update devDependencies to latest versions.',
|
|
33
|
+
scriptPath: resolveScriptPath(import.meta.url, './scripts/004-eslint9-flat-config.js'),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: '005-react-18-3',
|
|
37
|
+
version: '6.1.9',
|
|
38
|
+
description: 'Update React and ReactDOM 18.x versions to ^18.3.0 to surface React 19 compatibility issues.',
|
|
39
|
+
scriptPath: resolveScriptPath(import.meta.url, './scripts/005-react-18-3.js'),
|
|
38
40
|
},
|
|
39
|
-
|
|
41
|
+
// Do not use LEGACY_UPDATE_CUTOFF_VERSION for new migrations. It is only used above to force migrations to run
|
|
42
|
+
// for those written before the switch to updates as migrations.
|
|
43
|
+
] satisfies Migration[];
|
|
@@ -7,7 +7,7 @@ import { dirname, relative, resolve } from 'node:path';
|
|
|
7
7
|
import * as recast from 'recast';
|
|
8
8
|
import type { Context } from '../../context.js';
|
|
9
9
|
import { addDependenciesToPackageJson } from '../../utils.js';
|
|
10
|
-
|
|
10
|
+
// migrationsDebug removed - was from deleted migrations/utils.js
|
|
11
11
|
|
|
12
12
|
type Imports = Map<string, { name?: string; bindings?: string[] }>;
|
|
13
13
|
|
|
@@ -407,7 +407,7 @@ function getIgnorePaths(context: Context): string[] {
|
|
|
407
407
|
}
|
|
408
408
|
}
|
|
409
409
|
} catch (error) {
|
|
410
|
-
|
|
410
|
+
console.log('Error parsing package.json: %s', error);
|
|
411
411
|
}
|
|
412
412
|
}
|
|
413
413
|
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { Context } from '../../context.js';
|
|
3
|
+
import migrate from './005-react-18-3.js';
|
|
4
|
+
|
|
5
|
+
describe('005-react-18-3', () => {
|
|
6
|
+
it('should not modify anything if package.json does not exist', async () => {
|
|
7
|
+
const context = new Context('/virtual');
|
|
8
|
+
await migrate(context);
|
|
9
|
+
expect(context.listChanges()).toEqual({});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should not modify anything if there are no React dependencies', async () => {
|
|
13
|
+
const context = new Context('/virtual');
|
|
14
|
+
context.addFile(
|
|
15
|
+
'./package.json',
|
|
16
|
+
JSON.stringify({
|
|
17
|
+
dependencies: {
|
|
18
|
+
lodash: '^4.17.21',
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
const initialChanges = context.listChanges();
|
|
23
|
+
await migrate(context);
|
|
24
|
+
expect(context.listChanges()).toEqual(initialChanges);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should not update React if version is below 18.0.0', async () => {
|
|
28
|
+
const context = new Context('/virtual');
|
|
29
|
+
const packageJson = {
|
|
30
|
+
dependencies: {
|
|
31
|
+
react: '^17.0.2',
|
|
32
|
+
'react-dom': '^17.0.2',
|
|
33
|
+
},
|
|
34
|
+
devDependencies: {
|
|
35
|
+
'@types/react': '^17.0.0',
|
|
36
|
+
'@types/react-dom': '^17.0.0',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
context.addFile('./package.json', JSON.stringify(packageJson, null, 2));
|
|
40
|
+
const initialPackageJson = context.getFile('./package.json');
|
|
41
|
+
|
|
42
|
+
await migrate(context);
|
|
43
|
+
|
|
44
|
+
expect(context.getFile('./package.json')).toBe(initialPackageJson);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should update React 18.0.0 to ^18.3.0', async () => {
|
|
48
|
+
const context = new Context('/virtual');
|
|
49
|
+
context.addFile(
|
|
50
|
+
'./package.json',
|
|
51
|
+
JSON.stringify({
|
|
52
|
+
dependencies: {
|
|
53
|
+
react: '^18.0.0',
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
await migrate(context);
|
|
59
|
+
|
|
60
|
+
const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
|
|
61
|
+
expect(updatedPackageJson.dependencies.react).toBe('^18.3.0');
|
|
62
|
+
expect(updatedPackageJson.devDependencies?.['@types/react']).toBe('^18.3.0');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should not update React if version is already 18.3.0 or higher', async () => {
|
|
66
|
+
const context = new Context('/virtual');
|
|
67
|
+
const packageJson = {
|
|
68
|
+
dependencies: {
|
|
69
|
+
react: '^18.3.0',
|
|
70
|
+
'react-dom': '^18.3.0',
|
|
71
|
+
},
|
|
72
|
+
devDependencies: {
|
|
73
|
+
'@types/react': '^18.3.0',
|
|
74
|
+
'@types/react-dom': '^18.3.0',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
context.addFile('./package.json', JSON.stringify(packageJson, null, 2));
|
|
78
|
+
|
|
79
|
+
await migrate(context);
|
|
80
|
+
|
|
81
|
+
const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
|
|
82
|
+
expect(updatedPackageJson.dependencies.react).toBe('^18.3.0');
|
|
83
|
+
expect(updatedPackageJson.dependencies['react-dom']).toBe('^18.3.0');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should not downgrade React 19.0.0 to 18.3.0', async () => {
|
|
87
|
+
const context = new Context('/virtual');
|
|
88
|
+
const packageJson = {
|
|
89
|
+
dependencies: {
|
|
90
|
+
react: '^19.0.0',
|
|
91
|
+
'react-dom': '^19.0.0',
|
|
92
|
+
},
|
|
93
|
+
devDependencies: {
|
|
94
|
+
'@types/react': '^19.0.0',
|
|
95
|
+
'@types/react-dom': '^19.0.0',
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
context.addFile('./package.json', JSON.stringify(packageJson, null, 2));
|
|
99
|
+
|
|
100
|
+
await migrate(context);
|
|
101
|
+
|
|
102
|
+
const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
|
|
103
|
+
expect(updatedPackageJson.dependencies.react).toBe('^19.0.0');
|
|
104
|
+
expect(updatedPackageJson.dependencies['react-dom']).toBe('^19.0.0');
|
|
105
|
+
expect(updatedPackageJson.devDependencies['@types/react']).toBe('^19.0.0');
|
|
106
|
+
expect(updatedPackageJson.devDependencies['@types/react-dom']).toBe('^19.0.0');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should handle version ranges correctly', async () => {
|
|
110
|
+
const context = new Context('/virtual');
|
|
111
|
+
context.addFile(
|
|
112
|
+
'./package.json',
|
|
113
|
+
JSON.stringify({
|
|
114
|
+
dependencies: {
|
|
115
|
+
react: '~18.1.0',
|
|
116
|
+
'react-dom': '18.2.0',
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
await migrate(context);
|
|
122
|
+
|
|
123
|
+
const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
|
|
124
|
+
expect(updatedPackageJson.dependencies.react).toBe('^18.3.0');
|
|
125
|
+
expect(updatedPackageJson.dependencies['react-dom']).toBe('^18.3.0');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should be idempotent', async () => {
|
|
129
|
+
const context = new Context('/virtual');
|
|
130
|
+
context.addFile(
|
|
131
|
+
'./package.json',
|
|
132
|
+
JSON.stringify({
|
|
133
|
+
dependencies: {
|
|
134
|
+
react: '^18.2.0',
|
|
135
|
+
'react-dom': '^18.2.0',
|
|
136
|
+
},
|
|
137
|
+
devDependencies: {
|
|
138
|
+
'@types/react': '^18.2.0',
|
|
139
|
+
'@types/react-dom': '^18.2.0',
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
await expect(migrate).toBeIdempotent(context);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Context } from '../../context.js';
|
|
2
|
+
import { addDependenciesToPackageJson, isVersionGreater } from '../../utils.js';
|
|
3
|
+
|
|
4
|
+
export default function migrate(context: Context) {
|
|
5
|
+
if (context.doesFileExist('package.json')) {
|
|
6
|
+
const packageJson = JSON.parse(context.getFile('package.json') || '{}');
|
|
7
|
+
if (packageJson.dependencies?.react) {
|
|
8
|
+
if (isVersionGreater(packageJson.dependencies.react, '18.0.0', true)) {
|
|
9
|
+
addDependenciesToPackageJson(context, { react: '^18.3.0' }, { '@types/react': '^18.3.0' });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
if (packageJson.dependencies?.['react-dom']) {
|
|
13
|
+
if (isVersionGreater(packageJson.dependencies['react-dom'], '18.0.0', true)) {
|
|
14
|
+
addDependenciesToPackageJson(context, { 'react-dom': '^18.3.0' }, { '@types/react-dom': '^18.3.0' });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return context;
|
|
19
|
+
}
|
|
@@ -14,7 +14,7 @@ describe('Migration - append profile to webpack', () => {
|
|
|
14
14
|
})
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
const updatedContext = await migrate(context);
|
|
17
|
+
const updatedContext = await migrate(context, { profile: true, skipBackup: false, verbose: false });
|
|
18
18
|
|
|
19
19
|
expect(updatedContext.getFile('./package.json')).toMatch(
|
|
20
20
|
'webpack -c ./.config/webpack/webpack.config.ts --profile --env production'
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import type { Context } from '../../context.js';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Example migration that demonstrates basic context operations
|
|
5
|
+
* This example shows how to modify package.json, add/delete files, and rename files
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type MigrateOptions = {
|
|
9
|
+
profile?: boolean;
|
|
10
|
+
skipBackup?: boolean;
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default function migrate(context: Context, options: MigrateOptions = {}): Context {
|
|
15
|
+
const { profile = false, skipBackup = false, verbose = false } = options;
|
|
16
|
+
|
|
17
|
+
if (verbose) {
|
|
18
|
+
console.log('Running migration with options:', options);
|
|
19
|
+
}
|
|
20
|
+
|
|
4
21
|
const rawPkgJson = context.getFile('./package.json') ?? '{}';
|
|
5
22
|
const packageJson = JSON.parse(rawPkgJson);
|
|
6
23
|
|
|
@@ -9,14 +26,14 @@ export default function migrate(context: Context): Context {
|
|
|
9
26
|
|
|
10
27
|
const pattern = /(webpack.+-c\s.+\.ts)\s(.+)/;
|
|
11
28
|
|
|
12
|
-
if (pattern.test(buildScript) && !buildScript.includes('--profile')) {
|
|
29
|
+
if (profile && pattern.test(buildScript) && !buildScript.includes('--profile')) {
|
|
13
30
|
packageJson.scripts.build = buildScript.replace(pattern, `$1 --profile $2`);
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
context.updateFile('./package.json', JSON.stringify(packageJson, null, 2));
|
|
17
34
|
}
|
|
18
35
|
|
|
19
|
-
if (context.doesFileExist('./src/README.md')) {
|
|
36
|
+
if (!skipBackup && context.doesFileExist('./src/README.md')) {
|
|
20
37
|
context.deleteFile('./src/README.md');
|
|
21
38
|
}
|
|
22
39
|
|