@grafana/create-plugin 5.17.0 → 5.18.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 +18 -0
- package/CONTRIBUTING.md +117 -1
- package/dist/commands/update.command.js +28 -68
- package/dist/commands/update.migrate.command.js +27 -0
- package/dist/commands/update.standard.command.js +51 -0
- package/dist/migrations/context.js +118 -0
- package/dist/migrations/context.test.js +122 -0
- package/dist/migrations/fixtures/foo/bar.js +2 -0
- package/dist/migrations/fixtures/foo/baz.js +1 -0
- package/dist/migrations/fixtures/migrations.js +19 -0
- package/dist/migrations/manager.js +50 -0
- package/dist/migrations/manager.test.js +177 -0
- package/dist/migrations/migrations.js +3 -0
- package/dist/migrations/migrations.test.js +10 -0
- package/dist/migrations/scripts/example-migration.js +23 -0
- package/dist/migrations/scripts/example-migration.test.js +24 -0
- package/dist/migrations/test-utils.js +9 -0
- package/dist/migrations/utils.js +46 -0
- package/dist/migrations/utils.test.js +65 -0
- package/dist/utils/utils.cli.js +3 -0
- package/dist/utils/utils.config.js +9 -1
- package/dist/utils/utils.console.js +6 -0
- package/dist/utils/utils.git.js +13 -0
- package/dist/utils/utils.goSdk.js +6 -6
- package/dist/utils/utils.templates.js +3 -3
- package/package.json +6 -4
- package/src/commands/update.command.ts +33 -75
- package/src/commands/update.migrate.command.ts +31 -0
- package/src/commands/update.standard.command.ts +55 -0
- package/src/migrations/context.test.ts +148 -0
- package/src/migrations/context.ts +155 -0
- package/src/migrations/fixtures/foo/bar.ts +1 -0
- package/src/migrations/fixtures/foo/baz.ts +0 -0
- package/src/migrations/fixtures/migrations.ts +19 -0
- package/src/migrations/manager.test.ts +217 -0
- package/src/migrations/manager.ts +70 -0
- package/src/migrations/migrations.test.ts +12 -0
- package/src/migrations/migrations.ts +20 -0
- package/src/migrations/scripts/example-migration.test.ts +40 -0
- package/src/migrations/scripts/example-migration.ts +34 -0
- package/src/migrations/test-utils.ts +12 -0
- package/src/migrations/utils.test.ts +81 -0
- package/src/migrations/utils.ts +50 -0
- package/src/utils/utils.cli.ts +5 -0
- package/src/utils/utils.config.ts +12 -1
- package/src/utils/utils.console.ts +7 -0
- package/src/utils/utils.git.ts +14 -0
- package/src/utils/utils.goSdk.ts +6 -6
- package/src/utils/utils.templates.ts +3 -3
- package/templates/common/.config/docker-compose-base.yaml +1 -1
- package/templates/common/_package.json +4 -4
- package/tsconfig.json +1 -1
- package/vitest.config.ts +1 -0
- package/vitest.d.ts +11 -0
- package/vitest.setup.ts +53 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { getMigrationsToRun, runMigration, runMigrations } from './manager.js';
|
|
3
|
+
import migrationFixtures from './fixtures/migrations.js';
|
|
4
|
+
import { Context } from './context.js';
|
|
5
|
+
import { gitCommitNoVerify } from '../utils/utils.git.js';
|
|
6
|
+
import { flushChanges, printChanges } from './utils.js';
|
|
7
|
+
import { setRootConfig } from '../utils/utils.config.js';
|
|
8
|
+
vi.mock('./utils.js', () => ({
|
|
9
|
+
flushChanges: vi.fn(),
|
|
10
|
+
printChanges: vi.fn(),
|
|
11
|
+
migrationsDebug: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
vi.mock('../utils/utils.config.js', () => ({
|
|
14
|
+
setRootConfig: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
vi.mock('../utils/utils.git.js', () => ({
|
|
17
|
+
gitCommitNoVerify: vi.fn(),
|
|
18
|
+
}));
|
|
19
|
+
describe('Migrations', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
vi.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
describe('getMigrationsToRun', () => {
|
|
24
|
+
it('should return the migrations that need to be run', () => {
|
|
25
|
+
const fromVersion = '3.0.0';
|
|
26
|
+
const toVersion = '5.0.0';
|
|
27
|
+
const migrations = getMigrationsToRun(fromVersion, toVersion, migrationFixtures.migrations);
|
|
28
|
+
expect(migrations).toEqual({
|
|
29
|
+
'migration-key1': {
|
|
30
|
+
version: '5.0.0',
|
|
31
|
+
description: 'Update project to use new cache directory',
|
|
32
|
+
migrationScript: './5-0-0-cache-directory.js',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
const fromVersion2 = '5.0.0';
|
|
36
|
+
const toVersion2 = '5.5.0';
|
|
37
|
+
const migrations2 = getMigrationsToRun(fromVersion2, toVersion2, migrationFixtures.migrations);
|
|
38
|
+
expect(migrations2).toEqual({
|
|
39
|
+
'migration-key1': {
|
|
40
|
+
version: '5.0.0',
|
|
41
|
+
description: 'Update project to use new cache directory',
|
|
42
|
+
migrationScript: './5-0-0-cache-directory.js',
|
|
43
|
+
},
|
|
44
|
+
'migration-key2': {
|
|
45
|
+
version: '5.4.0',
|
|
46
|
+
description: 'Update project to use new cache directory',
|
|
47
|
+
migrationScript: './5-4-0-cache-directory.js',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
const fromVersion3 = '5.5.0';
|
|
51
|
+
const toVersion3 = '6.0.0';
|
|
52
|
+
const migrations3 = getMigrationsToRun(fromVersion3, toVersion3, migrationFixtures.migrations);
|
|
53
|
+
expect(migrations3).toEqual({
|
|
54
|
+
'migration-key3': {
|
|
55
|
+
version: '6.0.0',
|
|
56
|
+
description: 'Update project to use new cache directory',
|
|
57
|
+
migrationScript: './5-4-0-cache-directory.js',
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
it('should sort migrations by version', () => {
|
|
62
|
+
const fromVersion = '2.0.0';
|
|
63
|
+
const toVersion = '6.0.0';
|
|
64
|
+
const migrations = getMigrationsToRun(fromVersion, toVersion, {
|
|
65
|
+
'migration-key1': {
|
|
66
|
+
version: '5.3.0',
|
|
67
|
+
description: 'Update project to use new cache directory',
|
|
68
|
+
migrationScript: './5.3.0-migration.js',
|
|
69
|
+
},
|
|
70
|
+
'migration-key2': {
|
|
71
|
+
version: '2.3.0',
|
|
72
|
+
description: 'Update project to use new cache directory',
|
|
73
|
+
migrationScript: './2.3.0-migration.js',
|
|
74
|
+
},
|
|
75
|
+
'migration-key3': {
|
|
76
|
+
version: '2.0.0',
|
|
77
|
+
description: 'Update project to use new cache directory',
|
|
78
|
+
migrationScript: './2.0.0-migration.js',
|
|
79
|
+
},
|
|
80
|
+
'migration-key4': {
|
|
81
|
+
version: '2.0.0',
|
|
82
|
+
description: 'Update project to use new cache directory',
|
|
83
|
+
migrationScript: './2.0.0-migration.js',
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
expect(Object.keys(migrations)).toEqual(['migration-key3', 'migration-key4', 'migration-key2', 'migration-key1']);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('runMigration', () => {
|
|
90
|
+
it('should pass a context to the migration script', async () => {
|
|
91
|
+
const mockContext = new Context('/virtual');
|
|
92
|
+
const migrationFn = vi.fn().mockResolvedValue(mockContext);
|
|
93
|
+
vi.doMock('./test-migration.js', () => ({
|
|
94
|
+
default: migrationFn,
|
|
95
|
+
}));
|
|
96
|
+
const migration = {
|
|
97
|
+
version: '1.0.0',
|
|
98
|
+
description: 'test migration',
|
|
99
|
+
migrationScript: './test-migration.js',
|
|
100
|
+
};
|
|
101
|
+
const result = await runMigration(migration, mockContext);
|
|
102
|
+
expect(migrationFn).toHaveBeenCalledWith(mockContext);
|
|
103
|
+
expect(result).toBe(mockContext);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('runMigrations', () => {
|
|
107
|
+
const migrationOneFn = vi.fn();
|
|
108
|
+
const migrationTwoFn = vi.fn();
|
|
109
|
+
const consoleMock = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
110
|
+
vi.doMock('./migration-one.js', () => ({
|
|
111
|
+
default: migrationOneFn,
|
|
112
|
+
}));
|
|
113
|
+
vi.doMock('./migration-two.js', () => ({
|
|
114
|
+
default: migrationTwoFn,
|
|
115
|
+
}));
|
|
116
|
+
const migrations = {
|
|
117
|
+
'migration-one': {
|
|
118
|
+
version: '1.0.0',
|
|
119
|
+
description: '...',
|
|
120
|
+
migrationScript: './migration-one.js',
|
|
121
|
+
},
|
|
122
|
+
'migration-two': {
|
|
123
|
+
version: '1.2.0',
|
|
124
|
+
description: '...',
|
|
125
|
+
migrationScript: './migration-two.js',
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
beforeEach(() => {
|
|
129
|
+
migrationOneFn.mockImplementation(async (context) => {
|
|
130
|
+
await context.addFile('one.ts', '');
|
|
131
|
+
return context;
|
|
132
|
+
});
|
|
133
|
+
migrationTwoFn.mockImplementation(async (context) => {
|
|
134
|
+
await context.addFile('two.ts', '');
|
|
135
|
+
return context;
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
afterAll(() => {
|
|
139
|
+
consoleMock.mockReset();
|
|
140
|
+
});
|
|
141
|
+
it('should flush the changes for each migration', async () => {
|
|
142
|
+
await runMigrations(migrations);
|
|
143
|
+
expect(flushChanges).toHaveBeenCalledTimes(2);
|
|
144
|
+
});
|
|
145
|
+
it('should print the changes for each migration', async () => {
|
|
146
|
+
await runMigrations(migrations);
|
|
147
|
+
expect(printChanges).toHaveBeenCalledTimes(2);
|
|
148
|
+
});
|
|
149
|
+
it('should not commit the changes for each migration by default', async () => {
|
|
150
|
+
await runMigrations(migrations);
|
|
151
|
+
expect(gitCommitNoVerify).toHaveBeenCalledTimes(0);
|
|
152
|
+
});
|
|
153
|
+
it('should commit the changes for each migration if the CLI arg is present', async () => {
|
|
154
|
+
await runMigrations(migrations, { commitEachMigration: true });
|
|
155
|
+
expect(gitCommitNoVerify).toHaveBeenCalledTimes(2);
|
|
156
|
+
});
|
|
157
|
+
it('should not create a commit for a migration that has no changes', async () => {
|
|
158
|
+
migrationTwoFn.mockImplementation(async (context) => context);
|
|
159
|
+
await runMigrations(migrations, { commitEachMigration: true });
|
|
160
|
+
expect(gitCommitNoVerify).toHaveBeenCalledTimes(1);
|
|
161
|
+
});
|
|
162
|
+
it('should update version in ".config/.cprc.json" on a successful update', async () => {
|
|
163
|
+
await runMigrations(migrations);
|
|
164
|
+
expect(setRootConfig).toHaveBeenCalledTimes(1);
|
|
165
|
+
expect(setRootConfig).toHaveBeenCalledWith({ version: '1.2.0' });
|
|
166
|
+
});
|
|
167
|
+
it('should NOT update version in ".config/.cprc.json" if any of the migrations fail', async () => {
|
|
168
|
+
migrationTwoFn.mockImplementation(async () => {
|
|
169
|
+
throw new Error('Unknown error.');
|
|
170
|
+
});
|
|
171
|
+
await expect(async () => {
|
|
172
|
+
await runMigrations(migrations);
|
|
173
|
+
}).rejects.toThrow();
|
|
174
|
+
expect(setRootConfig).not.toHaveBeenCalled();
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import defaultMigrations from './migrations.js';
|
|
2
|
+
describe('migrations json', () => {
|
|
3
|
+
Object.entries(defaultMigrations.migrations).forEach(([key, migration]) => {
|
|
4
|
+
it(`should have a valid migration script path for ${key}`, () => {
|
|
5
|
+
expect(async () => {
|
|
6
|
+
await import(migration.migrationScript);
|
|
7
|
+
}).not.toThrow();
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export default 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
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import migrate from './example-migration.js';
|
|
2
|
+
import { createDefaultContext } from '../test-utils.js';
|
|
3
|
+
describe('Migration - append profile to webpack', () => {
|
|
4
|
+
test('should update the package.json', async () => {
|
|
5
|
+
const context = createDefaultContext();
|
|
6
|
+
context.updateFile('./package.json', JSON.stringify({
|
|
7
|
+
scripts: {
|
|
8
|
+
build: 'webpack -c ./.config/webpack/webpack.config.ts --env production',
|
|
9
|
+
},
|
|
10
|
+
}));
|
|
11
|
+
const updatedContext = await migrate(context);
|
|
12
|
+
expect(updatedContext.getFile('./package.json')).toMatch('webpack -c ./.config/webpack/webpack.config.ts --profile --env production');
|
|
13
|
+
expect(updatedContext.readDir('./src')).toEqual(['src/FOO.md', 'src/foo.json']);
|
|
14
|
+
});
|
|
15
|
+
it('should not make additional changes when run multiple times', async () => {
|
|
16
|
+
const context = await createDefaultContext();
|
|
17
|
+
await context.updateFile('./package.json', JSON.stringify({
|
|
18
|
+
scripts: {
|
|
19
|
+
build: 'webpack -c ./.config/webpack/webpack.config.ts --env production',
|
|
20
|
+
},
|
|
21
|
+
}));
|
|
22
|
+
await expect(migrate).toBeIdempotent(context);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Context } from './context.js';
|
|
2
|
+
export function createDefaultContext() {
|
|
3
|
+
const context = new Context('/virtual');
|
|
4
|
+
context.addFile('.eslintrc', '{}');
|
|
5
|
+
context.addFile('./package.json', '{}');
|
|
6
|
+
context.addFile('./src/README.md', '');
|
|
7
|
+
context.addFile('./src/FOO.md', '');
|
|
8
|
+
return context;
|
|
9
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { debug } from '../utils/utils.cli.js';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
export function printChanges(context, key, migration) {
|
|
6
|
+
const changes = context.listChanges();
|
|
7
|
+
const lines = [];
|
|
8
|
+
for (const [filePath, { changeType }] of Object.entries(changes)) {
|
|
9
|
+
if (changeType === 'add') {
|
|
10
|
+
lines.push(`${chalk.green('ADD')} ${filePath}`);
|
|
11
|
+
}
|
|
12
|
+
else if (changeType === 'update') {
|
|
13
|
+
lines.push(`${chalk.yellow('UPDATE')} ${filePath}`);
|
|
14
|
+
}
|
|
15
|
+
else if (changeType === 'delete') {
|
|
16
|
+
lines.push(`${chalk.red('DELETE')} ${filePath}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
console.log('--------------------------------');
|
|
20
|
+
console.log('Running migration:', key, chalk.bold(migration.migrationScript));
|
|
21
|
+
if (lines.length === 0) {
|
|
22
|
+
console.log('No changes were made');
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(`${chalk.bold('Changes:')}\n ${lines.join('\n ')}`);
|
|
26
|
+
}
|
|
27
|
+
console.log('');
|
|
28
|
+
}
|
|
29
|
+
export function flushChanges(context) {
|
|
30
|
+
const basePath = context.basePath;
|
|
31
|
+
const changes = context.listChanges();
|
|
32
|
+
for (const [filePath, { changeType, content }] of Object.entries(changes)) {
|
|
33
|
+
const resolvedPath = join(basePath, filePath);
|
|
34
|
+
if (changeType === 'add') {
|
|
35
|
+
mkdirSync(dirname(resolvedPath), { recursive: true });
|
|
36
|
+
writeFileSync(resolvedPath, content);
|
|
37
|
+
}
|
|
38
|
+
else if (changeType === 'update') {
|
|
39
|
+
writeFileSync(resolvedPath, content);
|
|
40
|
+
}
|
|
41
|
+
else if (changeType === 'delete') {
|
|
42
|
+
rmSync(resolvedPath);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export const migrationsDebug = debug.extend('migrations');
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { dirSync } from 'tmp';
|
|
2
|
+
import { Context } from './context.js';
|
|
3
|
+
import { flushChanges, printChanges } from './utils.js';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
describe('utils', () => {
|
|
8
|
+
const tmpObj = dirSync({ unsafeCleanup: true });
|
|
9
|
+
const tmpDir = join(tmpObj.name, 'cp-test-migration');
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
12
|
+
await mkdir(tmpDir, { recursive: true });
|
|
13
|
+
await writeFile(join(tmpDir, 'bar.ts'), 'content');
|
|
14
|
+
await writeFile(join(tmpDir, 'baz.ts'), 'content');
|
|
15
|
+
});
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
tmpObj.removeCallback();
|
|
18
|
+
});
|
|
19
|
+
describe('flushChanges', () => {
|
|
20
|
+
it('should write files to disk', async () => {
|
|
21
|
+
const context = new Context(tmpDir);
|
|
22
|
+
await context.addFile('file.txt', 'content');
|
|
23
|
+
await context.addFile('deeper/path/to/file.txt', 'content');
|
|
24
|
+
flushChanges(context);
|
|
25
|
+
expect(readFileSync(join(tmpDir, 'file.txt'), 'utf-8')).toBe('content');
|
|
26
|
+
expect(readFileSync(join(tmpDir, 'deeper/path/to/file.txt'), 'utf-8')).toBe('content');
|
|
27
|
+
});
|
|
28
|
+
it('should update files on disk', async () => {
|
|
29
|
+
const context = new Context(tmpDir);
|
|
30
|
+
await context.updateFile('bar.ts', 'new content');
|
|
31
|
+
flushChanges(context);
|
|
32
|
+
expect(readFileSync(join(tmpDir, 'bar.ts'), 'utf-8')).toBe('new content');
|
|
33
|
+
});
|
|
34
|
+
it('should delete files from disk', async () => {
|
|
35
|
+
const context = new Context(tmpDir);
|
|
36
|
+
await context.deleteFile('bar.ts');
|
|
37
|
+
flushChanges(context);
|
|
38
|
+
expect(() => readFileSync(join(tmpDir, 'bar.ts'), 'utf-8')).toThrowError();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('printChanges', () => {
|
|
42
|
+
const originalConsoleLog = console.log;
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
vitest.spyOn(console, 'log').mockImplementation(() => { });
|
|
45
|
+
});
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
console.log = originalConsoleLog;
|
|
48
|
+
});
|
|
49
|
+
it('should print changes', async () => {
|
|
50
|
+
const context = new Context(tmpDir);
|
|
51
|
+
await context.addFile('file.txt', 'content');
|
|
52
|
+
await context.updateFile('baz.ts', 'new content');
|
|
53
|
+
await context.deleteFile('bar.ts');
|
|
54
|
+
printChanges(context, 'key', { migrationScript: 'test', description: 'test', version: '1.0.0' });
|
|
55
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/ADD.+file\.txt/));
|
|
56
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/UPDATE.+baz\.ts/));
|
|
57
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/DELETE.+bar\.ts/));
|
|
58
|
+
});
|
|
59
|
+
it('should print no changes', async () => {
|
|
60
|
+
const context = new Context(tmpDir);
|
|
61
|
+
printChanges(context, 'key', { migrationScript: 'test', description: 'test', version: '1.0.0' });
|
|
62
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringMatching(/No changes were made/));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
});
|
package/dist/utils/utils.cli.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import minimist from 'minimist';
|
|
2
|
+
import createDebug from 'debug';
|
|
3
|
+
export const debug = createDebug('create-plugin');
|
|
2
4
|
export const args = process.argv.slice(2);
|
|
3
5
|
export const argv = minimist(args, {
|
|
4
6
|
alias: {
|
|
@@ -7,6 +9,7 @@ export const argv = minimist(args, {
|
|
|
7
9
|
hasBackend: 'backend',
|
|
8
10
|
pluginName: 'plugin-name',
|
|
9
11
|
orgName: 'org-name',
|
|
12
|
+
experimentalUpdates: 'experimental-updates',
|
|
10
13
|
},
|
|
11
14
|
});
|
|
12
15
|
export const commandName = argv._[0] || 'generate';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { getVersion } from './utils.version.js';
|
|
4
5
|
import { argv, commandName } from './utils.cli.js';
|
|
@@ -61,7 +62,7 @@ function readRCFileSync(path) {
|
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
function createFeatureFlags(flags) {
|
|
64
|
-
const featureFlags = commandName === 'generate' ? DEFAULT_FEATURE_FLAGS : flags ?? {};
|
|
65
|
+
const featureFlags = commandName === 'generate' ? DEFAULT_FEATURE_FLAGS : (flags ?? {});
|
|
65
66
|
const cliArgFlags = parseFeatureFlagsFromCliArgs();
|
|
66
67
|
return { ...featureFlags, ...cliArgFlags };
|
|
67
68
|
}
|
|
@@ -82,3 +83,10 @@ function parseFeatureFlagsFromCliArgs() {
|
|
|
82
83
|
return { ...acc, [flag]: true };
|
|
83
84
|
}, {});
|
|
84
85
|
}
|
|
86
|
+
export async function setRootConfig(configOverride = {}) {
|
|
87
|
+
const rootConfig = getRootConfig();
|
|
88
|
+
const rootConfigPath = path.resolve(process.cwd(), '.config/.cprc.json');
|
|
89
|
+
const updatedConfig = { ...rootConfig, ...configOverride };
|
|
90
|
+
await writeFile(rootConfigPath, JSON.stringify(updatedConfig, null, 2));
|
|
91
|
+
return updatedConfig;
|
|
92
|
+
}
|
|
@@ -7,6 +7,12 @@ const { prompt } = Enquirer;
|
|
|
7
7
|
marked.use(markedTerminal({
|
|
8
8
|
firstHeading: chalk.hex('#ff9900').underline.bold,
|
|
9
9
|
}));
|
|
10
|
+
export function printHeader(message, status = 'success') {
|
|
11
|
+
const color = status === 'success' ? 'green' : status === 'info' ? 'blue' : 'red';
|
|
12
|
+
let prefix = chalk.reset.inverse.bold[color](` CREATE PLUGIN `);
|
|
13
|
+
let txt = chalk[color](message);
|
|
14
|
+
console.log(`${prefix} ${txt}`);
|
|
15
|
+
}
|
|
10
16
|
export function displayAsMarkdown(msg) {
|
|
11
17
|
return marked(msg);
|
|
12
18
|
}
|
package/dist/utils/utils.git.js
CHANGED
|
@@ -21,3 +21,16 @@ export async function isGitDirectoryClean() {
|
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
export async function gitCommitNoVerify(commitMsg) {
|
|
25
|
+
try {
|
|
26
|
+
let addAllCommand = 'git add -A';
|
|
27
|
+
let commitCommand = `git commit --no-verify -m ${commitMsg}`;
|
|
28
|
+
await exec(addAllCommand);
|
|
29
|
+
await exec(commitCommand);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error instanceof Error) {
|
|
33
|
+
throw new Error(`Error committing changes:\n${error.message}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import which from 'which';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import createDebug from 'debug';
|
|
4
3
|
import { exec } from 'node:child_process';
|
|
4
|
+
import { debug } from './utils.cli.js';
|
|
5
5
|
const SDK_GO_MODULE = 'github.com/grafana/grafana-plugin-sdk-go';
|
|
6
|
-
const
|
|
6
|
+
const updateGoDebugger = debug.extend('update-go');
|
|
7
7
|
export async function updateGoSdkAndModules(exportPath) {
|
|
8
8
|
const goModPath = `${exportPath}/go.mod`;
|
|
9
9
|
if (!fs.existsSync(goModPath)) {
|
|
@@ -28,7 +28,7 @@ function updateSdk(exportPath) {
|
|
|
28
28
|
const command = `go get ${SDK_GO_MODULE}`;
|
|
29
29
|
exec(command, { cwd: exportPath }, (error) => {
|
|
30
30
|
if (error) {
|
|
31
|
-
|
|
31
|
+
updateGoDebugger(error);
|
|
32
32
|
reject();
|
|
33
33
|
}
|
|
34
34
|
resolve();
|
|
@@ -40,7 +40,7 @@ function updateGoMod(exportPath) {
|
|
|
40
40
|
const command = `go mod tidy`;
|
|
41
41
|
exec(command, { cwd: exportPath }, (error) => {
|
|
42
42
|
if (error) {
|
|
43
|
-
|
|
43
|
+
updateGoDebugger(error);
|
|
44
44
|
reject();
|
|
45
45
|
}
|
|
46
46
|
resolve();
|
|
@@ -52,7 +52,7 @@ function getLatestSdkVersion(exportPath) {
|
|
|
52
52
|
const command = `go list -m -json ${SDK_GO_MODULE}@latest`;
|
|
53
53
|
exec(command, { cwd: exportPath }, (error, stdout) => {
|
|
54
54
|
if (error) {
|
|
55
|
-
|
|
55
|
+
updateGoDebugger(error);
|
|
56
56
|
reject();
|
|
57
57
|
}
|
|
58
58
|
try {
|
|
@@ -60,7 +60,7 @@ function getLatestSdkVersion(exportPath) {
|
|
|
60
60
|
resolve(version);
|
|
61
61
|
}
|
|
62
62
|
catch (e) {
|
|
63
|
-
|
|
63
|
+
updateGoDebugger(e);
|
|
64
64
|
reject();
|
|
65
65
|
}
|
|
66
66
|
});
|
|
@@ -2,16 +2,16 @@ import { lt as semverLt } from 'semver';
|
|
|
2
2
|
import { glob } from 'glob';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
|
-
import createDebug from 'debug';
|
|
6
5
|
import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
|
|
7
6
|
import { normalizeId, renderHandlebarsTemplate } from './utils.handlebars.js';
|
|
8
7
|
import { getPluginJson } from './utils.plugin.js';
|
|
8
|
+
import { debug } from './utils.cli.js';
|
|
9
9
|
import { TEMPLATE_PATHS, EXPORT_PATH_PREFIX, EXTRA_TEMPLATE_VARIABLES, PLUGIN_TYPES, DEFAULT_FEATURE_FLAGS, } from '../constants.js';
|
|
10
10
|
import { getPackageManagerInstallCmd, getPackageManagerWithFallback, getPackageManagerFromUserAgent, } from './utils.packageManager.js';
|
|
11
11
|
import { getExportFileName } from '../utils/utils.files.js';
|
|
12
12
|
import { getGrafanaRuntimeVersion, getVersion } from './utils.version.js';
|
|
13
13
|
import { getConfig } from './utils.config.js';
|
|
14
|
-
const
|
|
14
|
+
const templatesDebugger = debug.extend('templates');
|
|
15
15
|
export function getTemplateFiles(pluginType, filter) {
|
|
16
16
|
const commonFiles = glob.sync(`${TEMPLATE_PATHS.common}/**`, { dot: true });
|
|
17
17
|
const pluginTypeSpecificFiles = glob.sync(`${TEMPLATE_PATHS[pluginType]}/**`, { dot: true });
|
|
@@ -112,6 +112,6 @@ export function getTemplateData(cliArgs) {
|
|
|
112
112
|
pluginExecutable: pluginJson.executable,
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
|
-
|
|
115
|
+
templatesDebugger('\nTemplate data:\n' + JSON.stringify(templateData, null, 2));
|
|
116
116
|
return templateData;
|
|
117
117
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/create-plugin",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.18.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"directory": "packages/create-plugin",
|
|
6
6
|
"url": "https://github.com/grafana/plugin-tools"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"generate-datasource-backend": "tsc && npm run clean-generated && CREATE_PLUGIN_DEV=true node ./dist/bin/run.js --pluginName='Sample datasource' --orgName='sample-org' --pluginType='datasource' --hasBackend",
|
|
38
38
|
"lint": "eslint --cache ./src",
|
|
39
39
|
"lint:fix": "npm run lint -- --fix",
|
|
40
|
-
"test": "vitest",
|
|
40
|
+
"test": "vitest --passWithNoTests",
|
|
41
41
|
"typecheck": "tsc --noEmit"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
@@ -61,9 +61,11 @@
|
|
|
61
61
|
"@types/marked-terminal": "^6.1.1",
|
|
62
62
|
"@types/minimist": "^1.2.5",
|
|
63
63
|
"@types/semver": "^7.5.8",
|
|
64
|
+
"@types/tmp": "^0.2.6",
|
|
64
65
|
"@types/which": "^3.0.4",
|
|
65
66
|
"eslint-plugin-react": "^7.37.4",
|
|
66
|
-
"eslint-plugin-react-hooks": "^5.1.0"
|
|
67
|
+
"eslint-plugin-react-hooks": "^5.1.0",
|
|
68
|
+
"tmp": "^0.2.3"
|
|
67
69
|
},
|
|
68
70
|
"overrides": {
|
|
69
71
|
"@types/marked-terminal": {
|
|
@@ -86,5 +88,5 @@
|
|
|
86
88
|
"engines": {
|
|
87
89
|
"node": ">=20"
|
|
88
90
|
},
|
|
89
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "1e3f1321dea4acc946c9596f772d42c6ef7ac6c6"
|
|
90
92
|
}
|