fastlane 2.135.2 → 2.140.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +64 -64
  3. data/deliver/lib/deliver/submit_for_review.rb +7 -1
  4. data/fastlane/lib/fastlane/action.rb +2 -2
  5. data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
  6. data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
  7. data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
  8. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +1 -1
  9. data/fastlane/lib/fastlane/actions/create_pull_request.rb +42 -2
  10. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +38 -4
  11. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +19 -0
  12. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +10 -0
  13. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +4 -2
  14. data/fastlane/lib/fastlane/actions/ensure_bundle_exec.rb +3 -3
  15. data/fastlane/lib/fastlane/actions/get_version_number.rb +7 -2
  16. data/fastlane/lib/fastlane/actions/gradle.rb +54 -3
  17. data/fastlane/lib/fastlane/actions/increment_version_number.rb +6 -3
  18. data/fastlane/lib/fastlane/actions/last_git_tag.rb +14 -5
  19. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +2 -2
  20. data/fastlane/lib/fastlane/actions/register_devices.rb +5 -1
  21. data/fastlane/lib/fastlane/actions/ruby_version.rb +1 -1
  22. data/fastlane/lib/fastlane/actions/run_tests.rb +5 -22
  23. data/fastlane/lib/fastlane/actions/setup_ci.rb +14 -8
  24. data/fastlane/lib/fastlane/actions/testfairy.rb +8 -1
  25. data/fastlane/lib/fastlane/actions/upload_to_play_store_internal_app_sharing.rb +78 -0
  26. data/fastlane/lib/fastlane/actions/verify_build.rb +1 -1
  27. data/fastlane/lib/fastlane/actions/xcode_select.rb +6 -1
  28. data/fastlane/lib/fastlane/cli_tools_distributor.rb +2 -2
  29. data/fastlane/lib/fastlane/commands_generator.rb +1 -1
  30. data/fastlane/lib/fastlane/helper/adb_helper.rb +13 -4
  31. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
  32. data/fastlane/lib/fastlane/runner.rb +23 -18
  33. data/fastlane/lib/fastlane/swift_fastlane_function.rb +9 -0
  34. data/fastlane/lib/fastlane/version.rb +1 -1
  35. data/fastlane/swift/Deliverfile.swift +1 -1
  36. data/fastlane/swift/Fastlane.swift +130 -28
  37. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  38. data/fastlane/swift/Gymfile.swift +1 -1
  39. data/fastlane/swift/Matchfile.swift +1 -1
  40. data/fastlane/swift/MatchfileProtocol.swift +6 -2
  41. data/fastlane/swift/Precheckfile.swift +1 -1
  42. data/fastlane/swift/Scanfile.swift +1 -1
  43. data/fastlane/swift/ScanfileProtocol.swift +13 -1
  44. data/fastlane/swift/Screengrabfile.swift +1 -1
  45. data/fastlane/swift/ScreengrabfileProtocol.swift +14 -2
  46. data/fastlane/swift/Snapshotfile.swift +1 -1
  47. data/fastlane_core/lib/fastlane_core/.build_watcher.rb.swp +0 -0
  48. data/fastlane_core/lib/fastlane_core/build_watcher.rb +6 -2
  49. data/fastlane_core/lib/fastlane_core/device_manager.rb +20 -0
  50. data/fastlane_core/lib/fastlane_core/helper.rb +7 -1
  51. data/frameit/lib/frameit/editor.rb +3 -0
  52. data/gym/lib/gym/generators/build_command_generator.rb +1 -0
  53. data/gym/lib/gym/runner.rb +38 -19
  54. data/match/lib/match/options.rb +8 -0
  55. data/match/lib/match/runner.rb +1 -0
  56. data/match/lib/match/storage/git_storage.rb +7 -2
  57. data/pilot/lib/pilot/.manager.rb.swp +0 -0
  58. data/pilot/lib/pilot/build_manager.rb +46 -12
  59. data/pilot/lib/pilot/options.rb +3 -1
  60. data/scan/lib/scan/detect_values.rb +6 -1
  61. data/scan/lib/scan/manager.rb +18 -1
  62. data/scan/lib/scan/options.rb +17 -0
  63. data/scan/lib/scan/runner.rb +6 -0
  64. data/scan/lib/scan/slack_poster.rb +1 -1
  65. data/scan/lib/scan/test_command_generator.rb +1 -1
  66. data/screengrab/lib/screengrab/module.rb +2 -0
  67. data/screengrab/lib/screengrab/options.rb +24 -11
  68. data/screengrab/lib/screengrab/runner.rb +79 -42
  69. data/spaceship/lib/spaceship/client.rb +9 -4
  70. data/spaceship/lib/spaceship/connect_api.rb +2 -0
  71. data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
  72. data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -0
  73. data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +71 -0
  74. data/spaceship/lib/spaceship/connect_api/models/beta_screenshot.rb +18 -0
  75. data/spaceship/lib/spaceship/connect_api/models/build.rb +5 -0
  76. data/spaceship/lib/spaceship/connect_api/models/build_beta_detail.rb +5 -0
  77. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +9 -0
  78. data/spaceship/lib/spaceship/portal/.certificate.rb.swp +0 -0
  79. data/spaceship/lib/spaceship/tunes/iap.rb +11 -11
  80. data/spaceship/lib/spaceship/tunes/iap_detail.rb +7 -3
  81. data/spaceship/lib/spaceship/tunes/iap_families.rb +12 -1
  82. data/spaceship/lib/spaceship/tunes/iap_family_details.rb +26 -17
  83. data/spaceship/lib/spaceship/tunes/tunes_client.rb +4 -7
  84. data/supply/lib/supply/client.rb +27 -0
  85. data/supply/lib/supply/options.rb +8 -2
  86. data/supply/lib/supply/uploader.rb +82 -33
  87. metadata +49 -26
  88. data/supply/lib/supply/.options.rb.swp +0 -0
  89. data/supply/lib/supply/.uploader.rb.swp +0 -0
@@ -132,7 +132,9 @@ module Pilot
132
132
  FastlaneCore::ConfigItem.new(key: :skip_waiting_for_build_processing,
133
133
  short_option: "-z",
134
134
  env_name: "PILOT_SKIP_WAITING_FOR_BUILD_PROCESSING",
135
- description: "Don't wait for the build to process. If set to true, the changelog won't be set, `distribute_external` option won't work and no build will be distributed to testers. (You might want to use this option if you are using this action on CI and have to pay for 'minutes used' on your CI plan)",
135
+ description: "If set to true, the `distribute_external` option won't work and no build will be distributed to testers. " \
136
+ "(You might want to use this option if you are using this action on CI and have to pay for 'minutes used' on your CI plan). " \
137
+ "If set to `true` and a changelog is provided, it will partially wait for the build to appear on AppStore Connect so the changelog can be set, and skip the remaining processing steps",
136
138
  is_string: false,
137
139
  default_value: false),
138
140
  FastlaneCore::ConfigItem.new(key: :update_build_info_on_upload,
@@ -108,7 +108,7 @@ module Scan
108
108
  def self.detect_simulator(devices, requested_os_type, deployment_target_key, default_device_name, simulator_type_descriptor)
109
109
  require 'set'
110
110
 
111
- deployment_target_version = Scan.project.build_settings(key: deployment_target_key) || '0'
111
+ deployment_target_version = get_deployment_target_version(deployment_target_key)
112
112
 
113
113
  simulators = filter_simulators(
114
114
  FastlaneCore::DeviceManager.simulators(requested_os_type).tap do |array|
@@ -215,5 +215,10 @@ module Scan
215
215
  Scan.config[:destination] = min_xcode8? ? ["platform=macOS"] : ["platform=OS X"]
216
216
  end
217
217
  end
218
+
219
+ # get deployment target version
220
+ def self.get_deployment_target_version(deployment_target_key)
221
+ Scan.config[:deployment_target_version] || Scan.project.build_settings(key: deployment_target_key) || '0'
222
+ end
218
223
  end
219
224
  end
@@ -4,8 +4,13 @@ require_relative 'runner'
4
4
 
5
5
  module Scan
6
6
  class Manager
7
+ attr_accessor :plist_files_before
8
+
7
9
  def work(options)
8
- Scan.config = options
10
+ Scan.config = options # we set this here to auto-detect missing values, which we need later on
11
+ unless options[:derived_data_path].to_s.empty?
12
+ self.plist_files_before = test_summary_filenames(Scan.config[:derived_data_path])
13
+ end
9
14
 
10
15
  # Also print out the path to the used Xcode installation
11
16
  # We go 2 folders up, to not show "Contents/Developer/"
@@ -17,5 +22,17 @@ module Scan
17
22
 
18
23
  return Runner.new.run
19
24
  end
25
+
26
+ def test_summary_filenames(derived_data_path)
27
+ files = []
28
+
29
+ # Xcode < 10
30
+ files += Dir["#{derived_data_path}/**/Logs/Test/*TestSummaries.plist"]
31
+
32
+ # Xcode 10
33
+ files += Dir["#{derived_data_path}/**/Logs/Test/*.xcresult/TestSummaries.plist"]
34
+
35
+ return files
36
+ end
20
37
  end
21
38
  end
@@ -81,6 +81,11 @@ module Scan
81
81
  description: "Enabling this option will automatically erase the simulator before running the application",
82
82
  default_value: false,
83
83
  type: Boolean),
84
+ FastlaneCore::ConfigItem.new(key: :disable_slide_to_type,
85
+ env_name: 'SCAN_DISABLE_SLIDE_TO_TYPE',
86
+ description: "Enabling this option will disable the simulator from showing the 'Slide to type' prompt",
87
+ default_value: true,
88
+ type: Boolean),
84
89
  FastlaneCore::ConfigItem.new(key: :prelaunch_simulator,
85
90
  env_name: 'SCAN_PRELAUNCH_SIMULATOR',
86
91
  description: "Enabling this option will launch the first simulator prior to calling any xcodebuild command",
@@ -311,6 +316,18 @@ module Scan
311
316
  UI.user_error!("File not found at path '#{File.expand_path(value)}'") unless File.exist?(value)
312
317
  end),
313
318
 
319
+ # build settings
320
+ FastlaneCore::ConfigItem.new(key: :app_name,
321
+ env_name: "SCAN_APP_NAME",
322
+ optional: true,
323
+ description: "App name to use in slack message and logfile name",
324
+ is_string: true),
325
+ FastlaneCore::ConfigItem.new(key: :deployment_target_version,
326
+ env_name: "SCAN_DEPLOYMENT_TARGET_VERSION",
327
+ optional: true,
328
+ description: "Target version of the app being build or tested. Used to filter out simulator version",
329
+ is_string: true),
330
+
314
331
  # slack
315
332
  FastlaneCore::ConfigItem.new(key: :slack_url,
316
333
  short_option: "-i",
@@ -31,6 +31,12 @@ module Scan
31
31
  end
32
32
  end
33
33
 
34
+ if Scan.config[:disable_slide_to_type]
35
+ Scan.devices.each do |device|
36
+ FastlaneCore::Simulator.disable_slide_to_type(udid: device.udid)
37
+ end
38
+ end
39
+
34
40
  # We call this method, to be sure that all other simulators are killed
35
41
  # And a correct one is freshly launched. Switching between multiple simulator
36
42
  # in case the user specified multiple targets works with no issues
@@ -44,7 +44,7 @@ module Scan
44
44
  end
45
45
 
46
46
  Fastlane::Actions::SlackAction.run({
47
- message: "#{Scan.project.app_name} Tests:\n#{Scan.config[:slack_message]}",
47
+ message: "#{Scan.config[:app_name] || Scan.project.app_name} Tests:\n#{Scan.config[:slack_message]}",
48
48
  channel: channel,
49
49
  slack_url: Scan.config[:slack_url].to_s,
50
50
  success: results[:build_errors].to_i == 0 && results[:failures].to_i == 0,
@@ -120,7 +120,7 @@ module Scan
120
120
 
121
121
  # Store the raw file
122
122
  def xcodebuild_log_path
123
- file_name = "#{Scan.project.app_name}-#{Scan.config[:scheme]}.log"
123
+ file_name = "#{Scan.config[:app_name] || Scan.project.app_name}-#{Scan.config[:scheme]}.log"
124
124
  containing = File.expand_path(Scan.config[:buildlog_path])
125
125
  FileUtils.mkdir_p(containing)
126
126
 
@@ -1,4 +1,5 @@
1
1
  require 'fastlane_core/helper'
2
+ require 'fastlane/boolean'
2
3
  require_relative 'detect_values'
3
4
 
4
5
  module Screengrab
@@ -19,6 +20,7 @@ module Screengrab
19
20
 
20
21
  Helper = FastlaneCore::Helper # you gotta love Ruby: Helper.* should use the Helper class contained in FastlaneCore
21
22
  UI = FastlaneCore::UI
23
+ Boolean = Fastlane::Boolean
22
24
  ROOT = Pathname.new(File.expand_path('../../..', __FILE__))
23
25
  DESCRIPTION = "Automated localized screenshots of your Android app on every device".freeze
24
26
  end
@@ -32,7 +32,7 @@ module Screengrab
32
32
  env_name: 'SCREENGRAB_CLEAR_PREVIOUS_SCREENSHOTS',
33
33
  description: "Enabling this option will automatically clear previously generated screenshots before running screengrab",
34
34
  default_value: false,
35
- is_string: false),
35
+ type: Boolean),
36
36
  FastlaneCore::ConfigItem.new(key: :output_directory,
37
37
  short_option: "-o",
38
38
  env_name: "SCREENGRAB_OUTPUT_DIRECTORY",
@@ -43,7 +43,7 @@ module Screengrab
43
43
  description: "Don't open the summary after running _screengrab_",
44
44
  default_value: DEFAULT_SKIP_OPEN_SUMMARY,
45
45
  default_value_dynamic: true,
46
- is_string: false),
46
+ type: Boolean),
47
47
  FastlaneCore::ConfigItem.new(key: :app_package_name,
48
48
  env_name: 'SCREENGRAB_APP_PACKAGE_NAME',
49
49
  short_option: "-a",
@@ -68,22 +68,26 @@ module Screengrab
68
68
  type: Array,
69
69
  description: "Only run tests in these Java classes"),
70
70
  FastlaneCore::ConfigItem.new(key: :launch_arguments,
71
- env_name: 'SCREENGRAB_LAUNCH_ARGUMENTS',
72
- optional: true,
73
- short_option: "-e",
74
- type: Array,
75
- description: "Additional launch arguments"),
71
+ env_name: 'SCREENGRAB_LAUNCH_ARGUMENTS',
72
+ optional: true,
73
+ short_option: "-e",
74
+ type: Array,
75
+ description: "Additional launch arguments"),
76
76
  FastlaneCore::ConfigItem.new(key: :test_instrumentation_runner,
77
77
  env_name: 'SCREENGRAB_TEST_INSTRUMENTATION_RUNNER',
78
78
  optional: true,
79
- default_value: 'android.support.test.runner.AndroidJUnitRunner',
79
+ default_value: 'androidx.test.runner.AndroidJUnitRunner',
80
80
  description: "The fully qualified class name of your test instrumentation runner"),
81
81
  FastlaneCore::ConfigItem.new(key: :ending_locale,
82
82
  env_name: 'SCREENGRAB_ENDING_LOCALE',
83
83
  optional: true,
84
- is_string: true,
85
84
  default_value: 'en-US',
86
85
  description: "Return the device to this locale after running tests"),
86
+ FastlaneCore::ConfigItem.new(key: :use_adb_root,
87
+ env_name: 'SCREENGRAB_USE_ADB_ROOT',
88
+ description: "Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors",
89
+ default_value: false,
90
+ type: Boolean),
87
91
  FastlaneCore::ConfigItem.new(key: :app_apk_path,
88
92
  env_name: 'SCREENGRAB_APP_APK_PATH',
89
93
  optional: true,
@@ -123,12 +127,21 @@ module Screengrab
123
127
  env_name: 'EXIT_ON_TEST_FAILURE',
124
128
  description: "Whether or not to exit Screengrab on test failure. Exiting on failure will not copy sceenshots to local machine nor open sceenshots summary",
125
129
  default_value: true,
126
- is_string: false),
130
+ type: Boolean),
127
131
  FastlaneCore::ConfigItem.new(key: :reinstall_app,
128
132
  env_name: 'SCREENGRAB_REINSTALL_APP',
129
133
  description: "Enabling this option will automatically uninstall the application before running it",
130
134
  default_value: false,
131
- is_string: false)
135
+ type: Boolean),
136
+ FastlaneCore::ConfigItem.new(key: :use_timestamp_suffix,
137
+ env_name: 'SCREENGRAB_USE_TIMESTAMP_SUFFIX',
138
+ description: "Add timestamp suffix to screenshot filename",
139
+ default_value: true,
140
+ type: Boolean),
141
+ FastlaneCore::ConfigItem.new(key: :adb_host,
142
+ env_name: 'SCREENGRAB_ADB_HOST',
143
+ description: "Configure the host used by adb to connect, allows running on remote devices farm",
144
+ optional: true)
132
145
  ]
133
146
  end
134
147
  end
@@ -1,5 +1,6 @@
1
1
  require 'fastlane_core/print_table'
2
2
  require 'fastlane_core/command_executor'
3
+ require 'fastlane/helper/adb_helper'
3
4
  require_relative 'reports_generator'
4
5
  require_relative 'module'
5
6
 
@@ -57,8 +58,13 @@ module Screengrab
57
58
 
58
59
  device_screenshots_paths = [
59
60
  determine_external_screenshots_path(device_serial),
60
- determine_internal_screenshots_path
61
- ]
61
+ determine_internal_screenshots_paths(@config[:app_package_name], @config[:locales])
62
+ ].flatten
63
+
64
+ # Root is needed to access device paths at /data
65
+ if @config[:use_adb_root]
66
+ run_adb_command("root", print_all: false, print_command: true)
67
+ end
62
68
 
63
69
  clear_device_previous_screenshots(device_serial, device_screenshots_paths)
64
70
 
@@ -67,6 +73,8 @@ module Screengrab
67
73
 
68
74
  validate_apk(app_apk_path)
69
75
 
76
+ enable_clean_status_bar(device_serial, app_apk_path)
77
+
70
78
  run_tests(device_serial, app_apk_path, tests_apk_path, test_classes_to_use, test_packages_to_use, @config[:launch_arguments])
71
79
 
72
80
  number_of_screenshots = pull_screenshots_from_device(device_serial, device_screenshots_paths, device_type_dir_name)
@@ -77,35 +85,26 @@ module Screengrab
77
85
  end
78
86
 
79
87
  def select_device
80
- devices = run_adb_command("adb devices -l", print_all: true, print_command: true).split("\n")
81
- # the first output by adb devices is "List of devices attached" so remove that and any adb startup output
82
- devices.reject! do |device|
83
- [
84
- 'server is out of date', # The adb server is out of date and must be restarted
85
- 'unauthorized', # The device has not yet accepted ADB control
86
- 'offline', # The device is offline, skip it
87
- '* daemon', # Messages printed when the daemon is starting up
88
- 'List of devices attached', # Header of table for data we want
89
- "doesn't match this client" # Message printed when there is an ADB client/server version mismatch
90
- ].any? { |status| device.include?(status) }
91
- end
88
+ adb = Fastlane::Helper::AdbHelper.new(adb_host: @config[:adb_host])
89
+ devices = adb.load_all_devices
92
90
 
93
91
  UI.user_error!('There are no connected and authorized devices or emulators') if devices.empty?
94
92
 
95
- devices.select! { |d| d.include?(@config[:specific_device]) } if @config[:specific_device]
93
+ specific_device = @config[:specific_device]
94
+ if specific_device
95
+ devices.select! do |d|
96
+ d.serial.include?(specific_device)
97
+ end
98
+ end
96
99
 
97
- UI.user_error!("No connected devices matched your criteria: #{@config[:specific_device]}") if devices.empty?
100
+ UI.user_error!("No connected devices matched your criteria: #{specific_device}") if devices.empty?
98
101
 
99
102
  if devices.length > 1
100
103
  UI.important("Multiple connected devices, selecting the first one")
101
104
  UI.important("To specify which connected device to use, use the -s (specific_device) config option")
102
105
  end
103
106
 
104
- # grab the serial number. the lines of output can look like these:
105
- # 00c22d4d84aec525 device usb:2148663295X product:bullhead model:Nexus_5X device:bullhead
106
- # 192.168.1.100:5555 device usb:2148663295X product:bullhead model:Nexus_5X device:genymotion
107
- # emulator-5554 device usb:2148663295X product:bullhead model:Nexus_5X device:emulator
108
- devices[0].match(/^\S+/)[0]
107
+ devices.first.serial
109
108
  end
110
109
 
111
110
  def select_app_apk(discovered_apk_paths)
@@ -139,15 +138,19 @@ module Screengrab
139
138
  # macOS evaluates $foo in `echo $foo` before executing the command,
140
139
  # Windows doesn't - hence the double backslash vs. single backslash
141
140
  command = Helper.windows? ? "shell echo \$EXTERNAL_STORAGE " : "shell echo \\$EXTERNAL_STORAGE"
142
- device_ext_storage = run_adb_command("adb -s #{device_serial} #{command}",
141
+ device_ext_storage = run_adb_command("-s #{device_serial} #{command}",
143
142
  print_all: true,
144
143
  print_command: true)
145
144
  device_ext_storage = device_ext_storage.strip
146
145
  File.join(device_ext_storage, @config[:app_package_name], 'screengrab')
147
146
  end
148
147
 
149
- def determine_internal_screenshots_path
150
- "/data/data/#{@config[:app_package_name]}/app_screengrab"
148
+ def determine_internal_screenshots_paths(app_package_name, locales)
149
+ locale_paths = locales.map do |locale|
150
+ "/data/user/0/#{app_package_name}/files/#{app_package_name}/screengrab/#{locale}/images/screenshots"
151
+ end
152
+
153
+ return ["/data/data/#{app_package_name}/app_screengrab"] + locale_paths
151
154
  end
152
155
 
153
156
  def clear_device_previous_screenshots(device_serial, device_screenshots_paths)
@@ -155,7 +158,7 @@ module Screengrab
155
158
 
156
159
  device_screenshots_paths.each do |device_path|
157
160
  if_device_path_exists(device_serial, device_path) do |path|
158
- run_adb_command("adb -s #{device_serial} shell rm -rf #{path}",
161
+ run_adb_command("-s #{device_serial} shell rm -rf #{path}",
159
162
  print_all: true,
160
163
  print_command: true)
161
164
  end
@@ -182,13 +185,13 @@ module Screengrab
182
185
 
183
186
  def install_apks(device_serial, app_apk_path, tests_apk_path)
184
187
  UI.message('Installing app APK')
185
- apk_install_output = run_adb_command("adb -s #{device_serial} install -t -r #{app_apk_path.shellescape}",
188
+ apk_install_output = run_adb_command("-s #{device_serial} install -t -r #{app_apk_path.shellescape}",
186
189
  print_all: true,
187
190
  print_command: true)
188
191
  UI.user_error!("App APK could not be installed") if apk_install_output.include?("Failure [")
189
192
 
190
193
  UI.message('Installing tests APK')
191
- apk_install_output = run_adb_command("adb -s #{device_serial} install -t -r #{tests_apk_path.shellescape}",
194
+ apk_install_output = run_adb_command("-s #{device_serial} install -t -r #{tests_apk_path.shellescape}",
192
195
  print_all: true,
193
196
  print_command: true)
194
197
  UI.user_error!("Tests APK could not be installed") if apk_install_output.include?("Failure [")
@@ -199,14 +202,14 @@ module Screengrab
199
202
 
200
203
  if packages.include?(app_package_name.to_s)
201
204
  UI.message('Uninstalling app APK')
202
- run_adb_command("adb -s #{device_serial} uninstall #{app_package_name}",
205
+ run_adb_command("-s #{device_serial} uninstall #{app_package_name}",
203
206
  print_all: true,
204
207
  print_command: true)
205
208
  end
206
209
 
207
210
  if packages.include?(tests_package_name.to_s)
208
211
  UI.message('Uninstalling tests APK')
209
- run_adb_command("adb -s #{device_serial} uninstall #{tests_package_name}",
212
+ run_adb_command("-s #{device_serial} uninstall #{tests_package_name}",
210
213
  print_all: true,
211
214
  print_command: true)
212
215
  end
@@ -214,20 +217,16 @@ module Screengrab
214
217
 
215
218
  def grant_permissions(device_serial)
216
219
  UI.message('Granting the permission necessary to change locales on the device')
217
- run_adb_command("adb -s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.CHANGE_CONFIGURATION",
220
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.CHANGE_CONFIGURATION",
218
221
  print_all: true,
219
222
  print_command: true)
220
223
 
221
- device_api_version = run_adb_command("adb -s #{device_serial} shell getprop ro.build.version.sdk",
222
- print_all: true,
223
- print_command: true).to_i
224
-
225
- if device_api_version >= 23
224
+ if device_api_version(device_serial) >= 23
226
225
  UI.message('Granting the permissions necessary to access device external storage')
227
- run_adb_command("adb -s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.WRITE_EXTERNAL_STORAGE",
226
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.WRITE_EXTERNAL_STORAGE",
228
227
  print_all: true,
229
228
  print_command: true)
230
- run_adb_command("adb -s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.READ_EXTERNAL_STORAGE",
229
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.READ_EXTERNAL_STORAGE",
231
230
  print_all: true,
232
231
  print_command: true)
233
232
  end
@@ -252,9 +251,10 @@ module Screengrab
252
251
  def run_tests_for_locale(locale, device_serial, test_classes_to_use, test_packages_to_use, launch_arguments)
253
252
  UI.message("Running tests for locale: #{locale}")
254
253
 
255
- instrument_command = ["adb -s #{device_serial} shell am instrument --no-window-animation -w",
254
+ instrument_command = ["-s #{device_serial} shell am instrument --no-window-animation -w",
256
255
  "-e testLocale #{locale.tr('-', '_')}",
257
256
  "-e endingLocale #{@config[:ending_locale].tr('-', '_')}"]
257
+ instrument_command << "-e appendTimestamp #{@config[:use_timestamp_suffix]}"
258
258
  instrument_command << "-e class #{test_classes_to_use.join(',')}" if test_classes_to_use
259
259
  instrument_command << "-e package #{test_packages_to_use.join(',')}" if test_packages_to_use
260
260
  instrument_command << launch_arguments.map { |item| '-e ' + item }.join(' ') if launch_arguments
@@ -281,10 +281,11 @@ module Screengrab
281
281
 
282
282
  # Make a temp directory into which to pull the screenshots before they are moved to their final location.
283
283
  # This makes directory cleanup easier, as the temp directory will be removed when the block completes.
284
+
284
285
  Dir.mktmpdir do |tempdir|
285
286
  device_screenshots_paths.each do |device_path|
286
287
  if_device_path_exists(device_serial, device_path) do |path|
287
- run_adb_command("adb -s #{device_serial} pull #{path} #{tempdir}",
288
+ run_adb_command("-s #{device_serial} pull #{path} #{tempdir}",
288
289
  print_all: false,
289
290
  print_command: true)
290
291
  end
@@ -347,7 +348,7 @@ module Screengrab
347
348
  # Some device commands fail if executed against a device path that does not exist, so this helper method
348
349
  # provides a way to conditionally execute a block only if the provided path exists on the device.
349
350
  def if_device_path_exists(device_serial, device_path)
350
- return if run_adb_command("adb -s #{device_serial} shell ls #{device_path}",
351
+ return if run_adb_command("-s #{device_serial} shell ls #{device_path}",
351
352
  print_all: false,
352
353
  print_command: false).include?('No such file')
353
354
 
@@ -359,7 +360,7 @@ module Screengrab
359
360
 
360
361
  # Return an array of packages that are installed on the device
361
362
  def installed_packages(device_serial)
362
- packages = run_adb_command("adb -s #{device_serial} shell pm list packages",
363
+ packages = run_adb_command("-s #{device_serial} shell pm list packages",
363
364
  print_all: true,
364
365
  print_command: true)
365
366
  packages.split("\n").map { |package| package.gsub("package:", "") }
@@ -367,7 +368,9 @@ module Screengrab
367
368
 
368
369
  def run_adb_command(command, print_all: false, print_command: false)
369
370
  adb_path = @android_env.adb_path.chomp("adb")
370
- output = @executor.execute(command: adb_path + command,
371
+ adb_host = @config[:adb_host]
372
+ host = adb_host.nil? ? '' : "-H #{adb_host} "
373
+ output = @executor.execute(command: adb_path + "adb " + host + command,
371
374
  print_all: print_all,
372
375
  print_command: print_command) || ''
373
376
  output.lines.reject do |line|
@@ -375,5 +378,39 @@ module Screengrab
375
378
  line.start_with?('adb: ')
376
379
  end.join('') # Lines retain their newline chars
377
380
  end
381
+
382
+ def device_api_version(device_serial)
383
+ run_adb_command("-s #{device_serial} shell getprop ro.build.version.sdk",
384
+ print_all: true, print_command: true).to_i
385
+ end
386
+
387
+ def enable_clean_status_bar(device_serial, app_apk_path)
388
+ return unless device_api_version(device_serial) >= 23
389
+
390
+ unless @android_env.aapt_path
391
+ UI.error("The `aapt` command could not be found, so status bar could not be cleaned. Make sure android_home is configured for screengrab or ANDROID_HOME is set in the environment")
392
+ return
393
+ end
394
+
395
+ # Check if the app wants to use the clean status bar feature
396
+ badging_dump = @executor.execute(command: "#{@android_env.aapt_path} dump badging #{app_apk_path}",
397
+ print_all: true, print_command: true)
398
+ return unless badging_dump.include?('uses-feature: name=\'tools.fastlane.screengrab.cleanstatusbar\'')
399
+
400
+ UI.message('Enabling clean status bar')
401
+
402
+ # Make sure the app requests the DUMP permission
403
+ unless badging_dump.include?('uses-permission: name=\'android.permission.DUMP\'')
404
+ UI.user_error!("The clean status bar feature requires the android.permission.DUMP permission but it could not be found in your app APK")
405
+ end
406
+
407
+ # Grant the DUMP permission
408
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.DUMP",
409
+ print_all: true, print_command: true)
410
+
411
+ # Enable the SystemUI demo mode
412
+ run_adb_command("-s #{device_serial} shell settings put global sysui_demo_allowed 1",
413
+ print_all: true, print_command: true)
414
+ end
378
415
  end
379
416
  end