fastlane 2.154.0 → 2.156.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) 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/html_generator.rb +8 -1
  5. data/deliver/lib/deliver/queue_worker.rb +64 -0
  6. data/deliver/lib/deliver/upload_screenshots.rb +122 -125
  7. data/fastlane/lib/fastlane/actions/create_keychain.rb +5 -1
  8. data/fastlane/lib/fastlane/actions/sync_code_signing.rb +5 -0
  9. data/fastlane/lib/fastlane/version.rb +1 -1
  10. data/fastlane/swift/Deliverfile.swift +1 -1
  11. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  12. data/fastlane/swift/Fastlane.swift +375 -182
  13. data/fastlane/swift/Gymfile.swift +1 -1
  14. data/fastlane/swift/GymfileProtocol.swift +1 -1
  15. data/fastlane/swift/Matchfile.swift +1 -1
  16. data/fastlane/swift/MatchfileProtocol.swift +6 -2
  17. data/fastlane/swift/Precheckfile.swift +1 -1
  18. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  19. data/fastlane/swift/Scanfile.swift +1 -1
  20. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  21. data/fastlane/swift/Screengrabfile.swift +1 -1
  22. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  23. data/fastlane/swift/Snapshotfile.swift +1 -1
  24. data/fastlane/swift/SnapshotfileProtocol.swift +5 -1
  25. data/fastlane_core/lib/fastlane_core/project.rb +1 -0
  26. data/gym/lib/gym/detect_values.rb +6 -3
  27. data/gym/lib/gym/generators/build_command_generator.rb +0 -1
  28. data/gym/lib/gym/module.rb +22 -0
  29. data/gym/lib/gym/runner.rb +8 -10
  30. data/match/lib/match/generator.rb +6 -0
  31. data/match/lib/match/options.rb +7 -2
  32. data/match/lib/match/runner.rb +12 -5
  33. data/match/lib/match/spaceship_ensure.rb +7 -9
  34. data/match/lib/match/storage/google_cloud_storage.rb +1 -1
  35. data/scan/lib/scan/test_command_generator.rb +3 -1
  36. data/screengrab/lib/screengrab/runner.rb +7 -7
  37. data/sigh/lib/sigh/download_all.rb +42 -27
  38. data/sigh/lib/sigh/module.rb +26 -0
  39. data/sigh/lib/sigh/options.rb +2 -2
  40. data/sigh/lib/sigh/runner.rb +100 -35
  41. data/snapshot/lib/snapshot/options.rb +5 -0
  42. data/snapshot/lib/snapshot/test_command_generator.rb +3 -2
  43. data/snapshot/lib/snapshot/test_command_generator_base.rb +3 -1
  44. data/snapshot/lib/snapshot/test_command_generator_xcode_8.rb +4 -1
  45. data/spaceship/lib/spaceship/.client.rb.swp +0 -0
  46. data/spaceship/lib/spaceship/.spaceauth_runner.rb.swp +0 -0
  47. data/spaceship/lib/spaceship/.two_step_or_factor_client.rb.swp +0 -0
  48. data/spaceship/lib/spaceship/connect_api/client.rb +2 -0
  49. data/spaceship/lib/spaceship/connect_api/model.rb +1 -1
  50. data/spaceship/lib/spaceship/connect_api/models/app.rb +3 -1
  51. data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +17 -5
  52. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +41 -7
  53. data/spaceship/lib/spaceship/connect_api/models/profile.rb +32 -1
  54. data/spaceship/lib/spaceship/connect_api/provisioning/client.rb +46 -4
  55. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +41 -0
  56. data/supply/lib/supply/client.rb +2 -1
  57. data/supply/lib/supply/options.rb +8 -1
  58. metadata +24 -19
@@ -5,6 +5,32 @@ module Sigh
5
5
  # Use this to just setup the configuration attribute and set it later somewhere else
6
6
  class << self
7
7
  attr_accessor :config
8
+
9
+ def profile_pretty_type(profile_type)
10
+ require 'spaceship'
11
+
12
+ case profile_type
13
+ when Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_DEVELOPMENT,
14
+ Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DEVELOPMENT,
15
+ Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_DEVELOPMENT,
16
+ Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DEVELOPMENT
17
+ "Development"
18
+ when Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_STORE,
19
+ Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_STORE,
20
+ Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_STORE,
21
+ Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_STORE
22
+ "AppStore"
23
+ when Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_ADHOC,
24
+ Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_ADHOC
25
+ "AdHoc"
26
+ when Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_INHOUSE,
27
+ Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_INHOUSE
28
+ "InHouse"
29
+ when Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DIRECT,
30
+ Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DIRECT
31
+ "Direct"
32
+ end
33
+ end
8
34
  end
9
35
 
10
36
  Helper = FastlaneCore::Helper # you gotta love Ruby: Helper.* should use the Helper class contained in FastlaneCore
@@ -131,12 +131,12 @@ module Sigh
131
131
  FastlaneCore::ConfigItem.new(key: :platform,
132
132
  short_option: '-p',
133
133
  env_name: "SIGH_PLATFORM",
134
- description: "Set the provisioning profile's platform (i.e. ios, tvos)",
134
+ description: "Set the provisioning profile's platform (i.e. ios, tvos, macos, catalyst)",
135
135
  is_string: false,
136
136
  default_value: "ios",
137
137
  verify_block: proc do |value|
138
138
  value = value.to_s
139
- pt = %w(macos tvos ios)
139
+ pt = %w(macos tvos ios catalyst)
140
140
  UI.user_error!("Unsupported platform, must be: #{pt}") unless pt.include?(value)
141
141
  end),
142
142
  FastlaneCore::ConfigItem.new(key: :readonly,
@@ -1,5 +1,7 @@
1
1
  require 'spaceship'
2
2
 
3
+ require 'base64'
4
+
3
5
  require 'fastlane_core/print_table'
4
6
  require 'fastlane_core/cert_checker'
5
7
  require_relative 'module'
@@ -42,7 +44,7 @@ module Sigh
42
44
 
43
45
  UI.user_error!("Something went wrong fetching the latest profile") unless profile
44
46
 
45
- if profile_type == Spaceship.provisioning_profile.in_house
47
+ if [Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_INHOUSE, Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_INHOUSE].include?(profile_type)
46
48
  ENV["SIGH_PROFILE_ENTERPRISE"] = "1"
47
49
  else
48
50
  ENV.delete("SIGH_PROFILE_ENTERPRISE")
@@ -55,11 +57,26 @@ module Sigh
55
57
  def profile_type
56
58
  return @profile_type if @profile_type
57
59
 
58
- @profile_type = Spaceship.provisioning_profile.app_store
59
- @profile_type = Spaceship.provisioning_profile.in_house if Spaceship.client.in_house?
60
- @profile_type = Spaceship.provisioning_profile.ad_hoc if Sigh.config[:adhoc]
61
- @profile_type = Spaceship.provisioning_profile.direct if Sigh.config[:developer_id]
62
- @profile_type = Spaceship.provisioning_profile.development if Sigh.config[:development]
60
+ case Sigh.config[:platform]
61
+ when "ios"
62
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_STORE
63
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_INHOUSE if Spaceship.client.in_house?
64
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_ADHOC if Sigh.config[:adhoc]
65
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_DEVELOPMENT if Sigh.config[:development]
66
+ when "tvos"
67
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_STORE
68
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_INHOUSE if Spaceship.client.in_house?
69
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_ADHOC if Sigh.config[:adhoc]
70
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_DEVELOPMENT if Sigh.config[:development]
71
+ when "macos"
72
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_STORE
73
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DEVELOPMENT if Sigh.config[:development]
74
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DIRECT if Sigh.config[:developer_id]
75
+ when "catalyst"
76
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_STORE
77
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DEVELOPMENT if Sigh.config[:development]
78
+ @profile_type = Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DIRECT if Sigh.config[:developer_id]
79
+ end
63
80
 
64
81
  @profile_type
65
82
  end
@@ -67,9 +84,13 @@ module Sigh
67
84
  # Fetches a profile matching the user's search requirements
68
85
  def fetch_profiles
69
86
  UI.message("Fetching profiles...")
70
- results = profile_type.find_by_bundle_id(bundle_id: Sigh.config[:app_identifier],
71
- mac: Sigh.config[:platform].to_s == 'macos',
72
- sub_platform: Sigh.config[:platform].to_s == 'tvos' ? 'tvOS' : nil)
87
+
88
+ # Filtering on 'profileType' seems to be undocumented as of 2020-07-30
89
+ # but works on both web session and official API
90
+ results = Spaceship::ConnectAPI::Profile.all(filter: { profileType: profile_type }, includes: "bundleId,certificates").select do |profile|
91
+ profile.bundle_id.identifier == Sigh.config[:app_identifier]
92
+ end
93
+
73
94
  results = results.find_all do |current_profile|
74
95
  if current_profile.valid? || Sigh.config[:force]
75
96
  true
@@ -93,7 +114,7 @@ module Sigh
93
114
  # "member" and not an a "admin"
94
115
  raw_certs = current_profile.certificates.map do |cert|
95
116
  begin
96
- raw_cert = cert.download_raw
117
+ raw_cert = Base64.decode64(cert.certificate_content)
97
118
  rescue => error
98
119
  UI.important("Cannot download cert #{cert.id} - #{error.message}")
99
120
  raw_cert = nil
@@ -114,31 +135,47 @@ module Sigh
114
135
  UI.message("Certificate for Provisioning Profile '#{current_profile.name}' not available locally: #{current_cert[:cert].id}, skipping this one...")
115
136
  end
116
137
  end
117
- installed && current_profile.certificate_valid?
138
+
139
+ # Don't need to check if certificate is valid because it comes with the
140
+ # profile in the response
141
+ installed
118
142
  end
119
143
  end
120
144
 
145
+ def profile_type_pretty_type
146
+ return Sigh.profile_pretty_type(profile_type)
147
+ end
148
+
121
149
  # Create a new profile and return it
122
150
  def create_profile!
123
- cert = certificate_to_use
124
- bundle_id = Sigh.config[:app_identifier]
125
- name = Sigh.config[:provisioning_name] || [bundle_id, profile_type.pretty_type].join(' ')
151
+ app_identifier = Sigh.config[:app_identifier]
152
+ name = Sigh.config[:provisioning_name] || [app_identifier, profile_type_pretty_type].join(' ')
126
153
 
127
154
  unless Sigh.config[:skip_fetch_profiles]
128
- if Spaceship.provisioning_profile.all(mac: Sigh.config[:platform].to_s == 'macos').find { |p| p.name == name }
155
+ profile = Spaceship::ConnectAPI::Profile.all.find { |p| p.name == name }
156
+ if profile
129
157
  UI.user_error!("The name '#{name}' is already taken, and fail_on_name_taken is true") if Sigh.config[:fail_on_name_taken]
130
158
  UI.error("The name '#{name}' is already taken, using another one.")
131
159
  name += " #{Time.now.to_i}"
132
160
  end
133
161
  end
134
162
 
163
+ bundle_id = Spaceship::ConnectAPI::BundleId.find(app_identifier)
164
+ unless bundle_id
165
+ UI.user_error!("Could not find App with App Identifier '#{Sigh.config[:app_identifier]}'")
166
+ end
167
+
135
168
  UI.important("Creating new provisioning profile for '#{Sigh.config[:app_identifier]}' with name '#{name}' for '#{Sigh.config[:platform]}' platform")
136
- profile = profile_type.create!(name: name,
137
- bundle_id: bundle_id,
138
- certificate: cert,
139
- mac: Sigh.config[:platform].to_s == 'macos',
140
- sub_platform: Sigh.config[:platform].to_s == 'tvos' ? 'tvOS' : nil,
141
- template_name: Sigh.config[:template_name])
169
+
170
+ profile = Spaceship::ConnectAPI::Profile.create(
171
+ name: name,
172
+ profile_type: profile_type,
173
+ bundle_id_id: bundle_id.id,
174
+ certificate_ids: certificates_to_use.map(&:id),
175
+ device_ids: devices_to_use.map(&:id),
176
+ template_name: Sigh.config[:template_name]
177
+ )
178
+
142
179
  profile
143
180
  end
144
181
 
@@ -155,16 +192,16 @@ module Sigh
155
192
  def certificates_for_profile_and_platform
156
193
  case Sigh.config[:platform].to_s
157
194
  when 'ios', 'tvos'
158
- if profile_type == Spaceship.provisioning_profile.Development
195
+ if profile_type == Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_DEVELOPMENT || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_DEVELOPMENT
159
196
  certificates = Spaceship.certificate.development.all +
160
197
  Spaceship.certificate.apple_development.all
161
- elsif profile_type == Spaceship.provisioning_profile.InHouse
198
+ elsif profile_type == Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_INHOUSE || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_INHOUSE
162
199
  # Enterprise accounts don't have access to Apple Distribution certificates
163
200
  certificates = Spaceship.certificate.in_house.all
164
201
  # handles case where the desired certificate type is adhoc but the account is an enterprise account
165
202
  # the apple dev portal api has a weird quirk in it where if you query for distribution certificates
166
203
  # for enterprise accounts, you get nothing back even if they exist.
167
- elsif profile_type == Spaceship.provisioning_profile.AdHoc && Spaceship.client && Spaceship.client.in_house?
204
+ elsif (profile_type == Spaceship::ConnectAPI::Profile::ProfileType::IOS_APP_ADHOC || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::TVOS_APP_ADHOC) && Spaceship.client && Spaceship.client.in_house?
168
205
  # Enterprise accounts don't have access to Apple Distribution certificates
169
206
  certificates = Spaceship.certificate.in_house.all
170
207
  else
@@ -173,14 +210,14 @@ module Sigh
173
210
  Spaceship.certificate.apple_distribution.all
174
211
  end
175
212
 
176
- when 'macos'
177
- if profile_type == Spaceship.provisioning_profile.Development
213
+ when 'macos', 'catalyst'
214
+ if profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DEVELOPMENT || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DEVELOPMENT
178
215
  certificates = Spaceship.certificate.mac_development.all +
179
216
  Spaceship.certificate.apple_development.all
180
- elsif profile_type == Spaceship.provisioning_profile.AppStore
217
+ elsif profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_STORE || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_STORE
181
218
  certificates = Spaceship.certificate.mac_app_distribution.all +
182
219
  Spaceship.certificate.apple_distribution.all
183
- elsif profile_type == Spaceship.provisioning_profile.Direct
220
+ elsif profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_APP_DIRECT || profile_type == Spaceship::ConnectAPI::Profile::ProfileType::MAC_CATALYST_APP_DIRECT
184
221
  certificates = Spaceship.certificate.developer_id_application.all
185
222
  else
186
223
  certificates = Spaceship.certificate.mac_app_distribution.all +
@@ -191,8 +228,30 @@ module Sigh
191
228
  certificates
192
229
  end
193
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
+
194
253
  # Certificate to use based on the current distribution mode
195
- def certificate_to_use
254
+ def certificates_to_use
196
255
  certificates = certificates_for_profile_and_platform
197
256
 
198
257
  # Filter them
@@ -235,26 +294,28 @@ module Sigh
235
294
  filters << "Owner Name: '#{Sigh.config[:cert_owner_name]}' " if Sigh.config[:cert_owner_name]
236
295
  filters << "Certificate ID: '#{Sigh.config[:cert_id]}' " if Sigh.config[:cert_id]
237
296
  UI.important("No certificates for filter: #{filters}") if filters.length > 0
238
- message = "Could not find a matching code signing identity for type '#{profile_type.to_s.split(':').last}'. "
297
+ message = "Could not find a matching code signing identity for type '#{profile_type_pretty_type}'. "
239
298
  message += "It is recommended to use match to manage code signing for you, more information on https://codesigning.guide. "
240
299
  message += "If you don't want to do so, you can also use cert to generate a new one: https://fastlane.tools/cert"
241
300
  UI.user_error!(message)
242
301
  end
243
302
 
244
303
  return certificates if Sigh.config[:development] # development profiles support multiple certificates
245
- return certificates.first
304
+ return [certificates.first]
246
305
  end
247
306
 
248
307
  # Downloads and stores the provisioning profile
249
308
  def download_profile(profile)
250
309
  UI.important("Downloading provisioning profile...")
251
- profile_name ||= "#{profile_type.pretty_type}_#{Sigh.config[:app_identifier]}"
310
+ profile_name ||= "#{profile_type_pretty_type}_#{Sigh.config[:app_identifier]}"
252
311
 
253
312
  if Sigh.config[:platform].to_s == 'tvos'
254
313
  profile_name += "_tvos"
314
+ elsif Sigh.config[:platform].to_s == 'catalyst'
315
+ profile_name += "_catalyst"
255
316
  end
256
317
 
257
- if Sigh.config[:platform].to_s == 'macos'
318
+ if ['macos', 'catalyst'].include?(Sigh.config[:platform].to_s)
258
319
  profile_name += '.provisionprofile'
259
320
  else
260
321
  profile_name += '.mobileprovision'
@@ -263,7 +324,8 @@ module Sigh
263
324
  tmp_path = Dir.mktmpdir("profile_download")
264
325
  output_path = File.join(tmp_path, profile_name)
265
326
  File.open(output_path, "wb") do |f|
266
- f.write(profile.download)
327
+ content = Base64.decode64(profile.profile_content)
328
+ f.write(content)
267
329
  end
268
330
 
269
331
  UI.success("Successfully downloaded provisioning profile...")
@@ -272,7 +334,10 @@ module Sigh
272
334
 
273
335
  # Makes sure the current App ID exists. If not, it will show an appropriate error message
274
336
  def ensure_app_exists!
275
- return if Spaceship::App.find(Sigh.config[:app_identifier], mac: Sigh.config[:platform].to_s == 'macos')
337
+ # Only ensuring by app identifier
338
+ # We used to ensure by platform (IOS and MAC_OS) but now apps are
339
+ # always UNIVERSAL as of 2020-07-30
340
+ return if Spaceship::ConnectAPI::BundleId.find(Sigh.config[:app_identifier])
276
341
  print_produce_command(Sigh.config)
277
342
  UI.user_error!("Could not find App with App Identifier '#{Sigh.config[:app_identifier]}'")
278
343
  end
@@ -278,6 +278,11 @@ module Snapshot
278
278
  env_name: "SNAPSHOT_DISABLE_XCPRETTY",
279
279
  description: "Disable xcpretty formatting of build",
280
280
  type: Boolean,
281
+ optional: true),
282
+ FastlaneCore::ConfigItem.new(key: :suppress_xcode_output,
283
+ env_name: "SNAPSHOT_SUPPRESS_XCODE_OUTPUT",
284
+ description: "Suppress the output of xcodebuild to stdout. Output is still saved in buildlog_path",
285
+ type: Boolean,
281
286
  optional: true)
282
287
  ]
283
288
  end
@@ -33,8 +33,9 @@ module Snapshot
33
33
 
34
34
  xcpretty = "xcpretty #{Snapshot.config[:xcpretty_args]}"
35
35
  xcpretty << "--no-color" if Helper.colors_disabled?
36
-
37
- return pipe << "| #{xcpretty}"
36
+ pipe << "| #{xcpretty}"
37
+ pipe << "> /dev/null" if Snapshot.config[:suppress_xcode_output]
38
+ return pipe
38
39
  end
39
40
 
40
41
  def destination(devices)
@@ -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]
@@ -24,7 +24,10 @@ module Snapshot
24
24
 
25
25
  def pipe(device_type, language, locale)
26
26
  log_path = xcodebuild_log_path(device_type: device_type, language: language, locale: locale)
27
- return ["| tee #{log_path.shellescape} | xcpretty #{Snapshot.config[:xcpretty_args]}"]
27
+ pipe = ["| tee #{log_path.shellescape}"]
28
+ pipe << "| xcpretty #{Snapshot.config[:xcpretty_args]}"
29
+ pipe << "> /dev/null" if Snapshot.config[:suppress_xcode_output]
30
+ return pipe
28
31
  end
29
32
 
30
33
  def destination(device_name)
@@ -164,6 +164,8 @@ module Spaceship
164
164
 
165
165
  raise UnexpectedResponse, "Temporary App Store Connect error: #{response.body}" if response.body['statusCode'] == 'ERROR'
166
166
 
167
+ store_csrf_tokens(response)
168
+
167
169
  return Spaceship::ConnectAPI::Response.new(body: response.body, status: response.status, client: self)
168
170
  end
169
171
 
@@ -152,7 +152,7 @@ module Spaceship
152
152
  id == included_data["id"] && type == included_data["type"]
153
153
  end
154
154
 
155
- inflate_model(relationship_data, included)
155
+ inflate_model(relationship_data, included) if relationship_data
156
156
  end
157
157
 
158
158
  # Map a hash or an array of data
@@ -10,6 +10,7 @@ module Spaceship
10
10
  attr_accessor :bundle_id
11
11
  attr_accessor :sku
12
12
  attr_accessor :primary_locale
13
+ attr_accessor :is_opted_in_to_distribute_ios_app_on_mac_app_store
13
14
  attr_accessor :removed
14
15
  attr_accessor :is_aag
15
16
  attr_accessor :available_in_new_territories
@@ -26,6 +27,7 @@ module Spaceship
26
27
  "bundleId" => "bundle_id",
27
28
  "sku" => "sku",
28
29
  "primaryLocale" => "primary_locale",
30
+ "isOptedInToDistributeIosAppOnMacAppStore" => "is_opted_in_to_distribute_ios_app_on_mac_app_store",
29
31
  "removed" => "removed",
30
32
  "isAAG" => "is_aag",
31
33
  "availableInNewTerritories" => "available_in_new_territories",
@@ -186,7 +188,7 @@ module Spaceship
186
188
 
187
189
  # Get the latest version
188
190
  return get_app_store_versions(filter: filter, includes: includes)
189
- .sort_by { |v| Gem::Version.new(v.version_string) }
191
+ .sort_by { |v| Date.parse(v.created_date) }
190
192
  .last
191
193
  end
192
194
 
@@ -1,4 +1,5 @@
1
1
  require_relative '../model'
2
+ require_relative './bundle_id_capability'
2
3
  module Spaceship
3
4
  class ConnectAPI
4
5
  class BundleId
@@ -20,15 +21,20 @@ module Spaceship
20
21
  "bundleIdCapabilities" => 'bundle_id_capabilities'
21
22
  })
22
23
 
23
- module Platform
24
- IOS = "IOS"
25
- MAC_OS = "MAC_OS"
26
- end
27
-
28
24
  def self.type
29
25
  return "bundleIds"
30
26
  end
31
27
 
28
+ #
29
+ # Helpers
30
+ #
31
+
32
+ def supports_catalyst?
33
+ return bundle_id_capabilities.any? do |capability|
34
+ capability.is_type?(Spaceship::ConnectAPI::BundleIdCapability::Type::MARZIPAN)
35
+ end
36
+ end
37
+
32
38
  #
33
39
  # API
34
40
  #
@@ -38,6 +44,12 @@ module Spaceship
38
44
  return resps.flat_map(&:to_models)
39
45
  end
40
46
 
47
+ def self.find(identifier, includes: nil)
48
+ return all(filter: { identifier: identifier }, includes: includes).find do |app|
49
+ app.identifier == identifier
50
+ end
51
+ end
52
+
41
53
  def self.get(bundle_id_id: nil, includes: nil)
42
54
  return Spaceship::ConnectAPI.get_bundle_id(bundle_id_id: bundle_id_id, includes: includes).first
43
55
  end
@@ -4,23 +4,57 @@ module Spaceship
4
4
  class BundleIdCapability
5
5
  include Spaceship::ConnectAPI::Model
6
6
 
7
- attr_accessor :capabilityType
8
- attr_accessor :bundleIdCapabilitiesSettingOption
7
+ attr_accessor :capability_type
8
+ attr_accessor :settings
9
9
 
10
10
  attr_mapping({
11
- "capabilityType" => "capabilityType",
12
- "settings" => "email"
11
+ "capabilityType" => "capability_type",
12
+ "settings" => "settings"
13
13
  })
14
14
 
15
- module Platform
16
- IOS = "IOS"
17
- MAC_OS = "MAC_OS"
15
+ module Type
16
+ ICLOUD = "ICLOUD"
17
+ IN_APP_PURCHASE = "IN_APP_PURCHASE"
18
+ GAME_CENTER = "GAME_CENTER"
19
+ PUSH_NOTIFICATIONS = "PUSH_NOTIFICATIONS"
20
+ WALLET = "WALLET"
21
+ INTER_APP_AUDIO = "INTER_APP_AUDIO"
22
+ MAPS = "MAPS"
23
+ ASSOCIATED_DOMAINS = "ASSOCIATED_DOMAINS"
24
+ PERSONAL_VPN = "PERSONAL_VPN"
25
+ APP_GROUPS = "APP_GROUPS"
26
+ HEALTHKIT = "HEALTHKIT"
27
+ HOMEKIT = "HOMEKIT"
28
+ WIRELESS_ACCESSORY_CONFIGURATION = "WIRELESS_ACCESSORY_CONFIGURATION"
29
+ APPLE_PAY = "APPLE_PAY"
30
+ DATA_PROTECTION = "DATA_PROTECTION"
31
+ SIRIKIT = "SIRIKIT"
32
+ NETWORK_EXTENSIONS = "NETWORK_EXTENSIONS"
33
+ MULTIPATH = "MULTIPATH"
34
+ HOT_SPOT = "HOT_SPOT"
35
+ NFC_TAG_READING = "NFC_TAG_READING"
36
+ CLASSKIT = "CLASSKIT"
37
+ AUTOFILL_CREDENTIAL_PROVIDER = "AUTOFILL_CREDENTIAL_PROVIDER"
38
+ ACCESS_WIFI_INFORMATION = "ACCESS_WIFI_INFORMATION"
39
+
40
+ # Undocumented as of 2020-06-09
41
+ MARZIPAN = "MARZIPAN" # Catalyst
18
42
  end
19
43
 
20
44
  def self.type
21
45
  return "bundleIdCapabilities"
22
46
  end
23
47
 
48
+ #
49
+ # Helpers
50
+ #
51
+
52
+ def is_type?(type)
53
+ # JWT session returns type under "capability_type" attribute
54
+ # Web session returns type under "id" attribute but with "P7GJR49W72_" prefixed
55
+ return capability_type == type || id.end_with?(type)
56
+ end
57
+
24
58
  #
25
59
  # API
26
60
  #