fastlane 2.155.3 → 2.156.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +80 -80
  3. data/deliver/lib/deliver/app_screenshot_iterator.rb +98 -0
  4. data/deliver/lib/deliver/queue_worker.rb +64 -0
  5. data/deliver/lib/deliver/upload_screenshots.rb +122 -125
  6. data/fastlane/lib/fastlane/version.rb +1 -1
  7. data/fastlane/swift/Deliverfile.swift +1 -1
  8. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  9. data/fastlane/swift/Fastlane.swift +1 -1
  10. data/fastlane/swift/Gymfile.swift +1 -1
  11. data/fastlane/swift/GymfileProtocol.swift +1 -1
  12. data/fastlane/swift/Matchfile.swift +1 -1
  13. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  14. data/fastlane/swift/Precheckfile.swift +1 -1
  15. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  16. data/fastlane/swift/Scanfile.swift +1 -1
  17. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  18. data/fastlane/swift/Screengrabfile.swift +1 -1
  19. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  20. data/fastlane/swift/Snapshotfile.swift +1 -1
  21. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  22. data/fastlane_core/lib/fastlane_core/project.rb +1 -0
  23. data/gym/lib/gym/generators/build_command_generator.rb +0 -1
  24. data/scan/lib/scan/test_command_generator.rb +3 -1
  25. data/screengrab/lib/screengrab/runner.rb +7 -7
  26. data/snapshot/lib/snapshot/test_command_generator_base.rb +3 -1
  27. data/{match/lib/match/.options.rb.swp → spaceship/lib/spaceship/.client.rb.swp} +0 -0
  28. data/spaceship/lib/spaceship/{connect_api/provisioning/.provisioning.rb.swp → .spaceauth_runner.rb.swp} +0 -0
  29. data/spaceship/lib/spaceship/{connect_api/models/.profile.rb.swp → .two_step_or_factor_client.rb.swp} +0 -0
  30. metadata +23 -24
  31. data/match/lib/match/.runner.rb.swp +0 -0
  32. data/sigh/lib/sigh/.options.rb.swp +0 -0
  33. data/sigh/lib/sigh/.runner.rb.swp +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7dab029713a3d68bde75d66db5b13e50f71fe6e378c994145c63de7d3b49d56
4
- data.tar.gz: 8c4d4b67a931321b413dd70abafc279209b8049a7b9329f5d919cafd9568bfd4
3
+ metadata.gz: 70c9faed2541a1cead4b030cf41328487f06a8b17e129a6d4ad8428de8fcaf25
4
+ data.tar.gz: 262293381bd7435f0b9dcac69ed77870c31eb59cfb023a97b09e747e89f7015a
5
5
  SHA512:
6
- metadata.gz: eb945426219d180a85d3c4a6ea709918811f5d39a836c3cff93771cd703f993f2ee448a3b2a542ef4c645e9d14a902ced2795b3a2d6f1184c49bb74bdd8c3c78
7
- data.tar.gz: b106c049969564f84684170db2a616d37f0be0a8e2e11a37fe3c1b0b58ae42e9317179bcf9ff112ccaab510ef1a968c21fbb8a8d43d12ced0d592d4ad3bbe2c4
6
+ metadata.gz: c27c2225cc7459a8d10e3c9b91dff5fa878d2b5c07f4cb11991132422f1de975a4549b5d0b460c9e213c7cb3c255e4c7caa655ab9b3369a78cdd7e6eb7258ff6
7
+ data.tar.gz: 37b00b6000617888e7940b7a55c2b57ad8cc8575d119c3583bfab9d10244831dc6007093d9e4d3933513abccd889f8eb6a6fcc14bcf6692e35a693ade259a769
data/README.md CHANGED
@@ -34,23 +34,11 @@ 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='stefan-natchev'>
38
- <a href='https://github.com/snatchev'>
39
- <img src='https://github.com/snatchev.png?size=140'>
40
- </a>
41
- <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
42
- </td>
43
- <td id='matthew-ellis'>
44
- <a href='https://github.com/matthewellis'>
45
- <img src='https://github.com/matthewellis.png?size=140'>
46
- </a>
47
- <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
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'>
37
+ <td id='fumiya-nakamura'>
38
+ <a href='https://github.com/nafu'>
39
+ <img src='https://github.com/nafu.png?size=140'>
52
40
  </a>
53
- <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
41
+ <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
54
42
  </td>
55
43
  <td id='danielle-tomlinson'>
56
44
  <a href='https://github.com/endocrimes'>
@@ -58,6 +46,18 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
58
46
  </a>
59
47
  <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
60
48
  </td>
49
+ <td id='jérôme-lacoste'>
50
+ <a href='https://github.com/lacostej'>
51
+ <img src='https://github.com/lacostej.png?size=140'>
52
+ </a>
53
+ <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
54
+ </td>
55
+ <td id='olivier-halligon'>
56
+ <a href='https://github.com/AliSoftware'>
57
+ <img src='https://github.com/AliSoftware.png?size=140'>
58
+ </a>
59
+ <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
60
+ </td>
61
61
  <td id='kohki-miki'>
62
62
  <a href='https://github.com/giginet'>
63
63
  <img src='https://github.com/giginet.png?size=140'>
@@ -66,55 +66,61 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
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='jorge-revuelta-h'>
70
+ <a href='https://github.com/minuscorp'>
71
+ <img src='https://github.com/minuscorp.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/minuscorp'>Jorge Revuelta H</a></h4>
74
74
  </td>
75
- <td id='daniel-jankowski'>
76
- <a href='https://github.com/mollyIV'>
77
- <img src='https://github.com/mollyIV.png?size=140'>
75
+ <td id='luka-mirosevic'>
76
+ <a href='https://github.com/lmirosevic'>
77
+ <img src='https://github.com/lmirosevic.png?size=140'>
78
78
  </a>
79
- <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
79
+ <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
80
80
  </td>
81
- <td id='iulian-onofrei'>
82
- <a href='https://github.com/revolter'>
83
- <img src='https://github.com/revolter.png?size=140'>
81
+ <td id='manu-wallner'>
82
+ <a href='https://github.com/milch'>
83
+ <img src='https://github.com/milch.png?size=140'>
84
84
  </a>
85
- <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
85
+ <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
86
86
  </td>
87
- <td id='max-ott'>
88
- <a href='https://github.com/max-ott'>
89
- <img src='https://github.com/max-ott.png?size=140'>
87
+ <td id='jan-piotrowski'>
88
+ <a href='https://github.com/janpio'>
89
+ <img src='https://github.com/janpio.png?size=140'>
90
90
  </a>
91
- <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
91
+ <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
92
92
  </td>
93
- <td id='jérôme-lacoste'>
94
- <a href='https://github.com/lacostej'>
95
- <img src='https://github.com/lacostej.png?size=140'>
93
+ <td id='helmut-januschka'>
94
+ <a href='https://github.com/hjanuschka'>
95
+ <img src='https://github.com/hjanuschka.png?size=140'>
96
96
  </a>
97
- <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
97
+ <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
98
98
  </td>
99
99
  </tr>
100
100
  <tr>
101
- <td id='fumiya-nakamura'>
102
- <a href='https://github.com/nafu'>
103
- <img src='https://github.com/nafu.png?size=140'>
101
+ <td id='iulian-onofrei'>
102
+ <a href='https://github.com/revolter'>
103
+ <img src='https://github.com/revolter.png?size=140'>
104
104
  </a>
105
- <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
105
+ <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
106
106
  </td>
107
- <td id='jan-piotrowski'>
108
- <a href='https://github.com/janpio'>
109
- <img src='https://github.com/janpio.png?size=140'>
107
+ <td id='matthew-ellis'>
108
+ <a href='https://github.com/matthewellis'>
109
+ <img src='https://github.com/matthewellis.png?size=140'>
110
110
  </a>
111
- <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
111
+ <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
112
112
  </td>
113
- <td id='luka-mirosevic'>
114
- <a href='https://github.com/lmirosevic'>
115
- <img src='https://github.com/lmirosevic.png?size=140'>
113
+ <td id='max-ott'>
114
+ <a href='https://github.com/max-ott'>
115
+ <img src='https://github.com/max-ott.png?size=140'>
116
116
  </a>
117
- <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
117
+ <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
118
+ </td>
119
+ <td id='daniel-jankowski'>
120
+ <a href='https://github.com/mollyIV'>
121
+ <img src='https://github.com/mollyIV.png?size=140'>
122
+ </a>
123
+ <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
118
124
  </td>
119
125
  <td id='aaron-brager'>
120
126
  <a href='https://github.com/getaaron'>
@@ -122,57 +128,51 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
122
128
  </a>
123
129
  <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
124
130
  </td>
125
- <td id='felix-krause'>
126
- <a href='https://github.com/KrauseFx'>
127
- <img src='https://github.com/KrauseFx.png?size=140'>
128
- </a>
129
- <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
130
- </td>
131
131
  </tr>
132
132
  <tr>
133
+ <td id='jimmy-dee'>
134
+ <a href='https://github.com/jdee'>
135
+ <img src='https://github.com/jdee.png?size=140'>
136
+ </a>
137
+ <h4 align='center'>Jimmy Dee</h4>
138
+ </td>
133
139
  <td id='josh-holtz'>
134
140
  <a href='https://github.com/joshdholtz'>
135
141
  <img src='https://github.com/joshdholtz.png?size=140'>
136
142
  </a>
137
143
  <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
138
144
  </td>
139
- <td id='helmut-januschka'>
140
- <a href='https://github.com/hjanuschka'>
141
- <img src='https://github.com/hjanuschka.png?size=140'>
142
- </a>
143
- <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
144
- </td>
145
- <td id='andrew-mcburney'>
146
- <a href='https://github.com/armcburney'>
147
- <img src='https://github.com/armcburney.png?size=140'>
148
- </a>
149
- <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
150
- </td>
151
- <td id='olivier-halligon'>
152
- <a href='https://github.com/AliSoftware'>
153
- <img src='https://github.com/AliSoftware.png?size=140'>
145
+ <td id='felix-krause'>
146
+ <a href='https://github.com/KrauseFx'>
147
+ <img src='https://github.com/KrauseFx.png?size=140'>
154
148
  </a>
155
- <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
149
+ <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
156
150
  </td>
157
- <td id='jimmy-dee'>
158
- <a href='https://github.com/jdee'>
159
- <img src='https://github.com/jdee.png?size=140'>
151
+ <td id='joshua-liebowitz'>
152
+ <a href='https://github.com/taquitos'>
153
+ <img src='https://github.com/taquitos.png?size=140'>
160
154
  </a>
161
- <h4 align='center'>Jimmy Dee</h4>
155
+ <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
162
156
  </td>
163
- </tr>
164
- <tr>
165
157
  <td id='maksym-grebenets'>
166
158
  <a href='https://github.com/mgrebenets'>
167
159
  <img src='https://github.com/mgrebenets.png?size=140'>
168
160
  </a>
169
161
  <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
170
162
  </td>
171
- <td id='manu-wallner'>
172
- <a href='https://github.com/milch'>
173
- <img src='https://github.com/milch.png?size=140'>
163
+ </tr>
164
+ <tr>
165
+ <td id='stefan-natchev'>
166
+ <a href='https://github.com/snatchev'>
167
+ <img src='https://github.com/snatchev.png?size=140'>
174
168
  </a>
175
- <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
169
+ <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
170
+ </td>
171
+ <td id='andrew-mcburney'>
172
+ <a href='https://github.com/armcburney'>
173
+ <img src='https://github.com/armcburney.png?size=140'>
174
+ </a>
175
+ <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
176
176
  </td>
177
177
  </table>
178
178
 
@@ -0,0 +1,98 @@
1
+ module Deliver
2
+ # This is a convinient class that enumerates app store connect's screenshots in various degrees.
3
+ class AppScreenshotIterator
4
+ NUMBER_OF_THREADS = Helper.test? ? 1 : [ENV.fetch("DELIVER_NUMBER_OF_THREADS", 10).to_i, 10].min
5
+
6
+ # @param localizations [Array<Spaceship::ConnectAPI::AppStoreVersionLocalization>]
7
+ def initialize(localizations)
8
+ @localizations = localizations
9
+ end
10
+
11
+ # Iterate app_screenshot_set over localizations
12
+ #
13
+ # @yield [localization, app_screenshot_set]
14
+ # @yieldparam [optional, Spaceship::ConnectAPI::AppStoreVersionLocalization] localization
15
+ # @yieldparam [optional, Spaceship::ConnectAPI::AppStoreScreenshotSet] app_screenshot_set
16
+ def each_app_screenshot_set(&block)
17
+ return enum_for(__method__) unless block_given?
18
+
19
+ # Collect app_screenshot_sets from localizations in parallel but
20
+ # limit the number of threads working at a time with using `lazy` and `force` controls
21
+ # to not attack App Store Connect
22
+ results = @localizations.each_slice(NUMBER_OF_THREADS).lazy.map do |localizations|
23
+ localizations.map do |localization|
24
+ Thread.new do
25
+ [localization, localization.get_app_screenshot_sets]
26
+ end
27
+ end
28
+ end.flat_map do |threads|
29
+ threads.map { |t| t.join.value }
30
+ end.force
31
+
32
+ results.each do |localization, app_screenshot_sets|
33
+ app_screenshot_sets.each do |app_screenshot_set|
34
+ yield(localization, app_screenshot_set)
35
+ end
36
+ end
37
+ end
38
+
39
+ # Iterate app_screenshot over localizations and app_screenshot_sets
40
+ #
41
+ # @yield [localization, app_screenshot_set, app_screenshot]
42
+ # @yieldparam [optional, Spaceship::ConnectAPI::AppStoreVersionLocalization] localization
43
+ # @yieldparam [optional, Spaceship::ConnectAPI::AppStoreScreenshotSet] app_screenshot_set
44
+ # @yieldparam [optional, Spaceship::ConnectAPI::AppStoreScreenshot] app_screenshot
45
+ def each_app_screenshot(&block)
46
+ return enum_for(__method__) unless block_given?
47
+
48
+ each_app_screenshot_set do |localization, app_screenshot_set|
49
+ app_screenshot_set.app_screenshots.each do |app_screenshot|
50
+ yield(localization, app_screenshot_set, app_screenshot)
51
+ end
52
+ end
53
+ end
54
+
55
+ # Iterate given local app_screenshot over localizations and app_screenshot_sets with index within each app_screenshot_set
56
+ #
57
+ # @param screenshots_per_language [Hash<String, Array<Deliver::AppScreenshot>]
58
+ # @yield [localization, app_screenshot_set, app_screenshot, index]
59
+ # @yieldparam [optional, Spaceship::ConnectAPI::AppStoreVersionLocalization] localization
60
+ # @yieldparam [optional, Spaceship::ConnectAPI::AppStoreScreenshotSet] app_screenshot_set
61
+ # @yieldparam [optional, Deliver::AppScreenshot] screenshot
62
+ # @yieldparam [optional, Integer] index a number reperesents which position the screenshot will be
63
+ def each_local_screenshot(screenshots_per_language, &block)
64
+ return enum_for(__method__, screenshots_per_language) unless block_given?
65
+
66
+ # Iterate over all the screenshots per language and display_type
67
+ # and then enqueue them to worker one by one if it's not duplciated on App Store Connect
68
+ screenshots_per_language.map do |language, screenshots_for_language|
69
+ localization = @localizations.find { |l| l.locale == language }
70
+ [localization, screenshots_for_language]
71
+ end.reject do |localization, _|
72
+ localization.nil?
73
+ end.each do |localization, screenshots_for_language|
74
+ iterate_over_screenshots_per_language(localization, screenshots_for_language, &block)
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def iterate_over_screenshots_per_language(localization, screenshots_for_language, &block)
81
+ app_screenshot_sets_per_display_type = localization.get_app_screenshot_sets.map { |set| [set.screenshot_display_type, set] }.to_h
82
+ screenshots_per_display_type = screenshots_for_language.reject { |screenshot| screenshot.device_type.nil? }.group_by(&:device_type)
83
+
84
+ screenshots_per_display_type.each do |display_type, screenshots|
85
+ # Create AppScreenshotSet for given display_type if it doesn't exsit
86
+ app_screenshot_set = app_screenshot_sets_per_display_type[display_type]
87
+ app_screenshot_set ||= localization.create_app_screenshot_set(attributes: { screenshotDisplayType: display_type })
88
+ iterate_over_screenshots_per_display_type(localization, app_screenshot_set, screenshots, &block)
89
+ end
90
+ end
91
+
92
+ def iterate_over_screenshots_per_display_type(localization, app_screenshot_set, screenshots, &block)
93
+ screenshots.each.with_index do |screenshot, index|
94
+ yield(localization, app_screenshot_set, screenshot, index)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,64 @@
1
+ require 'thread'
2
+
3
+ module Deliver
4
+ # This dispatches jobs to worker threads and make it work in parallel.
5
+ # It's suitable for I/O bounds works and not for CPU bounds works.
6
+ # Use this when you have all the items that you'll process in advance.
7
+ # Simply enqueue them to this and call `QueueWorker#start`.
8
+ class QueueWorker
9
+ # @param concurrency (Numeric) - A number of threads to be created
10
+ # @param block (Proc) - A task you want to execute with enqueued items
11
+ def initialize(concurrency, &block)
12
+ @concurrency = concurrency
13
+ @block = block
14
+ @queue = Queue.new
15
+ end
16
+
17
+ # @param job (Object) - An arbitary object that keeps parameters
18
+ def enqueue(job)
19
+ @queue.push(job)
20
+ end
21
+
22
+ # Call this after you enqueuned all the jobs you want to process
23
+ # This method blocks current thread until all the enqueued jobs are processed
24
+ def start
25
+ threads = []
26
+ @concurrency.times do
27
+ threads << Thread.new do
28
+ while running? && !empty?
29
+ job = @queue.pop
30
+ @block.call(job) if job
31
+ end
32
+ end
33
+ end
34
+
35
+ wait_for_complete
36
+ threads.each(&:join)
37
+ end
38
+
39
+ private
40
+
41
+ def running?
42
+ !@queue.closed?
43
+ end
44
+
45
+ def empty?
46
+ @queue.empty?
47
+ end
48
+
49
+ def wait_for_complete
50
+ wait_thread = Thread.new do
51
+ loop do
52
+ if @queue.empty?
53
+ @queue.close
54
+ break
55
+ end
56
+
57
+ sleep(1)
58
+ end
59
+ end
60
+
61
+ wait_thread.join
62
+ end
63
+ end
64
+ end
@@ -4,10 +4,17 @@ require 'digest/md5'
4
4
  require_relative 'app_screenshot'
5
5
  require_relative 'module'
6
6
  require_relative 'loader'
7
+ require_relative 'queue_worker'
8
+ require_relative 'app_screenshot_iterator'
7
9
 
8
10
  module Deliver
9
11
  # upload screenshots to App Store Connect
10
12
  class UploadScreenshots
13
+ DeleteScreenshotJob = Struct.new(:app_screenshot, :localization, :app_screenshot_set)
14
+ UploadScreenshotJob = Struct.new(:app_screenshot_set, :path)
15
+
16
+ NUMBER_OF_THREADS = Helper.test? ? 1 : [ENV.fetch("DELIVER_NUMBER_OF_THREADS", 10).to_i, 10].min
17
+
11
18
  def upload(options, screenshots)
12
19
  return if options[:skip_screenshots]
13
20
  return if options[:edit_live]
@@ -50,57 +57,47 @@ module Deliver
50
57
  localizations = version.get_app_store_version_localizations
51
58
  end
52
59
 
53
- upload_screenshots(screenshots_per_language, localizations, options)
60
+ upload_screenshots(localizations, screenshots_per_language)
61
+
62
+ Helper.show_loading_indicator("Sorting screenshots uploaded...")
63
+ sort_screenshots(localizations)
64
+ Helper.hide_loading_indicator
65
+
66
+ UI.success("Successfully uploaded screenshots to App Store Connect")
54
67
  end
55
68
 
56
69
  def delete_screenshots(localizations, screenshots_per_language, tries: 5)
57
70
  tries -= 1
58
71
 
59
- # Get localizations on version
60
- localizations.each do |localization|
61
- # Only delete screenshots if trying to upload
62
- next unless screenshots_per_language.keys.include?(localization.locale)
63
-
64
- # Iterate over all screenshots for each set and delete
65
- screenshot_sets = localization.get_app_screenshot_sets
66
-
67
- # Multi threading delete on single localization
68
- threads = []
69
- errors = []
70
-
71
- screenshot_sets.each do |screenshot_set|
72
- UI.message("Removing all previously uploaded screenshots for '#{localization.locale}' '#{screenshot_set.screenshot_display_type}'...")
73
- screenshot_set.app_screenshots.each do |screenshot|
74
- UI.verbose("Deleting screenshot - #{localization.locale} #{screenshot_set.screenshot_display_type} #{screenshot.id}")
75
- threads << Thread.new do
76
- begin
77
- screenshot.delete!
78
- UI.verbose("Deleted screenshot - #{localization.locale} #{screenshot_set.screenshot_display_type} #{screenshot.id}")
79
- rescue => error
80
- UI.verbose("Failed to delete screenshot - #{localization.locale} #{screenshot_set.screenshot_display_type} #{screenshot.id}")
81
- errors << error
82
- end
83
- end
84
- end
72
+ worker = QueueWorker.new(NUMBER_OF_THREADS) do |job|
73
+ start_time = Time.now
74
+ target = "#{job.localization.locale} #{job.app_screenshot_set.screenshot_display_type} #{job.app_screenshot.id}"
75
+ begin
76
+ UI.verbose("Deleting '#{target}'")
77
+ job.app_screenshot.delete!
78
+ UI.message("Deleted '#{target}' - (#{Time.now - start_time} secs)")
79
+ rescue => error
80
+ UI.error("Failed to delete screenshot #{target} - (#{Time.now - start_time} secs)")
81
+ UI.error(error.message)
85
82
  end
83
+ end
86
84
 
87
- sleep(1) # Feels bad but sleeping a bit to let the threads catchup
88
-
89
- unless threads.empty?
90
- Helper.show_loading_indicator("Waiting for screenshots to be deleted for '#{localization.locale}'... (might be slow)") unless FastlaneCore::Globals.verbose?
91
- threads.each(&:join)
92
- Helper.hide_loading_indicator unless FastlaneCore::Globals.verbose?
93
- end
85
+ iterator = AppScreenshotIterator.new(localizations)
86
+ iterator.each_app_screenshot do |localization, app_screenshot_set, app_screenshot|
87
+ # Only delete screenshots if trying to upload
88
+ next unless screenshots_per_language.keys.include?(localization.locale)
94
89
 
95
- # Crash if any errors happen while deleting
96
- errors.each do |error|
97
- UI.error(error.message)
98
- end
90
+ UI.verbose("Queued delete sceeenshot job for #{localization.locale} #{app_screenshot_set.screenshot_display_type} #{app_screenshot.id}")
91
+ worker.enqueue(DeleteScreenshotJob.new(app_screenshot, localization, app_screenshot_set))
99
92
  end
100
93
 
94
+ worker.start
95
+
101
96
  # Verify all screenshots have been deleted
102
97
  # Sometimes API requests will fail but screenshots will still be deleted
103
- count = count_screenshots(localizations)
98
+ count = iterator.each_app_screenshot_set.map { |_, app_screenshot_set| app_screenshot_set }
99
+ .reduce(0) { |sum, app_screenshot_set| sum + app_screenshot_set.app_screenshots.size }
100
+
104
101
  UI.important("Number of screenshots not deleted: #{count}")
105
102
  if count > 0
106
103
  if tries.zero?
@@ -114,113 +111,107 @@ module Deliver
114
111
  end
115
112
  end
116
113
 
117
- def count_screenshots(localizations)
118
- count = 0
119
- localizations.each do |localization|
120
- screenshot_sets = localization.get_app_screenshot_sets
121
- screenshot_sets.each do |screenshot_set|
122
- count += screenshot_set.app_screenshots.size
123
- end
124
- end
125
-
126
- return count
127
- end
128
-
129
- def upload_screenshots(screenshots_per_language, localizations, options)
130
- # Check if should wait for processing
131
- # Default to waiting if submitting for review (since needed for submission)
132
- # Otherwise use enviroment variable
133
- if ENV["DELIVER_SKIP_WAIT_FOR_SCREENSHOT_PROCESSING"].nil?
134
- wait_for_processing = options[:submit_for_review]
135
- UI.verbose("Setting wait_for_processing from ':submit_for_review' option")
136
- else
137
- UI.verbose("Setting wait_for_processing from 'DELIVER_SKIP_WAIT_FOR_SCREENSHOT_PROCESSING' environment variable")
138
- wait_for_processing = !FastlaneCore::Env.truthy?("DELIVER_SKIP_WAIT_FOR_SCREENSHOT_PROCESSING")
139
- end
140
-
141
- if wait_for_processing
142
- UI.important("Will wait for screenshot image processing")
143
- UI.important("Set env DELIVER_SKIP_WAIT_FOR_SCREENSHOT_PROCESSING=true to skip waiting for screenshots to process")
144
- else
145
- UI.important("Skipping the wait for screenshot image processing (which may affect submission)")
146
- UI.important("Set env DELIVER_SKIP_WAIT_FOR_SCREENSHOT_PROCESSING=false to wait for screenshots to process")
147
- end
114
+ def upload_screenshots(localizations, screenshots_per_language, tries: 5)
115
+ tries -= 1
148
116
 
149
117
  # Upload screenshots
150
- indized = {} # per language and device type
151
-
152
- screenshots_per_language.each do |language, screenshots_for_language|
153
- # Find localization to upload screenshots to
154
- localization = localizations.find do |l|
155
- l.locale == language
118
+ worker = QueueWorker.new(NUMBER_OF_THREADS) do |job|
119
+ begin
120
+ UI.verbose("Uploading '#{job.path}'...")
121
+ start_time = Time.now
122
+ job.app_screenshot_set.upload_screenshot(path: job.path, wait_for_processing: false)
123
+ UI.message("Uploaded '#{job.path}'... (#{Time.now - start_time} secs)")
124
+ rescue => error
125
+ UI.error(error)
156
126
  end
127
+ end
157
128
 
158
- unless localization
159
- UI.error("Couldn't find localization on version for #{language}")
129
+ number_of_screenshots = 0
130
+ iterator = AppScreenshotIterator.new(localizations)
131
+ iterator.each_local_screenshot(screenshots_per_language) do |localization, app_screenshot_set, screenshot, index|
132
+ if index >= 10
133
+ UI.error("Too many screenshots found for device '#{screenshot.device_type}' in '#{screenshot.language}', skipping this one (#{screenshot.path})")
160
134
  next
161
135
  end
162
136
 
163
- indized[localization.locale] ||= {}
137
+ checksum = UploadScreenshots.calculate_checksum(screenshot.path)
138
+ duplicate = app_screenshot_set.app_screenshots.any? { |s| s.source_file_checksum == checksum }
164
139
 
165
- # Create map to find screenshot set to add screenshot to
166
- app_screenshot_sets_map = {}
167
- app_screenshot_sets = localization.get_app_screenshot_sets
168
- app_screenshot_sets.each do |app_screenshot_set|
169
- app_screenshot_sets_map[app_screenshot_set.screenshot_display_type] = app_screenshot_set
140
+ # Enqueue uploading job if it's not duplicated otherwise screenshot will be skipped
141
+ if duplicate
142
+ UI.message("Previous uploaded. Skipping '#{screenshot.path}'...")
143
+ else
144
+ worker.enqueue(UploadScreenshotJob.new(app_screenshot_set, screenshot.path))
145
+ end
170
146
 
171
- # Set initial screnshot count
172
- indized[localization.locale][app_screenshot_set.screenshot_display_type] ||= {
173
- count: app_screenshot_set.app_screenshots.size,
174
- checksums: []
175
- }
147
+ number_of_screenshots += 1
148
+ end
176
149
 
177
- checksums = app_screenshot_set.app_screenshots.map(&:source_file_checksum).uniq
178
- indized[localization.locale][app_screenshot_set.screenshot_display_type][:checksums] = checksums
179
- end
150
+ worker.start
180
151
 
181
- UI.message("Uploading #{screenshots_for_language.length} screenshots for language #{language}")
182
- screenshots_for_language.each do |screenshot|
183
- display_type = screenshot.device_type
184
- set = app_screenshot_sets_map[display_type]
152
+ UI.verbose('Uploading jobs are completed')
185
153
 
186
- if display_type.nil?
187
- UI.error("Error... Screenshot size #{screenshot.screen_size} not valid for App Store Connect")
188
- next
189
- end
154
+ Helper.show_loading_indicator("Waiting for all the screenshots processed...")
155
+ states = wait_for_complete(iterator)
156
+ Helper.hide_loading_indicator
157
+ retry_upload_screenshots_if_needed(iterator, states, number_of_screenshots, tries, localizations, screenshots_per_language)
190
158
 
191
- unless set
192
- set = localization.create_app_screenshot_set(attributes: {
193
- screenshotDisplayType: display_type
194
- })
195
- app_screenshot_sets_map[display_type] = set
159
+ UI.message("Successfully uploaded all screenshots")
160
+ end
196
161
 
197
- indized[localization.locale][set.screenshot_display_type] = {
198
- count: 0,
199
- checksums: []
200
- }
201
- end
162
+ # Verify all screenshots have been processed
163
+ def wait_for_complete(iterator)
164
+ loop do
165
+ states = iterator.each_app_screenshot.map { |_, _, app_screenshot| app_screenshot }.each_with_object({}) do |app_screenshot, hash|
166
+ state = app_screenshot.asset_delivery_state['state']
167
+ hash[state] ||= 0
168
+ hash[state] += 1
169
+ end
202
170
 
203
- index = indized[localization.locale][set.screenshot_display_type][:count]
171
+ is_processing = states.fetch('UPLOAD_COMPLETE', 0) > 0
172
+ return states unless is_processing
204
173
 
205
- if index >= 10
206
- UI.error("Too many screenshots found for device '#{screenshot.device_type}' in '#{screenshot.language}', skipping this one (#{screenshot.path})")
207
- next
174
+ UI.verbose("There are still incomplete screenshots - #{states}")
175
+ sleep(5)
176
+ end
177
+ end
178
+
179
+ # Verify all screenshots states on App Store Connect are okay
180
+ def retry_upload_screenshots_if_needed(iterator, states, number_of_screenshots, tries, localizations, screenshots_per_language)
181
+ is_failure = states.fetch("FAILED", 0) > 0
182
+ is_missing_screenshot = states.reduce(0) { |sum, (k, v)| sum + v } != number_of_screenshots
183
+ if is_failure || is_missing_screenshot
184
+ if tries.zero?
185
+ incomplete_screenshot_count = states.reject { |k, v| k == 'COMPLETE' }.reduce(0) { |sum, (k, v)| sum + v }
186
+ UI.user_error!("Failed verification of all screenshots uploaded... #{incomplete_screenshot_count} incomplete screenshot(s) still exist")
187
+ else
188
+ UI.error("Failed to upload all screenshots... Tries remaining: #{tries}")
189
+ # Delete bad entries before retry
190
+ iterator.each_app_screenshot do |_, _, app_screenshot|
191
+ app_screenshot.delete! unless app_screenshot.complete?
208
192
  end
193
+ upload_screenshots(localizations, screenshots_per_language, tries: tries)
194
+ end
195
+ end
196
+ end
209
197
 
210
- bytes = File.binread(screenshot.path)
211
- checksum = Digest::MD5.hexdigest(bytes)
212
- duplicate = indized[localization.locale][set.screenshot_display_type][:checksums].include?(checksum)
198
+ def sort_screenshots(localizations)
199
+ iterator = AppScreenshotIterator.new(localizations)
213
200
 
214
- if duplicate
215
- UI.message("Previous uploaded. Skipping '#{screenshot.path}'...")
216
- else
217
- indized[localization.locale][set.screenshot_display_type][:count] += 1
218
- UI.message("Uploading '#{screenshot.path}'...")
219
- set.upload_screenshot(path: screenshot.path, wait_for_processing: wait_for_processing)
220
- end
201
+ # Re-order screenshots within app_screenshot_set
202
+ worker = QueueWorker.new(NUMBER_OF_THREADS) do |app_screenshot_set|
203
+ original_ids = app_screenshot_set.app_screenshots.map(&:id)
204
+ sorted_ids = app_screenshot_set.app_screenshots.sort_by(&:file_name).map(&:id)
205
+ if original_ids != sorted_ids
206
+ app_screenshot_set.reorder_screenshots(app_screenshot_ids: sorted_ids)
221
207
  end
222
208
  end
223
- UI.success("Successfully uploaded screenshots to App Store Connect")
209
+
210
+ iterator.each_app_screenshot_set do |_, app_screenshot_set|
211
+ worker.enqueue(app_screenshot_set)
212
+ end
213
+
214
+ worker.start
224
215
  end
225
216
 
226
217
  def collect_screenshots(options)
@@ -299,5 +290,11 @@ module Deliver
299
290
  Spaceship::Tunes.client.available_languages
300
291
  end
301
292
  end
293
+
294
+ # helper method to mock this step in tests
295
+ def self.calculate_checksum(path)
296
+ bytes = File.binread(path)
297
+ Digest::MD5.hexdigest(bytes)
298
+ end
302
299
  end
303
300
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.155.3'.freeze
2
+ VERSION = '2.156.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
@@ -14,4 +14,4 @@ class Deliverfile: DeliverfileProtocol {
14
14
  // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
- // Generated with fastlane 2.155.3
17
+ // Generated with fastlane 2.156.0
@@ -245,4 +245,4 @@ extension DeliverfileProtocol {
245
245
 
246
246
  // Please don't remove the lines below
247
247
  // They are used to detect outdated files
248
- // FastlaneRunnerAPIVersion [0.9.32]
248
+ // FastlaneRunnerAPIVersion [0.9.33]
@@ -9204,4 +9204,4 @@ let snapshotfile: Snapshotfile = Snapshotfile()
9204
9204
 
9205
9205
  // Please don't remove the lines below
9206
9206
  // They are used to detect outdated files
9207
- // FastlaneRunnerAPIVersion [0.9.85]
9207
+ // FastlaneRunnerAPIVersion [0.9.86]
@@ -14,4 +14,4 @@ class Gymfile: GymfileProtocol {
14
14
  // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
- // Generated with fastlane 2.155.3
17
+ // Generated with fastlane 2.156.0
@@ -181,4 +181,4 @@ extension GymfileProtocol {
181
181
 
182
182
  // Please don't remove the lines below
183
183
  // They are used to detect outdated files
184
- // FastlaneRunnerAPIVersion [0.9.35]
184
+ // FastlaneRunnerAPIVersion [0.9.36]
@@ -14,4 +14,4 @@ class Matchfile: MatchfileProtocol {
14
14
  // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
- // Generated with fastlane 2.155.3
17
+ // Generated with fastlane 2.156.0
@@ -165,4 +165,4 @@ extension MatchfileProtocol {
165
165
 
166
166
  // Please don't remove the lines below
167
167
  // They are used to detect outdated files
168
- // FastlaneRunnerAPIVersion [0.9.29]
168
+ // FastlaneRunnerAPIVersion [0.9.30]
@@ -14,4 +14,4 @@ class Precheckfile: PrecheckfileProtocol {
14
14
  // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
- // Generated with fastlane 2.155.3
17
+ // Generated with fastlane 2.156.0
@@ -33,4 +33,4 @@ extension PrecheckfileProtocol {
33
33
 
34
34
  // Please don't remove the lines below
35
35
  // They are used to detect outdated files
36
- // FastlaneRunnerAPIVersion [0.9.28]
36
+ // FastlaneRunnerAPIVersion [0.9.29]
@@ -14,4 +14,4 @@ class Scanfile: ScanfileProtocol {
14
14
  // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
- // Generated with fastlane 2.155.3
17
+ // Generated with fastlane 2.156.0
@@ -257,4 +257,4 @@ extension ScanfileProtocol {
257
257
 
258
258
  // Please don't remove the lines below
259
259
  // They are used to detect outdated files
260
- // FastlaneRunnerAPIVersion [0.9.40]
260
+ // FastlaneRunnerAPIVersion [0.9.41]
@@ -14,4 +14,4 @@ class Screengrabfile: ScreengrabfileProtocol {
14
14
  // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
- // Generated with fastlane 2.155.3
17
+ // Generated with fastlane 2.156.0
@@ -93,4 +93,4 @@ extension ScreengrabfileProtocol {
93
93
 
94
94
  // Please don't remove the lines below
95
95
  // They are used to detect outdated files
96
- // FastlaneRunnerAPIVersion [0.9.30]
96
+ // FastlaneRunnerAPIVersion [0.9.31]
@@ -14,4 +14,4 @@ class Snapshotfile: SnapshotfileProtocol {
14
14
  // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
- // Generated with fastlane 2.155.3
17
+ // Generated with fastlane 2.156.0
@@ -181,4 +181,4 @@ extension SnapshotfileProtocol {
181
181
 
182
182
  // Please don't remove the lines below
183
183
  // They are used to detect outdated files
184
- // FastlaneRunnerAPIVersion [0.9.24]
184
+ // FastlaneRunnerAPIVersion [0.9.25]
@@ -320,6 +320,7 @@ module FastlaneCore
320
320
  proj << "-scheme #{options[:scheme].shellescape}" if options[:scheme]
321
321
  proj << "-project #{options[:project].shellescape}" if options[:project]
322
322
  proj << "-configuration #{options[:configuration].shellescape}" if options[:configuration]
323
+ proj << "-derivedDataPath #{options[:derived_data_path].shellescape}" if options[:derived_data_path]
323
324
  proj << "-xcconfig #{options[:xcconfig].shellescape}" if options[:xcconfig]
324
325
 
325
326
  if FastlaneCore::Helper.xcode_at_least?('11.0') && options[:cloned_source_packages_path]
@@ -38,7 +38,6 @@ module Gym
38
38
  options << "-toolchain '#{config[:toolchain]}'" if config[:toolchain]
39
39
  options << "-destination '#{config[:destination]}'" if config[:destination]
40
40
  options << "-archivePath #{archive_path.shellescape}" unless config[:skip_archive]
41
- options << "-derivedDataPath '#{config[:derived_data_path]}'" if config[:derived_data_path]
42
41
  options << "-resultBundlePath '#{result_bundle_path}'" if config[:result_bundle]
43
42
  options << config[:xcargs] if config[:xcargs]
44
43
  options << "OTHER_SWIFT_FLAGS=\"-Xfrontend -debug-time-function-bodies\"" if config[:analyze_build_time]
@@ -35,7 +35,9 @@ module Scan
35
35
  options << "-sdk '#{config[:sdk]}'" if config[:sdk]
36
36
  options << destination # generated in `detect_values`
37
37
  options << "-toolchain '#{config[:toolchain]}'" if config[:toolchain]
38
- options << "-derivedDataPath '#{config[:derived_data_path]}'" if config[:derived_data_path]
38
+ if config[:derived_data_path] && !options.include?("-derivedDataPath #{config[:derived_data_path].shellescape}")
39
+ options << "-derivedDataPath #{config[:derived_data_path].shellescape}"
40
+ end
39
41
  options << "-resultBundlePath '#{result_bundle_path}'" if config[:result_bundle]
40
42
  if FastlaneCore::Helper.xcode_at_least?(10)
41
43
  options << "-parallel-testing-worker-count #{config[:concurrent_workers]}" if config[:concurrent_workers]
@@ -66,7 +66,7 @@ module Screengrab
66
66
  run_adb_command("-s #{device_serial} root", print_all: false, print_command: true)
67
67
  end
68
68
 
69
- clear_device_previous_screenshots(device_serial, device_screenshots_paths)
69
+ clear_device_previous_screenshots(@config[:app_package_name], device_serial, device_screenshots_paths)
70
70
 
71
71
  app_apk_path ||= select_app_apk(discovered_apk_paths)
72
72
  tests_apk_path ||= select_tests_apk(discovered_apk_paths)
@@ -157,12 +157,12 @@ module Screengrab
157
157
  end.flatten
158
158
  end
159
159
 
160
- def clear_device_previous_screenshots(device_serial, device_screenshots_paths)
160
+ def clear_device_previous_screenshots(app_package_name, device_serial, device_screenshots_paths)
161
161
  UI.message('Cleaning screenshots on device')
162
162
 
163
163
  device_screenshots_paths.each do |device_path|
164
- if_device_path_exists(device_serial, device_path) do |path|
165
- run_adb_command("-s #{device_serial} shell rm -rf #{path}",
164
+ if_device_path_exists(app_package_name, device_serial, device_path) do |path|
165
+ run_adb_command("-s #{device_serial} shell run-as #{app_package_name} rm -rf #{path}",
166
166
  print_all: true,
167
167
  print_command: true)
168
168
  end
@@ -296,7 +296,7 @@ module Screengrab
296
296
 
297
297
  Dir.mktmpdir do |tempdir|
298
298
  device_screenshots_paths.each do |device_path|
299
- if_device_path_exists(device_serial, device_path) do |path|
299
+ if_device_path_exists(@config[:app_package_name], device_serial, device_path) do |path|
300
300
  next unless path.include?(locale)
301
301
  run_adb_command("-s #{device_serial} pull #{path} #{tempdir}",
302
302
  print_all: false,
@@ -361,8 +361,8 @@ module Screengrab
361
361
 
362
362
  # Some device commands fail if executed against a device path that does not exist, so this helper method
363
363
  # provides a way to conditionally execute a block only if the provided path exists on the device.
364
- def if_device_path_exists(device_serial, device_path)
365
- return if run_adb_command("-s #{device_serial} shell ls #{device_path}",
364
+ def if_device_path_exists(app_package_name, device_serial, device_path)
365
+ return if run_adb_command("-s #{device_serial} shell run-as #{app_package_name} ls #{device_path}",
366
366
  print_all: false,
367
367
  print_command: false).include?('No such file')
368
368
 
@@ -24,7 +24,9 @@ module Snapshot
24
24
  options = []
25
25
  options += project_path_array
26
26
  options << "-sdk '#{config[:sdk]}'" if config[:sdk]
27
- options << "-derivedDataPath '#{derived_data_path}'"
27
+ if derived_data_path && !options.include?("-derivedDataPath #{derived_data_path.shellescape}")
28
+ options << "-derivedDataPath #{derived_data_path.shellescape}"
29
+ end
28
30
  options << "-resultBundlePath '#{result_bundle_path}'" if result_bundle_path
29
31
  if FastlaneCore::Helper.xcode_at_least?(11)
30
32
  options << "-testPlan '#{config[:testplan]}'" if config[:testplan]
metadata CHANGED
@@ -1,35 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.155.3
4
+ version: 2.156.0
5
5
  platform: ruby
6
6
  authors:
7
- - Jimmy Dee
8
- - Helmut Januschka
9
- - Felix Krause
10
- - Stefan Natchev
11
- - Daniel Jankowski
7
+ - Luka Mirosevic
8
+ - Max Ott
12
9
  - Fumiya Nakamura
13
- - Kohki Miki
14
- - Josh Holtz
15
- - Jorge Revuelta H
10
+ - Danielle Tomlinson
11
+ - Jimmy Dee
12
+ - Iulian Onofrei
16
13
  - Matthew Ellis
17
- - Max Ott
18
- - Maksym Grebenets
19
- - Luka Mirosevic
20
- - Manu Wallner
21
- - Aaron Brager
14
+ - Stefan Natchev
22
15
  - Andrew McBurney
23
- - Danielle Tomlinson
16
+ - Manu Wallner
17
+ - Jorge Revuelta H
18
+ - Olivier Halligon
19
+ - Felix Krause
24
20
  - Jan Piotrowski
25
- - Iulian Onofrei
21
+ - Helmut Januschka
26
22
  - Joshua Liebowitz
23
+ - Aaron Brager
24
+ - Kohki Miki
25
+ - Maksym Grebenets
26
+ - Daniel Jankowski
27
+ - Josh Holtz
27
28
  - Jérôme Lacoste
28
- - Olivier Halligon
29
29
  autorequire:
30
30
  bindir: bin
31
31
  cert_chain: []
32
- date: 2020-08-07 00:00:00.000000000 Z
32
+ date: 2020-08-11 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: slack-notifier
@@ -944,6 +944,7 @@ files:
944
944
  - deliver/lib/assets/summary.html.erb
945
945
  - deliver/lib/deliver.rb
946
946
  - deliver/lib/deliver/app_screenshot.rb
947
+ - deliver/lib/deliver/app_screenshot_iterator.rb
947
948
  - deliver/lib/deliver/commands_generator.rb
948
949
  - deliver/lib/deliver/detect_values.rb
949
950
  - deliver/lib/deliver/download_screenshots.rb
@@ -952,6 +953,7 @@ files:
952
953
  - deliver/lib/deliver/loader.rb
953
954
  - deliver/lib/deliver/module.rb
954
955
  - deliver/lib/deliver/options.rb
956
+ - deliver/lib/deliver/queue_worker.rb
955
957
  - deliver/lib/deliver/runner.rb
956
958
  - deliver/lib/deliver/setup.rb
957
959
  - deliver/lib/deliver/submit_for_review.rb
@@ -1447,8 +1449,6 @@ files:
1447
1449
  - match/lib/assets/MatchfileTemplate.swift
1448
1450
  - match/lib/assets/READMETemplate.md
1449
1451
  - match/lib/match.rb
1450
- - match/lib/match/.options.rb.swp
1451
- - match/lib/match/.runner.rb.swp
1452
1452
  - match/lib/match/change_password.rb
1453
1453
  - match/lib/match/commands_generator.rb
1454
1454
  - match/lib/match/encryption.rb
@@ -1558,8 +1558,6 @@ files:
1558
1558
  - sigh/README.md
1559
1559
  - sigh/lib/assets/resign.sh
1560
1560
  - sigh/lib/sigh.rb
1561
- - sigh/lib/sigh/.options.rb.swp
1562
- - sigh/lib/sigh/.runner.rb.swp
1563
1561
  - sigh/lib/sigh/commands_generator.rb
1564
1562
  - sigh/lib/sigh/download_all.rb
1565
1563
  - sigh/lib/sigh/local_manage.rb
@@ -1608,6 +1606,9 @@ files:
1608
1606
  - spaceship/lib/assets/languageMappingReadable.json
1609
1607
  - spaceship/lib/spaceship.rb
1610
1608
  - spaceship/lib/spaceship/.DS_Store
1609
+ - spaceship/lib/spaceship/.client.rb.swp
1610
+ - spaceship/lib/spaceship/.spaceauth_runner.rb.swp
1611
+ - spaceship/lib/spaceship/.two_step_or_factor_client.rb.swp
1611
1612
  - spaceship/lib/spaceship/base.rb
1612
1613
  - spaceship/lib/spaceship/client.rb
1613
1614
  - spaceship/lib/spaceship/commands_generator.rb
@@ -1615,7 +1616,6 @@ files:
1615
1616
  - spaceship/lib/spaceship/connect_api/client.rb
1616
1617
  - spaceship/lib/spaceship/connect_api/file_uploader.rb
1617
1618
  - spaceship/lib/spaceship/connect_api/model.rb
1618
- - spaceship/lib/spaceship/connect_api/models/.profile.rb.swp
1619
1619
  - spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb
1620
1620
  - spaceship/lib/spaceship/connect_api/models/app.rb
1621
1621
  - spaceship/lib/spaceship/connect_api/models/app_category.rb
@@ -1658,7 +1658,6 @@ files:
1658
1658
  - spaceship/lib/spaceship/connect_api/models/sandbox_tester.rb
1659
1659
  - spaceship/lib/spaceship/connect_api/models/territory.rb
1660
1660
  - spaceship/lib/spaceship/connect_api/models/user.rb
1661
- - spaceship/lib/spaceship/connect_api/provisioning/.provisioning.rb.swp
1662
1661
  - spaceship/lib/spaceship/connect_api/provisioning/client.rb
1663
1662
  - spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb
1664
1663
  - spaceship/lib/spaceship/connect_api/response.rb
Binary file