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

Allow platforms and community packages to provide additional health checks #1231

Merged
merged 10 commits into from
Sep 21, 2020
147 changes: 147 additions & 0 deletions docs/healthChecks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Health Check Plugins

Plugins can be used to extend the health checks that `react-native doctor` runs. This can be used to add additional checks for out of tree platforms, or other checks that are specific to a community module.

See [`Plugins`](./plugins.md) for information about how plugins work.


## How does it work?

To provide additional health checks, a package needs to have a `react-native.config.js` at the root folder in order to be discovered by the CLI as a plugin.

```js
module.exports = {
healthChecks: [
{
label: 'Foo',
healthchecks: [
label: 'bar-installed',
getDiagnostics: async () => ({
needsToBeFixed: !isBarInstalled()
}),
runAutomaticFix: async ({loader}) => {
await installBar();
loader.succeed();
},
}
],
};
```
Comment on lines +12 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so awesome.


> Above is an example of a plugin that extends the healthChecks performed by `react-native doctor` to check if `bar` is installed.

At the startup, React Native CLI reads configuration from all dependencies listed in `package.json` and reduces them into a single configuration.

At the end, an array of health check categories is concatenated to be checked when `react-native doctor` is run.


## HealthCheckCategory interface

```ts
type HealthCheckCategory = {
label: string;
healthchecks: HealthCheckInterface[];
};
```

##### `label`

Name of the category for this health check. This will be used to group health checks in doctor.

##### `healthChecks`

Array of health checks to perorm in this category


## HealthCheckInterface interface

```ts
type HealthCheckInterface = {
label: string;
visible?: boolean | void;
isRequired?: boolean;
description?: string;
getDiagnostics: (
environmentInfo: EnvironmentInfo,
) => Promise<{
version?: string;
versions?: [string];
versionRange?: string;
needsToBeFixed: boolean | string;
}>;
win32AutomaticFix?: RunAutomaticFix;
darwinAutomaticFix?: RunAutomaticFix;
linuxAutomaticFix?: RunAutomaticFix;
runAutomaticFix: RunAutomaticFix;
};
```

##### `label`

Name of this health check

##### `visible`

If set to false, doctor will ignore this health check

##### `isRequired`

Is this health check required or optional?

##### `description`

Longer description of this health check


##### `getDiagnostics`

Functions which performs the actual check. Simple checks can just return `needsToBeFixed`. Checks which are looking at versions of an installed components (such as the version of node), can also return `version`, `versions` and `versionRange` to provide better information to be displayed in `react-native doctor` when running the check

##### `win32AutomaticFix`

This function will be used to try to fix the issue when `react-native doctor` is run on a windows machine. If this is not specified, `runAutomaticFix` will be run instead.

##### `darwinAutomaticFix`

This function will be used to try to fix the issue when `react-native doctor` is run on a macOS machine. If this is not specified, `runAutomaticFix` will be run instead.

##### `linuxAutomaticFix`

This function will be used to try to fix the issue when `react-native doctor` is run on a linux machine. If this is not specified, `runAutomaticFix` will be run instead.

##### `runAutomaticFix`

This function will be used to try to fix the issue when `react-native doctor` is run and no more platform specific automatic fix function was provided.


## RunAutomaticFix interface

```ts
type RunAutomaticFix = (args: {
loader: Ora;
logManualInstallation: ({
healthcheck,
url,
command,
message,
}: {
healthcheck?: string;
url?: string;
command?: string;
message?: string;
}) => void;
environmentInfo: EnvironmentInfo;
}) => Promise<void> | void;
```

##### `loader`

A reference to a [`ora`](https://www.npmjs.com/package/ora) instance which should be used to report success / failure, and progress of the fix. The fix function should always call either `loader.succeed()` or `loader.fail()` before returning.

##### `logManualInstallation`

If an automated fix cannot be performed, this function should be used to provide instructions to the user on how to manually fix the issue.

##### `environmentInfo`

Provides information about the current system
3 changes: 3 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ At the startup, React Native CLI reads configuration from all dependencies liste

At the end, an array of commands concatenated from all plugins is passed on to the CLI to be loaded after built-in commands.

> See [`healthChecks`](./healthChecks.md) for information on how plugins can provide additional health checks for `react-native doctor`.

## Command interface

```ts
Expand Down Expand Up @@ -107,6 +109,7 @@ String that describes this particular usage.

A command with arguments and options (if applicable) that can be run in order to achieve the desired goal.


## Migrating from `rnpm` configuration

The changes are mostly cosmetic so the migration should be pretty straight-forward.
Expand Down
100 changes: 100 additions & 0 deletions packages/cli-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
AndroidDependencyConfig,
AndroidDependencyParams,
} from './android';
import {Ora} from './ora';
export {Ora} from './ora';

export type InquirerPrompt = any;

Expand Down Expand Up @@ -120,6 +122,100 @@ export type ProjectConfig = {
[key: string]: any;
};

export type NotFound = 'Not Found';
type AvailableInformation = {
version: string;
path: string;
};

type Information = AvailableInformation | NotFound;

export type EnvironmentInfo = {
System: {
OS: string;
CPU: string;
Memory: string;
Shell: AvailableInformation;
};
Binaries: {
Node: AvailableInformation;
Yarn: AvailableInformation;
npm: AvailableInformation;
Watchman: AvailableInformation;
};
SDKs: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the idea that this is what will get asked of envinfo? if so, please make sure that info continues to report the windows properties we care about: Windows SDKs, VS installs, dev mode reg keys.

'iOS SDK': {
Platforms: string[];
};
'Android SDK':
| {
'API Levels': string[] | NotFound;
'Build Tools': string[] | NotFound;
'System Images': string[] | NotFound;
'Android NDK': string | NotFound;
}
| NotFound;
};
IDEs: {
'Android Studio': AvailableInformation | NotFound;
Emacs: AvailableInformation;
Nano: AvailableInformation;
VSCode: AvailableInformation;
Vim: AvailableInformation;
Xcode: AvailableInformation;
};
Languages: {
Java: Information;
Python: Information;
};
};

export type HealthCheckCategory = {
label: string;
healthchecks: HealthCheckInterface[];
};

export type Healthchecks = {
common: HealthCheckCategory;
android: HealthCheckCategory;
ios?: HealthCheckCategory;
};

export type RunAutomaticFix = (args: {
loader: Ora;
logManualInstallation: ({
healthcheck,
url,
command,
message,
}: {
healthcheck?: string;
url?: string;
command?: string;
message?: string;
}) => void;
environmentInfo: EnvironmentInfo;
}) => Promise<void> | void;

export type HealthCheckInterface = {
label: string;
visible?: boolean | void;
isRequired?: boolean;
description?: string;
getDiagnostics: (
environmentInfo: EnvironmentInfo,
) => Promise<{
version?: string;
versions?: [string];
versionRange?: string;
needsToBeFixed: boolean | string;
}>;
win32AutomaticFix?: RunAutomaticFix;
darwinAutomaticFix?: RunAutomaticFix;
linuxAutomaticFix?: RunAutomaticFix;
runAutomaticFix: RunAutomaticFix;
};

/**
* @property root - Root where the configuration has been resolved from
* @property reactNativePath - Path to React Native source
Expand All @@ -128,6 +224,7 @@ export type ProjectConfig = {
* @property dependencies - Map of the dependencies that are present in the project
* @property platforms - Map of available platforms (build-ins and dynamically loaded)
* @property commands - An array of commands that are present in 3rd party packages
* @property healthChecks - An array of health check categories to add to doctor command
*/
export interface Config extends IOSNativeModulesConfig {
root: string;
Expand All @@ -151,6 +248,7 @@ export interface Config extends IOSNativeModulesConfig {
[name: string]: PlatformConfig<any, any, any, any>;
};
commands: Command[];
healthChecks: HealthCheckCategory[];
}

/**
Expand All @@ -175,6 +273,8 @@ export type UserDependencyConfig = {
commands: Command[];
// An array of extra platforms to load
platforms: Config['platforms'];
// Additional health checks
healthChecks: HealthCheckCategory[];
};

export {
Expand Down
Loading