Migrate the Grafana plugin build from grafana-toolkit to create-plugin - #118
Migrate the Grafana plugin build from grafana-toolkit to create-plugin#118PDGGK wants to merge 3 commits into
Conversation
@grafana/toolkit was archived by Grafana and no longer receives updates, so the plugin could not be built with a supported toolchain. This moves the frontend build to @grafana/create-plugin: webpack, SWC/Jest, the flat ESLint config, Playwright for e2e, and a package-lock.json replacing the yarn.lock. The generated .config directory is checked in as create-plugin intends and is not hand-edited; it can be refreshed with 'npx @grafana/create-plugin update'. The plugin's own CI workflow is updated in the same change, because it is what the migration breaks: it pinned Node 14, installed with 'yarn install --frozen-lockfile' and keyed both caches on yarn.lock, which this change removes. It now reads the Node version from the plugin's .nvmrc, caches on package-lock.json and runs 'npm ci && npm run build'. The Go backend step is untouched. grafanaDependency moves from >=9.3.0 to >=12.3.0. The plugin builds and is tested against the @grafana/data, @grafana/ui and @grafana/runtime 13.1.0 packages the new toolchain pulls in. Those are webpack externals resolved from the host Grafana at runtime, so an API present in the 13.1.0 types but absent on an older host fails at runtime rather than at build time, which is exactly why the declared floor should be the one we build and test against. The stricter ESLint config reports two errors in the tree-model query editors, where an array is mutated in place and the same reference is then handed to onChange. Both are changed to pass a new array instead. The same append, and two splice-based removals, remain a few lines away where the rule does not flag them; those are left for a separate change with tests rather than altering untested UI behaviour here. docker-compose.yaml also starts a standalone IoTDB alongside Grafana and ./provisioning wires the datasource to it, so 'npm run server' brings up a working plugin against a real server rather than an empty Grafana. Signed-off-by: Zihan Dai <99155080+PDGGK@users.noreply.github.com>
|
Thanks for taking this on — moving off the archived Three things below. The first is blocking; the second is a suggestion that would have caught the first automatically; the third needs a call from the PMC rather than from you or me. 1. Blocking:
|
The migration removed yarn.lock and moved the plugin to Node 22 and a webpack config loaded through ts-node, but connectors/grafana-plugin/pom.xml still drove frontend-maven-plugin with install-node-and-yarn, Node 16.13.1 and Yarn 1.22.17. That is a second consumer of the toolchain this change replaces, alongside the workflow already updated here, so mvn -Pwith-grafana-plugin package would have broken on master straight after the merge. The Maven executions now install Node from the same version the plugin declares and run npm ci and npm run build. ci rather than install so the lockfile stays authoritative and a drifted dependency set fails the build instead of resolving silently. Note that .npmrc sets ignore-scripts=true, which applies to the Maven-driven install as well. The reason this was not caught is that no CI job builds this module through Maven at all: grafana-plugin is not part of the with-all-connectors profile that compile-check.yml uses, and the Jenkinsfile's plain mvn clean install does not activate with-grafana-plugin either. The green build check is this workflow, which exercises the npm path directly, so it was verifying its own new path. A second job now runs the Maven entrypoint, which also covers the antrun execution bound to the package phase that invokes backend-compile.sh -- that one is not skipped by -DskipTests despite its execution id. Signed-off-by: Zihan Dai <99155080+PDGGK@users.noreply.github.com>
|
Thanks — item 1 is a real break and I had missed it in exactly the way you describe. Pushed as The pom. Verified locally: Item 2. Added as a second job in One thing worth recording from getting that job green: the antrun execution has Item 3. Agreed that both belong to the PMC rather than to this PR, and I will raise them on One observation I am deliberately not folding in, since it is pre-existing and this PR does not touch the file: |
Implements the three outcomes of the mailing-list thread, plus the licence coverage point raised in review. Agent-instruction files. @grafana/create-plugin emits a .config/AGENTS/ tree (four files, 316 lines). Removed, and gitignored so a regeneration cannot reintroduce them. Nothing in the build depends on them. RAT coverage. connectors/pom.xml excluded the whole grafana-plugin tree from apache-rat, so the one module in this repository carrying its own LICENSE was also the one nothing checked. The blanket exclusion is replaced by a list covering only generated output, binaries, and files that cannot carry a header: node/, node_modules/, dist/, coverage/, playwright-report/, test-results/, package-lock.json, CHANGELOG.md, LICENSE, .nvmrc, src/img/, an empty-directory marker, and the local lint cache. .config/ stays excluded because the scaffold regenerates it and marks it do-not-edit, so a header added there is lost on the next run. Eight hand-written files gained the standard header; RAT now passes with the tree in scope rather than exempt from it. Minimum-version smoke test. plugin.json declares a grafanaDependency floor, but the @grafana/* packages are webpack externals resolved from the host at runtime, so a plugin built against a newer Grafana compiles cleanly and then fails inside an older one. A declared floor is therefore only meaningful if something boots it. The new job parses the floor out of plugin.json -- failing loudly if it cannot -- boots that Grafana release alongside IoTDB, and checks two different failure modes: that the plugin frontend renders its own config fields, which is where an unresolved external surfaces, and that a table-model query returns data through the backend and the native client. Raising or lowering the declared floor changes what is tested, with no second place to keep in step. Documentation. The README claimed support for Grafana 9.3.0 and above; it now states the 12.3.0 floor, why the externals model makes an untested floor meaningless, and how CI holds it. CHANGELOG.md records the compatibility break. Note that its existing pointer to ../RELEASE_NOTES.md is a scaffold artifact -- no such file exists in this repository. Signed-off-by: Zihan Dai <99155080+PDGGK@users.noreply.github.com>
|
Implemented all three outcomes from the list thread, plus the licence point. Pushed as 1. Minimum version. The smoke test is I checked it fails for the right reasons rather than only that it passes: with Grafana stopped it fails; with IoTDB stopped only the query assertion fails while the two frontend ones stay green; with 2. AGENT files. Removed, and 3. LICENCE / RAT. The blanket One thing worth flagging rather than deciding on my own: On the Maven path. Confirmed: before this PR neither Grafana profile was invoked by any CI job or by the Jenkinsfile, so nothing was building this module through Maven. The new job runs One thing I found while checking, since it bears on whether to go further: the module is reachable from two opt-in profiles, One observation I am deliberately keeping out of this PR since it is pre-existing and untouched here: |
Why
@grafana/toolkitwas archived by Grafana and no longer receives updates, sonpm run buildwas pinned to an unmaintained toolchain. This migrates the plugin's frontend build to@grafana/create-plugin, which is the supported replacement.What changed
Build toolchain.
grafana-toolkit plugin:build/test/devare replaced by webpack, SWC/Jest, the flat ESLint config and Playwright, all driven from the generated.config/directory..config/is checked in ascreate-pluginintends, carries its own "do not edit" notice, and can be refreshed later withnpx @grafana/create-plugin update.Lockfile.
yarn.lockis removed in favour ofpackage-lock.json, matching the npm-based scripts the new toolchain generates.grafanaDependencymoves from>=9.3.0to>=12.3.0. This is the one compatibility decision in the change, so to be explicit about it: the plugin builds and is tested against@grafana/data,@grafana/uiand@grafana/runtime13.1.0. Those packages are webpack externals (.config/bundler/externals.ts), resolved from the host Grafana at runtime rather than bundled — so an API that exists in the 13.1.0 types but not on an older host does not fail the build, it fails at runtime in the user's Grafana with no bundled fallback. Declaring>=12.3.0, the floorcreate-plugindeclares for this SDK generation, states the range we can actually stand behind. If keeping a lower floor matters more, that is worth saying now — it would mean pinning the@grafana/*packages down instead.Two ESLint errors fixed. The stricter config flags
react-hooks/immutabilityin the tree-model query editors, where an array is mutated in place and the same reference is then passed toonChange— so a consumer comparing by reference sees no change. Both now pass a new array instead.To be plain about what this leaves behind:
FromValue.tsxandSelectValue.tsxstill contain the identical append (prefixPath[prefixPath.length] = ''; onChange(prefixPath)) a few lines below the corrected one, where the rule does not flag it, plus twosplice-based removals with the same shape. I left them because these components have no test coverage and a toolchain migration is the wrong place to change untested UI behaviour — but I am happy to fix the remaining sites in a separate change with tests.CI workflow updated in the same change.
.github/workflows/grafana-plugin.ymltriggers onconnectors/grafana-plugin/**, pinsnode-version: "14.x", installs withyarn install --frozen-lockfileand keys both caches onhashFiles('**/yarn.lock'). Since this change removesyarn.lock, that workflow would fail at install, and Node 14 cannot run the new toolchain in any case. It now takes the Node version from the plugin's.nvmrc— so it cannot drift away from the toolchain again — usessetup-node's npm cache keyed onpackage-lock.json, and runsnpm ci && npm run build. The Go/backend step is unchanged.Development environment.
docker-compose.yamlnow also starts a standalone IoTDB next to Grafana, andprovisioning/wires the datasource to it (REST on 18080 for the tree-model modes, native Thrift on 6667 for the table-model mode).npm run servertherefore brings up a Grafana with the plugin loaded and a server to query, instead of an empty instance.One known rough edge in the generated config:
.config/supervisord/supervisord.confwaits for a backend binary matchinggpx_iotdb*, derived from the plugin name, whileplugin.jsondeclaresexecutable: gpx_apache_iotdb_datasource. That only affectsDEVELOPMENT=true(the delve path); with the defaultDEVELOPMENT=falsethe entrypoint runs Grafana directly, which is the path verified below. I have not hand-edited it, since.config/is generated and regenerated bycreate-plugin update.Verification
Toolchain:
typecheck,lint(0 errors; 9 remaining warnings are pre-existing deprecation notices),test:ci(13 tests) andbuildall pass. The exact command chain the updated workflow runs —npm ci && npm run build— was run from a clean install to confirmpackage-lock.jsonandpackage.jsonare in sync, sincenpm cifails hard if they are not.End to end against real servers, not just a green build: the plugin was loaded into Grafana 13.1.0 from
docker compose up, with a realapache/iotdb:2.0.8behind it. Grafana registers the plugin (Plugin registered pluginId=apache-iotdb-datasource), the provisioned datasource connects, and a table-model queryrenders in a panel with the row-major result correctly pivoted into one series per tag value, and the same data shown in the table view.