@grafana/create-plugin 0.0.1
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/.eslintrc +6 -0
- package/.github/workflows/create-release.yml +49 -0
- package/.github/workflows/npm-bump-version.yml +51 -0
- package/.github/workflows/test.yml +31 -0
- package/.prettierrc +10 -0
- package/CONTRIBUTING.md +42 -0
- package/README.md +143 -0
- package/dist/bin/run.js +17 -0
- package/dist/commands/generate.command.js +56 -0
- package/dist/commands/generate.plopfile.js +119 -0
- package/dist/commands/index.js +19 -0
- package/dist/commands/migrate.command.js +133 -0
- package/dist/commands/update.command.js +101 -0
- package/dist/constants.js +74 -0
- package/dist/utils/tests/utils.files.test.js +30 -0
- package/dist/utils/tests/utils.handlebars.test.js +26 -0
- package/dist/utils/tests/utils.npm.test.js +138 -0
- package/dist/utils/tests/utils.plugin.test.js +20 -0
- package/dist/utils/tests/utils.templates.test.js +32 -0
- package/dist/utils/utils.console.js +41 -0
- package/dist/utils/utils.files.js +61 -0
- package/dist/utils/utils.handlebars.js +73 -0
- package/dist/utils/utils.npm.js +162 -0
- package/dist/utils/utils.plugin.js +14 -0
- package/dist/utils/utils.templates.js +77 -0
- package/docs/example.mp4 +0 -0
- package/jest.config.js +20 -0
- package/package.json +69 -0
- package/src/bin/run.ts +15 -0
- package/src/commands/generate.command.ts +15 -0
- package/src/commands/generate.plopfile.ts +151 -0
- package/src/commands/index.ts +3 -0
- package/src/commands/migrate.command.ts +99 -0
- package/src/commands/update.command.ts +66 -0
- package/src/constants.ts +99 -0
- package/src/utils/tests/utils.files.test.ts +41 -0
- package/src/utils/tests/utils.handlebars.test.ts +35 -0
- package/src/utils/tests/utils.npm.test.ts +193 -0
- package/src/utils/tests/utils.plugin.test.ts +22 -0
- package/src/utils/tests/utils.templates.test.ts +44 -0
- package/src/utils/utils.console.ts +41 -0
- package/src/utils/utils.files.ts +65 -0
- package/src/utils/utils.handlebars.ts +47 -0
- package/src/utils/utils.npm.ts +189 -0
- package/src/utils/utils.plugin.ts +9 -0
- package/src/utils/utils.templates.ts +76 -0
- package/templates/_partials/backend-getting-started.md +20 -0
- package/templates/_partials/frontend-getting-started.md +59 -0
- package/templates/app/README.md +20 -0
- package/templates/app/src/components/App/App.test.tsx +32 -0
- package/templates/app/src/components/App/App.tsx +8 -0
- package/templates/app/src/components/App/index.tsx +1 -0
- package/templates/app/src/components/AppConfig/AppConfig.test.tsx +51 -0
- package/templates/app/src/components/AppConfig/AppConfig.tsx +92 -0
- package/templates/app/src/components/AppConfig/index.tsx +1 -0
- package/templates/app/src/module.ts +12 -0
- package/templates/app/src/plugin.json +33 -0
- package/templates/backend/Magefile.go +12 -0
- package/templates/backend/go.mod +5 -0
- package/templates/backend/go.sum +568 -0
- package/templates/backend/pkg/main.go +24 -0
- package/templates/backend/pkg/plugin/datasource.go +111 -0
- package/templates/backend/pkg/plugin/datasource_test.go +28 -0
- package/templates/common/.config/.eslintrc +12 -0
- package/templates/common/.config/.prettierrc.js +16 -0
- package/templates/common/.config/Dockerfile +15 -0
- package/templates/common/.config/README.md +115 -0
- package/templates/common/.config/jest-setup.js +24 -0
- package/templates/common/.config/jest.config.js +31 -0
- package/templates/common/.config/tsconfig.json +17 -0
- package/templates/common/.config/types/custom.d.ts +37 -0
- package/templates/common/.config/webpack/constants.ts +3 -0
- package/templates/common/.config/webpack/tsconfig.webpack.json +9 -0
- package/templates/common/.config/webpack/utils.ts +17 -0
- package/templates/common/.config/webpack/webpack.config.ts +187 -0
- package/templates/common/.eslintrc +3 -0
- package/templates/common/.nvmrc +1 -0
- package/templates/common/.prettierrc.js +4 -0
- package/templates/common/CHANGELOG.md +5 -0
- package/templates/common/LICENSE +201 -0
- package/templates/common/cypress/integration/01-smoke.spec.ts +10 -0
- package/templates/common/docker-compose.yaml +14 -0
- package/templates/common/jest-setup.js +2 -0
- package/templates/common/jest.config.js +4 -0
- package/templates/common/package.json +67 -0
- package/templates/common/src/README.md +5 -0
- package/templates/common/src/img/logo.svg +1 -0
- package/templates/common/tsconfig.json +3 -0
- package/templates/datasource/README.md +20 -0
- package/templates/datasource/src/components/ConfigEditor.tsx +83 -0
- package/templates/datasource/src/components/QueryEditor.tsx +50 -0
- package/templates/datasource/src/datasource.ts +46 -0
- package/templates/datasource/src/module.ts +9 -0
- package/templates/datasource/src/plugin.json +37 -0
- package/templates/datasource/src/types.ts +24 -0
- package/templates/github/ci/.github/workflows/ci.yml +76 -0
- package/templates/github/ci/.github/workflows/release.yml +165 -0
- package/templates/github/is-compatible/.github/workflows/is-compatible.yml +17 -0
- package/templates/panel/README.md +22 -0
- package/templates/panel/src/components/SimplePanel.tsx +62 -0
- package/templates/panel/src/module.test.ts +6 -0
- package/templates/panel/src/module.ts +40 -0
- package/templates/panel/src/plugin.json +33 -0
- package/templates/panel/src/types.ts +7 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { TEXT, MIGRATION_CONFIG } from '../constants';
|
|
2
|
+
import { displayArrayAsList, printMessage, printSuccessMessage, confirmPrompt } from '../utils/utils.console';
|
|
3
|
+
import { compileTemplateFiles, getTemplateData } from '../utils/utils.templates';
|
|
4
|
+
import { getOnlyExistingInCwd, getOnlyNotExistingInCwd, removeFilesInCwd } from '../utils/utils.files';
|
|
5
|
+
import {
|
|
6
|
+
getPackageJsonUpdatesAsText,
|
|
7
|
+
updatePackageJson,
|
|
8
|
+
hasNpmDependenciesToUpdate,
|
|
9
|
+
getRemovableNpmDependencies,
|
|
10
|
+
removeNpmDependencies,
|
|
11
|
+
updateNpmScripts,
|
|
12
|
+
} from '../utils/utils.npm';
|
|
13
|
+
|
|
14
|
+
export const migrate = async () => {
|
|
15
|
+
try {
|
|
16
|
+
// 0. Warning
|
|
17
|
+
// -----------
|
|
18
|
+
printMessage(TEXT.migrationCommandWarning);
|
|
19
|
+
|
|
20
|
+
// 1. Add / update configuration files
|
|
21
|
+
// --------------------------
|
|
22
|
+
if (await confirmPrompt(TEXT.overrideFilesPrompt + '\n' + displayArrayAsList(MIGRATION_CONFIG.filesToOverride))) {
|
|
23
|
+
compileTemplateFiles(MIGRATION_CONFIG.filesToOverride, getTemplateData());
|
|
24
|
+
printSuccessMessage(TEXT.overrideFilesSuccess);
|
|
25
|
+
} else {
|
|
26
|
+
printMessage(TEXT.overrideFilesAborted);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 2. Add necessary files if they don't exist (files we don't want to override)
|
|
31
|
+
// (skipped automatically if there are none)
|
|
32
|
+
// --------------------------------------------
|
|
33
|
+
const filesToExist = getOnlyNotExistingInCwd(MIGRATION_CONFIG.filesToExist);
|
|
34
|
+
if (filesToExist.length) {
|
|
35
|
+
if (await confirmPrompt(TEXT.filesToExistPrompt + '\n' + displayArrayAsList(filesToExist))) {
|
|
36
|
+
compileTemplateFiles(filesToExist, getTemplateData());
|
|
37
|
+
printSuccessMessage(TEXT.filesToExistSuccess);
|
|
38
|
+
} else {
|
|
39
|
+
printMessage(TEXT.filesToExistAborted);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 3. Remove unnecessary files from the project
|
|
44
|
+
// (skipped automatically if there are none)
|
|
45
|
+
// --------------------------------------------
|
|
46
|
+
const filesToRemove = getOnlyExistingInCwd(MIGRATION_CONFIG.filesToRemove);
|
|
47
|
+
if (filesToRemove.length) {
|
|
48
|
+
if (await confirmPrompt(TEXT.removeFilesPrompt + '\n' + displayArrayAsList(filesToRemove))) {
|
|
49
|
+
removeFilesInCwd(filesToRemove);
|
|
50
|
+
printSuccessMessage(TEXT.removeFilesSuccess);
|
|
51
|
+
} else {
|
|
52
|
+
printMessage(TEXT.removeFilesAborted);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 4. Add / update dependencies inside the `package.json`
|
|
57
|
+
// (skipped automatically if there is nothing to update)
|
|
58
|
+
// ------------------------------------------------
|
|
59
|
+
if (hasNpmDependenciesToUpdate()) {
|
|
60
|
+
if (await confirmPrompt(TEXT.updateNpmDependenciesPrompt + getPackageJsonUpdatesAsText())) {
|
|
61
|
+
updatePackageJson();
|
|
62
|
+
printSuccessMessage(TEXT.updateNpmDependenciesSuccess);
|
|
63
|
+
} else {
|
|
64
|
+
printMessage(TEXT.updateNpmDependenciesAborted);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 5. Remove unncessary NPM dependencies from `package.json`
|
|
69
|
+
// (skipped automatically if there is nothing to be removed)
|
|
70
|
+
// ------------------------------------------------
|
|
71
|
+
const dependenciesToRemove = getRemovableNpmDependencies(MIGRATION_CONFIG.npmDependenciesToRemove);
|
|
72
|
+
const devDependenciesToRemove = getRemovableNpmDependencies(MIGRATION_CONFIG.devNpmDependenciesToRemove);
|
|
73
|
+
if (dependenciesToRemove.length) {
|
|
74
|
+
if (await confirmPrompt(TEXT.removeNpmDependenciesPrompt + '\n' + displayArrayAsList(dependenciesToRemove))) {
|
|
75
|
+
removeNpmDependencies(dependenciesToRemove);
|
|
76
|
+
removeNpmDependencies(devDependenciesToRemove, { devOnly: true });
|
|
77
|
+
printSuccessMessage(TEXT.removeNpmDependenciesSuccess);
|
|
78
|
+
} else {
|
|
79
|
+
printMessage(TEXT.removeNpmDependenciesAborted);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 6. Add / update NPM scripts
|
|
84
|
+
// (skipped automatically if there is nothing to update)
|
|
85
|
+
// ------------------------------------------------
|
|
86
|
+
if (await confirmPrompt(TEXT.updateNpmScriptsPrompt)) {
|
|
87
|
+
updateNpmScripts();
|
|
88
|
+
printSuccessMessage(TEXT.updateNpmScriptsSuccess);
|
|
89
|
+
} else {
|
|
90
|
+
printMessage(TEXT.updateNpmScriptsAborted);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 4. Summary
|
|
94
|
+
// -------------
|
|
95
|
+
printSuccessMessage(TEXT.migrationCommandSuccess);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(error);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { TEXT, UDPATE_CONFIG } from '../constants';
|
|
2
|
+
import { compileTemplateFiles, getTemplateData } from '../utils/utils.templates';
|
|
3
|
+
import { confirmPrompt, selectPrompt, printMessage, printSuccessMessage } from '../utils/utils.console';
|
|
4
|
+
import {
|
|
5
|
+
updatePackageJson,
|
|
6
|
+
hasNpmDependenciesToUpdate,
|
|
7
|
+
getPackageJsonUpdatesAsText,
|
|
8
|
+
updateNpmScripts,
|
|
9
|
+
} from '../utils/utils.npm';
|
|
10
|
+
|
|
11
|
+
export const update = async () => {
|
|
12
|
+
try {
|
|
13
|
+
// 0. Warning
|
|
14
|
+
// ----------
|
|
15
|
+
printMessage(TEXT.updateCommandWarning);
|
|
16
|
+
|
|
17
|
+
// 1. Add / update configuration files
|
|
18
|
+
// -----------------------------------
|
|
19
|
+
if (await confirmPrompt(TEXT.overrideFilesPrompt)) {
|
|
20
|
+
compileTemplateFiles(UDPATE_CONFIG.filesToOverride, getTemplateData());
|
|
21
|
+
printSuccessMessage(TEXT.overrideFilesSuccess);
|
|
22
|
+
} else {
|
|
23
|
+
printMessage(TEXT.overrideFilesAborted);
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 2. Add / update dependencies inside the `package.json`
|
|
28
|
+
// (skipped automatically if there is nothing to update)
|
|
29
|
+
// ------------------------------------------------
|
|
30
|
+
if (hasNpmDependenciesToUpdate()) {
|
|
31
|
+
const PROMPT_CHOICES = {
|
|
32
|
+
ALL: 'Yes, all of them',
|
|
33
|
+
ONLY_OUTDATED: 'Yes, but only the outdated ones',
|
|
34
|
+
NONE: 'No',
|
|
35
|
+
};
|
|
36
|
+
const shouldUpdateDeps = await selectPrompt(TEXT.updateNpmDependenciesPrompt + getPackageJsonUpdatesAsText(), [
|
|
37
|
+
PROMPT_CHOICES.ALL,
|
|
38
|
+
PROMPT_CHOICES.ONLY_OUTDATED,
|
|
39
|
+
PROMPT_CHOICES.NONE,
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
if (shouldUpdateDeps && shouldUpdateDeps !== PROMPT_CHOICES.NONE) {
|
|
43
|
+
updatePackageJson({ onlyOutdated: shouldUpdateDeps === PROMPT_CHOICES.ONLY_OUTDATED });
|
|
44
|
+
printSuccessMessage(TEXT.updateNpmDependenciesSuccess);
|
|
45
|
+
} else {
|
|
46
|
+
printMessage(TEXT.updateNpmDependenciesAborted);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 3. Add / update NPM scripts
|
|
51
|
+
// (skipped automatically if there is nothing to update)
|
|
52
|
+
// ------------------------------------------------
|
|
53
|
+
if (await confirmPrompt(TEXT.updateNpmScriptsPrompt)) {
|
|
54
|
+
updateNpmScripts();
|
|
55
|
+
printSuccessMessage(TEXT.updateNpmScriptsSuccess);
|
|
56
|
+
} else {
|
|
57
|
+
printMessage(TEXT.updateNpmScriptsAborted);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 4. Summary
|
|
61
|
+
// -------------
|
|
62
|
+
printSuccessMessage(TEXT.updateCommandSuccess);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(error);
|
|
65
|
+
}
|
|
66
|
+
};
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
export const IS_DEV = process.env.CREATE_PLUGIN_DEV !== undefined;
|
|
4
|
+
|
|
5
|
+
export const DEV_EXPORT_DIR = path.join(__dirname, '..', 'generated');
|
|
6
|
+
|
|
7
|
+
export const EXPORT_PATH_PREFIX = IS_DEV ? DEV_EXPORT_DIR : process.cwd();
|
|
8
|
+
|
|
9
|
+
export const DIST_DIR = path.join(__dirname, 'dist');
|
|
10
|
+
|
|
11
|
+
export const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
12
|
+
|
|
13
|
+
// Partials are template files that can be used in other templates
|
|
14
|
+
// (they won't be copied over to the generated folder as they are)
|
|
15
|
+
export const PARTIALS_DIR = path.join(TEMPLATES_DIR, '_partials');
|
|
16
|
+
|
|
17
|
+
export const TEMPLATE_PATHS: Record<string, string> = {
|
|
18
|
+
app: path.join(TEMPLATES_DIR, 'app'),
|
|
19
|
+
backend: path.join(TEMPLATES_DIR, 'backend'),
|
|
20
|
+
common: path.join(TEMPLATES_DIR, 'common'),
|
|
21
|
+
datasource: path.join(TEMPLATES_DIR, 'datasource'),
|
|
22
|
+
panel: path.join(TEMPLATES_DIR, 'panel'),
|
|
23
|
+
ciWorkflows: path.join(TEMPLATES_DIR, 'github', 'ci'),
|
|
24
|
+
isCompatibleWorkflow: path.join(TEMPLATES_DIR, 'github', 'is-compatible'),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export enum PLUGIN_TYPES {
|
|
28
|
+
app = 'app',
|
|
29
|
+
panel = 'panel',
|
|
30
|
+
datasource = 'datasource',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// This gets merged into variables coming from user prompts (when using Plop) or any other dynamic variables,
|
|
34
|
+
// and will be available to use in the templates.
|
|
35
|
+
// Example: "@grafana/ui": "{{ grafanaVersion }}"
|
|
36
|
+
export const EXTRA_TEMPLATE_VARIABLES = {
|
|
37
|
+
grafanaVersion: '9.1.2',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const MIGRATION_CONFIG = {
|
|
41
|
+
// Files that should be overriden during a migration.
|
|
42
|
+
// (paths are relative to the scaffolded projects root)
|
|
43
|
+
filesToOverride: [
|
|
44
|
+
'.config/',
|
|
45
|
+
'.eslintrc',
|
|
46
|
+
'.nvmrc',
|
|
47
|
+
'.prettierrc.js',
|
|
48
|
+
'docker-compose.yaml', // Using .yaml instead of .yml (https://yaml.org/faq.html)
|
|
49
|
+
'jest-setup.js',
|
|
50
|
+
'jest.config.js',
|
|
51
|
+
'tsconfig.json',
|
|
52
|
+
],
|
|
53
|
+
// Files that are mandatory for the plugins, but we don't want to ever override them. We are only creating the ones that don't exist.
|
|
54
|
+
// (paths are relative to the scaffolded projects root)
|
|
55
|
+
filesToExist: ['CHANGELOG.md'],
|
|
56
|
+
// Files that are no longer needed for the project and possibly can be removed.
|
|
57
|
+
filesToRemove: ['Dockerfile', 'docker-compose.yml', 'webpack/', '.webpack/', '.prettierrc'],
|
|
58
|
+
// NPM dependencies that are no longer needed for the project and possibly can be removed.
|
|
59
|
+
npmDependenciesToRemove: ['ts-loader', 'babel-loader', '@grafana/toolkit'],
|
|
60
|
+
devNpmDependenciesToRemove: ['@grafana/toolkit', '@grafana/runtime', '@grafana/data', '@grafana/ui'],
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const UDPATE_CONFIG = {
|
|
64
|
+
// Files that should be overriden between configuration version updates.
|
|
65
|
+
filesToOverride: ['.config/'],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// prettier-ignore
|
|
69
|
+
export const TEXT = {
|
|
70
|
+
overrideFilesPrompt: '**The following files will be overriden, would you like to continue?**',
|
|
71
|
+
overrideFilesSuccess: 'Configuration files updated successfully.',
|
|
72
|
+
overrideFilesAborted: 'Migration aborted.',
|
|
73
|
+
|
|
74
|
+
filesToExistPrompt: '**The following files are necessary for the project to work, can we scaffold them for you?**',
|
|
75
|
+
filesToExistSuccess: 'Extra necessaryily files created successfully.',
|
|
76
|
+
filesToExistAborted: 'No extra necessary files were scaffolded.',
|
|
77
|
+
|
|
78
|
+
removeFilesPrompt: '**The following files are possibly not needed for the project anymore, are you ok with us removing them?**',
|
|
79
|
+
removeFilesSuccess: 'Unnecessary files have been removed successfully.',
|
|
80
|
+
removeFilesAborted: 'No unnecessary files were deleted.',
|
|
81
|
+
|
|
82
|
+
updateNpmDependenciesPrompt: '**Would you like to update the following dependencies in the `package.json?`**',
|
|
83
|
+
updateNpmDependenciesSuccess: 'Successfully updated the NPM dependencies.',
|
|
84
|
+
updateNpmDependenciesAborted: 'No NPM dependencies have been updated.',
|
|
85
|
+
|
|
86
|
+
removeNpmDependenciesPrompt: '**Would you like to remove the following possibly unnecessary NPM dependencies?**',
|
|
87
|
+
removeNpmDependenciesSuccess: 'Unnecessary NPM dependencies removed successfully.',
|
|
88
|
+
removeNpmDependenciesAborted: 'No NPM dependencies have been removed.',
|
|
89
|
+
|
|
90
|
+
updateNpmScriptsPrompt: '**Would you like to update the `{ scripts }` in your `package.json`?**',
|
|
91
|
+
updateNpmScriptsSuccess: 'NPM scripts updated successfully.',
|
|
92
|
+
updateNpmScriptsAborted: 'No NPM scripts have been added or updated.',
|
|
93
|
+
|
|
94
|
+
migrationCommandWarning: '**⚠️ Warning!**\nThis is going to change files in your current project to make it up-to-date with the latest plugin configuration.\nPlease make sure that you have backed up your changes.',
|
|
95
|
+
migrationCommandSuccess: '**Done.**\nIf you have any questions please open an issue/discussion in https://github.com/grafana/create-plugin.',
|
|
96
|
+
|
|
97
|
+
updateCommandWarning: '**⚠️ Warning!**\nThis is going to update files under the `.config/` folder.\nMake sure to commit your changes before running this script.',
|
|
98
|
+
updateCommandSuccess: '**Done.**\nIf you have any questions please open an issue/discussion in https://github.com/grafana/create-plugin.',
|
|
99
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { PLUGIN_TYPES, TEMPLATE_PATHS } from '../../constants';
|
|
2
|
+
import { filterOutCommonFiles, isFile } from '../utils.files';
|
|
3
|
+
|
|
4
|
+
describe('Utils/Files', () => {
|
|
5
|
+
describe('filterOutCommonFiles()', () => {
|
|
6
|
+
test('should remove common template files from the list that have a plugin-specific override', () => {
|
|
7
|
+
expect(
|
|
8
|
+
filterOutCommonFiles(
|
|
9
|
+
[
|
|
10
|
+
// Common template files
|
|
11
|
+
`${TEMPLATE_PATHS.common}/.config/.eslintrc`,
|
|
12
|
+
`${TEMPLATE_PATHS.common}/.config/.gitignore`,
|
|
13
|
+
`${TEMPLATE_PATHS.common}/.config/package.json`,
|
|
14
|
+
|
|
15
|
+
// Override of a common template file
|
|
16
|
+
`${TEMPLATE_PATHS.app}/.config/package.json`,
|
|
17
|
+
|
|
18
|
+
// Only exists in the plugin-type specific templates
|
|
19
|
+
`${TEMPLATE_PATHS.app}/.config/README.md`,
|
|
20
|
+
],
|
|
21
|
+
PLUGIN_TYPES.app
|
|
22
|
+
)
|
|
23
|
+
).toEqual([
|
|
24
|
+
`${TEMPLATE_PATHS.common}/.config/.eslintrc`,
|
|
25
|
+
`${TEMPLATE_PATHS.common}/.config/.gitignore`,
|
|
26
|
+
`${TEMPLATE_PATHS.app}/.config/package.json`,
|
|
27
|
+
`${TEMPLATE_PATHS.app}/.config/README.md`,
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('isFile()', () => {
|
|
33
|
+
test('should return TRUE if the path is pointing to a file', () => {
|
|
34
|
+
expect(isFile(`${TEMPLATE_PATHS.common}/LICENSE`)).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should return FALSE if the path is pointing to a directory', () => {
|
|
38
|
+
expect(isFile(TEMPLATE_PATHS.common)).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { PLUGIN_TYPES } from '../../constants';
|
|
2
|
+
import { normalizeId } from '../utils.handlebars';
|
|
3
|
+
|
|
4
|
+
describe('Handlebars helpers', () => {
|
|
5
|
+
describe('normalize id', () => {
|
|
6
|
+
test.each([PLUGIN_TYPES.app, PLUGIN_TYPES.datasource, PLUGIN_TYPES.panel])(
|
|
7
|
+
'should return the id with the type appended',
|
|
8
|
+
(type: PLUGIN_TYPES) => {
|
|
9
|
+
const pluginName = 'my-plugin';
|
|
10
|
+
const orgName = 'my-org';
|
|
11
|
+
const actual = normalizeId(pluginName, orgName, type);
|
|
12
|
+
expect(actual).toEqual(`my-org-my-plugin-${type}`);
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
test.each([PLUGIN_TYPES.app, PLUGIN_TYPES.datasource, PLUGIN_TYPES.panel])(
|
|
16
|
+
'should not duplicate the type if it is already present',
|
|
17
|
+
(type: PLUGIN_TYPES) => {
|
|
18
|
+
const pluginName = `my-plugin-${type}`;
|
|
19
|
+
const orgName = 'my-org';
|
|
20
|
+
const actual = normalizeId(pluginName, orgName, type);
|
|
21
|
+
expect(actual).toEqual(`my-org-my-plugin-${type}`);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
test.each([PLUGIN_TYPES.app, PLUGIN_TYPES.datasource, PLUGIN_TYPES.panel])(
|
|
26
|
+
'should not duplicate the type if it is already present (no dash before type)',
|
|
27
|
+
(type: PLUGIN_TYPES) => {
|
|
28
|
+
const pluginName = `my-plugin${type}`;
|
|
29
|
+
const orgName = 'my-org';
|
|
30
|
+
const actual = normalizeId(pluginName, orgName, type);
|
|
31
|
+
expect(actual).toEqual(`my-org-my-plugin-${type}`);
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { updateNpmDependencies, getUpdatableNpmDependencies } from '../utils.npm';
|
|
2
|
+
|
|
3
|
+
describe('Utils / NPM', () => {
|
|
4
|
+
describe('getDepenciesToBeUpdated()', () => {
|
|
5
|
+
test('it should return a summary of dependencies to be updated', () => {
|
|
6
|
+
expect(
|
|
7
|
+
getUpdatableNpmDependencies(
|
|
8
|
+
// current
|
|
9
|
+
{
|
|
10
|
+
'@grafana/tsconfig': '^1.2.0-rc1',
|
|
11
|
+
'@swc/core': '^1.2.162',
|
|
12
|
+
'@types/minimist': '^1.6.2',
|
|
13
|
+
'@types/mkdirp': '^1.0.2',
|
|
14
|
+
'@types/semver': '^7.3.9',
|
|
15
|
+
'node-plop': '0.26.3',
|
|
16
|
+
},
|
|
17
|
+
// new
|
|
18
|
+
{
|
|
19
|
+
'@grafana/tsconfig': '^2.0.0', // updated
|
|
20
|
+
'@swc/core': '^1.2.162',
|
|
21
|
+
'@types/minimist': '^1.4.2', // updated
|
|
22
|
+
'@types/mkdirp': '^1.0.2',
|
|
23
|
+
'@types/semver': '^7.3.9',
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
).toEqual({
|
|
27
|
+
'@grafana/tsconfig': { prev: '^1.2.0-rc1', next: '^2.0.0' },
|
|
28
|
+
'@types/minimist': { prev: '^1.6.2', next: '^1.4.2' },
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('it should be possible to only update dependencies that are outdated', () => {
|
|
33
|
+
expect(
|
|
34
|
+
getUpdatableNpmDependencies(
|
|
35
|
+
// current
|
|
36
|
+
{
|
|
37
|
+
'@grafana/tsconfig': '^1.2.0-rc1',
|
|
38
|
+
'@swc/core': '^1.2.162',
|
|
39
|
+
'@types/minimist': '^1.6.2',
|
|
40
|
+
'@types/mkdirp': '^1.0.2',
|
|
41
|
+
'@types/semver': '^7.3.9',
|
|
42
|
+
'node-plop': '0.26.3',
|
|
43
|
+
},
|
|
44
|
+
// new
|
|
45
|
+
{
|
|
46
|
+
'@grafana/tsconfig': '^2.0.0', // updated
|
|
47
|
+
'@swc/core': '^1.2.162',
|
|
48
|
+
'@types/minimist': '^1.4.2', // updated - BUT older than the current one
|
|
49
|
+
'@types/mkdirp': '^1.0.2',
|
|
50
|
+
'@types/semver': '^7.3.9',
|
|
51
|
+
},
|
|
52
|
+
{ onlyOutdated: true }
|
|
53
|
+
)
|
|
54
|
+
).toEqual({
|
|
55
|
+
'@grafana/tsconfig': { prev: '^1.2.0-rc1', next: '^2.0.0' },
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('it should be able to override with using release channels like "latest"', () => {
|
|
60
|
+
expect(
|
|
61
|
+
getUpdatableNpmDependencies(
|
|
62
|
+
// current
|
|
63
|
+
{
|
|
64
|
+
'@grafana/tsconfig': 'latest',
|
|
65
|
+
'@swc/core': '^1.2.162',
|
|
66
|
+
'@types/minimist': '^1.6.2',
|
|
67
|
+
'@types/mkdirp': '^1.0.2',
|
|
68
|
+
'@types/semver': '^7.3.9',
|
|
69
|
+
'node-plop': '0.26.3',
|
|
70
|
+
},
|
|
71
|
+
// new
|
|
72
|
+
{
|
|
73
|
+
'@grafana/tsconfig': '^2.0.0', // updated
|
|
74
|
+
'@swc/core': 'latest', // updated
|
|
75
|
+
'@types/minimist': '^1.4.2', // updated
|
|
76
|
+
'@types/mkdirp': '^1.0.2',
|
|
77
|
+
'@types/semver': '^7.3.9',
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
).toEqual({
|
|
81
|
+
'@grafana/tsconfig': { prev: 'latest', next: '^2.0.0' },
|
|
82
|
+
'@swc/core': { prev: '^1.2.162', next: 'latest' },
|
|
83
|
+
'@types/minimist': { prev: '^1.6.2', next: '^1.4.2' },
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('updateDependencies()', () => {
|
|
89
|
+
test('it should update existing dependencies', () => {
|
|
90
|
+
expect(
|
|
91
|
+
updateNpmDependencies(
|
|
92
|
+
// dependencies
|
|
93
|
+
{
|
|
94
|
+
'@grafana/tsconfig': '^1.2.0-rc1',
|
|
95
|
+
'@swc/core': '^1.2.162',
|
|
96
|
+
'@types/minimist': '^1.2.2',
|
|
97
|
+
'@types/mkdirp': '^1.0.2',
|
|
98
|
+
'@types/semver': '^7.3.9',
|
|
99
|
+
'node-plop': '0.26.3',
|
|
100
|
+
},
|
|
101
|
+
// update summary
|
|
102
|
+
{
|
|
103
|
+
'@grafana/tsconfig': { prev: '^1.2.0-rc1', next: '^2.0.0' },
|
|
104
|
+
'@types/minimist': { prev: '^1.2.2', next: '^1.4.2' },
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
).toEqual({
|
|
108
|
+
'@grafana/tsconfig': '^2.0.0', // updated
|
|
109
|
+
'@swc/core': '^1.2.162',
|
|
110
|
+
'@types/minimist': '^1.4.2', // updated
|
|
111
|
+
'@types/mkdirp': '^1.0.2',
|
|
112
|
+
'@types/semver': '^7.3.9',
|
|
113
|
+
'node-plop': '0.26.3',
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('it should add new depdendencies', () => {
|
|
118
|
+
expect(
|
|
119
|
+
updateNpmDependencies(
|
|
120
|
+
// dependencies
|
|
121
|
+
{
|
|
122
|
+
'@grafana/tsconfig': '^1.2.0-rc1',
|
|
123
|
+
'@swc/core': '^1.2.162',
|
|
124
|
+
},
|
|
125
|
+
// update summary
|
|
126
|
+
{
|
|
127
|
+
'@grafana/tsconfig': { prev: '^1.2.0-rc1', next: '^1.2.0-rc1' },
|
|
128
|
+
'@swc/core': { prev: '^1.2.162', next: '^1.2.162' },
|
|
129
|
+
'@types/minimist': { prev: null, next: '^1.4.2' }, // new
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
).toEqual({
|
|
133
|
+
'@grafana/tsconfig': '^1.2.0-rc1',
|
|
134
|
+
'@swc/core': '^1.2.162',
|
|
135
|
+
'@types/minimist': '^1.4.2', // new
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('it should override `latest` and other release channels', () => {
|
|
140
|
+
expect(
|
|
141
|
+
updateNpmDependencies(
|
|
142
|
+
// dependencies
|
|
143
|
+
{
|
|
144
|
+
'@grafana/tsconfig': 'latest',
|
|
145
|
+
'@swc/core': '^1.2.162',
|
|
146
|
+
'@types/minimist': '^1.2.2',
|
|
147
|
+
'@types/mkdirp': '^1.0.2',
|
|
148
|
+
'@types/semver': '^8.0.0',
|
|
149
|
+
'node-plop': '0.26.3',
|
|
150
|
+
},
|
|
151
|
+
// update summary
|
|
152
|
+
{
|
|
153
|
+
'@grafana/tsconfig': { prev: 'latest', next: '^2.0.0' },
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
).toEqual({
|
|
157
|
+
'@grafana/tsconfig': '^2.0.0', // updated
|
|
158
|
+
'@swc/core': '^1.2.162',
|
|
159
|
+
'@types/minimist': '^1.2.2',
|
|
160
|
+
'@types/mkdirp': '^1.0.2',
|
|
161
|
+
'@types/semver': '^8.0.0',
|
|
162
|
+
'node-plop': '0.26.3',
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('it should be able to override with using release channels like "latest"', () => {
|
|
167
|
+
expect(
|
|
168
|
+
updateNpmDependencies(
|
|
169
|
+
// dependencies
|
|
170
|
+
{
|
|
171
|
+
'@grafana/tsconfig': '^2.0.0',
|
|
172
|
+
'@swc/core': '^1.2.162',
|
|
173
|
+
'@types/minimist': '^1.2.2',
|
|
174
|
+
'@types/mkdirp': '^1.0.2',
|
|
175
|
+
'@types/semver': '^8.0.0',
|
|
176
|
+
'node-plop': '0.26.3',
|
|
177
|
+
},
|
|
178
|
+
// update summary
|
|
179
|
+
{
|
|
180
|
+
'@grafana/tsconfig': { prev: '', next: 'latest' },
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
).toEqual({
|
|
184
|
+
'@grafana/tsconfig': 'latest', // updated
|
|
185
|
+
'@swc/core': '^1.2.162',
|
|
186
|
+
'@types/minimist': '^1.2.2',
|
|
187
|
+
'@types/mkdirp': '^1.0.2',
|
|
188
|
+
'@types/semver': '^8.0.0',
|
|
189
|
+
'node-plop': '0.26.3',
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { TEMPLATE_PATHS } from '../../constants';
|
|
2
|
+
import { getPluginJson } from '../utils.plugin';
|
|
3
|
+
|
|
4
|
+
describe('Utils / Plugins', () => {
|
|
5
|
+
describe('getPluginJson()', () => {
|
|
6
|
+
test('should return the parsed plugin JSON if the file exits', () => {
|
|
7
|
+
const srcDir = `${TEMPLATE_PATHS.app}/src`;
|
|
8
|
+
const pluginJson = getPluginJson(srcDir);
|
|
9
|
+
|
|
10
|
+
expect(pluginJson).toBeDefined();
|
|
11
|
+
expect(pluginJson.type).toBe('app');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('should throw an error if the plugin.json is not found', () => {
|
|
15
|
+
const srcDir = `${TEMPLATE_PATHS.app}/src/unknown`;
|
|
16
|
+
|
|
17
|
+
expect(() => {
|
|
18
|
+
getPluginJson(srcDir);
|
|
19
|
+
}).toThrow();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { PLUGIN_TYPES } from '../../constants';
|
|
2
|
+
import { getTemplateFiles } from '../utils.templates';
|
|
3
|
+
|
|
4
|
+
describe('Utils / Templates', () => {
|
|
5
|
+
describe('getTemplateFiles()', () => {
|
|
6
|
+
test('should return with a list of files', () => {
|
|
7
|
+
expect(getTemplateFiles(PLUGIN_TYPES.app).length).toBeGreaterThan(0);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('should be possible to filter templates by a sub-folder', () => {
|
|
11
|
+
const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, '.config/types');
|
|
12
|
+
|
|
13
|
+
// Should have found at least one file
|
|
14
|
+
expect(templateFiles.length).toBeGreaterThan(0);
|
|
15
|
+
|
|
16
|
+
// A file that should live in this sub-directory
|
|
17
|
+
expect(templateFiles.find((t) => t.includes('custom.d.ts'))).not.toBeUndefined();
|
|
18
|
+
|
|
19
|
+
// Something that should not be found in this sub-directory
|
|
20
|
+
expect(templateFiles.find((t) => t.includes('Dockerfile'))).toBeUndefined();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('should return an empty array when filtering by a non-existing sub-folder', () => {
|
|
24
|
+
const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, '.config/types/foo/bar/unknown');
|
|
25
|
+
|
|
26
|
+
expect(Array.isArray(templateFiles)).toBe(true);
|
|
27
|
+
expect(templateFiles.length).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('should be possible to filter for multiple different files', () => {
|
|
31
|
+
const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, ['.eslintrc', '.prettierrc.js', 'tsconfig.json']);
|
|
32
|
+
|
|
33
|
+
expect(Array.isArray(templateFiles)).toBe(true);
|
|
34
|
+
expect(templateFiles.length).toBe(3);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should be possible to filter for a single file', () => {
|
|
38
|
+
const templateFiles = getTemplateFiles(PLUGIN_TYPES.app, '.config/types/custom.d.ts');
|
|
39
|
+
|
|
40
|
+
expect(Array.isArray(templateFiles)).toBe(true);
|
|
41
|
+
expect(templateFiles.length).toBe(1);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { marked } = require('marked');
|
|
2
|
+
const TerminalRenderer = require('marked-terminal');
|
|
3
|
+
const { Confirm, Select } = require('enquirer');
|
|
4
|
+
|
|
5
|
+
marked.setOptions({
|
|
6
|
+
renderer: new TerminalRenderer(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export function displayAsMarkdown(msg: string) {
|
|
10
|
+
return marked(msg);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function displayArrayAsList(files: string[]) {
|
|
14
|
+
return ` - ${files.map((t) => `\`${t}\``).join('\n - ')}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function printMessage(msg: string) {
|
|
18
|
+
console.log(displayAsMarkdown(`\n${msg}`));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function printSuccessMessage(msg: string) {
|
|
22
|
+
console.log(displayAsMarkdown(`\n✔ ${msg}`));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function confirmPrompt(message: string) {
|
|
26
|
+
const prompt = new Confirm({
|
|
27
|
+
name: 'question',
|
|
28
|
+
message: displayAsMarkdown(message),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return prompt.run();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function selectPrompt(message: string, choices: string[]) {
|
|
35
|
+
const prompt = new Select({
|
|
36
|
+
choices,
|
|
37
|
+
message: displayAsMarkdown(message),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return prompt.run();
|
|
41
|
+
}
|