spaceship 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -15
- data/lib/spaceship.rb +2 -1
- data/lib/spaceship/base.rb +0 -1
- data/lib/spaceship/client.rb +71 -69
- data/lib/spaceship/helper/net_http_generic_request.rb +1 -1
- data/lib/spaceship/launcher.rb +19 -14
- data/lib/spaceship/portal/app.rb +23 -9
- data/lib/spaceship/portal/app_group.rb +77 -0
- data/lib/spaceship/portal/app_service.rb +222 -0
- data/lib/spaceship/portal/certificate.rb +2 -2
- data/lib/spaceship/portal/device.rb +7 -7
- data/lib/spaceship/portal/portal.rb +3 -1
- data/lib/spaceship/portal/portal_base.rb +1 -1
- data/lib/spaceship/portal/portal_client.rb +64 -10
- data/lib/spaceship/portal/provisioning_profile.rb +28 -54
- data/lib/spaceship/portal/spaceship.rb +27 -9
- data/lib/spaceship/portal/ui/select_team.rb +6 -8
- data/lib/spaceship/tunes/app_screenshot.rb +1 -1
- data/lib/spaceship/tunes/app_status.rb +5 -6
- data/lib/spaceship/tunes/app_submission.rb +24 -23
- data/lib/spaceship/tunes/app_version.rb +27 -34
- data/lib/spaceship/tunes/application.rb +24 -25
- data/lib/spaceship/tunes/build.rb +6 -7
- data/lib/spaceship/tunes/build_train.rb +2 -2
- data/lib/spaceship/tunes/language_converter.rb +14 -13
- data/lib/spaceship/tunes/language_item.rb +1 -1
- data/lib/spaceship/tunes/processing_build.rb +1 -1
- data/lib/spaceship/tunes/spaceship.rb +5 -5
- data/lib/spaceship/tunes/tester.rb +14 -15
- data/lib/spaceship/tunes/tunes_client.rb +61 -61
- data/lib/spaceship/ui.rb +1 -2
- data/lib/spaceship/version.rb +2 -2
- metadata +18 -2
@@ -0,0 +1,77 @@
|
|
1
|
+
module Spaceship
|
2
|
+
module Portal
|
3
|
+
# Represents an app group of the Apple Dev Portal
|
4
|
+
class AppGroup < PortalBase
|
5
|
+
# @return (String) The identifier assigned to this group
|
6
|
+
# @example
|
7
|
+
# "group.com.example.application"
|
8
|
+
attr_accessor :group_id
|
9
|
+
|
10
|
+
# @return (String) The prefix assigned to this group
|
11
|
+
# @example
|
12
|
+
# "9J57U9392R"
|
13
|
+
attr_accessor :prefix
|
14
|
+
|
15
|
+
# @return (String) The name of this group
|
16
|
+
# @example
|
17
|
+
# "App Group"
|
18
|
+
attr_accessor :name
|
19
|
+
|
20
|
+
# @return (String) Status of the group
|
21
|
+
# @example
|
22
|
+
# "current"
|
23
|
+
attr_accessor :status
|
24
|
+
|
25
|
+
# @return (String) The identifier of this app group, provided by the Dev Portal
|
26
|
+
# @example
|
27
|
+
# "2MAY7NPHAA"
|
28
|
+
attr_accessor :app_group_id
|
29
|
+
|
30
|
+
attr_mapping(
|
31
|
+
'applicationGroup' => :app_group_id,
|
32
|
+
'name' => :name,
|
33
|
+
'prefix' => :prefix,
|
34
|
+
'identifier' => :group_id,
|
35
|
+
'status' => :status
|
36
|
+
)
|
37
|
+
|
38
|
+
class << self
|
39
|
+
# Create a new object based on a hash.
|
40
|
+
# This is used to create a new object based on the server response.
|
41
|
+
def factory(attrs)
|
42
|
+
self.new(attrs)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return (Array) Returns all app groups available for this account
|
46
|
+
def all
|
47
|
+
client.app_groups.map { |group| self.factory(group) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Creates a new App Group on the Apple Dev Portal
|
51
|
+
#
|
52
|
+
# @param group_id [String] the identifier to assign to this group
|
53
|
+
# @param name [String] the name of the group
|
54
|
+
# @return (AppGroup) The group you just created
|
55
|
+
def create!(group_id: nil, name: nil)
|
56
|
+
new_group = client.create_app_group!(name, group_id)
|
57
|
+
self.new(new_group)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Find a specific App Group group_id
|
61
|
+
# @return (AppGroup) The app group you're looking for. This is nil if the app group can't be found.
|
62
|
+
def find(group_id)
|
63
|
+
all.find do |group|
|
64
|
+
group.group_id == group_id
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Delete this app group
|
70
|
+
# @return (AppGroup) The app group you just deletd
|
71
|
+
def delete!
|
72
|
+
client.delete_app_group!(app_group_id)
|
73
|
+
self
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
module Spaceship
|
2
|
+
module Portal
|
3
|
+
# Represents a single application service (its state to be more precise) on the Apple Dev Portal
|
4
|
+
class AppService
|
5
|
+
# @return (String) The identifier used by the Dev Portal to represent this service
|
6
|
+
# @example
|
7
|
+
# "homeKit"
|
8
|
+
attr_accessor :service_id
|
9
|
+
|
10
|
+
# @return (Object) The current value for this service
|
11
|
+
# @example
|
12
|
+
# false
|
13
|
+
attr_accessor :value
|
14
|
+
|
15
|
+
# @return (String) The service URI for this service
|
16
|
+
# @example
|
17
|
+
# "account/ios/identifiers/updateService.action"
|
18
|
+
attr_accessor :service_uri
|
19
|
+
|
20
|
+
def initialize(service_id, value)
|
21
|
+
@service_id = service_id
|
22
|
+
@value = value
|
23
|
+
|
24
|
+
if @service_id == "push"
|
25
|
+
# Push notifications have a special URI
|
26
|
+
@service_uri = "account/ios/identifiers/updatePushService.action"
|
27
|
+
else
|
28
|
+
# Default service URI
|
29
|
+
@service_uri = "account/ios/identifiers/updateService.action"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def app_group
|
35
|
+
self::AppGroup
|
36
|
+
end
|
37
|
+
|
38
|
+
def associated_domains
|
39
|
+
self::AssociatedDomains
|
40
|
+
end
|
41
|
+
|
42
|
+
def data_protection
|
43
|
+
self::DataProtection
|
44
|
+
end
|
45
|
+
|
46
|
+
def health_kit
|
47
|
+
self::HealthKit
|
48
|
+
end
|
49
|
+
|
50
|
+
def home_kit
|
51
|
+
self::HomeKit
|
52
|
+
end
|
53
|
+
|
54
|
+
def wireless_accessory
|
55
|
+
self::WirelessAccessory
|
56
|
+
end
|
57
|
+
|
58
|
+
def icloud
|
59
|
+
self::Cloud
|
60
|
+
end
|
61
|
+
|
62
|
+
def cloud_kit
|
63
|
+
self::CloudKit
|
64
|
+
end
|
65
|
+
|
66
|
+
def inter_app_audio
|
67
|
+
self::InterAppAudio
|
68
|
+
end
|
69
|
+
|
70
|
+
def passbook
|
71
|
+
self::Passbook
|
72
|
+
end
|
73
|
+
|
74
|
+
def push_notification
|
75
|
+
self::PushNotification
|
76
|
+
end
|
77
|
+
|
78
|
+
def vpn_configuration
|
79
|
+
self::VPNConfiguration
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def ==(other)
|
84
|
+
self.class == other.class &&
|
85
|
+
self.service_id == other.service_id &&
|
86
|
+
self.value == other.value &&
|
87
|
+
self.service_uri == other.service_uri
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Modules for "constants"
|
92
|
+
#
|
93
|
+
module AppGroup
|
94
|
+
def self.off
|
95
|
+
AppService.new("APG3427HIY", false)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.on
|
99
|
+
AppService.new("APG3427HIY", true)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
module AssociatedDomains
|
104
|
+
def self.off
|
105
|
+
AppService.new("SKC3T5S89Y", false)
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.on
|
109
|
+
AppService.new("SKC3T5S89Y", true)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
module DataProtection
|
114
|
+
def self.off
|
115
|
+
AppService.new("dataProtection", "")
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.complete
|
119
|
+
AppService.new("dataProtection", "complete")
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.unless_open
|
123
|
+
AppService.new("dataProtection", "unlessopen")
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.until_first_auth
|
127
|
+
AppService.new("dataProtection", "untilfirstauth")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
module HealthKit
|
132
|
+
def self.off
|
133
|
+
AppService.new("HK421J6T7P", false)
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.on
|
137
|
+
AppService.new("HK421J6T7P", true)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
module HomeKit
|
142
|
+
def self.off
|
143
|
+
AppService.new("homeKit", false)
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.on
|
147
|
+
AppService.new("homeKit", true)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
module WirelessAccessory
|
152
|
+
def self.off
|
153
|
+
AppService.new("WC421J6T7P", false)
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.on
|
157
|
+
AppService.new("WC421J6T7P", true)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
module Cloud
|
162
|
+
def self.off
|
163
|
+
AppService.new("iCloud", false)
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.on
|
167
|
+
AppService.new("iCloud", true)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
module CloudKit
|
172
|
+
def self.xcode5_compatible
|
173
|
+
AppService.new("cloudKitVersion", 1)
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.cloud_kit
|
177
|
+
AppService.new("cloudKitVersion", 2)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
module InterAppAudio
|
182
|
+
def self.off
|
183
|
+
AppService.new("IAD53UNK2F", false)
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.on
|
187
|
+
AppService.new("IAD53UNK2F", true)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
module Passbook
|
192
|
+
def self.off
|
193
|
+
AppService.new("pass", false)
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.on
|
197
|
+
AppService.new("pass", true)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
module PushNotification
|
202
|
+
def self.off
|
203
|
+
AppService.new("push", false)
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.on
|
207
|
+
AppService.new("push", true)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
module VPNConfiguration
|
212
|
+
def self.off
|
213
|
+
AppService.new("V66P55NK2I", false)
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.on
|
217
|
+
AppService.new("V66P55NK2I", true)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -237,7 +237,7 @@ module Spaceship
|
|
237
237
|
end
|
238
238
|
|
239
239
|
# ensure csr is a OpenSSL::X509::Request
|
240
|
-
csr = OpenSSL::X509::Request.new(csr) if csr.
|
240
|
+
csr = OpenSSL::X509::Request.new(csr) if csr.kind_of?(String)
|
241
241
|
|
242
242
|
# if this succeeds, we need to save the .cer and the private key in keychain access or wherever they go in linux
|
243
243
|
response = client.create_certificate!(type, csr.to_pem, app_id)
|
@@ -266,7 +266,7 @@ module Spaceship
|
|
266
266
|
|
267
267
|
# @return (Bool): Is this certificate a push profile for apps?
|
268
268
|
def is_push?
|
269
|
-
self.kind_of?PushCertificate
|
269
|
+
self.kind_of? PushCertificate
|
270
270
|
end
|
271
271
|
end
|
272
272
|
end
|
@@ -3,27 +3,27 @@ module Spaceship
|
|
3
3
|
# Represents a device from the Apple Developer Portal
|
4
4
|
class Device < PortalBase
|
5
5
|
# @return (String) The ID given from the developer portal. You'll probably not need it.
|
6
|
-
# @example
|
6
|
+
# @example
|
7
7
|
# "XJXGVS46MW"
|
8
8
|
attr_accessor :id
|
9
9
|
|
10
10
|
# @return (String) The name of the device
|
11
|
-
# @example
|
11
|
+
# @example
|
12
12
|
# "Felix Krause's iPhone 6"
|
13
13
|
attr_accessor :name
|
14
14
|
|
15
15
|
# @return (String) The UDID of the device
|
16
|
-
# @example
|
16
|
+
# @example
|
17
17
|
# "4c24a7ee5caaa4847f49aaab2d87483053f53b65"
|
18
18
|
attr_accessor :udid
|
19
19
|
|
20
20
|
# @return (String) The platform of the device. This is probably always "ios"
|
21
|
-
# @example
|
21
|
+
# @example
|
22
22
|
# "ios"
|
23
23
|
attr_accessor :platform
|
24
24
|
|
25
25
|
# @return (String) Status of the device. Probably always "c"
|
26
|
-
# @example
|
26
|
+
# @example
|
27
27
|
# "c"
|
28
28
|
attr_accessor :status
|
29
29
|
|
@@ -47,7 +47,7 @@ module Spaceship
|
|
47
47
|
client.devices.map { |device| self.factory(device) }
|
48
48
|
end
|
49
49
|
|
50
|
-
# @return (Device) Find a device based on the ID of the device. *Attention*:
|
50
|
+
# @return (Device) Find a device based on the ID of the device. *Attention*:
|
51
51
|
# This is *not* the UDID. nil if no device was found.
|
52
52
|
def find(device_id)
|
53
53
|
all.find do |device|
|
@@ -72,7 +72,7 @@ module Spaceship
|
|
72
72
|
# Register a new device to this account
|
73
73
|
# @param name (String) (required): The name of the new device
|
74
74
|
# @param udid (String) (required): The UDID of the new device
|
75
|
-
# @example
|
75
|
+
# @example
|
76
76
|
# Spaceship.device.create!(name: "Felix Krause's iPhone 6", udid: "4c24a7ee5caaa4847f49aaab2d87483053f53b65")
|
77
77
|
# @return (Device): The newly created device
|
78
78
|
def create!(name: nil, udid: nil)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spaceship/portal/portal_base'
|
2
2
|
require 'spaceship/portal/app'
|
3
|
+
require 'spaceship/portal/app_group'
|
4
|
+
require 'spaceship/portal/app_service'
|
3
5
|
require 'spaceship/portal/certificate'
|
4
6
|
require 'spaceship/portal/device'
|
5
7
|
require 'spaceship/portal/provisioning_profile'
|
6
|
-
require 'spaceship/portal/portal_client'
|
8
|
+
require 'spaceship/portal/portal_client'
|
@@ -13,7 +13,7 @@ module Spaceship
|
|
13
13
|
def api_key
|
14
14
|
cache_path = "/tmp/spaceship_api_key.txt"
|
15
15
|
begin
|
16
|
-
cached = File.read(cache_path)
|
16
|
+
cached = File.read(cache_path)
|
17
17
|
rescue Errno::ENOENT
|
18
18
|
end
|
19
19
|
return cached if cached
|
@@ -87,7 +87,6 @@ module Spaceship
|
|
87
87
|
@in_house = (team_information['type'] == 'In-House')
|
88
88
|
end
|
89
89
|
|
90
|
-
|
91
90
|
#####################################################
|
92
91
|
# @!group Apps
|
93
92
|
#####################################################
|
@@ -112,6 +111,28 @@ module Spaceship
|
|
112
111
|
parse_response(r, 'appId')
|
113
112
|
end
|
114
113
|
|
114
|
+
def update_service_for_app(app, service)
|
115
|
+
request(:post, service.service_uri, {
|
116
|
+
teamId: team_id,
|
117
|
+
displayId: app.app_id,
|
118
|
+
featureType: service.service_id,
|
119
|
+
featureValue: service.value
|
120
|
+
})
|
121
|
+
|
122
|
+
details_for_app(app)
|
123
|
+
end
|
124
|
+
|
125
|
+
def associate_groups_with_app(app, groups)
|
126
|
+
r = request(:post, 'account/ios/identifiers/assignApplicationGroupToAppId.action', {
|
127
|
+
teamId: team_id,
|
128
|
+
appIdId: app.app_id,
|
129
|
+
displayId: app.app_id,
|
130
|
+
applicationGroups: groups.map { |g| g.app_group_id }
|
131
|
+
})
|
132
|
+
|
133
|
+
details_for_app(app)
|
134
|
+
end
|
135
|
+
|
115
136
|
def create_app!(type, name, bundle_id)
|
116
137
|
ident_params = case type.to_sym
|
117
138
|
when :explicit
|
@@ -150,6 +171,39 @@ module Spaceship
|
|
150
171
|
parse_response(r)
|
151
172
|
end
|
152
173
|
|
174
|
+
#####################################################
|
175
|
+
# @!group App Groups
|
176
|
+
#####################################################
|
177
|
+
|
178
|
+
def app_groups
|
179
|
+
paging do |page_number|
|
180
|
+
r = request(:post, 'account/ios/identifiers/listApplicationGroups.action', {
|
181
|
+
teamId: team_id,
|
182
|
+
pageNumber: page_number,
|
183
|
+
pageSize: page_size,
|
184
|
+
sort: 'name=asc'
|
185
|
+
})
|
186
|
+
parse_response(r, 'applicationGroupList')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def create_app_group!(name, group_id)
|
191
|
+
r = request(:post, 'account/ios/identifiers/addApplicationGroup.action', {
|
192
|
+
name: name,
|
193
|
+
identifier: group_id,
|
194
|
+
teamId: team_id
|
195
|
+
})
|
196
|
+
parse_response(r, 'applicationGroup')
|
197
|
+
end
|
198
|
+
|
199
|
+
def delete_app_group!(app_group_id)
|
200
|
+
r = request(:post, 'account/ios/identifiers/deleteApplicationGroup.action', {
|
201
|
+
teamId: team_id,
|
202
|
+
applicationGroup: app_group_id
|
203
|
+
})
|
204
|
+
parse_response(r)
|
205
|
+
end
|
206
|
+
|
153
207
|
#####################################################
|
154
208
|
# @!group Devices
|
155
209
|
#####################################################
|
@@ -167,7 +221,7 @@ module Spaceship
|
|
167
221
|
end
|
168
222
|
|
169
223
|
def create_device!(device_name, device_id)
|
170
|
-
|
224
|
+
req = request(:post) do |r|
|
171
225
|
r.url "https://developerservices2.apple.com/services/#{PROTOCOL_VERSION}/ios/addDevice.action"
|
172
226
|
r.params = {
|
173
227
|
teamId: team_id,
|
@@ -176,7 +230,7 @@ module Spaceship
|
|
176
230
|
}
|
177
231
|
end
|
178
232
|
|
179
|
-
parse_response(
|
233
|
+
parse_response(req, 'device')
|
180
234
|
end
|
181
235
|
|
182
236
|
#####################################################
|
@@ -201,7 +255,7 @@ module Spaceship
|
|
201
255
|
teamId: team_id,
|
202
256
|
type: type,
|
203
257
|
csrContent: csr,
|
204
|
-
appIdId: app_id
|
258
|
+
appIdId: app_id # optional
|
205
259
|
})
|
206
260
|
parse_response(r, 'certRequest')
|
207
261
|
end
|
@@ -231,16 +285,16 @@ module Spaceship
|
|
231
285
|
#####################################################
|
232
286
|
|
233
287
|
def provisioning_profiles
|
234
|
-
|
288
|
+
req = request(:post) do |r|
|
235
289
|
r.url "https://developerservices2.apple.com/services/#{PROTOCOL_VERSION}/ios/listProvisioningProfiles.action"
|
236
290
|
r.params = {
|
237
291
|
teamId: team_id,
|
238
292
|
includeInactiveProfiles: true,
|
239
|
-
onlyCountLists: true
|
293
|
+
onlyCountLists: true
|
240
294
|
}
|
241
295
|
end
|
242
296
|
|
243
|
-
parse_response(
|
297
|
+
parse_response(req, 'provisioningProfiles')
|
244
298
|
end
|
245
299
|
|
246
300
|
def create_provisioning_profile!(name, distribution_method, app_id, certificate_ids, device_ids)
|
@@ -278,11 +332,11 @@ module Spaceship
|
|
278
332
|
provisioningProfileName: name,
|
279
333
|
appIdId: app_id,
|
280
334
|
distributionType: distribution_method,
|
281
|
-
certificateIds: certificate_ids.
|
335
|
+
certificateIds: certificate_ids.join(','),
|
282
336
|
deviceIds: device_ids
|
283
337
|
})
|
284
338
|
|
285
339
|
parse_response(r, 'provisioningProfile')
|
286
340
|
end
|
287
341
|
end
|
288
|
-
end
|
342
|
+
end
|