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.
- checksums.yaml +4 -4
- data/lib/assets/languageMapping.json +224 -0
- data/lib/spaceship.rb +20 -63
- data/lib/spaceship/base.rb +71 -14
- data/lib/spaceship/client.rb +9 -274
- data/lib/spaceship/launcher.rb +1 -1
- data/lib/spaceship/portal/app.rb +125 -0
- data/lib/spaceship/portal/certificate.rb +273 -0
- data/lib/spaceship/portal/device.rb +102 -0
- data/lib/spaceship/portal/portal.rb +6 -0
- data/lib/spaceship/portal/portal_base.rb +13 -0
- data/lib/spaceship/portal/portal_client.rb +289 -0
- data/lib/spaceship/portal/provisioning_profile.rb +369 -0
- data/lib/spaceship/portal/spaceship.rb +94 -0
- data/lib/spaceship/{ui → portal/ui}/select_team.rb +0 -0
- data/lib/spaceship/tunes/app_screenshot.rb +28 -0
- data/lib/spaceship/tunes/app_status.rb +63 -0
- data/lib/spaceship/tunes/app_submission.rb +149 -0
- data/lib/spaceship/tunes/app_version.rb +337 -0
- data/lib/spaceship/tunes/application.rb +253 -0
- data/lib/spaceship/tunes/build.rb +128 -0
- data/lib/spaceship/tunes/build_train.rb +79 -0
- data/lib/spaceship/tunes/language_converter.rb +44 -0
- data/lib/spaceship/tunes/language_item.rb +54 -0
- data/lib/spaceship/tunes/processing_build.rb +30 -0
- data/lib/spaceship/tunes/spaceship.rb +26 -0
- data/lib/spaceship/tunes/tester.rb +177 -0
- data/lib/spaceship/tunes/tunes.rb +12 -0
- data/lib/spaceship/tunes/tunes_base.rb +15 -0
- data/lib/spaceship/tunes/tunes_client.rb +360 -0
- data/lib/spaceship/version.rb +1 -1
- metadata +27 -7
- data/lib/spaceship/app.rb +0 -125
- data/lib/spaceship/certificate.rb +0 -271
- data/lib/spaceship/device.rb +0 -100
- data/lib/spaceship/provisioning_profile.rb +0 -367
@@ -0,0 +1,253 @@
|
|
1
|
+
module Spaceship
|
2
|
+
module Tunes
|
3
|
+
class Application < TunesBase
|
4
|
+
|
5
|
+
# @return (String) The App identifier of this app, provided by iTunes Connect
|
6
|
+
# @example
|
7
|
+
# "1013943394"
|
8
|
+
attr_accessor :apple_id
|
9
|
+
|
10
|
+
# @return (String) The name you provided for this app (in the default language)
|
11
|
+
# @example
|
12
|
+
# "Spaceship App"
|
13
|
+
attr_accessor :name
|
14
|
+
|
15
|
+
# @return (String) the supported platform of this app
|
16
|
+
# @example
|
17
|
+
# "ios"
|
18
|
+
attr_accessor :platform
|
19
|
+
|
20
|
+
# @return (String) The Vendor ID provided by iTunes Connect
|
21
|
+
# @example
|
22
|
+
# "1435592086"
|
23
|
+
attr_accessor :vendor_id
|
24
|
+
|
25
|
+
# @return (String) The bundle_id (app identifier) of your app
|
26
|
+
# @example
|
27
|
+
# "com.krausefx.app"
|
28
|
+
attr_accessor :bundle_id
|
29
|
+
|
30
|
+
# @return (String) Last modified
|
31
|
+
attr_accessor :last_modified
|
32
|
+
|
33
|
+
# @return (Integer) The number of issues provided by iTunes Connect
|
34
|
+
attr_accessor :issues_count
|
35
|
+
|
36
|
+
# @return (String) The URL to a low resolution app icon of this app (340x340px). Might be nil
|
37
|
+
# @example
|
38
|
+
# "https://is1-ssl.mzstatic.com/image/thumb/Purple7/v4/cd/a3/e2/cda3e2ac-4034-c6af-ee0c-3e4d9a0bafaa/pr_source.png/340x340bb-80.png"
|
39
|
+
# @example
|
40
|
+
# nil
|
41
|
+
attr_accessor :app_icon_preview_url
|
42
|
+
|
43
|
+
# @return [Array] A list of binaries which are not even yet processing based on the version
|
44
|
+
# Those builds are usually the ones that are just stuck on iTunes Connect...
|
45
|
+
attr_accessor :pre_processing_builds
|
46
|
+
|
47
|
+
attr_mapping(
|
48
|
+
'adamId' => :apple_id,
|
49
|
+
'name' => :name,
|
50
|
+
'appType' => :platform,
|
51
|
+
'vendorId' => :vendor_id,
|
52
|
+
'bundleId' => :bundle_id,
|
53
|
+
'lastModifiedDate' => :last_modified,
|
54
|
+
'issuesCount' => :issues_count,
|
55
|
+
'iconUrl' => :app_icon_preview_url
|
56
|
+
)
|
57
|
+
|
58
|
+
class << self
|
59
|
+
# Create a new object based on a hash.
|
60
|
+
# This is used to create a new object based on the server response.
|
61
|
+
def factory(attrs)
|
62
|
+
self.new(attrs)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return (Array) Returns all apps available for this account
|
66
|
+
def all
|
67
|
+
client.applications.map { |application| self.factory(application) }
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return (Spaceship::Tunes::Application) Returns the application matching the parameter
|
71
|
+
# as either the App ID or the bundle identifier
|
72
|
+
def find(identifier)
|
73
|
+
all.find do |app|
|
74
|
+
(app.apple_id == identifier.to_s or app.bundle_id == identifier)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates a new application on iTunes Connect
|
79
|
+
# @param name (String): The name of your app as it will appear on the App Store.
|
80
|
+
# This can't be longer than 255 characters.
|
81
|
+
# @param primary_language (String): If localized app information isn't available in an
|
82
|
+
# App Store territory, the information from your primary language will be used instead.
|
83
|
+
# @param version (String): The version number is shown on the App Store and should
|
84
|
+
# match the one you used in Xcode.
|
85
|
+
# @param sku (String): A unique ID for your app that is not visible on the App Store.
|
86
|
+
# @param bundle_id (String): The bundle ID must match the one you used in Xcode. It
|
87
|
+
# can't be changed after you submit your first build.
|
88
|
+
def create!(name: nil, primary_language: nil, version: nil, sku: nil, bundle_id: nil, bundle_id_suffix: nil)
|
89
|
+
client.create_application!(name: name,
|
90
|
+
primary_language: primary_language,
|
91
|
+
version: version,
|
92
|
+
sku: sku,
|
93
|
+
bundle_id: bundle_id,
|
94
|
+
bundle_id_suffix: bundle_id_suffix)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
#####################################################
|
99
|
+
# @!group Getting information
|
100
|
+
#####################################################
|
101
|
+
|
102
|
+
# @return (Spaceship::AppVersion) Receive the version that is currently live on the
|
103
|
+
# App Store. You can't modify all values there, so be careful.
|
104
|
+
def live_version
|
105
|
+
v = Spaceship::AppVersion.find(self, self.apple_id, true)
|
106
|
+
end
|
107
|
+
|
108
|
+
# @return (Spaceship::AppVersion) Receive the version that can fully be edited
|
109
|
+
def edit_version
|
110
|
+
# Apple's server will respond with the same version if there is only one, for both v=live and v=
|
111
|
+
# That's why we have to check in the app_summary.json request if there are 2 versions or just one
|
112
|
+
# if there is only one version, we'll return nil
|
113
|
+
if raw_data['versions'].count == 1
|
114
|
+
return nil # only live version, user should create a new version
|
115
|
+
end
|
116
|
+
|
117
|
+
Spaceship::AppVersion.find(self, self.apple_id, false)
|
118
|
+
end
|
119
|
+
|
120
|
+
# @return (Spaceship::AppVersion) This will return the `edit_version` if available
|
121
|
+
# and fallback to the `edit_version`. Use this to just access the latest data
|
122
|
+
def latest_version
|
123
|
+
edit_version || live_version
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return (String) An URL to this specific resource. You can enter this URL into your browser
|
127
|
+
def url
|
128
|
+
"https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/ra/ng/app/#{self.apple_id}"
|
129
|
+
end
|
130
|
+
|
131
|
+
# @return (Hash) Contains the reason for rejection.
|
132
|
+
# if everything is alright, the result will be
|
133
|
+
# `{"sectionErrorKeys"=>[], "sectionInfoKeys"=>[], "sectionWarningKeys"=>[], "replyConstraints"=>{"minLength"=>1, "maxLength"=>4000}, "appNotes"=>{"threads"=>[]}, "betaNotes"=>{"threads"=>[]}, "appMessages"=>{"threads"=>[]}}`
|
134
|
+
def resolution_center
|
135
|
+
client.get_resolution_center(apple_id)
|
136
|
+
end
|
137
|
+
|
138
|
+
#####################################################
|
139
|
+
# @!group Modifying
|
140
|
+
#####################################################
|
141
|
+
|
142
|
+
# Create a new version of your app
|
143
|
+
def create_version!(version_number)
|
144
|
+
if edit_version
|
145
|
+
raise "Cannot create a new version for this app as there already is an `edit_version` available"
|
146
|
+
end
|
147
|
+
|
148
|
+
client.create_version!(apple_id, version_number)
|
149
|
+
|
150
|
+
# Since we have stored the outdated raw_data, we need to refresh this object
|
151
|
+
# otherwise `edit_version` will return nil
|
152
|
+
# TODO: implemented -reload method
|
153
|
+
end
|
154
|
+
|
155
|
+
#####################################################
|
156
|
+
# @!group Builds
|
157
|
+
#####################################################
|
158
|
+
|
159
|
+
# A reference to all the build trains
|
160
|
+
# @return [Hash] a hash, the version number being the key
|
161
|
+
def build_trains
|
162
|
+
Tunes::BuildTrain.all(self, self.apple_id)
|
163
|
+
end
|
164
|
+
|
165
|
+
def pre_processing_builds
|
166
|
+
data = client.build_trains(apple_id) # we need to fetch all trains here to get the builds
|
167
|
+
|
168
|
+
data.fetch('processingBuilds', []).collect do |attrs|
|
169
|
+
attrs.merge!(build_train: self)
|
170
|
+
Tunes::ProcessingBuild.factory(attrs)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
#####################################################
|
175
|
+
# @!group Submit for Review
|
176
|
+
#####################################################
|
177
|
+
|
178
|
+
def create_submission
|
179
|
+
version = self.latest_version
|
180
|
+
if version.nil?
|
181
|
+
raise "Could not find a valid version to submit for review"
|
182
|
+
end
|
183
|
+
|
184
|
+
Spaceship::AppSubmission.create(self, self.apple_id, version)
|
185
|
+
end
|
186
|
+
|
187
|
+
#####################################################
|
188
|
+
# @!group General
|
189
|
+
#####################################################
|
190
|
+
def setup
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
#####################################################
|
195
|
+
# @!group Testers
|
196
|
+
#####################################################
|
197
|
+
|
198
|
+
# Add all testers (internal and external) to the current app list
|
199
|
+
def add_all_testers!
|
200
|
+
Tunes::Tester.external.add_all_to_app!(self.apple_id)
|
201
|
+
Tunes::Tester.internal.add_all_to_app!(self.apple_id)
|
202
|
+
end
|
203
|
+
|
204
|
+
# @return (Array) Returns all external testers available for this app
|
205
|
+
def external_testers
|
206
|
+
Tunes::Tester.external.all_by_app(self.apple_id)
|
207
|
+
end
|
208
|
+
|
209
|
+
# @return (Array) Returns all internal testers available for this app
|
210
|
+
def internal_testers
|
211
|
+
Tunes::Tester.internal.all_by_app(self.apple_id)
|
212
|
+
end
|
213
|
+
|
214
|
+
# @return (Spaceship::Tunes::Tester.external) Returns the external tester matching the parameter
|
215
|
+
# as either the Tester id or email
|
216
|
+
# @param identifier (String) (required): Value used to filter the tester
|
217
|
+
def find_external_tester(identifier)
|
218
|
+
Tunes::Tester.external.find_by_app(self.apple_id, identifier)
|
219
|
+
end
|
220
|
+
|
221
|
+
# @return (Spaceship::Tunes::Tester.internal) Returns the internal tester matching the parameter
|
222
|
+
# as either the Tester id or email
|
223
|
+
# @param identifier (String) (required): Value used to filter the tester
|
224
|
+
def find_internal_tester(identifier)
|
225
|
+
Tunes::Tester.internal.find_by_app(self.apple_id, identifier)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Add external tester to the current app list, if it doesn't exist will be created
|
229
|
+
# @param email (String) (required): The email of the tester
|
230
|
+
# @param first_name (String) (optional): The first name of the tester (Ignored if user already exist)
|
231
|
+
# @param last_name (String) (optional): The last name of the tester (Ignored if user already exist)
|
232
|
+
def add_external_tester!(email: nil, first_name: nil, last_name: nil)
|
233
|
+
raise "Tester is already on #{self.name} betatesters" if find_external_tester(email)
|
234
|
+
|
235
|
+
tester = Tunes::Tester.external.find(email) || Tunes::Tester.external.create!(email: email,
|
236
|
+
first_name: first_name,
|
237
|
+
last_name: last_name)
|
238
|
+
tester.add_to_app!(self.apple_id)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Remove external tester from the current app list that matching the parameter
|
242
|
+
# as either the Tester id or email
|
243
|
+
# @param identifier (String) (required): Value used to filter the tester
|
244
|
+
def remove_external_tester!(identifier)
|
245
|
+
tester = find_external_tester(identifier)
|
246
|
+
|
247
|
+
raise "Tester is not on #{self.name} betatesters" unless tester
|
248
|
+
|
249
|
+
tester.remove_from_app!(self.apple_id)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Spaceship
|
2
|
+
module Tunes
|
3
|
+
# Represents a build which is inside the build train
|
4
|
+
class Build < TunesBase
|
5
|
+
|
6
|
+
#####################################################
|
7
|
+
# @!group General metadata
|
8
|
+
#####################################################
|
9
|
+
|
10
|
+
# @return (Spaceship::Tunes::Application) A reference to the build train this build is contained in
|
11
|
+
attr_accessor :build_train
|
12
|
+
|
13
|
+
# @return (Integer) The ID generated by iTunes Connect
|
14
|
+
attr_accessor :id
|
15
|
+
|
16
|
+
# @return (Boolean)
|
17
|
+
attr_accessor :valid
|
18
|
+
|
19
|
+
# @return (String) The build version (not the version number)
|
20
|
+
attr_accessor :build_version
|
21
|
+
|
22
|
+
# @return (String) The version number (e.g. 1.3)
|
23
|
+
attr_accessor :train_version
|
24
|
+
|
25
|
+
# @return (Integer) The number of ticks since 1970 (e.g. 1413966436000)
|
26
|
+
attr_accessor :upload_date
|
27
|
+
|
28
|
+
# @return (String) URL to the app icon of this build (150x150px)
|
29
|
+
attr_accessor :icon_url
|
30
|
+
|
31
|
+
# @return (String)
|
32
|
+
attr_accessor :app_name
|
33
|
+
|
34
|
+
# @return (String) The platform of this build (e.g. 'ios')
|
35
|
+
attr_accessor :platform
|
36
|
+
|
37
|
+
# @return (Integer) When is this build going to be invalid
|
38
|
+
attr_accessor :internal_expiry_date
|
39
|
+
|
40
|
+
# @return (Bool) Does this build support WatchKit?
|
41
|
+
attr_accessor :watch_kit_enabled
|
42
|
+
|
43
|
+
# @return (Bool):
|
44
|
+
attr_accessor :ready_to_install
|
45
|
+
|
46
|
+
#####################################################
|
47
|
+
# @!group Analytics
|
48
|
+
#####################################################
|
49
|
+
|
50
|
+
# @return (Integer) Number of installs of this build
|
51
|
+
attr_accessor :install_count
|
52
|
+
|
53
|
+
# @return (Integer) Number of installs for this build that come from internal users
|
54
|
+
attr_accessor :internal_install_count
|
55
|
+
|
56
|
+
# @return (Integer) Number of installs for this build that come from external users
|
57
|
+
attr_accessor :external_install_count
|
58
|
+
|
59
|
+
# @return (Integer) Might be nil. The number of sessions for this build
|
60
|
+
attr_accessor :session_count
|
61
|
+
|
62
|
+
# @return (Integer) Might be nil. The number of crashes of this build
|
63
|
+
attr_accessor :crash_count
|
64
|
+
|
65
|
+
attr_mapping(
|
66
|
+
'uploadDate' => :upload_date,
|
67
|
+
'iconUrl' => :icon_url,
|
68
|
+
'buildVersion' => :build_version,
|
69
|
+
'trainVersion' => :train_version,
|
70
|
+
'appName' => :app_name,
|
71
|
+
'platform' => :platform,
|
72
|
+
'id' => :id,
|
73
|
+
'valid' => :valid,
|
74
|
+
|
75
|
+
'installCount' => :install_count,
|
76
|
+
'internalInstallCount' => :internal_install_count,
|
77
|
+
'externalInstallCount' => :external_install_count,
|
78
|
+
'sessionCount' => :session_count,
|
79
|
+
'crashCount' => :crash_count,
|
80
|
+
'internalExpiry' => :internal_expiry_date,
|
81
|
+
'watchKitEnabled' => :watch_kit_enabled,
|
82
|
+
'readyToInstall' => :ready_to_install,
|
83
|
+
)
|
84
|
+
|
85
|
+
class << self
|
86
|
+
# Create a new object based on a hash.
|
87
|
+
# This is used to create a new object based on the server response.
|
88
|
+
def factory(attrs)
|
89
|
+
self.new(attrs)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Example response
|
97
|
+
# "buildVersion": "0.9.10",
|
98
|
+
# "trainVersion": "0.9.10",
|
99
|
+
# "uploadDate": 1413966436000,
|
100
|
+
# "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",
|
101
|
+
# "appName": "Yeahaa",
|
102
|
+
# "platform": "ios",
|
103
|
+
# "betaEntitled": false,
|
104
|
+
# "id": 523299,
|
105
|
+
# "valid": true,
|
106
|
+
# "missingExportCompliance": false,
|
107
|
+
# "waitingForExportComplianceApproval": false,
|
108
|
+
# "addedInternalUsersCount": 0,
|
109
|
+
# "addedExternalUsersCount": 0,
|
110
|
+
# "invitedExternalUsersCount": 0,
|
111
|
+
# "invitedInternalUsersCount": 0,
|
112
|
+
# "acceptedInternalUsersCount": 0,
|
113
|
+
# "acceptedExternalUsersCount": 0,
|
114
|
+
# "installCount": 0,
|
115
|
+
# "internalInstallCount": 0,
|
116
|
+
# "externalInstallCount": 0,
|
117
|
+
# "sessionCount": null,
|
118
|
+
# "crashCount": null,
|
119
|
+
# "promotedVersion": null,
|
120
|
+
# "internalState": "noBetaEntitlement",
|
121
|
+
# "betaState": "noBetaEntitlement",
|
122
|
+
# "internalExpiry": 1416562036000,
|
123
|
+
# "externalExpiry": 0,
|
124
|
+
# "watchKitEnabled": false,
|
125
|
+
# "readyToInstall": false,
|
126
|
+
# "sdkBuildWhitelisted": true,
|
127
|
+
# "internalTesting": null,
|
128
|
+
# "externalTesting": null
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Spaceship
|
2
|
+
module Tunes
|
3
|
+
# Represents a build train of builds from iTunes Connect
|
4
|
+
# A build train is all builds for a given version number with different build numbers
|
5
|
+
class BuildTrain < TunesBase
|
6
|
+
|
7
|
+
# @return (Spaceship::Tunes::Application) A reference to the application
|
8
|
+
# this train is for
|
9
|
+
attr_accessor :application
|
10
|
+
|
11
|
+
# @return (Array) An array of all builds that are inside this train (Spaceship::Tunes::Build)
|
12
|
+
attr_reader :builds
|
13
|
+
|
14
|
+
# @return (String) The version number of this train
|
15
|
+
attr_reader :version_string
|
16
|
+
|
17
|
+
# @return (String) Platform (e.g. "ios")
|
18
|
+
attr_reader :platform
|
19
|
+
|
20
|
+
# @return (Bool) Is beta testing enabled for this train? Only one train can have enabled testing.
|
21
|
+
attr_reader :testing_enabled
|
22
|
+
|
23
|
+
# @return (Array) An array of all builds that are inside this train (Spaceship::Tunes::Build)
|
24
|
+
# I never got this to work to properly try and debug this
|
25
|
+
attr_reader :processing_builds
|
26
|
+
|
27
|
+
attr_mapping(
|
28
|
+
'versionString' => :version_string,
|
29
|
+
'platform' => :platform,
|
30
|
+
'testing.value' => :testing_enabled
|
31
|
+
)
|
32
|
+
|
33
|
+
class << self
|
34
|
+
# Create a new object based on a hash.
|
35
|
+
# This is used to create a new object based on the server response.
|
36
|
+
def factory(attrs)
|
37
|
+
self.new(attrs)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param application (Spaceship::Tunes::Application) The app this train is for
|
41
|
+
# @param app_id (String) The unique Apple ID of this app
|
42
|
+
def all(application, app_id)
|
43
|
+
data = client.build_trains(app_id)
|
44
|
+
result = {}
|
45
|
+
data['trains'].each do |attrs|
|
46
|
+
attrs.merge!(application: application)
|
47
|
+
current = self.factory(attrs)
|
48
|
+
result[current.version_string] = current
|
49
|
+
end
|
50
|
+
result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Setup all the builds and processing builds
|
55
|
+
def setup
|
56
|
+
@builds = self.raw_data['builds'].collect do |attrs|
|
57
|
+
attrs.merge!(build_train: self)
|
58
|
+
Tunes::Build.factory(attrs)
|
59
|
+
end
|
60
|
+
|
61
|
+
@processing_builds = self.raw_data['buildsInProcessing'].collect do |attrs|
|
62
|
+
attrs.merge!(build_train: self)
|
63
|
+
Tunes::Build.factory(attrs)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_testing_status!(new_value)
|
68
|
+
data = client.build_trains(self.application.apple_id)
|
69
|
+
data['trains'].each do |train|
|
70
|
+
train['testing']['value'] = false
|
71
|
+
train['testing']['value'] = new_value if train['versionString'] == version_string
|
72
|
+
end
|
73
|
+
result = client.update_build_trains!(application.apple_id, data)
|
74
|
+
self.testing_enabled = new_value
|
75
|
+
result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|