spaceship 0.3.2 → 0.4.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/README.md +18 -15
- data/lib/spaceship/base.rb +0 -1
- data/lib/spaceship/client.rb +80 -74
- 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 -11
- 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 +25 -24
- data/lib/spaceship/tunes/app_version.rb +31 -41
- data/lib/spaceship/tunes/application.rb +27 -28
- 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
- data/lib/spaceship.rb +2 -1
- metadata +19 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bee636c5de7df79ede26deda935649fb5a738e3f
|
|
4
|
+
data.tar.gz: 0e846d25300e1c0658e036f208991f841d55b5d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5a81882cdb7b1169c78d456e4a9c531da3888632ad6d9ecd9cb36d3b546a1c95db5e98a88369d3996847a5a61b5f6b80663fb2db4b4950d612c417e84989d80b
|
|
7
|
+
data.tar.gz: c894e87a4e5819716c5959cfeba5b8de19b2b82c91ef46c4ab506225e1fabfedd51058a46b1ca545eaabd7ae48bf8bbad3499a276f453ca930759d0fe7cd9197
|
data/README.md
CHANGED
|
@@ -66,17 +66,17 @@ Enough words, here is some code:
|
|
|
66
66
|
|
|
67
67
|
```ruby
|
|
68
68
|
Spaceship.login
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# Create a new app
|
|
71
71
|
app = Spaceship.app.create!(bundle_id: "com.krausefx.app", name: "Spaceship App")
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
# Use an existing certificate
|
|
74
74
|
cert = Spaceship.certificate.production.all.first
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
# Create a new provisioning profile
|
|
77
77
|
profile = Spaceship.provisioning_profile.app_store.create!(bundle_id: app.bundle_id,
|
|
78
78
|
certificate: cert)
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
# Print the name and download the new profile
|
|
81
81
|
puts "Created Profile " + profile.name
|
|
82
82
|
profile.download
|
|
@@ -84,7 +84,7 @@ profile.download
|
|
|
84
84
|
|
|
85
85
|
## Speed
|
|
86
86
|
|
|
87
|
-
How fast are tools using `spaceship` compared to web scraping?
|
|
87
|
+
How fast are tools using `spaceship` compared to web scraping?
|
|
88
88
|
|
|
89
89
|

|
|
90
90
|
|
|
@@ -110,13 +110,15 @@ Most [fastlane tools](https://fastlane.tools) already use `spaceship`, like `sig
|
|
|
110
110
|
|
|
111
111
|
The detailed documentation of all available classes is available on [RubyDoc](http://www.rubydoc.info/github/fastlane/spaceship/frames).
|
|
112
112
|
|
|
113
|
+
You can find the log file here `/tmp/spaceship[time].log`.
|
|
114
|
+
|
|
113
115
|
# Technical Details
|
|
114
116
|
|
|
115
117
|
## HTTP Client
|
|
116
118
|
|
|
117
|
-
Up until now all [fastlane tools](https://fastlane.tools) used web scraping to interact with Apple's web services. `spaceship` uses a simple HTTP client only, resulting in much less overhead and extremely improved speed.
|
|
119
|
+
Up until now all [fastlane tools](https://fastlane.tools) used web scraping to interact with Apple's web services. `spaceship` uses a simple HTTP client only, resulting in much less overhead and extremely improved speed.
|
|
118
120
|
|
|
119
|
-
Advantages of `spaceship` (HTTP client) over web scraping:
|
|
121
|
+
Advantages of `spaceship` (HTTP client) over web scraping:
|
|
120
122
|
|
|
121
123
|
- Blazing fast :rocket: 90% faster than previous methods
|
|
122
124
|
- No more overhead by loading images, HTML, JS and CSS files on each page load
|
|
@@ -129,18 +131,19 @@ Advantages of `spaceship` (HTTP client) over web scraping:
|
|
|
129
131
|
I won't go into too much technical details about the various API endpoints, but just to give you an idea:
|
|
130
132
|
|
|
131
133
|
- `https://idmsa.apple.com`: Used to authenticate to get a valid session
|
|
132
|
-
- `https://developerservices2.apple.com`:
|
|
134
|
+
- `https://developerservices2.apple.com`:
|
|
133
135
|
- Get a detailed list of all available provisioning profiles
|
|
134
136
|
- This API returns the devices, certificates and app for each of the profiles
|
|
135
137
|
- Register new devices
|
|
136
|
-
- `https://developer.apple.com`:
|
|
137
|
-
- List all devices, certificates and
|
|
138
|
+
- `https://developer.apple.com`:
|
|
139
|
+
- List all devices, certificates, apps and app groups
|
|
138
140
|
- Create new certificates, provisioning profiles and apps
|
|
141
|
+
- Disable/enable services on apps and assign them to app groups
|
|
139
142
|
- Delete certificates and apps
|
|
140
143
|
- Repair provisioning profiles
|
|
141
144
|
- Download provisioning profiles
|
|
142
145
|
- Team selection
|
|
143
|
-
- `https://itunesconnect.apple.com`:
|
|
146
|
+
- `https://itunesconnect.apple.com`:
|
|
144
147
|
- Managing apps
|
|
145
148
|
- Managing beta testers
|
|
146
149
|
- Submitting updates to review
|
|
@@ -150,11 +153,11 @@ I won't go into too much technical details about the various API endpoints, but
|
|
|
150
153
|
|
|
151
154
|
## Magic involved
|
|
152
155
|
|
|
153
|
-
`spaceship` does a lot of magic to get everything working so neatly:
|
|
156
|
+
`spaceship` does a lot of magic to get everything working so neatly:
|
|
154
157
|
|
|
155
158
|
- **Sensible Defaults**: You only have to provide the mandatory information (e.g. new provisioning profiles contain all devices by default)
|
|
156
159
|
- **Local Validation**: When pushing changes back to the Apple Dev Portal `spaceship` will make sure only valid data is sent to Apple (e.g. automatic repairing of provisioning profiles)
|
|
157
|
-
- **Various request/response types**: When working with the different API endpoints, `spaceship` has to deal with `JSON`, `XML`, `txt`, `plist` and sometimes even `HTML` responses and requests.
|
|
160
|
+
- **Various request/response types**: When working with the different API endpoints, `spaceship` has to deal with `JSON`, `XML`, `txt`, `plist` and sometimes even `HTML` responses and requests.
|
|
158
161
|
- **Automatic Pagination**: Even if you have thousands of apps, profiles or certificates, `spaceship` **can** handle your scale. It was heavily tested by first using `spaceship` to create hundreds of profiles and then accessing them using `spaceship`.
|
|
159
162
|
- **Session, Cookie and CSRF token**: All the security aspects are handled by `spaceship`.
|
|
160
163
|
- **Profile Magic**: Create and upload code signing requests, all managed by `spaceship`
|
|
@@ -162,9 +165,9 @@ I won't go into too much technical details about the various API endpoints, but
|
|
|
162
165
|
|
|
163
166
|
# Credits
|
|
164
167
|
|
|
165
|
-
The initial release was sponsored by [ZeroPush](https://zeropush.com).
|
|
168
|
+
The initial release was sponsored by [ZeroPush](https://zeropush.com).
|
|
166
169
|
|
|
167
|
-
`spaceship` was developed by
|
|
170
|
+
`spaceship` was developed by
|
|
168
171
|
- [@KrauseFx](https://twitter.com/KrauseFx).
|
|
169
172
|
- [@snatchev](https://twitter.com/snatchev/)
|
|
170
173
|
- [@mathcarignani](https://twitter.com/mathcarignani/)
|
data/lib/spaceship/base.rb
CHANGED
data/lib/spaceship/client.rb
CHANGED
|
@@ -5,7 +5,6 @@ require 'spaceship/ui'
|
|
|
5
5
|
require 'spaceship/helper/plist_middleware'
|
|
6
6
|
require 'spaceship/helper/net_http_generic_request'
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
if ENV["DEBUG"]
|
|
10
9
|
require 'openssl'
|
|
11
10
|
# this has to be on top of this file, since the value can't be changed later
|
|
@@ -20,12 +19,15 @@ module Spaceship
|
|
|
20
19
|
attr_accessor :cookie
|
|
21
20
|
|
|
22
21
|
# The logger in which all requests are logged
|
|
23
|
-
# /tmp/spaceship.log by default
|
|
22
|
+
# /tmp/spaceship[time].log by default
|
|
24
23
|
attr_accessor :logger
|
|
25
24
|
|
|
26
25
|
# Invalid user credentials were provided
|
|
27
26
|
class InvalidUserCredentialsError < StandardError; end
|
|
28
27
|
|
|
28
|
+
# Raised when no user credentials were passed at all
|
|
29
|
+
class NoUserCredentialsError < StandardError; end
|
|
30
|
+
|
|
29
31
|
class UnexpectedResponse < StandardError; end
|
|
30
32
|
|
|
31
33
|
# Authenticates with Apple's web services. This method has to be called once
|
|
@@ -71,14 +73,14 @@ module Spaceship
|
|
|
71
73
|
end
|
|
72
74
|
|
|
73
75
|
# The logger in which all requests are logged
|
|
74
|
-
# /tmp/spaceship.log by default
|
|
76
|
+
# /tmp/spaceship[time].log by default
|
|
75
77
|
def logger
|
|
76
78
|
unless @logger
|
|
77
79
|
if $verbose || ENV["VERBOSE"]
|
|
78
80
|
@logger = Logger.new(STDOUT)
|
|
79
81
|
else
|
|
80
82
|
# Log to file by default
|
|
81
|
-
path = "/tmp/spaceship.log"
|
|
83
|
+
path = "/tmp/spaceship#{Time.now.to_i}.log"
|
|
82
84
|
@logger = Logger.new(path)
|
|
83
85
|
end
|
|
84
86
|
|
|
@@ -138,11 +140,11 @@ module Spaceship
|
|
|
138
140
|
require 'credentials_manager'
|
|
139
141
|
data = CredentialsManager::PasswordManager.shared_manager(user, false)
|
|
140
142
|
user ||= data.username
|
|
141
|
-
password
|
|
143
|
+
password = data.password
|
|
142
144
|
end
|
|
143
145
|
|
|
144
|
-
if user.to_s.empty? or password.to_s.empty?
|
|
145
|
-
raise
|
|
146
|
+
if user.to_s.strip.empty? or password.to_s.strip.empty?
|
|
147
|
+
raise NoUserCredentialsError.new("No login data provided")
|
|
146
148
|
end
|
|
147
149
|
|
|
148
150
|
send_login_request(user, password) # different in subclasses
|
|
@@ -153,94 +155,98 @@ module Spaceship
|
|
|
153
155
|
!!@cookie
|
|
154
156
|
end
|
|
155
157
|
|
|
158
|
+
def with_retry(tries = 5, &block)
|
|
159
|
+
return block.call
|
|
160
|
+
rescue Faraday::Error::TimeoutError => ex # New Faraday version: Faraday::TimeoutError => ex
|
|
161
|
+
unless (tries -= 1).zero?
|
|
162
|
+
sleep 3
|
|
163
|
+
retry
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
raise ex # re-raise the exception
|
|
167
|
+
end
|
|
168
|
+
|
|
156
169
|
private
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
170
|
+
|
|
171
|
+
# Is called from `parse_response` to store the latest csrf_token (if available)
|
|
172
|
+
def store_csrf_tokens(response)
|
|
173
|
+
if response and response.headers
|
|
174
|
+
tokens = response.headers.select { |k, v| %w[csrf csrf_ts].include?(k) }
|
|
175
|
+
if tokens and not tokens.empty?
|
|
176
|
+
@csrf_tokens = tokens
|
|
164
177
|
end
|
|
165
178
|
end
|
|
179
|
+
end
|
|
166
180
|
|
|
167
181
|
# memoize the last csrf tokens from responses
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
182
|
+
def csrf_tokens
|
|
183
|
+
@csrf_tokens || {}
|
|
184
|
+
end
|
|
171
185
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
186
|
+
def request(method, url_or_path = nil, params = nil, headers = {}, &block)
|
|
187
|
+
if session?
|
|
188
|
+
headers.merge!({'Cookie' => cookie})
|
|
189
|
+
headers.merge!(csrf_tokens)
|
|
190
|
+
end
|
|
191
|
+
headers.merge!({'User-Agent' => 'spaceship'})
|
|
178
192
|
|
|
179
|
-
|
|
180
|
-
|
|
193
|
+
# Before encoding the parameters, log them
|
|
194
|
+
log_request(method, url_or_path, params)
|
|
181
195
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
196
|
+
# form-encode the params only if there are params, and the block is not supplied.
|
|
197
|
+
# this is so that certain requests can be made using the block for more control
|
|
198
|
+
if method == :post && params && !block_given?
|
|
199
|
+
params, headers = encode_params(params, headers)
|
|
200
|
+
end
|
|
187
201
|
|
|
188
|
-
|
|
202
|
+
response = send_request(method, url_or_path, params, headers, &block)
|
|
189
203
|
|
|
190
|
-
|
|
204
|
+
log_response(method, url_or_path, response)
|
|
191
205
|
|
|
192
|
-
|
|
193
|
-
|
|
206
|
+
return response
|
|
207
|
+
end
|
|
194
208
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
end
|
|
202
|
-
logger.info("#{method.upcase}: #{url} #{params_to_log.join(', ')}")
|
|
209
|
+
def log_request(method, url, params)
|
|
210
|
+
params_to_log = Hash(params).dup # to also work with nil
|
|
211
|
+
params_to_log.delete(:accountPassword) # Dev Portal
|
|
212
|
+
params_to_log.delete(:theAccountPW) # iTC
|
|
213
|
+
params_to_log = params_to_log.collect do |key, value|
|
|
214
|
+
"{#{key}: #{value}}"
|
|
203
215
|
end
|
|
216
|
+
logger.info("#{method.upcase}: #{url} #{params_to_log.join(', ')}")
|
|
217
|
+
end
|
|
204
218
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
219
|
+
def log_response(method, url, response)
|
|
220
|
+
logger.debug("#{method.upcase}: #{url}: #{response.body}")
|
|
221
|
+
end
|
|
208
222
|
|
|
209
223
|
# Actually sends the request to the remote server
|
|
210
224
|
# Automatically retries the request up to 3 times if something goes wrong
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return @client.send(method, url_or_path, params, headers, &block)
|
|
215
|
-
|
|
216
|
-
rescue Faraday::Error::TimeoutError => ex # New Faraday version: Faraday::TimeoutError => ex
|
|
217
|
-
unless (tries -= 1).zero?
|
|
218
|
-
sleep 3
|
|
219
|
-
retry
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
raise ex # re-raise the exception
|
|
225
|
+
def send_request(method, url_or_path, params, headers, &block)
|
|
226
|
+
with_retry do
|
|
227
|
+
@client.send(method, url_or_path, params, headers, &block)
|
|
223
228
|
end
|
|
229
|
+
end
|
|
224
230
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
if content == nil
|
|
233
|
-
raise UnexpectedResponse.new(response.body)
|
|
234
|
-
else
|
|
235
|
-
store_csrf_tokens(response)
|
|
236
|
-
content
|
|
237
|
-
end
|
|
231
|
+
def parse_response(response, expected_key = nil)
|
|
232
|
+
if expected_key
|
|
233
|
+
content = response.body[expected_key]
|
|
234
|
+
else
|
|
235
|
+
content = response.body
|
|
238
236
|
end
|
|
239
237
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
238
|
+
if content == nil
|
|
239
|
+
raise UnexpectedResponse.new(response.body)
|
|
240
|
+
else
|
|
241
|
+
store_csrf_tokens(response)
|
|
242
|
+
content
|
|
244
243
|
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def encode_params(params, headers)
|
|
247
|
+
params = Faraday::Utils::ParamsHash[params].to_query
|
|
248
|
+
headers = {'Content-Type' => 'application/x-www-form-urlencoded'}.merge(headers)
|
|
249
|
+
return params, headers
|
|
250
|
+
end
|
|
245
251
|
end
|
|
246
252
|
end
|
data/lib/spaceship/launcher.rb
CHANGED
|
@@ -6,17 +6,17 @@ module Spaceship
|
|
|
6
6
|
# spaceship. You can call `.new` without any parameters, but you'll have to call
|
|
7
7
|
# `.login` at a later point. If you prefer, you can pass the login credentials
|
|
8
8
|
# here already.
|
|
9
|
-
#
|
|
9
|
+
#
|
|
10
10
|
# Authenticates with Apple's web services. This method has to be called once
|
|
11
11
|
# to generate a valid session. The session will automatically be used from then
|
|
12
12
|
# on.
|
|
13
|
-
#
|
|
13
|
+
#
|
|
14
14
|
# This method will automatically use the username from the Appfile (if available)
|
|
15
15
|
# and fetch the password from the Keychain (if available)
|
|
16
|
-
#
|
|
16
|
+
#
|
|
17
17
|
# @param user (String) (optional): The username (usually the email address)
|
|
18
18
|
# @param password (String) (optional): The password
|
|
19
|
-
#
|
|
19
|
+
#
|
|
20
20
|
# @raise InvalidUserCredentialsError: raised if authentication failed
|
|
21
21
|
def initialize(user = nil, password = nil)
|
|
22
22
|
@client = PortalClient.new
|
|
@@ -33,30 +33,30 @@ module Spaceship
|
|
|
33
33
|
# Authenticates with Apple's web services. This method has to be called once
|
|
34
34
|
# to generate a valid session. The session will automatically be used from then
|
|
35
35
|
# on.
|
|
36
|
-
#
|
|
36
|
+
#
|
|
37
37
|
# This method will automatically use the username from the Appfile (if available)
|
|
38
38
|
# and fetch the password from the Keychain (if available)
|
|
39
|
-
#
|
|
39
|
+
#
|
|
40
40
|
# @param user (String) (optional): The username (usually the email address)
|
|
41
41
|
# @param password (String) (optional): The password
|
|
42
|
-
#
|
|
42
|
+
#
|
|
43
43
|
# @raise InvalidUserCredentialsError: raised if authentication failed
|
|
44
|
-
#
|
|
44
|
+
#
|
|
45
45
|
# @return (Spaceship::Client) The client the login method was called for
|
|
46
|
-
def login(user, password)
|
|
46
|
+
def login(user, password)
|
|
47
47
|
@client.login(user, password)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
# Open up the team selection for the user (if necessary).
|
|
51
|
-
#
|
|
51
|
+
#
|
|
52
52
|
# If the user is in multiple teams, a team selection is shown.
|
|
53
53
|
# The user can then select a team by entering the number
|
|
54
|
-
#
|
|
54
|
+
#
|
|
55
55
|
# Additionally, the team ID is shown next to each team name
|
|
56
56
|
# so that the user can use the environment variable `FASTLANE_TEAM_ID`
|
|
57
57
|
# for future user.
|
|
58
|
-
#
|
|
59
|
-
# @return (String) The ID of the select team. You also get the value if
|
|
58
|
+
#
|
|
59
|
+
# @return (String) The ID of the select team. You also get the value if
|
|
60
60
|
# the user is only in one team.
|
|
61
61
|
def select_team
|
|
62
62
|
@client.select_team
|
|
@@ -71,6 +71,11 @@ module Spaceship
|
|
|
71
71
|
Spaceship::App.set_client(@client)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
# @return (Class) Access the app groups for this spaceship
|
|
75
|
+
def app_group
|
|
76
|
+
Spaceship::AppGroup.set_client(@client)
|
|
77
|
+
end
|
|
78
|
+
|
|
74
79
|
# @return (Class) Access the devices for this spaceship
|
|
75
80
|
def device
|
|
76
81
|
Spaceship::Device.set_client(@client)
|
|
@@ -86,4 +91,4 @@ module Spaceship
|
|
|
86
91
|
Spaceship::ProvisioningProfile.set_client(@client)
|
|
87
92
|
end
|
|
88
93
|
end
|
|
89
|
-
end
|
|
94
|
+
end
|
data/lib/spaceship/portal/app.rb
CHANGED
|
@@ -4,7 +4,7 @@ module Spaceship
|
|
|
4
4
|
class App < PortalBase
|
|
5
5
|
|
|
6
6
|
# @return (String) The identifier of this app, provided by the Dev Portal
|
|
7
|
-
# @example
|
|
7
|
+
# @example
|
|
8
8
|
# "RGAWZGXSAA"
|
|
9
9
|
attr_accessor :app_id
|
|
10
10
|
|
|
@@ -14,17 +14,17 @@ module Spaceship
|
|
|
14
14
|
attr_accessor :name
|
|
15
15
|
|
|
16
16
|
# @return (String) the supported platform of this app
|
|
17
|
-
# @example
|
|
17
|
+
# @example
|
|
18
18
|
# "ios"
|
|
19
19
|
attr_accessor :platform
|
|
20
20
|
|
|
21
21
|
# Prefix provided by the Dev Portal
|
|
22
|
-
# @example
|
|
22
|
+
# @example
|
|
23
23
|
# "5A997XSHK2"
|
|
24
24
|
attr_accessor :prefix
|
|
25
25
|
|
|
26
26
|
# @return (String) The bundle_id (app identifier) of your app
|
|
27
|
-
# @example
|
|
27
|
+
# @example
|
|
28
28
|
# "com.krausefx.app"
|
|
29
29
|
attr_accessor :bundle_id
|
|
30
30
|
|
|
@@ -33,7 +33,7 @@ module Spaceship
|
|
|
33
33
|
|
|
34
34
|
# @return (Hash) Feature details
|
|
35
35
|
attr_accessor :features
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
# @return (Array) List of enabled features
|
|
38
38
|
attr_accessor :enabled_features
|
|
39
39
|
|
|
@@ -45,10 +45,10 @@ module Spaceship
|
|
|
45
45
|
|
|
46
46
|
# @return (Fixnum) Number of associated app groups
|
|
47
47
|
attr_accessor :app_groups_count
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
# @return (Fixnum) Number of associated cloud containers
|
|
50
50
|
attr_accessor :cloud_containers_count
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# @return (Fixnum) Number of associated identifiers
|
|
53
53
|
attr_accessor :identifiers_count
|
|
54
54
|
|
|
@@ -81,7 +81,7 @@ module Spaceship
|
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
# Creates a new App ID on the Apple Dev Portal
|
|
84
|
-
#
|
|
84
|
+
#
|
|
85
85
|
# if bundle_id ends with '*' then it is a wildcard id otherwise, it is an explicit id
|
|
86
86
|
# @param bundle_id [String] the bundle id (app_identifier) of the app associated with this provisioning profile
|
|
87
87
|
# @param name [String] the name of the App
|
|
@@ -113,13 +113,27 @@ module Spaceship
|
|
|
113
113
|
client.delete_app!(app_id)
|
|
114
114
|
self
|
|
115
115
|
end
|
|
116
|
-
|
|
116
|
+
|
|
117
117
|
# Fetch a specific App ID details based on the bundle_id
|
|
118
118
|
# @return (App) The app you're looking for. This is nil if the app can't be found.
|
|
119
119
|
def details
|
|
120
120
|
app = client.details_for_app(self)
|
|
121
121
|
self.class.factory(app)
|
|
122
122
|
end
|
|
123
|
+
|
|
124
|
+
# Associate specific groups with this app
|
|
125
|
+
# @return (App) The updated detailed app. This is nil if the app couldn't be found
|
|
126
|
+
def associate_groups(groups)
|
|
127
|
+
app = client.associate_groups_with_app(self, groups)
|
|
128
|
+
self.class.factory(app)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Update a service for the app with given AppService object
|
|
132
|
+
# @return (App) The updated detailed app. This is nil if the app couldn't be found
|
|
133
|
+
def update_service(service)
|
|
134
|
+
app = client.update_service_for_app(self, service)
|
|
135
|
+
self.class.factory(app)
|
|
136
|
+
end
|
|
123
137
|
end
|
|
124
138
|
end
|
|
125
139
|
end
|
|
@@ -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
|