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 +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
|