Skip to content

Chore: Update workflows and create-plugin update #126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .config/.cprc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "4.11.4"
"version": "5.22.4"
}
8 changes: 7 additions & 1 deletion .config/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-eslint-config
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-eslint-config
*/
{
"extends": ["@grafana/eslint-config"],
Expand All @@ -20,6 +20,12 @@
"parserOptions": {
"project": "./tsconfig.json"
}
},
{
"files": ["./tests/**/*"],
"rules": {
"react-hooks/rules-of-hooks": "off",
},
}
]
}
18 changes: 10 additions & 8 deletions .config/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ ARG grafana_image=grafana-enterprise

FROM grafana/${grafana_image}:${grafana_version}

ARG anonymous_auth_enabled=true
ARG development=false
ARG TARGETARCH

ARG GO_VERSION=1.21.6
ARG GO_ARCH=amd64
ARG GO_ARCH=${TARGETARCH:-amd64}

ENV DEV "${development}"

# Make it as simple as possible to access the grafana instance for development purposes
# Do NOT enable these settings in a public facing / production grafana instance
ENV GF_AUTH_ANONYMOUS_ORG_ROLE "Admin"
ENV GF_AUTH_ANONYMOUS_ENABLED "true"
ENV GF_AUTH_ANONYMOUS_ENABLED "${anonymous_auth_enabled}"
ENV GF_AUTH_BASIC_ENABLED "false"
# Set development mode so plugins can be loaded without the need to sign
ENV GF_DEFAULT_APP_MODE "development"
Expand All @@ -29,14 +31,14 @@ USER root
# Installing supervisor and inotify-tools
RUN if [ "${development}" = "true" ]; then \
if grep -i -q alpine /etc/issue; then \
apk add supervisor inotify-tools git; \
apk add supervisor inotify-tools git; \
elif grep -i -q ubuntu /etc/issue; then \
DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y supervisor inotify-tools git && \
rm -rf /var/lib/apt/lists/*; \
DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y supervisor inotify-tools git && \
rm -rf /var/lib/apt/lists/*; \
else \
echo 'ERROR: Unsupported base image' && /bin/false; \
echo 'ERROR: Unsupported base image' && /bin/false; \
fi \
fi

Expand Down
11 changes: 6 additions & 5 deletions .config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge
// webpack.config.ts
import type { Configuration } from 'webpack';
import { merge } from 'webpack-merge';
import grafanaConfig from './.config/webpack/webpack.config';
import grafanaConfig, { type Env } from './.config/webpack/webpack.config';

const config = async (env): Promise<Configuration> => {
const config = async (env: Env): Promise<Configuration> => {
const baseConfig = await grafanaConfig(env);

return merge(baseConfig, {
Expand Down Expand Up @@ -151,14 +151,15 @@ version: '3.7'

services:
grafana:
container_name: 'myorg-basic-app'
extends:
file: .config/docker-compose-base.yaml
service: grafana
build:
context: ./.config
args:
grafana_version: ${GRAFANA_VERSION:-9.1.2}
grafana_image: ${GRAFANA_IMAGE:-grafana}
```

In this example, we assign the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will allow you to set the value while running the docker-compose commands, which might be convenient in some scenarios.
In this example, we assign the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will allow you to set the value while running the docker compose commands, which might be convenient in some scenarios.

---
31 changes: 31 additions & 0 deletions .config/docker-compose-base.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
services:
grafana:
user: root
container_name: 'grafana-mqtt-datasource'

build:
context: .
args:
grafana_image: ${GRAFANA_IMAGE:-grafana-enterprise}
grafana_version: ${GRAFANA_VERSION:-12.0.1}
development: ${DEVELOPMENT:-false}
anonymous_auth_enabled: ${ANONYMOUS_AUTH_ENABLED:-true}
ports:
- 3000:3000/tcp
- 2345:2345/tcp # delve
security_opt:
- 'apparmor:unconfined'
- 'seccomp:unconfined'
cap_add:
- SYS_PTRACE
volumes:
- ../dist:/var/lib/grafana/plugins/grafana-mqtt-datasource
- ../provisioning:/etc/grafana/provisioning
- ..:/root/grafana-mqtt-datasource

environment:
NODE_ENV: development
GF_LOG_FILTERS: plugin.grafana-mqtt-datasource:debug
GF_LOG_LEVEL: debug
GF_DATAPROXY_LOGGING: 1
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-mqtt-datasource
8 changes: 4 additions & 4 deletions .config/jest-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-jest-config
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-jest-config
*/

import '@testing-library/jest-dom';
import { TextEncoder, TextDecoder } from 'util';

Object.assign(global, { TextDecoder, TextEncoder });

// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
Object.defineProperty(global, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
value: (query) => ({
matches: false,
media: query,
onchange: null,
Expand All @@ -22,7 +22,7 @@ Object.defineProperty(global, 'matchMedia', {
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
}),
});

HTMLCanvasElement.prototype.getContext = () => {};
2 changes: 1 addition & 1 deletion .config/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-jest-config
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-jest-config
*/

const path = require('path');
Expand Down
2 changes: 1 addition & 1 deletion .config/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in
* https://grafana.com/developers/plugin-tools/create-a-plugin/extend-a-plugin/extend-configurations#extend-the-typescript-config
* https://grafana.com/developers/plugin-tools/get-started/set-up-development-environment#extend-the-typescript-config
*/
{
"compilerOptions": {
Expand Down
37 changes: 37 additions & 0 deletions .config/types/bundler-rules.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Image declarations
declare module '*.gif' {
const src: string;
export default src;
}

declare module '*.jpg' {
const src: string;
export default src;
}

declare module '*.jpeg' {
const src: string;
export default src;
}

declare module '*.png' {
const src: string;
export default src;
}

declare module '*.webp' {
const src: string;
export default src;
}

declare module '*.svg' {
const src: string;
export default src;
}

// Font declarations
declare module '*.woff';
declare module '*.woff2';
declare module '*.eot';
declare module '*.ttf';
declare module '*.otf';
83 changes: 83 additions & 0 deletions .config/types/webpack-plugins.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
declare module 'replace-in-file-webpack-plugin' {
import { Compiler, Plugin } from 'webpack';

interface ReplaceRule {
search: string | RegExp;
replace: string | ((match: string) => string);
}

interface ReplaceOption {
dir?: string;
files?: string[];
test?: RegExp | RegExp[];
rules: ReplaceRule[];
}

class ReplaceInFilePlugin extends Plugin {
constructor(options?: ReplaceOption[]);
options: ReplaceOption[];
apply(compiler: Compiler): void;
}

export = ReplaceInFilePlugin;
}

declare module 'webpack-livereload-plugin' {
import { ServerOptions } from 'https';
import { Compiler, Plugin, Stats, Compilation } from 'webpack';

interface Options extends Pick<ServerOptions, 'cert' | 'key' | 'pfx'> {
/**
* protocol for livereload `<script>` src attribute value
* @default protocol of the page, either `http` or `https`
*/
protocol?: string | undefined;
/**
* The desired port for the livereload server.
* If you define port 0, an available port will be searched for, starting from 35729.
* @default 35729
*/
port?: number | undefined;
/**
* he desired hostname for the appended `<script>` (if present) to point to
* @default hostname of the page, like `localhost` or 10.0.2.2
*/
hostname?: string | undefined;
/**
* livereload `<script>` automatically to `<head>`.
* @default false
*/
appendScriptTag?: boolean | undefined;
/**
* RegExp of files to ignore. Null value means ignore nothing.
* It is also possible to define an array and use multiple anymatch patterns
*/
ignore?: RegExp | RegExp[] | null | undefined;
/**
* amount of milliseconds by which to delay the live reload (in case build takes longer)
* @default 0
*/
delay?: number | undefined;
/**
* create hash for each file source and only notify livereload if hash has changed
* @default false
*/
useSourceHash?: boolean | undefined;
}

class LiveReloadPlugin extends Plugin {
readonly isRunning: boolean;
constructor(options?: Options);

apply(compiler: Compiler): void;

start(watching: any, cb: () => void): void;
done(stats: Stats): void;
failed(): void;
autoloadJs(): string;
scriptTag(source: string): string;
applyCompilation(compilation: Compilation): void;
}

export = LiveReloadPlugin;
}
33 changes: 33 additions & 0 deletions .config/webpack/BuildModeWebpackPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import webpack, { type Compiler } from 'webpack';

const PLUGIN_NAME = 'BuildModeWebpack';

export class BuildModeWebpackPlugin {
apply(compiler: webpack.Compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
compilation.hooks.processAssets.tap(
{
name: PLUGIN_NAME,
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
},
async () => {
const assets = compilation.getAssets();
for (const asset of assets) {
if (asset.name.endsWith('plugin.json')) {
const pluginJsonString = asset.source.source().toString();
const pluginJsonWithBuildMode = JSON.stringify(
{
...JSON.parse(pluginJsonString),
buildMode: compilation.options.mode,
},
null,
4
);
compilation.updateAsset(asset.name, new webpack.sources.RawSource(pluginJsonWithBuildMode));
}
}
}
);
});
}
}
26 changes: 18 additions & 8 deletions .config/webpack/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import process from 'process';
import os from 'os';
import path from 'path';
import { glob } from 'glob';
import { SOURCE_DIR } from './constants';
import { SOURCE_DIR } from './constants.ts';

export function isWSL() {
if (process.platform !== 'linux') {
Expand All @@ -21,12 +21,22 @@ export function isWSL() {
}
}

function loadJson(path: string) {
const rawJson = fs.readFileSync(path, 'utf8');
return JSON.parse(rawJson);
}

export function getPackageJson() {
return require(path.resolve(process.cwd(), 'package.json'));
return loadJson(path.resolve(process.cwd(), 'package.json'));
}

export function getPluginJson() {
return require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
return loadJson(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
}

export function getCPConfigVersion() {
const cprcJson = path.resolve(process.cwd(), './.config', '.cprc.json');
return fs.existsSync(cprcJson) ? loadJson(cprcJson).version : { version: 'unknown' };
}

export function hasReadme() {
Expand All @@ -35,7 +45,7 @@ export function hasReadme() {

// Support bundling nested plugins by finding all plugin.json files in src directory
// then checking for a sibling module.[jt]sx? file.
export async function getEntries(): Promise<Record<string, string>> {
export async function getEntries() {
const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true });

const plugins = await Promise.all(
Expand All @@ -45,14 +55,14 @@ export async function getEntries(): Promise<Record<string, string>> {
})
);

return plugins.reduce((result, modules) => {
return modules.reduce((result, module) => {
return plugins.reduce<Record<string, string>>((result, modules) => {
return modules.reduce((innerResult, module) => {
const pluginPath = path.dirname(module);
const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, '');
const entryName = pluginName === '' ? 'module' : `${pluginName}/module`;

result[entryName] = module;
return result;
innerResult[entryName] = module;
return innerResult;
}, result);
}, {});
}
Loading