@grafana/create-plugin 6.2.0-canary.2314.19503588692.0 → 6.2.0-canary.2314.19529376890.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/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/templates/panel/.config/AGENTS/fundamentals.md +72 -50
- package/templates/panel/.config/AGENTS/howto/add-panel-options.md +130 -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/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
|
@@ -1,66 +1,88 @@
|
|
|
1
|
-
|
|
1
|
+
# Project overview
|
|
2
2
|
|
|
3
|
-
This repository contains a Grafana panel plugin
|
|
3
|
+
This repository contains a **Grafana panel plugin**, providing a custom visualization for Grafana dashboards.
|
|
4
|
+
Panel plugins are used to:
|
|
4
5
|
|
|
5
|
-
-
|
|
6
|
-
- Add
|
|
7
|
-
- Visualize or control external systems (
|
|
6
|
+
- Display data from Grafana data sources in custom ways
|
|
7
|
+
- Add interactive behavior (drill-downs, navigation, etc.)
|
|
8
|
+
- Visualize or control external systems (IoT, integrations, custom controls)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
---
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
# Plugin anatomy
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
- Declares plugin ID, type (`panel`), name, version, and metadata
|
|
15
|
-
- Picked up by Grafana during boot time to register plugin.
|
|
14
|
+
A typical panel plugin includes:
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
- Calls `new PanelPlugin(PanelComponent)` from `@grafana/data` and expose the instance from the module.
|
|
19
|
-
- Optionally wires in the options editor, panel migration handler, and panel defaults
|
|
16
|
+
## **plugin.json**
|
|
20
17
|
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
- Receives props such as `data`, `timeRange`, `width`, `height`, and `options`
|
|
24
|
-
- Works with Grafana data frames and field configuration APIs to read query results and settings.
|
|
18
|
+
- Declares plugin ID, type (`panel`), name, version
|
|
19
|
+
- Loaded by Grafana at startup
|
|
25
20
|
|
|
26
|
-
##
|
|
21
|
+
## **Main module (`src/module.ts`)**
|
|
27
22
|
|
|
28
|
-
|
|
23
|
+
- Exports: `new PanelPlugin(PanelComponent)`
|
|
24
|
+
- Registers panel options, migrations, defaults, extensions (links, components)
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
- Follow idiomatic React and TypeScript practices consistent with Grafana’s official example plugins
|
|
32
|
-
- Treat AGENTS.md as the authoritative source. If anything in .config/AGENTS conflicts with this file, follow the instructions in AGENTS.md
|
|
26
|
+
## **Panel component (`src/components/Panel.tsx`)**
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
- React component receiving: `data`, `timeRange`, `width`, `height`, `options`
|
|
29
|
+
- Renders visualization using Grafana data frames and field configs
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
- `src/module.ts` – main plugin entry point (creates `PanelPlugin`)
|
|
38
|
-
- `src/components` – React components for the panel
|
|
39
|
-
- `src/types.ts` – TypeScript types for panel options and internal models
|
|
40
|
-
- `tests/` – End-to-end tests (if configured)
|
|
41
|
-
- `provisioning/` - Provisioning files used in the local development environment.
|
|
42
|
-
- `README.md` – Human-facing project documentation
|
|
31
|
+
---
|
|
43
32
|
|
|
44
|
-
|
|
33
|
+
# Agent goals
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
- Prefer **functional React components** and hooks.
|
|
48
|
-
- Use **Grafana UI components** (`@grafana/ui`) and **Grafana data APIs** (`@grafana/data`) or **Grafana runtime APIs** (`@grafana/runtime`) instead of custom UI or data abstractions whenever possible.
|
|
49
|
-
- Keep the panel responsive:
|
|
50
|
-
- Respect `width` and `height` props.
|
|
51
|
-
- Avoid fixed layout sizes that break in narrow panels or large screens.
|
|
52
|
-
- Avoid introducing new dependencies unless:
|
|
53
|
-
- They’re necessary
|
|
54
|
-
- They’re compatible with Grafana’s frontend environment and plugin guidelines
|
|
55
|
-
- If custom styling is needed, please using `Emotion`.
|
|
35
|
+
Agents must:
|
|
56
36
|
|
|
57
|
-
|
|
37
|
+
- Preserve the existing options schema unless adding a migration handler
|
|
38
|
+
- Follow idiomatic React + TypeScript patterns used in official Grafana examples
|
|
39
|
+
- Treat **`AGENTS.md` as the authoritative source** over `.config/AGENTS/*`
|
|
58
40
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
# Repository layout
|
|
44
|
+
|
|
45
|
+
- `plugin.json` — Panel plugin manifest
|
|
46
|
+
- `src/module.ts` — Main plugin entry
|
|
47
|
+
- `src/components/` — Panel React components
|
|
48
|
+
- `src/types.ts` — Option and model types
|
|
49
|
+
- `tests/` — E2E tests (if present)
|
|
50
|
+
- `provisioning/` — Local development provisioning
|
|
51
|
+
- `README.md` — Human documentation
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
# Coding guidelines
|
|
56
|
+
|
|
57
|
+
- Use **TypeScript** and **functional React components**
|
|
58
|
+
- Use **@grafana/ui**, **@grafana/data**, **@grafana/runtime**
|
|
59
|
+
- Respect `width` and `height`; keep layout responsive
|
|
60
|
+
- Avoid unnecessary dependencies; ensure Grafana compatibility
|
|
61
|
+
- Use useTheme2() from @grafana/ui for visual tokens
|
|
62
|
+
- Avoid to hardcode colors, spacing, padding, or font sizes
|
|
63
|
+
- Follow existing file structure
|
|
64
|
+
- Keep code typed and predictable
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# Safety & constraints
|
|
69
|
+
|
|
70
|
+
Agents must **not**:
|
|
71
|
+
|
|
72
|
+
- Change plugin IDs or plugin type in `plugin.json`
|
|
73
|
+
- Modify anything under `.config/*`
|
|
74
|
+
- Add a backend — panel plugins are **frontend only**
|
|
75
|
+
- Remove or change existing options without a migration handler
|
|
76
|
+
- Break public APIs (options, field configs, panel props)
|
|
77
|
+
- Store or use credentials.
|
|
78
|
+
|
|
79
|
+
Agents **should**:
|
|
80
|
+
|
|
81
|
+
- Keep the plugin backward compatible
|
|
82
|
+
- Mirror patterns from Grafana’s official panel plugin examples
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
# How-to
|
|
87
|
+
|
|
88
|
+
- [How-to add panel options](./howto/add-panel-options.md)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Adding a New Panel Option
|
|
2
|
+
|
|
3
|
+
Always complete **all three steps**:
|
|
4
|
+
|
|
5
|
+
### **1. Extend the options type**
|
|
6
|
+
|
|
7
|
+
File: `src/types.ts`
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export interface SimpleOptions {
|
|
11
|
+
// existing...
|
|
12
|
+
myOptionName: MyOptionType;
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
* Property name must match the builder `path`.
|
|
17
|
+
* Type must match expected editor output.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
### **2. Register the option in `setPanelOptions`**
|
|
22
|
+
|
|
23
|
+
File: `src/module.ts` inside `setPanelOptions((builder) => { ... })`
|
|
24
|
+
|
|
25
|
+
Use the correct builder method:
|
|
26
|
+
|
|
27
|
+
| Type | Builder |
|
|
28
|
+
| ------------------ | -------------------- |
|
|
29
|
+
| boolean | `addBooleanSwitch` |
|
|
30
|
+
| number | `addNumberInput` |
|
|
31
|
+
| string | `addTextInput` |
|
|
32
|
+
| select | `addSelect` |
|
|
33
|
+
| radio | `addRadio` |
|
|
34
|
+
| radio group | `addRadio` |
|
|
35
|
+
| slider | `addSliderInput` |
|
|
36
|
+
| color picker | `addColorPicker` |
|
|
37
|
+
| unit picker | `addUnitPicker` |
|
|
38
|
+
| field namer picker | `addFieldNamePicker` |
|
|
39
|
+
|
|
40
|
+
Template:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
builder.addXxx({
|
|
44
|
+
path: 'myOptionName', // must match type property
|
|
45
|
+
name: 'My option',
|
|
46
|
+
defaultValue: <default>,
|
|
47
|
+
description: '',
|
|
48
|
+
settings: { /* optional */ },
|
|
49
|
+
// Optional visibility rule:
|
|
50
|
+
// showIf: (opts) => opts.someOtherOption,
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Rules:
|
|
55
|
+
|
|
56
|
+
* Every option **must** have a `defaultValue`.
|
|
57
|
+
* Put numeric constraints in `settings` (`min`, `max`, `step`).
|
|
58
|
+
* Use `showIf` for conditional display.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### **3. Use the option in the panel component**
|
|
63
|
+
|
|
64
|
+
File: `src/Panel.tsx` (or equivalent)
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
export const Panel = ({ options }) => {
|
|
68
|
+
const { myOptionName } = options;
|
|
69
|
+
// apply it in rendering/logic
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
No option may remain unused.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
# Quick Editor Recipes
|
|
78
|
+
|
|
79
|
+
### **Boolean**
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
.addBooleanSwitch({ path: 'flag', name: 'Flag', defaultValue: false })
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### **Number**
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
.addNumberInput({
|
|
89
|
+
path: 'max',
|
|
90
|
+
name: 'Max value',
|
|
91
|
+
defaultValue: 10,
|
|
92
|
+
settings: { min: 1, max: 100, step: 1 },
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### **String**
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
.addTextInput({ path: 'label', name: 'Label', defaultValue: '' })
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### **Select**
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
.addSelect({
|
|
106
|
+
path: 'mode',
|
|
107
|
+
name: 'Mode',
|
|
108
|
+
defaultValue: 'auto',
|
|
109
|
+
settings: { options: [
|
|
110
|
+
{ value: 'a', label: 'A' },
|
|
111
|
+
{ value: 'b', label: 'B' },
|
|
112
|
+
]},
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### **Radio**
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
.addRadio({
|
|
120
|
+
path: 'size',
|
|
121
|
+
name: 'Size',
|
|
122
|
+
defaultValue: 'md',
|
|
123
|
+
settings: { options: [
|
|
124
|
+
{ value: 'sm', label: 'Small' },
|
|
125
|
+
{ value: 'md', label: 'Medium' },
|
|
126
|
+
{ value: 'lg', label: 'Large' },
|
|
127
|
+
]},
|
|
128
|
+
showIf: (o) => o.showSize,
|
|
129
|
+
})
|
|
130
|
+
```
|
|
@@ -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 };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
function migrate(context) {
|
|
2
|
-
const rawPkgJson = context.getFile("./package.json") ?? "{}";
|
|
3
|
-
const packageJson = JSON.parse(rawPkgJson);
|
|
4
|
-
if (packageJson.scripts && packageJson.scripts.build) {
|
|
5
|
-
const buildScript = packageJson.scripts.build;
|
|
6
|
-
const pattern = /(webpack.+-c\s.+\.ts)\s(.+)/;
|
|
7
|
-
if (pattern.test(buildScript) && !buildScript.includes("--profile")) {
|
|
8
|
-
packageJson.scripts.build = buildScript.replace(pattern, `$1 --profile $2`);
|
|
9
|
-
}
|
|
10
|
-
context.updateFile("./package.json", JSON.stringify(packageJson, null, 2));
|
|
11
|
-
}
|
|
12
|
-
if (context.doesFileExist("./src/README.md")) {
|
|
13
|
-
context.deleteFile("./src/README.md");
|
|
14
|
-
}
|
|
15
|
-
if (!context.doesFileExist("./src/foo.json")) {
|
|
16
|
-
context.addFile("./src/foo.json", JSON.stringify({ foo: "bar" }));
|
|
17
|
-
}
|
|
18
|
-
if (context.doesFileExist(".eslintrc")) {
|
|
19
|
-
context.renameFile(".eslintrc", ".eslint.config.json");
|
|
20
|
-
}
|
|
21
|
-
context.readDir("./src");
|
|
22
|
-
return context;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export { migrate as default };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
migrations: {
|
|
3
|
-
'migration-key1': {
|
|
4
|
-
version: '5.0.0',
|
|
5
|
-
description: 'Update project to use new cache directory',
|
|
6
|
-
migrationScript: './5-0-0-cache-directory.js',
|
|
7
|
-
},
|
|
8
|
-
'migration-key2': {
|
|
9
|
-
version: '5.4.0',
|
|
10
|
-
description: 'Update project to use new cache directory',
|
|
11
|
-
migrationScript: './5-4-0-cache-directory.js',
|
|
12
|
-
},
|
|
13
|
-
'migration-key3': {
|
|
14
|
-
version: '6.0.0',
|
|
15
|
-
description: 'Update project to use new cache directory',
|
|
16
|
-
migrationScript: './5-4-0-cache-directory.js',
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { satisfies, gte } from 'semver';
|
|
2
|
-
import { Context } from './context.js';
|
|
3
|
-
import defaultMigrations, { MigrationMeta } from './migrations.js';
|
|
4
|
-
import { flushChanges, printChanges, migrationsDebug, formatFiles, 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
|
-
export type MigrationFn = (context: Context) => Context | Promise<Context>;
|
|
11
|
-
|
|
12
|
-
export function getMigrationsToRun(
|
|
13
|
-
fromVersion: string,
|
|
14
|
-
toVersion: string,
|
|
15
|
-
migrations: Record<string, MigrationMeta> = defaultMigrations.migrations
|
|
16
|
-
): Record<string, MigrationMeta> {
|
|
17
|
-
const semverRange = `${fromVersion} - ${toVersion}`;
|
|
18
|
-
|
|
19
|
-
const migrationsToRun = Object.entries(migrations)
|
|
20
|
-
.sort((a, b) => {
|
|
21
|
-
return gte(a[1].version, b[1].version) ? 1 : -1;
|
|
22
|
-
})
|
|
23
|
-
.reduce<Record<string, MigrationMeta>>((acc, [key, meta]) => {
|
|
24
|
-
if (satisfies(meta.version, semverRange)) {
|
|
25
|
-
acc[key] = meta;
|
|
26
|
-
}
|
|
27
|
-
return acc;
|
|
28
|
-
}, {});
|
|
29
|
-
|
|
30
|
-
return migrationsToRun;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
type RunMigrationsOptions = {
|
|
34
|
-
commitEachMigration?: boolean;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export async function runMigrations(migrations: Record<string, MigrationMeta>, options: RunMigrationsOptions = {}) {
|
|
38
|
-
const basePath = process.cwd();
|
|
39
|
-
const migrationList = Object.entries(migrations).map(
|
|
40
|
-
([key, migrationMeta]) => `${key} (${migrationMeta.description})`
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const migrationListBody = migrationList.length > 0 ? output.bulletList(migrationList) : ['No migrations to run.'];
|
|
44
|
-
|
|
45
|
-
output.log({ title: 'Running the following migrations:', body: migrationListBody });
|
|
46
|
-
|
|
47
|
-
for (const [key, migration] of Object.entries(migrations)) {
|
|
48
|
-
try {
|
|
49
|
-
const context = await runMigration(migration, new Context(basePath));
|
|
50
|
-
const shouldCommit = options.commitEachMigration && context.hasChanges();
|
|
51
|
-
|
|
52
|
-
migrationsDebug(`context for "${key} (${migration.migrationScript})":`);
|
|
53
|
-
migrationsDebug('%O', context.listChanges());
|
|
54
|
-
|
|
55
|
-
await formatFiles(context);
|
|
56
|
-
flushChanges(context);
|
|
57
|
-
printChanges(context, key, migration);
|
|
58
|
-
|
|
59
|
-
installNPMDependencies(context);
|
|
60
|
-
|
|
61
|
-
if (shouldCommit) {
|
|
62
|
-
await gitCommitNoVerify(`chore: run create-plugin migration - ${key} (${migration.migrationScript})`);
|
|
63
|
-
}
|
|
64
|
-
} catch (error) {
|
|
65
|
-
if (error instanceof Error) {
|
|
66
|
-
throw new Error(`Error running migration "${key} (${migration.migrationScript})": ${error.message}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
setRootConfig({ version: CURRENT_APP_VERSION });
|
|
72
|
-
|
|
73
|
-
if (options.commitEachMigration) {
|
|
74
|
-
await gitCommitNoVerify(`chore: update .config/.cprc.json to version ${CURRENT_APP_VERSION}.`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export async function runMigration(migration: MigrationMeta, context: Context): Promise<Context> {
|
|
79
|
-
const module: { default: MigrationFn } = await import(migration.migrationScript);
|
|
80
|
-
|
|
81
|
-
return module.default(context);
|
|
82
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import defaultMigrations from './migrations.js';
|
|
4
|
-
|
|
5
|
-
describe('migrations json', () => {
|
|
6
|
-
// As migration scripts are imported dynamically when update is run we assert the path is valid
|
|
7
|
-
// Vitest 4 reimplemented it's workers which caused the previous dynamic import tests to fail.
|
|
8
|
-
// This test now only asserts that the source file exists.
|
|
9
|
-
Object.entries(defaultMigrations.migrations).forEach(([key, migration]) => {
|
|
10
|
-
it(`should have a valid migration script path for ${key}`, () => {
|
|
11
|
-
const migrationPathString = migration.migrationScript.replace('.js', '.ts');
|
|
12
|
-
const path = join(__dirname, migrationPathString);
|
|
13
|
-
expect(existsSync(path)).toBe(true);
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { LEGACY_UPDATE_CUTOFF_VERSION } from '../constants.js';
|
|
2
|
-
|
|
3
|
-
export type MigrationMeta = {
|
|
4
|
-
version: string;
|
|
5
|
-
description: string;
|
|
6
|
-
migrationScript: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
type Migrations = {
|
|
10
|
-
migrations: Record<string, MigrationMeta>;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Do not use LEGACY_UPDATE_CUTOFF_VERSION for new migrations. It was used to force migrations to run
|
|
14
|
-
// for those written before the switch to updates as migrations.
|
|
15
|
-
export default {
|
|
16
|
-
migrations: {
|
|
17
|
-
'001-update-grafana-compose-extend': {
|
|
18
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
19
|
-
description: 'Update ./docker-compose.yaml to extend from ./.config/docker-compose-base.yaml.',
|
|
20
|
-
migrationScript: './scripts/001-update-grafana-compose-extend.js',
|
|
21
|
-
},
|
|
22
|
-
'002-update-is-compatible-workflow': {
|
|
23
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
24
|
-
description:
|
|
25
|
-
'Update ./.github/workflows/is-compatible.yml to use is-compatible github action instead of calling levitate directly',
|
|
26
|
-
migrationScript: './scripts/002-update-is-compatible-workflow.js',
|
|
27
|
-
},
|
|
28
|
-
'003-update-eslint-deprecation-rule': {
|
|
29
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
30
|
-
description: 'Replace deprecated eslint-plugin-deprecation with @typescript-eslint/no-deprecated rule.',
|
|
31
|
-
migrationScript: './scripts/003-update-eslint-deprecation-rule.js',
|
|
32
|
-
},
|
|
33
|
-
'004-eslint9-flat-config': {
|
|
34
|
-
version: LEGACY_UPDATE_CUTOFF_VERSION,
|
|
35
|
-
description: 'Migrate eslint config to flat config format and update devDependencies to latest versions.',
|
|
36
|
-
migrationScript: './scripts/004-eslint9-flat-config.js',
|
|
37
|
-
},
|
|
38
|
-
'005-react-18-3': {
|
|
39
|
-
version: '6.1.9',
|
|
40
|
-
description: 'Update React and ReactDOM 18.x versions to ^18.3.0 to surface React 19 compatibility issues.',
|
|
41
|
-
migrationScript: './scripts/005-react-18-3.js',
|
|
42
|
-
},
|
|
43
|
-
'006-webpack-nested-fix': {
|
|
44
|
-
version: '6.1.11',
|
|
45
|
-
description: 'Fix webpack variable replacement in nested plugins files.',
|
|
46
|
-
migrationScript: './scripts/006-webpack-nested-fix.js',
|
|
47
|
-
},
|
|
48
|
-
'007-remove-testing-library-types': {
|
|
49
|
-
version: '6.1.13',
|
|
50
|
-
description:
|
|
51
|
-
'Add setupTests.d.ts for @testing-library/jest-dom types and remove @types/testing-library__jest-dom npm package.',
|
|
52
|
-
migrationScript: './scripts/007-remove-testing-library-types.js',
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
} as Migrations;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import migrate from './example-migration.js';
|
|
2
|
-
import { createDefaultContext } from '../test-utils.js';
|
|
3
|
-
|
|
4
|
-
describe('Migration - append profile to webpack', () => {
|
|
5
|
-
test('should update the package.json', async () => {
|
|
6
|
-
const context = createDefaultContext();
|
|
7
|
-
|
|
8
|
-
context.updateFile(
|
|
9
|
-
'./package.json',
|
|
10
|
-
JSON.stringify({
|
|
11
|
-
scripts: {
|
|
12
|
-
build: 'webpack -c ./.config/webpack/webpack.config.ts --env production',
|
|
13
|
-
},
|
|
14
|
-
})
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
const updatedContext = await migrate(context);
|
|
18
|
-
|
|
19
|
-
expect(updatedContext.getFile('./package.json')).toMatch(
|
|
20
|
-
'webpack -c ./.config/webpack/webpack.config.ts --profile --env production'
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
expect(updatedContext.readDir('./src')).toEqual(['src/FOO.md', 'src/foo.json']);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should not make additional changes when run multiple times', async () => {
|
|
27
|
-
const context = await createDefaultContext();
|
|
28
|
-
|
|
29
|
-
await context.updateFile(
|
|
30
|
-
'./package.json',
|
|
31
|
-
JSON.stringify({
|
|
32
|
-
scripts: {
|
|
33
|
-
build: 'webpack -c ./.config/webpack/webpack.config.ts --env production',
|
|
34
|
-
},
|
|
35
|
-
})
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
await expect(migrate).toBeIdempotent(context);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { Context } from '../context.js';
|
|
2
|
-
|
|
3
|
-
export default function migrate(context: Context): Context {
|
|
4
|
-
const rawPkgJson = context.getFile('./package.json') ?? '{}';
|
|
5
|
-
const packageJson = JSON.parse(rawPkgJson);
|
|
6
|
-
|
|
7
|
-
if (packageJson.scripts && packageJson.scripts.build) {
|
|
8
|
-
const buildScript = packageJson.scripts.build;
|
|
9
|
-
|
|
10
|
-
const pattern = /(webpack.+-c\s.+\.ts)\s(.+)/;
|
|
11
|
-
|
|
12
|
-
if (pattern.test(buildScript) && !buildScript.includes('--profile')) {
|
|
13
|
-
packageJson.scripts.build = buildScript.replace(pattern, `$1 --profile $2`);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
context.updateFile('./package.json', JSON.stringify(packageJson, null, 2));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (context.doesFileExist('./src/README.md')) {
|
|
20
|
-
context.deleteFile('./src/README.md');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (!context.doesFileExist('./src/foo.json')) {
|
|
24
|
-
context.addFile('./src/foo.json', JSON.stringify({ foo: 'bar' }));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (context.doesFileExist('.eslintrc')) {
|
|
28
|
-
context.renameFile('.eslintrc', '.eslint.config.json');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
context.readDir('./src');
|
|
32
|
-
|
|
33
|
-
return context;
|
|
34
|
-
}
|
/package/dist/{migrations → codemods/migrations}/scripts/001-update-grafana-compose-extend.js
RENAMED
|
File without changes
|
/package/dist/{migrations → codemods/migrations}/scripts/002-update-is-compatible-workflow.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|