Fix module resolution for flipper-doctor and return it to sonar directory and effectively to GitHub

Summary: Fix module resolution for flipper-doctor and return it to sonar directory and effectively to GitHub

Reviewed By: mweststrate

Differential Revision: D18963720

fbshipit-source-id: 61ea78ecbb154de79c7a2d348f347c64325e794c
This commit is contained in:
Anton Nikolaev
2019-12-13 03:59:35 -08:00
committed by Facebook Github Bot
parent c7af0b53e6
commit 3fefd9de15
15 changed files with 4657 additions and 3 deletions

2
doctor/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/lib
node_modules/

1
doctor/.ignore Symbolic link
View File

@@ -0,0 +1 @@
.gitignore

8
doctor/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Flipper Doctor
This package exists for running checks to diagnose and potentially fix issues affecting the operation of Flipper.
It's designed to be primarily used programmatically but may also expose a CLI interface.
## Usage
`cd doctor`
`yarn run run`

7
doctor/jestconfig.json Normal file
View File

@@ -0,0 +1,7 @@
{
"transform": {
"^.+\\.(t|j)sx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
}

46
doctor/package.json Normal file
View File

@@ -0,0 +1,46 @@
{
"name": "flipper-doctor",
"version": "0.2.1",
"description": "Utility for checking for issues with a flipper installation",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"license": "MIT",
"devDependencies": {
"@types/jest": "^24.0.21",
"@typescript-eslint/eslint-plugin": "^2.8.0",
"eslint": "^6.6.0",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-flowtype": "^4.5.2",
"eslint-plugin-header": "^3.0.0",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-react": "^7.16.0",
"jest": "^24.9.0",
"prettier": "^1.19.1",
"ts-jest": "^24.1.0",
"tslint-config-prettier": "^1.18.0",
"typescript": "^3.7.2"
},
"scripts": {
"build": "tsc",
"prepare": "npm run build",
"prepublishOnly": "npm test && npm run lint",
"preversion": "npm run lint",
"test": "jest --config jestconfig.json --passWithNoTests",
"lint": "eslint -c ../../sonar/.eslintrc.js src/**/* --ext .js,.ts && tsc --noemit",
"fix": "eslint -c ../../sonar/.eslintrc.js src/**/* --fix --ext .js,.ts",
"run": "npm run build && node lib/cli.js"
},
"files": [
"lib/**/*"
],
"keywords": [
"Flipper",
"Doctor"
],
"author": "Facebook, Inc",
"dependencies": {
"@types/node": "^12.12.12",
"envinfo": "^7.4.0"
}
}

35
doctor/src/cli.ts Normal file
View File

@@ -0,0 +1,35 @@
/**
* 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 {getHealthchecks} from './index';
import {getEnvInfo} from './environmentInfo';
(async () => {
const environmentInfo = await getEnvInfo();
console.log(JSON.stringify(environmentInfo));
const healthchecks = getHealthchecks();
const results = await Promise.all(
Object.entries(healthchecks).map(async ([key, category]) => [
key,
category
? {
label: category.label,
results: await Promise.all(
category.healthchecks.map(async ({label, run}) => ({
label,
result: await run(environmentInfo),
})),
),
}
: {},
]),
);
console.log(JSON.stringify(results, null, 2));
})();

View File

@@ -0,0 +1,44 @@
/**
* 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 {run} from 'envinfo';
export type EnvironmentInfo = {
SDKs: {
'iOS SDK': {
Platforms: string[];
};
'Android SDK':
| {
'API Levels': string[] | 'Not Found';
'Build Tools': string[] | 'Not Found';
'System Images': string[] | 'Not Found';
'Android NDK': string | 'Not Found';
}
| 'Not Found';
};
IDEs: {
Xcode: {
version: string;
path: string;
};
};
};
export async function getEnvInfo(): Promise<EnvironmentInfo> {
return JSON.parse(
await run(
{
SDKs: ['iOS SDK', 'Android SDK'],
IDEs: ['Xcode'],
},
{json: true, showNotFound: true},
),
);
}

10
doctor/src/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
/**
* 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
*/
declare module 'envinfo';

170
doctor/src/index.ts Normal file
View File

@@ -0,0 +1,170 @@
/**
* 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 {exec} from 'child_process';
import {promisify} from 'util';
import {EnvironmentInfo, getEnvInfo} from './environmentInfo';
export {getEnvInfo} from './environmentInfo';
type HealthcheckCategory = {
label: string;
isRequired: boolean;
healthchecks: Healthcheck[];
};
type Healthchecks = {
common: HealthcheckCategory;
android: HealthcheckCategory;
ios?: HealthcheckCategory;
};
type Healthcheck = {
label: string;
isRequired?: boolean;
run: (
env: EnvironmentInfo,
) => Promise<{
hasProblem: boolean;
helpUrl?: string;
}>;
};
type CategoryResult = [
string,
{
label: string;
results: Array<{
label: string;
isRequired: boolean;
result: {hasProblem: boolean};
}>;
},
];
export function getHealthchecks(): Healthchecks {
return {
common: {
label: 'Common',
isRequired: true,
healthchecks: [
{
label: 'OpenSSL Installed',
run: async (_: EnvironmentInfo) => {
const isAvailable = await commandSucceeds('openssl version');
return {
hasProblem: !isAvailable,
};
},
},
],
},
android: {
label: 'Android',
isRequired: false,
healthchecks: [
{
label: 'SDK Installed',
isRequired: true,
run: async (e: EnvironmentInfo) => ({
hasProblem: e.SDKs['Android SDK'] === 'Not Found',
}),
},
],
},
...(process.platform === 'darwin'
? {
ios: {
label: 'iOS',
isRequired: false,
healthchecks: [
{
label: 'SDK Installed',
isRequired: true,
run: async (e: EnvironmentInfo) => ({
hasProblem: e.SDKs['iOS SDK'].Platforms.length === 0,
}),
},
{
label: 'XCode Installed',
isRequired: true,
run: async (e: EnvironmentInfo) => ({
hasProblem: e.IDEs == null || e.IDEs.Xcode == null,
}),
},
{
label: 'xcode-select set',
isRequired: true,
run: async (_: EnvironmentInfo) => ({
hasProblem: !(await commandSucceeds('xcode-select -p')),
}),
},
{
label: 'Instruments exists',
isRequired: true,
run: async (_: EnvironmentInfo) => {
const hasInstruments = await commandSucceeds(
'which instruments',
);
return {
hasProblem: !hasInstruments,
};
},
},
],
},
}
: {}),
};
}
export async function runHealthchecks(): Promise<Array<CategoryResult>> {
const environmentInfo = await getEnvInfo();
const healthchecks: Healthchecks = getHealthchecks();
const results: Array<CategoryResult> = (
await Promise.all(
Object.entries(healthchecks).map(async ([key, category]) => {
if (!category) {
return null;
}
const categoryResult: CategoryResult = [
key,
{
label: category.label,
results: await Promise.all(
category.healthchecks.map(async ({label, run, isRequired}) => ({
label,
isRequired: isRequired ?? true,
result: await run(environmentInfo).catch(e => {
console.error(e);
// TODO Improve result type to be: OK | Problem(message, fix...)
return {
hasProblem: true,
};
}),
})),
),
},
];
return categoryResult;
}),
)
).filter(notNull);
return results;
}
async function commandSucceeds(command: string): Promise<boolean> {
return await promisify(exec)(command)
.then(() => true)
.catch(() => false);
}
export function notNull<T>(x: T | null | undefined): x is T {
return x !== null && x !== undefined;
}

12
doctor/tsconfig.json Normal file
View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"lib": ["es7", "dom", "es2017"],
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true
},
"include": ["src"],
"exclude": ["node_modules", "**/__tests__/*"]
}

3
doctor/tslint.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": ["tslint:recommended", "tslint-config-prettier"]
}

4316
doctor/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -66,7 +66,7 @@ function compile(buildFolder, entry) {
), ),
}, },
resolver: { resolver: {
blacklistRE: /\/(sonar|flipper-public)\/dist\/|(\.native\.js$)/, blacklistRE: /\/(sonar|flipper-public)\/(dist|doctor)\/|(\.native\.js$)/,
}, },
}, },
{ {

View File

@@ -67,7 +67,7 @@ function startMetroServer(app) {
), ),
}, },
resolver: { resolver: {
blacklistRE: /\/(sonar|flipper)\/dist\/|(\.native\.js$)/, blacklistRE: /\/(sonar|flipper)\/(dist|doctor)\/|(\.native\.js$)/,
}, },
watch: true, watch: true,
}).then(metroBundlerServer => { }).then(metroBundlerServer => {

View File

@@ -214,7 +214,7 @@ async function compilePlugin(
}, },
resolver: { resolver: {
sourceExts: ['tsx', 'ts', 'js'], sourceExts: ['tsx', 'ts', 'js'],
blacklistRE: /\/(sonar|flipper-public)\/dist\/|(\.native\.js$)/, blacklistRE: /\/(sonar|flipper-public)\/(dist|doctor)\/|(\.native\.js$)/,
}, },
}, },
{ {