Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8e608e1
remove pod installation from init process
TMisiukiewicz Sep 21, 2023
1b83851
create dependency hashes and store it in cache
TMisiukiewicz Sep 21, 2023
2489a9c
move installPods from doctor to platform-ios
TMisiukiewicz Sep 21, 2023
220f78a
install pods on run-ios and build-ios
TMisiukiewicz Sep 21, 2023
a6bea5e
add --force-pods flag to run-ios
TMisiukiewicz Sep 21, 2023
afc3acb
add tests
TMisiukiewicz Sep 21, 2023
a108f68
add tests for pods installation
TMisiukiewicz Sep 21, 2023
7ee08d0
use crypto and rename releaseCacheManager to cacheManager
TMisiukiewicz Sep 21, 2023
bedd5d9
move run sudo to cli-tools
TMisiukiewicz Sep 21, 2023
628cd79
use findPodfilePath
TMisiukiewicz Sep 21, 2023
81ad72a
resolve only native dependencies for pod check
TMisiukiewicz Sep 21, 2023
a3b9248
update pod installation tests
TMisiukiewicz Sep 21, 2023
6b7dbef
add version property to dependency config & use it to hash dependencies
TMisiukiewicz Sep 21, 2023
8fd0b65
cr updates
TMisiukiewicz Sep 21, 2023
573a047
add pod installation prompt to init
TMisiukiewicz Sep 21, 2023
ce2e11c
better error handling when package.json not found
TMisiukiewicz Sep 21, 2023
d2cd20f
add --install-pods flag to init
TMisiukiewicz Sep 21, 2023
560b32b
update tests
TMisiukiewicz Sep 21, 2023
5f32ae5
fix config tests
TMisiukiewicz Sep 21, 2023
86a547e
set hash in cache when initializing new project
TMisiukiewicz Sep 21, 2023
5f386b4
try/catch require package.json
TMisiukiewicz Sep 21, 2023
9754e12
update type for installCocoaPods
TMisiukiewicz Sep 21, 2023
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 __e2e__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ beforeAll(() => {

// Initialise React Native project

runCLI(DIR, ['init', 'TestProject']);
runCLI(DIR, ['init', 'TestProject', '--install-pods']);

// Link CLI to the project
const pkgs = [
Expand Down
15 changes: 14 additions & 1 deletion __e2e__/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ test('init fails if the directory already exists', () => {

test('init should prompt for the project name', () => {
createCustomTemplateFiles();
const {stdout} = runCLI(DIR, ['init', 'test', '--template', templatePath]);
const {stdout} = runCLI(DIR, [
'init',
'test',
'--template',
templatePath,
'--install-pods',
'false',
]);

(prompts as jest.MockedFunction<typeof prompts>).mockReturnValue(
Promise.resolve({
Expand All @@ -79,6 +86,8 @@ test('init --template filepath', () => {
'--template',
templatePath,
'TestInit',
'--install-pods',
'false',
]);

expect(stdout).toContain('Run instructions');
Expand All @@ -103,6 +112,8 @@ test('init --template file with custom directory', () => {
projectName,
'--directory',
'custom-path',
'--install-pods',
'false',
]);

// make sure --directory option is used in run instructions
Expand Down Expand Up @@ -149,6 +160,8 @@ test('init uses npm as the package manager with --npm', () => {
templatePath,
'TestInit',
'--npm',
'--install-pods',
'false',
]);

expect(stdout).toContain('Run instructions');
Expand Down
3 changes: 1 addition & 2 deletions __e2e__/root.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ beforeAll(() => {
writeFiles(cwd, {});

// Initialise React Native project
runCLI(cwd, ['init', 'TestProject']);

runCLI(cwd, ['init', 'TestProject', '--install-pods']);
// Link CLI to the project
const pkgs = [
'@react-native-community/cli-platform-ios',
Expand Down
4 changes: 4 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ module.exports = {

Skip dependencies installation

#### `--install-pods [boolean]`

Determine if CocoaPods should be installed when initializing a project. If set to `true` it will install pods, if set to `false`, it will skip the step entirely. If not used, prompt will be displayed

#### `--npm`
> [!WARNING]
> `--npm` is deprecated and will be removed in the future. Please use `--pm npm` instead.
Expand Down
1 change: 1 addition & 0 deletions docs/platforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ On Android and iOS, this function returns a dependency configuration for:
```ts
type IOSDependencyConfig = {
podspecPath: string;
version: string;
scriptPhases: Array<IOSScriptPhase>;
configurations: string[];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Object {
],
"podspecPath": "<<REPLACED>>/node_modules/react-native-test/ReactNativeTest.podspec",
"scriptPhases": Array [],
"version": "unresolved",
},
},
"root": "<<REPLACED>>/node_modules/react-native-test",
Expand Down Expand Up @@ -57,6 +58,7 @@ Object {
"path": "./phase.sh",
},
],
"version": "unresolved",
},
},
"root": "<<REPLACED>>/node_modules/react-native-test",
Expand Down Expand Up @@ -107,6 +109,7 @@ Object {
"show_env_vars_in_log": false,
},
],
"version": "unresolved",
},
},
"root": "<<REPLACED>>/node_modules/react-native-test",
Expand All @@ -131,6 +134,7 @@ Object {
"configurations": Array [],
"podspecPath": "<<REPLACED>>/node_modules/react-native-test/ReactNativeTest.podspec",
"scriptPhases": Array [],
"version": "unresolved",
},
},
"root": "<<REPLACED>>/node_modules/react-native-test",
Expand All @@ -149,6 +153,7 @@ Object {
],
"podspecPath": "<<REPLACED>>/node_modules/react-native-test/ReactNativeTest.podspec",
"scriptPhases": Array [],
"version": "unresolved",
},
},
"root": "<<REPLACED>>/node_modules/react-native-test",
Expand Down
9 changes: 9 additions & 0 deletions packages/cli-config/src/__tests__/index-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ test('supports dependencies from user configuration with custom root and propert
writeFiles(DIR, {
...REACT_NATIVE_MOCK,
'native-libs/local-lib/LocalRNLibrary.podspec': '',
'native-libs/local-lib/package.json': `
{
"name": "local-lib",
"version": "0.0.1",
"dependencies": {
"react-native": "0.0.1"
}
}`,
'react-native.config.js': `
const path = require('path');
const root = path.resolve('${escapePathSeparator(
Expand Down Expand Up @@ -276,6 +284,7 @@ module.exports = {
"configurations": Array [],
"podspecPath": "custom-path",
"scriptPhases": Array [],
"version": "0.0.1",
},
},
"root": "<<REPLACED>>/native-libs/local-lib",
Expand Down
1 change: 1 addition & 0 deletions packages/cli-config/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export const projectConfig = t
// IOSDependencyConfig
.object({
podspecPath: t.string(),
version: t.string(),
configurations: t.array().items(t.string()).default([]),
scriptPhases: t.array().items(t.object()).default([]),
})
Expand Down
1 change: 0 additions & 1 deletion packages/cli-doctor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"prompts": "^2.4.2",
"semver": "^7.5.2",
"strip-ansi": "^5.2.0",
"sudo-prompt": "^9.0.0",
"wcwidth": "^1.0.1",
"yaml": "^2.2.1"
},
Expand Down
1 change: 0 additions & 1 deletion packages/cli-doctor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,3 @@ export const commands = {info, doctor};
* refactor the init in order to remove that connection.
*/
export {default as versionRanges} from './tools/versionRanges';
export {default as installPods} from './tools/installPods';
2 changes: 1 addition & 1 deletion packages/cli-doctor/src/tools/healthchecks/cocoaPods.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import execa from 'execa';
import {runSudo} from '@react-native-community/cli-tools';
import {doesSoftwareNeedToBeFixed} from '../checkInstallation';
import {runSudo} from '../installPods';
import {logError} from './common';
import {HealthCheckInterface} from '../../types';
import versionRanges from '../versionRanges';
Expand Down
6 changes: 6 additions & 0 deletions packages/cli-platform-ios/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ Installs passed binary instead of building a fresh one.
> default: false

List all available iOS devices and simulators and let you choose one to run the app.
#### `--force-pods`,

Force running `pod install` before running an app

### `build-ios`

Expand Down Expand Up @@ -165,6 +168,9 @@ Example:
npx react-native build-ios --extra-params "-jobs 4"
```

#### `--force-pods`,

Force running `pod install` before building an app
### `log-ios`

Usage:
Expand Down
134 changes: 134 additions & 0 deletions packages/cli-platform-ios/src/__tests__/pods.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import {writeFiles, getTempDirectory, cleanup} from '../../../../jest/helpers';
import installPods from '../tools/installPods';
import resolvePods, {compareMd5Hashes, getIosDependencies} from '../tools/pods';

const mockGet = jest.fn();
const mockSet = jest.fn();
jest.mock('@react-native-community/cli-tools', () => ({
...Object.assign(jest.requireActual('@react-native-community/cli-tools')),
cacheManager: {
get: mockGet,
set: mockSet,
},
}));
jest.mock('../tools/installPods', () => jest.fn());
const dependencyHash = 'd41d8cd98f00b204e9800998ecf8427e';

const packageJson = {
name: 'test-package',
dependencies: {dep1: '1.0.0'},
devDependencies: {dep2: '1.0.0'},
};

const commonDepConfig = {
root: '',
platforms: {
ios: {
podspecPath: '',
version: '1.0.0',
scriptPhases: [],
configurations: [],
},
},
};

const dependenciesConfig = {
dep1: {
name: 'dep1',
...commonDepConfig,
},
dep2: {
name: 'dep2',
...commonDepConfig,
},
};

const DIR = getTempDirectory('root_test');

const createTempFiles = (rest?: Record<string, string>) => {
writeFiles(DIR, {
'package.json': JSON.stringify(packageJson),
...rest,
});
};

beforeEach(async () => {
await cleanup(DIR);
jest.resetAllMocks();
});

describe('compareMd5Hashes', () => {
it('should return false if hashes are different', () => {
const result = compareMd5Hashes('hash1', 'hash2');

expect(result).toBe(false);
});

it('should return true if hashes are the same', () => {
const result = compareMd5Hashes('hash', 'hash');

expect(result).toBe(true);
});
});

describe('getIosDependencies', () => {
it('should return only dependencies with native code', () => {
const result = getIosDependencies(dependenciesConfig);
expect(result).toEqual(['dep1@1.0.0', 'dep2@1.0.0']);
});
});

describe('resolvePods', () => {
it('should install pods if they are not installed', async () => {
createTempFiles({'ios/Podfile/Manifest.lock': ''});

await resolvePods(DIR, {});

expect(installPods).toHaveBeenCalled();
});

it('should install pods when force option is set to true', async () => {
createTempFiles();

await resolvePods(DIR, {}, {forceInstall: true});

expect(installPods).toHaveBeenCalled();
});

it('should install pods when there is no cached hash of dependencies', async () => {
createTempFiles();

await resolvePods(DIR, {});

expect(mockSet).toHaveBeenCalledWith(
packageJson.name,
'dependencies',
dependencyHash,
);
});

it('should skip pods installation if the cached hash and current hash are the same', async () => {
createTempFiles({'ios/Pods/Manifest.lock': ''});

mockGet.mockImplementation(() => dependencyHash);

await resolvePods(DIR, {});

expect(installPods).not.toHaveBeenCalled();
});

it('should install pods if the cached hash and current hash are different', async () => {
createTempFiles({'ios/Pods/Manifest.lock': ''});

mockGet.mockImplementation(() => dependencyHash);

await resolvePods(DIR, {
dep1: {
name: 'dep1',
...commonDepConfig,
},
});

expect(installPods).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type BuildFlags = {
interactive?: boolean;
destination?: string;
extraParams?: string[];
forcePods?: boolean;
};

export const buildOptions = [
Expand Down
4 changes: 4 additions & 0 deletions packages/cli-platform-ios/src/commands/buildIOS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ import {buildProject} from './buildProject';
import {BuildFlags, buildOptions} from './buildOptions';
import {getConfiguration} from './getConfiguration';
import {getXcodeProjectAndDir} from './getXcodeProjectAndDir';
import resolvePods from '../../tools/pods';

async function buildIOS(_: Array<string>, ctx: Config, args: BuildFlags) {
const {xcodeProject, sourceDir} = getXcodeProjectAndDir(ctx.project.ios);

// check if pods need to be installed
await resolvePods(ctx.root, ctx.dependencies, {forceInstall: args.forcePods});

process.chdir(sourceDir);

const {scheme, mode} = await getConfiguration(xcodeProject, sourceDir, args);
Expand Down
4 changes: 4 additions & 0 deletions packages/cli-platform-ios/src/commands/runIOS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import listIOSDevices from '../../tools/listIOSDevices';
import {promptForDeviceSelection} from '../../tools/prompts';
import getSimulators from '../../tools/getSimulators';
import {getXcodeProjectAndDir} from '../buildIOS/getXcodeProjectAndDir';
import resolvePods from '../../tools/pods';

export interface FlagsT extends BuildFlags {
simulator?: string;
Expand All @@ -47,6 +48,9 @@ async function runIOS(_: Array<string>, ctx: Config, args: FlagsT) {

let {packager, port} = args;

// check if pods need to be installed
await resolvePods(ctx.root, ctx.dependencies, {forceInstall: args.forcePods});

const packagerStatus = await isPackagerRunning(port);

if (
Expand Down
Loading