fastlane 2.155.3 → 2.156.0

Sign up to get free protection for your applications and to get access to all the features.
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