Report versions of plugins and plugin load success rate (#1270)
Summary: Pull Request resolved: https://github.com/facebook/flipper/pull/1270 1) Report versions of loaded plugins so we can track auto-updates 2) Report plugin load success rate Reviewed By: jknoxville Differential Revision: D22066598 fbshipit-source-id: 23ef2fb37260438cc1a9a873c88a50b75cd718f4
This commit is contained in:
committed by
Facebook GitHub Bot
parent
fec52a3989
commit
c995fc8fc2
@@ -8,6 +8,9 @@
|
||||
*/
|
||||
|
||||
jest.mock('../../defaultPlugins');
|
||||
try {
|
||||
jest.mock('../../fb/Logger', () => require('../../fb-stubs/Logger'));
|
||||
} catch {}
|
||||
|
||||
import dispatcher, {
|
||||
getDynamicPlugins,
|
||||
@@ -158,6 +161,7 @@ test('requirePlugin loads plugin', () => {
|
||||
entry: path.join(__dirname, 'TestPlugin'),
|
||||
version: '1.0.0',
|
||||
});
|
||||
expect(plugin).not.toBeNull();
|
||||
expect(plugin!.prototype).toBeInstanceOf(FlipperPlugin);
|
||||
expect(plugin!.id).toBe(TestPlugin.id);
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@ import semver from 'semver';
|
||||
import {PluginDetails} from 'flipper-plugin-lib';
|
||||
import {addNotification} from '../reducers/notifications';
|
||||
import styled from '@emotion/styled';
|
||||
import {tryCatchReportPluginFailures, reportUsage} from '../utils/metrics';
|
||||
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import getPluginIndex from '../utils/getDefaultPluginsIndex';
|
||||
@@ -58,6 +59,7 @@ export default (store: Store, logger: Logger) => {
|
||||
const initialPlugins: Array<
|
||||
typeof FlipperPlugin | typeof FlipperDevicePlugin
|
||||
> = filterNewestVersionOfEachPlugin(getBundledPlugins(), getDynamicPlugins())
|
||||
.map(reportVersion)
|
||||
.filter(checkDisabled(disabledPlugins))
|
||||
.filter(checkGK(gatekeepedPlugins))
|
||||
.map(requirePlugin(failedPlugins, defaultPluginsIndex))
|
||||
@@ -70,7 +72,6 @@ export default (store: Store, logger: Logger) => {
|
||||
const deprecatedSpecPlugins = initialPlugins.filter(
|
||||
(p) => !p.isDefault && p.details.specVersion === 1,
|
||||
);
|
||||
|
||||
for (const plugin of deprecatedSpecPlugins) {
|
||||
store.dispatch(
|
||||
addNotification({
|
||||
@@ -149,6 +150,17 @@ export default (store: Store, logger: Logger) => {
|
||||
);
|
||||
};
|
||||
|
||||
function reportVersion(pluginDetails: PluginDetails) {
|
||||
reportUsage(
|
||||
'plugin:version',
|
||||
{
|
||||
version: pluginDetails.version,
|
||||
},
|
||||
pluginDetails.id,
|
||||
);
|
||||
return pluginDetails;
|
||||
}
|
||||
|
||||
export function filterNewestVersionOfEachPlugin(
|
||||
bundledPlugins: PluginDetails[],
|
||||
dynamicPlugins: PluginDetails[],
|
||||
@@ -237,33 +249,43 @@ export const requirePlugin = (
|
||||
pluginDetails: PluginDetails,
|
||||
): typeof FlipperPlugin | typeof FlipperDevicePlugin | null => {
|
||||
try {
|
||||
let plugin = pluginDetails.isDefault
|
||||
? defaultPluginsIndex[pluginDetails.name]
|
||||
: reqFn(pluginDetails.entry);
|
||||
if (plugin.default) {
|
||||
plugin = plugin.default;
|
||||
}
|
||||
if (!(plugin.prototype instanceof FlipperBasePlugin)) {
|
||||
throw new Error(`Plugin ${plugin.name} is not a FlipperBasePlugin`);
|
||||
}
|
||||
|
||||
plugin.id = plugin.id || pluginDetails.id;
|
||||
plugin.packageName = pluginDetails.name;
|
||||
plugin.details = pluginDetails;
|
||||
|
||||
// set values from package.json as static variables on class
|
||||
Object.keys(pluginDetails).forEach((key) => {
|
||||
if (key !== 'name' && key !== 'id') {
|
||||
plugin[key] =
|
||||
plugin[key] || pluginDetails[key as keyof PluginDetails];
|
||||
}
|
||||
});
|
||||
|
||||
return plugin;
|
||||
return tryCatchReportPluginFailures(
|
||||
() => requirePluginInternal(pluginDetails, defaultPluginsIndex, reqFn),
|
||||
'plugin:load',
|
||||
pluginDetails.id,
|
||||
);
|
||||
} catch (e) {
|
||||
failedPlugins.push([pluginDetails, e.message]);
|
||||
console.error(pluginDetails, e);
|
||||
console.error(`Plugin ${pluginDetails.id} failed to load`, e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const requirePluginInternal = (
|
||||
pluginDetails: PluginDetails,
|
||||
defaultPluginsIndex: any,
|
||||
reqFn: Function = global.electronRequire,
|
||||
) => {
|
||||
let plugin = pluginDetails.isDefault
|
||||
? defaultPluginsIndex[pluginDetails.name]
|
||||
: reqFn(pluginDetails.entry);
|
||||
if (plugin.default) {
|
||||
plugin = plugin.default;
|
||||
}
|
||||
if (!(plugin.prototype instanceof FlipperBasePlugin)) {
|
||||
throw new Error(`Plugin ${plugin.name} is not a FlipperBasePlugin`);
|
||||
}
|
||||
|
||||
plugin.id = plugin.id || pluginDetails.id;
|
||||
plugin.packageName = pluginDetails.name;
|
||||
plugin.details = pluginDetails;
|
||||
|
||||
// set values from package.json as static variables on class
|
||||
Object.keys(pluginDetails).forEach((key) => {
|
||||
if (key !== 'name' && key !== 'id') {
|
||||
plugin[key] = plugin[key] || pluginDetails[key as keyof PluginDetails];
|
||||
}
|
||||
});
|
||||
return plugin;
|
||||
};
|
||||
|
||||
@@ -110,6 +110,29 @@ export function tryCatchReportPlatformFailures<T>(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wraps a closure, preserving it's functionality but logging the success or
|
||||
failure state of it.
|
||||
*/
|
||||
export function tryCatchReportPluginFailures<T>(
|
||||
closure: () => T,
|
||||
name: string,
|
||||
plugin: string,
|
||||
): T {
|
||||
try {
|
||||
const result = closure();
|
||||
logPluginSuccessRate(name, plugin, {kind: 'success'});
|
||||
return result;
|
||||
} catch (e) {
|
||||
logPluginSuccessRate(name, plugin, {
|
||||
kind: 'failure',
|
||||
supportedOperation: !(e instanceof UnsupportedError),
|
||||
error: e,
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track usage of a feature.
|
||||
* @param action Unique name for the action performed. E.g. captureScreenshot
|
||||
|
||||
Reference in New Issue
Block a user