spaceship 0.37.0 → 0.38.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.
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