@grafana/create-plugin 6.2.0-canary.2314.19503588692.0 → 6.2.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 +12 -0
- package/dist/bin/run.js +3 -1
- package/dist/codemods/additions/additions.js +9 -0
- package/dist/codemods/additions/scripts/example-addition.js +47 -0
- package/dist/{migrations → codemods}/context.js +3 -2
- package/dist/codemods/migrations/manager.js +32 -0
- package/dist/codemods/migrations/migrations.js +50 -0
- package/dist/{migrations → codemods/migrations}/scripts/003-update-eslint-deprecation-rule.js +1 -1
- package/dist/{migrations → codemods/migrations}/scripts/004-eslint9-flat-config.js +1 -1
- package/dist/{migrations → codemods/migrations}/scripts/005-react-18-3.js +1 -1
- package/dist/{migrations → codemods/migrations}/scripts/007-remove-testing-library-types.js +1 -1
- package/dist/codemods/runner.js +33 -0
- package/dist/codemods/schema-parser.js +20 -0
- package/dist/{migrations → codemods}/utils.js +5 -16
- package/dist/commands/add.command.js +51 -0
- package/dist/commands/update.command.js +8 -42
- package/dist/utils/utils.checks.js +40 -0
- package/package.json +3 -2
- package/src/bin/run.ts +2 -1
- package/src/codemods/additions/additions.test.ts +17 -0
- package/src/codemods/additions/additions.ts +9 -0
- package/src/codemods/additions/scripts/example-addition.test.ts +92 -0
- package/src/codemods/additions/scripts/example-addition.ts +62 -0
- package/src/{migrations → codemods}/context.test.ts +10 -10
- package/src/{migrations → codemods}/context.ts +4 -2
- package/src/codemods/migrations/fixtures/migrations.ts +20 -0
- package/src/{migrations → codemods/migrations}/manager.test.ts +76 -77
- package/src/codemods/migrations/manager.ts +50 -0
- package/src/codemods/migrations/migrations.test.ts +17 -0
- package/src/codemods/migrations/migrations.ts +55 -0
- package/src/{migrations → codemods/migrations}/scripts/001-update-grafana-compose-extend.test.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/001-update-grafana-compose-extend.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/002-update-is-compatible-workflow.test.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/002-update-is-compatible-workflow.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/003-update-eslint-deprecation-rule.test.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/003-update-eslint-deprecation-rule.ts +2 -2
- package/src/{migrations → codemods/migrations}/scripts/004-eslint9-flat-config.test.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/004-eslint9-flat-config.ts +2 -2
- package/src/{migrations → codemods/migrations}/scripts/005-react-18-3.test.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/005-react-18-3.ts +2 -2
- package/src/{migrations → codemods/migrations}/scripts/006-webpack-nested-fix.test.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/006-webpack-nested-fix.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/007-remove-testing-library-types.test.ts +1 -1
- package/src/{migrations → codemods/migrations}/scripts/007-remove-testing-library-types.ts +2 -2
- package/src/codemods/runner.ts +51 -0
- package/src/codemods/schema-parser.ts +27 -0
- package/src/codemods/types.ts +16 -0
- package/src/{migrations → codemods}/utils.test.ts +5 -4
- package/src/{migrations → codemods}/utils.ts +8 -22
- package/src/commands/add.command.ts +56 -0
- package/src/commands/index.ts +1 -0
- package/src/commands/update.command.ts +9 -48
- package/src/utils/utils.checks.ts +47 -0
- package/dist/migrations/manager.js +0 -58
- package/dist/migrations/migrations.js +0 -43
- package/dist/migrations/scripts/example-migration.js +0 -25
- package/src/migrations/fixtures/migrations.ts +0 -19
- package/src/migrations/manager.ts +0 -82
- package/src/migrations/migrations.test.ts +0 -16
- package/src/migrations/migrations.ts +0 -55
- package/src/migrations/scripts/example-migration.test.ts +0 -40
- package/src/migrations/scripts/example-migration.ts +0 -34
- package/templates/panel/.config/AGENTS/fundamentals.md +0 -66
- package/templates/panel/AGENTS.md +0 -3
- /package/dist/{migrations → codemods/migrations}/scripts/001-update-grafana-compose-extend.js +0 -0
- /package/dist/{migrations → codemods/migrations}/scripts/002-update-is-compatible-workflow.js +0 -0
- /package/dist/{migrations → codemods/migrations}/scripts/006-webpack-nested-fix.js +0 -0
- /package/src/{migrations → codemods/migrations}/fixtures/foo/bar.ts +0 -0
- /package/src/{migrations → codemods/migrations}/fixtures/foo/baz.ts +0 -0
- /package/src/{migrations → codemods}/test-utils.ts +0 -0
package/src/{migrations → codemods/migrations}/scripts/003-update-eslint-deprecation-rule.test.ts
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import migrate from './003-update-eslint-deprecation-rule.js';
|
|
3
|
-
import { Context } from '
|
|
3
|
+
import { Context } from '../../context.js';
|
|
4
4
|
|
|
5
5
|
describe('003-update-eslint-deprecation-rule', () => {
|
|
6
6
|
it('should not update ESLint config if no deprecation rule is present', () => {
|
package/src/{migrations → codemods/migrations}/scripts/003-update-eslint-deprecation-rule.ts
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Context } from '
|
|
2
|
-
import { addDependenciesToPackageJson, removeDependenciesFromPackageJson } from '
|
|
1
|
+
import type { Context } from '../../context.js';
|
|
2
|
+
import { addDependenciesToPackageJson, removeDependenciesFromPackageJson } from '../../utils.js';
|
|
3
3
|
|
|
4
4
|
export default function migrate(context: Context) {
|
|
5
5
|
if (context.doesFileExist('.config/.eslintrc') && context.doesFileExist('package.json')) {
|
|
@@ -5,8 +5,8 @@ import { parse } from 'jsonc-parser';
|
|
|
5
5
|
import minimist from 'minimist';
|
|
6
6
|
import { dirname, relative, resolve } from 'node:path';
|
|
7
7
|
import * as recast from 'recast';
|
|
8
|
-
import type { Context } from '
|
|
9
|
-
import { addDependenciesToPackageJson, migrationsDebug } from '
|
|
8
|
+
import type { Context } from '../../context.js';
|
|
9
|
+
import { addDependenciesToPackageJson, migrationsDebug } from '../../utils.js';
|
|
10
10
|
|
|
11
11
|
type Imports = Map<string, { name?: string; bindings?: string[] }>;
|
|
12
12
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Context } from '
|
|
2
|
-
import { addDependenciesToPackageJson, isVersionGreater } from '
|
|
1
|
+
import type { Context } from '../../context.js';
|
|
2
|
+
import { addDependenciesToPackageJson, isVersionGreater } from '../../utils.js';
|
|
3
3
|
|
|
4
4
|
export default function migrate(context: Context) {
|
|
5
5
|
if (context.doesFileExist('package.json')) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import migrate from './006-webpack-nested-fix.js';
|
|
2
|
-
import { createDefaultContext } from '
|
|
2
|
+
import { createDefaultContext } from '../../test-utils.js';
|
|
3
3
|
|
|
4
4
|
describe('Migration - webpack nested fix', () => {
|
|
5
5
|
test('should transform files property to test property', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import * as recast from 'recast';
|
|
3
3
|
import * as typeScriptParser from 'recast/parsers/typescript.js';
|
|
4
|
-
import type { Context } from '
|
|
4
|
+
import type { Context } from '../../context.js';
|
|
5
5
|
|
|
6
6
|
const { builders } = recast.types;
|
|
7
7
|
|
package/src/{migrations → codemods/migrations}/scripts/007-remove-testing-library-types.test.ts
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import migrate from './007-remove-testing-library-types.js';
|
|
3
|
-
import { Context } from '
|
|
3
|
+
import { Context } from '../../context.js';
|
|
4
4
|
|
|
5
5
|
describe('006-remove-testing-library-types', () => {
|
|
6
6
|
it('should create setupTests.d.ts, remove types package, and add @testing-library/jest-dom when file does not exist', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Context } from '
|
|
2
|
-
import { removeDependenciesFromPackageJson, isVersionGreater } from '
|
|
1
|
+
import type { Context } from '../../context.js';
|
|
2
|
+
import { removeDependenciesFromPackageJson, isVersionGreater } from '../../utils.js';
|
|
3
3
|
|
|
4
4
|
export default function migrate(context: Context) {
|
|
5
5
|
if (context.doesFileExist('package.json')) {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Context } from './context.js';
|
|
2
|
+
import { formatFiles, flushChanges, installNPMDependencies, printChanges } from './utils.js';
|
|
3
|
+
import { parseAndValidateOptions } from './schema-parser.js';
|
|
4
|
+
import { Codemod } from './types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Run a single codemod
|
|
8
|
+
*
|
|
9
|
+
* Steps:
|
|
10
|
+
* 1. Load codemod module from scriptPath
|
|
11
|
+
* 2. Parse and validate options from schema
|
|
12
|
+
* 3. Execute codemod transformation
|
|
13
|
+
* 4. Format files
|
|
14
|
+
* 5. Flush changes to disk
|
|
15
|
+
* 6. Print summary
|
|
16
|
+
* 7. Install dependencies if needed
|
|
17
|
+
*/
|
|
18
|
+
export async function runCodemod(codemod: Codemod, options?: Record<string, any>): Promise<Context> {
|
|
19
|
+
const codemodModule = await import(codemod.scriptPath);
|
|
20
|
+
if (!codemodModule.default || typeof codemodModule.default !== 'function') {
|
|
21
|
+
throw new Error(`Codemod ${codemod.name} must export a default function`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let codemodOptions = {};
|
|
25
|
+
|
|
26
|
+
if (options && codemodModule.schema) {
|
|
27
|
+
codemodOptions = parseAndValidateOptions(options, codemodModule.schema);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const basePath = process.cwd();
|
|
31
|
+
const context = new Context(basePath);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const updatedContext = await codemodModule.default(context, codemodOptions);
|
|
35
|
+
|
|
36
|
+
// standard post-processing pipeline
|
|
37
|
+
await formatFiles(updatedContext);
|
|
38
|
+
flushChanges(updatedContext);
|
|
39
|
+
printChanges(updatedContext, codemod.name, codemod.description);
|
|
40
|
+
installNPMDependencies(updatedContext);
|
|
41
|
+
|
|
42
|
+
return updatedContext;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (error instanceof Error) {
|
|
45
|
+
const newError = new Error(`Error running ${codemod.name}: ${error.message}`);
|
|
46
|
+
newError.cause = error;
|
|
47
|
+
throw newError;
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as v from 'valibot';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parse and validate options using Valibot schema
|
|
5
|
+
* Valibot handles parsing, validation, type coercion, and defaults automatically
|
|
6
|
+
*/
|
|
7
|
+
export function parseAndValidateOptions<T extends v.BaseSchema<any, any, any>>(
|
|
8
|
+
options: Record<string, any>,
|
|
9
|
+
schema: T
|
|
10
|
+
): v.InferOutput<T> {
|
|
11
|
+
try {
|
|
12
|
+
return v.parse(schema, options);
|
|
13
|
+
} catch (error) {
|
|
14
|
+
if (v.isValiError(error)) {
|
|
15
|
+
// format Valibot validation errors
|
|
16
|
+
const formattedErrors = error.issues
|
|
17
|
+
.map((issue) => {
|
|
18
|
+
const path = issue.path?.map((p) => p.key).join('.') || '';
|
|
19
|
+
return ` --${path}: ${issue.message}`;
|
|
20
|
+
})
|
|
21
|
+
.join('\n');
|
|
22
|
+
|
|
23
|
+
throw new Error(`Invalid flag(s) provided:\n\n${formattedErrors}`);
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Context } from './context.js';
|
|
2
|
+
import type * as v from 'valibot';
|
|
3
|
+
|
|
4
|
+
// used as a generic constraint for codemod schemas. accepts any input, output and error types
|
|
5
|
+
type AnySchema = v.BaseSchema<any, any, any>;
|
|
6
|
+
|
|
7
|
+
export interface CodemodModule<TSchema extends AnySchema = AnySchema> {
|
|
8
|
+
default: (context: Context, options: v.InferOutput<TSchema>) => Context | Promise<Context>;
|
|
9
|
+
schema?: TSchema;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Codemod {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
scriptPath: string;
|
|
16
|
+
}
|
|
@@ -5,14 +5,15 @@ import {
|
|
|
5
5
|
removeDependenciesFromPackageJson,
|
|
6
6
|
flushChanges,
|
|
7
7
|
formatFiles,
|
|
8
|
-
printChanges,
|
|
9
8
|
readJsonFile,
|
|
10
9
|
isVersionGreater,
|
|
10
|
+
printChanges,
|
|
11
11
|
} from './utils.js';
|
|
12
12
|
import { join } from 'node:path';
|
|
13
13
|
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
14
14
|
import { readFileSync } from 'node:fs';
|
|
15
15
|
import { output } from '../utils/utils.console.js';
|
|
16
|
+
import { vi } from 'vitest';
|
|
16
17
|
|
|
17
18
|
describe('utils', () => {
|
|
18
19
|
const tmpObj = dirSync({ unsafeCleanup: true });
|
|
@@ -80,7 +81,7 @@ describe('utils', () => {
|
|
|
80
81
|
context.updateFile('baz.ts', 'new content');
|
|
81
82
|
context.deleteFile('bar.ts');
|
|
82
83
|
|
|
83
|
-
printChanges(context, 'key',
|
|
84
|
+
printChanges(context, 'key', 'test');
|
|
84
85
|
|
|
85
86
|
expect(outputMock.addHorizontalLine).toHaveBeenCalledWith('gray');
|
|
86
87
|
expect(outputMock.logSingleLine).toHaveBeenCalledWith('key (test)');
|
|
@@ -102,7 +103,7 @@ describe('utils', () => {
|
|
|
102
103
|
it('should print no changes', async () => {
|
|
103
104
|
const context = new Context(tmpDir);
|
|
104
105
|
|
|
105
|
-
printChanges(context, 'key',
|
|
106
|
+
printChanges(context, 'key', 'test');
|
|
106
107
|
|
|
107
108
|
expect(outputMock.logSingleLine).toHaveBeenCalledWith('No changes were made');
|
|
108
109
|
});
|
|
@@ -271,7 +272,7 @@ describe('utils', () => {
|
|
|
271
272
|
});
|
|
272
273
|
});
|
|
273
274
|
|
|
274
|
-
describe('
|
|
275
|
+
describe('isVersionGreater', () => {
|
|
275
276
|
describe('dist tag comparison', () => {
|
|
276
277
|
it('should return false when incoming is "latest" and existing is "next"', () => {
|
|
277
278
|
expect(isVersionGreater('latest', 'next')).toBe(false);
|
|
@@ -2,15 +2,14 @@ import { dirname, join } from 'node:path';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { Context } from './context.js';
|
|
4
4
|
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
-
import { debug } from '../utils/utils.cli.js';
|
|
6
5
|
import chalk from 'chalk';
|
|
7
|
-
import { MigrationMeta } from './migrations.js';
|
|
8
6
|
import { output } from '../utils/utils.console.js';
|
|
9
7
|
import { getPackageManagerSilentInstallCmd, getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
|
|
10
8
|
import { execSync } from 'node:child_process';
|
|
11
9
|
import { clean, coerce, gt, gte } from 'semver';
|
|
10
|
+
import { debug } from '../utils/utils.cli.js';
|
|
12
11
|
|
|
13
|
-
export function printChanges(context: Context, key: string,
|
|
12
|
+
export function printChanges(context: Context, key: string, description: string) {
|
|
14
13
|
const changes = context.listChanges();
|
|
15
14
|
const lines = [];
|
|
16
15
|
|
|
@@ -25,7 +24,7 @@ export function printChanges(context: Context, key: string, migration: Migration
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
output.addHorizontalLine('gray');
|
|
28
|
-
output.logSingleLine(`${key} (${
|
|
27
|
+
output.logSingleLine(`${key} (${description})`);
|
|
29
28
|
|
|
30
29
|
if (lines.length === 0) {
|
|
31
30
|
output.logSingleLine('No changes were made');
|
|
@@ -51,10 +50,8 @@ export function flushChanges(context: Context) {
|
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
export const migrationsDebug = debug.extend('migrations');
|
|
55
|
-
|
|
56
53
|
/**
|
|
57
|
-
* Formats the files in the
|
|
54
|
+
* Formats the files in the context using the version of prettier found in the local node_modules.
|
|
58
55
|
* If prettier isn't installed or the file is ignored or has no parser, it will not be formatted.
|
|
59
56
|
*
|
|
60
57
|
* @param context - The context to format.
|
|
@@ -104,7 +101,7 @@ export async function formatFiles(context: Context) {
|
|
|
104
101
|
}
|
|
105
102
|
|
|
106
103
|
// Cache the package.json contents to avoid re-installing dependencies if the package.json hasn't changed
|
|
107
|
-
// (This runs for each
|
|
104
|
+
// (This runs for each codemod used in an update)
|
|
108
105
|
let packageJsonInstallCache: string;
|
|
109
106
|
|
|
110
107
|
export function installNPMDependencies(context: Context) {
|
|
@@ -160,14 +157,10 @@ export function addDependenciesToPackageJson(
|
|
|
160
157
|
if (currentDeps[dep]) {
|
|
161
158
|
if (isVersionGreater(newVersion, currentDeps[dep])) {
|
|
162
159
|
currentDeps[dep] = newVersion;
|
|
163
|
-
} else {
|
|
164
|
-
migrationsDebug('would downgrade dependency %s to %s', dep, newVersion);
|
|
165
160
|
}
|
|
166
161
|
} else if (currentDevDeps[dep]) {
|
|
167
162
|
if (isVersionGreater(newVersion, currentDevDeps[dep])) {
|
|
168
163
|
currentDevDeps[dep] = newVersion;
|
|
169
|
-
} else {
|
|
170
|
-
migrationsDebug('would downgrade devDependency %s to %s', dep, newVersion);
|
|
171
164
|
}
|
|
172
165
|
} else {
|
|
173
166
|
// Not present, add to dependencies
|
|
@@ -180,14 +173,10 @@ export function addDependenciesToPackageJson(
|
|
|
180
173
|
if (currentDeps[dep]) {
|
|
181
174
|
if (isVersionGreater(newVersion, currentDeps[dep])) {
|
|
182
175
|
currentDeps[dep] = newVersion;
|
|
183
|
-
} else {
|
|
184
|
-
migrationsDebug('would downgrade dependency %s to %s', dep, newVersion);
|
|
185
176
|
}
|
|
186
177
|
} else if (currentDevDeps[dep]) {
|
|
187
178
|
if (isVersionGreater(newVersion, currentDevDeps[dep])) {
|
|
188
179
|
currentDevDeps[dep] = newVersion;
|
|
189
|
-
} else {
|
|
190
|
-
migrationsDebug('would downgrade devDependency %s to %s', dep, newVersion);
|
|
191
180
|
}
|
|
192
181
|
} else {
|
|
193
182
|
// Not present, add to devDependencies
|
|
@@ -214,8 +203,6 @@ export function addDependenciesToPackageJson(
|
|
|
214
203
|
...(Object.keys(sortedDevDeps).length > 0 && { devDependencies: sortedDevDeps }),
|
|
215
204
|
};
|
|
216
205
|
|
|
217
|
-
migrationsDebug('updated package.json', updatedPackageJson);
|
|
218
|
-
|
|
219
206
|
context.updateFile(packageJsonPath, JSON.stringify(updatedPackageJson, null, 2));
|
|
220
207
|
}
|
|
221
208
|
|
|
@@ -232,7 +219,6 @@ export function removeDependenciesFromPackageJson(
|
|
|
232
219
|
for (const dep of dependencies) {
|
|
233
220
|
if (currentPackageJson.dependencies?.[dep]) {
|
|
234
221
|
delete currentPackageJson.dependencies[dep];
|
|
235
|
-
migrationsDebug('removed dependency %s', dep);
|
|
236
222
|
hasChanges = true;
|
|
237
223
|
}
|
|
238
224
|
}
|
|
@@ -240,7 +226,6 @@ export function removeDependenciesFromPackageJson(
|
|
|
240
226
|
for (const dep of devDependencies) {
|
|
241
227
|
if (currentPackageJson.devDependencies?.[dep]) {
|
|
242
228
|
delete currentPackageJson.devDependencies[dep];
|
|
243
|
-
migrationsDebug('removed devDependency %s', dep);
|
|
244
229
|
hasChanges = true;
|
|
245
230
|
}
|
|
246
231
|
}
|
|
@@ -249,8 +234,6 @@ export function removeDependenciesFromPackageJson(
|
|
|
249
234
|
return;
|
|
250
235
|
}
|
|
251
236
|
|
|
252
|
-
migrationsDebug('updated package.json', currentPackageJson);
|
|
253
|
-
|
|
254
237
|
context.updateFile(packageJsonPath, JSON.stringify(currentPackageJson, null, 2));
|
|
255
238
|
}
|
|
256
239
|
|
|
@@ -315,3 +298,6 @@ function sortObjectByKeys<T extends Record<string, any>>(obj: T): T {
|
|
|
315
298
|
.sort()
|
|
316
299
|
.reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {} as T);
|
|
317
300
|
}
|
|
301
|
+
|
|
302
|
+
export const migrationsDebug = debug.extend('migrations');
|
|
303
|
+
export const additionsDebug = debug.extend('additions');
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import defaultAdditions from '../codemods/additions/additions.js';
|
|
2
|
+
import { runCodemod } from '../codemods/runner.js';
|
|
3
|
+
import { getPackageManagerExecCmd, getPackageManagerFromUserAgent } from '../utils/utils.packageManager.js';
|
|
4
|
+
import { performPreCodemodChecks } from '../utils/utils.checks.js';
|
|
5
|
+
import minimist from 'minimist';
|
|
6
|
+
import { output } from '../utils/utils.console.js';
|
|
7
|
+
|
|
8
|
+
export const add = async (argv: minimist.ParsedArgs) => {
|
|
9
|
+
const subCommand = argv._[1];
|
|
10
|
+
|
|
11
|
+
if (!subCommand) {
|
|
12
|
+
await showAdditionsHelp();
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
await performPreCodemodChecks(argv);
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const addition = defaultAdditions.find((addition) => addition.name === subCommand);
|
|
20
|
+
if (!addition) {
|
|
21
|
+
const additionsList = defaultAdditions.map((addition) => addition.name);
|
|
22
|
+
throw new Error(`Unknown addition: ${subCommand}\n\nAvailable additions: ${additionsList.join(', ')}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// filter out minimist internal properties (_ and $0) before passing to codemod
|
|
26
|
+
const { _, $0, ...codemodOptions } = argv;
|
|
27
|
+
await runCodemod(addition, codemodOptions);
|
|
28
|
+
|
|
29
|
+
output.success({
|
|
30
|
+
title: `Successfully added ${addition.name} to your plugin.`,
|
|
31
|
+
});
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof Error) {
|
|
34
|
+
output.error({
|
|
35
|
+
title: 'Addition failed',
|
|
36
|
+
body: [error.message],
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
async function showAdditionsHelp() {
|
|
44
|
+
const additionsList = defaultAdditions.map((addition) => addition.name);
|
|
45
|
+
const { packageManagerName, packageManagerVersion } = getPackageManagerFromUserAgent();
|
|
46
|
+
|
|
47
|
+
output.error({
|
|
48
|
+
title: 'No addition specified',
|
|
49
|
+
body: [
|
|
50
|
+
`Usage: ${getPackageManagerExecCmd(packageManagerName, packageManagerVersion)} add <addition-name> [options]`,
|
|
51
|
+
'',
|
|
52
|
+
'Available additions:',
|
|
53
|
+
...output.bulletList(additionsList),
|
|
54
|
+
],
|
|
55
|
+
});
|
|
56
|
+
}
|
package/src/commands/index.ts
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
import { getMigrationsToRun, runMigrations } from '../migrations/manager.js';
|
|
1
|
+
import { getMigrationsToRun, runMigrations } from '../codemods/migrations/manager.js';
|
|
2
2
|
import {
|
|
3
3
|
getPackageManagerExecCmd,
|
|
4
4
|
getPackageManagerSilentInstallCmd,
|
|
5
5
|
getPackageManagerWithFallback,
|
|
6
6
|
} from '../utils/utils.packageManager.js';
|
|
7
7
|
import { gte, lt } from 'semver';
|
|
8
|
-
import {
|
|
8
|
+
import { performPreCodemodChecks } from '../utils/utils.checks.js';
|
|
9
9
|
|
|
10
10
|
import { CURRENT_APP_VERSION } from '../utils/utils.version.js';
|
|
11
11
|
import { LEGACY_UPDATE_CUTOFF_VERSION } from '../constants.js';
|
|
12
12
|
import { getConfig } from '../utils/utils.config.js';
|
|
13
|
-
import { isPluginDirectory } from '../utils/utils.plugin.js';
|
|
14
13
|
import minimist from 'minimist';
|
|
15
14
|
import { output } from '../utils/utils.console.js';
|
|
16
15
|
import { spawnSync } from 'node:child_process';
|
|
17
16
|
|
|
18
17
|
export const update = async (argv: minimist.ParsedArgs) => {
|
|
19
|
-
await
|
|
18
|
+
await performPreCodemodChecks(argv);
|
|
20
19
|
const { version } = getConfig();
|
|
21
20
|
|
|
22
21
|
if (lt(version, LEGACY_UPDATE_CUTOFF_VERSION)) {
|
|
@@ -32,9 +31,13 @@ export const update = async (argv: minimist.ParsedArgs) => {
|
|
|
32
31
|
process.exit(0);
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
const commitEachMigration = argv.commit;
|
|
36
34
|
const migrations = getMigrationsToRun(version, CURRENT_APP_VERSION);
|
|
37
|
-
|
|
35
|
+
// filter out minimist internal properties (_ and $0) before passing to codemod
|
|
36
|
+
const { _, $0, ...codemodOptions } = argv;
|
|
37
|
+
await runMigrations(migrations, {
|
|
38
|
+
commitEachMigration: !!argv.commit,
|
|
39
|
+
codemodOptions,
|
|
40
|
+
});
|
|
38
41
|
output.success({
|
|
39
42
|
title: `Successfully updated create-plugin from ${version} to ${CURRENT_APP_VERSION}.`,
|
|
40
43
|
});
|
|
@@ -49,48 +52,6 @@ export const update = async (argv: minimist.ParsedArgs) => {
|
|
|
49
52
|
}
|
|
50
53
|
};
|
|
51
54
|
|
|
52
|
-
async function performPreUpdateChecks(argv: minimist.ParsedArgs) {
|
|
53
|
-
if (!(await isGitDirectory()) && !argv.force) {
|
|
54
|
-
output.error({
|
|
55
|
-
title: 'You are not inside a git directory',
|
|
56
|
-
body: [
|
|
57
|
-
`In order to proceed please run ${output.formatCode('git init')} in the root of your project and commit your changes.`,
|
|
58
|
-
`(This check is necessary to make sure that the updates are easy to revert and don't interfere with any changes you currently have.`,
|
|
59
|
-
`In case you want to proceed as is please use the ${output.formatCode('--force')} flag.)`,
|
|
60
|
-
],
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!(await isGitDirectoryClean()) && !argv.force) {
|
|
67
|
-
output.error({
|
|
68
|
-
title: 'Please clean your repository working tree before updating.',
|
|
69
|
-
body: [
|
|
70
|
-
'Commit your changes or stash them.',
|
|
71
|
-
`(This check is necessary to make sure that the updates are easy to revert and don't mess with any changes you currently have.`,
|
|
72
|
-
`In case you want to proceed as is please use the ${output.formatCode('--force')} flag.)`,
|
|
73
|
-
],
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (!isPluginDirectory() && !argv.force) {
|
|
80
|
-
output.error({
|
|
81
|
-
title: 'Are you inside a plugin directory?',
|
|
82
|
-
body: [
|
|
83
|
-
`We couldn't find a "src/plugin.json" file under your current directory.`,
|
|
84
|
-
`(Please make sure to run this command from the root of your plugin folder. In case you want to proceed as is please use the ${output.formatCode(
|
|
85
|
-
'--force'
|
|
86
|
-
)} flag.)`,
|
|
87
|
-
],
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
process.exit(1);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
55
|
/**
|
|
95
56
|
* Prepares a plugin for migrations by running the legacy update command and installing dependencies.
|
|
96
57
|
* This is a one time operation that ensures the plugin configs are "as expected" by the new migration system.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import minimist from 'minimist';
|
|
2
|
+
import { isGitDirectory, isGitDirectoryClean } from './utils.git.js';
|
|
3
|
+
import { isPluginDirectory } from './utils.plugin.js';
|
|
4
|
+
import { output } from './utils.console.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Ensures git directory exists, is clean, and we're in a plugin directory
|
|
8
|
+
*/
|
|
9
|
+
export async function performPreCodemodChecks(argv: minimist.ParsedArgs): Promise<void> {
|
|
10
|
+
if (!(await isGitDirectory()) && !argv.force) {
|
|
11
|
+
output.error({
|
|
12
|
+
title: 'You are not inside a git directory',
|
|
13
|
+
body: [
|
|
14
|
+
`In order to proceed please run ${output.formatCode('git init')} in the root of your project and commit your changes.`,
|
|
15
|
+
`(This check is necessary to make sure that changes are easy to revert and don't interfere with any changes you currently have.`,
|
|
16
|
+
`In case you want to proceed as is please use the ${output.formatCode('--force')} flag.)`,
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!(await isGitDirectoryClean()) && !argv.force) {
|
|
24
|
+
output.error({
|
|
25
|
+
title: 'Please clean your repository working tree before making changes.',
|
|
26
|
+
body: [
|
|
27
|
+
'Commit your changes or stash them.',
|
|
28
|
+
`(This check is necessary to make sure that changes are easy to revert and don't mess with any changes you currently have.`,
|
|
29
|
+
`In case you want to proceed as is please use the ${output.formatCode('--force')} flag.)`,
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!isPluginDirectory() && !argv.force) {
|
|
37
|
+
output.error({
|
|
38
|
+
title: 'Are you inside a plugin directory?',
|
|
39
|
+
body: [
|
|
40
|
+
`We couldn't find a "src/plugin.json" file under your current directory.`,
|
|
41
|
+
`(Please make sure to run this command from the root of your plugin folder. In case you want to proceed as is please use the ${output.formatCode('--force')} flag.)`,
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { gte, satisfies } from 'semver';
|
|
2
|
-
import { Context } from './context.js';
|
|
3
|
-
import defaultMigrations from './migrations.js';
|
|
4
|
-
import { migrationsDebug, formatFiles, flushChanges, printChanges, installNPMDependencies } from './utils.js';
|
|
5
|
-
import { gitCommitNoVerify } from '../utils/utils.git.js';
|
|
6
|
-
import { setRootConfig } from '../utils/utils.config.js';
|
|
7
|
-
import { output } from '../utils/utils.console.js';
|
|
8
|
-
import { CURRENT_APP_VERSION } from '../utils/utils.version.js';
|
|
9
|
-
|
|
10
|
-
function getMigrationsToRun(fromVersion, toVersion, migrations = defaultMigrations.migrations) {
|
|
11
|
-
const semverRange = `${fromVersion} - ${toVersion}`;
|
|
12
|
-
const migrationsToRun = Object.entries(migrations).sort((a, b) => {
|
|
13
|
-
return gte(a[1].version, b[1].version) ? 1 : -1;
|
|
14
|
-
}).reduce((acc, [key, meta]) => {
|
|
15
|
-
if (satisfies(meta.version, semverRange)) {
|
|
16
|
-
acc[key] = meta;
|
|
17
|
-
}
|
|
18
|
-
return acc;
|
|
19
|
-
}, {});
|
|
20
|
-
return migrationsToRun;
|
|
21
|
-
}
|
|
22
|
-
async function runMigrations(migrations, options = {}) {
|
|
23
|
-
const basePath = process.cwd();
|
|
24
|
-
const migrationList = Object.entries(migrations).map(
|
|
25
|
-
([key, migrationMeta]) => `${key} (${migrationMeta.description})`
|
|
26
|
-
);
|
|
27
|
-
const migrationListBody = migrationList.length > 0 ? output.bulletList(migrationList) : ["No migrations to run."];
|
|
28
|
-
output.log({ title: "Running the following migrations:", body: migrationListBody });
|
|
29
|
-
for (const [key, migration] of Object.entries(migrations)) {
|
|
30
|
-
try {
|
|
31
|
-
const context = await runMigration(migration, new Context(basePath));
|
|
32
|
-
const shouldCommit = options.commitEachMigration && context.hasChanges();
|
|
33
|
-
migrationsDebug(`context for "${key} (${migration.migrationScript})":`);
|
|
34
|
-
migrationsDebug("%O", context.listChanges());
|
|
35
|
-
await formatFiles(context);
|
|
36
|
-
flushChanges(context);
|
|
37
|
-
printChanges(context, key, migration);
|
|
38
|
-
installNPMDependencies(context);
|
|
39
|
-
if (shouldCommit) {
|
|
40
|
-
await gitCommitNoVerify(`chore: run create-plugin migration - ${key} (${migration.migrationScript})`);
|
|
41
|
-
}
|
|
42
|
-
} catch (error) {
|
|
43
|
-
if (error instanceof Error) {
|
|
44
|
-
throw new Error(`Error running migration "${key} (${migration.migrationScript})": ${error.message}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
setRootConfig({ version: CURRENT_APP_VERSION });
|
|
49
|
-
if (options.commitEachMigration) {
|
|
50
|
-
await gitCommitNoVerify(`chore: update .config/.cprc.json to version ${CURRENT_APP_VERSION}.`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
async function runMigration(migration, context) {
|
|
54
|
-
const module = await import(migration.migrationScript);
|
|
55
|
-
return module.default(context);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export { getMigrationsToRun, runMigration, runMigrations };
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { LEGACY_UPDATE_CUTOFF_VERSION } from '../constants.js';
|
|
2
|
-
|
|
3
|
-
var defaultMigrations = {
|
|
4
|
-
migrations: {
|
|
5
|
-
"001-update-grafana-compose-extend": {
|
|
6
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
7
|
-
description: "Update ./docker-compose.yaml to extend from ./.config/docker-compose-base.yaml.",
|
|
8
|
-
migrationScript: "./scripts/001-update-grafana-compose-extend.js"
|
|
9
|
-
},
|
|
10
|
-
"002-update-is-compatible-workflow": {
|
|
11
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
12
|
-
description: "Update ./.github/workflows/is-compatible.yml to use is-compatible github action instead of calling levitate directly",
|
|
13
|
-
migrationScript: "./scripts/002-update-is-compatible-workflow.js"
|
|
14
|
-
},
|
|
15
|
-
"003-update-eslint-deprecation-rule": {
|
|
16
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
17
|
-
description: "Replace deprecated eslint-plugin-deprecation with @typescript-eslint/no-deprecated rule.",
|
|
18
|
-
migrationScript: "./scripts/003-update-eslint-deprecation-rule.js"
|
|
19
|
-
},
|
|
20
|
-
"004-eslint9-flat-config": {
|
|
21
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
22
|
-
description: "Migrate eslint config to flat config format and update devDependencies to latest versions.",
|
|
23
|
-
migrationScript: "./scripts/004-eslint9-flat-config.js"
|
|
24
|
-
},
|
|
25
|
-
"005-react-18-3": {
|
|
26
|
-
version: "6.1.9",
|
|
27
|
-
description: "Update React and ReactDOM 18.x versions to ^18.3.0 to surface React 19 compatibility issues.",
|
|
28
|
-
migrationScript: "./scripts/005-react-18-3.js"
|
|
29
|
-
},
|
|
30
|
-
"006-webpack-nested-fix": {
|
|
31
|
-
version: "6.1.11",
|
|
32
|
-
description: "Fix webpack variable replacement in nested plugins files.",
|
|
33
|
-
migrationScript: "./scripts/006-webpack-nested-fix.js"
|
|
34
|
-
},
|
|
35
|
-
"007-remove-testing-library-types": {
|
|
36
|
-
version: "6.1.13",
|
|
37
|
-
description: "Add setupTests.d.ts for @testing-library/jest-dom types and remove @types/testing-library__jest-dom npm package.",
|
|
38
|
-
migrationScript: "./scripts/007-remove-testing-library-types.js"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export { defaultMigrations as default };
|