@grafana/create-plugin 6.2.0-canary.2233.19133609453.0 → 6.2.0-canary.2283.19173715977.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/CONTRIBUTING.md +3 -0
  3. package/dist/bin/run.js +1 -3
  4. package/dist/commands/update.command.js +1 -1
  5. package/dist/{codemods → migrations}/context.js +2 -3
  6. package/dist/{codemods/migrations → migrations}/manager.js +7 -8
  7. package/dist/{codemods/migrations → migrations}/migrations.js +6 -3
  8. package/dist/{codemods/migrations → migrations}/scripts/003-update-eslint-deprecation-rule.js +1 -1
  9. package/dist/{codemods/migrations → migrations}/scripts/004-eslint9-flat-config.js +1 -2
  10. package/dist/migrations/scripts/005-react-18-3.js +20 -0
  11. package/dist/{codemods → migrations}/utils.js +22 -5
  12. package/dist/utils/utils.config.js +1 -16
  13. package/package.json +2 -2
  14. package/src/bin/run.ts +1 -2
  15. package/src/commands/index.ts +0 -1
  16. package/src/commands/update.command.ts +1 -1
  17. package/src/{codemods → migrations}/context.test.ts +10 -10
  18. package/src/{codemods → migrations}/context.ts +2 -4
  19. package/src/{codemods/migrations → migrations}/manager.test.ts +10 -15
  20. package/src/{codemods/migrations → migrations}/manager.ts +9 -10
  21. package/src/{codemods/migrations → migrations}/migrations.ts +8 -3
  22. package/src/{codemods/migrations → migrations}/scripts/001-update-grafana-compose-extend.test.ts +1 -1
  23. package/src/{codemods/migrations → migrations}/scripts/001-update-grafana-compose-extend.ts +1 -1
  24. package/src/{codemods/migrations → migrations}/scripts/002-update-is-compatible-workflow.test.ts +1 -1
  25. package/src/{codemods/migrations → migrations}/scripts/002-update-is-compatible-workflow.ts +1 -1
  26. package/src/{codemods/migrations → migrations}/scripts/003-update-eslint-deprecation-rule.test.ts +1 -1
  27. package/src/{codemods/migrations → migrations}/scripts/003-update-eslint-deprecation-rule.ts +2 -2
  28. package/src/{codemods/migrations → migrations}/scripts/004-eslint9-flat-config.test.ts +1 -1
  29. package/src/{codemods/migrations → migrations}/scripts/004-eslint9-flat-config.ts +2 -3
  30. package/src/migrations/scripts/005-react-18-3.test.ts +147 -0
  31. package/src/migrations/scripts/005-react-18-3.ts +19 -0
  32. package/src/{codemods/migrations → migrations}/scripts/example-migration.test.ts +1 -1
  33. package/src/{codemods/migrations → migrations}/scripts/example-migration.ts +1 -1
  34. package/src/{codemods/migrations → migrations}/utils.test.ts +4 -4
  35. package/src/{codemods → migrations}/utils.ts +33 -37
  36. package/src/utils/utils.config.ts +1 -28
  37. package/templates/common/_package.json +5 -3
  38. package/templates/github/workflows/cp-update.yml +8 -13
  39. package/dist/codemods/additions/additions.js +0 -11
  40. package/dist/codemods/additions/manager.js +0 -115
  41. package/dist/codemods/additions/scripts/example-addition.js +0 -61
  42. package/dist/codemods/additions/utils.js +0 -10
  43. package/dist/codemods/migrations/utils.js +0 -10
  44. package/dist/commands/add.command.js +0 -86
  45. package/src/codemods/additions/additions.ts +0 -23
  46. package/src/codemods/additions/manager.ts +0 -145
  47. package/src/codemods/additions/scripts/example-addition.test.ts +0 -111
  48. package/src/codemods/additions/scripts/example-addition.ts +0 -79
  49. package/src/codemods/additions/utils.ts +0 -12
  50. package/src/codemods/migrations/utils.ts +0 -12
  51. package/src/codemods/types.ts +0 -21
  52. package/src/commands/add.command.ts +0 -97
  53. /package/dist/{codemods/migrations → migrations}/scripts/001-update-grafana-compose-extend.js +0 -0
  54. /package/dist/{codemods/migrations → migrations}/scripts/002-update-is-compatible-workflow.js +0 -0
  55. /package/dist/{codemods/migrations → migrations}/scripts/example-migration.js +0 -0
  56. /package/src/{codemods/migrations → migrations}/fixtures/foo/bar.ts +0 -0
  57. /package/src/{codemods/migrations → migrations}/fixtures/foo/baz.ts +0 -0
  58. /package/src/{codemods/migrations → migrations}/fixtures/migrations.ts +0 -0
  59. /package/src/{codemods/migrations → migrations}/migrations.test.ts +0 -0
  60. /package/src/{codemods → migrations}/test-utils.ts +0 -0
@@ -0,0 +1,147 @@
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 not downgrade React 19.0.0 to 18.3.1', async () => {
48
+ const context = new Context('/virtual');
49
+ const packageJson = {
50
+ dependencies: {
51
+ react: '^19.0.0',
52
+ 'react-dom': '^19.0.0',
53
+ },
54
+ devDependencies: {
55
+ '@types/react': '^19.0.0',
56
+ '@types/react-dom': '^19.0.0',
57
+ },
58
+ };
59
+ context.addFile('./package.json', JSON.stringify(packageJson, null, 2));
60
+
61
+ await migrate(context);
62
+
63
+ const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
64
+ expect(updatedPackageJson.dependencies.react).toBe('^19.0.0');
65
+ expect(updatedPackageJson.dependencies['react-dom']).toBe('^19.0.0');
66
+ expect(updatedPackageJson.devDependencies['@types/react']).toBe('^19.0.0');
67
+ expect(updatedPackageJson.devDependencies['@types/react-dom']).toBe('^19.0.0');
68
+ });
69
+
70
+ it('should update React 18.0.0 to 18.3.1', async () => {
71
+ const context = new Context('/virtual');
72
+ context.addFile(
73
+ './package.json',
74
+ JSON.stringify({
75
+ dependencies: {
76
+ react: '^18.0.0',
77
+ },
78
+ })
79
+ );
80
+
81
+ await migrate(context);
82
+
83
+ const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
84
+ expect(updatedPackageJson.dependencies.react).toBe('^18.3.1');
85
+ expect(updatedPackageJson.devDependencies?.['@types/react']).toBe('^18.3.1');
86
+ });
87
+
88
+ it('should not update React if version is already 18.3.1 or higher', async () => {
89
+ const context = new Context('/virtual');
90
+ const packageJson = {
91
+ dependencies: {
92
+ react: '^18.3.1',
93
+ 'react-dom': '^18.3.1',
94
+ },
95
+ devDependencies: {
96
+ '@types/react': '^18.3.1',
97
+ '@types/react-dom': '^18.3.1',
98
+ },
99
+ };
100
+ context.addFile('./package.json', JSON.stringify(packageJson, null, 2));
101
+
102
+ await migrate(context);
103
+
104
+ // Since the versions are already 18.3.1, the migration should still run
105
+ // but the versions should remain 18.3.1
106
+ const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
107
+ expect(updatedPackageJson.dependencies.react).toBe('^18.3.1');
108
+ expect(updatedPackageJson.dependencies['react-dom']).toBe('^18.3.1');
109
+ });
110
+
111
+ it('should handle version ranges correctly', async () => {
112
+ const context = new Context('/virtual');
113
+ context.addFile(
114
+ './package.json',
115
+ JSON.stringify({
116
+ dependencies: {
117
+ react: '~18.1.0',
118
+ 'react-dom': '18.2.0',
119
+ },
120
+ })
121
+ );
122
+
123
+ await migrate(context);
124
+
125
+ const updatedPackageJson = JSON.parse(context.getFile('./package.json') || '{}');
126
+ expect(updatedPackageJson.dependencies.react).toBe('^18.3.1');
127
+ expect(updatedPackageJson.dependencies['react-dom']).toBe('^18.3.1');
128
+ });
129
+
130
+ it('should be idempotent', async () => {
131
+ const context = new Context('/virtual');
132
+ context.addFile(
133
+ './package.json',
134
+ JSON.stringify({
135
+ dependencies: {
136
+ react: '^18.2.0',
137
+ 'react-dom': '^18.2.0',
138
+ },
139
+ devDependencies: {
140
+ '@types/react': '^18.2.0',
141
+ '@types/react-dom': '^18.2.0',
142
+ },
143
+ })
144
+ );
145
+ await expect(migrate).toBeIdempotent(context);
146
+ });
147
+ });
@@ -0,0 +1,19 @@
1
+ import { 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.1' }, { '@types/react': '^18.3.1' });
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.1' }, { '@types/react-dom': '^18.3.1' });
15
+ }
16
+ }
17
+ }
18
+ return context;
19
+ }
@@ -1,5 +1,5 @@
1
1
  import migrate from './example-migration.js';
2
- import { createDefaultContext } from '../../test-utils.js';
2
+ import { createDefaultContext } from '../test-utils.js';
3
3
 
4
4
  describe('Migration - append profile to webpack', () => {
5
5
  test('should update the package.json', async () => {
@@ -1,4 +1,4 @@
1
- import type { Context } from '../../context.js';
1
+ import type { Context } from '../context.js';
2
2
 
3
3
  export default function migrate(context: Context): Context {
4
4
  const rawPkgJson = context.getFile('./package.json') ?? '{}';
@@ -1,18 +1,18 @@
1
1
  import { dirSync } from 'tmp';
2
- import { Context } from '../context.js';
2
+ import { Context } from './context.js';
3
3
  import {
4
4
  addDependenciesToPackageJson,
5
5
  removeDependenciesFromPackageJson,
6
6
  flushChanges,
7
7
  formatFiles,
8
+ printChanges,
8
9
  readJsonFile,
9
10
  isVersionGreater,
10
- } from '../utils.js';
11
- import { printChanges } from './utils.js';
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
- import { output } from '../../utils/utils.console.js';
15
+ import { output } from '../utils/utils.console.js';
16
16
 
17
17
  describe('utils', () => {
18
18
  const tmpObj = dirSync({ unsafeCleanup: true });
@@ -1,30 +1,16 @@
1
- /**
2
- * Shared utilities for codemods (migrations and additions).
3
- * These functions work with the Context class to modify plugin codebases.
4
- */
5
-
6
1
  import { dirname, join } from 'node:path';
7
2
  import { createRequire } from 'node:module';
8
3
  import { Context } from './context.js';
9
4
  import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { debug } from '../utils/utils.cli.js';
10
6
  import chalk from 'chalk';
7
+ import { MigrationMeta } from './migrations.js';
11
8
  import { output } from '../utils/utils.console.js';
12
9
  import { getPackageManagerSilentInstallCmd, getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
13
10
  import { execSync } from 'node:child_process';
14
- import { clean, coerce, gt } from 'semver';
15
-
16
- /**
17
- * Generic metadata type for printChanges
18
- */
19
- type ChangeMetadata = {
20
- description: string;
21
- };
11
+ import { clean, coerce, gt, gte } from 'semver';
22
12
 
23
- /**
24
- * Prints changes made to the context in a formatted way.
25
- * Works with both migrations and additions.
26
- */
27
- export function printChanges(context: Context, key: string, meta: ChangeMetadata) {
13
+ export function printChanges(context: Context, key: string, migration: MigrationMeta) {
28
14
  const changes = context.listChanges();
29
15
  const lines = [];
30
16
 
@@ -39,7 +25,7 @@ export function printChanges(context: Context, key: string, meta: ChangeMetadata
39
25
  }
40
26
 
41
27
  output.addHorizontalLine('gray');
42
- output.logSingleLine(`${key} (${meta.description})`);
28
+ output.logSingleLine(`${key} (${migration.description})`);
43
29
 
44
30
  if (lines.length === 0) {
45
31
  output.logSingleLine('No changes were made');
@@ -48,9 +34,6 @@ export function printChanges(context: Context, key: string, meta: ChangeMetadata
48
34
  }
49
35
  }
50
36
 
51
- /**
52
- * Writes all changes from the context to the filesystem.
53
- */
54
37
  export function flushChanges(context: Context) {
55
38
  const basePath = context.basePath;
56
39
  const changes = context.listChanges();
@@ -68,8 +51,10 @@ export function flushChanges(context: Context) {
68
51
  }
69
52
  }
70
53
 
54
+ export const migrationsDebug = debug.extend('migrations');
55
+
71
56
  /**
72
- * Formats the files in the context using the version of prettier found in the local node_modules.
57
+ * Formats the files in the migration context using the version of prettier found in the local node_modules.
73
58
  * If prettier isn't installed or the file is ignored or has no parser, it will not be formatted.
74
59
  *
75
60
  * @param context - The context to format.
@@ -119,12 +104,9 @@ export async function formatFiles(context: Context) {
119
104
  }
120
105
 
121
106
  // Cache the package.json contents to avoid re-installing dependencies if the package.json hasn't changed
122
- // (This runs for each codemod used in an update)
107
+ // (This runs for each migration used in an update)
123
108
  let packageJsonInstallCache: string;
124
109
 
125
- /**
126
- * Installs NPM dependencies if package.json has changed.
127
- */
128
110
  export function installNPMDependencies(context: Context) {
129
111
  const hasPackageJsonChanges = Object.entries(context.listChanges()).some(
130
112
  ([filePath, { changeType }]) => filePath === 'package.json' && changeType === 'update'
@@ -152,9 +134,6 @@ export function installNPMDependencies(context: Context) {
152
134
  }
153
135
  }
154
136
 
155
- /**
156
- * Reads and parses a JSON file from the context.
157
- */
158
137
  export function readJsonFile<T extends object = any>(context: Context, path: string): T {
159
138
  if (!context.doesFileExist(path)) {
160
139
  throw new Error(`Cannot find ${path}`);
@@ -166,9 +145,6 @@ export function readJsonFile<T extends object = any>(context: Context, path: str
166
145
  }
167
146
  }
168
147
 
169
- /**
170
- * Adds or updates dependencies in package.json, preventing downgrades.
171
- */
172
148
  export function addDependenciesToPackageJson(
173
149
  context: Context,
174
150
  dependencies: Record<string, string>,
@@ -184,10 +160,14 @@ export function addDependenciesToPackageJson(
184
160
  if (currentDeps[dep]) {
185
161
  if (isVersionGreater(newVersion, currentDeps[dep])) {
186
162
  currentDeps[dep] = newVersion;
163
+ } else {
164
+ migrationsDebug('would downgrade dependency %s to %s', dep, newVersion);
187
165
  }
188
166
  } else if (currentDevDeps[dep]) {
189
167
  if (isVersionGreater(newVersion, currentDevDeps[dep])) {
190
168
  currentDevDeps[dep] = newVersion;
169
+ } else {
170
+ migrationsDebug('would downgrade devDependency %s to %s', dep, newVersion);
191
171
  }
192
172
  } else {
193
173
  // Not present, add to dependencies
@@ -200,10 +180,14 @@ export function addDependenciesToPackageJson(
200
180
  if (currentDeps[dep]) {
201
181
  if (isVersionGreater(newVersion, currentDeps[dep])) {
202
182
  currentDeps[dep] = newVersion;
183
+ } else {
184
+ migrationsDebug('would downgrade dependency %s to %s', dep, newVersion);
203
185
  }
204
186
  } else if (currentDevDeps[dep]) {
205
187
  if (isVersionGreater(newVersion, currentDevDeps[dep])) {
206
188
  currentDevDeps[dep] = newVersion;
189
+ } else {
190
+ migrationsDebug('would downgrade devDependency %s to %s', dep, newVersion);
207
191
  }
208
192
  } else {
209
193
  // Not present, add to devDependencies
@@ -230,12 +214,11 @@ export function addDependenciesToPackageJson(
230
214
  ...(Object.keys(sortedDevDeps).length > 0 && { devDependencies: sortedDevDeps }),
231
215
  };
232
216
 
217
+ migrationsDebug('updated package.json', updatedPackageJson);
218
+
233
219
  context.updateFile(packageJsonPath, JSON.stringify(updatedPackageJson, null, 2));
234
220
  }
235
221
 
236
- /**
237
- * Removes dependencies from package.json.
238
- */
239
222
  export function removeDependenciesFromPackageJson(
240
223
  context: Context,
241
224
  dependencies: string[],
@@ -249,6 +232,7 @@ export function removeDependenciesFromPackageJson(
249
232
  for (const dep of dependencies) {
250
233
  if (currentPackageJson.dependencies?.[dep]) {
251
234
  delete currentPackageJson.dependencies[dep];
235
+ migrationsDebug('removed dependency %s', dep);
252
236
  hasChanges = true;
253
237
  }
254
238
  }
@@ -256,6 +240,7 @@ export function removeDependenciesFromPackageJson(
256
240
  for (const dep of devDependencies) {
257
241
  if (currentPackageJson.devDependencies?.[dep]) {
258
242
  delete currentPackageJson.devDependencies[dep];
243
+ migrationsDebug('removed devDependency %s', dep);
259
244
  hasChanges = true;
260
245
  }
261
246
  }
@@ -264,6 +249,8 @@ export function removeDependenciesFromPackageJson(
264
249
  return;
265
250
  }
266
251
 
252
+ migrationsDebug('updated package.json', currentPackageJson);
253
+
267
254
  context.updateFile(packageJsonPath, JSON.stringify(currentPackageJson, null, 2));
268
255
  }
269
256
 
@@ -276,8 +263,13 @@ const DIST_TAGS = {
276
263
 
277
264
  /**
278
265
  * Compares two version strings to determine if the incoming version is greater
266
+ *
267
+ * @param incomingVersion - The incoming version to compare.
268
+ * @param existingVersion - The existing version to compare.
269
+ * @param orEqualTo - Whether to include the existing version in the comparison.
270
+ *
279
271
  */
280
- export function isVersionGreater(incomingVersion: string, existingVersion: string): boolean {
272
+ export function isVersionGreater(incomingVersion: string, existingVersion: string, orEqualTo = false) {
281
273
  const incomingIsDistTag = incomingVersion in DIST_TAGS;
282
274
  const existingIsDistTag = existingVersion in DIST_TAGS;
283
275
 
@@ -301,6 +293,10 @@ export function isVersionGreater(incomingVersion: string, existingVersion: strin
301
293
  return true;
302
294
  }
303
295
 
296
+ if (orEqualTo) {
297
+ return gte(incomingSemver, existingSemver);
298
+ }
299
+
304
300
  return gt(incomingSemver, existingSemver);
305
301
  }
306
302
 
@@ -1,6 +1,5 @@
1
1
  import { argv, commandName } from './utils.cli.js';
2
2
 
3
- import type { AdditionFeatureName } from '../codemods/additions/additions.js';
4
3
  import { CURRENT_APP_VERSION } from './utils.version.js';
5
4
  import { DEFAULT_FEATURE_FLAGS } from '../constants.js';
6
5
  import fs from 'node:fs';
@@ -10,27 +9,16 @@ import path from 'node:path';
10
9
  import { writeFile } from 'node:fs/promises';
11
10
  import { EOL } from 'node:os';
12
11
 
13
- type CoreFeatureFlags = {
12
+ export type FeatureFlags = {
14
13
  bundleGrafanaUI?: boolean;
15
14
 
16
15
  // If set to true, the plugin will be scaffolded with React Router v6. Defaults to true.
17
16
  // (Attention! We always scaffold new projects with React Router v6, so if you are changing this to `false` manually you will need to make changes to the React code as well.)
18
17
  useReactRouterV6?: boolean;
19
- usePlaywright?: boolean;
20
18
  useExperimentalRspack?: boolean;
21
19
  useExperimentalUpdates?: boolean;
22
20
  };
23
21
 
24
- type AdditionFeatureFlags = {
25
- [K in AdditionFeatureName]?: boolean;
26
- };
27
-
28
- export type FeatureFlags = CoreFeatureFlags & AdditionFeatureFlags;
29
-
30
- export function isFeatureEnabled(features: FeatureFlags, featureName: AdditionFeatureName): boolean {
31
- return features[featureName] === true;
32
- }
33
-
34
22
  export type CreatePluginConfig = UserConfig & {
35
23
  version: string;
36
24
  };
@@ -144,18 +132,3 @@ export async function setRootConfig(configOverride: Partial<CreatePluginConfig>
144
132
 
145
133
  return updatedConfig;
146
134
  }
147
-
148
- export async function setFeatureFlag(featureName: string, enabled = true): Promise<void> {
149
- const userConfig = getUserConfig() || { features: {} };
150
- const userConfigPath = path.resolve(process.cwd(), '.cprc.json');
151
-
152
- const updatedConfig = {
153
- ...userConfig,
154
- features: {
155
- ...userConfig.features,
156
- [featureName]: enabled,
157
- },
158
- };
159
-
160
- await writeFile(userConfigPath, JSON.stringify(updatedConfig, null, 2) + EOL);
161
- }
@@ -29,7 +29,9 @@
29
29
  "@testing-library/jest-dom": "6.1.4",
30
30
  "@testing-library/react": "14.0.0",
31
31
  "@types/jest": "^29.5.0",
32
- "@types/node": "^20.8.7",{{#if isAppType}}{{#unless useReactRouterV6}}
32
+ "@types/node": "^20.8.7",
33
+ "@types/react": "^18.3.0",
34
+ "@types/react-dom": "^18.3.0",{{#if isAppType}}{{#unless useReactRouterV6}}
33
35
  "@types/react-router-dom": "^{{ reactRouterVersion }}",{{/unless}}{{/if}}
34
36
  "@types/testing-library__jest-dom": "5.14.8",
35
37
  "@typescript-eslint/eslint-plugin": "^8.3.0",
@@ -77,8 +79,8 @@
77
79
  "@grafana/ui": "^12.2.1",
78
80
  "@grafana/schema": "^12.2.1",{{#if_eq pluginType "scenesapp" }}
79
81
  "@grafana/scenes": "{{ scenesVersion }}",{{/if_eq}}
80
- "react": "18.2.0",
81
- "react-dom": "18.2.0"{{#if isAppType}},
82
+ "react": "^18.3.0",
83
+ "react-dom": "^18.3.0"{{#if isAppType}},
82
84
  "react-router-dom": "^{{ reactRouterVersion }}",
83
85
  "rxjs": "7.8.2"{{/if}}
84
86
  },
@@ -1,3 +1,4 @@
1
+ {{!-- /* 🚨 The `${{ }}` Github workflow expressions need to be escaped so they are not being interpreted by Handlebars. (this comment is going to be removed after scaffolding) 🚨 */ --}}
1
2
  name: Create Plugin Update
2
3
 
3
4
  on:
@@ -5,22 +6,16 @@ on:
5
6
  schedule:
6
7
  - cron: '0 0 1 * *' # run once a month on the 1st day
7
8
 
8
- # To use the default github token with the following elevated permissions make sure to check:
9
- # **Allow GitHub Actions to create and approve pull requests** in https://github.com/ORG_NAME/REPO_NAME/settings/actions.
10
- # Alternatively create a fine-grained personal access token for your repository with
11
- # `contents: read and write` and `pull requests: read and write` and pass it to the action.
12
-
13
- permissions:
14
- contents: write
15
- pull-requests: write
9
+ # To use this workflow please create a fine-grained personal access token for your repository with:
10
+ # `contents: read and write`
11
+ # `pull requests: read and write`
12
+ # `workflows: read and write`
16
13
 
17
14
  jobs:
18
15
  release:
19
16
  runs-on: ubuntu-latest
20
17
  steps:
21
18
  - uses: grafana/plugin-actions/create-plugin-update@create-plugin-update/v1.1.0
22
- # Uncomment to use a fine-grained personal access token instead of default github token
23
- # (For more info on how to generate the token see https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
24
- # with:
25
- # Make sure to save the token in your repository secrets
26
- # token: ${{ secrets.GH_PAT_TOKEN }}
19
+ with:
20
+ # Make sure to save the token in your repository secrets as `GH_PAT_TOKEN`
21
+ token: $\{{ secrets.GH_PAT_TOKEN }}
@@ -1,11 +0,0 @@
1
- const additions = {
2
- i18n: {
3
- name: "i18n",
4
- description: "Add internationalization (i18n) support to your plugin",
5
- scriptPath: "./scripts/add-i18n.js",
6
- featureName: "i18nEnabled"
7
- }
8
- };
9
- var defaultAdditions = { additions };
10
-
11
- export { defaultAdditions as default };
@@ -1,115 +0,0 @@
1
- import { additionsDebug, printChanges } from './utils.js';
2
- import defaultAdditions from './additions.js';
3
- import { formatFiles, flushChanges, installNPMDependencies } from '../utils.js';
4
- import { getConfig, isFeatureEnabled, setFeatureFlag } from '../../utils/utils.config.js';
5
- import { Context } from '../context.js';
6
- import { output } from '../../utils/utils.console.js';
7
-
8
- function getAvailableAdditions(additions = defaultAdditions.additions) {
9
- return additions;
10
- }
11
- function getAdditionByName(name, additions = defaultAdditions.additions) {
12
- return additions[name];
13
- }
14
- async function loadAdditionModule(addition) {
15
- try {
16
- const module = await import(addition.scriptPath);
17
- return module;
18
- } catch (error) {
19
- additionsDebug('Failed to load addition module for "%s" from %s: %O', addition.name, addition.scriptPath, error);
20
- return null;
21
- }
22
- }
23
- async function getAdditionFlags(addition) {
24
- const module = await loadAdditionModule(addition);
25
- return module?.flags || [];
26
- }
27
- async function parseAdditionFlags(addition, argv) {
28
- const module = await loadAdditionModule(addition);
29
- if (module?.parseFlags) {
30
- return module.parseFlags(argv);
31
- }
32
- return {};
33
- }
34
- async function validateAdditionOptions(addition, options) {
35
- const flags = await getAdditionFlags(addition);
36
- if (!flags || flags.length === 0) {
37
- return;
38
- }
39
- const missingFlags = [];
40
- for (const flag of flags) {
41
- if (flag.required) {
42
- const value = options[flag.name];
43
- if (value === void 0 || value === null || Array.isArray(value) && value.length === 0) {
44
- missingFlags.push(flag.name);
45
- }
46
- }
47
- }
48
- if (missingFlags.length > 0) {
49
- const flagDocs = flags.filter((f) => missingFlags.includes(f.name)).map((f) => ` --${f.name}: ${f.description}`);
50
- throw new Error(
51
- `Missing required flag${missingFlags.length > 1 ? "s" : ""}:
52
-
53
- ` + flagDocs.join("\n") + `
54
-
55
- Example: npx @grafana/create-plugin add ${addition.name} --${missingFlags[0]}=value`
56
- );
57
- }
58
- }
59
- async function runAdditionByName(additionName, argv) {
60
- const addition = getAdditionByName(additionName);
61
- if (!addition) {
62
- const availableAdditions = getAvailableAdditions();
63
- const additionsList = Object.keys(availableAdditions);
64
- throw new Error(`Unknown addition: ${additionName}
65
-
66
- Available additions: ${additionsList.join(", ")}`);
67
- }
68
- const options = await parseAdditionFlags(addition, argv);
69
- await validateAdditionOptions(addition, options);
70
- await runAddition(addition, options);
71
- }
72
- async function runAddition(addition, additionOptions = {}) {
73
- const basePath = process.cwd();
74
- const config = getConfig();
75
- if (isFeatureEnabled(config.features, addition.featureName)) {
76
- output.log({
77
- title: `Addition '${addition.name}' is already enabled`,
78
- body: [`The feature flag '${addition.featureName}' is already set to true in .cprc.json.`, "No changes needed."]
79
- });
80
- return;
81
- }
82
- output.log({
83
- title: `Running addition: ${addition.name}`,
84
- body: [addition.description]
85
- });
86
- try {
87
- const context = new Context(basePath);
88
- const updatedContext = await executeAddition(addition, context, additionOptions);
89
- additionsDebug(`context for "${addition.name} (${addition.scriptPath})":`);
90
- additionsDebug("%O", updatedContext.listChanges());
91
- await formatFiles(updatedContext);
92
- flushChanges(updatedContext);
93
- printChanges(updatedContext, addition.name, addition);
94
- installNPMDependencies(updatedContext);
95
- await setFeatureFlag(addition.featureName, true);
96
- additionsDebug(`Set feature flag '${addition.featureName}' to true in .cprc.json`);
97
- output.success({
98
- title: `Successfully added ${addition.name} to your plugin.`
99
- });
100
- } catch (error) {
101
- if (error instanceof Error) {
102
- throw new Error(`Error running addition "${addition.name} (${addition.scriptPath})": ${error.message}`);
103
- }
104
- throw error;
105
- }
106
- }
107
- async function executeAddition(addition, context, options = {}) {
108
- const module = await loadAdditionModule(addition);
109
- if (!module) {
110
- throw new Error(`Failed to load addition module for ${addition.name}`);
111
- }
112
- return module.default(context, options);
113
- }
114
-
115
- export { executeAddition, getAdditionByName, getAdditionFlags, getAvailableAdditions, parseAdditionFlags, runAddition, runAdditionByName };