deliver 0.5.0 → 0.6.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 +5 -3
- data/bin/deliver +58 -13
- data/lib/assets/DeliverfileDefault +0 -5
- data/lib/deliver.rb +1 -1
- data/lib/deliver/app.rb +7 -6
- data/lib/deliver/app_metadata.rb +8 -148
- data/lib/deliver/app_metadata_screenshots.rb +153 -0
- data/lib/deliver/deliver_process.rb +24 -0
- data/lib/deliver/deliverer.rb +19 -0
- data/lib/deliver/deliverfile/deliverfile_creator.rb +1 -1
- data/lib/deliver/deliverfile/dsl.rb +7 -3
- data/lib/deliver/itunes_connect/itunes_connect.rb +72 -0
- data/lib/deliver/itunes_connect/itunes_connect_additional.rb +90 -0
- data/lib/deliver/itunes_connect/itunes_connect_app_icon.rb +35 -0
- data/lib/deliver/itunes_connect/itunes_connect_app_rating.rb +68 -0
- data/lib/deliver/itunes_connect/itunes_connect_helper.rb +83 -0
- data/lib/deliver/itunes_connect/itunes_connect_login.rb +61 -0
- data/lib/deliver/itunes_connect/itunes_connect_new_version.rb +57 -0
- data/lib/deliver/itunes_connect/itunes_connect_reader.rb +60 -0
- data/lib/deliver/itunes_connect/itunes_connect_submission.rb +222 -0
- data/lib/deliver/version.rb +1 -1
- metadata +12 -5
- data/lib/deliver/commands/init.rb +0 -10
- data/lib/deliver/commands/run.rb +0 -24
- data/lib/deliver/itunes_connect.rb +0 -552
@@ -0,0 +1,61 @@
|
|
1
|
+
module Deliver
|
2
|
+
# Login code
|
3
|
+
class ItunesConnect
|
4
|
+
# Loggs in a user with the given login data on the iTC Frontend.
|
5
|
+
# You don't need to pass a username and password. It will
|
6
|
+
# Automatically be fetched using the {CredentialsManager::PasswordManager}.
|
7
|
+
# This method will also automatically be called when triggering other
|
8
|
+
# actions like {#open_app_page}
|
9
|
+
# @param user (String) (optional) The username/email address
|
10
|
+
# @param password (String) (optional) The password
|
11
|
+
# @return (bool) true if everything worked fine
|
12
|
+
# @raise [ItunesConnectGeneralError] General error while executing
|
13
|
+
# this action
|
14
|
+
# @raise [ItunesConnectLoginError] Login data is wrong
|
15
|
+
def login(user = nil, password = nil)
|
16
|
+
Helper.log.info "Logging into iTunesConnect"
|
17
|
+
|
18
|
+
user ||= CredentialsManager::PasswordManager.shared_manager.username
|
19
|
+
password ||= CredentialsManager::PasswordManager.shared_manager.password
|
20
|
+
|
21
|
+
result = visit ITUNESCONNECT_URL
|
22
|
+
raise "Could not open iTunesConnect" unless result['status'] == 'success'
|
23
|
+
|
24
|
+
sleep 3
|
25
|
+
|
26
|
+
if page.has_content?"My Apps"
|
27
|
+
# Already logged in
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
wait_for_elements('#accountpassword')
|
33
|
+
rescue => ex
|
34
|
+
# when the user is already logged in, this will raise an exception
|
35
|
+
end
|
36
|
+
|
37
|
+
fill_in "accountname", with: user
|
38
|
+
fill_in "accountpassword", with: password
|
39
|
+
|
40
|
+
begin
|
41
|
+
(wait_for_elements(".enabled").first.click rescue nil) # Login Button
|
42
|
+
wait_for_elements('.homepageWrapper.ng-scope')
|
43
|
+
|
44
|
+
if page.has_content?"My Apps"
|
45
|
+
# Everything looks good
|
46
|
+
else
|
47
|
+
raise ItunesConnectLoginError.new("Looks like your login data was correct, but you do not have access to the apps.")
|
48
|
+
end
|
49
|
+
rescue => ex
|
50
|
+
Helper.log.debug(ex)
|
51
|
+
raise ItunesConnectLoginError.new("Error logging in user #{user} with the given password. Make sure you entered them correctly.")
|
52
|
+
end
|
53
|
+
|
54
|
+
Helper.log.info "Successfully logged into iTunesConnect"
|
55
|
+
|
56
|
+
true
|
57
|
+
rescue => ex
|
58
|
+
error_occured(ex)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Deliver
|
2
|
+
class ItunesConnect
|
3
|
+
# This method creates a new version of your app using the
|
4
|
+
# iTunesConnect frontend. This will happen directly after calling
|
5
|
+
# this method.
|
6
|
+
# @param app (Deliver::App) the app you want to modify
|
7
|
+
# @param version_number (String) the version number as string for
|
8
|
+
# the new version that should be created
|
9
|
+
def create_new_version!(app, version_number)
|
10
|
+
begin
|
11
|
+
current_version = get_live_version(app)
|
12
|
+
|
13
|
+
verify_app(app)
|
14
|
+
open_app_page(app)
|
15
|
+
|
16
|
+
if page.has_content?BUTTON_STRING_NEW_VERSION
|
17
|
+
|
18
|
+
if current_version == version_number
|
19
|
+
# This means, this version is already live on the App Store
|
20
|
+
raise "Version #{version_number} is already created, submitted and released on iTC. Please verify you're using a new version number."
|
21
|
+
end
|
22
|
+
|
23
|
+
click_on BUTTON_STRING_NEW_VERSION
|
24
|
+
|
25
|
+
Helper.log.info "Creating a new version (#{version_number})"
|
26
|
+
|
27
|
+
all(".fullWidth.nobottom.ng-isolate-scope.ng-pristine").last.set(version_number.to_s)
|
28
|
+
click_on "Create"
|
29
|
+
|
30
|
+
while not page.has_content?"Prepare for Submission"
|
31
|
+
sleep 1
|
32
|
+
Helper.log.debug("Waiting for 'Prepare for Submission'")
|
33
|
+
end
|
34
|
+
else
|
35
|
+
Helper.log.warn "Can not create version #{version_number} on iTunesConnect. Maybe it was already created."
|
36
|
+
Helper.log.info "Check out '#{current_url}' what's the latest version."
|
37
|
+
|
38
|
+
begin
|
39
|
+
created_version = first(".status.waiting").text.split(" ").first
|
40
|
+
if created_version != version_number
|
41
|
+
raise "Some other version ('#{created_version}') was created instead of the one you defined ('#{version_number}')"
|
42
|
+
end
|
43
|
+
rescue => ex
|
44
|
+
# Can not fetch the version number of the new version (this happens, when it's e.g. 'Developer Rejected')
|
45
|
+
unless page.has_content?version_number
|
46
|
+
raise "Some other version was created instead of the one you defined ('#{version_number}')."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
true
|
52
|
+
rescue => ex
|
53
|
+
error_occured(ex)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Deliver
|
2
|
+
# For all the information reading (e.g. version number)
|
3
|
+
class ItunesConnect
|
4
|
+
# This method will fetch the current status ({Deliver::App::AppStatus})
|
5
|
+
# of your app and return it. This method uses a headless browser
|
6
|
+
# under the hood, so it might take some time until you get the result
|
7
|
+
# @param app (Deliver::App) the app you want this information from
|
8
|
+
# @raise [ItunesConnectGeneralError] General error while executing
|
9
|
+
# this action
|
10
|
+
# @raise [ItunesConnectLoginError] Login data is wrong
|
11
|
+
def get_app_status(app)
|
12
|
+
begin
|
13
|
+
verify_app(app)
|
14
|
+
|
15
|
+
open_app_page(app)
|
16
|
+
|
17
|
+
if page.has_content?WAITING_FOR_REVIEW
|
18
|
+
# That's either Upload Received or Waiting for Review
|
19
|
+
if page.has_content?"To submit a new build, you must remove this version from review"
|
20
|
+
return App::AppStatus::WAITING_FOR_REVIEW
|
21
|
+
else
|
22
|
+
return App::AppStatus::UPLOAD_RECEIVED
|
23
|
+
end
|
24
|
+
elsif page.has_content?BUTTON_STRING_NEW_VERSION
|
25
|
+
return App::AppStatus::READY_FOR_SALE
|
26
|
+
elsif page.has_content?BUTTON_STRING_SUBMIT_FOR_REVIEW
|
27
|
+
return App::AppStatus::PREPARE_FOR_SUBMISSION
|
28
|
+
else
|
29
|
+
raise "App status not yet implemented"
|
30
|
+
end
|
31
|
+
rescue Exception => ex
|
32
|
+
error_occured(ex)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method will fetch the version number of the currently live version
|
37
|
+
# of your app and return it. This method uses a headless browser
|
38
|
+
# under the hood, so it might take some time until you get the result
|
39
|
+
# @param app (Deliver::App) the app you want this information from
|
40
|
+
# @raise [ItunesConnectGeneralError] General error while executing
|
41
|
+
# this action
|
42
|
+
# @raise [ItunesConnectLoginError] Login data is wrong
|
43
|
+
def get_live_version(app)
|
44
|
+
begin
|
45
|
+
verify_app(app)
|
46
|
+
|
47
|
+
open_app_page(app)
|
48
|
+
|
49
|
+
begin
|
50
|
+
return first(".status.ready").text.split(" ").first
|
51
|
+
rescue
|
52
|
+
Helper.log.debug "Could not fetch version number of the live version for app #{app}."
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
rescue => ex
|
56
|
+
error_occured(ex)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
module Deliver
|
2
|
+
# Everything related to submitting the app
|
3
|
+
class ItunesConnect
|
4
|
+
|
5
|
+
# This will put the latest uploaded build as a new beta build
|
6
|
+
def put_build_into_beta_testing!(app, version_number)
|
7
|
+
begin
|
8
|
+
verify_app(app)
|
9
|
+
open_app_page(app)
|
10
|
+
|
11
|
+
Helper.log.info("Choosing the latest build on iTunesConnect for beta distribution")
|
12
|
+
|
13
|
+
click_on "Prerelease"
|
14
|
+
|
15
|
+
wait_for_preprocessing
|
16
|
+
|
17
|
+
if all(".switcher.ng-binding").count == 0
|
18
|
+
raise "Could not find beta build on '#{current_url}'. Make sure it is available there"
|
19
|
+
end
|
20
|
+
|
21
|
+
if first(".switcher.ng-binding")['class'].include?"checked"
|
22
|
+
Helper.log.warn("Beta Build seems to be already active. Take a look at '#{current_url}'")
|
23
|
+
return true
|
24
|
+
end
|
25
|
+
|
26
|
+
first(".switcher.ng-binding").click
|
27
|
+
if page.has_content?"Are you sure you want to start testing"
|
28
|
+
click_on "Start"
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
return true
|
33
|
+
rescue => ex
|
34
|
+
error_occured(ex)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# This will choose the latest uploaded build on iTunesConnect as the production one
|
39
|
+
# After this method, you still have to call submit_for_review to actually submit the
|
40
|
+
# whole update
|
41
|
+
# @param app (Deliver::App) the app you want to choose the build for
|
42
|
+
# @param version_number (String) the version number as string for
|
43
|
+
def put_build_into_production!(app, version_number)
|
44
|
+
begin
|
45
|
+
verify_app(app)
|
46
|
+
open_app_page(app)
|
47
|
+
|
48
|
+
Helper.log.info("Choosing the latest build on iTunesConnect for release")
|
49
|
+
|
50
|
+
click_on "Prerelease"
|
51
|
+
|
52
|
+
wait_for_preprocessing
|
53
|
+
|
54
|
+
################# Apple is finished processing the ipa file #################
|
55
|
+
|
56
|
+
Helper.log.info("Apple finally finished processing the ipa file")
|
57
|
+
open_app_page(app)
|
58
|
+
|
59
|
+
begin
|
60
|
+
first('a', :text => BUTTON_ADD_NEW_BUILD).click
|
61
|
+
wait_for_elements(".buildModalList")
|
62
|
+
sleep 5
|
63
|
+
rescue
|
64
|
+
if page.has_content?"Upload Date"
|
65
|
+
# That's fine, the ipa was already selected
|
66
|
+
return true
|
67
|
+
else
|
68
|
+
raise "Could not find Build Button. It looks like the ipa file was not properly uploaded."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if page.all('td', :text => version_number).count > 1
|
73
|
+
Helper.log.fatal "There were multiple submitted builds found. Don't know which one to choose. Just choosing the top one for now"
|
74
|
+
end
|
75
|
+
|
76
|
+
result = page.first('td', :text => version_number).first(:xpath,"./..").first(:css, ".small").click
|
77
|
+
click_on "Done" # Save the modal dialog
|
78
|
+
click_on "Save" # on the top right to save everything else
|
79
|
+
|
80
|
+
error = page.has_content?BUTTON_ADD_NEW_BUILD
|
81
|
+
raise "Could not put build itself onto production. Try opening '#{current_url}'" if error
|
82
|
+
|
83
|
+
return true
|
84
|
+
rescue => ex
|
85
|
+
error_occured(ex)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Submits the update itself to Apple, this includes the app metadata and the ipa file
|
90
|
+
# This can easily cause exceptions, which will be shown on iTC.
|
91
|
+
# @param app (Deliver::App) the app you want to submit
|
92
|
+
# @param perms (Hash) information about content rights, ...
|
93
|
+
def submit_for_review!(app, perms = nil)
|
94
|
+
begin
|
95
|
+
verify_app(app)
|
96
|
+
open_app_page(app)
|
97
|
+
|
98
|
+
Helper.log.info("Submitting app for Review")
|
99
|
+
|
100
|
+
if not page.has_content?BUTTON_STRING_SUBMIT_FOR_REVIEW
|
101
|
+
if page.has_content?WAITING_FOR_REVIEW
|
102
|
+
Helper.log.info("App is already Waiting For Review")
|
103
|
+
return true
|
104
|
+
else
|
105
|
+
raise "Couldn't find button with name '#{BUTTON_STRING_SUBMIT_FOR_REVIEW}'"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
click_on BUTTON_STRING_SUBMIT_FOR_REVIEW
|
110
|
+
sleep 4
|
111
|
+
|
112
|
+
errors = (all(".pagemessage.error") || []).count > 0
|
113
|
+
raise "Some error occured when submitting the app for review: '#{current_url}'" if errors
|
114
|
+
|
115
|
+
wait_for_elements(".savingWrapper.ng-scope.ng-pristine")
|
116
|
+
wait_for_elements(".radiostyle")
|
117
|
+
sleep 3
|
118
|
+
|
119
|
+
if page.has_content?"Content Rights"
|
120
|
+
# Looks good.. just a few more steps
|
121
|
+
|
122
|
+
perms ||= {
|
123
|
+
export_compliance: {
|
124
|
+
encryption_updated: false,
|
125
|
+
cryptography_enabled: false,
|
126
|
+
is_exempt: false
|
127
|
+
},
|
128
|
+
third_party_content: {
|
129
|
+
contains_third_party_content: false,
|
130
|
+
has_rights: false
|
131
|
+
},
|
132
|
+
advertising_identifier: {
|
133
|
+
use_idfa: false,
|
134
|
+
serve_advertisement: false,
|
135
|
+
attribute_advertisement: false,
|
136
|
+
attribute_actions: false,
|
137
|
+
limit_ad_tracking: false
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
basic = "//*[@itc-radio='submitForReviewAnswers"
|
142
|
+
checkbox = "//*[@itc-checkbox='submitForReviewAnswers"
|
143
|
+
|
144
|
+
#####################
|
145
|
+
# Export Compliance #
|
146
|
+
#####################
|
147
|
+
if page.has_content?"Export"
|
148
|
+
|
149
|
+
if not perms[:export_compliance][:encryption_updated] and perms[:export_compliance][:cryptography_enabled]
|
150
|
+
raise "encryption_updated must be enabled if cryptography_enabled is enabled!"
|
151
|
+
end
|
152
|
+
|
153
|
+
begin
|
154
|
+
encryption_updated_control = all(:xpath, "#{basic}.exportCompliance.encryptionUpdated.value' and @radio-value='#{perms[:export_compliance][:encryption_updated]}']//input")
|
155
|
+
encryption_updated_control[0].trigger('click') if encryption_updated_control.count > 0
|
156
|
+
first(:xpath, "#{basic}.exportCompliance.usesEncryption.value' and @radio-value='#{perms[:export_compliance][:cryptography_enabled]}']//input").trigger('click')
|
157
|
+
first(:xpath, "#{basic}.exportCompliance.isExempt.value' and @radio-value='#{perms[:export_compliance][:is_exempt]}']//input").trigger('click')
|
158
|
+
rescue
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
##################
|
163
|
+
# Content Rights #
|
164
|
+
##################
|
165
|
+
if page.has_content?"Content Rights"
|
166
|
+
if not perms[:third_party_content][:contains_third_party_content] and perms[:third_party_content][:has_rights]
|
167
|
+
raise "contains_third_party_content must be enabled if has_rights is enabled".red
|
168
|
+
end
|
169
|
+
|
170
|
+
begin
|
171
|
+
first(:xpath, "#{basic}.contentRights.containsThirdPartyContent.value' and @radio-value='#{perms[:third_party_content][:contains_third_party_content]}']//input").trigger('click')
|
172
|
+
first(:xpath, "#{basic}.contentRights.hasRights.value' and @radio-value='#{perms[:third_party_content][:has_rights]}']//input").trigger('click')
|
173
|
+
rescue
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
##########################
|
178
|
+
# Advertising Identifier #
|
179
|
+
##########################
|
180
|
+
if page.has_content?"Advertising Identifier"
|
181
|
+
first(:xpath, "#{basic}.adIdInfo.usesIdfa.value' and @radio-value='#{perms[:advertising_identifier][:use_idfa]}']//a").click rescue nil
|
182
|
+
|
183
|
+
if perms[:advertising_identifier][:use_idfa]
|
184
|
+
if perms[:advertising_identifier][:serve_advertisement]
|
185
|
+
first(:xpath, "#{checkbox}.adIdInfo.servesAds.value']//a").click
|
186
|
+
end
|
187
|
+
if perms[:advertising_identifier][:attribute_advertisement]
|
188
|
+
first(:xpath, "#{checkbox}.adIdInfo.tracksInstall.value']//a").click
|
189
|
+
end
|
190
|
+
if perms[:advertising_identifier][:attribute_actions]
|
191
|
+
first(:xpath, "#{checkbox}.adIdInfo.tracksAction.value']//a").click
|
192
|
+
end
|
193
|
+
if perms[:advertising_identifier][:limit_ad_tracking]
|
194
|
+
first(:xpath, "#{checkbox}.adIdInfo.limitsTracking.value']//a").click
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
Helper.log.info("Filled out the export compliance and other information on iTC".green)
|
201
|
+
|
202
|
+
click_on "Submit"
|
203
|
+
sleep 5
|
204
|
+
|
205
|
+
if page.has_content?WAITING_FOR_REVIEW
|
206
|
+
# Everything worked :)
|
207
|
+
Helper.log.info("Successfully submitted App for Review".green)
|
208
|
+
return true
|
209
|
+
else
|
210
|
+
raise "So close, it looks like there went something wrong with the actual deployment. Checkout '#{current_url}'".red
|
211
|
+
end
|
212
|
+
else
|
213
|
+
raise "Something is missing here.".red
|
214
|
+
end
|
215
|
+
return false
|
216
|
+
rescue => ex
|
217
|
+
error_occured(ex)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|
data/lib/deliver/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deliver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -295,10 +295,9 @@ files:
|
|
295
295
|
- lib/deliver.rb
|
296
296
|
- lib/deliver/app.rb
|
297
297
|
- lib/deliver/app_metadata.rb
|
298
|
+
- lib/deliver/app_metadata_screenshots.rb
|
298
299
|
- lib/deliver/app_screenshot.rb
|
299
300
|
- lib/deliver/commands.rb
|
300
|
-
- lib/deliver/commands/init.rb
|
301
|
-
- lib/deliver/commands/run.rb
|
302
301
|
- lib/deliver/deliver_process.rb
|
303
302
|
- lib/deliver/deliverer.rb
|
304
303
|
- lib/deliver/deliverfile/deliverfile.rb
|
@@ -307,7 +306,15 @@ files:
|
|
307
306
|
- lib/deliver/dependency_checker.rb
|
308
307
|
- lib/deliver/helper.rb
|
309
308
|
- lib/deliver/ipa_uploader.rb
|
310
|
-
- lib/deliver/itunes_connect.rb
|
309
|
+
- lib/deliver/itunes_connect/itunes_connect.rb
|
310
|
+
- lib/deliver/itunes_connect/itunes_connect_additional.rb
|
311
|
+
- lib/deliver/itunes_connect/itunes_connect_app_icon.rb
|
312
|
+
- lib/deliver/itunes_connect/itunes_connect_app_rating.rb
|
313
|
+
- lib/deliver/itunes_connect/itunes_connect_helper.rb
|
314
|
+
- lib/deliver/itunes_connect/itunes_connect_login.rb
|
315
|
+
- lib/deliver/itunes_connect/itunes_connect_new_version.rb
|
316
|
+
- lib/deliver/itunes_connect/itunes_connect_reader.rb
|
317
|
+
- lib/deliver/itunes_connect/itunes_connect_submission.rb
|
311
318
|
- lib/deliver/itunes_search_api.rb
|
312
319
|
- lib/deliver/itunes_transporter.rb
|
313
320
|
- lib/deliver/languages.rb
|