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 +4 -4
- data/lib/spaceship/client.rb +19 -2
- data/lib/spaceship/du/du_client.rb +17 -5
- data/lib/spaceship/portal/certificate.rb +1 -1
- data/lib/spaceship/portal/device.rb +38 -9
- data/lib/spaceship/portal/portal_client.rb +22 -4
- data/lib/spaceship/tunes/app_version.rb +67 -12
- data/lib/spaceship/tunes/app_version_common.rb +5 -3
- data/lib/spaceship/tunes/application.rb +67 -24
- data/lib/spaceship/tunes/build_train.rb +13 -5
- data/lib/spaceship/tunes/tunes.rb +1 -0
- data/lib/spaceship/tunes/tunes_client.rb +32 -11
- data/lib/spaceship/tunes/version_set.rb +35 -0
- data/lib/spaceship/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9b4955b9e80e81c5533fe2af232a21da7e1574d
|
4
|
+
data.tar.gz: 8dee46b8cb98408df79cd57ef17e245ce545425c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8ad5bb425741a02cd3cb5981751825474791dc706d0ca3a46b3c3655079163b19d148696761ccaddf0f32e294d1f7f78c7c578aba89dd75425438e3c81ca424
|
7
|
+
data.tar.gz: 184f883e757dcaf0c0b39a8e8d577ef7eec8145d2b7ee94ffffe75d314d777532c0894214bcea1489ab42adcf78dc74e9d50b68522c639bd0371dea6994bfafb
|
data/lib/spaceship/client.rb
CHANGED
@@ -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
|
-
|
167
|
-
|
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
|
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
|
96
|
-
|
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)
|
@@ -22,7 +22,7 @@ module Spaceship
|
|
22
22
|
# "ios"
|
23
23
|
attr_accessor :platform
|
24
24
|
|
25
|
-
# @return (String) Status of the device.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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]
|
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.
|
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
|
-
|
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
|
-
|
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"
|
@@ -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
|
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
|
-
|
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:
|
593
|
-
|
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:
|
598
|
-
|
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
|
+
#
|
data/lib/spaceship/version.rb
CHANGED
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.
|
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-
|
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.
|
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
|