fastlane-plugin-maestro_orchestration 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -5
- data/lib/fastlane/plugin/maestro_orchestration/actions/maestro_orchestration_android_action.rb +8 -116
- data/lib/fastlane/plugin/maestro_orchestration/helper/maestro_orchestration_helper.rb +29 -101
- data/lib/fastlane/plugin/maestro_orchestration/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31054bd007a386794670905de05851f52f08ec754a2ace35738005dcafc761f5
|
4
|
+
data.tar.gz: f34f027a6eceed37ba8c6de14a5fb5f06c59dce196cdc59e5b6944147820772e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 542ab46c6d2b8f30f77b6a5800829443a96d1427c5db632c399bacbc3f1dec302421de6f81d7768b7c82e90047ec7892c33a2c02e2052a878d34f84934dbf4d7
|
7
|
+
data.tar.gz: 2c2e163734d8e63bc4177ed4f86edbb20a05503ef8af892f159f047eceb13114df54424d18585ad678304f903e41e396062a9ed8f6ff4a82d113c2dcfad9ecaf
|
data/README.md
CHANGED
@@ -28,15 +28,12 @@ Executes Maestro test suites within your Fastlane lanes, facilitating automated
|
|
28
28
|
| `device_type` | `MAESTRO_IOS_DEVICE` | The iOS simulator device type for new simulator (e.g., iPhone #, iPad, etc...). <br> **Default value:** 'com.apple.CoreSimulator.SimDeviceType.iPhone-15'|
|
29
29
|
|
30
30
|
## Parameters `Android`
|
31
|
-
|
31
|
+
For Android, we utilize the [Android Emulator Runner](https://github.com/ReactiveCircus/android-emulator-runner
|
32
|
+
) by ReactiveCircus, which efficiently manages the setup and initialization of the emulator.
|
32
33
|
| Parameter | Env Name | Notes |
|
33
34
|
| ------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
34
35
|
| `sdk_dir` | `MAESTRO_ANDROID_SDK_DIR` | Path to the Android SDK DIR. <br> **Required** `ENV["ANDROID_HOME"]`, `ENV["ANDROID_SDK_ROOT"]`, `~/Library/Android/sdk` |
|
35
36
|
| `maestro_flow_file` | `MAESTRO_IOS_FLOW_FILE` | The path to the Maestro flows YAML file. <br> **Required** |
|
36
|
-
| `emulator_name` | `MAESTRO_AVD_NAME` | Name of the AVD. <br> **Default value:** 'Maestro\_Android\_Emulator' |
|
37
|
-
| `emulator_package` | `MAESTRO_AVD_PACKAGE` | The selected system image of the emulator. <br> **Default value:** 'system-images;android-35;google_apis_playstore;arm64-v8a' |
|
38
|
-
| `emulator_device` | `MAESTRO_AVD_DEVICE` | Type of android device. <br> **Default value:** 'pixel_7_pro' |
|
39
|
-
| `emulator_port` | `MAESTRO_AVD_PORT` | Port of the emulator. <br> **Default value:** 5554 |
|
40
37
|
|
41
38
|
### 2. `maestro_orchestartion_s3_upload`
|
42
39
|
Uploads a folder of files (such as screenshots) to an S3 bucket, organizing them based on the app version, theme, and device type.
|
data/lib/fastlane/plugin/maestro_orchestration/actions/maestro_orchestration_android_action.rb
CHANGED
@@ -7,7 +7,7 @@ module Fastlane
|
|
7
7
|
module Actions
|
8
8
|
class MaestroOrchestrationAndroidAction < Action
|
9
9
|
def self.run(params)
|
10
|
-
required_params = [:
|
10
|
+
required_params = [:maestro_flow_file]
|
11
11
|
missing_params = required_params.select { |param| params[param].nil? }
|
12
12
|
|
13
13
|
if missing_params.any?
|
@@ -21,8 +21,7 @@ module Fastlane
|
|
21
21
|
|
22
22
|
adb = Helper::AdbHelper.new
|
23
23
|
|
24
|
-
|
25
|
-
sleep(5)
|
24
|
+
sleep(5) # Give time emulator to boot
|
26
25
|
demo_mode(params)
|
27
26
|
install_android_app(params)
|
28
27
|
|
@@ -46,82 +45,6 @@ module Fastlane
|
|
46
45
|
UI.success("Android emulator killed. Process finished.")
|
47
46
|
end
|
48
47
|
|
49
|
-
def self.setup_emulator(params)
|
50
|
-
emulator = Helper::EmulatorHelper.new
|
51
|
-
adb = Helper::AdbHelper.new
|
52
|
-
avdmanager = Helper::AvdHelper.new
|
53
|
-
|
54
|
-
UI.message("Stop all running emulators...")
|
55
|
-
devices = adb.load_all_devices
|
56
|
-
UI.success("Devices: #{devices}")
|
57
|
-
|
58
|
-
if devices.empty?
|
59
|
-
UI.message("No running emulators found.")
|
60
|
-
else
|
61
|
-
devices.each do |device|
|
62
|
-
UI.message("Stopping emulator: #{device.serial}")
|
63
|
-
adb.trigger(command: "emu kill", serial: device.serial)
|
64
|
-
sleep(10)
|
65
|
-
system("Stopped emulator: #{device.serial}")
|
66
|
-
end
|
67
|
-
end
|
68
|
-
UI.message("Waiting for all emulators to stop...")
|
69
|
-
sleep(10)
|
70
|
-
|
71
|
-
# Check if there is an AVD with this name, if so, delete it
|
72
|
-
UI.message("Checking if AVD exists with name: #{params[:emulator_name]}...")
|
73
|
-
avd_exists = `#{avdmanager.avdmanager_path} list avd`.include?(params[:emulator_name])
|
74
|
-
|
75
|
-
if avd_exists
|
76
|
-
UI.message("AVD found, deleting existing AVD: #{params[:emulator_name]}...")
|
77
|
-
avdmanager.delete_avd(name: params[:emulator_name])
|
78
|
-
else
|
79
|
-
UI.message("No existing AVD found with that name.")
|
80
|
-
end
|
81
|
-
|
82
|
-
UI.message("Setting up new Android emulator...")
|
83
|
-
avdmanager.create_avd(name: params[:emulator_name], package: params[:emulator_package], device: params[:emulator_device])
|
84
|
-
|
85
|
-
UI.message("Starting Android emulator...")
|
86
|
-
emulator.start_emulator(name: params[:emulator_name], port: params[:emulator_port])
|
87
|
-
adb.trigger(command: "wait-for-device", serial: "emulator-#{params[:emulator_port]}")
|
88
|
-
|
89
|
-
max_retries = 10
|
90
|
-
booted = Helper::MaestroOrchestrationHelper.wait_for_emulator_to_boot(adb, max_retries, "emulator-#{params[:emulator_port]}")
|
91
|
-
|
92
|
-
unless booted
|
93
|
-
UI.error("Emulator failed to boot after #{max_retries} attempts. Restarting ADB server...")
|
94
|
-
adb.trigger(command: "kill-server")
|
95
|
-
|
96
|
-
# Shut down the current emulator, delete it, create a new one, and restart ADB server
|
97
|
-
UI.message("Shutting down current emulator and deleting the AVD...")
|
98
|
-
adb.trigger(command: "emu kill", serial: "emulator-#{params[:emulator_port]}")
|
99
|
-
sleep(5) # Ensure the emulator is killed
|
100
|
-
avdmanager.delete_avd(name: params[:emulator_name])
|
101
|
-
|
102
|
-
UI.message("Creating new AVD...")
|
103
|
-
avdmanager.create_avd(name: params[:emulator_name], package: params[:emulator_package], device: params[:emulator_device])
|
104
|
-
|
105
|
-
UI.message("Restarting ADB server...")
|
106
|
-
adb.trigger(command: "start-server")
|
107
|
-
UI.message("ADB server restarted. Starting new emulator...")
|
108
|
-
|
109
|
-
# Start the newly created emulator
|
110
|
-
emulator.start_emulator(name: params[:emulator_name], port: params[:emulator_port])
|
111
|
-
adb.trigger(command: "wait-for-device", serial: "emulator-#{params[:emulator_port]}")
|
112
|
-
|
113
|
-
# Retry boot process after restarting ADB server
|
114
|
-
booted = Helper::MaestroOrchestrationHelper.wait_for_emulator_to_boot(adb, max_retries, "emulator-#{params[:emulator_port]}")
|
115
|
-
end
|
116
|
-
|
117
|
-
if booted
|
118
|
-
UI.success("Emulator is online and fully booted!")
|
119
|
-
else
|
120
|
-
UI.error("Emulator failed to boot even after restarting AVD and ADB server.")
|
121
|
-
raise "Failed to boot emulator. Please check emulator logs and configuration."
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
48
|
def self.demo_mode(params)
|
126
49
|
adb = Helper::AdbHelper.new
|
127
50
|
adb.load_all_devices
|
@@ -144,10 +67,14 @@ module Fastlane
|
|
144
67
|
adb.load_all_devices
|
145
68
|
serial = adb.devices.first.serial
|
146
69
|
|
70
|
+
UI.message("Generating 'assembleRelease' build...")
|
71
|
+
# Trigger the 'assembleRelease' build
|
72
|
+
system("./gradlew assembleRelease")
|
73
|
+
# After building, try to find the APK file in the release output directory
|
147
74
|
apk_path = Dir["app/build/outputs/apk/release/*.apk"].first
|
148
|
-
|
75
|
+
# If still not found after building, raise an error
|
149
76
|
if apk_path.nil?
|
150
|
-
UI.user_error!("Error: APK file not found in build outputs.")
|
77
|
+
UI.user_error!("Error: APK file not found in build outputs even after running assembleRelease.")
|
151
78
|
end
|
152
79
|
|
153
80
|
UI.message("Found APK file at: #{apk_path}")
|
@@ -171,41 +98,6 @@ module Fastlane
|
|
171
98
|
UI.user_error!("No ANDROID_SDK_DIR given, pass using `sdk_dir: 'sdk_dir'`") unless value && !value.empty?
|
172
99
|
end
|
173
100
|
),
|
174
|
-
FastlaneCore::ConfigItem.new(
|
175
|
-
key: :emulator_name,
|
176
|
-
env_name: "MAESTRO_AVD_NAME",
|
177
|
-
description: "Name of the AVD",
|
178
|
-
default_value: "Maestro_Android_Emulator",
|
179
|
-
optional: true
|
180
|
-
),
|
181
|
-
FastlaneCore::ConfigItem.new(
|
182
|
-
key: :emulator_package,
|
183
|
-
env_name: "MAESTRO_AVD_PACKAGE",
|
184
|
-
description: "The selected system image of the emulator",
|
185
|
-
default_value: "system-images;android-35;google_apis_playstore;arm64-v8a",
|
186
|
-
optional: true
|
187
|
-
),
|
188
|
-
FastlaneCore::ConfigItem.new(
|
189
|
-
key: :emulator_device,
|
190
|
-
env_name: "MAESTRO_AVD_DEVICE",
|
191
|
-
description: "Device",
|
192
|
-
default_value: "pixel_7_pro",
|
193
|
-
optional: true
|
194
|
-
),
|
195
|
-
FastlaneCore::ConfigItem.new(
|
196
|
-
key: :location,
|
197
|
-
env_name: "MAESTRO_AVD_LOCATION",
|
198
|
-
description: "Set location of the emulator '<longitude> <latitude>'",
|
199
|
-
default_value: "28.0362979, -82.4930012",
|
200
|
-
optional: true
|
201
|
-
),
|
202
|
-
FastlaneCore::ConfigItem.new(
|
203
|
-
key: :emulator_port,
|
204
|
-
env_name: "MAESTRO_AVD_PORT",
|
205
|
-
description: "Port of the emulator",
|
206
|
-
default_value: "5554",
|
207
|
-
optional: true
|
208
|
-
),
|
209
101
|
FastlaneCore::ConfigItem.new(
|
210
102
|
key: :maestro_flow_file,
|
211
103
|
env_name: "MAESTRO_ANDROID_FLOW_FILE",
|
@@ -10,8 +10,35 @@ module Fastlane
|
|
10
10
|
# class methods that you define here become available in your action
|
11
11
|
# as `Helper::MaestroOrchestrationHelper.your_method`
|
12
12
|
#
|
13
|
-
def self.
|
14
|
-
UI.message("
|
13
|
+
def self.stop_all_emulators(adb)
|
14
|
+
UI.message("Stop all running emulators...")
|
15
|
+
devices = adb.load_all_devices
|
16
|
+
UI.success("Devices: #{devices}")
|
17
|
+
|
18
|
+
devices.each do |device|
|
19
|
+
UI.message("Stopping emulator: #{device.serial}")
|
20
|
+
adb.trigger(command: "emu kill", serial: device.serial)
|
21
|
+
sleep(10)
|
22
|
+
end
|
23
|
+
UI.message("Waiting for all emulators to stop...")
|
24
|
+
sleep(10)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.handle_boot_failure(params, avdmanager, adb, emulator)
|
28
|
+
adb.trigger(command: "kill-server")
|
29
|
+
adb.trigger(command: "emu kill", serial: "emulator-#{params[:emulator_port]}")
|
30
|
+
sleep(5)
|
31
|
+
avdmanager.delete_avd(name: params[:emulator_name])
|
32
|
+
|
33
|
+
UI.message("Creating new AVD...")
|
34
|
+
avdmanager.create_avd(name: params[:emulator_name], package: params[:emulator_package], device: params[:emulator_device])
|
35
|
+
|
36
|
+
UI.message("Restarting ADB server...")
|
37
|
+
adb.trigger(command: "start-server")
|
38
|
+
UI.message("ADB server restarted. Starting new emulator...")
|
39
|
+
|
40
|
+
emulator.start_emulator(name: params[:emulator_name], port: params[:emulator_port])
|
41
|
+
adb.trigger(command: "wait-for-device", serial: "emulator-#{params[:emulator_port]}")
|
15
42
|
end
|
16
43
|
|
17
44
|
def self.wait_for_emulator_to_boot(adb, max_retries, serial)
|
@@ -85,104 +112,5 @@ module Fastlane
|
|
85
112
|
UI.error("Error removing file #{file_path}: #{e.message}")
|
86
113
|
end
|
87
114
|
end
|
88
|
-
|
89
|
-
class AvdHelper
|
90
|
-
# Path to the avd binary
|
91
|
-
attr_accessor :avdmanager_path
|
92
|
-
# Available AVDs
|
93
|
-
attr_accessor :avds
|
94
|
-
|
95
|
-
def initialize(avdmanager_path: nil)
|
96
|
-
android_home = ENV.fetch('ANDROID_HOME', nil) || ENV.fetch('ANDROID_SDK_ROOT', nil)
|
97
|
-
if (avdmanager_path.nil? || avdmanager_path == "avdmanager") && android_home
|
98
|
-
# First search for cmdline-tools dir
|
99
|
-
cmdline_tools_path = File.join(android_home, "cmdline-tools")
|
100
|
-
|
101
|
-
# Find the first available 'bin' folder within cmdline-tools
|
102
|
-
available_path = Dir.glob(File.join(cmdline_tools_path, "*", "bin")).first
|
103
|
-
raise "No valid bin path found in #{cmdline_tools_path}" unless available_path
|
104
|
-
|
105
|
-
avdmanager_path = File.join(available_path, "avdmanager")
|
106
|
-
end
|
107
|
-
|
108
|
-
self.avdmanager_path = Helper.get_executable_path(File.expand_path(avdmanager_path))
|
109
|
-
end
|
110
|
-
|
111
|
-
def trigger(command: nil)
|
112
|
-
raise "avdmanager_path is not set" unless avdmanager_path
|
113
|
-
|
114
|
-
# Build and execute the command
|
115
|
-
command = [avdmanager_path.shellescape, command].compact.join(" ").strip
|
116
|
-
Action.sh(command)
|
117
|
-
end
|
118
|
-
|
119
|
-
# Create a new AVD
|
120
|
-
def create_avd(name:, package:, device: "pixel_7_pro")
|
121
|
-
raise "AVD name is required" if name.nil? || name.empty?
|
122
|
-
raise "System image package is required" if package.nil? || package.empty?
|
123
|
-
|
124
|
-
command = [
|
125
|
-
"create avd",
|
126
|
-
"-n #{name.shellescape}",
|
127
|
-
"-f",
|
128
|
-
"-k \"#{package}\"",
|
129
|
-
"-d #{device.shellescape}"
|
130
|
-
].join(" ")
|
131
|
-
|
132
|
-
trigger(command: command)
|
133
|
-
end
|
134
|
-
|
135
|
-
# Delete an existing AVD
|
136
|
-
def delete_avd(name:)
|
137
|
-
raise "AVD name is required" if name.nil? || name.empty?
|
138
|
-
|
139
|
-
command = [
|
140
|
-
"delete avd",
|
141
|
-
"-n #{name.shellescape}"
|
142
|
-
].join(" ")
|
143
|
-
|
144
|
-
trigger(command: command)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
class EmulatorHelper
|
149
|
-
attr_accessor :emulator_path
|
150
|
-
|
151
|
-
def initialize(emulator_path: nil)
|
152
|
-
android_home = ENV.fetch('ANDROID_HOME', nil) || ENV.fetch('ANDROID_SDK_ROOT', nil)
|
153
|
-
if (emulator_path.nil? || emulator_path == "avdmanager") && android_home
|
154
|
-
emulator_path = File.join(android_home, "emulator", "emulator")
|
155
|
-
end
|
156
|
-
|
157
|
-
self.emulator_path = Helper.get_executable_path(File.expand_path(emulator_path))
|
158
|
-
end
|
159
|
-
|
160
|
-
def trigger(command: nil)
|
161
|
-
raise "emulator_path is not set" unless emulator_path
|
162
|
-
|
163
|
-
# Build and execute the command
|
164
|
-
command = [emulator_path.shellescape, command].compact.join(" ").strip
|
165
|
-
Action.sh(command)
|
166
|
-
end
|
167
|
-
|
168
|
-
# Start an emulator instance
|
169
|
-
def start_emulator(name:, port:)
|
170
|
-
raise "Emulator name is required" if name.nil? || name.empty?
|
171
|
-
raise "Port is required" if port.nil? || port.to_s.empty?
|
172
|
-
|
173
|
-
command = [
|
174
|
-
"-avd #{name.shellescape}",
|
175
|
-
"-port #{port.shellescape}",
|
176
|
-
"-wipe-data",
|
177
|
-
"-no-boot-anim",
|
178
|
-
"-no-snapshot",
|
179
|
-
"-no-audio",
|
180
|
-
"> /dev/null 2>&1 &"
|
181
|
-
].join(" ")
|
182
|
-
|
183
|
-
UI.message("Starting emulator #{name} on port #{port}...")
|
184
|
-
trigger(command: command)
|
185
|
-
end
|
186
|
-
end
|
187
115
|
end
|
188
116
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-maestro_orchestration
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nemanja Risteski
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-02-
|
10
|
+
date: 2025-02-13 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: fastlane-plugin-android_emulator
|