Skip to content

Commit

Permalink
doctor: add types (#664)
Browse files Browse the repository at this point in the history
* doctor: add types

* --amend

* --amend

* fix install cocoapods not awaiting results
  • Loading branch information
thymikee authored Sep 9, 2019
1 parent 7de69ee commit f942c1b
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 55 deletions.
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

0 comments on commit f942c1b

Please sign in to comment.