spaceship 0.37.0 → 0.38.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5876ed2b557a73506b42f22b1845d8e532574b96
4
- data.tar.gz: 8b70dd155a884a368c2b55ea67b320674581928a
3
+ metadata.gz: c9b4955b9e80e81c5533fe2af232a21da7e1574d
4
+ data.tar.gz: 8dee46b8cb98408df79cd57ef17e245ce545425c
5
5
  SHA512:
6
- metadata.gz: 705f85a89b839339b2b7b32344f8abf0525416add39db3a7ba07faf7b8fa2ae33f6db1dc7df0e7f225dce468fe60afd7400bcc8cfd82a59129ea783319bb8f17
7
- data.tar.gz: 70d0bd2a25191aff18e84378fb0e300383c2a56fc9a1282f0286d8d5b868733677bfdf1790a02c6c6297f8c218a8d5816b7c1accfcc181c434c13e29cfde576a
6
+ metadata.gz: d8ad5bb425741a02cd3cb5981751825474791dc706d0ca3a46b3c3655079163b19d148696761ccaddf0f32e294d1f7f78c7c578aba89dd75425438e3c81ca424
7
+ data.tar.gz: 184f883e757dcaf0c0b39a8e8d577ef7eec8145d2b7ee94ffffe75d314d777532c0894214bcea1489ab42adcf78dc74e9d50b68522c639bd0371dea6994bfafb
@@ -155,6 +155,7 @@ module Spaceship
155
155
 
156
156
  def store_cookie(path: nil)
157
157
  path ||= persistent_cookie_path
158
+ FileUtils.mkdir_p(File.expand_path("..", path))
158
159
 
159
160
  # really important to specify the session to true
160
161
  # otherwise myacinfo and more won't be stored
@@ -162,9 +163,21 @@ module Spaceship
162
163
  return File.read(path)
163
164
  end
164
165
 
166
+ # Returns preferred path for storing cookie
167
+ # for two step verification.
165
168
  def persistent_cookie_path
166
- path = File.expand_path(File.join("~", ".spaceship", self.user, "cookie"))
167
- FileUtils.mkdir_p(File.expand_path("..", path))
169
+ if ENV["SPACESHIP_COOKIE_PATH"]
170
+ path = File.expand_path(File.join(ENV["SPACESHIP_COOKIE_PATH"], "spaceship", self.user, "cookie"))
171
+ else
172
+ ["~/.spaceship", "/var/tmp/spaceship", "#{Dir.tmpdir}/spaceship"].each do |dir|
173
+ dir_parts = File.split(dir)
174
+ if directory_accessible?(dir_parts.first)
175
+ path = File.expand_path(File.join(dir, self.user, "cookie"))
176
+ break
177
+ end
178
+ end
179
+ end
180
+
168
181
  return path
169
182
  end
170
183
 
@@ -406,6 +419,10 @@ module Spaceship
406
419
 
407
420
  private
408
421
 
422
+ def directory_accessible?(path)
423
+ Dir.exist?(File.expand_path(path))
424
+ end
425
+
409
426
  def do_login(user, password)
410
427
  @loggedin = false
411
428
  ret = send_login_request(user, password) # different in subclasses
@@ -14,8 +14,8 @@ module Spaceship
14
14
  # @!group Images
15
15
  #####################################################
16
16
 
17
- def upload_screenshot(app_version, upload_file, content_provider_id, sso_token_for_image, device)
18
- upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, screenshot_picture_type(device))
17
+ def upload_screenshot(app_version, upload_file, content_provider_id, sso_token_for_image, device, is_messages)
18
+ upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, screenshot_picture_type(device, is_messages))
19
19
  end
20
20
 
21
21
  def upload_large_icon(app_version, upload_file, content_provider_id, sso_token_for_image)
@@ -90,10 +90,22 @@ module Spaceship
90
90
  }
91
91
  end
92
92
 
93
- def screenshot_picture_type(device)
93
+ def messages_picture_type_map
94
+ # rubocop:enable Style/ExtraSpacing
95
+ {
96
+ ipad: "MZPFT.SortedTabletMessagesScreenShot",
97
+ ipadPro: "MZPFT.SortedJ99MessagesScreenShot",
98
+ iphone6: "MZPFT.SortedN61MessagesScreenShot",
99
+ iphone6Plus: "MZPFT.SortedN56MessagesScreenShot",
100
+ iphone4: "MZPFT.SortedN41MessagesScreenShot"
101
+ }
102
+ end
103
+
104
+ def screenshot_picture_type(device, is_messages)
105
+ map = is_messages ? messages_picture_type_map : picture_type_map
94
106
  device = device.to_sym
95
- raise "Unknown picture type for device: #{device}" unless picture_type_map.key? device
96
- picture_type_map[device]
107
+ raise "Unknown picture type for device: #{device}" unless map.key? device
108
+ map[device]
97
109
  end
98
110
 
99
111
  def parse_upload_response(response)
@@ -151,7 +151,7 @@ module Spaceship
151
151
  "UPV3DW712I" => ProductionPush,
152
152
  "Y3B2F3TYSI" => Passbook,
153
153
  "3T2ZP62QW8" => WebsitePush,
154
- "E5D663CMZW" => WebsitePush,
154
+ "E5D663CMZW" => VoipPush,
155
155
  "4APLUP237T" => ApplePay
156
156
  }
157
157
 
@@ -22,7 +22,7 @@ module Spaceship
22
22
  # "ios"
23
23
  attr_accessor :platform
24
24
 
25
- # @return (String) Status of the device. Probably always "c"
25
+ # @return (String) Status of the device. "c" for enabled devices, "r" for disabled devices.
26
26
  # @example
27
27
  # "c"
28
28
  attr_accessor :status
@@ -59,9 +59,10 @@ module Spaceship
59
59
  end
60
60
 
61
61
  # @param mac [Bool] Fetches Mac devices if true
62
+ # @param include_disabled [Bool] Whether to include disable devices. false by default.
62
63
  # @return (Array) Returns all devices registered for this account
63
- def all(mac: false)
64
- client.devices(mac: mac).map { |device| self.factory(device) }
64
+ def all(mac: false, include_disabled: false)
65
+ client.devices(mac: mac, include_disabled: include_disabled).map { |device| self.factory(device) }
65
66
  end
66
67
 
67
68
  # @return (Array) Returns all Apple TVs registered for this account
@@ -109,26 +110,29 @@ module Spaceship
109
110
  end
110
111
 
111
112
  # @param mac [Bool] Searches for Macs if true
113
+ # @param include_disabled [Bool] Whether to include disable devices. false by default.
112
114
  # @return (Device) Find a device based on the ID of the device. *Attention*:
113
115
  # This is *not* the UDID. nil if no device was found.
114
- def find(device_id, mac: false)
115
- all(mac: mac).find do |device|
116
+ def find(device_id, mac: false, include_disabled: false)
117
+ all(mac: mac, include_disabled: include_disabled).find do |device|
116
118
  device.id == device_id
117
119
  end
118
120
  end
119
121
 
120
122
  # @param mac [Bool] Searches for Macs if true
123
+ # @param include_disabled [Bool] Whether to include disable devices. false by default.
121
124
  # @return (Device) Find a device based on the UDID of the device. nil if no device was found.
122
- def find_by_udid(device_udid, mac: false)
123
- all(mac: mac).find do |device|
125
+ def find_by_udid(device_udid, mac: false, include_disabled: false)
126
+ all(mac: mac, include_disabled: include_disabled).find do |device|
124
127
  device.udid.casecmp(device_udid) == 0
125
128
  end
126
129
  end
127
130
 
128
131
  # @param mac [Bool] Searches for Macs if true
132
+ # @param include_disabled [Bool] Whether to include disable devices. false by default.
129
133
  # @return (Device) Find a device based on its name. nil if no device was found.
130
- def find_by_name(device_name, mac: false)
131
- all(mac: mac).find do |device|
134
+ def find_by_name(device_name, mac: false, include_disabled: false)
135
+ all(mac: mac, include_disabled: include_disabled).find do |device|
132
136
  device.name == device_name
133
137
  end
134
138
  end
@@ -158,6 +162,31 @@ module Spaceship
158
162
  self.new(device)
159
163
  end
160
164
  end
165
+
166
+ def enabled?
167
+ return self.status == "c"
168
+ end
169
+
170
+ def disabled?
171
+ return self.status == "r"
172
+ end
173
+
174
+ # Enable current device.
175
+ def enable!
176
+ unless enabled?
177
+ attr = client.enable_device!(self.id, self.udid, mac: self.platform == 'mac')
178
+ initialize(attr)
179
+ end
180
+ end
181
+
182
+ # Disable current device. This will invalidate all provisioning profiles that use this device.
183
+ def disable!
184
+ if enabled?
185
+ client.disable_device!(self.id, self.udid, mac: self.platform == 'mac')
186
+ # disable request doesn't return device json, so we assume that the new status is "r" if response succeeded
187
+ self.status = "r"
188
+ end
189
+ end
161
190
  end
162
191
  end
163
192
  end
@@ -216,26 +216,28 @@ module Spaceship
216
216
  # @!group Devices
217
217
  #####################################################
218
218
 
219
- def devices(mac: false)
219
+ def devices(mac: false, include_disabled: false)
220
220
  paging do |page_number|
221
221
  r = request(:post, "account/#{platform_slug(mac)}/device/listDevices.action", {
222
222
  teamId: team_id,
223
223
  pageNumber: page_number,
224
224
  pageSize: page_size,
225
- sort: 'name=asc'
225
+ sort: 'name=asc',
226
+ includeRemovedDevices: include_disabled
226
227
  })
227
228
  parse_response(r, 'devices')
228
229
  end
229
230
  end
230
231
 
231
- def devices_by_class(device_class)
232
+ def devices_by_class(device_class, include_disabled: false)
232
233
  paging do |page_number|
233
234
  r = request(:post, 'account/ios/device/listDevices.action', {
234
235
  teamId: team_id,
235
236
  pageNumber: page_number,
236
237
  pageSize: page_size,
237
238
  sort: 'name=asc',
238
- deviceClasses: device_class
239
+ deviceClasses: device_class,
240
+ includeRemovedDevices: include_disabled
239
241
  })
240
242
  parse_response(r, 'devices')
241
243
  end
@@ -256,6 +258,22 @@ module Spaceship
256
258
  parse_response(req, 'device')
257
259
  end
258
260
 
261
+ def disable_device!(device_id, device_udid, mac: false)
262
+ request(:post, "https://developer.apple.com/services-account/#{PROTOCOL_VERSION}/account/#{platform_slug(mac)}/device/deleteDevice.action", {
263
+ teamId: team_id,
264
+ deviceId: device_id
265
+ })
266
+ end
267
+
268
+ def enable_device!(device_id, device_udid, mac: false)
269
+ req = request(:post, "https://developer.apple.com/services-account/#{PROTOCOL_VERSION}/account/#{platform_slug(mac)}/device/enableDevice.action", {
270
+ teamId: team_id,
271
+ displayId: device_id,
272
+ deviceNumber: device_udid
273
+ })
274
+ parse_response(req, 'device')
275
+ end
276
+
259
277
  #####################################################
260
278
  # @!group Certificates
261
279
  #####################################################
@@ -168,14 +168,13 @@ module Spaceship
168
168
  # @param application (Spaceship::Tunes::Application) The app this version is for
169
169
  # @param app_id (String) The unique Apple ID of this app
170
170
  # @param is_live (Boolean)
171
- def find(application, app_id, is_live)
171
+ def find(application, app_id, is_live, platform: nil)
172
172
  # we only support applications
173
- platform = Spaceship::Tunes::AppVersionCommon.find_platform(application.raw_data['versionSets'])
174
- raise "We do not support BUNDLE types right now" if platform['type'] == 'BUNDLE'
173
+ raise "We do not support BUNDLE types right now" if application.type == 'BUNDLE'
175
174
 
176
175
  # too bad the "id" field is empty, it forces us to make more requests to the server
177
176
  # these could also be cached
178
- attrs = client.app_version(app_id, is_live)
177
+ attrs = client.app_version(app_id, is_live, platform: platform)
179
178
  return nil unless attrs
180
179
 
181
180
  attrs[:application] = application
@@ -380,16 +379,17 @@ module Spaceship
380
379
  # @param sort_order (Fixnum): The sort_order, from 1 to 5
381
380
  # @param language (String): The language for this screenshot
382
381
  # @param device (string): The device for this screenshot
383
- def upload_screenshot!(screenshot_path, sort_order, language, device)
382
+ # @param is_messages (Bool): True if the screenshot is for iMessage
383
+ def upload_screenshot!(screenshot_path, sort_order, language, device, is_messages)
384
384
  raise "sort_order must be higher than 0" unless sort_order > 0
385
385
  raise "sort_order must not be > 5" if sort_order > 5
386
386
  # this will also check both language and device parameters
387
- device_lang_screenshots = screenshots_data_for_language_and_device(language, device)["value"]
387
+ device_lang_screenshots = screenshots_data_for_language_and_device(language, device, is_messages)["value"]
388
388
 
389
389
  existing_sort_orders = device_lang_screenshots.map { |s| s["value"]["sortOrder"] }
390
390
  if screenshot_path # adding / replacing
391
391
  upload_file = UploadFile.from_path screenshot_path
392
- screenshot_data = client.upload_screenshot(self, upload_file, device)
392
+ screenshot_data = client.upload_screenshot(self, upload_file, device, is_messages)
393
393
 
394
394
  # Since October 2016 we also need to pass the size, height, width and checksum
395
395
  # otherwise iTunes Connect validation will fail at a later point
@@ -411,7 +411,8 @@ module Spaceship
411
411
  # if this value is not set, iTC will fallback to another device type for screenshots
412
412
  language_details = raw_data_details.find { |d| d["language"] == language }["displayFamilies"]["value"]
413
413
  device_language_details = language_details.find { |display_family| display_family['name'] == device }
414
- device_language_details["scaled"]["value"] = false
414
+ scaled_key = is_messages ? "messagesScaled" : "scaled"
415
+ device_language_details[scaled_key]["value"] = false
415
416
 
416
417
  if existing_sort_orders.include?(sort_order) # replace
417
418
  device_lang_screenshots[existing_sort_orders.index(sort_order)] = new_screenshot
@@ -447,7 +448,7 @@ module Spaceship
447
448
  def upload_trailer!(trailer_path, language, device, timestamp = "05.00", preview_image_path = nil)
448
449
  raise "No app trailer supported for iphone35" if device == 'iphone35'
449
450
 
450
- device_lang_trailer = trailer_data_for_language_and_device(language, device)
451
+ device_lang_trailer = trailer_data_for_language_and_device(language, device, is_messages)
451
452
  if trailer_path # adding / replacing trailer / replacing preview
452
453
  raise "Invalid timestamp #{timestamp}" if (timestamp =~ /^[0-9][0-9].[0-9][0-9]$/).nil?
453
454
 
@@ -554,8 +555,9 @@ module Spaceship
554
555
  @transit_app_file = Tunes::TransitAppFile.factory(transit_app_file) if transit_app_file
555
556
  end
556
557
 
557
- def screenshots_data_for_language_and_device(language, device)
558
- container_data_for_language_and_device("screenshots", language, device)
558
+ def screenshots_data_for_language_and_device(language, device, is_messages)
559
+ data_field = is_messages ? "messagesScreenshots" : "screenshots"
560
+ container_data_for_language_and_device(data_field, language, device)
559
561
  end
560
562
 
561
563
  def trailer_data_for_language_and_device(language, device)
@@ -582,7 +584,7 @@ module Spaceship
582
584
 
583
585
  raw_data_details.each do |row|
584
586
  # Now that's one language right here
585
- @screenshots[row['language']] = setup_screenshots_for(row)
587
+ @screenshots[row['language']] = setup_screenshots_for(row) + setup_messages_screenshots_for(row)
586
588
  end
587
589
  end
588
590
 
@@ -626,6 +628,34 @@ module Spaceship
626
628
  # "isRequired": false,
627
629
  # "errorKeys": null
628
630
  # }],
631
+ # "messagesScaled": {
632
+ # "value": false,
633
+ # "isEditable": false,
634
+ # "isRequired": false,
635
+ # "errorKeys": null
636
+ # },
637
+ # "messagesScreenshots": {
638
+ # "value": [{
639
+ # "value": {
640
+ # "assetToken": "Purple62/v4/08/0a/04/080a0430-c2cc-2577-f491-9e0a09c58ffe/mzl.pbcpzqyg.jpg",
641
+ # "sortOrder": 1,
642
+ # "type": null,
643
+ # "originalFileName": "ios-414-1.jpg"
644
+ # },
645
+ # "isEditable": true,
646
+ # "isRequired": false,
647
+ # "errorKeys": null
648
+ # }, {
649
+ # "value": {
650
+ # "assetToken": "Purple71/v4/de/81/aa/de81aa10-64f6-332e-c974-9ee46adab675/mzl.cshkjvwl.jpg",
651
+ # "sortOrder": 2,
652
+ # "type": null,
653
+ # "originalFileName": "ios-414-2.jpg"
654
+ # },
655
+ # "isEditable": true,
656
+ # "isRequired": false,
657
+ # "errorKeys": null
658
+ # }],
629
659
  # "isEditable": true,
630
660
  # "isRequired": false,
631
661
  # "errorKeys": null
@@ -651,6 +681,31 @@ module Spaceship
651
681
  return result
652
682
  end
653
683
 
684
+ # generates the nested data structure to represent screenshots
685
+ def setup_messages_screenshots_for(row)
686
+ return [] if row.nil? || row["displayFamilies"].nil?
687
+
688
+ display_families = row.fetch("displayFamilies", {}).fetch("value", nil)
689
+ return [] unless display_families
690
+
691
+ result = []
692
+
693
+ display_families.each do |display_family|
694
+ display_family_screenshots = display_family.fetch("messagesScreenshots", {})
695
+ next unless display_family_screenshots
696
+ display_family_screenshots.fetch("value", []).each do |screenshot|
697
+ screenshot_data = screenshot["value"]
698
+ data = {
699
+ device_type: display_family['name'],
700
+ language: row["language"]
701
+ }.merge(screenshot_data)
702
+ result << Tunes::AppScreenshot.factory(data)
703
+ end
704
+ end
705
+
706
+ return result
707
+ end
708
+
654
709
  def setup_trailers
655
710
  @trailers = {}
656
711
  raw_data_details.each do |row|
@@ -10,18 +10,20 @@ module Spaceship
10
10
  version['id']
11
11
  end
12
12
 
13
- def find_platform(versions)
13
+ def find_platform(versions, search_platform: nil)
14
14
  # We only support platforms that exist ATM
15
15
  platform = versions.detect do |p|
16
16
  ['ios', 'osx', 'appletvos'].include? p['platformString']
17
17
  end
18
18
 
19
- raise "Could not find platform ios, osx or appletvos for app #{app_id}" unless platform
19
+ raise "Could not find platform 'ios', 'osx' or 'appletvos'" unless platform
20
20
 
21
21
  # If your app has versions for both iOS and tvOS we will default to returning the iOS version for now.
22
22
  # This is intentional as we need to do more work to support apps that have hybrid versions.
23
- if versions.length > 1
23
+ if versions.length > 1 && search_platform.nil?
24
24
  platform = versions.detect { |p| p['platformString'] == "ios" }
25
+ elsif !search_platform.nil?
26
+ platform = versions.detect { |p| p['platformString'] == search_platform }
25
27
  end
26
28
  platform
27
29
  end
@@ -34,6 +34,9 @@ module Spaceship
34
34
  # nil
35
35
  attr_accessor :app_icon_preview_url
36
36
 
37
+ # @return (Array) An array of all versions sets
38
+ attr_accessor :version_sets
39
+
37
40
  attr_mapping(
38
41
  'adamId' => :apple_id,
39
42
  'name' => :name,
@@ -91,21 +94,28 @@ module Spaceship
91
94
  # @!group Getting information
92
95
  #####################################################
93
96
 
97
+ def version_set_for_platform(platform)
98
+ version_sets.each do |version_set|
99
+ return version_set if version_set.platform == platform
100
+ end
101
+ nil
102
+ end
103
+
94
104
  # @return (Spaceship::AppVersion) Receive the version that is currently live on the
95
105
  # App Store. You can't modify all values there, so be careful.
96
- def live_version
97
- Spaceship::AppVersion.find(self, self.apple_id, true)
106
+ def live_version(platform: nil)
107
+ Spaceship::AppVersion.find(self, self.apple_id, true, platform: platform)
98
108
  end
99
109
 
100
110
  # @return (Spaceship::AppVersion) Receive the version that can fully be edited
101
- def edit_version
102
- Spaceship::AppVersion.find(self, self.apple_id, false)
111
+ def edit_version(platform: nil)
112
+ Spaceship::AppVersion.find(self, self.apple_id, false, platform: platform)
103
113
  end
104
114
 
105
115
  # @return (Spaceship::AppVersion) This will return the `edit_version` if available
106
116
  # and fallback to the `live_version`. Use this to just access the latest data
107
- def latest_version
108
- edit_version || live_version
117
+ def latest_version(platform: nil)
118
+ edit_version(platform: platform) || live_version(platform: platform)
109
119
  end
110
120
 
111
121
  # @return (String) An URL to this specific resource. You can enter this URL into your browser
@@ -126,11 +136,40 @@ module Spaceship
126
136
  Tunes::AppRatings.factory(attrs)
127
137
  end
128
138
 
139
+ def platforms
140
+ platforms = []
141
+ version_sets.each do |version_set|
142
+ platforms << version_set.platform
143
+ end
144
+ platforms
145
+ end
146
+
147
+ def type
148
+ if self.version_sets.nil?
149
+ raise 'The application has no version sets and Spaceship does not know what to do here.'
150
+ end
151
+
152
+ if self.version_sets.length == 1
153
+ version_sets[0].platform
154
+ end
155
+ platform = Spaceship::Tunes::AppVersionCommon.find_platform(raw_data['versionSets'])
156
+ platform['type']
157
+ end
158
+
129
159
  # kept for backward compatibility
130
160
  # tries to guess the platform of the currently submitted apps
131
161
  # note that as ITC now supports multiple app types, this might break
132
162
  # if your app supports more than one
133
163
  def platform
164
+ if self.version_sets.nil?
165
+ raise 'The application has no version sets and Spaceship does not know what to do here.'
166
+ end
167
+
168
+ if self.version_sets.length == 1
169
+ version_sets[0].platform
170
+ elsif self.platforms == %w(ios appletvos)
171
+ 'ios'
172
+ end
134
173
  Spaceship::Tunes::AppVersionCommon.find_platform(raw_data['versionSets'])['platformString']
135
174
  end
136
175
 
@@ -156,12 +195,12 @@ module Spaceship
156
195
  # Create a new version of your app
157
196
  # Since we have stored the outdated raw_data, we need to refresh this object
158
197
  # otherwise `edit_version` will return nil
159
- def create_version!(version_number)
160
- if edit_version
198
+ def create_version!(version_number, platform: nil)
199
+ if edit_version(platform: platform)
161
200
  raise "Cannot create a new version for this app as there already is an `edit_version` available"
162
201
  end
163
202
 
164
- client.create_version!(apple_id, version_number)
203
+ client.create_version!(apple_id, version_number, platform.nil? ? 'ios' : platform)
165
204
 
166
205
  # Future: implemented -reload method
167
206
  end
@@ -170,8 +209,8 @@ module Spaceship
170
209
  # This will either create a new version or change the version number
171
210
  # from an existing version
172
211
  # @return (Bool) Was something changed?
173
- def ensure_version!(version_number)
174
- if (e = edit_version)
212
+ def ensure_version!(version_number, platform: nil)
213
+ if (e = edit_version(platform: platform))
175
214
  if e.version.to_s != version_number.to_s
176
215
  # Update an existing version
177
216
  e.version = version_number
@@ -180,7 +219,7 @@ module Spaceship
180
219
  end
181
220
  return false
182
221
  else
183
- create_version!(version_number)
222
+ create_version!(version_number, platform: platform)
184
223
  return true
185
224
  end
186
225
  end
@@ -200,9 +239,9 @@ module Spaceship
200
239
  #####################################################
201
240
 
202
241
  # TestFlight: A reference to all the build trains
203
- # @return [Hash] a hash, the version number being the key
204
- def build_trains
205
- Tunes::BuildTrain.all(self, self.apple_id)
242
+ # @return [Hash] a hash, the version number and platform being the key
243
+ def build_trains(platform: nil)
244
+ Tunes::BuildTrain.all(self, self.apple_id, platform: platform)
206
245
  end
207
246
 
208
247
  # The numbers of all build trains that were uploaded
@@ -224,11 +263,11 @@ module Spaceship
224
263
  end
225
264
  end
226
265
 
227
- # @return [Array] A list of all builds in an invalid state
228
- def all_invalid_builds
266
+ # @return [Array]A list of binaries which are in the invalid state
267
+ def all_invalid_builds(platform: nil)
229
268
  builds = []
230
269
 
231
- self.build_trains.values.each do |train|
270
+ self.build_trains(platform: platform).values.each do |train|
232
271
  builds.concat(train.invalid_builds)
233
272
  end
234
273
 
@@ -237,10 +276,10 @@ module Spaceship
237
276
 
238
277
  # @return [Array] This will return an array of *all* processing builds
239
278
  # this include pre-processing or standard processing
240
- def all_processing_builds
279
+ def all_processing_builds(platform: nil)
241
280
  builds = []
242
281
 
243
- self.build_trains.values.each do |train|
282
+ self.build_trains(platform: platform).each do |version_number, train|
244
283
  builds.concat(train.processing_builds)
245
284
  end
246
285
 
@@ -249,9 +288,9 @@ module Spaceship
249
288
 
250
289
  # Get all builds that are already processed for all build trains
251
290
  # You can either use the return value (array) or pass a block
252
- def builds
291
+ def builds(platform: nil)
253
292
  all_builds = []
254
- self.build_trains.each do |version_number, train|
293
+ self.build_trains(platform: platform).each do |version_number, train|
255
294
  train.builds.each do |build|
256
295
  yield(build) if block_given?
257
296
  all_builds << build unless block_given?
@@ -301,6 +340,11 @@ module Spaceship
301
340
  # @!group General
302
341
  #####################################################
303
342
  def setup
343
+ super
344
+ @version_sets = (self.raw_data['versionSets'] || []).map do |attrs|
345
+ attrs[:application] = self
346
+ Tunes::VersionSet.factory(attrs)
347
+ end
304
348
  end
305
349
 
306
350
  #####################################################
@@ -381,8 +425,7 @@ module Spaceship
381
425
  # private to module
382
426
  def ensure_not_a_bundle
383
427
  # we only support applications
384
- platform = Spaceship::Tunes::AppVersionCommon.find_platform(raw_data['versionSets'])
385
- raise "We do not support BUNDLE types right now" if platform['type'] == 'BUNDLE'
428
+ raise "We do not support BUNDLE types right now" if self.type == 'BUNDLE'
386
429
  end
387
430
  end
388
431
  end
@@ -6,6 +6,10 @@ module Spaceship
6
6
  # @return (Spaceship::Tunes::Application) A reference to the application this train is for
7
7
  attr_accessor :application
8
8
 
9
+ # @return (Spaceship::Tunes::VersionSet) A reference to the version set
10
+ # this train is for
11
+ attr_accessor :version_set
12
+
9
13
  # @return (Array) An array of all builds that are inside this train (Spaceship::Tunes::Build)
10
14
  attr_reader :builds
11
15
 
@@ -45,16 +49,18 @@ module Spaceship
45
49
 
46
50
  # @param application (Spaceship::Tunes::Application) The app this train is for
47
51
  # @param app_id (String) The unique Apple ID of this app
48
- def all(application, app_id)
52
+ def all(application, app_id, platform: nil)
49
53
  trains = []
50
- trains += client.build_trains(app_id, 'internal')['trains']
51
- trains += client.build_trains(app_id, 'external')['trains']
54
+ trains += client.build_trains(app_id, 'internal', platform: platform)['trains']
55
+ trains += client.build_trains(app_id, 'external', platform: platform)['trains']
52
56
 
53
57
  result = {}
54
58
  trains.each do |attrs|
55
59
  attrs[:application] = application
56
60
  current = self.factory(attrs)
57
- result[current.version_string] = current
61
+ if (!platform.nil? && current.platform == platform) || platform.nil?
62
+ result[current.version_string] = current
63
+ end
58
64
  end
59
65
  result
60
66
  end
@@ -101,6 +107,8 @@ module Spaceship
101
107
  @processing_builds << build
102
108
  end
103
109
  end
110
+
111
+ self.version_set = self.application.version_set_for_platform(self.platform)
104
112
  end
105
113
 
106
114
  # @return (Spaceship::Tunes::Build) The latest build for this train, sorted by upload time.
@@ -110,7 +118,7 @@ module Spaceship
110
118
 
111
119
  # @param (testing_type) internal or external
112
120
  def update_testing_status!(new_value, testing_type, build = nil)
113
- data = client.build_trains(self.application.apple_id, testing_type)
121
+ data = client.build_trains(self.application.apple_id, testing_type, platform: self.application.platform)
114
122
 
115
123
  build ||= latest_build if testing_type == 'external'
116
124
  testing_key = "#{testing_type}Testing"
@@ -1,5 +1,6 @@
1
1
  require 'spaceship/tunes/tunes_base'
2
2
  require 'spaceship/tunes/application'
3
+ require 'spaceship/tunes/version_set'
3
4
  require 'spaceship/tunes/app_version'
4
5
  require 'spaceship/tunes/app_version_common'
5
6
  require 'spaceship/tunes/app_submission'
@@ -129,6 +129,7 @@ module Spaceship
129
129
  loop do
130
130
  puts "Multiple iTunes Connect teams found, please enter the number of the team you want to use: "
131
131
  puts "Note: to automatically choose the team, provide either the iTunes Connect Team ID, or the Team Name in your fastlane/Appfile:"
132
+ puts "Alternatively you can pass the team name or team ID using the `FASTLANE_ITC_TEAM_ID` or `FASTLANE_ITC_TEAM_NAME` environment variable"
132
133
  first_team = teams.first["contentProvider"]
133
134
  puts ""
134
135
  puts " itc_team_id \"#{first_team['contentProviderId']}\""
@@ -265,6 +266,7 @@ module Spaceship
265
266
  # can't be changed after you submit your first build.
266
267
  def create_application!(name: nil, primary_language: nil, version: nil, sku: nil, bundle_id: nil, bundle_id_suffix: nil, company_name: nil)
267
268
  # First, we need to fetch the data from Apple, which we then modify with the user's values
269
+ primary_language ||= "English"
268
270
  app_type = 'ios'
269
271
  r = request(:get, "ra/apps/create/v2/?platformString=#{app_type}")
270
272
  data = parse_response(r, 'data')
@@ -274,7 +276,8 @@ module Spaceship
274
276
  data['versionString'] = { value: version }
275
277
  data['name'] = { value: name }
276
278
  data['bundleId'] = { value: bundle_id }
277
- data['primaryLanguage'] = { value: primary_language || 'English' }
279
+ data['primaryLanguage'] = { value: primary_language }
280
+ data['primaryLocaleCode'] = { value: primary_language.to_language_code }
278
281
  data['vendorId'] = { value: sku }
279
282
  data['bundleIdSuffix'] = { value: bundle_id_suffix }
280
283
  data['companyName'] = { value: company_name } if company_name
@@ -328,14 +331,14 @@ module Spaceship
328
331
  # @!group AppVersions
329
332
  #####################################################
330
333
 
331
- def app_version(app_id, is_live)
334
+ def app_version(app_id, is_live, platform: nil)
332
335
  raise "app_id is required" unless app_id
333
336
 
334
337
  # First we need to fetch the IDs for the edit / live version
335
338
  r = request(:get, "ra/apps/#{app_id}/overview")
336
339
  platforms = parse_response(r, 'data')['platforms']
337
340
 
338
- platform = Spaceship::Tunes::AppVersionCommon.find_platform(platforms)
341
+ platform = Spaceship::Tunes::AppVersionCommon.find_platform(platforms, search_platform: platform)
339
342
  return nil unless platform
340
343
 
341
344
  version_id = Spaceship::Tunes::AppVersionCommon.find_version_id(platform, is_live)
@@ -484,13 +487,27 @@ module Spaceship
484
487
  # @param app_version (AppVersion): The version of your app
485
488
  # @param upload_image (UploadFile): The image to upload
486
489
  # @param device (string): The target device
490
+ # @param is_messages (Bool): True if the screenshot is for iMessage
487
491
  # @return [JSON] the response
488
- def upload_screenshot(app_version, upload_image, device)
492
+ def upload_screenshot(app_version, upload_image, device, is_messages)
489
493
  raise "app_version is required" unless app_version
490
494
  raise "upload_image is required" unless upload_image
491
495
  raise "device is required" unless device
492
496
 
493
- du_client.upload_screenshot(app_version, upload_image, content_provider_id, sso_token_for_image, device)
497
+ du_client.upload_screenshot(app_version, upload_image, content_provider_id, sso_token_for_image, device, is_messages)
498
+ end
499
+
500
+ # Uploads an iMessage screenshot
501
+ # @param app_version (AppVersion): The version of your app
502
+ # @param upload_image (UploadFile): The image to upload
503
+ # @param device (string): The target device
504
+ # @return [JSON] the response
505
+ def upload_messages_screenshot(app_version, upload_image, device)
506
+ raise "app_version is required" unless app_version
507
+ raise "upload_image is required" unless upload_image
508
+ raise "device is required" unless device
509
+
510
+ du_client.upload_messages_screenshot(app_version, upload_image, content_provider_id, sso_token_for_image, device)
494
511
  end
495
512
 
496
513
  # Uploads the transit app file
@@ -558,9 +575,11 @@ module Spaceship
558
575
  #####################################################
559
576
 
560
577
  # @param (testing_type) internal or external
561
- def build_trains(app_id, testing_type)
578
+ def build_trains(app_id, testing_type, platform: nil)
562
579
  raise "app_id is required" unless app_id
563
- r = request(:get, "ra/apps/#{app_id}/trains/?testingType=#{testing_type}")
580
+ url = "ra/apps/#{app_id}/trains/?testingType=#{testing_type}"
581
+ url += "&platform=#{platform}" unless platform.nil?
582
+ r = request(:get, url)
564
583
  parse_response(r, 'data')
565
584
  end
566
585
 
@@ -589,13 +608,15 @@ module Spaceship
589
608
  end
590
609
 
591
610
  # All build trains, even if there is no TestFlight
592
- def all_build_trains(app_id: nil, platform: nil)
593
- r = request(:get, "ra/apps/#{app_id}/buildHistory?platform=#{platform || 'ios'}")
611
+ def all_build_trains(app_id: nil, platform: 'ios')
612
+ platform = 'ios' if platform.nil?
613
+ r = request(:get, "ra/apps/#{app_id}/buildHistory?platform=#{platform}")
594
614
  handle_itc_response(r.body)
595
615
  end
596
616
 
597
- def all_builds_for_train(app_id: nil, train: nil, platform: nil)
598
- r = request(:get, "ra/apps/#{app_id}/trains/#{train}/buildHistory?platform=#{platform || 'ios'}")
617
+ def all_builds_for_train(app_id: nil, train: nil, platform: 'ios')
618
+ platform = 'ios' if platform.nil?
619
+ r = request(:get, "ra/apps/#{app_id}/trains/#{train}/buildHistory?platform=#{platform}")
599
620
  handle_itc_response(r.body)
600
621
  end
601
622
 
@@ -0,0 +1,35 @@
1
+ module Spaceship
2
+ module Tunes
3
+ # Represents a version set inside of an application
4
+ class VersionSet < TunesBase
5
+ #####################################################
6
+ # @!group General metadata
7
+ #####################################################
8
+
9
+ # @return (String) The type of the version set. So far only APP
10
+ attr_accessor :type
11
+
12
+ # @return (Spaceship::Tunes::Application) A reference to the application the version_set is contained in
13
+ attr_accessor :application
14
+
15
+ # @return (String)
16
+ attr_accessor :platform
17
+
18
+ attr_mapping(
19
+ 'type' => :type,
20
+ 'platformString' => :platform
21
+ )
22
+
23
+ class << self
24
+ # Create a new object based on a hash.
25
+ # This is used to create a new object based on the server response.
26
+ def factory(attrs)
27
+ self.new(attrs)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ #
35
+ #
@@ -1,4 +1,4 @@
1
1
  module Spaceship
2
- VERSION = "0.37.0".freeze
2
+ VERSION = "0.38.0".freeze
3
3
  DESCRIPTION = "Ruby library to access the Apple Dev Center and iTunes Connect".freeze
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spaceship
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.0
4
+ version: 0.38.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felix Krause
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-11-03 00:00:00.000000000 Z
12
+ date: 2016-11-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: credentials_manager
@@ -377,6 +377,7 @@ files:
377
377
  - lib/spaceship/tunes/tunes_base.rb
378
378
  - lib/spaceship/tunes/tunes_client.rb
379
379
  - lib/spaceship/tunes/user_detail.rb
380
+ - lib/spaceship/tunes/version_set.rb
380
381
  - lib/spaceship/two_step_client.rb
381
382
  - lib/spaceship/ui.rb
382
383
  - lib/spaceship/update_checker.rb
@@ -401,7 +402,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
401
402
  version: '0'
402
403
  requirements: []
403
404
  rubyforge_project:
404
- rubygems_version: 2.5.1
405
+ rubygems_version: 2.6.7
405
406
  signing_key:
406
407
  specification_version: 4
407
408
  summary: Ruby library to access the Apple Dev Center and iTunes Connect