deliver 0.13.5 → 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -208
- data/bin/deliver +1 -1
- data/lib/assets/DeliverfileDefault +2 -22
- data/lib/assets/summary.html.erb +27 -39
- data/lib/deliver.rb +16 -14
- data/lib/deliver/app_screenshot.rb +43 -33
- data/lib/deliver/commands_generator.rb +30 -108
- data/lib/deliver/detect_values.rb +23 -0
- data/lib/deliver/download_screenshots.rb +30 -9
- data/lib/deliver/html_generator.rb +7 -8
- data/lib/deliver/options.rb +126 -0
- data/lib/deliver/runner.rb +75 -0
- data/lib/deliver/setup.rb +84 -0
- data/lib/deliver/submit_for_review.rb +60 -0
- data/lib/deliver/upload_assets.rb +22 -0
- data/lib/deliver/upload_metadata.rb +100 -0
- data/lib/deliver/upload_price_tier.rb +21 -0
- data/lib/deliver/upload_screenshots.rb +63 -0
- data/lib/deliver/version.rb +2 -1
- metadata +37 -62
- data/lib/assets/DeliverLanguageMapping.json +0 -187
- data/lib/assets/DeliverfileExample +0 -38
- data/lib/deliver/app.rb +0 -167
- data/lib/deliver/app_metadata.rb +0 -419
- data/lib/deliver/app_metadata_screenshots.rb +0 -189
- data/lib/deliver/deliver_process.rb +0 -426
- data/lib/deliver/deliverer.rb +0 -138
- data/lib/deliver/deliverfile/deliverfile.rb +0 -35
- data/lib/deliver/deliverfile/deliverfile_creator.rb +0 -135
- data/lib/deliver/deliverfile/dsl.rb +0 -142
- data/lib/deliver/dependency_checker.rb +0 -19
- data/lib/deliver/ipa_file_analyser.rb +0 -44
- data/lib/deliver/ipa_uploader.rb +0 -148
- data/lib/deliver/itunes_connect/itunes_connect.rb +0 -12
- data/lib/deliver/itunes_connect/itunes_connect_additional.rb +0 -105
- data/lib/deliver/itunes_connect/itunes_connect_app_icon.rb +0 -41
- data/lib/deliver/itunes_connect/itunes_connect_app_rating.rb +0 -90
- data/lib/deliver/itunes_connect/itunes_connect_apple_watch_app_icon.rb +0 -42
- data/lib/deliver/itunes_connect/itunes_connect_information.rb +0 -34
- data/lib/deliver/itunes_connect/itunes_connect_new_version.rb +0 -67
- data/lib/deliver/itunes_connect/itunes_connect_reader.rb +0 -46
- data/lib/deliver/itunes_connect/itunes_connect_screenshot_fetcher.rb +0 -54
- data/lib/deliver/itunes_connect/itunes_connect_submission.rb +0 -282
- data/lib/deliver/itunes_transporter.rb +0 -221
- data/lib/deliver/metadata_item.rb +0 -94
- data/lib/deliver/testflight.rb +0 -27
@@ -1,189 +0,0 @@
|
|
1
|
-
module Deliver
|
2
|
-
class AppMetadata
|
3
|
-
#####################################################
|
4
|
-
# @!group Screenshot related
|
5
|
-
#####################################################
|
6
|
-
|
7
|
-
# Removes all currently enabled screenshots for the given language.
|
8
|
-
# @param (String) language The language, which has to be in this list: {FastlaneCore::Languages}.
|
9
|
-
def clear_all_screenshots(language)
|
10
|
-
raise AppMetadataParameterError.new(INVALID_LANGUAGE_ERROR) unless FastlaneCore::Languages::ALL_LANGUAGES.include?language
|
11
|
-
|
12
|
-
update_localized_value('software_screenshots', {language => {}}) do |field, useless, language|
|
13
|
-
field.children.remove # remove all the screenshots
|
14
|
-
end
|
15
|
-
information[language][:screenshots] = []
|
16
|
-
true
|
17
|
-
end
|
18
|
-
|
19
|
-
# Appends another screenshot to the already existing ones
|
20
|
-
# @param (String) language The language, which has to be in this list: {FastlaneCore::Languages}.
|
21
|
-
# @param (Deliver::AppScreenshot) app_screenshot The screenshot you want to add to the app metadata.
|
22
|
-
# @raise (AppMetadataTooManyScreenshotsError) When there are already 5 screenshots (MAXIMUM_NUMBER_OF_SCREENSHOTS).
|
23
|
-
|
24
|
-
def add_screenshot(language, app_screenshot)
|
25
|
-
raise AppMetadataParameterError.new(INVALID_LANGUAGE_ERROR) unless FastlaneCore::Languages::ALL_LANGUAGES.include?language
|
26
|
-
|
27
|
-
create_locale_if_not_exists(language)
|
28
|
-
|
29
|
-
# Fetch the 'software_screenshots' node (array) for the specific locale
|
30
|
-
locales = self.fetch_value("//x:locale[@name='#{language}']")
|
31
|
-
|
32
|
-
screenshots = self.fetch_value("//x:locale[@name='#{language}']/x:software_screenshots").first
|
33
|
-
|
34
|
-
if not screenshots or screenshots.children.count == 0
|
35
|
-
screenshots.remove if screenshots
|
36
|
-
|
37
|
-
# First screenshot ever
|
38
|
-
screenshots = Nokogiri::XML::Node.new('software_screenshots', @data)
|
39
|
-
locales.first << screenshots
|
40
|
-
|
41
|
-
node_set = Nokogiri::XML::NodeSet.new(@data)
|
42
|
-
node_set << app_screenshot.create_xml_node(@data, 1)
|
43
|
-
screenshots.children = node_set
|
44
|
-
else
|
45
|
-
# There is already at least one screenshot
|
46
|
-
next_index = 1
|
47
|
-
screenshots.children.each do |screen|
|
48
|
-
if screen['display_target'] == app_screenshot.screen_size
|
49
|
-
next_index += 1
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
if next_index > MAXIMUM_NUMBER_OF_SCREENSHOTS
|
54
|
-
raise AppMetadataTooManyScreenshotsError.new("Only #{MAXIMUM_NUMBER_OF_SCREENSHOTS} screenshots are allowed per language per device type (#{app_screenshot.screen_size})")
|
55
|
-
end
|
56
|
-
|
57
|
-
# Ready for storing the screenshot into the metadata.xml now
|
58
|
-
screenshots.children.after(app_screenshot.create_xml_node(@data, next_index))
|
59
|
-
end
|
60
|
-
|
61
|
-
information[language][:screenshots] << app_screenshot
|
62
|
-
|
63
|
-
app_screenshot.store_file_inside_package(@package_path)
|
64
|
-
end
|
65
|
-
|
66
|
-
# This method will clear all screenshots and set the new ones you pass
|
67
|
-
# @param new_screenshots
|
68
|
-
# +code+
|
69
|
-
# {
|
70
|
-
# 'de-DE' => [
|
71
|
-
# AppScreenshot.new('path/screenshot1.png', Deliver::ScreenSize::IOS_35),
|
72
|
-
# AppScreenshot.new('path/screenshot2.png', Deliver::ScreenSize::IOS_40),
|
73
|
-
# AppScreenshot.new('path/screenshot3.png', Deliver::ScreenSize::IOS_IPAD)
|
74
|
-
# ]
|
75
|
-
# }
|
76
|
-
# This method uses {#clear_all_screenshots} and {#add_screenshot} under the hood.
|
77
|
-
# @return [bool] true if everything was successful
|
78
|
-
# @raise [AppMetadataParameterError] error is raised when parameters are invalid
|
79
|
-
def set_all_screenshots(new_screenshots)
|
80
|
-
error_text = "Please pass a hash, containing an array of AppScreenshot objects"
|
81
|
-
raise AppMetadataParameterError.new(error_text) unless new_screenshots.kind_of?Hash
|
82
|
-
|
83
|
-
new_screenshots.each do |key, value|
|
84
|
-
if key.kind_of?String and value.kind_of?Array and value.count > 0 and value.first.kind_of?AppScreenshot
|
85
|
-
|
86
|
-
self.clear_all_screenshots(key)
|
87
|
-
|
88
|
-
value.each do |screen|
|
89
|
-
add_screenshot(key, screen)
|
90
|
-
end
|
91
|
-
else
|
92
|
-
raise AppMetadataParameterError.new(error_text)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
true
|
96
|
-
end
|
97
|
-
|
98
|
-
# Automatically add all screenshots contained in the given directory to the app.
|
99
|
-
#
|
100
|
-
# This method will automatically detect which device type each screenshot is.
|
101
|
-
#
|
102
|
-
# This will also clear all existing screenshots before setting the new ones.
|
103
|
-
# @param (Hash) hash A hash containing a different path for each locale ({FastlaneCore::Languages::ALL_LANGUAGES})
|
104
|
-
# @param (Bool) Use the framed screenshots? Only use it if you use frameit 2.0
|
105
|
-
|
106
|
-
def set_screenshots_for_each_language(hash, use_framed = false)
|
107
|
-
raise AppMetadataParameterError.new("Parameter needs to be an hash, containg strings with the new description") unless hash.kind_of?Hash
|
108
|
-
hash.each do |language, current_path|
|
109
|
-
resulting_path = "#{current_path}/**/*.{png,jpg,jpeg}"
|
110
|
-
|
111
|
-
raise AppMetadataParameterError.new(INVALID_LANGUAGE_ERROR) unless FastlaneCore::Languages::ALL_LANGUAGES.include?language
|
112
|
-
|
113
|
-
# https://stackoverflow.com/questions/21688855/
|
114
|
-
# File::FNM_CASEFOLD = ignore case
|
115
|
-
if Dir.glob(resulting_path, File::FNM_CASEFOLD).count == 0
|
116
|
-
Helper.log.error("No screenshots found at the given path '#{resulting_path}'")
|
117
|
-
else
|
118
|
-
self.clear_all_screenshots(language)
|
119
|
-
|
120
|
-
Dir.glob(resulting_path, File::FNM_CASEFOLD).sort.each do |path|
|
121
|
-
# When frameit is enabled, we only want to upload the framed screenshots
|
122
|
-
if use_framed
|
123
|
-
# Except for Watch screenshots, they are okay without _framed
|
124
|
-
is_apple_watch = ((AppScreenshot.new(path).screen_size == AppScreenshot::ScreenSize::IOS_APPLE_WATCH) rescue false)
|
125
|
-
unless is_apple_watch
|
126
|
-
next unless path.include?"_framed."
|
127
|
-
end
|
128
|
-
else
|
129
|
-
next if path.include?"_framed."
|
130
|
-
end
|
131
|
-
|
132
|
-
begin
|
133
|
-
add_screenshot(language, Deliver::AppScreenshot.new(path))
|
134
|
-
rescue AppMetadataTooManyScreenshotsError => ex
|
135
|
-
# We just use the first 5 ones
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
true
|
142
|
-
end
|
143
|
-
|
144
|
-
# This method will run through all the available locales, check if there is
|
145
|
-
# a folder for this language (e.g. 'en-US') and use all screenshots in there
|
146
|
-
# @param (String) path A path to the folder, which contains a folder for each locale
|
147
|
-
# @param (Bool) Use the framed screenshots? Only use it if you use frameit 2.0
|
148
|
-
def set_all_screenshots_from_path(path, use_framed = false)
|
149
|
-
raise AppMetadataParameterError.new("Parameter needs to be a path (string)") unless path.kind_of?String
|
150
|
-
|
151
|
-
found = false
|
152
|
-
FastlaneCore::Languages::ALL_LANGUAGES.each do |language|
|
153
|
-
full_path = File.join(path, language)
|
154
|
-
if File.directory?(full_path)
|
155
|
-
found = true
|
156
|
-
set_screenshots_for_each_language({
|
157
|
-
language => full_path
|
158
|
-
}, use_framed)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# Legacy:
|
163
|
-
# We also want to support the "legacy" language format (ja-JP instead of just ja)
|
164
|
-
FastlaneCore::Languages::ALL_LANGUAGES_LEGACY.each do |language|
|
165
|
-
full_path = File.join(path, language)
|
166
|
-
if File.directory?(full_path)
|
167
|
-
|
168
|
-
if FastlaneCore::Languages::ALL_LANGUAGES.include?language
|
169
|
-
# We're all good, this language code is still supported
|
170
|
-
else
|
171
|
-
# This language code was changed - need to modify that
|
172
|
-
short_code = language.match(/(\w\w)\-.*/)
|
173
|
-
if short_code and short_code.length == 2
|
174
|
-
Helper.log.info "Using language code #{short_code[1]} instead of #{language}"
|
175
|
-
language = short_code[1]
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
found = true
|
180
|
-
set_screenshots_for_each_language({
|
181
|
-
language => full_path
|
182
|
-
}, use_framed)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
return found
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
@@ -1,426 +0,0 @@
|
|
1
|
-
module Deliver
|
2
|
-
# This class takes care of verifying all inputs and triggering the upload process
|
3
|
-
class DeliverProcess
|
4
|
-
|
5
|
-
# DeliverUnitTestsError is triggered, when the unit tests of the given block failed.
|
6
|
-
class DeliverUnitTestsError < StandardError
|
7
|
-
end
|
8
|
-
|
9
|
-
# @return (Deliver::App) The App that is currently being edited.
|
10
|
-
attr_accessor :app
|
11
|
-
|
12
|
-
# @return (Deliver::IpaUploader) The IPA uploader that is currently being used.
|
13
|
-
attr_accessor :ipa
|
14
|
-
|
15
|
-
# @return (Hash) All the updated/new information we got from the Deliverfile.
|
16
|
-
# is used to store the deploy information until the Deliverfile finished running.
|
17
|
-
attr_accessor :deploy_information
|
18
|
-
|
19
|
-
# @return (String): The app identifier of the currently used app (e.g. com.krausefx.app)
|
20
|
-
attr_accessor :app_identifier
|
21
|
-
|
22
|
-
def initialize(deploy_information = nil)
|
23
|
-
@deploy_information = deploy_information || {}
|
24
|
-
@deploy_information[:blocks] ||= {}
|
25
|
-
end
|
26
|
-
|
27
|
-
def run
|
28
|
-
begin
|
29
|
-
fetch_information_from_ipa_file
|
30
|
-
pre_load_default_values
|
31
|
-
|
32
|
-
unless metadata_only?
|
33
|
-
run_unit_tests
|
34
|
-
end
|
35
|
-
|
36
|
-
Helper.log.info("Got all information needed to deploy a new update ('#{app_version}') for app '#{app_identifier}'")
|
37
|
-
|
38
|
-
verify_app_on_itunesconnect unless metadata_only?
|
39
|
-
|
40
|
-
|
41
|
-
if is_beta_build?
|
42
|
-
Helper.log.info "Beta builds don't upload new metadata to iTunesConnect".yellow
|
43
|
-
else
|
44
|
-
upload_metadata
|
45
|
-
end
|
46
|
-
|
47
|
-
# Always upload a new ipa (except if none was given)
|
48
|
-
trigger_ipa_upload unless metadata_only?
|
49
|
-
|
50
|
-
call_success_block
|
51
|
-
rescue => ex
|
52
|
-
call_error_block(ex)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def upload_metadata
|
57
|
-
if ready_for_sale?
|
58
|
-
raise "Cannot update metadata of apps 'Ready for Sale'. You can dupe: http://www.openradar.appspot.com/18263306".red
|
59
|
-
end
|
60
|
-
|
61
|
-
load_metadata_from_config_json_folder # the json file generated from the quick start # deprecated
|
62
|
-
load_metadata_folder # this is the new way of defining app metadata
|
63
|
-
set_app_metadata
|
64
|
-
set_screenshots
|
65
|
-
|
66
|
-
verify_pdf_file
|
67
|
-
|
68
|
-
additional_itc_information # e.g. copyright, age rating
|
69
|
-
|
70
|
-
trigger_metadata_upload
|
71
|
-
end
|
72
|
-
|
73
|
-
#####################################################
|
74
|
-
# @!group Getters
|
75
|
-
#####################################################
|
76
|
-
|
77
|
-
def app
|
78
|
-
return @app if @app
|
79
|
-
|
80
|
-
@app = Deliver::App.new(app_identifier: app_identifier,
|
81
|
-
apple_id: @deploy_information[Deliverer::ValKey::APPLE_ID]) # apple_id can be nil, will be fetched automatically
|
82
|
-
end
|
83
|
-
|
84
|
-
def app_version
|
85
|
-
return @app_version if @app_version
|
86
|
-
|
87
|
-
if Helper.is_test?
|
88
|
-
raise "No App Version given"
|
89
|
-
end
|
90
|
-
|
91
|
-
@app_version ||= ask("Which version number should be updated? ")
|
92
|
-
end
|
93
|
-
|
94
|
-
def app_identifier
|
95
|
-
return @app_identifier if @app_identifier
|
96
|
-
|
97
|
-
if Helper.is_test?
|
98
|
-
raise "No App Identifier given"
|
99
|
-
end
|
100
|
-
|
101
|
-
Helper.log.info "No App Identifier found. Pass one using `app_identifier` in your Deliverfile".yellow
|
102
|
-
@app_identifier = ask("App Identifier (e.g. com.krausefx.app): ")
|
103
|
-
end
|
104
|
-
|
105
|
-
# Preloads default values from the given hashes + Appfile
|
106
|
-
def pre_load_default_values
|
107
|
-
@app_identifier ||= @deploy_information[Deliverer::ValKey::APP_IDENTIFIER]
|
108
|
-
@app_identifier ||= (CredentialsManager::AppfileConfig.try_fetch_value(:app_identifier) rescue nil)
|
109
|
-
@app_identifier ||= (@ipa.fetch_app_identifier rescue nil) # since ipa might be nil
|
110
|
-
|
111
|
-
@app_version ||= @deploy_information[Deliverer::ValKey::APP_VERSION]
|
112
|
-
@app_version ||= ENV["DELIVER_VERSION"] if ENV["DELIVER_VERSION"].to_s.length > 0
|
113
|
-
@app_version ||= (@ipa.fetch_app_version rescue nil) # since ipa might be nil
|
114
|
-
@app_version ||= (app.get_live_version rescue nil) # pull the latest version from iTunes Connect
|
115
|
-
end
|
116
|
-
|
117
|
-
#####################################################
|
118
|
-
# @!group What kind of release
|
119
|
-
#####################################################
|
120
|
-
|
121
|
-
# Deployment = Submission of the binary
|
122
|
-
def skip_deployment?
|
123
|
-
@deploy_information[Deliverer::ValKey::SKIP_DEPLOY]
|
124
|
-
end
|
125
|
-
|
126
|
-
# Release = App Store and not TestFlight
|
127
|
-
def is_release_build?
|
128
|
-
is_beta_build? == false
|
129
|
-
end
|
130
|
-
|
131
|
-
# TestFlight Buil
|
132
|
-
def is_beta_build?
|
133
|
-
@deploy_information[Deliverer::ValKey::IS_BETA_IPA]
|
134
|
-
end
|
135
|
-
|
136
|
-
# Only upload metadata and no binary
|
137
|
-
def metadata_only?
|
138
|
-
ENV["DELIVER_SKIP_BINARY"]
|
139
|
-
end
|
140
|
-
|
141
|
-
# Is the app already ready for sale?
|
142
|
-
# if so, we can't update the app metadata: http://www.openradar.appspot.com/18263306
|
143
|
-
def ready_for_sale?
|
144
|
-
return false if Helper.is_test?
|
145
|
-
return @ready if @checked_for_ready
|
146
|
-
|
147
|
-
@checked_for_ready = true
|
148
|
-
@ready = (app.get_app_status == App::AppStatus::READY_FOR_SALE)
|
149
|
-
end
|
150
|
-
|
151
|
-
#####################################################
|
152
|
-
# @!group All the methods
|
153
|
-
#####################################################
|
154
|
-
|
155
|
-
def run_unit_tests
|
156
|
-
if @deploy_information[:blocks][:unit_tests]
|
157
|
-
result = @deploy_information[:blocks][:unit_tests].call
|
158
|
-
if result
|
159
|
-
Helper.log.debug("Unit tests successful".green)
|
160
|
-
else
|
161
|
-
raise DeliverUnitTestsError.new("Unit tests failed. Got result: '#{result}'. Need 'true' or 1 to succeed.".red)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def fetch_information_from_ipa_file
|
167
|
-
used_ipa_file = ENV["IPA_OUTPUT_PATH"]# if (ENV["IPA_OUTPUT_PATH"] and File.exists?(ENV["IPA_OUTPUT_PATH"]))
|
168
|
-
|
169
|
-
if is_release_build?
|
170
|
-
used_ipa_file = @deploy_information[:ipa] if @deploy_information[:ipa]
|
171
|
-
elsif is_beta_build?
|
172
|
-
used_ipa_file = @deploy_information[:beta_ipa] if @deploy_information[:beta_ipa]
|
173
|
-
end
|
174
|
-
|
175
|
-
if used_ipa_file.kind_of?Proc
|
176
|
-
# The user provided a block. We only want to execute the block now, since it might be a long build step
|
177
|
-
used_ipa_file = used_ipa_file.call
|
178
|
-
|
179
|
-
Deliverfile::Deliverfile::DSL.validate_ipa!(used_ipa_file)
|
180
|
-
end
|
181
|
-
|
182
|
-
if (used_ipa_file || '').length == 0 and is_beta_build?
|
183
|
-
# Beta Release but no ipa given
|
184
|
-
used_ipa_file = Dir["*.ipa"].first
|
185
|
-
|
186
|
-
unless used_ipa_file
|
187
|
-
raise "Could not find an ipa file for 'beta' mode. Provide one using `beta_ipa do ... end` in your Deliverfile.".red
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
ENV["DELIVER_IPA_PATH"] = used_ipa_file
|
192
|
-
|
193
|
-
if used_ipa_file
|
194
|
-
upload_strategy = Deliver::IPA_UPLOAD_STRATEGY_APP_STORE
|
195
|
-
if is_beta_build?
|
196
|
-
upload_strategy = Deliver::IPA_UPLOAD_STRATEGY_BETA_BUILD
|
197
|
-
end
|
198
|
-
if skip_deployment?
|
199
|
-
upload_strategy = Deliver::IPA_UPLOAD_STRATEGY_JUST_UPLOAD
|
200
|
-
Helper.log.info "Skipping submission of app update"
|
201
|
-
end
|
202
|
-
|
203
|
-
@ipa = Deliver::IpaUploader.new(Deliver::App.new, '/tmp/', used_ipa_file, upload_strategy)
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
def verify_app_on_itunesconnect
|
208
|
-
if (@ipa and is_release_build?) or !@ipa
|
209
|
-
# This is a real release, which should also upload the ipa file onto production
|
210
|
-
app.create_new_version!(app_version) unless Helper.is_test?
|
211
|
-
app.metadata.verify_version(app_version) if @ipa
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
def options_mapping
|
216
|
-
{
|
217
|
-
'title' => Deliverer::ValKey::TITLE,
|
218
|
-
'description' => Deliverer::ValKey::DESCRIPTION,
|
219
|
-
'version_whats_new' => Deliverer::ValKey::CHANGELOG,
|
220
|
-
'keywords' => Deliverer::ValKey::KEYWORDS,
|
221
|
-
'privacy_url' => Deliverer::ValKey::PRIVACY_URL,
|
222
|
-
'software_url' => Deliverer::ValKey::MARKETING_URL,
|
223
|
-
'support_url' => Deliverer::ValKey::SUPPORT_URL
|
224
|
-
}
|
225
|
-
end
|
226
|
-
|
227
|
-
def load_metadata_from_config_json_folder
|
228
|
-
return unless @deploy_information[Deliverer::ValKey::CONFIG_JSON_FOLDER]
|
229
|
-
|
230
|
-
file_path = @deploy_information[:config_json_folder]
|
231
|
-
unless file_path.split("/").last.include?"metadata.json"
|
232
|
-
file_path += "/metadata.json"
|
233
|
-
end
|
234
|
-
|
235
|
-
raise "Could not find metadatafile at path '#{file_path}'".red unless File.exists?file_path
|
236
|
-
|
237
|
-
content = JSON.parse(File.read(file_path))
|
238
|
-
content.each do |language, current|
|
239
|
-
|
240
|
-
options_mapping.each do |key, value|
|
241
|
-
if current[key]
|
242
|
-
@deploy_information[value] ||= {}
|
243
|
-
@deploy_information[value][language] ||= current[key]
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
def load_metadata_folder
|
250
|
-
# Fetch the information from the ./metadata folder if it exists
|
251
|
-
metadata_folder = './metadata'
|
252
|
-
return unless File.exists?metadata_folder
|
253
|
-
|
254
|
-
Dir[File.join(metadata_folder, '*')].each do |language_folder|
|
255
|
-
language = File.basename(language_folder)
|
256
|
-
|
257
|
-
options_mapping.each do |key, value|
|
258
|
-
content = File.read(File.join(language_folder, "#{key}.txt")) rescue nil
|
259
|
-
next unless content
|
260
|
-
content = content.split("\n") if key == 'keywords'
|
261
|
-
content = content.strip if ['privacy_url', 'software_url', 'support_url'].include?key
|
262
|
-
@deploy_information[value] ||= {}
|
263
|
-
@deploy_information[value][language] ||= content
|
264
|
-
|
265
|
-
Helper.log.info "Successfully loaded content from '#{key}.txt' for language #{language_folder}"
|
266
|
-
end
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
def set_app_metadata
|
271
|
-
app.metadata.update_title(@deploy_information[Deliverer::ValKey::TITLE]) if @deploy_information[Deliverer::ValKey::TITLE]
|
272
|
-
app.metadata.update_description(@deploy_information[Deliverer::ValKey::DESCRIPTION]) if @deploy_information[Deliverer::ValKey::DESCRIPTION]
|
273
|
-
|
274
|
-
app.metadata.update_support_url(@deploy_information[Deliverer::ValKey::SUPPORT_URL]) if @deploy_information[Deliverer::ValKey::SUPPORT_URL]
|
275
|
-
app.metadata.update_changelog(@deploy_information[Deliverer::ValKey::CHANGELOG]) if @deploy_information[Deliverer::ValKey::CHANGELOG]
|
276
|
-
app.metadata.update_marketing_url(@deploy_information[Deliverer::ValKey::MARKETING_URL]) if @deploy_information[Deliverer::ValKey::MARKETING_URL]
|
277
|
-
app.metadata.update_privacy_url(@deploy_information[Deliverer::ValKey::PRIVACY_URL]) if @deploy_information[Deliverer::ValKey::PRIVACY_URL]
|
278
|
-
|
279
|
-
app.metadata.update_keywords(@deploy_information[Deliverer::ValKey::KEYWORDS]) if @deploy_information[Deliverer::ValKey::KEYWORDS]
|
280
|
-
|
281
|
-
app.metadata.update_price_tier(@deploy_information[Deliverer::ValKey::PRICE_TIER]) if @deploy_information[Deliverer::ValKey::PRICE_TIER]
|
282
|
-
end
|
283
|
-
|
284
|
-
def screenshots_path
|
285
|
-
return @screens_path if @screens_path
|
286
|
-
|
287
|
-
@screens_path = @deploy_information[Deliverer::ValKey::SCREENSHOTS_PATH]
|
288
|
-
if (ENV["DELIVER_SCREENSHOTS_PATH"] || '').length > 0
|
289
|
-
Helper.log.warn "Overwriting screenshots path from config (#{@screens_path}) with (#{ENV["DELIVER_SCREENSHOTS_PATH"]})".yellow
|
290
|
-
@screens_path = ENV["DELIVER_SCREENSHOTS_PATH"]
|
291
|
-
end
|
292
|
-
|
293
|
-
@screens_path ||= "./screenshots/" # default value
|
294
|
-
|
295
|
-
return @screens_path
|
296
|
-
end
|
297
|
-
|
298
|
-
def set_screenshots
|
299
|
-
screens_path = screenshots_path
|
300
|
-
if screens_path
|
301
|
-
# Not using Snapfile. Not a good user.
|
302
|
-
if not app.metadata.set_all_screenshots_from_path(screens_path, use_framed_screenshots?)
|
303
|
-
# This path does not contain folders for each language
|
304
|
-
if screens_path.kind_of?String
|
305
|
-
if @deploy_information[Deliverer::ValKey::DEFAULT_LANGUAGE]
|
306
|
-
screens_path = { @deploy_information[Deliverer::ValKey::DEFAULT_LANGUAGE] => screens_path } # use the default language
|
307
|
-
@deploy_information[Deliverer::ValKey::SCREENSHOTS_PATH] = screens_path
|
308
|
-
else
|
309
|
-
Helper.log.error "You must have folders for the screenshots (#{screens_path}) for each language (e.g. en-US, de-DE)."
|
310
|
-
screens_path = nil
|
311
|
-
end
|
312
|
-
end
|
313
|
-
app.metadata.set_screenshots_for_each_language(screens_path, use_framed_screenshots?) if screens_path
|
314
|
-
end
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
# Should _framed screenshots be used for the screenshot upload?
|
319
|
-
# This will only be true if there is a Framefile, as this makes the screenshots valid
|
320
|
-
# since the resolution is only correct when using a background + title using frameit 2.0
|
321
|
-
def use_framed_screenshots?
|
322
|
-
return Dir[screenshots_path + "**/Framefile.json"].count > 0
|
323
|
-
end
|
324
|
-
|
325
|
-
def verify_pdf_file
|
326
|
-
if @deploy_information[Deliverer::ValKey::SKIP_PDF]
|
327
|
-
Helper.log.debug "PDF verify was skipped"
|
328
|
-
else
|
329
|
-
# Everything is prepared for the upload
|
330
|
-
# We may have to ask the user if that's okay
|
331
|
-
html_path = HtmlGenerator.new.render(self)
|
332
|
-
unless Helper.is_test?
|
333
|
-
puts "----------------------------------------------------------------------------"
|
334
|
-
puts "Verifying the upload via the HTML file can be disabled by either adding"
|
335
|
-
puts "'skip_pdf true' to your Deliverfile or using the flag --force."
|
336
|
-
puts "----------------------------------------------------------------------------"
|
337
|
-
|
338
|
-
system("open '#{html_path}'")
|
339
|
-
okay = agree("Does the Preview on path '#{html_path}' look okay for you? (blue = updated) (y/n)", true)
|
340
|
-
|
341
|
-
unless okay
|
342
|
-
dir ||= app.get_metadata_directory
|
343
|
-
dir += "/#{app.apple_id}.itmsp"
|
344
|
-
FileUtils.rm_rf(dir) unless Helper.is_test?
|
345
|
-
raise "Did not upload the metadata, because the HTML file was rejected by the user".yellow
|
346
|
-
end
|
347
|
-
end
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
def trigger_metadata_upload
|
352
|
-
result = app.metadata.upload!
|
353
|
-
raise "Error uploading app metadata".red unless result == true
|
354
|
-
end
|
355
|
-
|
356
|
-
def itc
|
357
|
-
@itc ||= ItunesConnect.new
|
358
|
-
end
|
359
|
-
|
360
|
-
def additional_itc_information
|
361
|
-
# e.g. rating or copyright
|
362
|
-
itc.set_copyright!(app, @deploy_information[Deliverer::ValKey::COPYRIGHT]) if @deploy_information[Deliverer::ValKey::COPYRIGHT]
|
363
|
-
itc.set_app_review_information!(app, @deploy_information[Deliverer::ValKey::APP_REVIEW_INFORMATION]) if @deploy_information[Deliverer::ValKey::APP_REVIEW_INFORMATION]
|
364
|
-
itc.set_release_after_approval!(app, @deploy_information[Deliverer::ValKey::AUTOMATIC_RELEASE]) if @deploy_information[Deliverer::ValKey::AUTOMATIC_RELEASE] != nil
|
365
|
-
|
366
|
-
# Categories
|
367
|
-
primary = @deploy_information[Deliverer::ValKey::PRIMARY_CATEGORY]
|
368
|
-
secondary = @deploy_information[Deliverer::ValKey::SECONDARY_CATEGORY]
|
369
|
-
primary_subcategories = @deploy_information[Deliverer::ValKey::PRIMARY_SUBCATEGORIES]
|
370
|
-
secondary_subcategories = @deploy_information[Deliverer::ValKey::SECONDARY_SUBCATEGORIES]
|
371
|
-
itc.set_categories!(app, primary, secondary, primary_subcategories, secondary_subcategories) if (primary or secondary)
|
372
|
-
|
373
|
-
# App Rating
|
374
|
-
itc.set_app_rating!(app, @deploy_information[Deliverer::ValKey::RATINGS_CONFIG_PATH]) if @deploy_information[Deliverer::ValKey::RATINGS_CONFIG_PATH]
|
375
|
-
|
376
|
-
# App Icon
|
377
|
-
itc.upload_app_icon!(app, @deploy_information[Deliverer::ValKey::APP_ICON]) if @deploy_information[Deliverer::ValKey::APP_ICON]
|
378
|
-
|
379
|
-
# Apple Watch App Icon
|
380
|
-
itc.upload_apple_watch_app_icon!(app, @deploy_information[Deliverer::ValKey::APPLE_WATCH_APP_ICON]) if @deploy_information[Deliverer::ValKey::APPLE_WATCH_APP_ICON]
|
381
|
-
end
|
382
|
-
|
383
|
-
def trigger_ipa_upload
|
384
|
-
if @ipa
|
385
|
-
@ipa.app = app # we now have the resulting app
|
386
|
-
result = @ipa.upload! # Important: this will also actually deploy the app on iTunesConnect
|
387
|
-
raise "Error uploading ipa file".red unless result == true
|
388
|
-
else
|
389
|
-
Helper.log.warn "No IPA file given. Only the metadata was uploaded. If you want to deploy a full update, provide an ipa file."
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
def call_success_block
|
394
|
-
if @deploy_information[:blocks][:success]
|
395
|
-
@deploy_information[:blocks][:success].call(hash_for_callback)
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
def call_error_block(ex)
|
400
|
-
if @deploy_information[:blocks][:error]
|
401
|
-
# Custom error handling, we just call this one
|
402
|
-
@deploy_information[:blocks][:error].call(hash_for_callback(ex))
|
403
|
-
end
|
404
|
-
|
405
|
-
# Re-Raise the exception
|
406
|
-
raise ex
|
407
|
-
end
|
408
|
-
|
409
|
-
private
|
410
|
-
#####################################################
|
411
|
-
# @!group All the helper methods
|
412
|
-
#####################################################
|
413
|
-
|
414
|
-
def hash_for_callback(error = nil)
|
415
|
-
{
|
416
|
-
error: error,
|
417
|
-
app_version: (app_version rescue nil),
|
418
|
-
app_identifier: (app_identifier rescue nil),
|
419
|
-
skipped_deploy: skip_deployment?,
|
420
|
-
is_release_build: is_release_build?,
|
421
|
-
is_beta_build: is_beta_build?,
|
422
|
-
ipa_path: ENV["DELIVER_IPA_PATH"]
|
423
|
-
}
|
424
|
-
end
|
425
|
-
end
|
426
|
-
end
|