Repository: ReactiveCircus/android-emulator-runner
Pull request #10 (2019-12-13 07:18:38)

Support multi-line script.
Resolves #10 

Multi-line script is now supported.


Patch:
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 9605299..17a06d7 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -34,6 +34,8 @@ jobs:
         target: google_apis
         arch: x86_64
         profile: Nexus 6
-        emulator-options: -no-window -no-snapshot -noaudio -no-boot-anim -camera-back emulated
+        emulator-options: -no-window -no-snapshot -noaudio -no-boot-anim -camera-back none
         disable-animations: true
-        script: adb devices -l
+        script: |
+          adb reconnect
+          adb devices -l
diff --git a/lib/emulator-manager.js b/lib/emulator-manager.js
index d6fa8e0..d2ef920 100644
--- a/lib/emulator-manager.js
+++ b/lib/emulator-manager.js
@@ -66,7 +66,7 @@ function killEmulator() {
             yield exec.exec(`${ADB_PATH} -s emulator-5554 emu kill`);
         }
         catch (error) {
-            console.log('No emulator running on port 5554');
+            console.log(error.message);
         }
     });
 }
@@ -76,7 +76,6 @@ exports.killEmulator = killEmulator;
  */
 function waitForDevice() {
     return __awaiter(this, void 0, void 0, function* () {
-        const adbPath = `${process.env.ANDROID_HOME}/platform-tools/adb`;
         let booted = false;
         let attempts = 0;
         const retryInterval = 2; // retry every 2 seconds
@@ -84,7 +83,7 @@ function waitForDevice() {
         while (!booted) {
             try {
                 let result = '';
-                yield exec.exec(`${adbPath} shell getprop sys.boot_completed`, [], {
+                yield exec.exec(`${ADB_PATH} shell getprop sys.boot_completed`, [], {
                     listeners: {
                         stdout: (data) => {
                             result += data.toString();
diff --git a/lib/main.js b/lib/main.js
index 57bb7e8..644450c 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -20,6 +20,7 @@ const sdk_installer_1 = require("./sdk-installer");
 const input_validator_1 = require("./input-validator");
 const emulator_manager_1 = require("./emulator-manager");
 const exec = __importStar(require("@actions/exec"));
+const script_parser_1 = require("./script-parser");
 function run() {
     return __awaiter(this, void 0, void 0, function* () {
         try {
@@ -39,7 +40,7 @@ function run() {
             // CPU architecture of the system image
             const arch = core.getInput('arch');
             input_validator_1.checkArch(arch);
-            console.log(`CPI architecture: ${arch}`);
+            console.log(`CPU architecture: ${arch}`);
             // Hardware profile used for creating the AVD
             const profile = core.getInput('profile');
             console.log(`Hardware profile: ${profile}`);
@@ -51,19 +52,31 @@ function run() {
             input_validator_1.checkDisableAnimations(disableAnimationsInput);
             const disableAnimations = disableAnimationsInput === 'true';
             console.log(`disable animations: ${disableAnimations}`);
-            // custom scrpt to run
-            const script = core.getInput('script', { required: true });
+            // custom script to run
+            const scriptInput = core.getInput('script', { required: true });
+            const scripts = script_parser_1.parseScript(scriptInput);
+            console.log(`Script:`);
+            scripts.forEach((script) => __awaiter(this, void 0, void 0, function* () {
+                console.log(`${script}`);
+            }));
             try {
                 // install SDK
                 yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch);
                 // launch an emulator
                 yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, emulatorOptions, disableAnimations);
-                // execute the custom script
-                yield exec.exec(`${script}`);
             }
             catch (error) {
                 core.setFailed(error.message);
             }
+            // execute the custom script
+            scripts.forEach((script) => __awaiter(this, void 0, void 0, function* () {
+                try {
+                    yield exec.exec(`${script}`);
+                }
+                catch (error) {
+                    core.setFailed(error.message);
+                }
+            }));
             // finally kill the emulator
             yield emulator_manager_1.killEmulator();
         }
diff --git a/lib/script-parser.js b/lib/script-parser.js
new file mode 100644
index 0000000..2ea283c
--- /dev/null
+++ b/lib/script-parser.js
@@ -0,0 +1,19 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+/**
+ * Convert a (potentially multi-line) script to an array of single-line script(s).
+ */
+function parseScript(rawScript) {
+    const scripts = rawScript
+        .trim()
+        .split(/\r\n|\n|\r/)
+        .map((value) => value.trim())
+        .filter((value) => {
+        return !value.startsWith('#') && value.length > 0;
+    });
+    if (scripts.length == 0) {
+        throw new Error(`No valid script found.`);
+    }
+    return scripts;
+}
+exports.parseScript = parseScript;
diff --git a/src/emulator-manager.ts b/src/emulator-manager.ts
index e25ff63..49a33f3 100644
--- a/src/emulator-manager.ts
+++ b/src/emulator-manager.ts
@@ -49,7 +49,7 @@ export async function killEmulator(): Promise<void> {
   try {
     await exec.exec(`${ADB_PATH} -s emulator-5554 emu kill`);
   } catch (error) {
-    console.log('No emulator running on port 5554');
+    console.log(error.message);
   }
 }
 
@@ -57,7 +57,6 @@ export async function killEmulator(): Promise<void> {
  * Wait for emulator to boot.
  */
 async function waitForDevice(): Promise<void> {
-  const adbPath = `${process.env.ANDROID_HOME}/platform-tools/adb`;
   let booted = false;
   let attempts = 0;
   const retryInterval = 2; // retry every 2 seconds
@@ -65,7 +64,7 @@ async function waitForDevice(): Promise<void> {
   while (!booted) {
     try {
       let result = '';
-      await exec.exec(`${adbPath} shell getprop sys.boot_completed`, [], {
+      await exec.exec(`${ADB_PATH} shell getprop sys.boot_completed`, [], {
         listeners: {
           stdout: (data: Buffer) => {
             result += data.toString();
diff --git a/src/main.ts b/src/main.ts
index a145cc8..dc4e7e9 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,6 +3,7 @@ import { installAndroidSdk } from './sdk-installer';
 import { checkApiLevel, checkTarget, checkArch, checkDisableAnimations } from './input-validator';
 import { launchEmulator, killEmulator } from './emulator-manager';
 import * as exec from '@actions/exec';
+import { parseScript } from './script-parser';
 
 async function run() {
   try {
@@ -25,7 +26,7 @@ async function run() {
     // CPU architecture of the system image
     const arch = core.getInput('arch');
     checkArch(arch);
-    console.log(`CPI architecture: ${arch}`);
+    console.log(`CPU architecture: ${arch}`);
 
     // Hardware profile used for creating the AVD
     const profile = core.getInput('profile');
@@ -41,8 +42,13 @@ async function run() {
     const disableAnimations = disableAnimationsInput === 'true';
     console.log(`disable animations: ${disableAnimations}`);
 
-    // custom scrpt to run
-    const script = core.getInput('script', { required: true });
+    // custom script to run
+    const scriptInput = core.getInput('script', { required: true });
+    const scripts = parseScript(scriptInput);
+    console.log(`Script:`);
+    scripts.forEach(async (script: string) => {
+      console.log(`${script}`);
+    });
 
     try {
       // install SDK
@@ -50,13 +56,19 @@ async function run() {
 
       // launch an emulator
       await launchEmulator(apiLevel, target, arch, profile, emulatorOptions, disableAnimations);
-
-      // execute the custom script
-      await exec.exec(`${script}`);
     } catch (error) {
       core.setFailed(error.message);
     }
 
+    // execute the custom script
+    scripts.forEach(async (script: string) => {
+      try {
+        await exec.exec(`${script}`);
+      } catch (error) {
+        core.setFailed(error.message);
+      }
+    });
+
     // finally kill the emulator
     await killEmulator();
   } catch (error) {
diff --git a/src/script-parser.ts b/src/script-parser.ts
new file mode 100644
index 0000000..813d36b
--- /dev/null
+++ b/src/script-parser.ts
@@ -0,0 +1,18 @@
+/**
+ * Convert a (potentially multi-line) script to an array of single-line script(s).
+ */
+export function parseScript(rawScript: string): Array<string> {
+  const scripts: Array<string> = rawScript
+    .trim()
+    .split(/\r\n|\n|\r/)
+    .map((value: string) => value.trim())
+    .filter((value: string) => {
+      return !value.startsWith('#') && value.length > 0;
+    });
+
+  if (scripts.length == 0) {
+    throw new Error(`No valid script found.`);
+  }
+
+  return scripts;
+}


Test patch:
diff --git a/__tests__/script-parser.test.ts b/__tests__/script-parser.test.ts
new file mode 100644
index 0000000..6bb4cde
--- /dev/null
+++ b/__tests__/script-parser.test.ts
@@ -0,0 +1,33 @@
+import * as parser from '../src/script-parser';
+
+describe('script parser tests', () => {
+  it('Scripts are trimmed', () => {
+    const script = ` command \n`;
+    expect(parser.parseScript(script)).toEqual(['command']);
+  });
+
+  it('Commented lines are filtered out', () => {
+    const script = `
+      # command1
+      command2 
+
+      # command3
+      command4
+      `;
+    expect(parser.parseScript(script)).toEqual(['command2', 'command4']);
+  });
+
+  it('Throws if parsed scripts array is empty', () => {
+    const func = () => {
+      const script = `
+        # command1
+
+        # command2
+
+      `;
+      const result = parser.parseScript(script);
+      console.log(`Result: ${result}`);
+    };
+    expect(func).toThrowError(`No valid script found.`);
+  });
+});