From c34130a0dd9398e2d86f2819df7d4cd4246f5ef7 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 22 Nov 2023 20:50:46 +0100 Subject: [PATCH 1/8] recheck Xcode project when pods are installed in run-ios --- .../src/commands/runIOS/index.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/cli-platform-ios/src/commands/runIOS/index.ts b/packages/cli-platform-ios/src/commands/runIOS/index.ts index f7758a63d..cff9905c7 100644 --- a/packages/cli-platform-ios/src/commands/runIOS/index.ts +++ b/packages/cli-platform-ios/src/commands/runIOS/index.ts @@ -30,6 +30,7 @@ import getSimulators from '../../tools/getSimulators'; import {getXcodeProjectAndDir} from '../buildIOS/getXcodeProjectAndDir'; import resolvePods from '../../tools/pods'; import getArchitecture from '../../tools/getArchitecture'; +import findXcodeProject from '../../config/findXcodeProject'; export interface FlagsT extends BuildFlags { simulator?: string; @@ -46,7 +47,7 @@ async function runIOS(_: Array, ctx: Config, args: FlagsT) { link.setPlatform('ios'); let {packager, port} = args; - + let installedPods = false; // check if pods need to be installed if (ctx.project.ios?.automaticPodsInstallation || args.forcePods) { const isAppRunningNewArchitecture = ctx.project.ios?.sourceDir @@ -57,6 +58,8 @@ async function runIOS(_: Array, ctx: Config, args: FlagsT) { forceInstall: args.forcePods, newArchEnabled: isAppRunningNewArchitecture, }); + + installedPods = true; } if (packager) { @@ -79,7 +82,16 @@ async function runIOS(_: Array, ctx: Config, args: FlagsT) { link.setVersion(ctx.reactNativeVersion); } - const {xcodeProject, sourceDir} = getXcodeProjectAndDir(ctx.project.ios); + let {xcodeProject, sourceDir} = getXcodeProjectAndDir(ctx.project.ios); + + // if project is freshly created, revisit Xcode project to verify Pods are installed correctly. + // This is needed because ctx project is created before Pods are installed, so it might have outdated information. + if (installedPods) { + const recheckXcodeProject = findXcodeProject(fs.readdirSync(sourceDir)); + if (recheckXcodeProject) { + xcodeProject = recheckXcodeProject; + } + } process.chdir(sourceDir); From 63ae5b84f16b9ac173b4942abbad91d82c057802 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 22 Nov 2023 21:08:04 +0100 Subject: [PATCH 2/8] remove existing project cache on init --- packages/cli-tools/src/cacheManager.ts | 9 +++++++++ packages/cli/src/commands/init/init.ts | 3 +++ 2 files changed, 12 insertions(+) diff --git a/packages/cli-tools/src/cacheManager.ts b/packages/cli-tools/src/cacheManager.ts index 40f03c5fa..21587dc91 100644 --- a/packages/cli-tools/src/cacheManager.ts +++ b/packages/cli-tools/src/cacheManager.ts @@ -48,6 +48,14 @@ function getCacheRootPath() { return cachePath; } +function removeProjectCache(name: string) { + const fullPath = path.resolve(getCacheRootPath(), name); + + if (fs.existsSync(fullPath)) { + fs.rmSync(fullPath, {recursive: true}); + } +} + function get(name: string, key: CacheKey): string | undefined { const cache = loadCache(name); if (cache) { @@ -67,4 +75,5 @@ function set(name: string, key: CacheKey, value: string) { export default { get, set, + removeProjectCache, }; diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index 848885b34..b75ab0a02 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -383,6 +383,9 @@ export default (async function initialize( projectName = projName; } + // if the project with the name already has cache, remove the cache to avoid problems with pods installation + cacheManager.removeProjectCache(projectName); + validateProjectName(projectName); if (!!options.template && !!options.version) { From 8ffddb4aa602548e3f39e490a06b127219284614 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 22 Nov 2023 21:37:59 +0100 Subject: [PATCH 3/8] don't create config file for < 0.73 --- packages/cli/src/commands/init/init.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index b75ab0a02..701696240 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -30,6 +30,7 @@ import {getYarnVersionIfAvailable} from '../../tools/yarn'; import {createHash} from 'crypto'; import createGitRepository from './createGitRepository'; import deepmerge from 'deepmerge'; +import semver from 'semver'; const DEFAULT_VERSION = 'latest'; @@ -57,6 +58,7 @@ interface TemplateOptions { skipInstall?: boolean; packageName?: string; installCocoaPods?: string | boolean; + version?: string; } function doesDirectoryExist(dir: string) { @@ -111,6 +113,7 @@ async function createFromTemplate({ skipInstall, packageName, installCocoaPods, + version, }: TemplateOptions) { logger.debug('Initializing new project'); logger.log(banner); @@ -171,7 +174,14 @@ async function createFromTemplate({ packageName, }); - createDefaultConfigFile(projectDirectory, loader); + const coerceRnVersion = semver.valid(semver.coerce(version)); + + if ( + version === 'latest' || + (coerceRnVersion && semver.satisfies(coerceRnVersion, '>=0.73.0')) + ) { + createDefaultConfigFile(projectDirectory, loader); + } const {postInitScript} = templateConfig; if (postInitScript) { @@ -349,6 +359,7 @@ async function createProject( skipInstall: options.skipInstall, packageName: options.packageName, installCocoaPods: options.installPods, + version, }); } @@ -394,6 +405,7 @@ export default (async function initialize( const root = process.cwd(); const version = options.version || DEFAULT_VERSION; + const directoryName = path.relative(root, options.directory || projectName); if (options.pm && !checkPackageManagerAvailability(options.pm)) { From 44a36abfbb8b7c2f3ff8524f5259c6294b9e8995 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Mon, 27 Nov 2023 17:36:45 +0100 Subject: [PATCH 4/8] add tests for cacheManager removeCache --- .../src/__tests__/cacheManager.test.ts | 34 +++++++++++++++++++ packages/cli-tools/src/cacheManager.ts | 17 ++++++++-- packages/cli/src/commands/init/init.ts | 6 ++-- 3 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 packages/cli-tools/src/__tests__/cacheManager.test.ts diff --git a/packages/cli-tools/src/__tests__/cacheManager.test.ts b/packages/cli-tools/src/__tests__/cacheManager.test.ts new file mode 100644 index 000000000..29105e19d --- /dev/null +++ b/packages/cli-tools/src/__tests__/cacheManager.test.ts @@ -0,0 +1,34 @@ +import fs from 'fs'; +import path from 'path'; +import cacheManager from '../cacheManager'; + +const projectName = 'Project1'; +const cachePath = '.react-native-cli/cache'; +const fullPath = path.join(cachePath, projectName); + +describe('cacheManager', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + test('should remove cache if it exists', () => { + jest.spyOn(fs, 'existsSync').mockReturnValue(true); + jest.spyOn(fs, 'rmSync').mockImplementation(() => {}); + jest + .spyOn(path, 'resolve') + .mockReturnValue(path.join(cachePath, projectName)); + + cacheManager.removeProjectCache(projectName); + + expect(fs.rmSync).toHaveBeenCalledWith(fullPath, {recursive: true}); + }); + + test('should not remove cache if it does not exist', () => { + jest.spyOn(fs, 'existsSync').mockReturnValue(false); + jest.spyOn(fs, 'rmSync').mockImplementation(() => {}); + + cacheManager.removeProjectCache(projectName); + + expect(fs.rmSync).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/cli-tools/src/cacheManager.ts b/packages/cli-tools/src/cacheManager.ts index 21587dc91..f227445ee 100644 --- a/packages/cli-tools/src/cacheManager.ts +++ b/packages/cli-tools/src/cacheManager.ts @@ -2,6 +2,7 @@ import path from 'path'; import fs from 'fs'; import os from 'os'; import appDirs from 'appdirsjs'; +import chalk from 'chalk'; import logger from './logger'; type CacheKey = 'eTag' | 'lastChecked' | 'latestVersion' | 'dependencies'; @@ -49,10 +50,19 @@ function getCacheRootPath() { } function removeProjectCache(name: string) { - const fullPath = path.resolve(getCacheRootPath(), name); + const cacheRootPath = getCacheRootPath(); + try { + const fullPath = path.resolve(cacheRootPath, name); - if (fs.existsSync(fullPath)) { - fs.rmSync(fullPath, {recursive: true}); + if (fs.existsSync(fullPath)) { + fs.rmSync(fullPath, {recursive: true}); + } + } catch { + logger.error( + `Failed to remove cache for ${name}. If you experience any issues when running freshly initialized project, please remove ${chalk.underline( + path.join(cacheRootPath, name), + )} folder manually.`, + ); } } @@ -76,4 +86,5 @@ export default { get, set, removeProjectCache, + getCacheRootPath, }; diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index 701696240..c772bde01 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -136,6 +136,9 @@ async function createFromTemplate({ packageManager = 'npm'; } + // if the project with the name already has cache, remove the cache to avoid problems with pods installation + cacheManager.removeProjectCache(projectName); + const projectDirectory = await setProjectDirectory(directory); const loader = getLoader({text: 'Downloading template'}); @@ -394,9 +397,6 @@ export default (async function initialize( projectName = projName; } - // if the project with the name already has cache, remove the cache to avoid problems with pods installation - cacheManager.removeProjectCache(projectName); - validateProjectName(projectName); if (!!options.template && !!options.version) { From 30e3ea9d594669535377959707402555230f9887 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Mon, 27 Nov 2023 18:23:13 +0100 Subject: [PATCH 5/8] cleanup tests --- .../src/__tests__/cacheManager.test.ts | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/cli-tools/src/__tests__/cacheManager.test.ts b/packages/cli-tools/src/__tests__/cacheManager.test.ts index 29105e19d..30c1287ab 100644 --- a/packages/cli-tools/src/__tests__/cacheManager.test.ts +++ b/packages/cli-tools/src/__tests__/cacheManager.test.ts @@ -1,34 +1,37 @@ import fs from 'fs'; import path from 'path'; import cacheManager from '../cacheManager'; +import {cleanup, getTempDirectory} from '../../../../jest/helpers'; +const DIR = getTempDirectory('.react-native-cli/cache'); const projectName = 'Project1'; -const cachePath = '.react-native-cli/cache'; -const fullPath = path.join(cachePath, projectName); +const fullPath = path.join(DIR, projectName); describe('cacheManager', () => { beforeEach(() => { - jest.resetAllMocks(); + jest.restoreAllMocks(); }); - test('should remove cache if it exists', () => { - jest.spyOn(fs, 'existsSync').mockReturnValue(true); + afterEach(() => { + cleanup(DIR); + }); + + test('should not remove cache if it does not exist', () => { + jest.spyOn(fs, 'existsSync').mockReturnValue(false); jest.spyOn(fs, 'rmSync').mockImplementation(() => {}); - jest - .spyOn(path, 'resolve') - .mockReturnValue(path.join(cachePath, projectName)); cacheManager.removeProjectCache(projectName); - expect(fs.rmSync).toHaveBeenCalledWith(fullPath, {recursive: true}); + expect(fs.rmSync).not.toHaveBeenCalled(); }); - test('should not remove cache if it does not exist', () => { - jest.spyOn(fs, 'existsSync').mockReturnValue(false); + test('should remove cache if it exists', () => { + jest.spyOn(fs, 'existsSync').mockReturnValue(true); jest.spyOn(fs, 'rmSync').mockImplementation(() => {}); + jest.spyOn(path, 'resolve').mockReturnValue(fullPath); cacheManager.removeProjectCache(projectName); - expect(fs.rmSync).not.toHaveBeenCalled(); + expect(fs.rmSync).toHaveBeenCalledWith(fullPath, {recursive: true}); }); }); From e431a78bcfbbb7efb60e2afaba213ee5faa04130 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Mon, 27 Nov 2023 18:32:59 +0100 Subject: [PATCH 6/8] add init tests --- __e2e__/init.test.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/__e2e__/init.test.ts b/__e2e__/init.test.ts index d5c4391cc..0c934fdf7 100644 --- a/__e2e__/init.test.ts +++ b/__e2e__/init.test.ts @@ -194,3 +194,23 @@ test('init --platform-name should work for out of tree platform', () => { expect(dirFiles.length).toBeGreaterThan(0); }); + +test('should not create custom config file if installed version is below 0.73', () => { + createCustomTemplateFiles(); + + runCLI(DIR, ['init', PROJECT_NAME, '--skip-install', '--version', '0.72.0']); + + let dirFiles = fs.readdirSync(path.join(DIR, PROJECT_NAME)); + + expect(dirFiles).not.toContain('react-native.config.js'); +}); + +test('should create custom config file if installed version is latest (starting from 0.73)', () => { + createCustomTemplateFiles(); + + runCLI(DIR, ['init', PROJECT_NAME, '--skip-install']); + + let dirFiles = fs.readdirSync(path.join(DIR, PROJECT_NAME)); + + expect(dirFiles).toContain('react-native.config.js'); +}); From b77c50319e5a4319b1680aed684d3447867d0b7c Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 29 Nov 2023 08:56:22 +0100 Subject: [PATCH 7/8] test custom react-native.config.js content --- __e2e__/init.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/__e2e__/init.test.ts b/__e2e__/init.test.ts index 0c934fdf7..9804c32ed 100644 --- a/__e2e__/init.test.ts +++ b/__e2e__/init.test.ts @@ -213,4 +213,22 @@ test('should create custom config file if installed version is latest (starting let dirFiles = fs.readdirSync(path.join(DIR, PROJECT_NAME)); expect(dirFiles).toContain('react-native.config.js'); + const fileContent = fs.readFileSync( + path.join(DIR, PROJECT_NAME, 'react-native.config.js'), + 'utf8', + ); + + const configFileContent = ` + module.exports = { + project: { + ios: { + automaticPodsInstallation: true + } + } + }`; + + //normalize all white-spaces for easier comparision + expect(fileContent.replace(/\s+/g, '')).toEqual( + configFileContent.replace(/\s+/g, ''), + ); }); From 9e550d7ff269f88b4956f70c3ead2d67c3562cd2 Mon Sep 17 00:00:00 2001 From: Tomasz Misiukiewicz Date: Wed, 29 Nov 2023 08:57:33 +0100 Subject: [PATCH 8/8] update cacheManager message --- packages/cli-tools/src/cacheManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli-tools/src/cacheManager.ts b/packages/cli-tools/src/cacheManager.ts index f227445ee..06f21d25e 100644 --- a/packages/cli-tools/src/cacheManager.ts +++ b/packages/cli-tools/src/cacheManager.ts @@ -59,9 +59,9 @@ function removeProjectCache(name: string) { } } catch { logger.error( - `Failed to remove cache for ${name}. If you experience any issues when running freshly initialized project, please remove ${chalk.underline( + `Failed to remove cache for ${name}. If you experience any issues when running freshly initialized project, please remove the "${chalk.underline( path.join(cacheRootPath, name), - )} folder manually.`, + )}" folder manually.`, ); } }