spaceship 0.0.15 → 0.1.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/assets/languageMapping.json +224 -0
  3. data/lib/spaceship.rb +20 -63
  4. data/lib/spaceship/base.rb +71 -14
  5. data/lib/spaceship/client.rb +9 -274
  6. data/lib/spaceship/launcher.rb +1 -1
  7. data/lib/spaceship/portal/app.rb +125 -0
  8. data/lib/spaceship/portal/certificate.rb +273 -0
  9. data/lib/spaceship/portal/device.rb +102 -0
  10. data/lib/spaceship/portal/portal.rb +6 -0
  11. data/lib/spaceship/portal/portal_base.rb +13 -0
  12. data/lib/spaceship/portal/portal_client.rb +289 -0
  13. data/lib/spaceship/portal/provisioning_profile.rb +369 -0
  14. data/lib/spaceship/portal/spaceship.rb +94 -0
  15. data/lib/spaceship/{ui → portal/ui}/select_team.rb +0 -0
  16. data/lib/spaceship/tunes/app_screenshot.rb +28 -0
  17. data/lib/spaceship/tunes/app_status.rb +63 -0
  18. data/lib/spaceship/tunes/app_submission.rb +149 -0
  19. data/lib/spaceship/tunes/app_version.rb +337 -0
  20. data/lib/spaceship/tunes/application.rb +253 -0
  21. data/lib/spaceship/tunes/build.rb +128 -0
  22. data/lib/spaceship/tunes/build_train.rb +79 -0
  23. data/lib/spaceship/tunes/language_converter.rb +44 -0
  24. data/lib/spaceship/tunes/language_item.rb +54 -0
  25. data/lib/spaceship/tunes/processing_build.rb +30 -0
  26. data/lib/spaceship/tunes/spaceship.rb +26 -0
  27. data/lib/spaceship/tunes/tester.rb +177 -0
  28. data/lib/spaceship/tunes/tunes.rb +12 -0
  29. data/lib/spaceship/tunes/tunes_base.rb +15 -0
  30. data/lib/spaceship/tunes/tunes_client.rb +360 -0
  31. data/lib/spaceship/version.rb +1 -1
  32. metadata +27 -7
  33. data/lib/spaceship/app.rb +0 -125
  34. data/lib/spaceship/certificate.rb +0 -271
  35. data/lib/spaceship/device.rb +0 -100
  36. data/lib/spaceship/provisioning_profile.rb +0 -367
@@ -5,6 +5,7 @@ require 'spaceship/ui'
5
5
  require 'spaceship/helper/plist_middleware'
6
6
  require 'spaceship/helper/net_http_generic_request'
7
7
 
8
+
8
9
  if ENV["DEBUG"]
9
10
  require 'openssl'
10
11
  # this has to be on top of this file, since the value can't be changed later
@@ -49,8 +50,12 @@ module Spaceship
49
50
  end
50
51
  end
51
52
 
53
+ def self.hostname
54
+ raise "You must implemented self.hostname"
55
+ end
56
+
52
57
  def initialize
53
- @client = Faraday.new("https://developer.apple.com/services-account/#{PROTOCOL_VERSION}/") do |c|
58
+ @client = Faraday.new(self.class.hostname) do |c|
54
59
  c.response :json, content_type: /\bjson$/
55
60
  c.response :xml, content_type: /\bxml$/
56
61
  c.response :plist, content_type: /\bplist$/
@@ -65,28 +70,6 @@ module Spaceship
65
70
  end
66
71
  end
67
72
 
68
- # Fetches the latest API Key from the Apple Dev Portal
69
- def api_key
70
- cache_path = "/tmp/spaceship_api_key.txt"
71
- begin
72
- cached = File.read(cache_path)
73
- rescue Errno::ENOENT
74
- end
75
- return cached if cached
76
-
77
- landing_url = "https://developer.apple.com/membercenter/index.action"
78
- logger.info("GET: " + landing_url)
79
- headers = @client.get(landing_url).headers
80
- results = headers['location'].match(/.*appIdKey=(\h+)/)
81
- if results.length > 1
82
- api_key = results[1]
83
- File.write(cache_path, api_key)
84
- return api_key
85
- else
86
- raise "Could not find latest API Key from the Dev Portal"
87
- end
88
- end
89
-
90
73
  # The logger in which all requests are logged
91
74
  # /tmp/spaceship.log by default
92
75
  def logger
@@ -162,19 +145,7 @@ module Spaceship
162
145
  raise InvalidUserCredentialsError.new("No login data provided")
163
146
  end
164
147
 
165
- response = request(:post, "https://idmsa.apple.com/IDMSWebAuth/authenticate", {
166
- appleId: user,
167
- accountPassword: password,
168
- appIdKey: api_key
169
- })
170
-
171
- if response['Set-Cookie'] =~ /myacinfo=(\w+);/
172
- @cookie = "myacinfo=#{$1};"
173
- return @client
174
- else
175
- # User Credentials are wrong
176
- raise InvalidUserCredentialsError.new(response)
177
- end
148
+ send_login_request(user, password) # different in subclasses
178
149
  end
179
150
 
180
151
  # @return (Bool) Do we have a valid session?
@@ -182,243 +153,6 @@ module Spaceship
182
153
  !!@cookie
183
154
  end
184
155
 
185
- # @return (Array) A list of all available teams
186
- def teams
187
- r = request(:post, 'account/listTeams.action')
188
- parse_response(r, 'teams')
189
- end
190
-
191
- # @return (String) The currently selected Team ID
192
- def team_id
193
- return @current_team_id if @current_team_id
194
-
195
- if teams.count > 1
196
- puts "The current user is in #{teams.count} teams. Pass a team ID or call `select_team` to choose a team. Using the first one for now."
197
- end
198
- @current_team_id ||= teams[0]['teamId']
199
- end
200
-
201
- # Shows a team selection for the user in the terminal. This should not be
202
- # called on CI systems
203
- def select_team
204
- @current_team_id = self.UI.select_team
205
- end
206
-
207
- # Set a new team ID which will be used from now on
208
- def team_id=(team_id)
209
- @current_team_id = team_id
210
- end
211
-
212
- # @return (Hash) Fetches all information of the currently used team
213
- def team_information
214
- teams.find do |t|
215
- t['teamId'] == team_id
216
- end
217
- end
218
-
219
- # Is the current session from an Enterprise In House account?
220
- def in_house?
221
- return @in_house unless @in_house.nil?
222
- @in_house = (team_information['type'] == 'In-House')
223
- end
224
-
225
- #####################################################
226
- # @!group Apps
227
- #####################################################
228
-
229
- def apps
230
- paging do |page_number|
231
- r = request(:post, 'account/ios/identifiers/listAppIds.action', {
232
- teamId: team_id,
233
- pageNumber: page_number,
234
- pageSize: page_size,
235
- sort: 'name=asc'
236
- })
237
- parse_response(r, 'appIds')
238
- end
239
- end
240
-
241
- def details_for_app(app)
242
- r = request(:post, 'account/ios/identifiers/getAppIdDetail.action', {
243
- teamId: team_id,
244
- appIdId: app.app_id
245
- })
246
- parse_response(r, 'appId')
247
- end
248
-
249
- def create_app!(type, name, bundle_id)
250
- ident_params = case type.to_sym
251
- when :explicit
252
- {
253
- type: 'explicit',
254
- explicitIdentifier: bundle_id,
255
- appIdentifierString: bundle_id,
256
- push: 'on',
257
- inAppPurchase: 'on',
258
- gameCenter: 'on'
259
- }
260
- when :wildcard
261
- {
262
- type: 'wildcard',
263
- wildcardIdentifier: bundle_id,
264
- appIdentifierString: bundle_id
265
- }
266
- end
267
-
268
- params = {
269
- appIdName: name,
270
- teamId: team_id
271
- }
272
-
273
- params.merge!(ident_params)
274
-
275
- r = request(:post, 'account/ios/identifiers/addAppId.action', params)
276
- parse_response(r, 'appId')
277
- end
278
-
279
- def delete_app!(app_id)
280
- r = request(:post, 'account/ios/identifiers/deleteAppId.action', {
281
- teamId: team_id,
282
- appIdId: app_id
283
- })
284
- parse_response(r)
285
- end
286
-
287
- #####################################################
288
- # @!group Devices
289
- #####################################################
290
-
291
- def devices
292
- paging do |page_number|
293
- r = request(:post, 'account/ios/device/listDevices.action', {
294
- teamId: team_id,
295
- pageNumber: page_number,
296
- pageSize: page_size,
297
- sort: 'name=asc'
298
- })
299
- parse_response(r, 'devices')
300
- end
301
- end
302
-
303
- def create_device!(device_name, device_id)
304
- r = request(:post) do |r|
305
- r.url "https://developerservices2.apple.com/services/#{PROTOCOL_VERSION}/ios/addDevice.action"
306
- r.params = {
307
- teamId: team_id,
308
- deviceNumber: device_id,
309
- name: device_name
310
- }
311
- end
312
-
313
- parse_response(r, 'device')
314
- end
315
-
316
- #####################################################
317
- # @!group Certificates
318
- #####################################################
319
-
320
- def certificates(types)
321
- paging do |page_number|
322
- r = request(:post, 'account/ios/certificate/listCertRequests.action', {
323
- teamId: team_id,
324
- types: types.join(','),
325
- pageNumber: page_number,
326
- pageSize: page_size,
327
- sort: 'certRequestStatusCode=asc'
328
- })
329
- parse_response(r, 'certRequests')
330
- end
331
- end
332
-
333
- def create_certificate!(type, csr, app_id = nil)
334
- r = request(:post, 'account/ios/certificate/submitCertificateRequest.action', {
335
- teamId: team_id,
336
- type: type,
337
- csrContent: csr,
338
- appIdId: app_id #optional
339
- })
340
- parse_response(r, 'certRequest')
341
- end
342
-
343
- def download_certificate(certificate_id, type)
344
- {type: type, certificate_id: certificate_id}.each { |k, v| raise "#{k} must not be nil" if v.nil? }
345
-
346
- r = request(:post, 'https://developer.apple.com/account/ios/certificate/certificateContentDownload.action', {
347
- teamId: team_id,
348
- displayId: certificate_id,
349
- type: type
350
- })
351
- parse_response(r)
352
- end
353
-
354
- def revoke_certificate!(certificate_id, type)
355
- r = request(:post, 'account/ios/certificate/revokeCertificate.action', {
356
- teamId: team_id,
357
- certificateId: certificate_id,
358
- type: type
359
- })
360
- parse_response(r, 'certRequests')
361
- end
362
-
363
- #####################################################
364
- # @!group Provisioning Profiles
365
- #####################################################
366
-
367
- def provisioning_profiles
368
- r = request(:post) do |r|
369
- r.url "https://developerservices2.apple.com/services/#{PROTOCOL_VERSION}/ios/listProvisioningProfiles.action"
370
- r.params = {
371
- teamId: team_id,
372
- includeInactiveProfiles: true,
373
- onlyCountLists: true,
374
- }
375
- end
376
-
377
- parse_response(r, 'provisioningProfiles')
378
- end
379
-
380
- def create_provisioning_profile!(name, distribution_method, app_id, certificate_ids, device_ids)
381
- r = request(:post, 'account/ios/profile/createProvisioningProfile.action', {
382
- teamId: team_id,
383
- provisioningProfileName: name,
384
- appIdId: app_id,
385
- distributionType: distribution_method,
386
- certificateIds: certificate_ids,
387
- deviceIds: device_ids
388
- })
389
- parse_response(r, 'provisioningProfile')
390
- end
391
-
392
- def download_provisioning_profile(profile_id)
393
- r = request(:get, 'https://developer.apple.com/account/ios/profile/profileContentDownload.action', {
394
- teamId: team_id,
395
- displayId: profile_id
396
- })
397
- parse_response(r)
398
- end
399
-
400
- def delete_provisioning_profile!(profile_id)
401
- r = request(:post, 'account/ios/profile/deleteProvisioningProfile.action', {
402
- teamId: team_id,
403
- provisioningProfileId: profile_id
404
- })
405
- parse_response(r)
406
- end
407
-
408
- def repair_provisioning_profile!(profile_id, name, distribution_method, app_id, certificate_ids, device_ids)
409
- r = request(:post, 'account/ios/profile/regenProvisioningProfile.action', {
410
- teamId: team_id,
411
- provisioningProfileId: profile_id,
412
- provisioningProfileName: name,
413
- appIdId: app_id,
414
- distributionType: distribution_method,
415
- certificateIds: certificate_ids.first, # we are most of the times only allowed to pass one
416
- deviceIds: device_ids
417
- })
418
-
419
- parse_response(r, 'provisioningProfile')
420
- end
421
-
422
156
  private
423
157
  # Is called from `parse_response` to store the latest csrf_token (if available)
424
158
  def store_csrf_tokens(response)
@@ -460,7 +194,8 @@ module Spaceship
460
194
 
461
195
  def log_request(method, url, params)
462
196
  params_to_log = Hash(params).dup # to also work with nil
463
- params_to_log.delete(:accountPassword)
197
+ params_to_log.delete(:accountPassword) # Dev Portal
198
+ params_to_log.delete(:theAccountPW) # iTC
464
199
  params_to_log = params_to_log.collect do |key, value|
465
200
  "{#{key}: #{value}}"
466
201
  end
@@ -19,7 +19,7 @@ module Spaceship
19
19
  #
20
20
  # @raise InvalidUserCredentialsError: raised if authentication failed
21
21
  def initialize(user = nil, password = nil)
22
- @client = Client.new
22
+ @client = PortalClient.new
23
23
 
24
24
  if user or password
25
25
  @client.login(user, password)
@@ -0,0 +1,125 @@
1
+ module Spaceship
2
+ module Portal
3
+ # Represents an App ID from the Developer Portal
4
+ class App < PortalBase
5
+
6
+ # @return (String) The identifier of this app, provided by the Dev Portal
7
+ # @example
8
+ # "RGAWZGXSAA"
9
+ attr_accessor :app_id
10
+
11
+ # @return (String) The name you provided for this app
12
+ # @example
13
+ # "Spaceship"
14
+ attr_accessor :name
15
+
16
+ # @return (String) the supported platform of this app
17
+ # @example
18
+ # "ios"
19
+ attr_accessor :platform
20
+
21
+ # Prefix provided by the Dev Portal
22
+ # @example
23
+ # "5A997XSHK2"
24
+ attr_accessor :prefix
25
+
26
+ # @return (String) The bundle_id (app identifier) of your app
27
+ # @example
28
+ # "com.krausefx.app"
29
+ attr_accessor :bundle_id
30
+
31
+ # @return (Bool) Is this app a wildcard app (e.g. com.krausefx.*)
32
+ attr_accessor :is_wildcard
33
+
34
+ # @return (Hash) Feature details
35
+ attr_accessor :features
36
+
37
+ # @return (Array) List of enabled features
38
+ attr_accessor :enabled_features
39
+
40
+ # @return (Bool) Development Push Enabled?
41
+ attr_accessor :dev_push_enabled
42
+
43
+ # @return (Bool) Production Push Enabled?
44
+ attr_accessor :prod_push_enabled
45
+
46
+ # @return (Fixnum) Number of associated app groups
47
+ attr_accessor :app_groups_count
48
+
49
+ # @return (Fixnum) Number of associated cloud containers
50
+ attr_accessor :cloud_containers_count
51
+
52
+ # @return (Fixnum) Number of associated identifiers
53
+ attr_accessor :identifiers_count
54
+
55
+ attr_mapping(
56
+ 'appIdId' => :app_id,
57
+ 'name' => :name,
58
+ 'appIdPlatform' => :platform,
59
+ 'prefix' => :prefix,
60
+ 'identifier' => :bundle_id,
61
+ 'isWildCard' => :is_wildcard,
62
+ 'features' => :features,
63
+ 'enabledFeatures' => :enabled_features,
64
+ 'isDevPushEnabled' => :dev_push_enabled,
65
+ 'isProdPushEnabled' => :prod_push_enabled,
66
+ 'associatedApplicationGroupsCount' => :app_groups_count,
67
+ 'associatedCloudContainersCount' => :cloud_containers_count,
68
+ 'associatedIdentifiersCount' => :identifiers_count
69
+ )
70
+
71
+ class << self
72
+ # Create a new object based on a hash.
73
+ # This is used to create a new object based on the server response.
74
+ def factory(attrs)
75
+ self.new(attrs)
76
+ end
77
+
78
+ # @return (Array) Returns all apps available for this account
79
+ def all
80
+ client.apps.map { |app| self.factory(app) }
81
+ end
82
+
83
+ # Creates a new App ID on the Apple Dev Portal
84
+ #
85
+ # if bundle_id ends with '*' then it is a wildcard id otherwise, it is an explicit id
86
+ # @param bundle_id [String] the bundle id (app_identifier) of the app associated with this provisioning profile
87
+ # @param name [String] the name of the App
88
+ # @return (App) The app you just created
89
+ def create!(bundle_id: nil, name: nil)
90
+ if bundle_id.end_with?('*')
91
+ type = :wildcard
92
+ else
93
+ type = :explicit
94
+ end
95
+
96
+ new_app = client.create_app!(type, name, bundle_id)
97
+ self.new(new_app)
98
+ end
99
+
100
+ # Find a specific App ID based on the bundle_id
101
+ # @return (App) The app you're looking for. This is nil if the app can't be found.
102
+ def find(bundle_id)
103
+ all.find do |app|
104
+ app.bundle_id == bundle_id
105
+ end
106
+ end
107
+ end
108
+
109
+ # Delete this App ID. This action will most likely fail if the App ID is already in the store
110
+ # or there are active profiles
111
+ # @return (App) The app you just deletd
112
+ def delete!
113
+ client.delete_app!(app_id)
114
+ self
115
+ end
116
+
117
+ # Fetch a specific App ID details based on the bundle_id
118
+ # @return (App) The app you're looking for. This is nil if the app can't be found.
119
+ def details
120
+ app = client.details_for_app(self)
121
+ self.class.factory(app)
122
+ end
123
+ end
124
+ end
125
+ end