Skip to content
Closed
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
35 changes: 17 additions & 18 deletions docs/healthChecks.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Health Check Plugins

Plugins can be used to extend the health checks that `npx 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.
Plugins can be used to extend the health checks that `npx 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.
See [`Plugins`](./plugins.md) for information about how plugins work.

## How does it work?

Expand All @@ -21,7 +21,7 @@ module.exports = {
}),
runAutomaticFix: async ({loader}) => {
await installBar();
loader.succeed();
loader.success();
},
},
],
Expand Down Expand Up @@ -61,9 +61,7 @@ type HealthCheckInterface = {
visible?: boolean | void;
isRequired?: boolean;
description: string;
getDiagnostics: (
environmentInfo: EnvironmentInfo,
) => Promise<{
getDiagnostics: (environmentInfo: EnvironmentInfo) => Promise<{
version?: string;
versions?: [string];
versionRange?: string;
Expand Down Expand Up @@ -94,7 +92,7 @@ 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 component (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
Functions which performs the actual check. Simple checks can just return `needsToBeFixed`. Checks which are looking at versions of an installed component (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`

Expand All @@ -116,7 +114,7 @@ This function will be used to try to fix the issue when `react-native doctor` is

```ts
type RunAutomaticFix = (args: {
loader: Ora;
loader: Spinner;
logManualInstallation: ({
healthcheck,
url,
Expand All @@ -134,7 +132,7 @@ type RunAutomaticFix = (args: {

##### `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.
A reference to a [`nanospinner`](https://www.npmjs.com/package/nanospinner) instance which should be used to report success / failure, and progress of the fix. The fix function should always call either `loader.success()` or `loader.error()` before returning.

##### `logManualInstallation`

Expand All @@ -146,26 +144,27 @@ Provides information about the current system

### Examples of RunAutomaticFix implementations

A health check that requires the user to manually go download/install something. This check will immediately display a message to notify the user how to fix the issue.
A health check that requires the user to manually go download/install something. This check will immediately display a message to notify the user how to fix the issue.

```ts
async function needToInstallFoo({loader, logManualInstallation}) {
loader.fail();
loader.error();

return logManualInstallation({
healthcheck: 'Foo',
url: 'https:/foo.com/download',
});
return logManualInstallation({
healthcheck: 'Foo',
url: 'https:/foo.com/download',
});
}
```

A health check that runs some commands locally which may fix the issue. This check will display a spinner while the exec commands are running. Then once the commands are complete, the spinner will change to a checkmark.
A health check that runs some commands locally which may fix the issue. This check will display a spinner while the exec commands are running. Then once the commands are complete, the spinner will change to a checkmark.

```ts
import { exec } from 'promisify-child-process';
import {exec} from 'promisify-child-process';
async function fixFoo({loader}) {
await exec(`foo --install`);
await exec(`foo --fix`);

loader.succeed();
loader.success();
}
```
24 changes: 14 additions & 10 deletions docs/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,29 @@ module.exports = {

## Post init script loading

The responsibility of showing the user progress of the "Executing post init script" goes to the implementor. In the cli, the `ora` package is used to display progress.
For a simple usage in a custom template, `ora` can be used like this in a postInitScript :
The responsibility of showing the user progress of the "Executing post init script" goes to the implementor. In the cli, the `nanospinner` package is used to display progress.
For a simple usage in a custom template, `nanospinner` can be used like this in a postInitScript :

```javascript
#!/usr/bin/env node
const ora = require('ora');
const {createSpinner} = require('nanospinner');

const spinner = ora('Executing post init script ');
const spinner = createSpinner('Executing post init script ');

new Promise((resolve) => {
spinner.start();
// do something
resolve();
}).then(() => {
spinner.succeed();
}).catch(() => {
spinner.fail();
throw new Error('Something went wrong during the post init script execution');
});
})
.then(() => {
spinner.success();
})
.catch(() => {
spinner.error();
throw new Error(
'Something went wrong during the post init script execution',
);
});
```

You can find example custom template [here](https://github.com/Esemesek/react-native-new-template).
Expand Down
4 changes: 2 additions & 2 deletions packages/cli-clean/src/clean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,10 @@ export async function clean(
spinner.start(label);
await action()
.then(() => {
spinner.succeed();
spinner.success();
})
.catch((e) => {
spinner.fail(`${label} » ${e}`);
spinner.error(`${label} » ${e}`);
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli-config-apple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"devDependencies": {
"@react-native-community/cli-types": "20.0.2",
"ora": "^5.4.1"
"nanospinner": "^1.0.0"
},
"files": [
"build",
Expand Down
18 changes: 9 additions & 9 deletions packages/cli-config-apple/src/tools/installPods.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import execa from 'execa';
import type {Ora} from 'ora';
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The import statement still references the old ora package type. This should be updated to import Spinner from nanospinner instead. The type Ora is no longer available after migrating to nanospinner.

Suggested change
import type {Ora} from 'ora';
import type {Spinner} from 'nanospinner';

Copilot uses AI. Check for mistakes.
import pico from 'picocolors';
import chalk from 'chalk';

Check failure on line 4 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

'chalk' is declared but its value is never read.

Check failure on line 4 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

'chalk' is declared but its value is never read.

Check failure on line 4 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

'chalk' is declared but its value is never read.

Check failure on line 4 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

'chalk' is declared but its value is never read.

Check failure on line 4 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

'chalk' is declared but its value is never read.
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

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

The import has been changed from pico (picocolors) to chalk, but the code still uses pico throughout the file (lines 30, 32, 86, 97, 98, 130, 131). This will cause runtime errors. Either revert to pico or update all usages to chalk.

Copilot uses AI. Check for mistakes.
import {
logger,
NoopLoader,
Expand All @@ -23,13 +23,13 @@
newArchEnabled?: boolean;
}

async function runPodInstall(loader: Ora, options: RunPodInstallOptions) {
async function runPodInstall(loader: Spinner, options: RunPodInstallOptions) {

Check failure on line 26 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'Spinner'.

Check failure on line 26 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'Spinner'.

Check failure on line 26 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'Spinner'.

Check failure on line 26 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'Spinner'.

Check failure on line 26 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'Spinner'.
const shouldHandleRepoUpdate = options?.shouldHandleRepoUpdate || true;
try {
loader.start(
`Installing CocoaPods dependencies ${pico.bold(

Check failure on line 30 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'pico'.

Check failure on line 30 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'pico'.

Check failure on line 30 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'pico'.

Check failure on line 30 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'pico'.

Check failure on line 30 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'pico'.
options?.newArchEnabled ? 'with New Architecture' : '',
)} ${pico.dim('(this may take a few minutes)')}`,

Check failure on line 32 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'pico'.

Check failure on line 32 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'pico'.

Check failure on line 32 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'pico'.

Check failure on line 32 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'pico'.

Check failure on line 32 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'pico'.
);

await execaPod(['install'], {
Expand Down Expand Up @@ -66,7 +66,7 @@
newArchEnabled: options?.newArchEnabled,
});
} else {
loader.fail();
loader.error();
logger.error(stderr);

throw new CLIError(
Expand All @@ -80,10 +80,10 @@
}
}

async function runPodUpdate(loader: Ora) {
async function runPodUpdate(loader: Spinner) {

Check failure on line 83 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'Spinner'.

Check failure on line 83 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'Spinner'.

Check failure on line 83 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'Spinner'.

Check failure on line 83 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'Spinner'.

Check failure on line 83 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'Spinner'.
try {
loader.start(
`Updating CocoaPods repositories ${pico.dim(

Check failure on line 86 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'pico'.

Check failure on line 86 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'pico'.

Check failure on line 86 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'pico'.

Check failure on line 86 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'pico'.

Check failure on line 86 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'pico'.
'(this may take a few minutes)',
)}`,
);
Expand All @@ -91,11 +91,11 @@
} catch (error) {
// "pod" command outputs errors to stdout (at least some of them)
logger.log((error as any).stderr || (error as any).stdout);
loader.fail();
loader.error();

throw new CLIError(
`Failed to update CocoaPods repositories for iOS project.\nPlease try again manually: "pod repo update".\nCocoaPods documentation: ${pico.dim(

Check failure on line 97 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'pico'.

Check failure on line 97 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'pico'.

Check failure on line 97 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'pico'.

Check failure on line 97 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'pico'.

Check failure on line 97 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'pico'.
pico.underline('https://cocoapods.org/'),

Check failure on line 98 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'pico'.

Check failure on line 98 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'pico'.

Check failure on line 98 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'pico'.

Check failure on line 98 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'pico'.

Check failure on line 98 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'pico'.
)}`,
);
}
Expand All @@ -113,17 +113,17 @@
}
}

async function installCocoaPods(loader: Ora) {
async function installCocoaPods(loader: Spinner) {

Check failure on line 116 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (22)

Cannot find name 'Spinner'.

Check failure on line 116 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'Spinner'.

Check failure on line 116 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / Unit tests (20)

Cannot find name 'Spinner'.

Check failure on line 116 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (22, ubuntu-latest)

Cannot find name 'Spinner'.

Check failure on line 116 in packages/cli-config-apple/src/tools/installPods.ts

View workflow job for this annotation

GitHub Actions / E2E Tests (20, ubuntu-latest)

Cannot find name 'Spinner'.
loader.stop();

loader.start('Installing CocoaPods');

try {
await installCocoaPodsWithGem();

return loader.succeed();
return loader.success();
} catch (error) {
loader.fail();
loader.error();
logger.error((error as any).stderr);

throw new CLIError(
Expand All @@ -134,7 +134,7 @@
}
}

async function installPods(loader?: Ora, options?: PodInstallOptions) {
async function installPods(loader?: Spinner, options?: PodInstallOptions) {
loader = loader || new NoopLoader();
try {
if (!options?.iosFolderPath && !fs.existsSync('ios')) {
Expand Down
12 changes: 6 additions & 6 deletions packages/cli-config-apple/src/tools/pods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ async function install(
root: string,
reactNativePath: string,
) {
const loader = getLoader('Installing CocoaPods...');
const loader = getLoader({text: 'Installing CocoaPods...'});
try {
await runCodegen({
root,
Expand All @@ -108,9 +108,9 @@ async function install(
iosFolderPath,
});
cacheManager.set(packageJson.name, 'dependencies', currentDependenciesHash);
loader.succeed();
loader.success();
} catch (error) {
loader.fail();
loader.error();
throw new CLIError(
`Something went wrong while installing CocoaPods. Please run ${pico.bold(
'pod install',
Expand Down Expand Up @@ -184,7 +184,7 @@ export default async function resolvePods(
currentPodfileLockChecksum ?? '',
);
} else {
const loader = getLoader('Installing CocoaPods...');
const loader = getLoader({text: 'Installing CocoaPods...'});
try {
await installPods(loader, {
skipBundleInstall: !!cachedDependenciesHash,
Expand All @@ -204,9 +204,9 @@ export default async function resolvePods(
'podfileLock',
currentPodfileLockChecksum ?? '',
);
loader.succeed();
loader.success();
} catch (error) {
loader.fail();
loader.error();
throw new CLIError(
`Something went wrong while installing CocoaPods. Please run ${pico.bold(
'pod install',
Expand Down
8 changes: 4 additions & 4 deletions packages/cli-config-apple/src/tools/runBundleInstall.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import execa from 'execa';
import {CLIError, logger, link} from '@react-native-community/cli-tools';
import type {Ora} from 'ora';
import type {Spinner} from 'nanospinner';

async function runBundleInstall(loader: Ora) {
async function runBundleInstall(loader: Spinner) {
try {
loader.start('Installing Ruby Gems');

await execa('bundle', ['install']);
} catch (error) {
loader.fail();
loader.error();
logger.error((error as any).stderr || (error as any).stdout);
throw new CLIError(
`Looks like your iOS environment is not properly set. Please go to ${link.docs(
Expand All @@ -19,7 +19,7 @@ async function runBundleInstall(loader: Ora) {
);
}

loader.succeed();
loader.success();
}

export default runBundleInstall;
2 changes: 1 addition & 1 deletion packages/cli-doctor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"deepmerge": "^4.3.0",
"envinfo": "^7.13.0",
"execa": "^5.0.0",
"nanospinner": "^1.0.0",
"node-stream-zip": "^1.9.1",
"ora": "^5.4.1",
"picocolors": "^1.1.1",
"semver": "^7.5.2",
"wcwidth": "^1.0.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli-doctor/src/tools/brewInstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async function brewInstall({
return onSuccess();
}

return loader.succeed();
return loader.success();
} catch (error) {
if (typeof onFail === 'function') {
return onFail();
Expand Down
2 changes: 1 addition & 1 deletion packages/cli-doctor/src/tools/downloadAndUnzip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const downloadAndUnzip = async ({

const installer = await fetchToTemp(downloadUrl);

loader.text = `Installing ${component} in "${installPath}"`;
loader.update(`Installing ${component} in "${installPath}"`);
try {
await unzip(installer, installPath);
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ describe('androidSDK', () => {
'android/build.gradle': `
buildscript {
ext {
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '34.0.0'
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '34.0.0'
minSdkVersion = 16
compileSdkVersion = 28
targetSdkVersion = 28
Expand Down Expand Up @@ -123,8 +123,8 @@ describe('androidSDK', () => {

it('installs the SDK if it is missing on Windows', async () => {
const loader = new tools.NoopLoader();
const loaderSucceedSpy = jest.spyOn(loader, 'succeed');
const loaderFailSpy = jest.spyOn(loader, 'fail');
const loaderSuccessSpy = jest.spyOn(loader, 'success');
const loaderErrorSpy = jest.spyOn(loader, 'error');
const downloadAndUnzipSpy = jest
.spyOn(downloadAndUnzip, 'downloadAndUnzip')
.mockImplementation(() => Promise.resolve());
Expand Down Expand Up @@ -178,10 +178,10 @@ describe('androidSDK', () => {
expect(requiredComponents.includes(call[0])).toBeTruthy();
}

expect(loaderFailSpy).toHaveBeenCalledTimes(0);
expect(loaderErrorSpy).toHaveBeenCalledTimes(0);
expect(logSpy).toHaveBeenCalledTimes(0);

expect(loaderSucceedSpy).toBeCalledWith(
expect(loaderSuccessSpy).toBeCalledWith(
'Android SDK configured. You might need to restart your PC for all changes to take effect.',
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ describe('androidStudio', () => {

it('downloads and unzips Android Studio on Windows when missing', async () => {
const loader = new NoopLoader();
const loaderSucceedSpy = jest.spyOn(loader, 'succeed');
const loaderFailSpy = jest.spyOn(loader, 'fail');
const loaderSuccessSpy = jest.spyOn(loader, 'success');
const loaderErrorSpy = jest.spyOn(loader, 'error');
const downloadAndUnzipSpy = jest
.spyOn(downloadAndUnzip, 'downloadAndUnzip')
.mockImplementation(() => Promise.resolve());
Expand All @@ -65,10 +65,10 @@ describe('androidStudio', () => {
environmentInfo,
});

expect(loaderFailSpy).toHaveBeenCalledTimes(0);
expect(loaderErrorSpy).toHaveBeenCalledTimes(0);
expect(logSpy).toHaveBeenCalledTimes(0);
expect(downloadAndUnzipSpy).toBeCalledTimes(1);
expect(loaderSucceedSpy).toBeCalledWith(
expect(loaderSuccessSpy).toBeCalledWith(
`Android Studio installed successfully in "${
downloadAndUnzipSpy.mock.calls[0][0].installPath || ''
}".`,
Expand Down
Loading
Loading