From 28fd8da6153a554781ba4dc9c55a4e0e6c970b90 Mon Sep 17 00:00:00 2001 From: Anton Nikolaev Date: Tue, 11 May 2021 17:02:24 -0700 Subject: [PATCH] Install only compatible plugins Summary: Currently, when user installs a new plugin which was not installed before that, Flipper always takes the latest available version of it. This is not correct, because the latest version might be incompatible with the currently running version of Flipper. To avoid that, instead of always using just the latest version we will be using the most recent version which is compatible with the current Flipper version. Reviewed By: passy Differential Revision: D28306505 fbshipit-source-id: 4258a456d6a5d92cbf48af55c0efb17ecf560b57 --- desktop/app/src/dispatcher/plugins.tsx | 34 +++++++++++++++++++ desktop/app/src/utils/isPluginCompatible.tsx | 25 ++++++++++++++ .../src/__tests__/getPluginDetails.node.ts | 6 ++++ desktop/plugin-lib/src/getPluginDetails.ts | 2 ++ 4 files changed, 67 insertions(+) create mode 100644 desktop/app/src/utils/isPluginCompatible.tsx diff --git a/desktop/app/src/dispatcher/plugins.tsx b/desktop/app/src/dispatcher/plugins.tsx index 100f62d4c..793677009 100644 --- a/desktop/app/src/dispatcher/plugins.tsx +++ b/desktop/app/src/dispatcher/plugins.tsx @@ -20,6 +20,8 @@ import { addFailedPlugins, registerLoadedPlugins, registerBundledPlugins, + registerMarketplacePlugins, + MarketplacePluginDetails, } from '../reducers/plugins'; import GK from '../fb-stubs/GK'; import {FlipperBasePlugin} from '../plugin'; @@ -49,6 +51,7 @@ import * as crc32 from 'crc32'; // eslint-disable-next-line import/no-unresolved import getDefaultPluginsIndex from '../utils/getDefaultPluginsIndex'; import {isDevicePluginDefinition} from '../utils/pluginUtils'; +import {isPluginCompatible} from '../utils/isPluginCompatible'; let defaultPluginsIndex: any = null; @@ -74,6 +77,13 @@ export default async (store: Store, logger: Logger) => { defaultPluginsIndex = getDefaultPluginsIndex(); + const marketplacePlugins = store.getState().plugins.marketplacePlugins; + store.dispatch( + registerMarketplacePlugins( + selectCompatibleMarketplaceVersions(marketplacePlugins), + ), + ); + const uninstalledPlugins = store.getState().plugins.uninstalledPlugins; const bundledPlugins = getBundledPlugins(); @@ -320,3 +330,27 @@ const requirePluginInternal = ( } return plugin; }; + +export function selectCompatibleMarketplaceVersions( + availablePlugins: MarketplacePluginDetails[], +): MarketplacePluginDetails[] { + const plugins: MarketplacePluginDetails[] = []; + for (const plugin of availablePlugins) { + if (!isPluginCompatible(plugin)) { + const compatibleVersion = + plugin.availableVersions?.find(isPluginCompatible) ?? + plugin.availableVersions?.slice(-1).pop(); + if (compatibleVersion) { + plugins.push({ + ...compatibleVersion, + availableVersions: plugin?.availableVersions, + }); + } else { + plugins.push(plugin); + } + } else { + plugins.push(plugin); + } + } + return plugins; +} diff --git a/desktop/app/src/utils/isPluginCompatible.tsx b/desktop/app/src/utils/isPluginCompatible.tsx new file mode 100644 index 000000000..dfa632f95 --- /dev/null +++ b/desktop/app/src/utils/isPluginCompatible.tsx @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {PluginDetails} from 'plugin-lib'; +import semver from 'semver'; +import GK from '../fb-stubs/GK'; +import {getAppVersion} from './info'; + +export function isPluginCompatible(plugin: PluginDetails) { + const flipperVersion = getAppVersion(); + return ( + GK.get('flipper_disable_plugin_compatibility_checks') || + flipperVersion === '0.0.0' || + !plugin.engines?.flipper || + semver.lte(plugin.engines?.flipper, flipperVersion) + ); +} + +export default isPluginCompatible; diff --git a/desktop/plugin-lib/src/__tests__/getPluginDetails.node.ts b/desktop/plugin-lib/src/__tests__/getPluginDetails.node.ts index ec306e7d0..c2f5b29a2 100644 --- a/desktop/plugin-lib/src/__tests__/getPluginDetails.node.ts +++ b/desktop/plugin-lib/src/__tests__/getPluginDetails.node.ts @@ -40,6 +40,7 @@ test('getPluginDetailsV1', async () => { "category": undefined, "description": "Description of Test Plugin", "dir": "/Users/mock/.flipper/thirdparty/flipper-plugin-test", + "engines": undefined, "entry": "/Users/mock/.flipper/plugins/flipper-plugin-test@2.0.0.js", "flipperSDKVersion": undefined, "gatekeeper": "GK_flipper_plugin_test", @@ -81,6 +82,7 @@ test('getPluginDetailsV2', async () => { "category": undefined, "description": "Description of Test Plugin", "dir": "/Users/mock/.flipper/thirdparty/flipper-plugin-test", + "engines": undefined, "entry": "/Users/mock/.flipper/thirdparty/flipper-plugin-test/dist/bundle.js", "flipperSDKVersion": undefined, "gatekeeper": "GK_flipper_plugin_test", @@ -122,6 +124,7 @@ test('id used as title if the latter omited', async () => { "category": undefined, "description": "Description of Test Plugin", "dir": "/Users/mock/.flipper/thirdparty/flipper-plugin-test", + "engines": undefined, "entry": "/Users/mock/.flipper/thirdparty/flipper-plugin-test/dist/bundle.js", "flipperSDKVersion": undefined, "gatekeeper": "GK_flipper_plugin_test", @@ -162,6 +165,7 @@ test('name without "flipper-plugin-" prefix is used as title if the latter omite "category": undefined, "description": "Description of Test Plugin", "dir": "/Users/mock/.flipper/thirdparty/flipper-plugin-test", + "engines": undefined, "entry": "/Users/mock/.flipper/thirdparty/flipper-plugin-test/dist/bundle.js", "flipperSDKVersion": undefined, "gatekeeper": "GK_flipper_plugin_test", @@ -205,6 +209,7 @@ test('flipper-plugin-version is parsed', async () => { "category": undefined, "description": "Description of Test Plugin", "dir": "/Users/mock/.flipper/thirdparty/flipper-plugin-test", + "engines": undefined, "entry": "/Users/mock/.flipper/thirdparty/flipper-plugin-test/dist/bundle.js", "flipperSDKVersion": "^0.45", "gatekeeper": "GK_flipper_plugin_test", @@ -252,6 +257,7 @@ test('plugin type and supported devices parsed', async () => { "category": undefined, "description": "Description of Test Plugin", "dir": "/Users/mock/.flipper/thirdparty/flipper-plugin-test", + "engines": undefined, "entry": "/Users/mock/.flipper/thirdparty/flipper-plugin-test/dist/bundle.js", "flipperSDKVersion": undefined, "gatekeeper": "GK_flipper_plugin_test", diff --git a/desktop/plugin-lib/src/getPluginDetails.ts b/desktop/plugin-lib/src/getPluginDetails.ts index 043238b09..ee1a2c053 100644 --- a/desktop/plugin-lib/src/getPluginDetails.ts +++ b/desktop/plugin-lib/src/getPluginDetails.ts @@ -89,6 +89,7 @@ function getPluginDetailsV1(packageJson: any): PluginDetails { flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'], pluginType: packageJson?.pluginType, supportedDevices: packageJson?.supportedDevices, + engines: packageJson.engines, }; } @@ -111,6 +112,7 @@ function getPluginDetailsV2(packageJson: any): PluginDetails { flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'], pluginType: packageJson?.pluginType, supportedDevices: packageJson?.supportedDevices, + engines: packageJson.engines, }; }