Script for plugin type-checking (#2172)
Summary: Pull Request resolved: https://github.com/facebook/flipper/pull/2172 New script which runs "tsc" for all plugins, receives list of errors and then checks which plugins are affected. It works for shared libs too, e.g. if there is an error in a shared library, then all plugins dependant on it will be counted as affected. For convenience, script saves list of errors affecting each plugin to "tsc-errors.log" in plugin folder. This script will be used for automatic type-checking plugins against current "stable" and "insiders" versions of Flipper. An alternative to this implementation would be to simply run "tsc" for each plugin individually, but such implementation takes a lot of time (5+ sec per plugin) and so cannot be effectively used on diffs. Reviewed By: mweststrate Differential Revision: D27499765 fbshipit-source-id: fcbbfc94a13e6c7c5beff0c889a929f84c41b2dd
This commit is contained in:
committed by
Facebook GitHub Bot
parent
e7c5a5cc93
commit
dc7226b7dc
1
desktop/.gitignore
vendored
1
desktop/.gitignore
vendored
@@ -6,3 +6,4 @@ node_modules/
|
|||||||
/app/src/defaultPlugins/index.tsx
|
/app/src/defaultPlugins/index.tsx
|
||||||
/coverage
|
/coverage
|
||||||
.env
|
.env
|
||||||
|
tsc-error.log
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import {theme, TrackingScope, _SandyPluginRenderer} from 'flipper-plugin';
|
|||||||
import {isDevicePluginDefinition, isSandyPlugin} from './utils/pluginUtils';
|
import {isDevicePluginDefinition, isSandyPlugin} from './utils/pluginUtils';
|
||||||
import {ContentContainer} from './sandy-chrome/ContentContainer';
|
import {ContentContainer} from './sandy-chrome/ContentContainer';
|
||||||
import {Alert, Typography} from 'antd';
|
import {Alert, Typography} from 'antd';
|
||||||
import {InstalledPluginDetails} from 'plugin-lib';
|
import {InstalledPluginDetails} from 'flipper-plugin-lib';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import {loadPlugin} from './reducers/pluginManager';
|
import {loadPlugin} from './reducers/pluginManager';
|
||||||
import {produce} from 'immer';
|
import {produce} from 'immer';
|
||||||
|
|||||||
@@ -227,9 +227,10 @@
|
|||||||
"dev-server": "cross-env NODE_ENV=development ./ts-node scripts/start-dev-server.ts",
|
"dev-server": "cross-env NODE_ENV=development ./ts-node scripts/start-dev-server.ts",
|
||||||
"everything": "yarn reset && yarn install && yarn lint && yarn test && yarn test-electron && yarn build --mac --mac-dmg --win --linux --linux-deb && yarn start",
|
"everything": "yarn reset && yarn install && yarn lint && yarn test && yarn test-electron && yarn build --mac --mac-dmg --win --linux --linux-deb && yarn start",
|
||||||
"fix": "eslint . --fix --ext .js,.ts,.tsx",
|
"fix": "eslint . --fix --ext .js,.ts,.tsx",
|
||||||
"lint": "yarn lint:eslint && yarn lint:tsc",
|
"lint": "yarn lint:eslint && yarn lint:tsc && yarn tsc-plugins",
|
||||||
"lint:eslint": "eslint . --ext .js,.ts,.tsx",
|
"lint:eslint": "eslint . --ext .js,.ts,.tsx",
|
||||||
"lint:tsc": "tsc --noemit",
|
"lint:tsc": "tsc --noemit",
|
||||||
|
"tsc-plugins": "./ts-node scripts/tsc-plugins.ts",
|
||||||
"list-plugins": "./ts-node scripts/list-plugins.ts",
|
"list-plugins": "./ts-node scripts/list-plugins.ts",
|
||||||
"open-dist": "open ../dist/mac/Flipper.app --args --launcher=false --inspect=9229",
|
"open-dist": "open ../dist/mac/Flipper.app --args --launcher=false --inspect=9229",
|
||||||
"postinstall": "patch-package && ./ts-node scripts/gen-type-index.ts && yarn --cwd plugins install --mutex network:30331 && yarn build:tsc && ./ts-node scripts/generate-plugin-entry-points.ts && yarn build:themes",
|
"postinstall": "patch-package && ./ts-node scripts/gen-type-index.ts && yarn --cwd plugins install --mutex network:30331 && yarn build:tsc && ./ts-node scripts/generate-plugin-entry-points.ts && yarn build:themes",
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"*"
|
"*"
|
||||||
],
|
],
|
||||||
"nohoist": [
|
"nohoist": [
|
||||||
"flipper-plugin-kaios-big-allocations/firefox-client"
|
"flipper-plugin-kaios-big-allocations/firefox-client",
|
||||||
|
"flipper-plugin-kaios-big-allocations/patch-package"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
@@ -19,7 +20,6 @@
|
|||||||
"url": "https://fb.workplace.com/groups/flippersupport/"
|
"url": "https://fb.workplace.com/groups/flippersupport/"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2"
|
||||||
"patch-package": "^6.2.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const GrabMetroDevice = connect<
|
|||||||
ReduxState
|
ReduxState
|
||||||
>(({connections: {devices}}) => ({
|
>(({connections: {devices}}) => ({
|
||||||
metroDevice: devices.find(
|
metroDevice: devices.find(
|
||||||
(device) => device.os === 'Metro' && !device.isArchived,
|
(device: Device) => device.os === 'Metro' && !device.isArchived,
|
||||||
) as MetroDevice,
|
) as MetroDevice,
|
||||||
}))(function ({
|
}))(function ({
|
||||||
metroDevice,
|
metroDevice,
|
||||||
|
|||||||
20
desktop/plugins/tsconfig.json
Normal file
20
desktop/plugins/tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"rootDir": ".",
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"public/",
|
||||||
|
"fb/"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"**/lib/",
|
||||||
|
"**/dist/",
|
||||||
|
"**/node_modules/",
|
||||||
|
"**/__tests__/",
|
||||||
|
"**/__test__/"
|
||||||
|
]
|
||||||
|
}
|
||||||
148
desktop/scripts/tsc-plugins.ts
Normal file
148
desktop/scripts/tsc-plugins.ts
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/**
|
||||||
|
* 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 fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import {exec} from 'child_process';
|
||||||
|
import {EOL} from 'os';
|
||||||
|
import pmap from 'p-map';
|
||||||
|
import {rootDir} from './paths';
|
||||||
|
import yargs from 'yargs';
|
||||||
|
|
||||||
|
const argv = yargs
|
||||||
|
.usage('yarn tsc-plugins [args]')
|
||||||
|
.version(false)
|
||||||
|
.options({
|
||||||
|
dir: {
|
||||||
|
description: 'Plugins directory name ("plugins" by default)',
|
||||||
|
type: 'string',
|
||||||
|
default: 'plugins',
|
||||||
|
alias: 'd',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.help()
|
||||||
|
.strict()
|
||||||
|
.parse(process.argv.slice(1));
|
||||||
|
|
||||||
|
const pluginsDir = path.join(rootDir, argv.dir);
|
||||||
|
const fbPluginsDir = path.join(pluginsDir, 'fb');
|
||||||
|
const publicPluginsDir = path.join(pluginsDir, 'public');
|
||||||
|
|
||||||
|
async function tscPlugins(): Promise<number> {
|
||||||
|
const stdout = await new Promise<string | undefined>((resolve) =>
|
||||||
|
exec(
|
||||||
|
`./node_modules/.bin/tsc -p ./${argv.dir}/tsconfig.json`,
|
||||||
|
{
|
||||||
|
cwd: rootDir,
|
||||||
|
},
|
||||||
|
(err, stdout) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
resolve(stdout);
|
||||||
|
} else {
|
||||||
|
resolve(undefined);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (stdout) {
|
||||||
|
console.error(stdout);
|
||||||
|
}
|
||||||
|
const errors = (stdout?.split(EOL) ?? []).filter((l) => l !== '');
|
||||||
|
if (errors.length > 0) {
|
||||||
|
await findAffectedPlugins(errors);
|
||||||
|
}
|
||||||
|
return stdout ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findAffectedPlugins(errors: string[]) {
|
||||||
|
const [publicPackages, fbPackages] = await Promise.all([
|
||||||
|
fs.readdir(publicPluginsDir),
|
||||||
|
fs.readdir(fbPluginsDir).catch(() => [] as string[]),
|
||||||
|
]);
|
||||||
|
const allPackages = await pmap(
|
||||||
|
[
|
||||||
|
...publicPackages.map((p) => path.join(publicPluginsDir, p)),
|
||||||
|
...fbPackages.map((p) => path.join(fbPluginsDir, p)),
|
||||||
|
],
|
||||||
|
async (p) => ({
|
||||||
|
dir: p,
|
||||||
|
json: await fs
|
||||||
|
.readJson(path.join(p, 'package.json'))
|
||||||
|
.catch(() => undefined),
|
||||||
|
}),
|
||||||
|
).then((dirs) => dirs.filter((dir) => !!dir.json));
|
||||||
|
const packageByName = new Map(
|
||||||
|
allPackages.map((p) => [p.json.name as string, p]),
|
||||||
|
);
|
||||||
|
const depsByName = new Map<string, Set<string>>();
|
||||||
|
function getDependencies(name: string): Set<string> {
|
||||||
|
if (!depsByName.has(name)) {
|
||||||
|
const set = new Set<string>();
|
||||||
|
const pkg = packageByName.get(name)!;
|
||||||
|
set.add(name);
|
||||||
|
const allDeps = Object.keys({
|
||||||
|
...(pkg.json.dependencies ?? {}),
|
||||||
|
...(pkg.json.peerDependencies ?? {}),
|
||||||
|
});
|
||||||
|
for (const dep of allDeps) {
|
||||||
|
if (packageByName.get(dep)) {
|
||||||
|
const subDeps = getDependencies(dep);
|
||||||
|
for (const subDep of subDeps) {
|
||||||
|
set.add(subDep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
depsByName.set(name, set);
|
||||||
|
}
|
||||||
|
return depsByName.get(name)!;
|
||||||
|
}
|
||||||
|
for (const name of packageByName.keys()) {
|
||||||
|
depsByName.set(name, getDependencies(name));
|
||||||
|
}
|
||||||
|
for (const pkg of allPackages) {
|
||||||
|
if (!pkg.json?.keywords?.includes('flipper-plugin')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const logFile = path.join(pkg.dir, 'tsc-error.log');
|
||||||
|
await fs.remove(logFile);
|
||||||
|
let logStream: fs.WriteStream | undefined;
|
||||||
|
for (const dep of depsByName.get(pkg.json.name)!) {
|
||||||
|
const relativeDir = path.relative(rootDir, packageByName.get(dep)!.dir);
|
||||||
|
for (const error of errors) {
|
||||||
|
if (error.startsWith(relativeDir)) {
|
||||||
|
if (!logStream) {
|
||||||
|
logStream = fs.createWriteStream(logFile);
|
||||||
|
console.error(
|
||||||
|
`Plugin ${path.relative(
|
||||||
|
rootDir,
|
||||||
|
pkg.dir,
|
||||||
|
)} has tsc errors. Check ${path.relative(
|
||||||
|
rootDir,
|
||||||
|
logFile,
|
||||||
|
)} for details.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
logStream.write(error);
|
||||||
|
logStream.write(EOL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logStream?.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tscPlugins()
|
||||||
|
.then((code) => {
|
||||||
|
process.exit(code);
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user