fastlane 2.155.0 → 2.156.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +74 -74
  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 +123 -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/sigh/lib/sigh/runner.rb +27 -3
  27. data/snapshot/lib/snapshot/test_command_generator_base.rb +3 -1
  28. data/spaceship/lib/spaceship/connect_api/.client.rb.swp +0 -0
  29. data/spaceship/lib/spaceship/connect_api/models/profile.rb +3 -2
  30. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +2 -2
  31. metadata +22 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d05003197423c1e94c2728d49100fbacb7d5f5b657491b94e90f34432d2774ba
4
- data.tar.gz: 99b28cc3d83ec3500d9a90554db8464ee479a7e533141e9246164d26fef8edba
3
+ metadata.gz: 8ddb9f8d09ffcb09f5ddd4d6365f67d41c538e8804630e40911e058a8174aaf2
4
+ data.tar.gz: 8bf0f6513c658bb9891058e5bee6fb22689bc496376e4aff6a2d2e5f1a2b9b74
5
5
  SHA512:
6
- metadata.gz: 9a7b6ce2df7348ad80f366ad54a619ad1d966348e3e2a0f616f43d160681c1ba15625f7c16923d4b0bbfa3c873b3936891001f53c5349abba1e0a3c0a6bb4704
7
- data.tar.gz: c75739db5b1e8dcea81230f67effe0d1b46de274cab20d85183aa3dafb64088ed85a7260f2aa47e14e802c8a81879b541d7ba4fbca55f56a2c84c1cb09fbeae0
6
+ metadata.gz: 9627a6de633cc011c1cd083468869543125e4eb021f025152c3aaf0e4e6067c80bcc514e71c1d425485138df0ff7ab43fa70771d846e0270c49ad50b60dc47c1
7
+ data.tar.gz: 177ba0af8b688d96e5374f7a3175663cebe4e3bae3966733880e75e0634cc4e1cdedc3f12c1c8ac0cd415b024eb3aa9385489d67f98b2e9d4e5175631d2874bf
data/README.md CHANGED
@@ -34,43 +34,17 @@ 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='danielle-tomlinson'>
38
- <a href='https://github.com/endocrimes'>
39
- <img src='https://github.com/endocrimes.png?size=140'>
40
- </a>
41
- <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</a></h4>
42
- </td>
43
- <td id='olivier-halligon'>
44
- <a href='https://github.com/AliSoftware'>
45
- <img src='https://github.com/AliSoftware.png?size=140'>
46
- </a>
47
- <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
48
- </td>
49
- <td id='max-ott'>
50
- <a href='https://github.com/max-ott'>
51
- <img src='https://github.com/max-ott.png?size=140'>
52
- </a>
53
- <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
54
- </td>
55
37
  <td id='jorge-revuelta-h'>
56
38
  <a href='https://github.com/minuscorp'>
57
39
  <img src='https://github.com/minuscorp.png?size=140'>
58
40
  </a>
59
41
  <h4 align='center'><a href='https://twitter.com/minuscorp'>Jorge Revuelta H</a></h4>
60
42
  </td>
61
- <td id='andrew-mcburney'>
62
- <a href='https://github.com/armcburney'>
63
- <img src='https://github.com/armcburney.png?size=140'>
64
- </a>
65
- <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
66
- </td>
67
- </tr>
68
- <tr>
69
- <td id='jérôme-lacoste'>
70
- <a href='https://github.com/lacostej'>
71
- <img src='https://github.com/lacostej.png?size=140'>
43
+ <td id='luka-mirosevic'>
44
+ <a href='https://github.com/lmirosevic'>
45
+ <img src='https://github.com/lmirosevic.png?size=140'>
72
46
  </a>
73
- <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
47
+ <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
74
48
  </td>
75
49
  <td id='josh-holtz'>
76
50
  <a href='https://github.com/joshdholtz'>
@@ -78,11 +52,11 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
78
52
  </a>
79
53
  <h4 align='center'><a href='https://twitter.com/joshdholtz'>Josh Holtz</a></h4>
80
54
  </td>
81
- <td id='manu-wallner'>
82
- <a href='https://github.com/milch'>
83
- <img src='https://github.com/milch.png?size=140'>
55
+ <td id='felix-krause'>
56
+ <a href='https://github.com/KrauseFx'>
57
+ <img src='https://github.com/KrauseFx.png?size=140'>
84
58
  </a>
85
- <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
59
+ <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
86
60
  </td>
87
61
  <td id='fumiya-nakamura'>
88
62
  <a href='https://github.com/nafu'>
@@ -90,57 +64,51 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
90
64
  </a>
91
65
  <h4 align='center'><a href='https://twitter.com/nafu003'>Fumiya Nakamura</a></h4>
92
66
  </td>
93
- <td id='felix-krause'>
94
- <a href='https://github.com/KrauseFx'>
95
- <img src='https://github.com/KrauseFx.png?size=140'>
96
- </a>
97
- <h4 align='center'><a href='https://twitter.com/KrauseFx'>Felix Krause</a></h4>
98
- </td>
99
67
  </tr>
100
68
  <tr>
69
+ <td id='max-ott'>
70
+ <a href='https://github.com/max-ott'>
71
+ <img src='https://github.com/max-ott.png?size=140'>
72
+ </a>
73
+ <h4 align='center'><a href='https://twitter.com/ott_max'>Max Ott</a></h4>
74
+ </td>
101
75
  <td id='stefan-natchev'>
102
76
  <a href='https://github.com/snatchev'>
103
77
  <img src='https://github.com/snatchev.png?size=140'>
104
78
  </a>
105
79
  <h4 align='center'><a href='https://twitter.com/snatchev'>Stefan Natchev</a></h4>
106
80
  </td>
107
- <td id='matthew-ellis'>
108
- <a href='https://github.com/matthewellis'>
109
- <img src='https://github.com/matthewellis.png?size=140'>
110
- </a>
111
- <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
112
- </td>
113
- <td id='daniel-jankowski'>
114
- <a href='https://github.com/mollyIV'>
115
- <img src='https://github.com/mollyIV.png?size=140'>
81
+ <td id='jérôme-lacoste'>
82
+ <a href='https://github.com/lacostej'>
83
+ <img src='https://github.com/lacostej.png?size=140'>
116
84
  </a>
117
- <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
85
+ <h4 align='center'><a href='https://twitter.com/lacostej'>Jérôme Lacoste</a></h4>
118
86
  </td>
119
- <td id='jimmy-dee'>
120
- <a href='https://github.com/jdee'>
121
- <img src='https://github.com/jdee.png?size=140'>
87
+ <td id='joshua-liebowitz'>
88
+ <a href='https://github.com/taquitos'>
89
+ <img src='https://github.com/taquitos.png?size=140'>
122
90
  </a>
123
- <h4 align='center'>Jimmy Dee</h4>
91
+ <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
124
92
  </td>
125
- <td id='jan-piotrowski'>
126
- <a href='https://github.com/janpio'>
127
- <img src='https://github.com/janpio.png?size=140'>
93
+ <td id='iulian-onofrei'>
94
+ <a href='https://github.com/revolter'>
95
+ <img src='https://github.com/revolter.png?size=140'>
128
96
  </a>
129
- <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
97
+ <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
130
98
  </td>
131
99
  </tr>
132
100
  <tr>
133
- <td id='luka-mirosevic'>
134
- <a href='https://github.com/lmirosevic'>
135
- <img src='https://github.com/lmirosevic.png?size=140'>
101
+ <td id='jimmy-dee'>
102
+ <a href='https://github.com/jdee'>
103
+ <img src='https://github.com/jdee.png?size=140'>
136
104
  </a>
137
- <h4 align='center'><a href='https://twitter.com/lmirosevic'>Luka Mirosevic</a></h4>
105
+ <h4 align='center'>Jimmy Dee</h4>
138
106
  </td>
139
- <td id='maksym-grebenets'>
140
- <a href='https://github.com/mgrebenets'>
141
- <img src='https://github.com/mgrebenets.png?size=140'>
107
+ <td id='andrew-mcburney'>
108
+ <a href='https://github.com/armcburney'>
109
+ <img src='https://github.com/armcburney.png?size=140'>
142
110
  </a>
143
- <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
111
+ <h4 align='center'><a href='https://twitter.com/armcburney'>Andrew McBurney</a></h4>
144
112
  </td>
145
113
  <td id='kohki-miki'>
146
114
  <a href='https://github.com/giginet'>
@@ -148,31 +116,63 @@ If the above doesn't help, please [submit an issue](https://github.com/fastlane/
148
116
  </a>
149
117
  <h4 align='center'><a href='https://twitter.com/giginet'>Kohki Miki</a></h4>
150
118
  </td>
119
+ <td id='jan-piotrowski'>
120
+ <a href='https://github.com/janpio'>
121
+ <img src='https://github.com/janpio.png?size=140'>
122
+ </a>
123
+ <h4 align='center'><a href='https://twitter.com/Sujan'>Jan Piotrowski</a></h4>
124
+ </td>
125
+ <td id='olivier-halligon'>
126
+ <a href='https://github.com/AliSoftware'>
127
+ <img src='https://github.com/AliSoftware.png?size=140'>
128
+ </a>
129
+ <h4 align='center'><a href='https://twitter.com/aligatr'>Olivier Halligon</a></h4>
130
+ </td>
131
+ </tr>
132
+ <tr>
151
133
  <td id='helmut-januschka'>
152
134
  <a href='https://github.com/hjanuschka'>
153
135
  <img src='https://github.com/hjanuschka.png?size=140'>
154
136
  </a>
155
137
  <h4 align='center'><a href='https://twitter.com/hjanuschka'>Helmut Januschka</a></h4>
156
138
  </td>
139
+ <td id='daniel-jankowski'>
140
+ <a href='https://github.com/mollyIV'>
141
+ <img src='https://github.com/mollyIV.png?size=140'>
142
+ </a>
143
+ <h4 align='center'><a href='https://twitter.com/mollyIV'>Daniel Jankowski</a></h4>
144
+ </td>
145
+ <td id='manu-wallner'>
146
+ <a href='https://github.com/milch'>
147
+ <img src='https://github.com/milch.png?size=140'>
148
+ </a>
149
+ <h4 align='center'><a href='https://twitter.com/acrooow'>Manu Wallner</a></h4>
150
+ </td>
157
151
  <td id='aaron-brager'>
158
152
  <a href='https://github.com/getaaron'>
159
153
  <img src='https://github.com/getaaron.png?size=140'>
160
154
  </a>
161
155
  <h4 align='center'><a href='https://twitter.com/getaaron'>Aaron Brager</a></h4>
162
156
  </td>
157
+ <td id='matthew-ellis'>
158
+ <a href='https://github.com/matthewellis'>
159
+ <img src='https://github.com/matthewellis.png?size=140'>
160
+ </a>
161
+ <h4 align='center'><a href='https://twitter.com/mellis1995'>Matthew Ellis</a></h4>
162
+ </td>
163
163
  </tr>
164
164
  <tr>
165
- <td id='iulian-onofrei'>
166
- <a href='https://github.com/revolter'>
167
- <img src='https://github.com/revolter.png?size=140'>
165
+ <td id='maksym-grebenets'>
166
+ <a href='https://github.com/mgrebenets'>
167
+ <img src='https://github.com/mgrebenets.png?size=140'>
168
168
  </a>
169
- <h4 align='center'><a href='https://twitter.com/Revolt666'>Iulian Onofrei</a></h4>
169
+ <h4 align='center'><a href='https://twitter.com/mgrebenets'>Maksym Grebenets</a></h4>
170
170
  </td>
171
- <td id='joshua-liebowitz'>
172
- <a href='https://github.com/taquitos'>
173
- <img src='https://github.com/taquitos.png?size=140'>
171
+ <td id='danielle-tomlinson'>
172
+ <a href='https://github.com/endocrimes'>
173
+ <img src='https://github.com/endocrimes.png?size=140'>
174
174
  </a>
175
- <h4 align='center'><a href='https://twitter.com/taquitos'>Joshua Liebowitz</a></h4>
175
+ <h4 align='center'><a href='https://twitter.com/endocrimes'>Danielle Tomlinson</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,108 @@ 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
208
- end
174
+ UI.verbose("There are still incomplete screenshots - #{states}")
175
+ sleep(5)
176
+ end
177
+ end
209
178
 
210
- bytes = File.binread(screenshot.path)
211
- checksum = Digest::MD5.hexdigest(bytes)
212
- duplicate = indized[localization.locale][set.screenshot_display_type][:checksums].include?(checksum)
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 && !screenshots_per_language.empty?
213
183
 
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)
184
+ if is_failure || is_missing_screenshot
185
+ if tries.zero?
186
+ incomplete_screenshot_count = states.reject { |k, v| k == 'COMPLETE' }.reduce(0) { |sum, (k, v)| sum + v }
187
+ UI.user_error!("Failed verification of all screenshots uploaded... #{incomplete_screenshot_count} incomplete screenshot(s) still exist")
188
+ else
189
+ UI.error("Failed to upload all screenshots... Tries remaining: #{tries}")
190
+ # Delete bad entries before retry
191
+ iterator.each_app_screenshot do |_, _, app_screenshot|
192
+ app_screenshot.delete! unless app_screenshot.complete?
220
193
  end
194
+ upload_screenshots(localizations, screenshots_per_language, tries: tries)
221
195
  end
222
196
  end
223
- UI.success("Successfully uploaded screenshots to App Store Connect")
197
+ end
198
+
199
+ def sort_screenshots(localizations)
200
+ iterator = AppScreenshotIterator.new(localizations)
201
+
202
+ # Re-order screenshots within app_screenshot_set
203
+ worker = QueueWorker.new(NUMBER_OF_THREADS) do |app_screenshot_set|
204
+ original_ids = app_screenshot_set.app_screenshots.map(&:id)
205
+ sorted_ids = app_screenshot_set.app_screenshots.sort_by(&:file_name).map(&:id)
206
+ if original_ids != sorted_ids
207
+ app_screenshot_set.reorder_screenshots(app_screenshot_ids: sorted_ids)
208
+ end
209
+ end
210
+
211
+ iterator.each_app_screenshot_set do |_, app_screenshot_set|
212
+ worker.enqueue(app_screenshot_set)
213
+ end
214
+
215
+ worker.start
224
216
  end
225
217
 
226
218
  def collect_screenshots(options)
@@ -299,5 +291,11 @@ module Deliver
299
291
  Spaceship::Tunes.client.available_languages
300
292
  end
301
293
  end
294
+
295
+ # helper method to mock this step in tests
296
+ def self.calculate_checksum(path)
297
+ bytes = File.binread(path)
298
+ Digest::MD5.hexdigest(bytes)
299
+ end
302
300
  end
303
301
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.155.0'.freeze
2
+ VERSION = '2.156.1'.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.0
17
+ // Generated with fastlane 2.156.1
@@ -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.29]
248
+ // FastlaneRunnerAPIVersion [0.9.34]
@@ -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.82]
9207
+ // FastlaneRunnerAPIVersion [0.9.87]
@@ -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.0
17
+ // Generated with fastlane 2.156.1
@@ -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.32]
184
+ // FastlaneRunnerAPIVersion [0.9.37]
@@ -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.0
17
+ // Generated with fastlane 2.156.1
@@ -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.26]
168
+ // FastlaneRunnerAPIVersion [0.9.31]
@@ -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.0
17
+ // Generated with fastlane 2.156.1
@@ -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.25]
36
+ // FastlaneRunnerAPIVersion [0.9.30]
@@ -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.0
17
+ // Generated with fastlane 2.156.1
@@ -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.37]
260
+ // FastlaneRunnerAPIVersion [0.9.42]
@@ -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.0
17
+ // Generated with fastlane 2.156.1
@@ -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.27]
96
+ // FastlaneRunnerAPIVersion [0.9.32]
@@ -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.0
17
+ // Generated with fastlane 2.156.1
@@ -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.21]
184
+ // FastlaneRunnerAPIVersion [0.9.26]
@@ -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
 
@@ -171,7 +171,9 @@ module Sigh
171
171
  name: name,
172
172
  profile_type: profile_type,
173
173
  bundle_id_id: bundle_id.id,
174
- certificate_ids: [certificate_to_use.id]
174
+ certificate_ids: certificates_to_use.map(&:id),
175
+ device_ids: devices_to_use.map(&:id),
176
+ template_name: Sigh.config[:template_name]
175
177
  )
176
178
 
177
179
  profile
@@ -226,8 +228,30 @@ module Sigh
226
228
  certificates
227
229
  end
228
230
 
231
+ def devices_to_use
232
+ # Only use devices if development or adhoc
233
+ return [] if !Sigh.config[:development] && !Sigh.config[:adhoc]
234
+
235
+ device_class = case Sigh.config[:platform].to_s
236
+ when 'ios'
237
+ [
238
+ Spaceship::ConnectAPI::Device::DeviceClass::APPLE_WATCH,
239
+ Spaceship::ConnectAPI::Device::DeviceClass::IPAD,
240
+ Spaceship::ConnectAPI::Device::DeviceClass::IPHONE,
241
+ Spaceship::ConnectAPI::Device::DeviceClass::IPOD
242
+ ].join(",")
243
+ when 'tvos'
244
+ Spaceship::ConnectAPI::Device::DeviceClass::APPLE_TV
245
+ when 'macos', 'catalyst'
246
+ Spaceship::ConnectAPI::Device::DeviceClass::MAC
247
+ end
248
+
249
+ filter = { deviceClass: device_class }
250
+ return Spaceship::ConnectAPI::Device.all(filter: filter)
251
+ end
252
+
229
253
  # Certificate to use based on the current distribution mode
230
- def certificate_to_use
254
+ def certificates_to_use
231
255
  certificates = certificates_for_profile_and_platform
232
256
 
233
257
  # Filter them
@@ -277,7 +301,7 @@ module Sigh
277
301
  end
278
302
 
279
303
  return certificates if Sigh.config[:development] # development profiles support multiple certificates
280
- return certificates.first
304
+ return [certificates.first]
281
305
  end
282
306
 
283
307
  # Downloads and stores the provisioning profile
@@ -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]
@@ -69,14 +69,15 @@ module Spaceship
69
69
  return resps.flat_map(&:to_models)
70
70
  end
71
71
 
72
- def self.create(name: nil, profile_type: nil, bundle_id_id: nil, certificate_ids: nil, device_ids: nil)
72
+ def self.create(name: nil, profile_type: nil, bundle_id_id: nil, certificate_ids: nil, device_ids: nil, template_name: nil)
73
73
  resp = Spaceship::ConnectAPI.post_profiles(
74
74
  bundle_id_id: bundle_id_id,
75
75
  certificates: certificate_ids,
76
76
  devices: device_ids,
77
77
  attributes: {
78
78
  name: name,
79
- profileType: profile_type
79
+ profileType: profile_type,
80
+ templateName: template_name
80
81
  }
81
82
  )
82
83
  return resp.to_models.first
@@ -65,10 +65,10 @@ module Spaceship
65
65
  end
66
66
  },
67
67
  devices: {
68
- data: (devices || []).map do |certificate|
68
+ data: (devices || []).map do |device|
69
69
  {
70
70
  type: "devices",
71
- id: devices
71
+ id: device
72
72
  }
73
73
  end
74
74
  }
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.0
4
+ version: 2.156.1
5
5
  platform: ruby
6
6
  authors:
7
+ - Aaron Brager
8
+ - Luka Mirosevic
9
+ - Maksym Grebenets
10
+ - Jorge Revuelta H
7
11
  - Manu Wallner
8
- - Helmut Januschka
9
- - Jérôme Lacoste
10
- - Fumiya Nakamura
11
- - Felix Krause
12
- - Jimmy Dee
12
+ - Stefan Natchev
13
+ - Andrew McBurney
14
+ - Matthew Ellis
15
+ - Josh Holtz
16
+ - Max Ott
13
17
  - Iulian Onofrei
14
- - Danielle Tomlinson
15
- - Maksym Grebenets
16
- - Jan Piotrowski
17
- - Luka Mirosevic
18
18
  - Joshua Liebowitz
19
+ - Jimmy Dee
19
20
  - Daniel Jankowski
20
- - Max Ott
21
- - Olivier Halligon
22
- - Josh Holtz
23
- - Matthew Ellis
24
- - Stefan Natchev
25
- - Jorge Revuelta H
21
+ - Jan Piotrowski
26
22
  - Kohki Miki
27
- - Aaron Brager
28
- - Andrew McBurney
23
+ - Jérôme Lacoste
24
+ - Fumiya Nakamura
25
+ - Olivier Halligon
26
+ - Felix Krause
27
+ - Danielle Tomlinson
28
+ - Helmut Januschka
29
29
  autorequire:
30
30
  bindir: bin
31
31
  cert_chain: []
32
- date: 2020-08-06 00:00:00.000000000 Z
32
+ date: 2020-08-13 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
@@ -1608,6 +1610,7 @@ files:
1608
1610
  - spaceship/lib/spaceship/client.rb
1609
1611
  - spaceship/lib/spaceship/commands_generator.rb
1610
1612
  - spaceship/lib/spaceship/connect_api.rb
1613
+ - spaceship/lib/spaceship/connect_api/.client.rb.swp
1611
1614
  - spaceship/lib/spaceship/connect_api/client.rb
1612
1615
  - spaceship/lib/spaceship/connect_api/file_uploader.rb
1613
1616
  - spaceship/lib/spaceship/connect_api/model.rb