fastlane 2.135.2 → 2.136.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc8a348892470f7c95c046a30e878eeb46a3364e29266d6e2eede8820cda60c9
4
- data.tar.gz: a33412ac7217f0dfe530dcbee955c80c3290cdacabaef708ae9a755008470863
3
+ metadata.gz: b8c1652cb1f5fa0d2fbd567e4d4721fc85be17dae9506afcf4fe8c9bd80c3ec6
4
+ data.tar.gz: d257b400a19b96ccb7a0803af98f71cc6af521b8745a27e4a5083e547a7387bd
5
5
  SHA512:
6
- metadata.gz: f1eb4a8112757f60290d56eb206f26039b5c47abf1999cd09fcfe29eb308596aa8e117057c4ea09e651c2d63526effae43ff9e0b8d577ce155fe9ff36a110e83
7
- data.tar.gz: f071dcaa3f3a11baa944d5c6408a544a3f7f42d76ec9bdfa32d2a962717242587583e958d8bbd4c2dade656d0b95779c971ddaaabdb0f49da42a3ebcd4171b0b
6
+ metadata.gz: a83e00a94cac8a0ac90f1273f70c1676dc1ddee5190599b84c1b2759b09d6f79054cbf13e9b1c3c1c7c928ccb941ec322a35ff9f479c7324db1ff9c71f541917
7
+ data.tar.gz: 1a70fc80b4d8bfddec51d92044dbc36d806629ae03e8d3b55be3832d5694ecb06391f1c2e6df47477c439c61522a4849317fac988f360e7407bd206caac96bfb
data/README.md CHANGED
@@ -34,49 +34,55 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
34
34
  <!-- This table is regenerated and resorted on each release -->
35
35
  <table id='team'>
36
36
  <tr>
37
- <td id='iulian-onofrei'>
38
- <a href='https://github.com/revolter'>
39
- <img src='https://github.com/revolter.png?size=140'>
37
+ <td id='felix-krause'>
38
+ <a href='https://github.com/KrauseFx'>
39
+ <img src='https://github.com/KrauseFx.png?size=140'>
40
40
  </a>
41
- <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
41
+ <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
42
42
  </td>
43
- <td id='stefan-natchev'>
44
- <a href='https://github.com/snatchev'>
45
- <img src='https://github.com/snatchev.png?size=140'>
43
+ <td id='matthew-ellis'>
44
+ <a href='https://github.com/matthewellis'>
45
+ <img src='https://github.com/matthewellis.png?size=140'>
46
46
  </a>
47
- <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
47
+ <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
48
48
  </td>
49
- <td id='jorge-revuelta-h'>
50
- <a href='https://github.com/minuscorp'>
51
- <img src='https://github.com/minuscorp.png?size=140'>
49
+ <td id='luka-mirosevic'>
50
+ <a href='https://github.com/lmirosevic'>
51
+ <img src='https://github.com/lmirosevic.png?size=140'>
52
52
  </a>
53
- <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
53
+ <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
54
54
  </td>
55
- <td id='josh-holtz'>
56
- <a href='https://github.com/joshdholtz'>
57
- <img src='https://github.com/joshdholtz.png?size=140'>
55
+ <td id='aaron-brager'>
56
+ <a href='https://github.com/getaaron'>
57
+ <img src='https://github.com/getaaron.png?size=140'>
58
58
  </a>
59
- <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
59
+ <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
60
60
  </td>
61
- <td id='danielle-tomlinson'>
62
- <a href='https://github.com/endocrimes'>
63
- <img src='https://github.com/endocrimes.png?size=140'>
61
+ <td id='fumiya-nakamura'>
62
+ <a href='https://github.com/nafu'>
63
+ <img src='https://github.com/nafu.png?size=140'>
64
64
  </a>
65
- <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
65
+ <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
66
66
  </td>
67
67
  </tr>
68
68
  <tr>
69
- <td id='joshua-liebowitz'>
70
- <a href='https://github.com/taquitos'>
71
- <img src='https://github.com/taquitos.png?size=140'>
69
+ <td id='manu-wallner'>
70
+ <a href='https://github.com/milch'>
71
+ <img src='https://github.com/milch.png?size=140'>
72
72
  </a>
73
- <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
73
+ <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
74
74
  </td>
75
- <td id='olivier-halligon'>
76
- <a href='https://github.com/AliSoftware'>
77
- <img src='https://github.com/AliSoftware.png?size=140'>
75
+ <td id='helmut-januschka'>
76
+ <a href='https://github.com/hjanuschka'>
77
+ <img src='https://github.com/hjanuschka.png?size=140'>
78
78
  </a>
79
- <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
79
+ <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
80
+ </td>
81
+ <td id='kohki-miki'>
82
+ <a href='https://github.com/giginet'>
83
+ <img src='https://github.com/giginet.png?size=140'>
84
+ </a>
85
+ <h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
80
86
  </td>
81
87
  <td id='maksym-grebenets'>
82
88
  <a href='https://github.com/mgrebenets'>
@@ -84,81 +90,75 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
84
90
  </a>
85
91
  <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
86
92
  </td>
87
- <td id='jérôme-lacoste'>
88
- <a href='https://github.com/lacostej'>
89
- <img src='https://github.com/lacostej.png?size=140'>
90
- </a>
91
- <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
92
- </td>
93
- <td id='kohki-miki'>
94
- <a href='https://github.com/giginet'>
95
- <img src='https://github.com/giginet.png?size=140'>
93
+ <td id='stefan-natchev'>
94
+ <a href='https://github.com/snatchev'>
95
+ <img src='https://github.com/snatchev.png?size=140'>
96
96
  </a>
97
- <h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
97
+ <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
98
98
  </td>
99
99
  </tr>
100
100
  <tr>
101
+ <td id='iulian-onofrei'>
102
+ <a href='https://github.com/revolter'>
103
+ <img src='https://github.com/revolter.png?size=140'>
104
+ </a>
105
+ <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
106
+ </td>
101
107
  <td id='andrew-mcburney'>
102
108
  <a href='https://github.com/armcburney'>
103
109
  <img src='https://github.com/armcburney.png?size=140'>
104
110
  </a>
105
111
  <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
106
112
  </td>
107
- <td id='luka-mirosevic'>
108
- <a href='https://github.com/lmirosevic'>
109
- <img src='https://github.com/lmirosevic.png?size=140'>
110
- </a>
111
- <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
112
- </td>
113
- <td id='jan-piotrowski'>
114
- <a href='https://github.com/janpio'>
115
- <img src='https://github.com/janpio.png?size=140'>
113
+ <td id='olivier-halligon'>
114
+ <a href='https://github.com/AliSoftware'>
115
+ <img src='https://github.com/AliSoftware.png?size=140'>
116
116
  </a>
117
- <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
117
+ <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
118
118
  </td>
119
- <td id='fumiya-nakamura'>
120
- <a href='https://github.com/nafu'>
121
- <img src='https://github.com/nafu.png?size=140'>
119
+ <td id='jorge-revuelta-h'>
120
+ <a href='https://github.com/minuscorp'>
121
+ <img src='https://github.com/minuscorp.png?size=140'>
122
122
  </a>
123
- <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
123
+ <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
124
124
  </td>
125
- <td id='felix-krause'>
126
- <a href='https://github.com/KrauseFx'>
127
- <img src='https://github.com/KrauseFx.png?size=140'>
125
+ <td id='josh-holtz'>
126
+ <a href='https://github.com/joshdholtz'>
127
+ <img src='https://github.com/joshdholtz.png?size=140'>
128
128
  </a>
129
- <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
129
+ <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
130
130
  </td>
131
131
  </tr>
132
132
  <tr>
133
- <td id='manu-wallner'>
134
- <a href='https://github.com/milch'>
135
- <img src='https://github.com/milch.png?size=140'>
133
+ <td id='danielle-tomlinson'>
134
+ <a href='https://github.com/endocrimes'>
135
+ <img src='https://github.com/endocrimes.png?size=140'>
136
136
  </a>
137
- <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
137
+ <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
138
138
  </td>
139
- <td id='helmut-januschka'>
140
- <a href='https://github.com/hjanuschka'>
141
- <img src='https://github.com/hjanuschka.png?size=140'>
139
+ <td id='jérôme-lacoste'>
140
+ <a href='https://github.com/lacostej'>
141
+ <img src='https://github.com/lacostej.png?size=140'>
142
142
  </a>
143
- <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
143
+ <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
144
144
  </td>
145
- <td id='jimmy-dee'>
146
- <a href='https://github.com/jdee'>
147
- <img src='https://github.com/jdee.png?size=140'>
145
+ <td id='joshua-liebowitz'>
146
+ <a href='https://github.com/taquitos'>
147
+ <img src='https://github.com/taquitos.png?size=140'>
148
148
  </a>
149
- <h4 align='center'>Jimmy Dee</h4>
149
+ <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
150
150
  </td>
151
- <td id='aaron-brager'>
152
- <a href='https://github.com/getaaron'>
153
- <img src='https://github.com/getaaron.png?size=140'>
151
+ <td id='jan-piotrowski'>
152
+ <a href='https://github.com/janpio'>
153
+ <img src='https://github.com/janpio.png?size=140'>
154
154
  </a>
155
- <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
155
+ <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
156
156
  </td>
157
- <td id='matthew-ellis'>
158
- <a href='https://github.com/matthewellis'>
159
- <img src='https://github.com/matthewellis.png?size=140'>
157
+ <td id='jimmy-dee'>
158
+ <a href='https://github.com/jdee'>
159
+ <img src='https://github.com/jdee.png?size=140'>
160
160
  </a>
161
- <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
161
+ <h4 align='center'>Jimmy Dee</h4>
162
162
  </td>
163
163
  </tr>
164
164
  </table>
@@ -26,11 +26,13 @@ sudo gem install fastlane
26
26
 
27
27
  ##### Gradle dependency
28
28
  ```java
29
- androidTestCompile('tools.fastlane:screengrab:x.x.x')
29
+ androidTestImplementation 'tools.fastlane:screengrab:x.x.x'
30
30
  ```
31
31
 
32
32
  The latest version is [ ![Download](https://api.bintray.com/packages/fastlane/fastlane/screengrab/images/download.svg) ](https://bintray.com/fastlane/fastlane/screengrab/_latestVersion)
33
33
 
34
+ As of Screengrab version 2.0.0, all Android test dependencies are AndroidX dependencies. This means a device with API 18+, Android 4.3 or greater is required. If you wish to capture screenshots with an older Android OS, then you must use a 1.x.x version.
35
+
34
36
  ##### Configuring your Manifest Permissions
35
37
 
36
38
  Ensure that the following permissions exist in your **src/debug/AndroidManifest.xml**
@@ -82,10 +84,10 @@ As of _screengrab_ 0.5.0, you can specify different strategies to control the wa
82
84
  * Multi-window situations are correctly captured (dialogs, etc.)
83
85
  * Works on Android N
84
86
 
85
- However, UI Automator requires a device with **API level >= 18**, so it is not yet the default strategy. To enable it for all screenshots by default, make the following call before your tests run:
87
+ UI Automator is the default strategy. However, UI Automator requires a device with **API level >= 18**. If you need to grab screenshots on an older Android version, use the latest 1.x.x version of this library and set the DecorView ScreenshotStrategy.
86
88
 
87
89
  ```java
88
- Screengrab.setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy());
90
+ Screengrab.setDefaultScreenshotStrategy(new DecorViewScreenshotStrategy());
89
91
  ```
90
92
 
91
93
  ## Improved screenshot capture with Falcon
@@ -169,7 +171,39 @@ If you're having trouble getting your device unlocked and the screen activated t
169
171
 
170
172
  ## Clean Status Bar
171
173
 
172
- You can use [QuickDemo](https://github.com/PSPDFKit-labs/QuickDemo) to clean up the status bar for your screenshots.
174
+ Screengrab can clean your status bar to make your screenshots even more beautiful.
175
+ Note: the clean status bar feature is only supported on devices with *API level >= 23*.
176
+
177
+ To use the clean status bar feature add the following lines to your src/debug/AndroidManifest.xml
178
+ ```xml
179
+ <!-- Indicates the use of the clean status bar feature -->
180
+ <uses-feature android:name="tools.fastlane.screengrab.cleanstatusbar"/>
181
+ <!-- Allows for changing the status bar -->
182
+ <uses-permission android:name="android.permission.DUMP"/>
183
+ ```
184
+
185
+ After that you can enable and disable the clean status bar at any moment during your tests.
186
+ In most cases you probably want to do this in the @BeforeClass and @AfterClass methods.
187
+ ```java
188
+ @BeforeClass
189
+ public static void beforeAll() {
190
+ CleanStatusBar.enableWithDefaults();
191
+ }
192
+
193
+ @AfterClass
194
+ public static void afterAll() {
195
+ CleanStatusBar.disable();
196
+ }
197
+ ```
198
+
199
+ Have a look at the methods of the `CleanStatusBar` class to customize the status bar even more.
200
+ You could for example show the Bluetooth icon and the LTE text.
201
+ ```java
202
+ new CleanStatusBar()
203
+ .setBluetoothState(BluetoothState.DISCONNECTED)
204
+ .setMobileNetworkDataType(MobileDataType.LTE)
205
+ .enable();
206
+ ```
173
207
 
174
208
  # Advanced _screengrab_
175
209
 
@@ -158,6 +158,7 @@ CrossPlatform/ForkUsage:
158
158
  Lint/IsStringUsage:
159
159
  Include:
160
160
  - gym/**/*
161
+ - screengrab/**/*
161
162
  - supply/**/*
162
163
  Style/MethodCallWithArgsParentheses:
163
164
  Enabled: true
@@ -147,6 +147,7 @@ module Fastlane
147
147
  unless default_value.nil?
148
148
  if type == "[String : Any]"
149
149
  # we can't handle default values for Hashes, yet
150
+ # see method swift_default_implementations for similar behavior
150
151
  default_value = "[:]"
151
152
  elsif type != "Bool" && type != "[String]" && type != "Int" && type != "((String) -> Void)"
152
153
  default_value = "\"#{default_value}\""
@@ -343,6 +344,10 @@ module Fastlane
343
344
  unless default_value.nil?
344
345
  if type == "Bool" || type == "[String]" || type == "Int" || default_value.kind_of?(Array)
345
346
  default_value = default_value.to_s
347
+ elsif default_value.kind_of?(Hash)
348
+ # we can't handle default values for Hashes, yet
349
+ # see method parameters for similar behavior
350
+ default_value = "[:]"
346
351
  else
347
352
  default_value = "\"#{default_value}\""
348
353
  end
@@ -366,6 +371,10 @@ module Fastlane
366
371
  default_value ||= "[]"
367
372
  end
368
373
 
374
+ if type == "[String : Any]"
375
+ default_value ||= "[:]"
376
+ end
377
+
369
378
  " var #{var_for_parameter_name}: #{type} { return #{default_value} }"
370
379
  end
371
380
 
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.135.2'.freeze
2
+ VERSION = '2.136.0'.freeze
3
3
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
4
4
  MINIMUM_XCODE_RELEASE = "7.0".freeze
5
5
  RUBOCOP_REQUIREMENT = '0.49.1'.freeze
@@ -18,4 +18,4 @@ class Deliverfile: DeliverfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.136.0
@@ -1210,12 +1210,17 @@ func bundleInstall(binstubs: String? = nil,
1210
1210
  - launchArguments: Additional launch arguments
1211
1211
  - testInstrumentationRunner: The fully qualified class name of your test instrumentation runner
1212
1212
  - endingLocale: Return the device to this locale after running tests
1213
+ - useAdbRoot: Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors
1213
1214
  - appApkPath: The path to the APK for the app under test
1214
1215
  - testsApkPath: The path to the APK for the the tests bundle
1215
1216
  - specificDevice: Use the device or emulator with the given serial number or qualifier
1216
1217
  - deviceType: Type of device used for screenshots. Matches Google Play Types (phone, sevenInch, tenInch, tv, wear)
1217
1218
  - exitOnTestFailure: Whether or not to exit Screengrab on test failure. Exiting on failure will not copy sceenshots to local machine nor open sceenshots summary
1218
1219
  - reinstallApp: Enabling this option will automatically uninstall the application before running it
1220
+ - useTimestampSuffix: Add timestamp suffix to screenshot filename
1221
+ - adbHost: Configure the host used by adb to connect, allows running on remote devices farm
1222
+ - cleanStatusBar: Enabling this option will clean the status bar
1223
+ - cleanStatusBarConfig: Specifies the configuration for the clean status bar
1219
1224
  */
1220
1225
  func captureAndroidScreenshots(androidHome: String? = nil,
1221
1226
  buildToolsVersion: String? = nil,
@@ -1228,14 +1233,19 @@ func captureAndroidScreenshots(androidHome: String? = nil,
1228
1233
  useTestsInPackages: [String]? = nil,
1229
1234
  useTestsInClasses: [String]? = nil,
1230
1235
  launchArguments: [String]? = nil,
1231
- testInstrumentationRunner: String = "android.support.test.runner.AndroidJUnitRunner",
1236
+ testInstrumentationRunner: String = "androidx.test.runner.AndroidJUnitRunner",
1232
1237
  endingLocale: String = "en-US",
1238
+ useAdbRoot: Bool = false,
1233
1239
  appApkPath: String? = nil,
1234
1240
  testsApkPath: String? = nil,
1235
1241
  specificDevice: String? = nil,
1236
1242
  deviceType: String = "phone",
1237
1243
  exitOnTestFailure: Bool = true,
1238
- reinstallApp: Bool = false) {
1244
+ reinstallApp: Bool = false,
1245
+ useTimestampSuffix: Bool = true,
1246
+ adbHost: String? = nil,
1247
+ cleanStatusBar: Bool = false,
1248
+ cleanStatusBarConfig: [String : Any] = [:]) {
1239
1249
  let command = RubyCommand(commandID: "", methodName: "capture_android_screenshots", className: nil, args: [RubyCommand.Argument(name: "android_home", value: androidHome),
1240
1250
  RubyCommand.Argument(name: "build_tools_version", value: buildToolsVersion),
1241
1251
  RubyCommand.Argument(name: "locales", value: locales),
@@ -1249,12 +1259,17 @@ func captureAndroidScreenshots(androidHome: String? = nil,
1249
1259
  RubyCommand.Argument(name: "launch_arguments", value: launchArguments),
1250
1260
  RubyCommand.Argument(name: "test_instrumentation_runner", value: testInstrumentationRunner),
1251
1261
  RubyCommand.Argument(name: "ending_locale", value: endingLocale),
1262
+ RubyCommand.Argument(name: "use_adb_root", value: useAdbRoot),
1252
1263
  RubyCommand.Argument(name: "app_apk_path", value: appApkPath),
1253
1264
  RubyCommand.Argument(name: "tests_apk_path", value: testsApkPath),
1254
1265
  RubyCommand.Argument(name: "specific_device", value: specificDevice),
1255
1266
  RubyCommand.Argument(name: "device_type", value: deviceType),
1256
1267
  RubyCommand.Argument(name: "exit_on_test_failure", value: exitOnTestFailure),
1257
- RubyCommand.Argument(name: "reinstall_app", value: reinstallApp)])
1268
+ RubyCommand.Argument(name: "reinstall_app", value: reinstallApp),
1269
+ RubyCommand.Argument(name: "use_timestamp_suffix", value: useTimestampSuffix),
1270
+ RubyCommand.Argument(name: "adb_host", value: adbHost),
1271
+ RubyCommand.Argument(name: "clean_status_bar", value: cleanStatusBar),
1272
+ RubyCommand.Argument(name: "clean_status_bar_config", value: cleanStatusBarConfig)])
1258
1273
  _ = runner.executeCommand(command)
1259
1274
  }
1260
1275
 
@@ -5791,12 +5806,17 @@ func scp(username: String,
5791
5806
  - launchArguments: Additional launch arguments
5792
5807
  - testInstrumentationRunner: The fully qualified class name of your test instrumentation runner
5793
5808
  - endingLocale: Return the device to this locale after running tests
5809
+ - useAdbRoot: Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors
5794
5810
  - appApkPath: The path to the APK for the app under test
5795
5811
  - testsApkPath: The path to the APK for the the tests bundle
5796
5812
  - specificDevice: Use the device or emulator with the given serial number or qualifier
5797
5813
  - deviceType: Type of device used for screenshots. Matches Google Play Types (phone, sevenInch, tenInch, tv, wear)
5798
5814
  - exitOnTestFailure: Whether or not to exit Screengrab on test failure. Exiting on failure will not copy sceenshots to local machine nor open sceenshots summary
5799
5815
  - reinstallApp: Enabling this option will automatically uninstall the application before running it
5816
+ - useTimestampSuffix: Add timestamp suffix to screenshot filename
5817
+ - adbHost: Configure the host used by adb to connect, allows running on remote devices farm
5818
+ - cleanStatusBar: Enabling this option will clean the status bar
5819
+ - cleanStatusBarConfig: Specifies the configuration for the clean status bar
5800
5820
  */
5801
5821
  func screengrab(androidHome: Any? = screengrabfile.androidHome,
5802
5822
  buildToolsVersion: Any? = screengrabfile.buildToolsVersion,
@@ -5811,12 +5831,17 @@ func screengrab(androidHome: Any? = screengrabfile.androidHome,
5811
5831
  launchArguments: [String]? = screengrabfile.launchArguments,
5812
5832
  testInstrumentationRunner: Any = screengrabfile.testInstrumentationRunner,
5813
5833
  endingLocale: Any = screengrabfile.endingLocale,
5834
+ useAdbRoot: Bool = screengrabfile.useAdbRoot,
5814
5835
  appApkPath: Any? = screengrabfile.appApkPath,
5815
5836
  testsApkPath: Any? = screengrabfile.testsApkPath,
5816
5837
  specificDevice: Any? = screengrabfile.specificDevice,
5817
5838
  deviceType: Any = screengrabfile.deviceType,
5818
5839
  exitOnTestFailure: Bool = screengrabfile.exitOnTestFailure,
5819
- reinstallApp: Bool = screengrabfile.reinstallApp) {
5840
+ reinstallApp: Bool = screengrabfile.reinstallApp,
5841
+ useTimestampSuffix: Bool = screengrabfile.useTimestampSuffix,
5842
+ adbHost: Any? = screengrabfile.adbHost,
5843
+ cleanStatusBar: Bool = screengrabfile.cleanStatusBar,
5844
+ cleanStatusBarConfig: [String : Any] = screengrabfile.cleanStatusBarConfig) {
5820
5845
  let command = RubyCommand(commandID: "", methodName: "screengrab", className: nil, args: [RubyCommand.Argument(name: "android_home", value: androidHome),
5821
5846
  RubyCommand.Argument(name: "build_tools_version", value: buildToolsVersion),
5822
5847
  RubyCommand.Argument(name: "locales", value: locales),
@@ -5830,12 +5855,17 @@ func screengrab(androidHome: Any? = screengrabfile.androidHome,
5830
5855
  RubyCommand.Argument(name: "launch_arguments", value: launchArguments),
5831
5856
  RubyCommand.Argument(name: "test_instrumentation_runner", value: testInstrumentationRunner),
5832
5857
  RubyCommand.Argument(name: "ending_locale", value: endingLocale),
5858
+ RubyCommand.Argument(name: "use_adb_root", value: useAdbRoot),
5833
5859
  RubyCommand.Argument(name: "app_apk_path", value: appApkPath),
5834
5860
  RubyCommand.Argument(name: "tests_apk_path", value: testsApkPath),
5835
5861
  RubyCommand.Argument(name: "specific_device", value: specificDevice),
5836
5862
  RubyCommand.Argument(name: "device_type", value: deviceType),
5837
5863
  RubyCommand.Argument(name: "exit_on_test_failure", value: exitOnTestFailure),
5838
- RubyCommand.Argument(name: "reinstall_app", value: reinstallApp)])
5864
+ RubyCommand.Argument(name: "reinstall_app", value: reinstallApp),
5865
+ RubyCommand.Argument(name: "use_timestamp_suffix", value: useTimestampSuffix),
5866
+ RubyCommand.Argument(name: "adb_host", value: adbHost),
5867
+ RubyCommand.Argument(name: "clean_status_bar", value: cleanStatusBar),
5868
+ RubyCommand.Argument(name: "clean_status_bar_config", value: cleanStatusBarConfig)])
5839
5869
  _ = runner.executeCommand(command)
5840
5870
  }
5841
5871
 
@@ -8326,4 +8356,4 @@ let snapshotfile: Snapshotfile = Snapshotfile()
8326
8356
 
8327
8357
  // Please don't remove the lines below
8328
8358
  // They are used to detect outdated files
8329
- // FastlaneRunnerAPIVersion [0.9.63]
8359
+ // FastlaneRunnerAPIVersion [0.9.64]
@@ -18,4 +18,4 @@ class Gymfile: GymfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.136.0
@@ -18,4 +18,4 @@ class Matchfile: MatchfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.136.0
@@ -18,4 +18,4 @@ class Precheckfile: PrecheckfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.136.0
@@ -18,4 +18,4 @@ class Scanfile: ScanfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.136.0
@@ -18,4 +18,4 @@ class Screengrabfile: ScreengrabfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.136.0
@@ -39,6 +39,9 @@ protocol ScreengrabfileProtocol: class {
39
39
  /// Return the device to this locale after running tests
40
40
  var endingLocale: String { get }
41
41
 
42
+ /// Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors
43
+ var useAdbRoot: Bool { get }
44
+
42
45
  /// The path to the APK for the app under test
43
46
  var appApkPath: String? { get }
44
47
 
@@ -56,6 +59,18 @@ protocol ScreengrabfileProtocol: class {
56
59
 
57
60
  /// Enabling this option will automatically uninstall the application before running it
58
61
  var reinstallApp: Bool { get }
62
+
63
+ /// Add timestamp suffix to screenshot filename
64
+ var useTimestampSuffix: Bool { get }
65
+
66
+ /// Configure the host used by adb to connect, allows running on remote devices farm
67
+ var adbHost: String? { get }
68
+
69
+ /// Enabling this option will clean the status bar
70
+ var cleanStatusBar: Bool { get }
71
+
72
+ /// Specifies the configuration for the clean status bar
73
+ var cleanStatusBarConfig: [String : Any] { get }
59
74
  }
60
75
 
61
76
  extension ScreengrabfileProtocol {
@@ -70,16 +85,21 @@ extension ScreengrabfileProtocol {
70
85
  var useTestsInPackages: [String]? { return nil }
71
86
  var useTestsInClasses: [String]? { return nil }
72
87
  var launchArguments: [String]? { return nil }
73
- var testInstrumentationRunner: String { return "android.support.test.runner.AndroidJUnitRunner" }
88
+ var testInstrumentationRunner: String { return "androidx.test.runner.AndroidJUnitRunner" }
74
89
  var endingLocale: String { return "en-US" }
90
+ var useAdbRoot: Bool { return false }
75
91
  var appApkPath: String? { return nil }
76
92
  var testsApkPath: String? { return nil }
77
93
  var specificDevice: String? { return nil }
78
94
  var deviceType: String { return "phone" }
79
95
  var exitOnTestFailure: Bool { return true }
80
96
  var reinstallApp: Bool { return false }
97
+ var useTimestampSuffix: Bool { return true }
98
+ var adbHost: String? { return nil }
99
+ var cleanStatusBar: Bool { return false }
100
+ var cleanStatusBarConfig: [String : Any] { return [:] }
81
101
  }
82
102
 
83
103
  // Please don't remove the lines below
84
104
  // They are used to detect outdated files
85
- // FastlaneRunnerAPIVersion [0.9.11]
105
+ // FastlaneRunnerAPIVersion [0.9.12]
@@ -18,4 +18,4 @@ class Snapshotfile: SnapshotfileProtocol {
18
18
 
19
19
 
20
20
 
21
- // Generated with fastlane 2.135.2
21
+ // Generated with fastlane 2.136.0
@@ -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,30 @@ 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),
145
+ FastlaneCore::ConfigItem.new(key: :clean_status_bar,
146
+ env_name: 'SCREENGRAB_CLEAN_STATUS_BAR',
147
+ description: "Enabling this option will clean the status bar",
148
+ default_value: false,
149
+ type: Boolean),
150
+ FastlaneCore::ConfigItem.new(key: :clean_status_bar_config,
151
+ description: "Specifies the configuration for the clean status bar",
152
+ default_value: {},
153
+ type: Hash)
132
154
  ]
133
155
  end
134
156
  end
@@ -57,8 +57,13 @@ module Screengrab
57
57
 
58
58
  device_screenshots_paths = [
59
59
  determine_external_screenshots_path(device_serial),
60
- determine_internal_screenshots_path
61
- ]
60
+ determine_internal_screenshots_paths(@config[:app_package_name], @config[:locales])
61
+ ].flatten
62
+
63
+ # Root is needed to access device paths at /data
64
+ if @config[:use_adb_root]
65
+ run_adb_command("root", print_all: false, print_command: true)
66
+ end
62
67
 
63
68
  clear_device_previous_screenshots(device_serial, device_screenshots_paths)
64
69
 
@@ -67,6 +72,8 @@ module Screengrab
67
72
 
68
73
  validate_apk(app_apk_path)
69
74
 
75
+ enable_clean_status_bar(device_serial, app_apk_path)
76
+
70
77
  run_tests(device_serial, app_apk_path, tests_apk_path, test_classes_to_use, test_packages_to_use, @config[:launch_arguments])
71
78
 
72
79
  number_of_screenshots = pull_screenshots_from_device(device_serial, device_screenshots_paths, device_type_dir_name)
@@ -77,7 +84,7 @@ module Screengrab
77
84
  end
78
85
 
79
86
  def select_device
80
- devices = run_adb_command("adb devices -l", print_all: true, print_command: true).split("\n")
87
+ devices = run_adb_command("devices -l", print_all: true, print_command: true).split("\n")
81
88
  # the first output by adb devices is "List of devices attached" so remove that and any adb startup output
82
89
  devices.reject! do |device|
83
90
  [
@@ -139,15 +146,19 @@ module Screengrab
139
146
  # macOS evaluates $foo in `echo $foo` before executing the command,
140
147
  # Windows doesn't - hence the double backslash vs. single backslash
141
148
  command = Helper.windows? ? "shell echo \$EXTERNAL_STORAGE " : "shell echo \\$EXTERNAL_STORAGE"
142
- device_ext_storage = run_adb_command("adb -s #{device_serial} #{command}",
149
+ device_ext_storage = run_adb_command("-s #{device_serial} #{command}",
143
150
  print_all: true,
144
151
  print_command: true)
145
152
  device_ext_storage = device_ext_storage.strip
146
153
  File.join(device_ext_storage, @config[:app_package_name], 'screengrab')
147
154
  end
148
155
 
149
- def determine_internal_screenshots_path
150
- "/data/data/#{@config[:app_package_name]}/app_screengrab"
156
+ def determine_internal_screenshots_paths(app_package_name, locales)
157
+ locale_paths = locales.map do |locale|
158
+ "/data/user/0/#{app_package_name}/files/#{app_package_name}/screengrab/#{locale}/images/screenshots"
159
+ end
160
+
161
+ return ["/data/data/#{app_package_name}/app_screengrab"] + locale_paths
151
162
  end
152
163
 
153
164
  def clear_device_previous_screenshots(device_serial, device_screenshots_paths)
@@ -155,7 +166,7 @@ module Screengrab
155
166
 
156
167
  device_screenshots_paths.each do |device_path|
157
168
  if_device_path_exists(device_serial, device_path) do |path|
158
- run_adb_command("adb -s #{device_serial} shell rm -rf #{path}",
169
+ run_adb_command("-s #{device_serial} shell rm -rf #{path}",
159
170
  print_all: true,
160
171
  print_command: true)
161
172
  end
@@ -182,13 +193,13 @@ module Screengrab
182
193
 
183
194
  def install_apks(device_serial, app_apk_path, tests_apk_path)
184
195
  UI.message('Installing app APK')
185
- apk_install_output = run_adb_command("adb -s #{device_serial} install -t -r #{app_apk_path.shellescape}",
196
+ apk_install_output = run_adb_command("-s #{device_serial} install -t -r #{app_apk_path.shellescape}",
186
197
  print_all: true,
187
198
  print_command: true)
188
199
  UI.user_error!("App APK could not be installed") if apk_install_output.include?("Failure [")
189
200
 
190
201
  UI.message('Installing tests APK')
191
- apk_install_output = run_adb_command("adb -s #{device_serial} install -t -r #{tests_apk_path.shellescape}",
202
+ apk_install_output = run_adb_command("-s #{device_serial} install -t -r #{tests_apk_path.shellescape}",
192
203
  print_all: true,
193
204
  print_command: true)
194
205
  UI.user_error!("Tests APK could not be installed") if apk_install_output.include?("Failure [")
@@ -199,14 +210,14 @@ module Screengrab
199
210
 
200
211
  if packages.include?(app_package_name.to_s)
201
212
  UI.message('Uninstalling app APK')
202
- run_adb_command("adb -s #{device_serial} uninstall #{app_package_name}",
213
+ run_adb_command("-s #{device_serial} uninstall #{app_package_name}",
203
214
  print_all: true,
204
215
  print_command: true)
205
216
  end
206
217
 
207
218
  if packages.include?(tests_package_name.to_s)
208
219
  UI.message('Uninstalling tests APK')
209
- run_adb_command("adb -s #{device_serial} uninstall #{tests_package_name}",
220
+ run_adb_command("-s #{device_serial} uninstall #{tests_package_name}",
210
221
  print_all: true,
211
222
  print_command: true)
212
223
  end
@@ -214,20 +225,16 @@ module Screengrab
214
225
 
215
226
  def grant_permissions(device_serial)
216
227
  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",
228
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.CHANGE_CONFIGURATION",
218
229
  print_all: true,
219
230
  print_command: true)
220
231
 
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
232
+ if device_api_version(device_serial) >= 23
226
233
  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",
234
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.WRITE_EXTERNAL_STORAGE",
228
235
  print_all: true,
229
236
  print_command: true)
230
- run_adb_command("adb -s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.READ_EXTERNAL_STORAGE",
237
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.READ_EXTERNAL_STORAGE",
231
238
  print_all: true,
232
239
  print_command: true)
233
240
  end
@@ -252,9 +259,10 @@ module Screengrab
252
259
  def run_tests_for_locale(locale, device_serial, test_classes_to_use, test_packages_to_use, launch_arguments)
253
260
  UI.message("Running tests for locale: #{locale}")
254
261
 
255
- instrument_command = ["adb -s #{device_serial} shell am instrument --no-window-animation -w",
262
+ instrument_command = ["-s #{device_serial} shell am instrument --no-window-animation -w",
256
263
  "-e testLocale #{locale.tr('-', '_')}",
257
264
  "-e endingLocale #{@config[:ending_locale].tr('-', '_')}"]
265
+ instrument_command << "-e appendTimestamp #{@config[:use_timestamp_suffix]}"
258
266
  instrument_command << "-e class #{test_classes_to_use.join(',')}" if test_classes_to_use
259
267
  instrument_command << "-e package #{test_packages_to_use.join(',')}" if test_packages_to_use
260
268
  instrument_command << launch_arguments.map { |item| '-e ' + item }.join(' ') if launch_arguments
@@ -281,10 +289,11 @@ module Screengrab
281
289
 
282
290
  # Make a temp directory into which to pull the screenshots before they are moved to their final location.
283
291
  # This makes directory cleanup easier, as the temp directory will be removed when the block completes.
292
+
284
293
  Dir.mktmpdir do |tempdir|
285
294
  device_screenshots_paths.each do |device_path|
286
295
  if_device_path_exists(device_serial, device_path) do |path|
287
- run_adb_command("adb -s #{device_serial} pull #{path} #{tempdir}",
296
+ run_adb_command("-s #{device_serial} pull #{path} #{tempdir}",
288
297
  print_all: false,
289
298
  print_command: true)
290
299
  end
@@ -347,7 +356,7 @@ module Screengrab
347
356
  # Some device commands fail if executed against a device path that does not exist, so this helper method
348
357
  # provides a way to conditionally execute a block only if the provided path exists on the device.
349
358
  def if_device_path_exists(device_serial, device_path)
350
- return if run_adb_command("adb -s #{device_serial} shell ls #{device_path}",
359
+ return if run_adb_command("-s #{device_serial} shell ls #{device_path}",
351
360
  print_all: false,
352
361
  print_command: false).include?('No such file')
353
362
 
@@ -359,7 +368,7 @@ module Screengrab
359
368
 
360
369
  # Return an array of packages that are installed on the device
361
370
  def installed_packages(device_serial)
362
- packages = run_adb_command("adb -s #{device_serial} shell pm list packages",
371
+ packages = run_adb_command("-s #{device_serial} shell pm list packages",
363
372
  print_all: true,
364
373
  print_command: true)
365
374
  packages.split("\n").map { |package| package.gsub("package:", "") }
@@ -367,7 +376,9 @@ module Screengrab
367
376
 
368
377
  def run_adb_command(command, print_all: false, print_command: false)
369
378
  adb_path = @android_env.adb_path.chomp("adb")
370
- output = @executor.execute(command: adb_path + command,
379
+ adb_host = @config[:adb_host]
380
+ host = adb_host.nil? ? '' : "-H #{adb_host} "
381
+ output = @executor.execute(command: adb_path + "adb " + host + command,
371
382
  print_all: print_all,
372
383
  print_command: print_command) || ''
373
384
  output.lines.reject do |line|
@@ -375,5 +386,34 @@ module Screengrab
375
386
  line.start_with?('adb: ')
376
387
  end.join('') # Lines retain their newline chars
377
388
  end
389
+
390
+ def device_api_version(device_serial)
391
+ run_adb_command("-s #{device_serial} shell getprop ro.build.version.sdk",
392
+ print_all: true, print_command: true).to_i
393
+ end
394
+
395
+ def enable_clean_status_bar(device_serial, app_apk_path)
396
+ return unless device_api_version(device_serial) >= 23
397
+
398
+ # Check if the app wants to use the clean status bar feature
399
+ badging_dump = @executor.execute(command: "#{@android_env.aapt_path} dump badging #{app_apk_path}",
400
+ print_all: true, print_command: true)
401
+ return unless badging_dump.include?('uses-feature: name=\'tools.fastlane.screengrab.cleanstatusbar\'')
402
+
403
+ UI.message('Enabling clean status bar')
404
+
405
+ # Make sure the app requests the DUMP permission
406
+ unless badging_dump.include?('uses-permission: name=\'android.permission.DUMP\'')
407
+ UI.user_error!("The clean status bar feature requires the android.permission.DUMP permission but it could not be found in your app APK")
408
+ end
409
+
410
+ # Grant the DUMP permission
411
+ run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.DUMP",
412
+ print_all: true, print_command: true)
413
+
414
+ # Enable the SystemUI demo mode
415
+ run_adb_command("-s #{device_serial} shell settings put global sysui_demo_allowed 1",
416
+ print_all: true, print_command: true)
417
+ end
378
418
  end
379
419
  end
@@ -19,12 +19,12 @@ module Supply
19
19
  # Updating a track with empty version codes can completely clear out a track
20
20
  update_track(apk_version_codes) unless apk_version_codes.empty?
21
21
 
22
- if !Supply.config[:rollout].nil? && Supply.config[:track].to_s != ""
22
+ if Supply.config[:track_promote_to]
23
+ promote_track
24
+ elsif !Supply.config[:rollout].nil? && Supply.config[:track].to_s != ""
23
25
  update_rollout
24
26
  end
25
27
 
26
- promote_track if Supply.config[:track_promote_to]
27
-
28
28
  if Supply.config[:validate_only]
29
29
  UI.message("Validating all track and release changes with Google Play...")
30
30
  client.validate_current_edit!
@@ -42,7 +42,12 @@ module Supply
42
42
  client.begin_edit(package_name: Supply.config[:package_name])
43
43
 
44
44
  if (!Supply.config[:skip_upload_metadata] || !Supply.config[:skip_upload_images] || !Supply.config[:skip_upload_changelogs] || !Supply.config[:skip_upload_screenshots]) && metadata_path
45
+ # Use version code from config if version codes is empty and no nil or empty string
45
46
  version_codes = [Supply.config[:version_code]] if version_codes.empty?
47
+ version_codes = version_codes.reject do |version_code|
48
+ version_codes.to_s == ""
49
+ end
50
+
46
51
  version_codes.each do |version_code|
47
52
  UI.user_error!("Could not find folder #{metadata_path}") unless File.directory?(metadata_path)
48
53
 
@@ -60,7 +65,7 @@ module Supply
60
65
  upload_metadata(language, listing) unless Supply.config[:skip_upload_metadata]
61
66
  upload_images(language) unless Supply.config[:skip_upload_images]
62
67
  upload_screenshots(language) unless Supply.config[:skip_upload_screenshots]
63
- release_notes << upload_changelog(language, release.name) unless Supply.config[:skip_upload_changelogs]
68
+ release_notes << upload_changelog(language, version_code) unless Supply.config[:skip_upload_changelogs]
64
69
  end
65
70
 
66
71
  upload_changelogs(release_notes, release, track) unless release_notes.empty?
@@ -84,8 +89,9 @@ module Supply
84
89
 
85
90
  track = tracks.first
86
91
  releases = track.releases
92
+
87
93
  releases = releases.select { |r| r.status == status } if status
88
- releases = releases.select { |r| r.version_codes.map(&:to_s).include?(version_code.to_s) }
94
+ releases = releases.select { |r| r.version_codes.map(&:to_s).include?(version_code.to_s) } if version_code
89
95
 
90
96
  if releases.size > 1
91
97
  UI.user_error!("More than one release found in this track. Please specify with the :version_code option to select a release.")
@@ -96,10 +102,12 @@ module Supply
96
102
 
97
103
  def update_rollout
98
104
  track, release = fetch_track_and_release!(Supply.config[:track], Supply.config[:version_code], Supply::ReleaseStatus::IN_PROGRESS)
105
+ UI.user_error!("Unable to find the requested track - '#{Supply.config[:track]}'") unless track
106
+ UI.user_error!("Unable to find the requested release on track - '#{Supply.config[:track]}'") unless release
107
+
99
108
  version_code = release.version_codes.first
100
109
 
101
110
  UI.message("Updating #{version_code}'s rollout to '#{Supply.config[:rollout]}' on track '#{Supply.config[:track]}'...")
102
- UI.user_error!("Unable to find the requested track - '#{Supply.config[:track]}'") unless track
103
111
 
104
112
  if track && release
105
113
  completed = Supply.config[:rollout].to_f == 1
@@ -149,6 +157,10 @@ module Supply
149
157
  releases = releases.select do |release|
150
158
  release.version_codes.include?(Supply.config[:version_code].to_s)
151
159
  end
160
+ else
161
+ releases = releases.select do |release|
162
+ release.status == Supply::ReleaseStatus::COMPLETED
163
+ end
152
164
  end
153
165
 
154
166
  if releases.size == 0
@@ -157,9 +169,17 @@ module Supply
157
169
  UI.user_error!("Track '#{Supply.config[:track]}' has more than one release - use :version_code to filter the release to promote")
158
170
  end
159
171
 
160
- release = track_from.releases.first
172
+ release = releases.first
161
173
  track_to = client.tracks(Supply.config[:track_promote_to]).first
162
174
 
175
+ if Supply.config[:rollout]
176
+ release.status = Supply::ReleaseStatus::IN_PROGRESS
177
+ release.user_fraction = Supply.config[:rollout]
178
+ else
179
+ release.status = Supply::ReleaseStatus::COMPLETED
180
+ release.user_fraction = nil
181
+ end
182
+
163
183
  if track_to
164
184
  # Its okay to set releases to an array containing the newest release
165
185
  # Google Play will keep previous releases there this release is a partial rollout
@@ -174,16 +194,16 @@ module Supply
174
194
  client.update_track(Supply.config[:track_promote_to], track_to)
175
195
  end
176
196
 
177
- def upload_changelog(language, version_name)
178
- UI.user_error!("Cannot find changelog because no version name given - please specify :version_name") unless version_name
197
+ def upload_changelog(language, version_code)
198
+ UI.user_error!("Cannot find changelog because no version code given - please specify :version_code") unless version_code
179
199
 
180
- path = File.join(Supply.config[:metadata_path], language, Supply::CHANGELOGS_FOLDER_NAME, "#{version_name}.txt")
200
+ path = File.join(Supply.config[:metadata_path], language, Supply::CHANGELOGS_FOLDER_NAME, "#{version_code}.txt")
181
201
  changelog_text = ''
182
202
  if File.exist?(path)
183
- UI.message("Updating changelog for '#{version_name}' and language '#{language}'...")
203
+ UI.message("Updating changelog for '#{version_code}' and language '#{language}'...")
184
204
  changelog_text = File.read(path, encoding: 'UTF-8')
185
205
  else
186
- UI.message("Could not find changelog for '#{version_name}' and language '#{language}' at path #{path}...")
206
+ UI.message("Could not find changelog for '#{version_code}' and language '#{language}' at path #{path}...")
187
207
  end
188
208
 
189
209
  AndroidPublisher::LocalizedText.new({
metadata CHANGED
@@ -1,33 +1,33 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.135.2
4
+ version: 2.136.0
5
5
  platform: ruby
6
6
  authors:
7
- - Andrew McBurney
8
- - Jan Piotrowski
9
- - Maksym Grebenets
10
- - Olivier Halligon
11
- - Kohki Miki
12
- - Iulian Onofrei
13
7
  - Danielle Tomlinson
14
- - Manu Wallner
15
- - Luka Mirosevic
8
+ - Jimmy Dee
16
9
  - Helmut Januschka
10
+ - Olivier Halligon
11
+ - Joshua Liebowitz
17
12
  - Josh Holtz
18
- - Felix Krause
19
- - Jérôme Lacoste
13
+ - Manu Wallner
14
+ - Jan Piotrowski
15
+ - Kohki Miki
20
16
  - Stefan Natchev
21
- - Aaron Brager
22
- - Jimmy Dee
17
+ - Jorge Revuelta H
23
18
  - Fumiya Nakamura
19
+ - Jérôme Lacoste
20
+ - Felix Krause
21
+ - Maksym Grebenets
22
+ - Iulian Onofrei
24
23
  - Matthew Ellis
25
- - Jorge Revuelta H
26
- - Joshua Liebowitz
24
+ - Aaron Brager
25
+ - Luka Mirosevic
26
+ - Andrew McBurney
27
27
  autorequire:
28
28
  bindir: bin
29
29
  cert_chain: []
30
- date: 2019-11-11 00:00:00.000000000 Z
30
+ date: 2019-11-15 00:00:00.000000000 Z
31
31
  dependencies:
32
32
  - !ruby/object:Gem::Dependency
33
33
  name: slack-notifier
@@ -1731,7 +1731,6 @@ files:
1731
1731
  - spaceship/lib/spaceship/ui.rb
1732
1732
  - supply/README.md
1733
1733
  - supply/lib/supply.rb
1734
- - supply/lib/supply/.options.rb.swp
1735
1734
  - supply/lib/supply/.uploader.rb.swp
1736
1735
  - supply/lib/supply/apk_listing.rb
1737
1736
  - supply/lib/supply/client.rb