spaceship 0.6.1 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 046dcf3de83d63e9e9d4feaeda5b09d8b409db1d
4
- data.tar.gz: fb112b2b56de7ac46c9f8e866a99df53f4bafe24
3
+ metadata.gz: cb67ea61ddcb8fc09c87de04eb400be6a4c0c9e2
4
+ data.tar.gz: c62c7bc6307daf12b7dd9a890c30241e633ec02c
5
5
  SHA512:
6
- metadata.gz: a3eefd3ccd0cdbce93caaa729e1286ad10c7975ec08925b7c99e419ccd7d1d3dfe8c3f77bcd75d492f66b2a568891518ecc96277a91217e06bdc865824e45ee8
7
- data.tar.gz: eefe43691c442b18bb53c990de69ebe28f876803bcbb010a492edf4e9d7893895fa6666039d368415a861c9359ac12d6f57f2b15a7ca678e5d0b3581e3d6708a
6
+ metadata.gz: 86c17cf18e9949250db8d312822188f2896ba4beff339fd949d876fc0e9bd4c2b017d58dc18bcade5a831682ab8f84cddcdd3d640cbf1fe4b2d22b33d7e7cb38
7
+ data.tar.gz: bd449519839313194d8128f72b6f1fa74f4a89b03293f35b33b692cf5e638d1014f03ccc01db8fb1dd73db8270dc4a77c5559f52f6f8182725f60ffa442766a7
data/lib/spaceship.rb CHANGED
@@ -10,7 +10,6 @@ require 'spaceship/portal/spaceship'
10
10
  # iTunes Connect
11
11
  require 'spaceship/tunes/tunes'
12
12
  require 'spaceship/tunes/spaceship'
13
- require 'spaceship/tunes/tester'
14
13
 
15
14
  # To support legacy code
16
15
  module Spaceship
@@ -45,7 +45,9 @@ module Spaceship
45
45
  end
46
46
 
47
47
  def to_json
48
- @hash.to_json
48
+ h = @hash.dup
49
+ h.delete(:application)
50
+ h.to_json
49
51
  end
50
52
  end
51
53
 
@@ -0,0 +1,107 @@
1
+ module Spaceship
2
+ module Tunes
3
+ class AppDetails < TunesBase
4
+ attr_accessor :application
5
+
6
+ ####
7
+ # Localized values
8
+ ####
9
+
10
+ # @return (Array) Raw access the all available languages. You shouldn't use it probbaly
11
+ attr_accessor :languages
12
+
13
+ # @return (Hash) A hash representing the app name in all languages
14
+ attr_reader :name
15
+
16
+ # @return (Hash) A hash representing the keywords in all languages
17
+ attr_reader :privacy_url
18
+
19
+ # Categories (e.g. MZGenre.Business)
20
+ attr_accessor :primary_category
21
+
22
+ attr_accessor :primary_first_sub_category
23
+
24
+ attr_accessor :primary_second_sub_category
25
+
26
+ attr_accessor :secondary_category
27
+
28
+ attr_accessor :secondary_first_sub_category
29
+
30
+ attr_accessor :secondary_second_sub_category
31
+
32
+ attr_mapping(
33
+ 'localizedMetadata.value' => :languages,
34
+ 'primaryCategory.value' => :primary_category,
35
+ 'primaryFirstSubCategory.value' => :primary_first_sub_category,
36
+ 'primarySecondSubCategory.value' => :primary_second_sub_category,
37
+ 'secondaryCategory.value' => :secondary_category,
38
+ 'secondaryFirstSubCategory.value' => :secondary_first_sub_category,
39
+ 'secondarySecondSubCategory.value' => :secondary_second_sub_category
40
+ )
41
+
42
+ class << self
43
+ # Create a new object based on a hash.
44
+ # This is used to create a new object based on the server response.
45
+ def factory(attrs)
46
+ obj = self.new(attrs)
47
+ obj.unfold_languages
48
+
49
+ return obj
50
+ end
51
+ end
52
+
53
+ # Prefill name, privacy url
54
+ def unfold_languages
55
+ {
56
+ name: :name,
57
+ privacyPolicyUrl: :privacy_url
58
+ }.each do |json, attribute|
59
+ instance_variable_set("@#{attribute}".to_sym, LanguageItem.new(json, languages))
60
+ end
61
+ end
62
+
63
+ # Push all changes that were made back to iTunes Connect
64
+ def save!
65
+ client.update_app_details!(application.apple_id, raw_data)
66
+ end
67
+
68
+ # Custom Setters
69
+ #
70
+ def primary_category=(value)
71
+ value = "MZGenre.#{value}" unless value.include? "MZGenre"
72
+ super(value)
73
+ end
74
+
75
+ def primary_first_sub_category=(value)
76
+ value = "MZGenre.#{value}" unless value.include? "MZGenre"
77
+ super(value)
78
+ end
79
+
80
+ def primary_second_sub_category=(value)
81
+ value = "MZGenre.#{value}" unless value.include? "MZGenre"
82
+ super(value)
83
+ end
84
+
85
+ def secondary_category=(value)
86
+ value = "MZGenre.#{value}" unless value.include? "MZGenre"
87
+ super(value)
88
+ end
89
+
90
+ def secondary_first_sub_category=(value)
91
+ value = "MZGenre.#{value}" unless value.include? "MZGenre"
92
+ super(value)
93
+ end
94
+
95
+ def secondary_second_sub_category=(value)
96
+ value = "MZGenre.#{value}" unless value.include? "MZGenre"
97
+ super(value)
98
+ end
99
+
100
+ #####################################################
101
+ # @!group General
102
+ #####################################################
103
+ def setup
104
+ end
105
+ end
106
+ end
107
+ end
@@ -20,19 +20,6 @@ module Spaceship
20
20
  # @return (Bool) Is that the version that's currently available in the App Store?
21
21
  attr_accessor :is_live
22
22
 
23
- # Categories (e.g. MZGenre.Business)
24
- attr_accessor :primary_category
25
-
26
- attr_accessor :primary_first_sub_category
27
-
28
- attr_accessor :primary_second_sub_category
29
-
30
- attr_accessor :secondary_category
31
-
32
- attr_accessor :secondary_first_sub_category
33
-
34
- attr_accessor :secondary_second_sub_category
35
-
36
23
  # @return (String) App Status (e.g. 'readyForSale'). You should use `app_status` instead
37
24
  attr_accessor :raw_status
38
25
 
@@ -100,9 +87,6 @@ module Spaceship
100
87
  # @return (Array) Raw access the all available languages. You shouldn't use it probbaly
101
88
  attr_accessor :languages
102
89
 
103
- # @return (Hash) A hash representing the app name in all languages
104
- attr_reader :name
105
-
106
90
  # @return (Hash) A hash representing the keywords in all languages
107
91
  attr_reader :keywords
108
92
 
@@ -112,9 +96,6 @@ module Spaceship
112
96
  # @return (Hash) The changelog
113
97
  attr_reader :release_notes
114
98
 
115
- # @return (Hash) A hash representing the keywords in all languages
116
- attr_reader :privacy_url
117
-
118
99
  # @return (Hash) A hash representing the keywords in all languages
119
100
  attr_reader :support_url
120
101
 
@@ -133,13 +114,7 @@ module Spaceship
133
114
  'details.value' => :languages,
134
115
  'largeAppIcon.value.originalFileName' => :app_icon_original_name,
135
116
  'largeAppIcon.value.url' => :app_icon_url,
136
- 'primaryCategory.value' => :primary_category,
137
- 'primaryFirstSubCategory.value' => :primary_first_sub_category,
138
- 'primarySecondSubCategory.value' => :primary_second_sub_category,
139
117
  'releaseOnApproval.value' => :release_on_approval,
140
- 'secondaryCategory.value' => :secondary_category,
141
- 'secondaryFirstSubCategory.value' => :secondary_first_sub_category,
142
- 'secondarySecondSubCategory.value' => :secondary_second_sub_category,
143
118
  'status' => :raw_status,
144
119
  'supportsAppleWatch' => :supports_apple_watch,
145
120
  'versionId' => :version_id,
@@ -169,9 +144,10 @@ module Spaceship
169
144
 
170
145
  # @param application (Spaceship::Tunes::Application) The app this version is for
171
146
  # @param app_id (String) The unique Apple ID of this app
172
- # @param is_live (Boolean) Is that the version that's live in the App Store?
173
- def find(application, app_id, is_live = false)
147
+ # @param is_live (Boolean)
148
+ def find(application, app_id, is_live)
174
149
  attrs = client.app_version(app_id, is_live)
150
+ return nil unless attrs
175
151
  attrs.merge!(application: application)
176
152
  attrs.merge!(is_live: is_live)
177
153
 
@@ -226,7 +202,9 @@ module Spaceship
226
202
 
227
203
  # @return (String) An URL to this specific resource. You can enter this URL into your browser
228
204
  def url
229
- "https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app/#{self.application.apple_id}/" + (self.is_live? ? "cur" : "")
205
+ url = "https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app/904332168/ios/versioninfo/"
206
+ url += "deliverable" if self.is_live?
207
+ return url
230
208
  end
231
209
 
232
210
  # Private methods
@@ -246,10 +224,8 @@ module Spaceship
246
224
  # Prefill name, keywords, etc...
247
225
  def unfold_languages
248
226
  {
249
- name: :name,
250
227
  keywords: :keywords,
251
228
  description: :description,
252
- privacyURL: :privacy_url,
253
229
  supportURL: :support_url,
254
230
  marketingURL: :marketing_url,
255
231
  releaseNotes: :release_notes
@@ -268,36 +244,6 @@ module Spaceship
268
244
  !super.nil?
269
245
  end
270
246
 
271
- def primary_category=(value)
272
- value = "MZGenre.#{value}" unless value.include? "MZGenre"
273
- super(value)
274
- end
275
-
276
- def primary_first_sub_category=(value)
277
- value = "MZGenre.#{value}" unless value.include? "MZGenre"
278
- super(value)
279
- end
280
-
281
- def primary_second_sub_category=(value)
282
- value = "MZGenre.#{value}" unless value.include? "MZGenre"
283
- super(value)
284
- end
285
-
286
- def secondary_category=(value)
287
- value = "MZGenre.#{value}" unless value.include? "MZGenre"
288
- super(value)
289
- end
290
-
291
- def secondary_first_sub_category=(value)
292
- value = "MZGenre.#{value}" unless value.include? "MZGenre"
293
- super(value)
294
- end
295
-
296
- def secondary_second_sub_category=(value)
297
- value = "MZGenre.#{value}" unless value.include? "MZGenre"
298
- super(value)
299
- end
300
-
301
247
  private
302
248
 
303
249
  # generates the nested data structure to represent screenshots
@@ -55,7 +55,7 @@ module Spaceship
55
55
  # Create a new object based on a hash.
56
56
  # This is used to create a new object based on the server response.
57
57
  def factory(attrs)
58
- self.new(attrs)
58
+ return self.new(attrs)
59
59
  end
60
60
 
61
61
  # @return (Array) Returns all apps available for this account
@@ -101,16 +101,24 @@ module Spaceship
101
101
  # @return (Spaceship::AppVersion) Receive the version that is currently live on the
102
102
  # App Store. You can't modify all values there, so be careful.
103
103
  def live_version
104
+ if raw_data['versions'].count == 1
105
+ v = raw_data['versions'].last
106
+ if ['Prepare for Upload', 'prepareForUpload'].include?(v['state']) # this only applies for the initial version
107
+ return nil
108
+ end
109
+ end
110
+
104
111
  Spaceship::AppVersion.find(self, self.apple_id, true)
105
112
  end
106
113
 
107
114
  # @return (Spaceship::AppVersion) Receive the version that can fully be edited
108
115
  def edit_version
109
- # Apple's server will respond with the same version if there is only one, for both v=live and v=
110
- # That's why we have to check in the app_summary.json request if there are 2 versions or just one
111
- # if there is only one version, we'll return nil
112
116
  if raw_data['versions'].count == 1
113
- return nil # only live version, user should create a new version
117
+ v = raw_data['versions'].last
118
+
119
+ unless ['Prepare for Upload', 'prepareForUpload'].include?(v['state']) # this only applies for the initial version
120
+ return nil # only live version, user should create a new version
121
+ end
114
122
  end
115
123
 
116
124
  Spaceship::AppVersion.find(self, self.apple_id, false)
@@ -134,6 +142,12 @@ module Spaceship
134
142
  client.get_resolution_center(apple_id)
135
143
  end
136
144
 
145
+ def details
146
+ attrs = client.app_details(apple_id)
147
+ attrs.merge!(application: self)
148
+ Tunes::AppDetails.factory(attrs)
149
+ end
150
+
137
151
  #####################################################
138
152
  # @!group Modifying
139
153
  #####################################################
@@ -165,7 +179,7 @@ module Spaceship
165
179
  # These are all build that have no information except the upload date
166
180
  # Those builds can also be the builds that are stuck on iTC.
167
181
  def pre_processing_builds
168
- data = client.build_trains(apple_id) # we need to fetch all trains here to get the builds
182
+ data = client.build_trains(apple_id, 'internal') # we need to fetch all trains here to get the builds
169
183
 
170
184
  builds = data.fetch('processingBuilds', []).collect do |attrs|
171
185
  attrs.merge!(build_train: self)
@@ -40,9 +40,11 @@ module Spaceship
40
40
  # @return (Integer): When is the external build going to expire?
41
41
  attr_accessor :external_expiry_date
42
42
 
43
- # @return (Boolean): Is this build available for external beta testing
44
- # this is only true after the build was approved by Apple
45
- attr_accessor :external_testing_enabled
43
+ # @return (Bool) Is external beta testing enabled for this train? Only one train can have enabled testing.
44
+ attr_reader :external_testing_enabled
45
+
46
+ # @return (Bool) Is internal beta testing enabled for this train? Only one train can have enabled testing.
47
+ attr_reader :internal_testing_enabled
46
48
 
47
49
  # @return (Bool) Does this build support WatchKit?
48
50
  attr_accessor :watch_kit_enabled
@@ -87,7 +89,9 @@ module Spaceship
87
89
  'internalExpiry' => :internal_expiry_date,
88
90
  'externalExpiry' => :external_expiry_date,
89
91
  'watchKitEnabled' => :watch_kit_enabled,
90
- 'readyToInstall' => :ready_to_install
92
+ 'readyToInstall' => :ready_to_install,
93
+ 'internalTesting.value' => :internal_testing_enabled,
94
+ 'externalTesting.value' => :external_testing_enabled
91
95
  )
92
96
 
93
97
  class << self
@@ -102,7 +106,7 @@ module Spaceship
102
106
  super
103
107
 
104
108
  self.external_expiry_date ||= 0
105
- @external_testing_enabled = self.external_expiry_date > 0
109
+ self.internal_expiry_date ||= 0
106
110
  end
107
111
 
108
112
  # This will submit this build for TestFlight beta review
@@ -127,7 +131,7 @@ module Spaceship
127
131
  # }
128
132
  def submit_for_beta_review!(metadata)
129
133
  # First, enable beta testing for this train (per iTC requirement)
130
- self.build_train.update_testing_status!(true)
134
+ self.build_train.update_testing_status!(true, 'external')
131
135
 
132
136
  parameters = {
133
137
  app_id: self.build_train.application.apple_id,
@@ -160,14 +164,8 @@ module Spaceship
160
164
  # @examples:
161
165
  # External, Internal, Inactive, Expired
162
166
  def testing_status
163
- testing ||= "External" if self.external_expiry_date > 0
164
-
165
- if self.build_train.testing_enabled
166
- # only the latest build is actually valid
167
- if self.build_train.builds.find_all { |b| b.upload_date > self.upload_date }.count == 0
168
- testing ||= "Internal"
169
- end
170
- end
167
+ testing ||= "External" if self.external_testing_enabled
168
+ testing ||= "Internal" if self.internal_testing_enabled
171
169
 
172
170
  if Time.at(self.internal_expiry_date / 1000) > Time.now
173
171
  testing ||= "Inactive"
@@ -188,36 +186,49 @@ module Spaceship
188
186
  end
189
187
  end
190
188
 
191
- # Example response
192
- # "buildVersion": "0.9.10",
193
- # "trainVersion": "0.9.10",
194
- # "uploadDate": 1413966436000,
195
- # "iconUrl": "https://is5-ssl.mzstatic.com/image/thumb/Newsstand5/v4/e8/ab/f8/e8abf8ca-6c22-a519-aa1b-c73901c4917e/Icon-60@2x.png.png/150x150bb-80.png",
196
- # "appName": "Yeahaa",
197
- # "platform": "ios",
198
- # "betaEntitled": false,
199
- # "id": 523299,
200
- # "valid": true,
201
- # "missingExportCompliance": false,
202
- # "waitingForExportComplianceApproval": false,
203
- # "addedInternalUsersCount": 0,
204
- # "addedExternalUsersCount": 0,
205
- # "invitedExternalUsersCount": 0,
206
- # "invitedInternalUsersCount": 0,
207
- # "acceptedInternalUsersCount": 0,
208
- # "acceptedExternalUsersCount": 0,
209
- # "installCount": 0,
210
- # "internalInstallCount": 0,
211
- # "externalInstallCount": 0,
212
- # "sessionCount": null,
213
- # "crashCount": null,
214
- # "promotedVersion": null,
215
- # "internalState": "noBetaEntitlement",
216
- # "betaState": "noBetaEntitlement",
217
- # "internalExpiry": 1416562036000,
218
- # "externalExpiry": 0,
219
- # "watchKitEnabled": false,
220
- # "readyToInstall": false,
221
- # "sdkBuildWhitelisted": true,
222
- # "internalTesting": null,
223
- # "externalTesting": null
189
+ # Example Response
190
+ # {"sectionErrorKeys"=>[],
191
+ # "sectionInfoKeys"=>[],
192
+ # "sectionWarningKeys"=>[],
193
+ # "buildVersion"=>"1",
194
+ # "trainVersion"=>"1.0",
195
+ # "uploadDate"=>1441975590000,
196
+ # "iconUrl"=>
197
+ # "https://is2-ssl.mzstatic.com/image/thumb/Newsstand3/v4/a9/f9/8b/a9f98b23-592d-af2e-6e10-a04873bed5df/Icon-76@2x.png.png/150x150bb-80.png",
198
+ # "iconAssetToken"=>
199
+ # "Newsstand3/v4/a9/f9/8b/a9f98b23-592d-af2e-6e10-a04873bed5df/Icon-76@2x.png.png",
200
+ # "appName"=>"Updated by fastlane",
201
+ # "platform"=>"ios",
202
+ # "betaEntitled"=>true,
203
+ # "exceededFileSizeLimit"=>false,
204
+ # "wentLiveWithVersion"=>false,
205
+ # "processing"=>false,
206
+ # "id"=>5298023,
207
+ # "valid"=>true,
208
+ # "missingExportCompliance"=>false,
209
+ # "waitingForExportComplianceApproval"=>false,
210
+ # "addedInternalUsersCount"=>0,
211
+ # "addedExternalUsersCount"=>0,
212
+ # "invitedExternalUsersCount"=>0,
213
+ # "invitedInternalUsersCount"=>0,
214
+ # "acceptedInternalUsersCount"=>1,
215
+ # "acceptedExternalUsersCount"=>0,
216
+ # "installCount"=>0,
217
+ # "internalInstallCount"=>0,
218
+ # "externalInstallCount"=>0,
219
+ # "sessionCount"=>0,
220
+ # "internalSessionCount"=>0,
221
+ # "externalSessionCount"=>0,
222
+ # "crashCount"=>0,
223
+ # "internalCrashCount"=>0,
224
+ # "externalCrashCount"=>0,
225
+ # "promotedVersion"=>nil,
226
+ # "internalState"=>"inactive",
227
+ # "betaState"=>"submitForReview",
228
+ # "internalExpiry"=>1444567590000,
229
+ # "externalExpiry"=>0,
230
+ # "watchKitEnabled"=>false,
231
+ # "readyToInstall"=>true,
232
+ # "sdkBuildWhitelisted"=>true,
233
+ # "internalTesting"=>{"value"=>false, "isEditable"=>true, "isRequired"=>false, "errorKeys"=>nil},
234
+ # "externalTesting"=>{"value"=>false, "isEditable"=>true, "isRequired"=>false, "errorKeys"=>nil}
@@ -17,8 +17,11 @@ module Spaceship
17
17
  # @return (String) Platform (e.g. "ios")
18
18
  attr_reader :platform
19
19
 
20
- # @return (Bool) Is beta testing enabled for this train? Only one train can have enabled testing.
21
- attr_reader :testing_enabled
20
+ # @return (Bool) Is external beta testing enabled for this train? Only one train can have enabled testing.
21
+ attr_reader :external_testing_enabled
22
+
23
+ # @return (Bool) Is internal beta testing enabled for this train? Only one train can have enabled testing.
24
+ attr_reader :internal_testing_enabled
22
25
 
23
26
  # @return (Array) An array of all builds that are inside this train (Spaceship::Tunes::Build)
24
27
  # I never got this to work to properly try and debug this
@@ -27,7 +30,8 @@ module Spaceship
27
30
  attr_mapping(
28
31
  'versionString' => :version_string,
29
32
  'platform' => :platform,
30
- 'testing.value' => :testing_enabled
33
+ 'externalTesting.value' => :external_testing_enabled,
34
+ 'internalTesting.value' => :internal_testing_enabled
31
35
  )
32
36
 
33
37
  class << self
@@ -40,9 +44,12 @@ module Spaceship
40
44
  # @param application (Spaceship::Tunes::Application) The app this train is for
41
45
  # @param app_id (String) The unique Apple ID of this app
42
46
  def all(application, app_id)
43
- data = client.build_trains(app_id)
47
+ trains = []
48
+ trains += client.build_trains(app_id, 'internal')['trains']
49
+ trains += client.build_trains(app_id, 'external')['trains']
50
+
44
51
  result = {}
45
- data['trains'].each do |attrs|
52
+ trains.each do |attrs|
46
53
  attrs.merge!(application: application)
47
54
  current = self.factory(attrs)
48
55
  result[current.version_string] = current
@@ -66,14 +73,19 @@ module Spaceship
66
73
  end
67
74
  end
68
75
 
69
- def update_testing_status!(new_value)
70
- data = client.build_trains(self.application.apple_id)
76
+ # @param (testing_type) internal or external
77
+ def update_testing_status!(new_value, testing_type)
78
+ data = client.build_trains(self.application.apple_id, testing_type)
79
+
71
80
  data['trains'].each do |train|
72
- train['testing']['value'] = false
73
- train['testing']['value'] = new_value if train['versionString'] == version_string
81
+ train["#{testing_type}Testing"]['value'] = false
82
+ train["#{testing_type}Testing"]['value'] = new_value if train['versionString'] == version_string
74
83
  end
75
- result = client.update_build_trains!(application.apple_id, data)
76
- self.testing_enabled = new_value
84
+
85
+ result = client.update_build_trains!(application.apple_id, testing_type, data)
86
+ self.internal_testing_enabled = new_value if testing_type == 'internal'
87
+ self.external_testing_enabled = new_value if testing_type == 'external'
88
+
77
89
  result
78
90
  end
79
91
  end
@@ -6,6 +6,8 @@ module Spaceship
6
6
  attr_accessor :original_array # reference to original array
7
7
 
8
8
  def initialize(identifier, ref)
9
+ raise "ref is nil" if ref.nil?
10
+
9
11
  self.identifier = identifier.to_s
10
12
  self.original_array = ref
11
13
  end
@@ -20,7 +22,7 @@ module Spaceship
20
22
 
21
23
  def get_lang(lang)
22
24
  result = self.original_array.find do |current|
23
- current['language'] == lang
25
+ current['language'] == lang or current['localeCode'] == lang # Apple being consistent
24
26
  end
25
27
  return result if result
26
28
 
@@ -10,3 +10,5 @@ require 'spaceship/tunes/language_converter'
10
10
  require 'spaceship/tunes/build'
11
11
  require 'spaceship/tunes/processing_build'
12
12
  require 'spaceship/tunes/build_train'
13
+ require 'spaceship/tunes/tester'
14
+ require 'spaceship/tunes/app_details'
@@ -6,6 +6,12 @@ module Spaceship
6
6
  class ITunesConnectError < StandardError
7
7
  end
8
8
 
9
+ # ITunesConnectNoChangesError is thrown when the only error is that there were no changes
10
+ # usually those errors are irrelevant
11
+ class ITunesConnectNoChangesError < ITunesConnectError
12
+
13
+ end
14
+
9
15
  #####################################################
10
16
  # @!group Init and Login
11
17
  #####################################################
@@ -75,6 +81,8 @@ module Spaceship
75
81
  end
76
82
  end
77
83
 
84
+ # rubocop:disable Metrics/CyclomaticComplexity
85
+ # rubocop:disable Metrics/PerceivedComplexity
78
86
  def handle_itc_response(raw)
79
87
  return unless raw
80
88
  return unless raw.kind_of? Hash
@@ -116,7 +124,12 @@ module Spaceship
116
124
  errors << different_error if different_error
117
125
 
118
126
  if errors.count > 0 # they are separated by `.` by default
119
- raise ITunesConnectError.new, errors.join(' ')
127
+ if errors.count == 1 and errors.first == "You haven't made any changes."
128
+ # This is a special error for which we throw a separate exception
129
+ raise ITunesConnectNoChangesError.new, errors.first
130
+ else
131
+ raise ITunesConnectError.new, errors.join(' ')
132
+ end
120
133
  end
121
134
 
122
135
  puts data['sectionInfoKeys'] if data['sectionInfoKeys']
@@ -124,16 +137,33 @@ module Spaceship
124
137
 
125
138
  return data
126
139
  end
140
+ # rubocop:enable Metrics/CyclomaticComplexity
141
+ # rubocop:enable Metrics/PerceivedComplexity
127
142
 
128
143
  #####################################################
129
144
  # @!group Applications
130
145
  #####################################################
131
146
 
132
147
  def applications
133
- r = request(:get, 'ra/apps/manageyourapps/summary')
148
+ r = request(:get, 'ra/apps/manageyourapps/summary/v2')
134
149
  parse_response(r, 'data')['summaries']
135
150
  end
136
151
 
152
+ def app_details(app_id)
153
+ r = request(:get, "ra/apps/#{app_id}/details")
154
+ parse_response(r, 'data')
155
+ end
156
+
157
+ def update_app_details!(app_id, data)
158
+ r = request(:post) do |req|
159
+ req.url "ra/apps/#{app_id}/details"
160
+ req.body = data.to_json
161
+ req.headers['Content-Type'] = 'application/json'
162
+ end
163
+
164
+ handle_itc_response(r.body)
165
+ end
166
+
137
167
  # Creates a new application on iTunes Connect
138
168
  # @param name (String): The name of your app as it will appear on the App Store.
139
169
  # This can't be longer than 255 characters.
@@ -146,21 +176,27 @@ module Spaceship
146
176
  # can't be changed after you submit your first build.
147
177
  def create_application!(name: nil, primary_language: nil, version: nil, sku: nil, bundle_id: nil, bundle_id_suffix: nil, company_name: nil)
148
178
  # First, we need to fetch the data from Apple, which we then modify with the user's values
149
- r = request(:get, 'ra/apps/create/?appType=ios')
179
+ app_type = 'ios'
180
+ r = request(:get, "ra/apps/create/v2/?platformString=#{app_type}")
150
181
  data = parse_response(r, 'data')
151
182
 
152
183
  # Now fill in the values we have
153
- data['versionString']['value'] = version
154
- data['newApp']['name']['value'] = name
184
+ # some values are nil, that's why there is a hash
185
+ data['versionString'] = { value: version }
186
+ data['newApp']['name'] = { value: name }
155
187
  data['newApp']['bundleId']['value'] = bundle_id
156
188
  data['newApp']['primaryLanguage']['value'] = primary_language || 'English'
157
- data['newApp']['vendorId']['value'] = sku
189
+ data['newApp']['vendorId'] = {value: sku }
158
190
  data['newApp']['bundleIdSuffix']['value'] = bundle_id_suffix
159
191
  data['companyName']['value'] = company_name if company_name
192
+ data['newApp']['appType'] = app_type
193
+
194
+ data['initialPlatform'] = app_type
195
+ data['enabledPlatformsForCreation']['value'] = [app_type]
160
196
 
161
197
  # Now send back the modified hash
162
198
  r = request(:post) do |req|
163
- req.url 'ra/apps/create/?appType=ios'
199
+ req.url 'ra/apps/create/v2'
164
200
  req.body = data.to_json
165
201
  req.headers['Content-Type'] = 'application/json'
166
202
  end
@@ -191,9 +227,17 @@ module Spaceship
191
227
  def app_version(app_id, is_live)
192
228
  raise "app_id is required" unless app_id
193
229
 
194
- v_text = (is_live ? 'live' : nil)
230
+ # First we need to fetch the IDs for the edit / live version
231
+ r = request(:get, "ra/apps/#{app_id}/overview")
232
+ platforms = parse_response(r, 'data')['platforms']
233
+
234
+ platforms = platforms.first # That won't work for mac apps
195
235
 
196
- r = request(:get, "ra/apps/version/#{app_id}", {v: v_text})
236
+ version = platforms[(is_live ? 'deliverableVersion' : 'inFlightVersion')]
237
+ return nil unless version
238
+ version_id = version['id']
239
+
240
+ r = request(:get, "ra/apps/#{app_id}/platforms/ios/versions/#{version_id}")
197
241
  parse_response(r, 'data')
198
242
  end
199
243
 
@@ -215,18 +259,18 @@ module Spaceship
215
259
  # @!group Build Trains
216
260
  #####################################################
217
261
 
218
- def build_trains(app_id)
262
+ # @param (testing_type) internal or external
263
+ def build_trains(app_id, testing_type)
219
264
  raise "app_id is required" unless app_id
220
-
221
- r = request(:get, "ra/apps/#{app_id}/trains/")
265
+ r = request(:get, "ra/apps/#{app_id}/trains/?testingType=#{testing_type}")
222
266
  parse_response(r, 'data')
223
267
  end
224
268
 
225
- def update_build_trains!(app_id, data)
269
+ def update_build_trains!(app_id, testing_type, data)
226
270
  raise "app_id is required" unless app_id
227
271
 
228
272
  r = request(:post) do |req|
229
- req.url "ra/apps/#{app_id}/trains/"
273
+ req.url "ra/apps/#{app_id}/testingTypes/#{testing_type}/trains/"
230
274
  req.body = data.to_json
231
275
  req.headers['Content-Type'] = 'application/json'
232
276
  end
@@ -1,3 +1,3 @@
1
1
  module Spaceship
2
- VERSION = "0.6.1"
2
+ VERSION = "0.7.0"
3
3
  end
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.6.1
4
+ version: 0.7.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: 2015-09-08 00:00:00.000000000 Z
12
+ date: 2015-09-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: credentials_manager
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 0.8.0
20
+ version: 0.8.1
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: 0.8.0
27
+ version: 0.8.1
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: multi_xml
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -251,6 +251,7 @@ files:
251
251
  - lib/spaceship/portal/provisioning_profile.rb
252
252
  - lib/spaceship/portal/spaceship.rb
253
253
  - lib/spaceship/portal/ui/select_team.rb
254
+ - lib/spaceship/tunes/app_details.rb
254
255
  - lib/spaceship/tunes/app_screenshot.rb
255
256
  - lib/spaceship/tunes/app_status.rb
256
257
  - lib/spaceship/tunes/app_submission.rb
@@ -288,7 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
288
289
  version: '0'
289
290
  requirements: []
290
291
  rubyforge_project:
291
- rubygems_version: 2.4.5
292
+ rubygems_version: 2.4.6
292
293
  signing_key:
293
294
  specification_version: 4
294
295
  summary: Because you would rather spend your time building stuff than fighting provisioning