Commit 03e3ddcb by Ryan McKinley Committed by GitHub

Plugins: add a bundle plugins folder (#20850)

parent 553f50e4
......@@ -282,7 +282,8 @@
},
"workspaces": {
"packages": [
"packages/*"
"packages/*",
"plugins-bundled/internal/*"
],
"nohoist": [
"**/@types/*",
......
......@@ -67,6 +67,7 @@
"execa": "^1.0.0",
"expect-puppeteer": "4.1.1",
"file-loader": "^4.0.0",
"fork-ts-checker-webpack-plugin": "1.0.0",
"fs-extra": "^8.1.0",
"globby": "^10.0.1",
"html-loader": "0.5.5",
......
......@@ -18,6 +18,7 @@ import { githubPublishTask } from './tasks/plugin.utils';
import { ciBuildPluginTask, ciBuildPluginDocsTask, ciPackagePluginTask, ciPluginReportTask } from './tasks/plugin.ci';
import { buildPackageTask } from './tasks/package.build';
import { pluginCreateTask } from './tasks/plugin.create';
import { bundleManagedTask } from './tasks/plugin/bundle.managed';
export const run = (includeInternalScripts = false) => {
if (includeInternalScripts) {
......@@ -196,6 +197,13 @@ export const run = (includeInternalScripts = false) => {
});
program
.command('plugin:bundle-managed')
.description('Builds managed plugins')
.action(async cmd => {
await execTask(bundleManagedTask)({});
});
program
.command('plugin:github-publish')
.option('--dryrun', 'Do a dry run only', false)
.option('--verbose', 'Print verbose', false)
......
......@@ -13,6 +13,7 @@ describe('Manifest', () => {
"manifest.ts",
"nodeVersionChecker.ts",
"package.build.ts",
"plugin/bundle.managed.ts",
"plugin/bundle.ts",
"plugin/create.ts",
"plugin/tests.ts",
......
import { Task, TaskRunner } from '../task';
import { restoreCwd } from '../../utils/cwd';
import execa = require('execa');
const fs = require('fs');
const util = require('util');
const readdirPromise = util.promisify(fs.readdir);
interface BundeManagedOptions {}
const MANAGED_PLUGINS_PATH = `${process.cwd()}/plugins-bundled`;
const MANAGED_PLUGINS_SCOPES = ['internal', 'external'];
const bundleManagedPluginsRunner: TaskRunner<BundeManagedOptions> = async () => {
await Promise.all(
MANAGED_PLUGINS_SCOPES.map(async scope => {
try {
const plugins = await readdirPromise(`${MANAGED_PLUGINS_PATH}/${scope}`);
if (plugins.length > 0) {
for (const plugin of plugins) {
process.chdir(`${MANAGED_PLUGINS_PATH}/${scope}/${plugin}`);
try {
await execa('yarn', ['dev']);
console.log(`[${scope}]: ${plugin} bundled`);
} catch (e) {
console.log(e.stdout);
}
}
}
} catch (e) {
console.log(e);
}
})
);
restoreCwd();
};
export const bundleManagedTask = new Task<BundeManagedOptions>('Bundle managed plugins', bundleManagedPluginsRunner);
......@@ -7,6 +7,7 @@ const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const readdirPromise = util.promisify(fs.readdir);
const accessPromise = util.promisify(fs.access);
......@@ -123,6 +124,11 @@ const getCommonPlugins = (options: WebpackConfigurationOptions) => {
],
},
]),
new ForkTsCheckerWebpackPlugin({
tsconfig: path.join(process.cwd(), 'tsconfig.json'),
// Only report problems in detected in plugin's code
reportFiles: ['**/*.{ts,tsx}'],
}),
];
};
......@@ -205,7 +211,10 @@ const getBaseWebpackConfig: WebpackConfigurationGetter = async options => {
},
{
loader: 'ts-loader',
options: { onlyCompileBundledFiles: true },
options: {
onlyCompileBundledFiles: true,
transpileOnly: true,
},
},
],
exclude: /(node_modules)/,
......
......@@ -78,6 +78,14 @@ func (pm *PluginManager) Init() error {
return errutil.Wrapf(err, "Failed to scan main plugin directory '%s'", plugDir)
}
pm.log.Info("Checking Bundled Plugins")
plugDir = path.Join(setting.HomePath, "plugins-bundled")
if _, err := os.Stat(plugDir); !os.IsNotExist(err) {
if err := pm.scan(plugDir); err != nil {
return errutil.Wrapf(err, "failed to scan bundled plugin directory '%s'", plugDir)
}
}
// check if plugins dir exists
if _, err := os.Stat(setting.PluginsPath); os.IsNotExist(err) {
if err = os.MkdirAll(setting.PluginsPath, os.ModePerm); err != nil {
......
# packaged by toolkit
dist
coverage
# Ignore external git configs
external
Bundled Plugins
===============
Bundled plugins are built as true plugins, and managed by the grafana install.
TODO: the packaging system should move all `dist` items to the root and remove sources.
{
"name": "@grafana-plugins/input-datasource",
"version": "6.6.0-pre",
"description": "Input Datasource",
"repository": {
"type": "git",
"url": "http://github.com/grafana/grafana.git"
},
"scripts": {
"build": "grafana-toolkit plugin:build",
"test": "grafana-toolkit plugin:test",
"dev": "grafana-toolkit plugin:dev",
"watch": "grafana-toolkit plugin:dev --watch"
},
"author": "Grafana Labs",
"license": "Apache-2.0",
"devDependencies": {
"@grafana/data": "^6.6.0-pre",
"@grafana/ui": "^6.6.0-pre",
"@grafana/toolkit": "^6.6.0-pre"
}
}
......@@ -9,7 +9,7 @@ import {
readCSV,
} from '@grafana/data';
import { getQueryOptions } from 'test/helpers/getQueryOptions';
import { getQueryOptions } from './testHelpers';
describe('InputDatasource', () => {
const data = readCSV('a,b,c\n1,2,3\n4,5,6');
......
......@@ -99,7 +99,7 @@ function getLength(data?: DataFrameDTO | DataFrame) {
if (data.hasOwnProperty('length')) {
return (data as DataFrame).length;
}
return data.fields[0].values.length;
return data.fields[0].values!.length;
}
export function describeDataFrame(data: Array<DataFrameDTO | DataFrame>): string {
......
......@@ -5,9 +5,6 @@
"state": "alpha",
"metrics": true,
"alerting": false,
"annotations": false,
"logs": false,
"info": {
"description": "Data source that supports manual table & CSV input",
......
import { DataQueryRequest, DataQuery, CoreApp } from '@grafana/data';
import { dateTime } from '@grafana/data';
export function getQueryOptions<TQuery extends DataQuery>(
options: Partial<DataQueryRequest<TQuery>>
): DataQueryRequest<TQuery> {
const raw = { from: 'now', to: 'now-1h' };
const range = { from: dateTime(), to: dateTime(), raw: raw };
const defaults: DataQueryRequest<TQuery> = {
requestId: 'TEST',
app: CoreApp.Dashboard,
range: range,
targets: [],
scopedVars: {},
timezone: 'browser',
panelId: 1,
dashboardId: 1,
interval: '60s',
intervalMs: 60000,
maxDataPoints: 500,
startTime: 0,
};
Object.assign(defaults, options);
return defaults;
}
{
"extends": "../../../packages/grafana-toolkit/src/config/tsconfig.plugin.json",
"include": ["src", "types"],
"compilerOptions": {
"rootDir": "./src",
"baseUrl": "./src",
"typeRoots": ["./node_modules/@types"]
}
}
......@@ -27,8 +27,6 @@ const mssqlPlugin = async () =>
await import(/* webpackChunkName: "mssqlPlugin" */ 'app/plugins/datasource/mssql/module');
const testDataDSPlugin = async () =>
await import(/* webpackChunkName: "testDataDSPlugin" */ 'app/plugins/datasource/testdata/module');
const inputDatasourcePlugin = async () =>
await import(/* webpackChunkName: "inputDatasourcePlugin" */ 'app/plugins/datasource/input/module');
const stackdriverPlugin = async () =>
await import(/* webpackChunkName: "stackdriverPlugin" */ 'app/plugins/datasource/stackdriver/module');
const azureMonitorPlugin = async () =>
......@@ -73,7 +71,6 @@ const builtInPlugins: any = {
'app/plugins/datasource/mssql/module': mssqlPlugin,
'app/plugins/datasource/prometheus/module': prometheusPlugin,
'app/plugins/datasource/testdata/module': testDataDSPlugin,
'app/plugins/datasource/input/module': inputDatasourcePlugin,
'app/plugins/datasource/stackdriver/module': stackdriverPlugin,
'app/plugins/datasource/grafana-azure-monitor-datasource/module': azureMonitorPlugin,
......
// Use the real plugin_loader (stubbed by default)
jest.unmock('app/features/plugins/plugin_loader');
(global as any).ace = {
define: jest.fn(),
};
jest.mock('app/core/core', () => {
return {
coreModule: {
directive: jest.fn(),
},
};
});
import { SystemJS } from '@grafana/runtime';
import { AppPluginMeta, PluginMetaInfo, PluginType, AppPlugin } from '@grafana/data';
// Loaded after the `unmock` abve
import { importAppPlugin } from './plugin_loader';
class MyCustomApp extends AppPlugin {
initWasCalled = false;
calledTwice = false;
init(meta: AppPluginMeta) {
this.initWasCalled = true;
this.calledTwice = this.meta === meta;
}
}
describe('Load App', () => {
const app = new MyCustomApp();
const modulePath = 'my/custom/plugin/module';
beforeAll(() => {
SystemJS.set(modulePath, SystemJS.newModule({ plugin: app }));
});
afterAll(() => {
SystemJS.delete(modulePath);
});
it('should call init and set meta', async () => {
const meta: AppPluginMeta = {
id: 'test-app',
module: modulePath,
baseUrl: 'xxx',
info: {} as PluginMetaInfo,
type: PluginType.app,
name: 'test',
};
// Check that we mocked the import OK
const m = await SystemJS.import(modulePath);
expect(m.plugin).toBe(app);
const loaded = await importAppPlugin(meta);
expect(loaded).toBe(app);
expect(app.meta).toBe(meta);
expect(app.initWasCalled).toBeTruthy();
expect(app.calledTwice).toBeFalsy();
const again = await importAppPlugin(meta);
expect(again).toBe(app);
expect(app.calledTwice).toBeTruthy();
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment