Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

imp: add types to doctor #664

Merged
merged 4 commits into from
Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ esproposal.export_star_as=enable
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
module.name_mapper='types' -> '<PROJECT_ROOT>/types/index.js'
module.name_mapper='^types' -> '<PROJECT_ROOT>/types/index.js'

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
Expand Down
11 changes: 9 additions & 2 deletions packages/cli/src/commands/doctor/checkInstallation.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @flow
import semver from 'semver';
import commandExists from 'command-exists';

Expand All @@ -6,7 +7,7 @@ const PACKAGE_MANAGERS = {
NPM: 'NPM',
};

const isSoftwareInstalled = async command => {
const isSoftwareInstalled = async (command: string) => {
try {
await commandExists(command);

Expand All @@ -16,7 +17,13 @@ const isSoftwareInstalled = async command => {
}
};

const doesSoftwareNeedToBeFixed = ({version, versionRange}) =>
const doesSoftwareNeedToBeFixed = ({
version,
versionRange,
}: {
version: string,
versionRange: string,
}) =>
version === 'Not Found' ||
!semver.satisfies(semver.coerce(version), versionRange);

Expand Down
42 changes: 35 additions & 7 deletions packages/cli/src/commands/doctor/doctor.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// @flow
import chalk from 'chalk';
import envinfo from 'envinfo';
import {logger} from '@react-native-community/cli-tools';
import {getHealthchecks, HEALTHCHECK_TYPES} from './healthchecks';
import {getLoader} from '../../tools/loader';
import printFixOptions, {KEYS} from './printFixOptions';
import runAutomaticFix, {AUTOMATIC_FIX_LEVELS} from './runAutomaticFix';
import type {ConfigT} from 'types';
import type {HealthCheckInterface} from './types';

const printCategory = ({label, key}) => {
if (key > 0) {
Expand All @@ -14,7 +17,15 @@ const printCategory = ({label, key}) => {
logger.log(chalk.dim(label));
};

const printIssue = ({label, needsToBeFixed, isRequired}) => {
const printIssue = ({
label,
needsToBeFixed,
isRequired,
}: {
label: string,
needsToBeFixed: boolean,
isRequired: boolean,
}) => {
const symbol = needsToBeFixed
? isRequired
? chalk.red('✖')
Expand All @@ -29,7 +40,16 @@ const printOverallStats = ({errors, warnings}) => {
logger.log(`${chalk.bold('Warnings:')} ${warnings}`);
};

export default (async function runDoctor(argv, ctx, options) {
type FlagsT = {
fix: boolean | void,
contributor: boolean | void,
};

export default (async function runDoctor(
argv: Array<string>,
ctx: ConfigT,
options: FlagsT,
) {
const Loader = getLoader();
const loader = new Loader();

Expand All @@ -48,25 +68,31 @@ export default (async function runDoctor(argv, ctx, options) {
),
);

const iterateOverHealthChecks = async ({label, healthchecks}) => ({
const iterateOverHealthChecks = async ({
label,
healthchecks,
}: {
label: string,
healthchecks: Array<HealthCheckInterface>,
}) => ({
label,
healthchecks: (await Promise.all(
healthchecks.map(async healthcheck => {
if (healthcheck.visible === false) {
return;
}

const {needsToBeFixed} = healthcheck.getDiagnostics
? healthcheck.getDiagnostics(environmentInfo)
: await healthcheck.getDiagnosticsAsync(environmentInfo);
const {needsToBeFixed} = await healthcheck.getDiagnostics(
environmentInfo,
);

// Assume that it's required unless specified otherwise
const isRequired = healthcheck.isRequired !== false;
const isWarning = needsToBeFixed && !isRequired;

return {
label: healthcheck.label,
needsToBeFixed,
needsToBeFixed: Boolean(needsToBeFixed),
runAutomaticFix: healthcheck.runAutomaticFix,
isRequired,
type: needsToBeFixed
Expand All @@ -87,6 +113,7 @@ export default (async function runDoctor(argv, ctx, options) {
);

const iterateOverCategories = categories =>
// $FlowFixMe - bad Object.values typings
Promise.all(categories.map(iterateOverHealthChecks));

const healthchecksPerCategory = await iterateOverCategories(
Expand Down Expand Up @@ -129,6 +156,7 @@ export default (async function runDoctor(argv, ctx, options) {
}

const onKeyPress = async key => {
// $FlowFixMe
process.stdin.setRawMode(false);
process.stdin.removeAllListeners('data');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// @flow
import chalk from 'chalk';
import Ora from 'ora';
import {logManualInstallation} from './common';
import type {HealthCheckInterface} from '../types';

// List of answers on how to set `ANDROID_HOME` for each platform
const URLS = {
Expand All @@ -10,12 +13,12 @@ const URLS = {

const label = 'ANDROID_HOME';

export default {
export default ({
label,
getDiagnostics: () => ({
getDiagnostics: async () => ({
needsToBeFixed: !process.env.ANDROID_HOME,
}),
runAutomaticFix: async ({loader}) => {
runAutomaticFix: async ({loader}: {loader: typeof Ora}) => {
loader.info();

logManualInstallation({
Expand All @@ -24,4 +27,4 @@ export default {
)}.`,
});
},
};
}: HealthCheckInterface);
17 changes: 13 additions & 4 deletions packages/cli/src/commands/doctor/healthchecks/androidNDK.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
// @flow
import chalk from 'chalk';
import Ora from 'ora';
import {logManualInstallation} from './common';
import versionRanges from '../versionRanges';
import {doesSoftwareNeedToBeFixed} from '../checkInstallation';
import type {EnvironmentInfo, HealthCheckInterface} from '../types';

export default {
export default ({
label: 'Android NDK',
getDiagnosticsAsync: async ({SDKs}) => ({
getDiagnostics: async ({SDKs}: EnvironmentInfo) => ({
needsToBeFixed: doesSoftwareNeedToBeFixed({
version: SDKs['Android SDK']['Android NDK'],
versionRange: versionRanges.ANDROID_NDK,
}),
}),
runAutomaticFix: async ({loader, environmentInfo}) => {
runAutomaticFix: async ({
loader,
environmentInfo,
}: {
loader: typeof Ora,
environmentInfo: EnvironmentInfo,
}) => {
const version = environmentInfo.SDKs['Android SDK']['Android NDK'];
const isNDKInstalled = version !== 'Not Found';

Expand All @@ -30,4 +39,4 @@ export default {
url: 'https://developer.android.com/ndk/downloads',
});
},
};
}: HealthCheckInterface);
31 changes: 22 additions & 9 deletions packages/cli/src/commands/doctor/healthchecks/androidSDK.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
// @flow
import chalk from 'chalk';
import Ora from 'ora';
import {logManualInstallation} from './common';
import versionRanges from '../versionRanges';
import {doesSoftwareNeedToBeFixed} from '../checkInstallation';
import execa from 'execa';
import type {EnvironmentInfo, HealthCheckInterface} from '../types';

const installMessage = `Read more about how to update Android SDK at ${chalk.dim(
'https://developer.android.com/studio',
)}`;

export default {
export default ({
label: 'Android SDK',
getDiagnosticsAsync: async ({SDKs}) => {
getDiagnostics: async ({SDKs}: EnvironmentInfo) => {
let sdks = SDKs['Android SDK'];

// This is a workaround for envinfo's Android SDK check not working on
// Windows. This can be removed when envinfo fixes it.
// See the PR: https://github.com/tabrindle/envinfo/pull/119
if (sdks === 'Not Found' && process.platform !== 'darwin') {
try {
// $FlowFixMe bad execa types
const {stdout} = await execa(
process.env.ANDROID_HOME
? `${process.env.ANDROID_HOME}/tools/bin/sdkmanager`
Expand All @@ -29,7 +33,9 @@ export default {
const regex = /build-tools;([\d|.]+)[\S\s]/g;
let match = null;
while ((match = regex.exec(stdout)) !== null) {
matches.push(match[1]);
if (match) {
matches.push(match[1]);
}
}
if (matches.length > 0) {
sdks = {
Expand All @@ -42,13 +48,20 @@ export default {
return {
needsToBeFixed:
(sdks === 'Not Found' && installMessage) ||
doesSoftwareNeedToBeFixed({
version: sdks['Build Tools'][0],
versionRange: versionRanges.ANDROID_NDK,
}),
(sdks !== 'Not Found' &&
doesSoftwareNeedToBeFixed({
version: sdks['Build Tools'][0],
versionRange: versionRanges.ANDROID_NDK,
})),
};
},
runAutomaticFix: async ({loader, environmentInfo}) => {
runAutomaticFix: async ({
loader,
environmentInfo,
}: {
loader: typeof Ora,
environmentInfo: EnvironmentInfo,
}) => {
const version = environmentInfo.SDKs['Android SDK'][0];
const isNDKInstalled = version !== 'Not Found';

Expand All @@ -65,4 +78,4 @@ export default {
url: 'https://facebook.github.io/react-native/docs/getting-started',
});
},
};
}: HealthCheckInterface);
8 changes: 5 additions & 3 deletions packages/cli/src/commands/doctor/healthchecks/cocoaPods.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// @flow
import {isSoftwareInstalled} from '../checkInstallation';
import {installCocoaPods} from '../../../tools/installPods';
import {type HealthCheckInterface} from '../types';

export default {
export default ({
label: 'CocoaPods',
getDiagnosticsAsync: async () => ({
getDiagnostics: async () => ({
needsToBeFixed: !(await isSoftwareInstalled('pod')),
}),
runAutomaticFix: async ({loader}) => await installCocoaPods(loader),
};
}: HealthCheckInterface);
13 changes: 12 additions & 1 deletion packages/cli/src/commands/doctor/healthchecks/common.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
// @flow
import logger from '@react-native-community/cli-tools/build/logger';
import chalk from 'chalk';

// Space is necessary to keep correct ordering on screen
const logMessage = message => logger.log(` ${message}`);

const logManualInstallation = ({healthcheck, url, command, message}) => {
const logManualInstallation = ({
healthcheck = '',
url,
command,
message,
}: {
healthcheck?: string,
url?: string,
command?: string,
message?: string,
}) => {
if (message) {
return logMessage(message);
}
Expand Down
9 changes: 7 additions & 2 deletions packages/cli/src/commands/doctor/healthchecks/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @flow
import nodeJS from './nodeJS';
import {yarn, npm} from './packageManagers';
import watchman from './watchman';
Expand All @@ -13,7 +14,12 @@ export const HEALTHCHECK_TYPES = {
WARNING: 'WARNING',
};

export const getHealthchecks = ({contributor}) => ({
type Options = {
fix: boolean | void,
contributor: boolean | void,
};

export const getHealthchecks = ({contributor}: Options) => ({
common: {
label: 'Common',
healthchecks: [
Expand All @@ -25,7 +31,6 @@ export const getHealthchecks = ({contributor}) => ({
},
android: {
label: 'Android',
// TODO: Android NDK should be shown only with a special flag
healthchecks: [
androidHomeEnvVariable,
androidSDK,
Expand Down
12 changes: 8 additions & 4 deletions packages/cli/src/commands/doctor/healthchecks/iosDeploy.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// @flow
import execa from 'execa';
import Ora from 'ora';
import {isSoftwareInstalled, PACKAGE_MANAGERS} from '../checkInstallation';
import {packageManager} from './packageManagers';
import {logManualInstallation} from './common';
import type {HealthCheckInterface} from '../types';

const getInstallationCommand = () => {
if (packageManager === PACKAGE_MANAGERS.YARN) {
Expand All @@ -15,13 +18,13 @@ const getInstallationCommand = () => {
return undefined;
};

export default {
export default ({
label: 'ios-deploy',
isRequired: false,
getDiagnosticsAsync: async () => ({
getDiagnostics: async () => ({
needsToBeFixed: !(await isSoftwareInstalled('ios-deploy')),
}),
runAutomaticFix: async ({loader}) => {
runAutomaticFix: async ({loader}: {loader: typeof Ora}) => {
const installationCommand = getInstallationCommand();

// This means that we couldn't "guess" the package manager
Expand All @@ -33,6 +36,7 @@ export default {
healthcheck: 'ios-deploy',
url: 'https://github.com/ios-control/ios-deploy#readme',
});
return;
}

try {
Expand All @@ -51,4 +55,4 @@ export default {
});
}
},
};
}: HealthCheckInterface);
Loading