|
|
@@ -7,89 +7,34 @@ import { getPluginJson } from '../../config/utils/pluginValidation';
|
|
|
import execa = require('execa');
|
|
|
import path = require('path');
|
|
|
import fs = require('fs');
|
|
|
+import { getPackageDetails } from '../utils/fileHelper';
|
|
|
+import {
|
|
|
+ job,
|
|
|
+ getJobFolder,
|
|
|
+ writeJobStats,
|
|
|
+ getCiFolder,
|
|
|
+ agregateWorkflowInfo,
|
|
|
+ agregateCoverageInfo,
|
|
|
+ getPluginSourceInfo,
|
|
|
+ TestResultInfo,
|
|
|
+ agregateTestInfo,
|
|
|
+} from './plugin/ci';
|
|
|
|
|
|
export interface PluginCIOptions {
|
|
|
backend?: string;
|
|
|
full?: boolean;
|
|
|
}
|
|
|
|
|
|
-const calcJavascriptSize = (base: string, files?: string[]): number => {
|
|
|
- files = files || fs.readdirSync(base);
|
|
|
- let size = 0;
|
|
|
-
|
|
|
- if (files) {
|
|
|
- files.forEach(file => {
|
|
|
- const newbase = path.join(base, file);
|
|
|
- const stat = fs.statSync(newbase);
|
|
|
- if (stat.isDirectory()) {
|
|
|
- size += calcJavascriptSize(newbase, fs.readdirSync(newbase));
|
|
|
- } else {
|
|
|
- if (file.endsWith('.js')) {
|
|
|
- size += stat.size;
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
- return size;
|
|
|
-};
|
|
|
-
|
|
|
-const getJobFromProcessArgv = () => {
|
|
|
- const arg = process.argv[2];
|
|
|
- if (arg && arg.startsWith('plugin:ci-')) {
|
|
|
- const task = arg.substring('plugin:ci-'.length);
|
|
|
- if ('build' === task) {
|
|
|
- if ('--platform' === process.argv[3] && process.argv[4]) {
|
|
|
- return task + '_' + process.argv[4];
|
|
|
- }
|
|
|
- return 'build_nodejs';
|
|
|
- }
|
|
|
- return task;
|
|
|
- }
|
|
|
- return 'unknown_job';
|
|
|
-};
|
|
|
-
|
|
|
-const job = process.env.CIRCLE_JOB || getJobFromProcessArgv();
|
|
|
-
|
|
|
-const getJobFolder = () => {
|
|
|
- const dir = path.resolve(process.cwd(), 'ci', 'jobs', job);
|
|
|
- if (!fs.existsSync(dir)) {
|
|
|
- fs.mkdirSync(dir, { recursive: true });
|
|
|
- }
|
|
|
- return dir;
|
|
|
-};
|
|
|
-
|
|
|
-const getCiFolder = () => {
|
|
|
- const dir = path.resolve(process.cwd(), 'ci');
|
|
|
- if (!fs.existsSync(dir)) {
|
|
|
- fs.mkdirSync(dir, { recursive: true });
|
|
|
- }
|
|
|
- return dir;
|
|
|
-};
|
|
|
-
|
|
|
-const writeJobStats = (startTime: number, workDir: string) => {
|
|
|
- const stats = {
|
|
|
- job,
|
|
|
- startTime,
|
|
|
- endTime: Date.now(),
|
|
|
- };
|
|
|
- const f = path.resolve(workDir, 'stats.json');
|
|
|
- fs.writeFile(f, JSON.stringify(stats, null, 2), err => {
|
|
|
- if (err) {
|
|
|
- throw new Error('Unable to stats: ' + f);
|
|
|
- }
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
/**
|
|
|
* 1. BUILD
|
|
|
*
|
|
|
* when platform exists it is building backend, otherwise frontend
|
|
|
*
|
|
|
* Each build writes data:
|
|
|
- * ~/work/build_xxx/
|
|
|
+ * ~/ci/jobs/build_xxx/
|
|
|
*
|
|
|
* Anything that should be put into the final zip file should be put in:
|
|
|
- * ~/work/build_xxx/dist
|
|
|
+ * ~/ci/jobs/build_xxx/dist
|
|
|
*/
|
|
|
const buildPluginRunner: TaskRunner<PluginCIOptions> = async ({ backend }) => {
|
|
|
const start = Date.now();
|
|
|
@@ -158,23 +103,22 @@ const buildPluginDocsRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
export const ciBuildPluginDocsTask = new Task<PluginCIOptions>('Build Plugin Docs', buildPluginDocsRunner);
|
|
|
|
|
|
/**
|
|
|
- * 2. BUNDLE
|
|
|
+ * 2. Package
|
|
|
*
|
|
|
* Take everything from `~/ci/job/{any}/dist` and
|
|
|
* 1. merge it into: `~/ci/dist`
|
|
|
- * 2. zip it into artifacts in `~/ci/artifacts`
|
|
|
+ * 2. zip it into packages in `~/ci/packages`
|
|
|
* 3. prepare grafana environment in: `~/ci/grafana-test-env`
|
|
|
- *
|
|
|
*/
|
|
|
-const bundlePluginRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
+const packagePluginRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
const start = Date.now();
|
|
|
const ciDir = getCiFolder();
|
|
|
- const artifactsDir = path.resolve(ciDir, 'artifacts');
|
|
|
+ const packagesDir = path.resolve(ciDir, 'packages');
|
|
|
const distDir = path.resolve(ciDir, 'dist');
|
|
|
const docsDir = path.resolve(ciDir, 'docs');
|
|
|
const grafanaEnvDir = path.resolve(ciDir, 'grafana-test-env');
|
|
|
- await execa('rimraf', [artifactsDir, distDir, grafanaEnvDir]);
|
|
|
- fs.mkdirSync(artifactsDir);
|
|
|
+ await execa('rimraf', [packagesDir, distDir, grafanaEnvDir]);
|
|
|
+ fs.mkdirSync(packagesDir);
|
|
|
fs.mkdirSync(distDir);
|
|
|
fs.mkdirSync(grafanaEnvDir);
|
|
|
|
|
|
@@ -199,10 +143,19 @@ const bundlePluginRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ console.log('Save the source info in plugin.json');
|
|
|
+ const pluginJsonFile = path.resolve(distDir, 'plugin.json');
|
|
|
+ const pluginInfo = getPluginJson(pluginJsonFile);
|
|
|
+ (pluginInfo.info as any).source = await getPluginSourceInfo();
|
|
|
+ fs.writeFile(pluginJsonFile, JSON.stringify(pluginInfo, null, 2), err => {
|
|
|
+ if (err) {
|
|
|
+ throw new Error('Error writing: ' + pluginJsonFile);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
console.log('Building ZIP');
|
|
|
- const pluginInfo = getPluginJson(`${distDir}/plugin.json`);
|
|
|
let zipName = pluginInfo.id + '-' + pluginInfo.info.version + '.zip';
|
|
|
- let zipFile = path.resolve(artifactsDir, zipName);
|
|
|
+ let zipFile = path.resolve(packagesDir, zipName);
|
|
|
process.chdir(distDir);
|
|
|
await execa('zip', ['-r', zipFile, '.']);
|
|
|
restoreCwd();
|
|
|
@@ -212,58 +165,31 @@ const bundlePluginRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
throw new Error('Invalid zip file: ' + zipFile);
|
|
|
}
|
|
|
|
|
|
- const zipInfo: any = {
|
|
|
- name: zipName,
|
|
|
- size: zipStats.size,
|
|
|
- };
|
|
|
const info: any = {
|
|
|
- plugin: zipInfo,
|
|
|
+ plugin: await getPackageDetails(zipFile, distDir),
|
|
|
};
|
|
|
- try {
|
|
|
- const exe = await execa('shasum', [zipFile]);
|
|
|
- const idx = exe.stdout.indexOf(' ');
|
|
|
- const sha1 = exe.stdout.substring(0, idx);
|
|
|
- fs.writeFile(zipFile + '.sha1', sha1, err => {});
|
|
|
- zipInfo.sha1 = sha1;
|
|
|
- } catch {
|
|
|
- console.warn('Unable to read SHA1 Checksum');
|
|
|
- }
|
|
|
|
|
|
console.log('Setup Grafan Environment');
|
|
|
let p = path.resolve(grafanaEnvDir, 'plugins', pluginInfo.id);
|
|
|
fs.mkdirSync(p, { recursive: true });
|
|
|
await execa('unzip', [zipFile, '-d', p]);
|
|
|
|
|
|
- // If docs exist, zip them into artifacts
|
|
|
+ // If docs exist, zip them into packages
|
|
|
if (fs.existsSync(docsDir)) {
|
|
|
console.log('Creating documentation zip');
|
|
|
zipName = pluginInfo.id + '-' + pluginInfo.info.version + '-docs.zip';
|
|
|
- zipFile = path.resolve(artifactsDir, zipName);
|
|
|
+ zipFile = path.resolve(packagesDir, zipName);
|
|
|
process.chdir(docsDir);
|
|
|
await execa('zip', ['-r', zipFile, '.']);
|
|
|
restoreCwd();
|
|
|
|
|
|
- const zipStats = fs.statSync(zipFile);
|
|
|
- const zipInfo: any = {
|
|
|
- name: zipName,
|
|
|
- size: zipStats.size,
|
|
|
- };
|
|
|
- try {
|
|
|
- const exe = await execa('shasum', [zipFile]);
|
|
|
- const idx = exe.stdout.indexOf(' ');
|
|
|
- const sha1 = exe.stdout.substring(0, idx);
|
|
|
- fs.writeFile(zipFile + '.sha1', sha1, err => {});
|
|
|
- zipInfo.sha1 = sha1;
|
|
|
- } catch {
|
|
|
- console.warn('Unable to read SHA1 Checksum');
|
|
|
- }
|
|
|
- info.docs = zipInfo;
|
|
|
+ info.docs = await getPackageDetails(zipFile, docsDir);
|
|
|
}
|
|
|
|
|
|
- p = path.resolve(artifactsDir, 'info.json');
|
|
|
+ p = path.resolve(packagesDir, 'info.json');
|
|
|
fs.writeFile(p, JSON.stringify(info, null, 2), err => {
|
|
|
if (err) {
|
|
|
- throw new Error('Error writing artifact info: ' + p);
|
|
|
+ throw new Error('Error writing package info: ' + p);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@@ -283,7 +209,7 @@ const bundlePluginRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
writeJobStats(start, getJobFolder());
|
|
|
};
|
|
|
|
|
|
-export const ciBundlePluginTask = new Task<PluginCIOptions>('Bundle Plugin', bundlePluginRunner);
|
|
|
+export const ciPackagePluginTask = new Task<PluginCIOptions>('Bundle Plugin', packagePluginRunner);
|
|
|
|
|
|
/**
|
|
|
* 3. Test (end-to-end)
|
|
|
@@ -294,11 +220,11 @@ export const ciBundlePluginTask = new Task<PluginCIOptions>('Bundle Plugin', bun
|
|
|
const testPluginRunner: TaskRunner<PluginCIOptions> = async ({ full }) => {
|
|
|
const start = Date.now();
|
|
|
const workDir = getJobFolder();
|
|
|
- const pluginInfo = getPluginJson(`${process.cwd()}/src/plugin.json`);
|
|
|
-
|
|
|
+ const pluginInfo = getPluginJson(`${process.cwd()}/ci/dist/plugin.json`);
|
|
|
+ const results: TestResultInfo = { job };
|
|
|
const args = {
|
|
|
withCredentials: true,
|
|
|
- baseURL: process.env.GRAFANA_URL || 'http://localhost:3000/',
|
|
|
+ baseURL: process.env.BASE_URL || 'http://localhost:3000/',
|
|
|
responseType: 'json',
|
|
|
auth: {
|
|
|
username: 'admin',
|
|
|
@@ -306,40 +232,32 @@ const testPluginRunner: TaskRunner<PluginCIOptions> = async ({ full }) => {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
- const axios = require('axios');
|
|
|
- const frontendSettings = await axios.get('api/frontend/settings', args);
|
|
|
-
|
|
|
- console.log('Grafana Version: ' + JSON.stringify(frontendSettings.data.buildInfo, null, 2));
|
|
|
+ try {
|
|
|
+ const axios = require('axios');
|
|
|
+ const frontendSettings = await axios.get('api/frontend/settings', args);
|
|
|
+ results.grafana = frontendSettings.data.buildInfo;
|
|
|
|
|
|
- const allPlugins: any[] = await axios.get('api/plugins', args).data;
|
|
|
- // for (const plugin of allPlugins) {
|
|
|
- // if (plugin.id === pluginInfo.id) {
|
|
|
- // console.log('------------');
|
|
|
- // console.log(plugin);
|
|
|
- // console.log('------------');
|
|
|
- // } else {
|
|
|
- // console.log('Plugin:', plugin.id, plugin.latestVersion);
|
|
|
- // }
|
|
|
- // }
|
|
|
- console.log('PLUGINS:', allPlugins);
|
|
|
+ console.log('Grafana: ' + JSON.stringify(results.grafana, null, 2));
|
|
|
|
|
|
- if (full) {
|
|
|
const pluginSettings = await axios.get(`api/plugins/${pluginInfo.id}/settings`, args);
|
|
|
console.log('Plugin Info: ' + JSON.stringify(pluginSettings.data, null, 2));
|
|
|
- }
|
|
|
|
|
|
- console.log('TODO puppeteer');
|
|
|
+ console.log('TODO Puppeteer Tests', workDir);
|
|
|
|
|
|
- const elapsed = Date.now() - start;
|
|
|
- const stats = {
|
|
|
- job,
|
|
|
- sha1: `${process.env.CIRCLE_SHA1}`,
|
|
|
- startTime: start,
|
|
|
- buildTime: elapsed,
|
|
|
- endTime: Date.now(),
|
|
|
- };
|
|
|
+ results.status = 'TODO... puppeteer';
|
|
|
+ } catch (err) {
|
|
|
+ results.error = err;
|
|
|
+ results.status = 'EXCEPTION Thrown';
|
|
|
+ console.log('Test Error', err);
|
|
|
+ }
|
|
|
+
|
|
|
+ const f = path.resolve(workDir, 'results.json');
|
|
|
+ fs.writeFile(f, JSON.stringify(results, null, 2), err => {
|
|
|
+ if (err) {
|
|
|
+ throw new Error('Error saving: ' + f);
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- console.log('TODO Puppeteer Tests', stats);
|
|
|
writeJobStats(start, workDir);
|
|
|
};
|
|
|
|
|
|
@@ -352,35 +270,28 @@ export const ciTestPluginTask = new Task<PluginCIOptions>('Test Plugin (e2e)', t
|
|
|
*
|
|
|
*/
|
|
|
const pluginReportRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
- const start = Date.now();
|
|
|
- const workDir = getJobFolder();
|
|
|
- const reportDir = path.resolve(process.cwd(), 'ci', 'report');
|
|
|
- await execa('rimraf', [reportDir]);
|
|
|
- fs.mkdirSync(reportDir);
|
|
|
+ const ciDir = path.resolve(process.cwd(), 'ci');
|
|
|
+ const packageInfo = require(path.resolve(ciDir, 'packages', 'info.json'));
|
|
|
+
|
|
|
+ console.log('Save the source info in plugin.json');
|
|
|
+ const pluginJsonFile = path.resolve(ciDir, 'dist', 'plugin.json');
|
|
|
+ const report = {
|
|
|
+ plugin: getPluginJson(pluginJsonFile),
|
|
|
+ packages: packageInfo,
|
|
|
+ workflow: agregateWorkflowInfo(),
|
|
|
+ coverage: agregateCoverageInfo(),
|
|
|
+ tests: agregateTestInfo(),
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('REPORT', report);
|
|
|
|
|
|
- const file = path.resolve(reportDir, `report.txt`);
|
|
|
- fs.writeFile(file, `TODO... actually make a report (csv etc)`, err => {
|
|
|
+ const file = path.resolve(ciDir, 'report.json');
|
|
|
+ fs.writeFile(file, JSON.stringify(report, null, 2), err => {
|
|
|
if (err) {
|
|
|
throw new Error('Unable to write: ' + file);
|
|
|
}
|
|
|
});
|
|
|
-
|
|
|
- console.log('TODO... real report');
|
|
|
- writeJobStats(start, workDir);
|
|
|
-};
|
|
|
-
|
|
|
-export const ciPluginReportTask = new Task<PluginCIOptions>('Deploy plugin', pluginReportRunner);
|
|
|
-
|
|
|
-/**
|
|
|
- * 5. Deploy
|
|
|
- *
|
|
|
- * deploy the zip to a running grafana instance
|
|
|
- *
|
|
|
- */
|
|
|
-const deployPluginRunner: TaskRunner<PluginCIOptions> = async () => {
|
|
|
- console.log('TODO DEPLOY??');
|
|
|
- console.log(' if PR => write a comment to github with difference ');
|
|
|
- console.log(' if master | vXYZ ==> upload artifacts to some repo ');
|
|
|
+ console.log('TODO... notify some service');
|
|
|
};
|
|
|
|
|
|
-export const ciDeployPluginTask = new Task<PluginCIOptions>('Deploy plugin', deployPluginRunner);
|
|
|
+export const ciPluginReportTask = new Task<PluginCIOptions>('Generate Plugin Report', pluginReportRunner);
|