@grafana/create-plugin 0.5.4 → 0.6.0-canary.160.e62f4fc.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 CHANGED
@@ -1,53 +1,3 @@
1
- # v0.5.4 (Fri Nov 18 2022)
2
-
3
- #### 🐛 Bug Fix
4
-
5
- - Create-plugin: Fix failing jest config [#151](https://github.com/grafana/plugin-tools/pull/151) ([@jackw](https://github.com/jackw))
6
-
7
- #### Authors: 1
8
-
9
- - Jack Westbrook ([@jackw](https://github.com/jackw))
10
-
11
- ---
12
-
13
- # v0.5.3 (Thu Nov 17 2022)
14
-
15
- #### 🐛 Bug Fix
16
-
17
- - Create-Plugin: Transform known ES modules in jest config [#145](https://github.com/grafana/plugin-tools/pull/145) ([@jackw](https://github.com/jackw))
18
-
19
- #### Authors: 1
20
-
21
- - Jack Westbrook ([@jackw](https://github.com/jackw))
22
-
23
- ---
24
-
25
- # v0.5.2 (Thu Nov 17 2022)
26
-
27
- #### 🐛 Bug Fix
28
-
29
- - Create-Plugin: Bump dependencies to support node 18 [#144](https://github.com/grafana/plugin-tools/pull/144) ([@jackw](https://github.com/jackw))
30
- - Create-Plugin: Backend template: Switch from Info to Debug level [#146](https://github.com/grafana/plugin-tools/pull/146) ([@xnyo](https://github.com/xnyo))
31
-
32
- #### Authors: 2
33
-
34
- - Giuseppe Guerra ([@xnyo](https://github.com/xnyo))
35
- - Jack Westbrook ([@jackw](https://github.com/jackw))
36
-
37
- ---
38
-
39
- # v0.5.1 (Mon Nov 14 2022)
40
-
41
- #### 🐛 Bug Fix
42
-
43
- - Fix: include uppercase characters when normalising plugin id [#142](https://github.com/grafana/plugin-tools/pull/142) ([@jackw](https://github.com/jackw))
44
-
45
- #### Authors: 1
46
-
47
- - Jack Westbrook ([@jackw](https://github.com/jackw))
48
-
49
- ---
50
-
51
1
  # v0.5.0 (Mon Nov 07 2022)
52
2
 
53
3
  :tada: This release contains work from a new contributor! :tada:
@@ -31,6 +31,7 @@ var constants_1 = require("../constants");
31
31
  function default_1(plop) {
32
32
  plop.setHelper('if_eq', utils_handlebars_1.ifEq);
33
33
  plop.setHelper('normalize_id', utils_handlebars_1.normalizeId);
34
+ plop.setActionType('printSuccessMessage', printSuccessMessage);
34
35
  plop.setGenerator('create-plugin', {
35
36
  description: 'used to scaffold a grafana plugin',
36
37
  prompts: [
@@ -111,7 +112,11 @@ function default_1(plop) {
111
112
  ? getActionsForTemplateFolder({ folderPath: constants_1.TEMPLATE_PATHS.isCompatibleWorkflow, exportPath: exportPath })
112
113
  : [];
113
114
  var readmeActions = getActionsForReadme({ exportPath: exportPath });
114
- return __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], commonActions, true), pluginTypeSpecificActions, true), backendActions, true), ciWorkflowActions, true), readmeActions, true), isCompatibleWorkflowActions, true);
115
+ return __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], commonActions, true), pluginTypeSpecificActions, true), backendActions, true), ciWorkflowActions, true), readmeActions, true), isCompatibleWorkflowActions, true), [
116
+ {
117
+ type: 'printSuccessMessage'
118
+ },
119
+ ], false);
115
120
  }
116
121
  });
117
122
  }
@@ -121,6 +126,7 @@ function getActionsForReadme(_a) {
121
126
  return [
122
127
  replacePatternWithTemplateInReadme('-- INSERT FRONTEND GETTING STARTED --', 'frontend-getting-started.md', exportPath),
123
128
  replacePatternWithTemplateInReadme('-- INSERT BACKEND GETTING STARTED --', 'backend-getting-started.md', exportPath),
129
+ replacePatternWithTemplateInReadme('-- INSERT DISTRIBUTING YOUR PLUGIN --', 'distributing-your-plugin.md', exportPath),
124
130
  ];
125
131
  }
126
132
  function replacePatternWithTemplateInReadme(pattern, partialsFile, exportPath) {
@@ -170,3 +176,14 @@ function getExportPath(pluginName, orgName, pluginType) {
170
176
  return path_1["default"].join(process.cwd(), (0, utils_handlebars_1.normalizeId)(pluginName, orgName, pluginType));
171
177
  }
172
178
  }
179
+ function printSuccessMessage(answers) {
180
+ var directory = (0, utils_handlebars_1.normalizeId)(answers.pluginName, answers.orgName, answers.pluginType);
181
+ var commands = __spreadArray(__spreadArray([
182
+ ' * `yarn install` to install frontend dependencies.',
183
+ ' * `docker-compose up` to start a grafana development server.',
184
+ ' * `yarn dev` to build (and watch) the plugin frontend code.'
185
+ ], (answers.hasBackend ? [' * `mage -v build:linux` to build the plugin backend code.'] : []), true), [
186
+ ' * Open http://localhost:3000/dashboard/new in your browser to create a dashboard to begin developing your plugin.',
187
+ ], false);
188
+ return "\n Congratulations on scaffolding a Grafana ".concat(answers.pluginName, " plugin! \uD83D\uDE80\n\n ## What's next?\n Navigate into ./").concat(directory, " and run the following commands to get started:\n").concat(commands.map(function (command) { return command; }).join('\n'), "\n\n View the README.md for futher information.\n Learn more about Grafana Plugins at https://grafana.com/docs/grafana/latest/plugins/developing/development/\n\n");
189
+ }
@@ -22,11 +22,5 @@ describe('Handlebars helpers', function () {
22
22
  var actual = (0, utils_handlebars_1.normalizeId)(pluginName, orgName, type);
23
23
  expect(actual).toEqual("myorg-myplugin-".concat(type));
24
24
  });
25
- test.each([constants_1.PLUGIN_TYPES.app, constants_1.PLUGIN_TYPES.datasource, constants_1.PLUGIN_TYPES.panel])('should handle uppercase characters', function (type) {
26
- var pluginName = "MyPlugin";
27
- var orgName = 'MyOrg';
28
- var actual = (0, utils_handlebars_1.normalizeId)(pluginName, orgName, type);
29
- expect(actual).toEqual("myorg-myplugin-".concat(type));
30
- });
31
25
  });
32
26
  });
@@ -39,7 +39,7 @@ var ifEq = function (a, b, options) {
39
39
  exports.ifEq = ifEq;
40
40
  var normalizeId = function (pluginName, orgName, type) {
41
41
  var re = new RegExp("-?".concat(type, "$"), 'i');
42
- var nameRegex = new RegExp('[^0-9a-zA-Z]', 'g');
42
+ var nameRegex = new RegExp('[^0-9a-z]', 'g');
43
43
  var newPluginName = pluginName.replace(re, '').replace(nameRegex, '');
44
44
  var newOrgName = orgName.replace(nameRegex, '');
45
45
  return changeCase.lowerCase(newOrgName) + '-' + changeCase.lowerCase(newPluginName) + "-".concat(type);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/create-plugin",
3
- "version": "0.5.4",
3
+ "version": "0.6.0-canary.160.e62f4fc.0",
4
4
  "main": "index.js",
5
5
  "repository": {
6
6
  "directory": "packages/create-plugin",
@@ -59,5 +59,5 @@
59
59
  "engines": {
60
60
  "node": ">=16"
61
61
  },
62
- "gitHead": "c1aa7f5feb47e958cc2b683f654ab28803b1eeb5"
62
+ "gitHead": "e62f4fc1fe115ff39cb9cd7f224515c8660cd797"
63
63
  }
@@ -27,6 +27,8 @@ export default function (plop: NodePlopAPI) {
27
27
  plop.setHelper('if_eq', ifEq);
28
28
  plop.setHelper('normalize_id', normalizeId);
29
29
 
30
+ plop.setActionType('printSuccessMessage', printSuccessMessage);
31
+
30
32
  plop.setGenerator('create-plugin', {
31
33
  description: 'used to scaffold a grafana plugin',
32
34
  prompts: [
@@ -131,6 +133,9 @@ export default function (plop: NodePlopAPI) {
131
133
  ...ciWorkflowActions,
132
134
  ...readmeActions,
133
135
  ...isCompatibleWorkflowActions,
136
+ {
137
+ type: 'printSuccessMessage',
138
+ },
134
139
  ];
135
140
  },
136
141
  });
@@ -148,6 +153,11 @@ function getActionsForReadme({ exportPath }: { exportPath: string }): ModifyActi
148
153
  'backend-getting-started.md',
149
154
  exportPath
150
155
  ),
156
+ replacePatternWithTemplateInReadme(
157
+ '-- INSERT DISTRIBUTING YOUR PLUGIN --',
158
+ 'distributing-your-plugin.md',
159
+ exportPath
160
+ ),
151
161
  ];
152
162
  }
153
163
 
@@ -221,3 +231,27 @@ function getExportPath(pluginName: string, orgName: string, pluginType: PLUGIN_T
221
231
  return path.join(process.cwd(), normalizeId(pluginName, orgName, pluginType));
222
232
  }
223
233
  }
234
+
235
+ function printSuccessMessage(answers: CliArgs) {
236
+ const directory = normalizeId(answers.pluginName, answers.orgName, answers.pluginType);
237
+
238
+ const commands = [
239
+ ' * `yarn install` to install frontend dependencies.',
240
+ ' * `docker-compose up` to start a grafana development server.',
241
+ ' * `yarn dev` to build (and watch) the plugin frontend code.',
242
+ ...(answers.hasBackend ? [' * `mage -v build:linux` to build the plugin backend code.'] : []),
243
+ ' * Open http://localhost:3000/dashboard/new in your browser to create a dashboard to begin developing your plugin.',
244
+ ];
245
+
246
+ return `
247
+ Congratulations on scaffolding a Grafana ${answers.pluginName} plugin! 🚀
248
+
249
+ ## What's next?
250
+ Navigate into ./${directory} and run the following commands to get started:
251
+ ${commands.map((command) => command).join('\n')}
252
+
253
+ View the README.md for futher information.
254
+ Learn more about Grafana Plugins at https://grafana.com/docs/grafana/latest/plugins/developing/development/
255
+
256
+ `;
257
+ }
@@ -31,15 +31,5 @@ describe('Handlebars helpers', () => {
31
31
  expect(actual).toEqual(`myorg-myplugin-${type}`);
32
32
  }
33
33
  );
34
-
35
- test.each([PLUGIN_TYPES.app, PLUGIN_TYPES.datasource, PLUGIN_TYPES.panel])(
36
- 'should handle uppercase characters',
37
- (type: PLUGIN_TYPES) => {
38
- const pluginName = `MyPlugin`;
39
- const orgName = 'MyOrg';
40
- const actual = normalizeId(pluginName, orgName, type);
41
- expect(actual).toEqual(`myorg-myplugin-${type}`);
42
- }
43
- );
44
34
  });
45
35
  });
@@ -12,7 +12,7 @@ export const ifEq = (a: any, b: any, options: HelperOptions) => {
12
12
 
13
13
  export const normalizeId = (pluginName: string, orgName: string, type: PLUGIN_TYPES) => {
14
14
  const re = new RegExp(`-?${type}$`, 'i');
15
- const nameRegex = new RegExp('[^0-9a-zA-Z]', 'g');
15
+ const nameRegex = new RegExp('[^0-9a-z]', 'g');
16
16
 
17
17
  const newPluginName = pluginName.replace(re, '').replace(nameRegex, '');
18
18
  const newOrgName = orgName.replace(nameRegex, '');
@@ -0,0 +1,38 @@
1
+ # Distributing your plugin
2
+
3
+ When distributing a Grafana plugin either within the community or privately the plugin must be signed so the Grafana application can verify its authenticity. This can be done with the `@grafana/sign-plugin` package.
4
+
5
+ _Note: It's not necessary to sign a plugin during development. The docker development environment that is scaffolded with `@grafana/create-plugin` caters for running the plugin without a signature._
6
+
7
+ ## Initial steps
8
+
9
+ Before signing a plugin please read the Grafana [plugin publishing and signing criteria](https://grafana.com/docs/grafana/latest/developers/plugins/publishing-and-signing-criteria/) documentation carefully.
10
+
11
+ `@grafana/create-plugin` has added the necessary commands and workflows to make signing and distributing a plugin via the grafana plugins catalog as straightforward as possible.
12
+
13
+ Before signing a plugin for the first time please consult the Grafana [plugin signature levels](https://grafana.com/docs/grafana/latest/developers/plugins/sign-a-plugin/#plugin-signature-levels) documentation to understand the differences between the types of signature level.
14
+
15
+ 1. Create a [Grafana Cloud account](https://grafana.com/signup).
16
+ 2. Make sure that the first part of the plugin ID matches the slug of your Grafana Cloud account.
17
+ - _You can find the plugin ID in the plugin.json file inside your plugin directory. For example, if your account slug is `acmecorp`, you need to prefix the plugin ID with `acmecorp-`._
18
+ 3. Create a Grafana Cloud API key with the `PluginPublisher` role.
19
+ 4. Keep a record of this API key as it will be required for signing a plugin
20
+
21
+ ## Signing a plugin
22
+
23
+ ### Using Github actions release workflow
24
+
25
+ If the plugin is using the github actions supplied with `@grafana/create-plugin` signing a plugin is included out of the box. The [release workflow](./.github/workflows/release.yml) can prepare everything to make submitting your plugin to Grafana as easy as possible. Before being able to sign the plugin however a secret needs adding to the Github repository.
26
+
27
+ 1. Please navigate to "settings > secrets > actions" within your repo to create secrets.
28
+ 2. Click "New repository secret"
29
+ 3. Name the secret "GRAFANA_API_KEY"
30
+ 4. Paste your Grafana Cloud API key in the Secret field
31
+ 5. Click "Add secret"
32
+
33
+ #### Push a version tag
34
+
35
+ To trigger the workflow we need to push a version tag to github. This can be achieved with the following steps:
36
+
37
+ 1. Run `npm version <major|minor|patch>`
38
+ 2. Run `git push origin main --follow-tags`
@@ -11,6 +11,8 @@ App plugins can let you create a custom out-of-the-box monitoring experience by
11
11
  -- INSERT FRONTEND GETTING STARTED --
12
12
  {{#if hasBackend}}-- INSERT BACKEND GETTING STARTED --{{/if}}
13
13
 
14
+ -- INSERT DISTRIBUTING YOUR PLUGIN --
15
+
14
16
  ## Learn more
15
17
 
16
18
  Below you can find source code for existing app plugins and other related documentation.
@@ -44,9 +44,7 @@ func (d *Datasource) Dispose() {
44
44
  // The QueryDataResponse contains a map of RefID to the response for each query, and each response
45
45
  // contains Frames ([]*Frame).
46
46
  func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
47
- // when logging at a non-Debug level, make sure you don't include sensitive information in the message
48
- // (like the *backend.QueryDataRequest)
49
- log.DefaultLogger.Debug("QueryData called", "numQueries", len(req.Queries))
47
+ log.DefaultLogger.Info("QueryData called", "request", req)
50
48
 
51
49
  // create response struct
52
50
  response := backend.NewQueryDataResponse()
@@ -96,9 +94,7 @@ func (d *Datasource) query(_ context.Context, pCtx backend.PluginContext, query
96
94
  // datasource configuration page which allows users to verify that
97
95
  // a datasource is working as expected.
98
96
  func (d *Datasource) CheckHealth(_ context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
99
- // when logging at a non-Debug level, make sure you don't include sensitive information in the message
100
- // (like the *backend.QueryDataRequest)
101
- log.DefaultLogger.Debug("CheckHealth called")
97
+ log.DefaultLogger.Info("CheckHealth called", "request", req)
102
98
 
103
99
  var status = backend.HealthStatusOk
104
100
  var message = "Data source is working"
@@ -16,12 +16,11 @@ to issues around working with the project.
16
16
  Edit the `.eslintrc` file in the project root in order to extend the ESLint configuration.
17
17
 
18
18
  **Example:**
19
-
20
19
  ```json
21
20
  {
22
21
  "extends": "./.config/.eslintrc",
23
22
  "rules": {
24
- "react/prop-types": "off"
23
+ "react/prop-types": "off"
25
24
  }
26
25
  }
27
26
  ```
@@ -33,11 +32,10 @@ Edit the `.eslintrc` file in the project root in order to extend the ESLint conf
33
32
  Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration.
34
33
 
35
34
  **Example:**
36
-
37
35
  ```javascript
38
36
  module.exports = {
39
37
  // Prettier configuration provided by Grafana scaffolding
40
- ...require('./.config/.prettierrc.js'),
38
+ ...require("./.config/.prettierrc.js"),
41
39
 
42
40
  semi: false,
43
41
  };
@@ -52,23 +50,7 @@ There are two configuration in the project root that belong to Jest: `jest-setup
52
50
  **`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to
53
51
  set up the Jest DOM for the testing library and to apply some polyfills. ([link to Jest docs](https://jestjs.io/docs/configuration#setupfilesafterenv-array))
54
52
 
55
- **`jest.config.js`:** The main Jest configuration file that extends the Grafana recommended setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
56
-
57
- #### ESM errors with Jest
58
-
59
- A common issue found with the current jest config involves importing an npm package which only offers an ESM build. These packages cause jest to error with `SyntaxError: Cannot use import statement outside a module`. To work around this we provide a list of known packages to pass to the `[transformIgnorePatterns](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)` jest configuration property. If need be this can be extended in the following way:
60
-
61
- ```javascript
62
- process.env.TZ = 'UTC';
63
- const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils');
64
-
65
- module.exports = {
66
- // Jest configuration provided by Grafana
67
- ...require('./.config/jest.config'),
68
- // Inform jest to only transform specific node_module packages.
69
- transformIgnorePatterns: [nodeModulesToTransform([...grafanaESModules, 'packageName'])],
70
- };
71
- ```
53
+ **`jest.config.js`:** The main Jest configuration file that is extending our basic Grafana-tailored setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
72
54
 
73
55
  ---
74
56
 
@@ -77,7 +59,6 @@ module.exports = {
77
59
  Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration.
78
60
 
79
61
  **Example:**
80
-
81
62
  ```json
82
63
  {
83
64
  "extends": "./.config/tsconfig.json",
@@ -99,7 +80,6 @@ Create a new config file that is going to extend the basic one provided by Grafa
99
80
  It can live in the project root, e.g. `webpack.config.ts`.
100
81
 
101
82
  #### 2. Merge the basic config provided by Grafana and your custom setup
102
-
103
83
  We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this.
104
84
 
105
85
  ```typescript
@@ -120,6 +100,7 @@ const config = async (env): Promise<Configuration> => {
120
100
  };
121
101
 
122
102
  export default config;
103
+
123
104
  ```
124
105
 
125
106
  #### 3. Update the `package.json` to use the new Webpack config
@@ -127,14 +108,12 @@ export default config;
127
108
  We need to update the `scripts` in the `package.json` to use the extended Webpack configuration.
128
109
 
129
110
  **Update for `build`:**
130
-
131
111
  ```diff
132
112
  -"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
133
113
  +"build": "webpack -c ./webpack.config.ts --env production",
134
114
  ```
135
115
 
136
116
  **Update for `dev`:**
137
-
138
117
  ```diff
139
118
  -"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
140
119
  +"dev": "webpack -w -c ./webpack.config.ts --env development",
@@ -5,12 +5,11 @@
5
5
  */
6
6
 
7
7
  const path = require('path');
8
- const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils');
9
8
 
10
9
  module.exports = {
11
10
  moduleNameMapper: {
12
- '\\.(css|scss|sass)$': 'identity-obj-proxy',
13
- 'react-inlinesvg': path.resolve(__dirname, 'jest', 'mocks', 'react-inlinesvg.tsx'),
11
+ "\\.(css|scss|sass)$": "identity-obj-proxy",
12
+ "react-inlinesvg": path.resolve(__dirname, "mocks", "react-inlinesvg.tsx"),
14
13
  },
15
14
  modulePaths: ['<rootDir>/src'],
16
15
  setupFilesAfterEnv: ['<rootDir>/jest-setup.js'],
@@ -36,7 +35,5 @@ module.exports = {
36
35
  },
37
36
  ],
38
37
  },
39
- // Jest will throw `Cannot use import statement outside module` if it tries to load an
40
- // ES module without it being transformed first. ./config/README.md#esm-errors-with-jest
41
- transformIgnorePatterns: [nodeModulesToTransform(grafanaESModules)],
38
+ transformIgnorePatterns: [],
42
39
  };
@@ -12,7 +12,8 @@
12
12
  "lint:fix": "yarn lint --fix",
13
13
  "e2e": "yarn cypress install && yarn grafana-e2e run",
14
14
  "e2e:update": "yarn cypress install && yarn grafana-e2e run --update-screenshots",
15
- "server": "docker-compose up --build"
15
+ "server": "docker-compose up --build",
16
+ "sign": "npx --yes @grafana/sign-plugin"
16
17
  },
17
18
  "author": "{{ sentenceCase orgName }}",
18
19
  "license": "Apache-2.0",
@@ -20,40 +21,40 @@
20
21
  "@babel/core": "^7.16.7",
21
22
  "@grafana/e2e": "{{ grafanaVersion }}",
22
23
  "@grafana/e2e-selectors": "{{ grafanaVersion }}",
23
- "@grafana/eslint-config": "^5.1.0",
24
+ "@grafana/eslint-config": "^2.5.0",
24
25
  "@grafana/tsconfig": "^1.2.0-rc1",
25
26
  "@swc/core": "^1.2.144",
26
- "@swc/helpers": "^0.4.12",
27
+ "@swc/helpers": "^0.3.6",
27
28
  "@swc/jest": "^0.2.20",
28
29
  "@testing-library/jest-dom": "^5.16.2",
29
- "@testing-library/react": "^13.4.0",
30
+ "@testing-library/react": "^12.1.3",
30
31
  "@types/glob": "^8.0.0",
31
- "@types/jest": "^29.2.2",
32
- "@types/lodash": "^4.14.188",{{#if_eq pluginType "app"}}
32
+ "@types/jest": "^27.4.1",
33
+ "@types/lodash": "latest",{{#if_eq pluginType "app"}}
33
34
  "@types/react-router-dom": "^5.3.3",{{/if_eq}}
34
- "@types/node": "^18.11.9",
35
- "@typescript-eslint/eslint-plugin": "^5.42.1",
36
- "@typescript-eslint/parser": "^5.42.1",
37
- "copy-webpack-plugin": "^11.0.0",
38
- "css-loader": "^6.7.1",
39
- "eslint": "8.26.0",
35
+ "@types/node": "^17.0.19",
36
+ "@typescript-eslint/eslint-plugin": "^4.33.0",
37
+ "@typescript-eslint/parser": "^4.33.0",
38
+ "copy-webpack-plugin": "^10.0.0",
39
+ "css-loader": "6.7.1",
40
+ "eslint": "^7.32.0",
40
41
  "eslint-config-prettier": "^8.3.0",
41
- "eslint-plugin-jsdoc": "^39.6.2",
42
+ "eslint-plugin-jsdoc": "^36.1.0",
42
43
  "eslint-plugin-prettier": "^4.0.0",
43
44
  "eslint-plugin-react": "^7.26.1",
44
45
  "eslint-plugin-react-hooks": "^4.2.0",
45
46
  "eslint-webpack-plugin": "^3.1.1",
46
- "fork-ts-checker-webpack-plugin": "^7.2.0",
47
47
  "glob": "^8.0.3",
48
48
  "identity-obj-proxy": "3.0.0",
49
49
  "jest": "27.5.0",
50
+ "fork-ts-checker-webpack-plugin": "^7.2.0",
50
51
  "prettier": "^2.5.0",
51
52
  "replace-in-file-webpack-plugin": "^1.0.6",
52
- "sass": "1.56.1",
53
- "sass-loader": "13.2.0",
53
+ "sass": "1.55.0",
54
+ "sass-loader": "13.1.0",
54
55
  "style-loader": "3.3.1",
55
- "swc-loader": "^0.2.3",
56
- "tsconfig-paths": "^4.1.0",
56
+ "swc-loader": "^0.1.15",
57
+ "tsconfig-paths": "^3.12.0",
57
58
  "ts-node": "^10.5.0",
58
59
  "typescript": "^4.4.0",
59
60
  "webpack": "^5.69.1",
@@ -11,6 +11,8 @@ Grafana supports a wide range of data sources, including Prometheus, MySQL, and
11
11
  -- INSERT FRONTEND GETTING STARTED --
12
12
  {{#if hasBackend}}-- INSERT BACKEND GETTING STARTED --{{/if}}
13
13
 
14
+ -- INSERT DISTRIBUTING YOUR PLUGIN --
15
+
14
16
  ## Learn more
15
17
 
16
18
  Below you can find source code for existing app plugins and other related documentation.
@@ -10,6 +10,7 @@ on:
10
10
  branches:
11
11
  - master
12
12
  - main
13
+
13
14
  jobs:
14
15
  build:
15
16
  runs-on: ubuntu-latest
@@ -19,34 +20,18 @@ jobs:
19
20
  - name: Setup Node.js environment
20
21
  uses: actions/setup-node@v3
21
22
  with:
22
- node-version: '16.x'
23
-
24
- - name: Get yarn cache directory path
25
- id: yarn-cache-dir-path
26
- run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
27
-
28
- - name: Cache yarn cache
29
- uses: actions/cache@v3
30
- id: cache-yarn-cache
31
- with:
32
- path: $\{{ steps.yarn-cache-dir-path.outputs.dir }}
33
- key: $\{{ runner.os }}-yarn-$\{{ hashFiles('**/yarn.lock') }}
34
- restore-keys: |
35
- $\{{ runner.os }}-yarn-
36
-
37
- - name: Cache node_modules
38
- id: cache-node-modules
39
- uses: actions/cache@v3
40
- with:
41
- path: node_modules
42
- key: $\{{ runner.os }}-$\{{ matrix.node-version }}-nodemodules-$\{{ hashFiles('**/yarn.lock') }}
43
- restore-keys: |
44
- $\{{ runner.os }}-$\{{ matrix.node-version }}-nodemodules-
45
-
23
+ node-version: '16'
24
+ cache: 'yarn'
46
25
  - name: Install dependencies
47
- run: yarn install --frozen-lockfile
26
+ run: yarn install --immutable --prefer-offline
48
27
 
49
- - name: Build and test frontend
28
+ - name: Check types
29
+ run: yarn typecheck
30
+ - name: Lint
31
+ run: yarn lint
32
+ - name: Unit tests
33
+ run: yarn test:ci
34
+ - name: Build frontend
50
35
  run: yarn build
51
36
 
52
37
  - name: Start grafana docker
@@ -55,7 +40,7 @@ jobs:
55
40
  - name: Run e2e tests
56
41
  run: yarn e2e
57
42
 
58
- - name: stop grafana docker
43
+ - name: Stop grafana docker
59
44
  run: docker-compose down
60
45
 
61
46
  - name: Check for backend
@@ -4,52 +4,29 @@ name: Release
4
4
  on:
5
5
  push:
6
6
  tags:
7
- - 'v*.*.*' # Run workflow on version tags, e.g. v1.0.0.
7
+ - 'v*' # Run workflow on version tags, e.g. v1.0.0.
8
8
 
9
9
  jobs:
10
10
  release:
11
11
  runs-on: ubuntu-latest
12
-
12
+ env:
13
+ GRAFANA_API_KEY: $\{{ secrets.GRAFANA_API_KEY }} # Requires a Grafana API key from Grafana.com.
13
14
  steps:
14
15
  - uses: actions/checkout@v3
15
16
 
16
17
  - name: Setup Node.js environment
17
18
  uses: actions/setup-node@v3
18
19
  with:
19
- node-version: '16.x'
20
+ node-version: '16'
21
+ cache: 'yarn'
20
22
 
21
23
  - name: Setup Go environment
22
24
  uses: actions/setup-go@v3
23
25
  with:
24
26
  go-version: '1.19'
25
27
 
26
- - name: Get yarn cache directory path
27
- id: yarn-cache-dir-path
28
- run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
29
-
30
- - name: Cache yarn cache
31
- uses: actions/cache@v3
32
- id: cache-yarn-cache
33
- with:
34
- path: $\{{ steps.yarn-cache-dir-path.outputs.dir }}
35
- key: $\{{ runner.os }}-yarn-$\{{ hashFiles('**/yarn.lock') }}
36
- restore-keys: |
37
- $\{{ runner.os }}-yarn-
38
-
39
- - name: Cache node_modules
40
- id: cache-node-modules
41
- uses: actions/cache@v3
42
- with:
43
- path: node_modules
44
- key: $\{{ runner.os }}-$\{{ matrix.node-version }}-nodemodules-$\{{ hashFiles('**/yarn.lock') }}
45
- restore-keys: |
46
- $\{{ runner.os }}-$\{{ matrix.node-version }}-nodemodules-
47
-
48
28
  - name: Install dependencies
49
- run: yarn install --frozen-lockfile;
50
- if: |
51
- steps.cache-yarn-cache.outputs.cache-hit != 'true' ||
52
- steps.cache-node-modules.outputs.cache-hit != 'true'
29
+ run: yarn install --immutable --prefer-offline
53
30
 
54
31
  - name: Build and test frontend
55
32
  run: yarn build
@@ -76,10 +53,15 @@ jobs:
76
53
  version: latest
77
54
  args: buildAll
78
55
 
56
+ - name: Warn missing Grafana API key
57
+ run: |
58
+ echo Please generate a Grafana API key: https://grafana.com/docs/grafana/latest/developers/plugins/sign-a-plugin/#generate-an-api-key
59
+ echo Once done please go to \"settings \> secrets \> actions\" to add it as GRAFANA_API_KEY
60
+ if: $\{{ env.GRAFANA_API_KEY == '' }}
61
+
79
62
  - name: Sign plugin
80
63
  run: yarn sign
81
- env:
82
- GRAFANA_API_KEY: $\{{ secrets.GRAFANA_API_KEY }} # Requires a Grafana API key from Grafana.com.
64
+ if: $\{{ env.GRAFANA_API_KEY != '' }}
83
65
 
84
66
  - name: Get plugin metadata
85
67
  id: metadata
@@ -117,49 +99,35 @@ jobs:
117
99
  md5sum $\{{ steps.metadata.outputs.archive }} > $\{{ steps.metadata.outputs.archive-checksum }}
118
100
  echo "checksum=$(cat ./$\{{ steps.metadata.outputs.archive-checksum }} | cut -d' ' -f1)" >> $GITHUB_OUTPUT
119
101
 
120
- - name: Lint plugin
102
+ - name: Validate plugin
121
103
  run: |
122
104
  git clone https://github.com/grafana/plugin-validator
123
105
  pushd ./plugin-validator/pkg/cmd/plugincheck2
124
106
  go install
125
107
  popd
126
- plugincheck2 -config ./plugin-validator/config/publishing.yaml $\{{ steps.metadata.outputs.archive }}
108
+ plugincheck2 -config ./plugin-validator/config/default.yaml $\{{ steps.metadata.outputs.archive }}
127
109
 
128
- - name: Create release
129
- id: create_release
130
- uses: actions/create-release@v1
131
- env:
132
- GITHUB_TOKEN: $\{{ secrets.GITHUB_TOKEN }}
110
+ - name: Create Github release
111
+ uses: softprops/action-gh-release@v1
133
112
  with:
134
- tag_name: $\{{ github.ref }}
135
- release_name: Release $\{{ github.ref }}
136
- body_path: $\{{ steps.changelog.outputs.path }}
137
113
  draft: true
138
-
139
- - name: Add plugin to release
140
- id: upload-plugin-asset
141
- uses: actions/upload-release-asset@v1
142
- env:
143
- GITHUB_TOKEN: $\{{ secrets.GITHUB_TOKEN }}
144
- with:
145
- upload_url: $\{{ steps.create_release.outputs.upload_url }}
146
- asset_path: ./$\{{ steps.metadata.outputs.archive }}
147
- asset_name: $\{{ steps.metadata.outputs.archive }}
148
- asset_content_type: application/zip
149
-
150
- - name: Add checksum to release
151
- id: upload-checksum-asset
152
- uses: actions/upload-release-asset@v1
153
- env:
154
- GITHUB_TOKEN: $\{{ secrets.GITHUB_TOKEN }}
155
- with:
156
- upload_url: $\{{ steps.create_release.outputs.upload_url }}
157
- asset_path: ./$\{{ steps.metadata.outputs.archive-checksum }}
158
- asset_name: $\{{ steps.metadata.outputs.archive-checksum }}
159
- asset_content_type: text/plain
160
-
161
- - name: Publish to Grafana.com
162
- run: |
163
- echo A draft release has been created for your plugin. Please review and publish it. Then submit your plugin to grafana.com/plugins by opening a PR to https://github.com/grafana/grafana-plugin-repository with the following entry:
164
- echo
165
- echo '{ "id": "$\{{ steps.metadata.outputs.plugin-id }}", "type": "$\{{ steps.metadata.outputs.plugin-type }}", "url": "https://github.com/$\{{ github.repository }}", "versions": [ { "version": "$\{{ steps.metadata.outputs.plugin-version }}", "commit": "$\{{ github.sha }}", "url": "https://github.com/$\{{ github.repository }}", "download": { "any": { "url": "https://github.com/$\{{ github.repository }}/releases/download/v$\{{ steps.metadata.outputs.plugin-version }}/$\{{ steps.metadata.outputs.archive }}", "md5": "$\{{ steps.package-plugin.outputs.checksum }}" } } } ] }' | jq .
114
+ generate_release_notes: true
115
+ files: |
116
+ ./$\{{ steps.metadata.outputs.archive }}
117
+ ./$\{{ steps.metadata.outputs.archive-checksum }}
118
+ body: |
119
+ **This Github draft release has been created for your plugin.**
120
+
121
+ _Note: if this is the first release for your plugin please consult the [distributing-your-plugin section](https://github.com/$\{{github.repository}}/blob/main/README.md#distributing-your-plugin) of the README_
122
+
123
+ If you would like to submit this release to Grafana please consider the following steps:
124
+
125
+ - Check the Validate plugin step in the [release workflow](https://github.com/$\{{github.repository}}/commit/$\{{github.sha}}/checks/$\{{github.run_id}}) for any warnings that need attention
126
+ - Navigate to https://grafana.com/auth/sign-in/ to sign into your account
127
+ - Once logged in click **My Plugins** in the admin navigation
128
+ - Click the **Submit Plugin** button
129
+ - Fill in the Plugin Submission form:
130
+ - Paste this [.zip asset link](https://github.com/$\{{ github.repository }}/releases/download/v$\{{ steps.metadata.outputs.plugin-version }}/$\{{ steps.metadata.outputs.archive }}) in the Plugin URL field
131
+ - Paste this [.zip.md5 link](https://github.com/$\{{ github.repository }}/releases/download/v$\{{ steps.metadata.outputs.plugin-version }}/$\{{ steps.metadata.outputs.archive-checksum }}) in the MD5 field
132
+
133
+ Once done please remove these instructions and publish this release.
@@ -1,5 +1,5 @@
1
1
  name: Latest Grafana API compatibility check
2
- on: [push, pull_request]
2
+ on: [pull_request]
3
3
 
4
4
  jobs:
5
5
  compatibilitycheck:
@@ -9,8 +9,9 @@ jobs:
9
9
  - uses: actions/setup-node@v3
10
10
  with:
11
11
  node-version: '16'
12
+ cache: 'yarn'
12
13
  - name: Install dependencies
13
- run: yarn install
14
+ run: yarn install --immutable --prefer-offline
14
15
  - name: Build plugin
15
16
  run: yarn build
16
17
  - name: Compatibility check
@@ -13,6 +13,8 @@ Use panel plugins when you want to do things like visualize data returned by dat
13
13
  -- INSERT FRONTEND GETTING STARTED --
14
14
  {{#if hasBackend}}-- INSERT BACKEND GETTING STARTED --{{/if}}
15
15
 
16
+ -- INSERT DISTRIBUTING YOUR PLUGIN --
17
+
16
18
  ## Learn more
17
19
 
18
20
  Below you can find source code for existing app plugins and other related documentation.
@@ -1,19 +0,0 @@
1
- /*
2
- * ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
3
- *
4
- * In order to extend the configuration follow the steps in .config/README.md
5
- */
6
-
7
- /*
8
- * This utility function is useful in combination with jest `transformIgnorePatterns` config
9
- * to transform specific packages (e.g.ES modules) in a projects node_modules folder.
10
- */
11
- const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!(${moduleNames.join('|')})\/)`;
12
-
13
- // Array of known nested grafana package dependencies that only bundle an ESM version
14
- const grafanaESModules = ['ol', 'react-colorful'];
15
-
16
- module.exports = {
17
- nodeModulesToTransform,
18
- grafanaESModules
19
- }