deliver 0.13.5 → 1.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -208
  3. data/bin/deliver +1 -1
  4. data/lib/assets/DeliverfileDefault +2 -22
  5. data/lib/assets/summary.html.erb +27 -39
  6. data/lib/deliver.rb +16 -14
  7. data/lib/deliver/app_screenshot.rb +43 -33
  8. data/lib/deliver/commands_generator.rb +30 -108
  9. data/lib/deliver/detect_values.rb +23 -0
  10. data/lib/deliver/download_screenshots.rb +30 -9
  11. data/lib/deliver/html_generator.rb +7 -8
  12. data/lib/deliver/options.rb +126 -0
  13. data/lib/deliver/runner.rb +75 -0
  14. data/lib/deliver/setup.rb +84 -0
  15. data/lib/deliver/submit_for_review.rb +60 -0
  16. data/lib/deliver/upload_assets.rb +22 -0
  17. data/lib/deliver/upload_metadata.rb +100 -0
  18. data/lib/deliver/upload_price_tier.rb +21 -0
  19. data/lib/deliver/upload_screenshots.rb +63 -0
  20. data/lib/deliver/version.rb +2 -1
  21. metadata +37 -62
  22. data/lib/assets/DeliverLanguageMapping.json +0 -187
  23. data/lib/assets/DeliverfileExample +0 -38
  24. data/lib/deliver/app.rb +0 -167
  25. data/lib/deliver/app_metadata.rb +0 -419
  26. data/lib/deliver/app_metadata_screenshots.rb +0 -189
  27. data/lib/deliver/deliver_process.rb +0 -426
  28. data/lib/deliver/deliverer.rb +0 -138
  29. data/lib/deliver/deliverfile/deliverfile.rb +0 -35
  30. data/lib/deliver/deliverfile/deliverfile_creator.rb +0 -135
  31. data/lib/deliver/deliverfile/dsl.rb +0 -142
  32. data/lib/deliver/dependency_checker.rb +0 -19
  33. data/lib/deliver/ipa_file_analyser.rb +0 -44
  34. data/lib/deliver/ipa_uploader.rb +0 -148
  35. data/lib/deliver/itunes_connect/itunes_connect.rb +0 -12
  36. data/lib/deliver/itunes_connect/itunes_connect_additional.rb +0 -105
  37. data/lib/deliver/itunes_connect/itunes_connect_app_icon.rb +0 -41
  38. data/lib/deliver/itunes_connect/itunes_connect_app_rating.rb +0 -90
  39. data/lib/deliver/itunes_connect/itunes_connect_apple_watch_app_icon.rb +0 -42
  40. data/lib/deliver/itunes_connect/itunes_connect_information.rb +0 -34
  41. data/lib/deliver/itunes_connect/itunes_connect_new_version.rb +0 -67
  42. data/lib/deliver/itunes_connect/itunes_connect_reader.rb +0 -46
  43. data/lib/deliver/itunes_connect/itunes_connect_screenshot_fetcher.rb +0 -54
  44. data/lib/deliver/itunes_connect/itunes_connect_submission.rb +0 -282
  45. data/lib/deliver/itunes_transporter.rb +0 -221
  46. data/lib/deliver/metadata_item.rb +0 -94
  47. data/lib/deliver/testflight.rb +0 -27
@@ -1,19 +0,0 @@
1
- module Deliver
2
- class DependencyChecker
3
- def self.check_dependencies
4
- return if Helper.is_test?
5
- self.check_xcode_select
6
- end
7
-
8
- def self.check_xcode_select
9
- unless `xcode-select -v`.include?"xcode-select version "
10
- Helper.log.fatal '#############################################################'
11
- Helper.log.fatal "# You have to install the Xcode commdand line tools to use deliver"
12
- Helper.log.fatal "# Install the latest version of Xcode from the AppStore"
13
- Helper.log.fatal "# Run xcode-select --install to install the developer tools"
14
- Helper.log.fatal '#############################################################'
15
- raise "Run 'xcode-select --install' and start deliver again"
16
- end
17
- end
18
- end
19
- end
@@ -1,44 +0,0 @@
1
- module Deliver
2
- class IpaFileAnalyser
3
-
4
- # Fetches the app identifier (e.g. com.facebook.Facebook) from the given ipa file.
5
- def self.fetch_app_identifier(path)
6
- plist = IpaFileAnalyser.fetch_info_plist_file(path)
7
- return plist['CFBundleIdentifier'] if plist
8
- return nil
9
- end
10
-
11
- # Fetches the app version from the given ipa file.
12
- def self.fetch_app_version(path)
13
- plist = IpaFileAnalyser.fetch_info_plist_file(path)
14
- return plist['CFBundleShortVersionString'] if plist
15
- return nil
16
- end
17
-
18
- def self.fetch_info_plist_file(path)
19
- Zip::File.open(path) do |zipfile|
20
- zipfile.each do |file|
21
- if file.name.include?'.plist' and not ['.bundle', '.framework'].any? { |a| file.name.include?a }
22
- # We can not be completely sure, that's the correct plist file, so we have to try
23
- begin
24
- # The XML file has to be properly unpacked first
25
- tmp_path = "/tmp/deploytmp.plist"
26
- File.write(tmp_path, zipfile.read(file))
27
- system("plutil -convert xml1 #{tmp_path}")
28
- result = Plist::parse_xml(tmp_path)
29
- File.delete(tmp_path)
30
-
31
- if result['CFBundleIdentifier'] or result['CFBundleVersion']
32
- return result
33
- end
34
- rescue
35
- # We don't really care, look for another XML file
36
- end
37
- end
38
- end
39
- end
40
-
41
- nil
42
- end
43
- end
44
- end
@@ -1,148 +0,0 @@
1
- require 'zip'
2
- require 'plist'
3
-
4
- module Deliver
5
- class IpaUploaderError < StandardError
6
- end
7
-
8
- IPA_UPLOAD_STRATEGY_APP_STORE = 1
9
- IPA_UPLOAD_STRATEGY_BETA_BUILD = 2
10
- IPA_UPLOAD_STRATEGY_JUST_UPLOAD = 3
11
-
12
- # This class takes care of preparing and uploading the given ipa file
13
- # Metadata + IPA file can not be handled in one file
14
- class IpaUploader < AppMetadata
15
- attr_accessor :app
16
- attr_accessor :publish_strategy
17
-
18
- # Create a new uploader for one ipa file. This will only upload the ipa and no
19
- # other app metadata.
20
- # @param app (Deliver::App) The app for which the ipa should be uploaded for
21
- # @param dir (String) The path to where we can store (copy) the ipa file. Usually /tmp/
22
- # @param ipa_path (String) The path to the IPA file which should be uploaded
23
- # @param publish_strategy (Int) If it's a beta build, it will be released to the testers.
24
- # If it's a production build it will be released into production. Otherwise no action.
25
- # @raise (IpaUploaderError) Is thrown when the ipa file was not found or is not valid
26
- def initialize(app, dir, ipa_path, publish_strategy)
27
- ipa_path.dup.strip! # remove unused white spaces
28
- raise IpaUploaderError.new("IPA on path '#{ipa_path}' not found") unless File.exists?(ipa_path)
29
- raise IpaUploaderError.new("IPA on path '#{ipa_path}' is not a valid IPA file") unless ipa_path.include?".ipa"
30
-
31
- super(app, dir, false)
32
-
33
- @ipa_file = Deliver::MetadataItem.new(ipa_path)
34
- @publish_strategy = publish_strategy
35
- end
36
-
37
- # Fetches the app identifier (e.g. com.facebook.Facebook) from the given ipa file.
38
- def fetch_app_identifier
39
- return IpaFileAnalyser.fetch_app_identifier(@ipa_file.path)
40
- end
41
-
42
- # Fetches the app version from the given ipa file.
43
- def fetch_app_version
44
- return IpaFileAnalyser.fetch_app_version(@ipa_file.path)
45
- end
46
-
47
-
48
- #####################################################
49
- # @!group Uploading the ipa file
50
- #####################################################
51
-
52
- # Actually upload the ipa file to Apple
53
- # @param submit_information (Hash) A hash containing submit information (export, content rights)
54
- def upload!(submit_information = nil)
55
- Helper.log.info "Uploading ipa file to iTunesConnect"
56
- build_document
57
-
58
- # Write the current XML state to disk
59
- folder_name = "#{@app.apple_id}.itmsp"
60
- path = "#{@metadata_dir}/#{folder_name}/"
61
- FileUtils.mkdir_p path
62
-
63
- File.write("#{path}/#{METADATA_FILE_NAME}", @data.to_xml)
64
-
65
- @ipa_file.store_file_inside_package(path)
66
-
67
- is_okay = true
68
- begin
69
- is_okay = transporter.upload(@app, @metadata_dir)
70
- rescue => ex
71
- Helper.log.debug ex
72
- is_okay = ex.to_s.include?"ready exists a binary upload with build" # this just means, the ipa is already online
73
- end
74
-
75
- if is_okay
76
- unless Helper.is_test?
77
- return publish_on_itunes_connect(submit_information)
78
- end
79
- end
80
-
81
- return is_okay
82
- end
83
-
84
-
85
-
86
- private
87
- # This method will trigger the iTunesConnect class to choose the latest build
88
- # @return Was it successful?
89
- def publish_on_itunes_connect(submit_information = nil)
90
- if @publish_strategy == IPA_UPLOAD_STRATEGY_APP_STORE
91
- return publish_production_build(submit_information)
92
- elsif @publish_strategy == IPA_UPLOAD_STRATEGY_BETA_BUILD
93
- return publish_beta_build
94
- else
95
- Helper.log.info "deliver will **not** submit the app for Review or for TestFlight distribution".yellow
96
- Helper.log.info "If you want to distribute the binary, don't define `skip_deploy` ".yellow
97
-
98
- if ENV["DELIVER_WHAT_TO_TEST"] or ENV["DELIVER_BETA_DESCRIPTION"] or ENV["DELIVER_BETA_FEEDBACK_EMAIL"]
99
- Helper.log.warn "---------------------------------------------------".yellow
100
- Helper.log.warn "You provided beta version metadata, but used the ".yellow
101
- Helper.log.warn "`skip_deploy` option when running deliver.".yellow
102
- Helper.log.warn "You have to remove `skip_deploy` to set a changelog".yellow
103
- Helper.log.warn "for TestFlight builds".yellow
104
- Helper.log.warn "---------------------------------------------------".yellow
105
- end
106
- end
107
- return true
108
- end
109
-
110
- def publish_beta_build
111
- # Distribute to beta testers
112
- Helper.log.info "Distributing the latest build to Beta Testers."
113
- if self.app.itc.put_build_into_beta_testing!(self.app, self.fetch_app_version)
114
- return true
115
- end
116
- return false
117
- end
118
-
119
- def publish_production_build(submit_information)
120
- # Publish onto Production
121
- Helper.log.info "Putting the latest build onto production."
122
- if self.app.itc.put_build_into_production!(self.app, self.fetch_app_version)
123
- if self.app.itc.submit_for_review!(self.app, submit_information)
124
- Helper.log.info "Successfully deployed a new update of your app. You can now enjoy a good cold Club Mate.".green
125
- return true
126
- end
127
- end
128
- return false
129
- end
130
-
131
-
132
- def build_document
133
- builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
134
- xml.package(xmlns: "http://apple.com/itunes/importer", version: "software4.7") {
135
- xml.software_assets(apple_id: @app.apple_id) {
136
- xml.asset(type: 'bundle') {
137
-
138
- }
139
- }
140
- }
141
- end
142
-
143
- @data = builder.doc
144
- asset = @data.xpath('//x:asset', "x" => Deliver::AppMetadata::ITUNES_NAMESPACE).first
145
- asset << @ipa_file.create_xml_node(@data)
146
- end
147
- end
148
- end
@@ -1,12 +0,0 @@
1
- require 'fastlane_core/itunes_connect/itunes_connect'
2
-
3
- # Import all the actions
4
- require 'deliver/itunes_connect/itunes_connect_submission'
5
- require 'deliver/itunes_connect/itunes_connect_reader'
6
- require 'deliver/itunes_connect/itunes_connect_new_version'
7
- require 'deliver/itunes_connect/itunes_connect_app_icon'
8
- require 'deliver/itunes_connect/itunes_connect_apple_watch_app_icon'
9
- require 'deliver/itunes_connect/itunes_connect_app_rating'
10
- require 'deliver/itunes_connect/itunes_connect_additional'
11
- require 'deliver/itunes_connect/itunes_connect_screenshot_fetcher'
12
- require 'deliver/itunes_connect/itunes_connect_information'
@@ -1,105 +0,0 @@
1
- module Deliver
2
- class ItunesConnect < FastlaneCore::ItunesConnect
3
- # This file sets additional information like copyright and age rating
4
-
5
- def set_copyright!(app, text)
6
- verify_app(app)
7
- open_app_page(app)
8
-
9
- Helper.log.info "Setting copyright to '#{text}'".green
10
-
11
- first("input[ng-model='versionInfo.copyright.value']").set text
12
-
13
- (click_on "Save" rescue nil) # if nothing has changed, there is no back button and we don't care
14
- rescue => ex
15
- error_occured(ex)
16
- end
17
-
18
- def set_app_review_information!(app, hash)
19
- verify_app(app)
20
- open_app_page(app)
21
-
22
- Helper.log.info "Setting review information: #{hash}"
23
-
24
- first("input[ng-model='versionInfo.appReviewInfo.firstName.value']").set hash[:first_name]
25
- first("input[ng-model='versionInfo.appReviewInfo.lastName.value']").set hash[:last_name]
26
- first("input[ng-model='versionInfo.appReviewInfo.phoneNumber.value']").set hash[:phone_number]
27
- first("input[ng-model='versionInfo.appReviewInfo.emailAddress.value']").set hash[:email_address]
28
- first("input[ng-model='versionInfo.appReviewInfo.userName.value']").set hash[:demo_user]
29
- first("input[ng-model='versionInfo.appReviewInfo.password.value']").set hash[:demo_password]
30
- first("span[ng-show='versionInfo.appReviewInfo.reviewNotes.isEditable'] > * > textarea").set hash[:notes]
31
-
32
- (click_on "Save" rescue nil) # if nothing has changed, there is no back button and we don't care
33
-
34
- Helper.log.info "Successfully saved review information".green
35
- rescue => ex
36
- error_occured(ex)
37
- end
38
-
39
- def set_release_after_approval!(app, automatic_release)
40
- verify_app(app)
41
- open_app_page(app)
42
-
43
- Helper.log.info "Setting automatic release to '#{automatic_release}'".green
44
-
45
- radio_value = automatic_release ? "true" : "false"
46
-
47
- # Find the correct radio button
48
- first("div[itc-radio='versionInfo.releaseOnApproval.value'][radio-value='#{radio_value}'] > * > a").click
49
-
50
- (click_on "Save" rescue nil) # if nothing has changed, there is no back button and we don't care
51
- rescue => ex
52
- error_occured(ex)
53
- end
54
-
55
- def set_categories!(app, primary, secondary, primarySubs, secondarySubs)
56
- verify_app(app)
57
- open_app_page(app)
58
-
59
- Helper.log.info "Setting primary/secondary category.'".green
60
-
61
- set_category_dropdown(primary, "primaryCategory")
62
-
63
- set_category_dropdown(secondary, "secondaryCategory")
64
-
65
- if primarySubs
66
- if primarySubs.length > 0
67
- set_category_dropdown(primarySubs[0], "primaryFirstSubCategory")
68
- end
69
- if primarySubs.length > 1
70
- set_category_dropdown(primarySubs[1], "primarySecondSubCategory")
71
- end
72
- end
73
-
74
- if secondarySubs
75
- if secondarySubs.length > 0
76
- set_category_dropdown(secondarySubs[0], "secondaryFirstSubCategory")
77
- end
78
- if secondarySubs.length > 1
79
- set_category_dropdown(secondarySubs[1], "secondarySecondSubCategory")
80
- end
81
- end
82
-
83
- (click_on "Save" rescue nil) # if nothing has changed, there is no back button and we don't care
84
- rescue => ex
85
- error_occured(ex)
86
- end
87
-
88
- private
89
-
90
- def set_category_dropdown(value, catId)
91
- if value
92
- all("select[ng-model='versionInfo.#{catId}.value'] > option").each do |category|
93
- if category.text.to_s == value.to_s
94
- category.select_option
95
- value = nil
96
- break
97
- end
98
- end
99
- if value
100
- Helper.log.info "Could not find #{catId} '#{value}'. Make sure it's available on iTC".red
101
- end
102
- end
103
- end
104
- end
105
- end
@@ -1,41 +0,0 @@
1
- require 'fastimage'
2
-
3
- module Deliver
4
- class ItunesConnect < FastlaneCore::ItunesConnect
5
- # Uploading a new full size app icon
6
-
7
- def upload_app_icon!(app, path)
8
- path = File.expand_path(path)
9
- raise "Could not find app icon at path '#{path}'".red unless File.exists?path
10
-
11
- size = FastImage.size(path)
12
- raise "App icon must have the resolution of 1024x1024px".red unless (size[0] == 1024 and size[1] == 1024)
13
-
14
- # Remove alpha channel
15
- Helper.log.info "Removing alpha channel from provided App Icon (iTunes Connect requirement)".green
16
-
17
- `sips -s format bmp '#{path}' &> /dev/null ` # &> /dev/null since there is warning because of the extension
18
- `sips -s format png '#{path}'`
19
-
20
- begin
21
- verify_app(app)
22
- open_app_page(app)
23
-
24
- Helper.log.info "Starting upload of new app icon".green
25
-
26
- evaluate_script("$('.appversionicon:not(.watchIcon) > .ios7-style-icon').prev().click()") # delete button
27
- evaluate_script("$('[style-class=\"appversionicon rounded\"] [itc-launch-filechooser] + input').attr('id', 'deliverFileUploadInput')") # set div
28
- evaluate_script("URL = webkitURL; URL.createObjectURL = function(){return 'blob:abc'}"); # shim URL
29
- page.attach_file("deliverFileUploadInput", path) # add file
30
-
31
- sleep 10
32
-
33
- click_on "Save"
34
-
35
- Helper.log.info "Finished uploading the new app icon".green
36
- rescue => ex
37
- error_occured(ex)
38
- end
39
- end
40
- end
41
- end
@@ -1,90 +0,0 @@
1
- require 'json'
2
-
3
- module Deliver
4
- class ItunesConnect < FastlaneCore::ItunesConnect
5
- # Setting the app's age restrictions
6
-
7
- def set_app_rating!(app, path_to_json)
8
- path_to_json = File.expand_path(path_to_json)
9
- raise "Could not find app rating JSON file" unless File.exists?(path_to_json)
10
-
11
- config = JSON.parse(File.read(path_to_json))
12
-
13
- verify_app(app)
14
- open_app_page(app)
15
-
16
- Helper.log.info "Updating the app's rating".green
17
-
18
- first("a[ng-show='versionInfo.ratings.isEditable']").click # open the ratings screen
19
-
20
- rows = wait_for_elements(".defaultTable.ratingsTable > tbody > tr.ng-scope") # .ng-scope, since there is one empty row
21
-
22
- if rows.count != (config.count - 1) # -1 the kids
23
- raise "The number of options passed in the config file does not match the number of options available on iTC! Make sure to use the latest template from https://github.com/KrauseFx/deliver/blob/master/assets/example_rating_config.json".red
24
- end
25
-
26
-
27
- # Setting all the values based on config file
28
- rows.each_with_index do |row, index|
29
- current = config[index]
30
-
31
- level = name_for_level(current['level'], current['type'] == 'boolean')
32
-
33
- Helper.log.info "Setting '#{current['comment']}' to #{level}.".green
34
-
35
- radio_value = "ITC.apps.ratings.level.#{level}"
36
-
37
- row.first("td > div[radio-value='#{radio_value}']").click
38
- end
39
-
40
-
41
- # Apple, doing some extra thingy for the kids section
42
- begin
43
- val = config.last['level'].to_i
44
- currently_enabled = (all("div[itc-checkbox='tempPageContent.ratingDialog.madeForKidsChecked'] > * > input").last.value != "")
45
- Helper.log.info "Setting kids mode to #{val}".green
46
- if val > 0
47
- if not currently_enabled
48
- all("div[itc-checkbox='tempPageContent.ratingDialog.madeForKidsChecked'] > * > a").last.click
49
- end
50
-
51
- # Kids is enabled, check mode
52
- first("select[ng-model='tempRatings.ageBand'] > option[value='#{val - 1}']").select_option # -1 since 0 is no kids mode
53
- else
54
- if currently_enabled
55
- # disable kids mode
56
- all("div[itc-checkbox='tempPageContent.ratingDialog.madeForKidsChecked'] > * > a").last.click
57
- end
58
- end
59
- rescue
60
- Helper.log.warn "Couldn't set kids mode because of other options."
61
- end
62
-
63
- # Check if there is a warning or error message because of this rating
64
- error_message = first("p[ng-show='tempPageContent.ratingDialog.showErrorMessage']")
65
- Helper.log.error error_message.text if error_message
66
-
67
- Helper.log.info "Finished setting updated app rating"
68
-
69
- (click_on "Done" rescue nil)
70
-
71
- (click_on "Save" rescue nil) # if nothing has changed, there is no back button and we don't care
72
- rescue => ex
73
- error_occured(ex)
74
- end
75
-
76
- private
77
- def name_for_level(level, is_boolean)
78
- if is_boolean
79
- return "NO" if level == 0
80
- return "YES" if level == 1
81
- else
82
- return "NONE" if level == 0
83
- return "INFREQUENT_MILD" if level == 1
84
- return "FREQUENT_INTENSE" if level == 2
85
- end
86
-
87
- raise "Unknown level '#{level}' - must be 0, 1 or 2".red
88
- end
89
- end
90
- end