From d69ed9d9a12b6e896a6a7995b01b3a9b4a10c63c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 7 May 2019 10:35:45 +0200 Subject: [PATCH 01/12] chore: cleanup run-android implementation --- docs/commands.md | 2 - .../src/commands/runAndroid/adb.js | 1 - .../src/commands/runAndroid/index.js | 50 ++++---- .../commands/runAndroid/runOnAllDevices.js | 107 ++++++------------ .../runAndroid/tryLaunchAppOnDevice.js | 20 ++-- .../commands/runAndroid/tryRunAdbReverse.js | 15 ++- 6 files changed, 78 insertions(+), 117 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 7ba65c626..acddd7c6d 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -262,8 +262,6 @@ Builds your app and starts it on a connected Android emulator or device. #### Options -#### `--install-debug` - #### `--root [string]` Override the root directory for the Android build (which contains the android directory)'. diff --git a/packages/platform-android/src/commands/runAndroid/adb.js b/packages/platform-android/src/commands/runAndroid/adb.js index d526829bc..c67f467c6 100644 --- a/packages/platform-android/src/commands/runAndroid/adb.js +++ b/packages/platform-android/src/commands/runAndroid/adb.js @@ -70,7 +70,6 @@ function getAvailableCPUs(adbPath: string, device: string): Array { } export default { - parseDevicesResult, getDevices, getAvailableCPUs, }; diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 09c7f71c5..31022f788 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -30,10 +30,23 @@ function checkAndroid(root) { return fs.existsSync(path.join(root, 'android/gradlew')); } +export type FlagsT = {| + root: string, + variant: string, + appFolder: string, + appId: string, + appIdSuffix: string, + mainActivity: string, + deviceId?: string, + packager: boolean, + port: number, + terminal: string, +|}; + /** * Starts the app on a connected Android emulator or device. */ -function runAndroid(argv: Array, ctx: ConfigT, args: Object) { +function runAndroid(argv: Array, ctx: ConfigT, args: FlagsT) { if (!checkAndroid(args.root)) { logger.error( 'Android project not found. Are you sure this is a React Native project?', @@ -90,16 +103,13 @@ function buildAndRun(args) { const adbPath = getAdbPath(); if (args.deviceId) { - if (typeof args.deviceId === 'string') { - return runOnSpecificDevice( - args, - cmd, - packageNameWithSuffix, - packageName, - adbPath, - ); - } - logger.error('Argument missing for parameter --deviceId'); + return runOnSpecificDevice( + args, + cmd, + packageNameWithSuffix, + packageName, + adbPath, + ); } else { return runOnAllDevices( args, @@ -119,21 +129,20 @@ function runOnSpecificDevice( adbPath, ) { const devices = adb.getDevices(adbPath); - if (devices && devices.length > 0) { - if (devices.indexOf(args.deviceId) !== -1) { + const {deviceId} = args; + if (devices.length > 0 && deviceId) { + if (devices.indexOf(deviceId) !== -1) { buildApk(gradlew); installAndLaunchOnDevice( args, - args.deviceId, + deviceId, packageNameWithSuffix, packageName, adbPath, ); } else { logger.error( - `Could not find device with the id: "${ - args.deviceId - }". Choose one of the following:`, + `Could not find device with the id: "${deviceId}". Choose one of the following:`, ...devices, ); } @@ -305,19 +314,12 @@ export default { 'builds your app and starts it on a connected Android emulator or device', func: runAndroid, options: [ - { - name: '--install-debug', - }, { name: '--root [string]', description: 'Override the root directory for the android build (which contains the android directory)', default: '', }, - { - name: '--flavor [string]', - description: '--flavor has been deprecated. Use --variant instead', - }, { name: '--variant [string]', default: 'debug', diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index 3eb59ae44..2417a2210 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -7,103 +7,60 @@ * @flow */ -import {spawnSync, execFileSync} from 'child_process'; -import {logger} from '@react-native-community/cli-tools'; +import chalk from 'chalk'; +import {execFileSync} from 'child_process'; +import {logger, CLIError} from '@react-native-community/cli-tools'; import adb from './adb'; import tryRunAdbReverse from './tryRunAdbReverse'; import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; +import type {FlagsT} from '.'; function getCommand(appFolder, command) { return appFolder ? `${appFolder}:${command}` : command; } +function toPascalCase(value: string) { + return value[0].toUpperCase() + value.slice(1); +} + function runOnAllDevices( - args: Object, + args: FlagsT, cmd: string, packageNameWithSuffix: string, packageName: string, adbPath: string, ) { try { - const gradleArgs = []; - - if (args.installDebug) { - gradleArgs.push(getCommand(args.appFolder, args.installDebug)); - } else if (args.variant) { - gradleArgs.push( - `${getCommand( - args.appFolder, - 'install', - )}${args.variant[0].toUpperCase()}${args.variant.slice(1)}`, - ); - } else if (args.flavor) { - logger.warn('--flavor has been deprecated. Use --variant instead'); - gradleArgs.push( - `${getCommand( - args.appFolder, - 'install', - )}${args.flavor[0].toUpperCase()}${args.flavor.slice(1)}`, - ); - } else { - gradleArgs.push(getCommand(args.appFolder, 'installDebug')); - } + const gradleArgs = [ + getCommand(args.appFolder, 'install' + toPascalCase(args.variant)), + ]; - logger.info( - `Building and installing the app on the device (cd android && ${cmd} ${gradleArgs.join( - ' ', - )})...`, + logger.info('Installing the app...'); + logger.debug( + `Running command "cd android && ${cmd} ${gradleArgs.join(' ')}"`, ); - execFileSync(cmd, gradleArgs, { - stdio: [process.stdin, process.stdout, process.stderr], - }); + execFileSync(cmd, gradleArgs, {stdio: 'inherit'}); } catch (e) { - logger.error( - 'Could not install the app on the device, read the error above for details.\n' + - 'Make sure you have an Android emulator running or a device connected and have\n' + - 'set up your Android development environment:\n' + - 'https://facebook.github.io/react-native/docs/getting-started.html', + throw new CLIError( + `Failed to install the app. Make sure you have an Android emulator running or a device connected and the Android development environment set up: ${chalk.underline.dim( + 'https://facebook.github.io/react-native/docs/getting-started.html#android-development-environment', + )}`, + e, ); - // stderr is automatically piped from the gradle process, so the user - // should see the error already, there is no need to do - // `logger.info(e.stderr)` - return Promise.reject(e); } const devices = adb.getDevices(adbPath); - if (devices && devices.length > 0) { - devices.forEach(device => { - tryRunAdbReverse(args.port, device); - tryLaunchAppOnDevice( - device, - packageNameWithSuffix, - packageName, - adbPath, - args.mainActivity, - ); - }); - } else { - try { - // If we cannot execute based on adb devices output, fall back to - // shell am start - const fallbackAdbArgs = [ - 'shell', - 'am', - 'start', - '-n', - `${packageNameWithSuffix}/${packageName}.MainActivity`, - ]; - logger.info( - `Starting the app (${adbPath} ${fallbackAdbArgs.join(' ')}...`, - ); - spawnSync(adbPath, fallbackAdbArgs, {stdio: 'inherit'}); - } catch (e) { - logger.error('adb invocation failed. Do you have adb in your PATH?'); - // stderr is automatically piped from the gradle process, so the user - // should see the error already, there is no need to do - // `logger.info(e.stderr)` - return Promise.reject(e); - } - } + + (devices.length > 0 ? devices : [undefined]).forEach(device => { + tryRunAdbReverse(args.port, device); + tryLaunchAppOnDevice( + device, + packageNameWithSuffix, + packageName, + adbPath, + args.mainActivity, + ); + }); } export default runOnAllDevices; diff --git a/packages/platform-android/src/commands/runAndroid/tryLaunchAppOnDevice.js b/packages/platform-android/src/commands/runAndroid/tryLaunchAppOnDevice.js index a2b88d021..4fd39fbec 100644 --- a/packages/platform-android/src/commands/runAndroid/tryLaunchAppOnDevice.js +++ b/packages/platform-android/src/commands/runAndroid/tryLaunchAppOnDevice.js @@ -8,10 +8,10 @@ */ import {spawnSync} from 'child_process'; -import {logger} from '@react-native-community/cli-tools'; +import {logger, CLIError} from '@react-native-community/cli-tools'; function tryLaunchAppOnDevice( - device: string, + device?: string, packageNameWithSuffix: string, packageName: string, adbPath: string, @@ -19,20 +19,22 @@ function tryLaunchAppOnDevice( ) { try { const adbArgs = [ - '-s', - device, 'shell', 'am', 'start', '-n', `${packageNameWithSuffix}/${packageName}.${mainActivity}`, ]; - logger.info( - `Starting the app on ${device} (${adbPath} ${adbArgs.join(' ')})...`, - ); + if (device) { + adbArgs.unshift('-s', device); + logger.info(`Starting the app on "${device}"...`); + } else { + logger.info('Starting the app...'); + } + logger.debug(`Running command "${adbPath} ${adbArgs.join(' ')}"`); spawnSync(adbPath, adbArgs, {stdio: 'inherit'}); - } catch (e) { - logger.error('adb invocation failed. Do you have adb in your PATH?'); + } catch (error) { + throw new CLIError('Failed to start the app.', error); } } diff --git a/packages/platform-android/src/commands/runAndroid/tryRunAdbReverse.js b/packages/platform-android/src/commands/runAndroid/tryRunAdbReverse.js index 58c443b67..ffb021540 100644 --- a/packages/platform-android/src/commands/runAndroid/tryRunAdbReverse.js +++ b/packages/platform-android/src/commands/runAndroid/tryRunAdbReverse.js @@ -12,7 +12,7 @@ import {logger} from '@react-native-community/cli-tools'; import getAdbPath from './getAdbPath'; // Runs ADB reverse tcp:8081 tcp:8081 to allow loading the jsbundle from the packager -function tryRunAdbReverse(packagerPort: number | string, device: string) { +function tryRunAdbReverse(packagerPort: number | string, device?: string) { try { const adbPath = getAdbPath(); const adbArgs = ['reverse', `tcp:${packagerPort}`, `tcp:${packagerPort}`]; @@ -22,13 +22,16 @@ function tryRunAdbReverse(packagerPort: number | string, device: string) { adbArgs.unshift('-s', device); } - logger.info(`Running ${adbPath} ${adbArgs.join(' ')}`); + logger.info('Connecting to the development server...'); + logger.debug(`Running command "${adbPath} ${adbArgs.join(' ')}"`); - execFileSync(adbPath, adbArgs, { - stdio: [process.stdin, process.stdout, process.stderr], - }); + execFileSync(adbPath, adbArgs, {stdio: 'inherit'}); } catch (e) { - logger.info(`Could not run adb reverse: ${e.message}`); + logger.warn( + `Failed to connect to development server using "adb reverse": ${ + e.message + }`, + ); } } From 31448629b70fd16df865f5948a89316162f95e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 7 May 2019 10:36:18 +0200 Subject: [PATCH 02/12] feat: overhaul gradle install errors --- .../src/commands/runAndroid/index.js | 43 +++++++++---------- .../commands/runAndroid/runOnAllDevices.js | 43 +++++++++++++++---- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 31022f788..004aa1fcd 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -46,7 +46,7 @@ export type FlagsT = {| /** * Starts the app on a connected Android emulator or device. */ -function runAndroid(argv: Array, ctx: ConfigT, args: FlagsT) { +function runAndroid(argv: Array, config: ConfigT, args: FlagsT) { if (!checkAndroid(args.root)) { logger.error( 'Android project not found. Are you sure this is a React Native project?', @@ -55,7 +55,7 @@ function runAndroid(argv: Array, ctx: ConfigT, args: FlagsT) { } if (!args.packager) { - return buildAndRun(args); + return buildAndRun(args, config); } return isPackagerRunning(args.port).then(result => { @@ -66,9 +66,9 @@ function runAndroid(argv: Array, ctx: ConfigT, args: FlagsT) { } else { // result == 'not_running' logger.info('Starting JS server...'); - startServerInNewWindow(args.port, args.terminal, ctx.reactNativePath); + startServerInNewWindow(args.port, args.terminal, config.reactNativePath); } - return buildAndRun(args); + return buildAndRun(args, config); }); } @@ -84,7 +84,7 @@ function getPackageNameWithSuffix(appId, appIdSuffix, packageName) { } // Builds the app and runs it on a connected emulator / device. -function buildAndRun(args) { +function buildAndRun(args, config) { process.chdir(path.join(args.root, 'android')); const cmd = process.platform.startsWith('win') ? 'gradlew.bat' : './gradlew'; @@ -117,6 +117,7 @@ function buildAndRun(args) { packageNameWithSuffix, packageName, adbPath, + config, ); } } @@ -142,7 +143,7 @@ function runOnSpecificDevice( ); } else { logger.error( - `Could not find device with the id: "${deviceId}". Choose one of the following:`, + `Could not find device with the id: "${deviceId}". Please choose one of the following:`, ...devices, ); } @@ -153,17 +154,15 @@ function runOnSpecificDevice( function buildApk(gradlew) { try { - logger.info('Building the app...'); - // using '-x lint' in order to ignore linting errors while building the apk - execFileSync(gradlew, ['build', '-x', 'lint'], { + const gradleArgs = ['build', '-x', 'lint']; + logger.info('Building the app...'); + logger.debug(`Running command "${gradlew} ${gradleArgs.join(' ')}"`); + execFileSync(gradlew, gradleArgs, { stdio: [process.stdin, process.stdout, process.stderr], }); } catch (error) { - throw new CLIError( - 'Could not build the app, read the error above for details', - error, - ); + throw new CLIError(`Failed to build the app: ${error.message}`, error); } } @@ -183,17 +182,15 @@ function tryInstallAppOnDevice(args, adbPath, device) { const pathToApk = `${buildDirectory}/${apkFile}`; const adbArgs = ['-s', device, 'install', '-r', '-d', pathToApk]; - logger.info( - `Installing the app on the device (cd android && adb -s ${device} install -r -d ${pathToApk}`, + logger.info(`Installing the app on the device "${device}"...`); + logger.debug( + `Running command "cd android && adb -s ${device} install -r -d ${pathToApk}"`, ); - execFileSync(adbPath, adbArgs, { - stdio: [process.stdin, process.stdout, process.stderr], - }); - } catch (e) { - logger.error( - `${ - e.message - }\nCould not install the app on the device, read the error above for details.`, + execFileSync(adbPath, adbArgs, {stdio: 'inherit'}); + } catch (error) { + throw new CLIError( + `Failed to install the app on the device: ${error.message}`, + error, ); } } diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index 2417a2210..f75efac1f 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -14,6 +14,7 @@ import adb from './adb'; import tryRunAdbReverse from './tryRunAdbReverse'; import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; import type {FlagsT} from '.'; +import type {ConfigT} from 'types'; function getCommand(appFolder, command) { return appFolder ? `${appFolder}:${command}` : command; @@ -23,12 +24,13 @@ function toPascalCase(value: string) { return value[0].toUpperCase() + value.slice(1); } -function runOnAllDevices( +async function runOnAllDevices( args: FlagsT, cmd: string, packageNameWithSuffix: string, packageName: string, adbPath: string, + config: ConfigT, ) { try { const gradleArgs = [ @@ -40,14 +42,9 @@ function runOnAllDevices( `Running command "cd android && ${cmd} ${gradleArgs.join(' ')}"`, ); - execFileSync(cmd, gradleArgs, {stdio: 'inherit'}); - } catch (e) { - throw new CLIError( - `Failed to install the app. Make sure you have an Android emulator running or a device connected and the Android development environment set up: ${chalk.underline.dim( - 'https://facebook.github.io/react-native/docs/getting-started.html#android-development-environment', - )}`, - e, - ); + execFileSync(cmd, gradleArgs, {stdio: ['inherit', 'inherit', 'pipe']}); + } catch (error) { + throw createInstallError(error); } const devices = adb.getDevices(adbPath); @@ -63,4 +60,32 @@ function runOnAllDevices( }); } +function createInstallError(error) { + const stderr = (error.stderr || '').toString(); + const docs = + 'https://facebook.github.io/react-native/docs/getting-started.html#android-development-environment'; + let message = `Make sure you have the Android development environment set up: ${chalk.underline.dim( + docs, + )}`; + + // Pass the error message from the command to stdout because we pipe it to + // parent process so it's not visible + console.log(stderr); + + // Handle some common failures and make the errors more helpful + if (stderr.includes('No connected devices')) { + message = + 'Make sure you have an Android emulator running or a device connected'; + } else if ( + stderr.includes('licences have not been accepted') || + stderr.includes('accept the SDK license') + ) { + message = `Please accept all necessary SDK licenses using SDK Manager: "${chalk.bold( + '$ANDROID_HOME/tools/bin/sdkmanager --licenses', + )}"`; + } + + return new CLIError(`Failed to install the app. ${message}.`, error); +} + export default runOnAllDevices; From ce8eecd7274c4a962d10476fdf2d87575cf34c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 7 May 2019 10:54:22 +0200 Subject: [PATCH 03/12] fix copying executables by bringing back chmod --- packages/cli/src/tools/copyFiles.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/tools/copyFiles.js b/packages/cli/src/tools/copyFiles.js index 795f6862c..6f8206a05 100644 --- a/packages/cli/src/tools/copyFiles.js +++ b/packages/cli/src/tools/copyFiles.js @@ -53,7 +53,7 @@ function copyFile(srcPath: string, destPath: string) { */ function copyBinaryFile(srcPath, destPath, cb) { let cbCalled = false; - // const {mode} = fs.statSync(srcPath); + const {mode} = fs.statSync(srcPath); const readStream = fs.createReadStream(srcPath); const writeStream = fs.createWriteStream(destPath); readStream.on('error', err => { @@ -64,10 +64,7 @@ function copyBinaryFile(srcPath, destPath, cb) { }); readStream.on('close', () => { done(); - // We may revisit setting mode to original later, however this fn is used - // before "replace placeholder in template" step, which expects files to be - // writable. - // fs.chmodSync(destPath, mode); + fs.chmodSync(destPath, mode); }); readStream.pipe(writeStream); function done(err) { From 4abd3025e98c1b6b29a4af7bc271558f1f18d3cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 7 May 2019 11:11:00 +0200 Subject: [PATCH 04/12] rename 'installDebug' -> 'task' --- docs/commands.md | 6 ++- .../__tests__/runOnAllDevices.test.js | 46 ++++++------------- .../src/commands/runAndroid/index.js | 6 +++ .../commands/runAndroid/runOnAllDevices.js | 8 ++-- 4 files changed, 30 insertions(+), 36 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index acddd7c6d..f69734c33 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -300,7 +300,7 @@ Do not launch packager while building. #### `--port [number]` -> default: process.env.RCT_METRO_PORT || 8081, +> default: process.env.RCT_METRO_PORT || 8081 #### `--terminal [string]` @@ -308,6 +308,10 @@ Do not launch packager while building. Launches the Metro Bundler in a new window using the specified terminal path. +#### `--task [string]` + +Run custom Gradle task instead of default "installDebug" where "debug" is default variant. + ### `run-ios` Usage: diff --git a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js index 840e5cb54..5775dd5c4 100644 --- a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js +++ b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js @@ -22,7 +22,9 @@ describe('--appFolder', () => { }); it('uses installDebug as default if no arguments', () => { - runOnAllDevices({}); + runOnAllDevices({ + variant: 'debug', + }); expect(execFileSync.mock.calls[0][1]).toContain('installDebug'); }); @@ -30,59 +32,39 @@ describe('--appFolder', () => { it('uses appFolder and default variant', () => { runOnAllDevices({ appFolder: 'someApp', + variant: 'debug', }); expect(execFileSync.mock.calls[0][1]).toContain('someApp:installDebug'); }); - it('uses appFolder and variant', () => { - runOnAllDevices({ - appFolder: 'app', - variant: 'debug', - }); - - expect(execFileSync.mock.calls[0][1]).toContain('app:installDebug'); - - runOnAllDevices({ - appFolder: 'anotherApp', - variant: 'debug', - }); - - expect(execFileSync.mock.calls[1][1]).toContain('anotherApp:installDebug'); - + it('uses appFolder and custom variant', () => { runOnAllDevices({ appFolder: 'anotherApp', variant: 'staging', }); - expect(execFileSync.mock.calls[2][1]).toContain( + expect(execFileSync.mock.calls[0][1]).toContain( 'anotherApp:installStaging', ); }); - it('uses appFolder and flavor', () => { + it('uses only task argument', () => { runOnAllDevices({ - appFolder: 'app', - flavor: 'someFlavor', - }); - - expect(execFileSync.mock.calls[0][1]).toContain('app:installSomeFlavor'); - }); - - it('uses only installDebug argument', () => { - runOnAllDevices({ - installDebug: 'someCommand', + task: 'someTask', + variant: 'debug', }); - expect(execFileSync.mock.calls[0][1]).toContain('someCommand'); + expect(execFileSync.mock.calls[0][1]).toContain('someTask'); }); - it('uses appFolder and custom installDebug argument', () => { + it('uses appFolder and custom task argument', () => { runOnAllDevices({ appFolder: 'anotherApp', - installDebug: 'someCommand', + task: 'someTask', + variant: 'debug', }); - expect(execFileSync.mock.calls[0][1]).toContain('anotherApp:someCommand'); + expect(execFileSync.mock.calls[0][1]).toContain('anotherApp:someTask'); }); }); diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 004aa1fcd..1fc7b5ea4 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -31,6 +31,7 @@ function checkAndroid(root) { } export type FlagsT = {| + task?: string, root: string, variant: string, appFolder: string, @@ -363,5 +364,10 @@ export default { 'Launches the Metro Bundler in a new window using the specified terminal path.', default: getDefaultUserTerminal, }, + { + name: '--task [string]', + description: + 'Run custom Gradle task instead of default "installDebug" where "debug" is default variant', + }, ], }; diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index f75efac1f..cb9d1da65 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -16,7 +16,7 @@ import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; import type {FlagsT} from '.'; import type {ConfigT} from 'types'; -function getCommand(appFolder, command) { +function getTaskName(appFolder, command) { return appFolder ? `${appFolder}:${command}` : command; } @@ -24,7 +24,7 @@ function toPascalCase(value: string) { return value[0].toUpperCase() + value.slice(1); } -async function runOnAllDevices( +function runOnAllDevices( args: FlagsT, cmd: string, packageNameWithSuffix: string, @@ -34,7 +34,9 @@ async function runOnAllDevices( ) { try { const gradleArgs = [ - getCommand(args.appFolder, 'install' + toPascalCase(args.variant)), + args.task + ? getTaskName(args.appFolder, args.task) + : getTaskName(args.appFolder, 'install' + toPascalCase(args.variant)), ]; logger.info('Installing the app...'); From fa1f718c34805b5eb3170e5b36bc065eeab12a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 7 May 2019 11:19:59 +0200 Subject: [PATCH 05/12] cleanup unused args from refactor --- packages/platform-android/src/commands/runAndroid/index.js | 7 +++---- .../src/commands/runAndroid/runOnAllDevices.js | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 1fc7b5ea4..3610edafe 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -56,7 +56,7 @@ function runAndroid(argv: Array, config: ConfigT, args: FlagsT) { } if (!args.packager) { - return buildAndRun(args, config); + return buildAndRun(args); } return isPackagerRunning(args.port).then(result => { @@ -69,7 +69,7 @@ function runAndroid(argv: Array, config: ConfigT, args: FlagsT) { logger.info('Starting JS server...'); startServerInNewWindow(args.port, args.terminal, config.reactNativePath); } - return buildAndRun(args, config); + return buildAndRun(args); }); } @@ -85,7 +85,7 @@ function getPackageNameWithSuffix(appId, appIdSuffix, packageName) { } // Builds the app and runs it on a connected emulator / device. -function buildAndRun(args, config) { +function buildAndRun(args) { process.chdir(path.join(args.root, 'android')); const cmd = process.platform.startsWith('win') ? 'gradlew.bat' : './gradlew'; @@ -118,7 +118,6 @@ function buildAndRun(args, config) { packageNameWithSuffix, packageName, adbPath, - config, ); } } diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index cb9d1da65..e87b01895 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -14,7 +14,6 @@ import adb from './adb'; import tryRunAdbReverse from './tryRunAdbReverse'; import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; import type {FlagsT} from '.'; -import type {ConfigT} from 'types'; function getTaskName(appFolder, command) { return appFolder ? `${appFolder}:${command}` : command; @@ -30,7 +29,6 @@ function runOnAllDevices( packageNameWithSuffix: string, packageName: string, adbPath: string, - config: ConfigT, ) { try { const gradleArgs = [ From 97f2d9ddbdb6b51bdaa967fffc56323d8a3bb94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 7 May 2019 11:23:22 +0200 Subject: [PATCH 06/12] use inherit and don't show null error --- .../platform-android/src/commands/runAndroid/index.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 3610edafe..1f4accc00 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -158,11 +158,9 @@ function buildApk(gradlew) { const gradleArgs = ['build', '-x', 'lint']; logger.info('Building the app...'); logger.debug(`Running command "${gradlew} ${gradleArgs.join(' ')}"`); - execFileSync(gradlew, gradleArgs, { - stdio: [process.stdin, process.stdout, process.stderr], - }); + execFileSync(gradlew, gradleArgs, {stdio: 'inherit'}); } catch (error) { - throw new CLIError(`Failed to build the app: ${error.message}`, error); + throw new CLIError('Failed to build the app.', error); } } @@ -188,10 +186,7 @@ function tryInstallAppOnDevice(args, adbPath, device) { ); execFileSync(adbPath, adbArgs, {stdio: 'inherit'}); } catch (error) { - throw new CLIError( - `Failed to install the app on the device: ${error.message}`, - error, - ); + throw new CLIError('Failed to install the app on the device.', error); } } From b2f79ab2006cea10654c09c6d77075c0e6ad162a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 8 May 2019 23:49:13 +0200 Subject: [PATCH 07/12] simplify creating gradle args --- .../commands/runAndroid/__tests__/runOnAllDevices.test.js | 2 +- .../src/commands/runAndroid/runOnAllDevices.js | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js index 5775dd5c4..3a1a51fd4 100644 --- a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js +++ b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js @@ -21,7 +21,7 @@ describe('--appFolder', () => { jest.clearAllMocks(); }); - it('uses installDebug as default if no arguments', () => { + it('uses task "install[Variant]" as default task', () => { runOnAllDevices({ variant: 'debug', }); diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index e87b01895..6370e9338 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -31,11 +31,8 @@ function runOnAllDevices( adbPath: string, ) { try { - const gradleArgs = [ - args.task - ? getTaskName(args.appFolder, args.task) - : getTaskName(args.appFolder, 'install' + toPascalCase(args.variant)), - ]; + const task = args.task || 'install' + toPascalCase(args.variant); + const gradleArgs = [getTaskName(args.appFolder, task)]; logger.info('Installing the app...'); logger.debug( From 3c5801d871f801fde088386b068e58ca15dd447b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 8 May 2019 23:57:04 +0200 Subject: [PATCH 08/12] adjust descriptions --- docs/commands.md | 6 +++++- packages/platform-android/src/commands/runAndroid/index.js | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index f69734c33..30f5e14db 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -270,6 +270,8 @@ Override the root directory for the Android build (which contains the android di > default: 'debug' +Specify your app's build variant. + #### `--appFolder [string]` > default: 'app' @@ -310,7 +312,9 @@ Launches the Metro Bundler in a new window using the specified terminal path. #### `--task [string]` -Run custom Gradle task instead of default "installDebug" where "debug" is default variant. +> default: 'installDebug' + +Run custom Gradle task. ### `run-ios` diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 1f4accc00..60005f0b9 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -314,6 +314,7 @@ export default { }, { name: '--variant [string]', + description: "Specify your app's build variant", default: 'debug', }, { @@ -360,8 +361,7 @@ export default { }, { name: '--task [string]', - description: - 'Run custom Gradle task instead of default "installDebug" where "debug" is default variant', + description: 'Run custom Gradle task. By default it\'s "installDebug"', }, ], }; From 1b1c4a57885a882d054b4724a1afd5439499fba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 10 May 2019 13:20:06 +0200 Subject: [PATCH 09/12] use logger --- .../platform-android/src/commands/runAndroid/runOnAllDevices.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index 6370e9338..40112cc0d 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -67,7 +67,7 @@ function createInstallError(error) { // Pass the error message from the command to stdout because we pipe it to // parent process so it's not visible - console.log(stderr); + logger.log(stderr); // Handle some common failures and make the errors more helpful if (stderr.includes('No connected devices')) { From 339ee4c15c034d66b7e458fa1714121bd91d02a1 Mon Sep 17 00:00:00 2001 From: Kacper Wiszczuk Date: Fri, 10 May 2019 14:39:30 +0200 Subject: [PATCH 10/12] Add support for multiple tasks --- docs/commands.md | 5 +++-- .../runAndroid/__tests__/runOnAllDevices.test.js | 16 ++++++++++++++-- .../src/commands/runAndroid/index.js | 5 +++-- .../src/commands/runAndroid/runOnAllDevices.js | 13 +++++++++---- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 30f5e14db..84d45dc9e 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -310,11 +310,12 @@ Do not launch packager while building. Launches the Metro Bundler in a new window using the specified terminal path. -#### `--task [string]` +#### `--task [list]` > default: 'installDebug' -Run custom Gradle task. +Run custom gradle tasks. If this argument is provided, then `--variant` option is ignored. +Example: `yarn react-native run-android --tasks clean,installDebug`. ### `run-ios` diff --git a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js index 3a1a51fd4..5afb5e352 100644 --- a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js +++ b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js @@ -51,7 +51,7 @@ describe('--appFolder', () => { it('uses only task argument', () => { runOnAllDevices({ - task: 'someTask', + task: ['someTask'], variant: 'debug', }); @@ -61,10 +61,22 @@ describe('--appFolder', () => { it('uses appFolder and custom task argument', () => { runOnAllDevices({ appFolder: 'anotherApp', - task: 'someTask', + task: ['someTask'], variant: 'debug', }); expect(execFileSync.mock.calls[0][1]).toContain('anotherApp:someTask'); }); + + it('uses multiple tasks', () => { + runOnAllDevices({ + appFolder: 'app', + task: ['clean', 'someTask'], + }); + + expect(execFileSync.mock.calls[0][1]).toContain( + 'app:clean', + 'app:someTask', + ); + }); }); diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 60005f0b9..746a74d2f 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -31,7 +31,7 @@ function checkAndroid(root) { } export type FlagsT = {| - task?: string, + task?: Array, root: string, variant: string, appFolder: string, @@ -360,8 +360,9 @@ export default { default: getDefaultUserTerminal, }, { - name: '--task [string]', + name: '--task [list]', description: 'Run custom Gradle task. By default it\'s "installDebug"', + parse: (val: string) => val.split(','), }, ], }; diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index 40112cc0d..1e544c2ab 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -15,8 +15,13 @@ import tryRunAdbReverse from './tryRunAdbReverse'; import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; import type {FlagsT} from '.'; -function getTaskName(appFolder, command) { - return appFolder ? `${appFolder}:${command}` : command; +function getTaskName( + appFolder: string, + commands: Array, +): Array { + return appFolder + ? commands.map(command => `${appFolder}:${command}`) + : commands; } function toPascalCase(value: string) { @@ -31,8 +36,8 @@ function runOnAllDevices( adbPath: string, ) { try { - const task = args.task || 'install' + toPascalCase(args.variant); - const gradleArgs = [getTaskName(args.appFolder, task)]; + const task = args.task || ['install' + toPascalCase(args.variant)]; + const gradleArgs = getTaskName(args.appFolder, task); logger.info('Installing the app...'); logger.debug( From e3a01cdc17646c12f4120f4d1e22a3437ff24617 Mon Sep 17 00:00:00 2001 From: Kacper Wiszczuk Date: Fri, 10 May 2019 15:08:27 +0200 Subject: [PATCH 11/12] Change function name to match current functionality --- .../src/commands/runAndroid/runOnAllDevices.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index 1e544c2ab..0675e7abe 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -15,7 +15,7 @@ import tryRunAdbReverse from './tryRunAdbReverse'; import tryLaunchAppOnDevice from './tryLaunchAppOnDevice'; import type {FlagsT} from '.'; -function getTaskName( +function getTaskNames( appFolder: string, commands: Array, ): Array { @@ -37,7 +37,7 @@ function runOnAllDevices( ) { try { const task = args.task || ['install' + toPascalCase(args.variant)]; - const gradleArgs = getTaskName(args.appFolder, task); + const gradleArgs = getTaskNames(args.appFolder, task); logger.info('Installing the app...'); logger.debug( From c4065401529405e04ed21d8c69b67d5da2dc80e6 Mon Sep 17 00:00:00 2001 From: Kacper Wiszczuk Date: Fri, 10 May 2019 15:16:09 +0200 Subject: [PATCH 12/12] Change task to tasks --- docs/commands.md | 2 +- .../commands/runAndroid/__tests__/runOnAllDevices.test.js | 6 +++--- packages/platform-android/src/commands/runAndroid/index.js | 6 +++--- .../src/commands/runAndroid/runOnAllDevices.js | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 84d45dc9e..d6ae064bd 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -310,7 +310,7 @@ Do not launch packager while building. Launches the Metro Bundler in a new window using the specified terminal path. -#### `--task [list]` +#### `--tasks [list]` > default: 'installDebug' diff --git a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js index 5afb5e352..86cd9948b 100644 --- a/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js +++ b/packages/platform-android/src/commands/runAndroid/__tests__/runOnAllDevices.test.js @@ -51,7 +51,7 @@ describe('--appFolder', () => { it('uses only task argument', () => { runOnAllDevices({ - task: ['someTask'], + tasks: ['someTask'], variant: 'debug', }); @@ -61,7 +61,7 @@ describe('--appFolder', () => { it('uses appFolder and custom task argument', () => { runOnAllDevices({ appFolder: 'anotherApp', - task: ['someTask'], + tasks: ['someTask'], variant: 'debug', }); @@ -71,7 +71,7 @@ describe('--appFolder', () => { it('uses multiple tasks', () => { runOnAllDevices({ appFolder: 'app', - task: ['clean', 'someTask'], + tasks: ['clean', 'someTask'], }); expect(execFileSync.mock.calls[0][1]).toContain( diff --git a/packages/platform-android/src/commands/runAndroid/index.js b/packages/platform-android/src/commands/runAndroid/index.js index 746a74d2f..096da3991 100644 --- a/packages/platform-android/src/commands/runAndroid/index.js +++ b/packages/platform-android/src/commands/runAndroid/index.js @@ -31,7 +31,7 @@ function checkAndroid(root) { } export type FlagsT = {| - task?: Array, + tasks?: Array, root: string, variant: string, appFolder: string, @@ -360,8 +360,8 @@ export default { default: getDefaultUserTerminal, }, { - name: '--task [list]', - description: 'Run custom Gradle task. By default it\'s "installDebug"', + name: '--tasks [list]', + description: 'Run custom Gradle tasks. By default it\'s "installDebug"', parse: (val: string) => val.split(','), }, ], diff --git a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js index 0675e7abe..a4e9b2fff 100644 --- a/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js +++ b/packages/platform-android/src/commands/runAndroid/runOnAllDevices.js @@ -36,8 +36,8 @@ function runOnAllDevices( adbPath: string, ) { try { - const task = args.task || ['install' + toPascalCase(args.variant)]; - const gradleArgs = getTaskNames(args.appFolder, task); + const tasks = args.tasks || ['install' + toPascalCase(args.variant)]; + const gradleArgs = getTaskNames(args.appFolder, tasks); logger.info('Installing the app...'); logger.debug(