1import { Command } from '@expo/commander';
2import spawnAsync from '@expo/spawn-async';
3import chalk from 'chalk';
4
5import { ANDROID_DIR } from '../Constants';
6import { getNextSDKVersionAsync } from '../ProjectVersions';
7
8type ActionOptions = {
9  checkout?: string;
10  sdkVersion?: string;
11};
12
13async function updateReactAndroidAsync(sdkVersion: string): Promise<void> {
14  console.log(
15    `Running ${chalk.blue('ReactAndroidCodeTransformer')} with ${chalk.yellow(
16      `./gradlew :tools:execute --args ${sdkVersion}`
17    )} command...`
18  );
19  await spawnAsync('./gradlew', [':tools:execute', '--args', sdkVersion], {
20    cwd: ANDROID_DIR,
21    stdio: 'inherit',
22  });
23}
24
25async function action(options: ActionOptions) {
26  // When we're updating React Native, we mostly want it to be for the next SDK that isn't versioned yet.
27  const androidSdkVersion = options.sdkVersion || (await getNextSDKVersionAsync('android'));
28
29  if (!androidSdkVersion) {
30    throw new Error(
31      'Cannot obtain next SDK version. Try to run with --sdkVersion <sdkVersion> flag.'
32    );
33  }
34
35  console.log(
36    `Updating ${chalk.green('ReactAndroid')} for SDK ${chalk.cyan(androidSdkVersion)} ...`
37  );
38  await updateReactAndroidAsync(androidSdkVersion);
39}
40
41export default (program: Command) => {
42  program
43    .command('update-react-native')
44    .alias('update-rn', 'urn')
45    .description(
46      'Updates React Native submodule and applies Expo-specific code transformations on ReactAndroid and ReactCommon folders.'
47    )
48    .option(
49      '-s, --sdkVersion [string]',
50      'SDK version for which the forked React Native will be used. Defaults to the newest SDK version increased by a major update.'
51    )
52    .asyncAction(action);
53};
54