diff --git a/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js b/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js index 01766beea..9f5e11826 100644 --- a/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js +++ b/packages/cli/src/commands/upgrade/__tests__/upgrade.test.js @@ -53,6 +53,7 @@ jest.mock('@react-native-community/cli-tools', () => ({ error: jest.fn((...args) => mockPushLog('error', args)), warn: jest.fn((...args) => mockPushLog('warn', args)), success: jest.fn((...args) => mockPushLog('success', args)), + debug: jest.fn((...args) => mockPushLog('debug', args)), log: jest.fn((...args) => mockPushLog(args)), }, })); @@ -252,7 +253,8 @@ test('cleans up if patching fails,', async () => { if (command === 'git' && args[0] === 'apply') { return Promise.reject({ code: 1, - stderr: 'error: .flowconfig: does not exist in index\n', + stderr: + 'error: .flowconfig: does not exist in index\nerror: ios/MyApp.xcodeproj/project.pbxproj: patch does not apply', }); } if (command === 'git' && args[0] === 'rev-parse') { @@ -272,16 +274,24 @@ test('cleans up if patching fails,', async () => { [fs] write tmp-upgrade-rn.patch $ execa git rev-parse --show-prefix $ execa git apply --binary --check tmp-upgrade-rn.patch --exclude=package.json -p2 --3way --directory= - info Applying diff (excluding: package.json, .flowconfig)... - $ execa git apply tmp-upgrade-rn.patch --exclude=package.json --exclude=.flowconfig -p2 --3way --directory= + info Applying diff... + warn Excluding files that exist in the template, but not in your project: + - .flowconfig + error Excluding files that failed to apply the diff: + - ios/MyApp.xcodeproj/project.pbxproj + Please make sure to check the actual changes after the upgrade command is finished. + You can find them in our Upgrade Helper web app: https://react-native-community.github.io/upgrade-helper/?from=0.57.8&to=0.58.4 + $ execa git apply tmp-upgrade-rn.patch --exclude=package.json --exclude=.flowconfig --exclude=ios/MyApp.xcodeproj/project.pbxproj -p2 --3way --directory= + debug \\"git apply\\" failed. Error output: error: .flowconfig: does not exist in index - error Automatically applying diff failed + error: ios/MyApp.xcodeproj/project.pbxproj: patch does not apply + error Automatically applying diff failed. We did our best to automatically upgrade as many files as possible [fs] unlink tmp-upgrade-rn.patch $ execa git status -s error Patch failed to apply for unknown reason. Please fall back to manual way of upgrading info You may find these resources helpful: • Release notes: https://github.com/facebook/react-native/releases/tag/v0.58.4 - • Comparison between versions: https://github.com/react-native-community/rn-diff-purge/compare/release/0.57.8..release/0.58.4 + • Manual Upgrade Helper: https://react-native-community.github.io/upgrade-helper/?from=0.57.8&to=0.58.4 • Git diff: https://raw.githubusercontent.com/react-native-community/rn-diff-purge/diffs/diffs/0.57.8..0.58.4.diff" `); }, 60000); diff --git a/packages/cli/src/commands/upgrade/upgrade.js b/packages/cli/src/commands/upgrade/upgrade.js index 43e5749d3..d3cbb5085 100644 --- a/packages/cli/src/commands/upgrade/upgrade.js +++ b/packages/cli/src/commands/upgrade/upgrade.js @@ -14,9 +14,9 @@ type FlagsT = { legacy: boolean | void, }; -const rnDiffPurgeUrl = - 'https://github.com/react-native-community/rn-diff-purge'; -const rnDiffPurgeRawDiffsUrl = +// https://react-native-community.github.io/upgrade-helper/?from=0.59.10&to=0.60.0-rc.3 +const webDiffUrl = 'https://react-native-community.github.io/upgrade-helper'; +const rawDiffUrl = 'https://raw.githubusercontent.com/react-native-community/rn-diff-purge/diffs/diffs'; const getLatestRNVersion = async (): Promise => { @@ -46,9 +46,7 @@ const getPatch = async (currentVersion, newVersion, config) => { logger.info(`Fetching diff between v${currentVersion} and v${newVersion}...`); try { - patch = await fetch( - `${rnDiffPurgeRawDiffsUrl}/${currentVersion}..${newVersion}.diff`, - ); + patch = await fetch(`${rawDiffUrl}/${currentVersion}..${newVersion}.diff`); } catch (error) { logger.error( `Failed to fetch diff for react-native@${newVersion}. Maybe it's not released yet?`, @@ -166,7 +164,9 @@ const applyPatch = async ( newVersion: string, tmpPatchFile: string, ) => { - let filesToExclude = ['package.json']; + const defaultExcludes = ['package.json']; + let filesThatDontExist = []; + let filesThatFailedToApply = []; // $FlowFixMe ThenableChildProcess is incompatible with Promise const {stdout: relativePathFromRoot} = await execa('git', [ 'rev-parse', @@ -174,7 +174,7 @@ const applyPatch = async ( ]); try { try { - const excludes = filesToExclude.map( + const excludes = defaultExcludes.map( e => `--exclude=${path.join(relativePathFromRoot, e)}`, ); await execa('git', [ @@ -192,19 +192,41 @@ const applyPatch = async ( ]); logger.info('Applying diff...'); } catch (error) { - filesToExclude = [ - ...filesToExclude, - ...error.stderr - .split('\n') + const errorLines = error.stderr.split('\n'); + filesThatDontExist = [ + ...errorLines .filter(x => x.includes('does not exist in index')) .map(x => x.replace(/^error: (.*): does not exist in index$/, '$1')), ].filter(Boolean); - logger.info(`Applying diff (excluding: ${filesToExclude.join(', ')})...`); - } finally { - const excludes = filesToExclude.map( - e => `--exclude=${path.join(relativePathFromRoot, e)}`, + filesThatFailedToApply = errorLines + .filter(x => x.includes('patch does not apply')) + .map(x => x.replace(/^error: (.*): patch does not apply$/, '$1')) + .filter(Boolean); + + logger.info('Applying diff...'); + logger.warn( + `Excluding files that exist in the template, but not in your project:\n${filesThatDontExist + .map(file => ` - ${chalk.bold(file)}`) + .join('\n')}`, ); + if (filesThatFailedToApply.length) { + logger.error( + `Excluding files that failed to apply the diff:\n${filesThatFailedToApply + .map(file => ` - ${chalk.bold(file)}`) + .join( + '\n', + )}\nPlease make sure to check the actual changes after the upgrade command is finished.\nYou can find them in our Upgrade Helper web app: ${chalk.underline.dim( + `${webDiffUrl}/?from=${currentVersion}&to=${newVersion}`, + )}`, + ); + } + } finally { + const excludes = [ + ...defaultExcludes, + ...filesThatDontExist, + ...filesThatFailedToApply, + ].map(e => `--exclude=${path.join(relativePathFromRoot, e)}`); await execa('git', [ 'apply', tmpPatchFile, @@ -216,9 +238,11 @@ const applyPatch = async ( } } catch (error) { if (error.stderr) { - logger.log(`${chalk.dim(error.stderr.trim())}`); + logger.debug(`"git apply" failed. Error output:\n${error.stderr}`); } - logger.error('Automatically applying diff failed'); + logger.error( + 'Automatically applying diff failed. We did our best to automatically upgrade as many files as possible', + ); return false; } return true; @@ -279,7 +303,7 @@ async function upgrade(argv: Array, ctx: ConfigT, args: FlagsT) { if (!patchSuccess) { if (stdout) { logger.warn( - 'Continuing after failure. Most of the files are upgraded but you will need to deal with some conflicts manually', + 'Continuing after failure. Some of the files are upgraded but you will need to deal with conflicts manually', ); await installDeps(newVersion, projectDir); logger.info('Running "git status" to check what changed...'); @@ -304,11 +328,11 @@ async function upgrade(argv: Array, ctx: ConfigT, args: FlagsT) { • Release notes: ${chalk.underline.dim( `https://github.com/facebook/react-native/releases/tag/v${newVersion}`, )} -• Comparison between versions: ${chalk.underline.dim( - `${rnDiffPurgeUrl}/compare/release/${currentVersion}..release/${newVersion}`, +• Manual Upgrade Helper: ${chalk.underline.dim( + `${webDiffUrl}/?from=${currentVersion}&to=${newVersion}`, )} • Git diff: ${chalk.underline.dim( - `${rnDiffPurgeRawDiffsUrl}/${currentVersion}..${newVersion}.diff`, + `${rawDiffUrl}/${currentVersion}..${newVersion}.diff`, )}`); throw new CLIError(