fastlane 2.160.0 → 2.165.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +78 -78
  3. data/cert/lib/cert/options.rb +28 -1
  4. data/cert/lib/cert/runner.rb +51 -34
  5. data/deliver/lib/deliver/app_screenshot_iterator.rb +4 -4
  6. data/deliver/lib/deliver/module.rb +2 -0
  7. data/deliver/lib/deliver/options.rb +5 -5
  8. data/deliver/lib/deliver/queue_worker.rb +14 -29
  9. data/deliver/lib/deliver/upload_metadata.rb +20 -5
  10. data/deliver/lib/deliver/upload_screenshots.rb +28 -13
  11. data/fastlane/lib/fastlane/actions/.download_dsyms.rb.swp +0 -0
  12. data/fastlane/lib/fastlane/actions/actions_helper.rb +20 -1
  13. data/fastlane/lib/fastlane/actions/app_store_build_number.rb +39 -3
  14. data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +15 -1
  15. data/fastlane/lib/fastlane/actions/check_app_store_metadata.rb +1 -0
  16. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +2 -2
  17. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +2 -2
  18. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +1 -1
  19. data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +2 -2
  20. data/fastlane/lib/fastlane/actions/docs/run_tests.md +2 -2
  21. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +12 -3
  22. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +2 -2
  23. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +1 -1
  24. data/fastlane/lib/fastlane/actions/download_dsyms.rb +1 -0
  25. data/fastlane/lib/fastlane/actions/ensure_git_status_clean.rb +13 -2
  26. data/fastlane/lib/fastlane/actions/get_certificates.rb +1 -0
  27. data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +1 -0
  28. data/fastlane/lib/fastlane/actions/import_from_git.rb +9 -1
  29. data/fastlane/lib/fastlane/actions/is_ci.rb +1 -1
  30. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +15 -0
  31. data/fastlane/lib/fastlane/actions/register_device.rb +46 -5
  32. data/fastlane/lib/fastlane/actions/register_devices.rb +50 -16
  33. data/fastlane/lib/fastlane/actions/set_changelog.rb +31 -3
  34. data/fastlane/lib/fastlane/actions/sync_code_signing.rb +1 -0
  35. data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +3 -2
  36. data/fastlane/lib/fastlane/fast_file.rb +74 -23
  37. data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
  38. data/fastlane/lib/fastlane/version.rb +1 -1
  39. data/fastlane/swift/Deliverfile.swift +1 -1
  40. data/fastlane/swift/DeliverfileProtocol.swift +4 -4
  41. data/fastlane/swift/Fastlane.swift +120 -27
  42. data/fastlane/swift/Gymfile.swift +1 -1
  43. data/fastlane/swift/GymfileProtocol.swift +1 -1
  44. data/fastlane/swift/LaneFileProtocol.swift +28 -36
  45. data/fastlane/swift/MainProcess.swift +1 -1
  46. data/fastlane/swift/Matchfile.swift +1 -1
  47. data/fastlane/swift/MatchfileProtocol.swift +21 -5
  48. data/fastlane/swift/Precheckfile.swift +1 -1
  49. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  50. data/fastlane/swift/Scanfile.swift +1 -1
  51. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  52. data/fastlane/swift/Screengrabfile.swift +1 -1
  53. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  54. data/fastlane/swift/Snapshotfile.swift +1 -1
  55. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  56. data/fastlane/swift/main.swift +1 -1
  57. data/fastlane_core/lib/fastlane_core/analytics/analytics_session.rb +6 -7
  58. data/fastlane_core/lib/fastlane_core/device_manager.rb +8 -4
  59. data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
  60. data/fastlane_core/lib/fastlane_core/keychain_importer.rb +3 -3
  61. data/gym/lib/gym/generators/package_command_generator_xcode7.rb +2 -2
  62. data/match/lib/match/generator.rb +6 -1
  63. data/match/lib/match/importer.rb +63 -18
  64. data/match/lib/match/migrate.rb +13 -2
  65. data/match/lib/match/nuke.rb +65 -22
  66. data/match/lib/match/options.rb +34 -3
  67. data/match/lib/match/runner.rb +38 -10
  68. data/match/lib/match/spaceship_ensure.rb +27 -21
  69. data/match/lib/match/storage/google_cloud_storage.rb +20 -3
  70. data/match/lib/match/storage/s3_storage.rb +19 -3
  71. data/scan/lib/scan/detect_values.rb +5 -8
  72. data/scan/lib/scan/runner.rb +2 -1
  73. data/sigh/lib/assets/resign.sh +1 -1
  74. data/sigh/lib/sigh/download_all.rb +16 -4
  75. data/sigh/lib/sigh/options.rb +21 -0
  76. data/sigh/lib/sigh/runner.rb +83 -41
  77. data/snapshot/lib/assets/SnapshotHelper.swift +4 -0
  78. data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +2 -1
  79. data/spaceship/README.md +1 -1
  80. data/spaceship/lib/spaceship/client.rb +9 -4
  81. data/spaceship/lib/spaceship/connect_api.rb +27 -0
  82. data/spaceship/lib/spaceship/connect_api/api_client.rb +12 -3
  83. data/spaceship/lib/spaceship/connect_api/client.rb +20 -7
  84. data/spaceship/lib/spaceship/connect_api/models/app.rb +51 -0
  85. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +3 -1
  86. data/spaceship/lib/spaceship/connect_api/models/beta_tester.rb +2 -1
  87. data/spaceship/lib/spaceship/connect_api/models/certificate.rb +42 -0
  88. data/spaceship/lib/spaceship/connect_api/models/custom_app_organization.rb +43 -0
  89. data/spaceship/lib/spaceship/connect_api/models/custom_app_user.rb +41 -0
  90. data/spaceship/lib/spaceship/connect_api/models/device.rb +5 -0
  91. data/spaceship/lib/spaceship/connect_api/models/profile.rb +7 -1
  92. data/spaceship/lib/spaceship/connect_api/models/user_invitation.rb +59 -0
  93. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +45 -2
  94. data/spaceship/lib/spaceship/connect_api/spaceship.rb +7 -4
  95. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +13 -0
  96. data/spaceship/lib/spaceship/connect_api/token.rb +6 -1
  97. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +75 -1
  98. data/spaceship/lib/spaceship/connect_api/users/users.rb +40 -0
  99. data/spaceship/lib/spaceship/helper/net_http_generic_request.rb +11 -5
  100. data/supply/lib/supply/uploader.rb +1 -1
  101. metadata +19 -15
@@ -15,6 +15,7 @@ require 'spaceship/connect_api/models/device'
15
15
  require 'spaceship/connect_api/models/profile'
16
16
 
17
17
  require 'spaceship/connect_api/models/user'
18
+ require 'spaceship/connect_api/models/user_invitation'
18
19
 
19
20
  require 'spaceship/connect_api/models/app'
20
21
  require 'spaceship/connect_api/models/beta_app_localization'
@@ -30,6 +31,8 @@ require 'spaceship/connect_api/models/beta_tester_metric'
30
31
  require 'spaceship/connect_api/models/build'
31
32
  require 'spaceship/connect_api/models/build_delivery'
32
33
  require 'spaceship/connect_api/models/build_beta_detail'
34
+ require 'spaceship/connect_api/models/custom_app_organization'
35
+ require 'spaceship/connect_api/models/custom_app_user'
33
36
  require 'spaceship/connect_api/models/pre_release_version'
34
37
 
35
38
  require 'spaceship/connect_api/models/age_rating_declaration'
@@ -85,5 +88,29 @@ module Spaceship
85
88
  end
86
89
  end
87
90
  end
91
+
92
+ # Defined in the App Store Connect API docs:
93
+ #
94
+ # Used for creating BundleId and Device
95
+ module BundleIdPlatform
96
+ IOS = "IOS"
97
+ MAC_OS = "MAC_OS"
98
+
99
+ ALL = [IOS, MAC_OS]
100
+
101
+ def self.map(platform)
102
+ return platform if ALL.include?(platform)
103
+
104
+ # Map from fastlane input and Spaceship::TestFlight platform values
105
+ case platform.to_sym
106
+ when :osx, :macos, :mac
107
+ return Spaceship::ConnectAPI::Platform::MAC_OS
108
+ when :ios
109
+ return Spaceship::ConnectAPI::Platform::IOS
110
+ else
111
+ raise "Cannot find a matching platform for '#{platform}' - valid values are #{ALL.join(', ')}"
112
+ end
113
+ end
114
+ end
88
115
  end
89
116
  end
@@ -17,7 +17,7 @@ module Spaceship
17
17
  #####################################################
18
18
 
19
19
  # Instantiates a client with cookie session or a JWT token.
20
- def initialize(cookie: nil, current_team_id: nil, token: nil, another_client: nil)
20
+ def initialize(cookie: nil, current_team_id: nil, token: nil, csrf_tokens: nil, another_client: nil)
21
21
  params_count = [cookie, token, another_client].compact.size
22
22
  if params_count != 1
23
23
  raise "Must initialize with one of :cookie, :token, or :another_client"
@@ -25,10 +25,10 @@ module Spaceship
25
25
 
26
26
  if token.nil?
27
27
  if another_client.nil?
28
- super(cookie: cookie, current_team_id: current_team_id, timeout: 1200)
28
+ super(cookie: cookie, current_team_id: current_team_id, csrf_tokens: csrf_tokens, timeout: 1200)
29
29
  return
30
30
  end
31
- super(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id)
31
+ super(cookie: another_client.instance_variable_get(:@cookie), current_team_id: another_client.team_id, csrf_tokens: another_client.csrf_tokens)
32
32
  else
33
33
  options = {
34
34
  request: {
@@ -152,6 +152,7 @@ module Spaceship
152
152
 
153
153
  def with_asc_retry(tries = 5, &_block)
154
154
  tries = 1 if Object.const_defined?("SpecHelper")
155
+
155
156
  response = yield
156
157
 
157
158
  status = response.status if response
@@ -162,6 +163,10 @@ module Spaceship
162
163
  end
163
164
 
164
165
  return response
166
+ rescue UnauthorizedAccessError => error
167
+ # Catch unathorized access and re-raising
168
+ # There is no need to try again
169
+ raise error
165
170
  rescue => error
166
171
  tries -= 1
167
172
  puts(error) if Spaceship::Globals.verbose?
@@ -194,6 +199,10 @@ module Spaceship
194
199
  return Spaceship::ConnectAPI::Response.new(body: response.body, status: response.status, client: self)
195
200
  end
196
201
 
202
+ def handle_401(response)
203
+ raise UnauthorizedAccessError, handle_errors(response) if response && (response.body || {})['errors']
204
+ end
205
+
197
206
  def handle_errors(response)
198
207
  # Example error format
199
208
  # {
@@ -13,20 +13,23 @@ module Spaceship
13
13
 
14
14
  # Initializes client with Apple's App Store Connect JWT auth key.
15
15
  #
16
- # This method will automatically use the key id, issuer id, and filepath from environment
16
+ # This method will automatically use the arguments from environment
17
17
  # variables if not given.
18
18
  #
19
- # All three parameters are needed to authenticate.
19
+ # The key_id, issuer_id and either filepath or key are needed to authenticate.
20
20
  #
21
21
  # @param key_id (String) (optional): The key id
22
22
  # @param issuer_id (String) (optional): The issuer id
23
23
  # @param filepath (String) (optional): The filepath
24
+ # @param key (String) (optional): The key
25
+ # @param duration (Integer) (optional): How long this session should last
26
+ # @param in_house (Boolean) (optional): Whether this session is an Enterprise one
24
27
  #
25
28
  # @raise InvalidUserCredentialsError: raised if authentication failed
26
29
  #
27
30
  # @return (Spaceship::ConnectAPI::Client) The client the login method was called for
28
- def self.auth(key_id: nil, issuer_id: nil, filepath: nil)
29
- token = Spaceship::ConnectAPI::Token.create(key_id: key_id, issuer_id: issuer_id, filepath: filepath)
31
+ def self.auth(key_id: nil, issuer_id: nil, filepath: nil, key: nil, duration: nil, in_house: nil)
32
+ token = Spaceship::ConnectAPI::Token.create(key_id: key_id, issuer_id: issuer_id, filepath: filepath, key: key, duration: duration, in_house: in_house)
30
33
  return ConnectAPI::Client.new(token: token)
31
34
  end
32
35
 
@@ -97,8 +100,18 @@ module Spaceship
97
100
  end
98
101
 
99
102
  def portal_team_id
100
- return nil if @portal_client.nil?
101
- return @portal_client.team_id
103
+ if token
104
+ message = [
105
+ "Cannot determine portal team id via the App Store Connect API (yet)",
106
+ "Look to see if you can get the portal team id from somewhere else",
107
+ "View more info in the docs at https://docs.fastlane.tools/app-store-connect-api/"
108
+ ]
109
+ raise message.join('. ')
110
+ elsif @portal_client
111
+ return @portal_client.team_id
112
+ else
113
+ raise "No App Store Connect API token or Portal Client set"
114
+ end
102
115
  end
103
116
 
104
117
  def tunes_team_id
@@ -126,7 +139,7 @@ module Spaceship
126
139
  "Or set the 'SPACESHIP_CONNECT_API_IN_HOUSE' environment variable to 'true'",
127
140
  "View more info in the docs at https://docs.fastlane.tools/app-store-connect-api/"
128
141
  ]
129
- raise message.join('\n')
142
+ raise message.join('. ')
130
143
  end
131
144
  return !!token.in_house
132
145
  elsif @portal_client
@@ -18,11 +18,26 @@ module Spaceship
18
18
  attr_accessor :app_store_versions
19
19
  attr_accessor :prices
20
20
 
21
+ # Only available with Apple ID auth
22
+ attr_accessor :distribution_type
23
+ attr_accessor :educationDiscountType
24
+
21
25
  module ContentRightsDeclaration
22
26
  USES_THIRD_PARTY_CONTENT = "USES_THIRD_PARTY_CONTENT"
23
27
  DOES_NOT_USE_THIRD_PARTY_CONTENT = "DOES_NOT_USE_THIRD_PARTY_CONTENT"
24
28
  end
25
29
 
30
+ module DistributionType
31
+ APP_STORE = "APP_STORE"
32
+ CUSTOM = "CUSTOM"
33
+ end
34
+
35
+ module EducationDiscountType
36
+ DISCOUNTED = "DISCOUNTED"
37
+ NOT_APPLICABLE = "NOT_APPLICABLE"
38
+ NOT_DISCOUNTED = "NOT_DISCOUNTED"
39
+ end
40
+
26
41
  self.attr_mapping({
27
42
  "name" => "name",
28
43
  "bundleId" => "bundle_id",
@@ -32,6 +47,8 @@ module Spaceship
32
47
  "removed" => "removed",
33
48
  "isAAG" => "is_aag",
34
49
  "availableInNewTerritories" => "available_in_new_territories",
50
+ "distributionType" => "distribution_type",
51
+ "educationDiscountType" => "education_discount_type",
35
52
 
36
53
  "contentRightsDeclaration" => "content_rights_declaration",
37
54
 
@@ -252,6 +269,24 @@ module Spaceship
252
269
  return resps.flat_map(&:to_models)
253
270
  end
254
271
 
272
+ #
273
+ # B2B
274
+ #
275
+
276
+ def disable_b2b
277
+ update(attributes: {
278
+ distributionType: DistributionType::APP_STORE,
279
+ education_discount_type: EducationDiscountType::NOT_DISCOUNTED
280
+ })
281
+ end
282
+
283
+ def enable_b2b
284
+ update(attributes: {
285
+ distributionType: App::DistributionType::CUSTOM,
286
+ education_discount_type: EducationDiscountType::NOT_APPLICABLE
287
+ })
288
+ end
289
+
255
290
  #
256
291
  # Beta Feedback
257
292
  #
@@ -323,6 +358,22 @@ module Spaceship
323
358
  return resps.flat_map(&:to_models).first
324
359
  end
325
360
 
361
+ #
362
+ # Education
363
+ #
364
+
365
+ def disable_educational_discount
366
+ update(attributes: {
367
+ education_discount_type: EducationDiscountType::NOT_DISCOUNTED
368
+ })
369
+ end
370
+
371
+ def enable_educational_discount
372
+ update(attributes: {
373
+ education_discount_type: EducationDiscountType::DISCOUNTED
374
+ })
375
+ end
376
+
326
377
  #
327
378
  # Users
328
379
  #
@@ -111,7 +111,9 @@ module Spaceship
111
111
  timeout_minutes = (ENV["SPACESHIP_SCREENSHOT_UPLOAD_TIMEOUT"] || 20).to_i
112
112
 
113
113
  loop do
114
- puts("Waiting for screenshot to appear before uploading...")
114
+ # This error handling needs to be revised since any error occured can reach here.
115
+ # It should handle errors based on what status code is.
116
+ puts("Waiting for screenshots to appear before uploading. This is unlikely to be recovered unless it's 503 error. error=\"#{error}\"")
115
117
  sleep(30)
116
118
 
117
119
  screenshots = Spaceship::ConnectAPI::AppScreenshotSet
@@ -35,7 +35,8 @@ module Spaceship
35
35
  #
36
36
 
37
37
  def self.all(filter: {}, includes: nil, limit: nil, sort: nil)
38
- return Spaceship::ConnectAPI.get_beta_testers(filter: filter, includes: includes)
38
+ resps = Spaceship::ConnectAPI.get_beta_testers(filter: filter, includes: includes).all_pages
39
+ return resps.flat_map(&:to_models)
39
40
  end
40
41
 
41
42
  def self.find(email: nil, includes: nil)
@@ -1,4 +1,7 @@
1
1
  require_relative '../model'
2
+
3
+ require 'openssl'
4
+
2
5
  module Spaceship
3
6
  class ConnectAPI
4
7
  class Certificate
@@ -6,6 +9,7 @@ module Spaceship
6
9
 
7
10
  attr_accessor :certificate_content
8
11
  attr_accessor :display_name
12
+ attr_accessor :expiration_date
9
13
  attr_accessor :name
10
14
  attr_accessor :platform
11
15
  attr_accessor :serial_number
@@ -47,6 +51,26 @@ module Spaceship
47
51
  Time.parse(expiration_date) > Time.now
48
52
  end
49
53
 
54
+ # Create a new code signing request that can be used to
55
+ # generate a new certificate
56
+ # @example
57
+ # Create a new certificate signing request
58
+ # csr, pkey = Spaceship.certificate.create_certificate_signing_request
59
+ #
60
+ # # Use the signing request to create a new distribution certificate
61
+ # Spaceship.certificate.production.create!(csr: csr)
62
+ def self.create_certificate_signing_request
63
+ key = OpenSSL::PKey::RSA.new(2048)
64
+ csr = OpenSSL::X509::Request.new
65
+ csr.version = 0
66
+ csr.subject = OpenSSL::X509::Name.new([
67
+ ['CN', 'PEM', OpenSSL::ASN1::UTF8STRING]
68
+ ])
69
+ csr.public_key = key.public_key
70
+ csr.sign(key, OpenSSL::Digest::SHA1.new)
71
+ return [csr, key]
72
+ end
73
+
50
74
  #
51
75
  # API
52
76
  #
@@ -55,6 +79,24 @@ module Spaceship
55
79
  resps = Spaceship::ConnectAPI.get_certificates(filter: filter, includes: includes).all_pages
56
80
  return resps.flat_map(&:to_models)
57
81
  end
82
+
83
+ def self.create(certificate_type: nil, csr_content: nil)
84
+ attributes = {
85
+ certificateType: certificate_type,
86
+ csrContent: csr_content
87
+ }
88
+ resp = Spaceship::ConnectAPI.post_certificate(attributes: attributes)
89
+ return resp.to_models.first
90
+ end
91
+
92
+ def self.get(certificate_id: nil, includes: nil)
93
+ resp = Spaceship::ConnectAPI.get_certificate(certificate_id: certificate_id, includes: includes)
94
+ return resp.to_models.first
95
+ end
96
+
97
+ def delete!
98
+ Spaceship::ConnectAPI.delete_certificate(certificate_id: id)
99
+ end
58
100
  end
59
101
  end
60
102
  end
@@ -0,0 +1,43 @@
1
+ require_relative '../model'
2
+ module Spaceship
3
+ class ConnectAPI
4
+ class CustomAppOrganization
5
+ include Spaceship::ConnectAPI::Model
6
+
7
+ attr_accessor :device_enrollment_program_id
8
+ attr_accessor :name
9
+
10
+ attr_mapping({
11
+ "deviceEnrollmentProgramId" => "device_enrollment_program_id",
12
+ "name" => "name"
13
+ })
14
+
15
+ def self.type
16
+ return "customAppOrganizations"
17
+ end
18
+
19
+ #
20
+ # API
21
+ #
22
+
23
+ def self.all(app_id: nil, filter: {}, includes: nil, limit: nil, sort: nil)
24
+ resps = Spaceship::ConnectAPI.get_custom_app_organization(
25
+ app_id: app_id,
26
+ filter: filter,
27
+ includes: includes,
28
+ limit: nil,
29
+ sort: nil
30
+ ).all_pages
31
+ return resps.flat_map(&:to_models)
32
+ end
33
+
34
+ def self.create(app_id: nil, device_enrollment_program_id: nil, name: nil)
35
+ return Spaceship::ConnectAPI.post_custom_app_organization(app_id: app_id, device_enrollment_program_id: device_enrollment_program_id, name: name).first
36
+ end
37
+
38
+ def delete!
39
+ Spaceship::ConnectAPI.delete_custom_app_organization(custom_app_organization_id: id)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,41 @@
1
+ require_relative '../model'
2
+ module Spaceship
3
+ class ConnectAPI
4
+ class CustomAppUser
5
+ include Spaceship::ConnectAPI::Model
6
+
7
+ attr_accessor :apple_id
8
+
9
+ attr_mapping({
10
+ "appleId" => "apple_id"
11
+ })
12
+
13
+ def self.type
14
+ return "customAppUsers"
15
+ end
16
+
17
+ #
18
+ # API
19
+ #
20
+
21
+ def self.all(app_id: nil, filter: {}, includes: nil, limit: nil, sort: nil)
22
+ resps = Spaceship::ConnectAPI.get_custom_app_users(
23
+ app_id: app_id,
24
+ filter: filter,
25
+ includes: includes,
26
+ limit: nil,
27
+ sort: nil
28
+ ).all_pages
29
+ return resps.flat_map(&:to_models)
30
+ end
31
+
32
+ def self.create(app_id: nil, apple_id: nil)
33
+ return Spaceship::ConnectAPI.post_custom_app_user(app_id: app_id, apple_id: apple_id).first
34
+ end
35
+
36
+ def delete!
37
+ Spaceship::ConnectAPI.delete_custom_app_user(custom_app_user_id: id)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -48,6 +48,11 @@ module Spaceship
48
48
  resps = Spaceship::ConnectAPI.get_devices(filter: filter, includes: includes).all_pages
49
49
  return resps.flat_map(&:to_models)
50
50
  end
51
+
52
+ def self.create(name: nil, platform: nil, udid: nil)
53
+ resp = Spaceship::ConnectAPI.post_device(name: name, platform: platform, udid: udid)
54
+ return resp.to_models.first
55
+ end
51
56
  end
52
57
  end
53
58
  end
@@ -27,7 +27,8 @@ module Spaceship
27
27
  "expirationDate" => "expiration_date",
28
28
 
29
29
  "bundleId" => "bundle_id",
30
- "certificates" => "certificates"
30
+ "certificates" => "certificates",
31
+ "devices" => "devices"
31
32
  })
32
33
 
33
34
  module ProfileState
@@ -83,6 +84,11 @@ module Spaceship
83
84
  return resp.to_models.first
84
85
  end
85
86
 
87
+ def fetch_all_devices(filter: {}, includes: nil, sort: nil)
88
+ resps = Spaceship::ConnectAPI.get_devices(profile_id: id, filter: filter, includes: includes).all_pages
89
+ return resps.flat_map(&:to_models)
90
+ end
91
+
86
92
  def delete!
87
93
  return Spaceship::ConnectAPI.delete_profile(profile_id: id)
88
94
  end