diff --git a/BuildaKit/PersistenceMigrator.swift b/BuildaKit/PersistenceMigrator.swift index a14ff0e..25203eb 100644 --- a/BuildaKit/PersistenceMigrator.swift +++ b/BuildaKit/PersistenceMigrator.swift @@ -9,7 +9,7 @@ import Foundation import BuildaUtils import XcodeServerSDK -@testable import BuildaGitServer +import BuildaGitServer public protocol MigratorType { init(persistence: Persistence) diff --git a/Podfile b/Podfile index 5847786..434dda5 100644 --- a/Podfile +++ b/Podfile @@ -35,6 +35,7 @@ def buildasaur_app_pods rac pod 'Ji', '~> 1.2.0' pod 'CryptoSwift' + pod 'Sparkle' end def test_pods diff --git a/Podfile.lock b/Podfile.lock index ea06a8b..a6416af 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -30,6 +30,7 @@ PODS: - ReactiveCocoa/Core - Result (~> 1.0) - Result (1.0.1) + - Sparkle (1.13.1) - SwiftSafe (0.1) - XcodeServerSDK (0.5.6): - BuildaUtils (~> 0.2.3) @@ -46,6 +47,7 @@ DEPENDENCIES: - Nimble (~> 3.0.0) - OAuthSwift - ReactiveCocoa (= 4.0.0-RC.1) + - Sparkle - XcodeServerSDK (~> 0.5.6) EXTERNAL SOURCES: @@ -67,6 +69,7 @@ SPEC CHECKSUMS: OAuthSwift: f2e0de083739da5697be095c9af2671242a4ed8b ReactiveCocoa: 2b0f654beb7642b82cfd3fdb845205ae9889422c Result: caef80340451e1f07492fa1e89117f83613bce24 + Sparkle: 2fbd47b869621d1e679c7554e3e19dda02104818 SwiftSafe: 77ffd12b02678790bec1ef56a2d14ec5036f1fd6 XcodeServerSDK: 6300badc4a799da9ad6e970b366eda18d4a47bda diff --git a/fastlane/Fastfile b/fastlane/Fastfile index c34e485..099348c 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -7,7 +7,7 @@ update_fastlane # This is the minimum version number required. # Update this, if you use features of a newer version -fastlane_version "1.26.0" +fastlane_version "1.57.0" before_all do |lane| end @@ -76,27 +76,90 @@ end lane :release do run_tests build - release_no_build + release_app end lane :release_app do - raise "No built app found in ./build/Buildasaur.app" unless File.exist?("../build/Buildasaur.app") - version = get_info_plist_value( - key: "CFBundleShortVersionString", - path: "Buildasaur/Info.plist" - ) - github( - assets: ["./build/Buildasaur.app"], - version: version + + app_path = "../build/Buildasaur.app" + raise "No built app found in #{app_path}" unless File.exist?(app_path) + + app_zip_path = zip_app_bundle(app_path: app_path) + raise "No zipped app found in #{app_zip_path}" unless File.exist?(app_zip_path) + + ENV['FL_GET_INFO_PLIST_PATH'] = File.absolute_path("#{app_path}/Contents/Info.plist") + human_version = get_info_plist_value(key: "CFBundleShortVersionString") + machine_version = get_info_plist_value(key: "CFBundleVersion") + + release_info = github( + assets: [app_zip_path], + version: human_version + ) + # release_info = { + # title: "v1.0-beta1 - Hello!", + # description: "# Hey\n[Link](http://here)", + # version_tag: "v1.0-beta1" + # } + sparkle( + app_zip_path: app_zip_path, + release_title: release_info[:title], + release_description: release_info[:description], + release_version_tag: release_info[:version_tag], + machine_version: machine_version, + human_version: human_version ) + + UI.message "Now review and commit changes to the repository!" +end + +private_lane :zip_app_bundle do |params| + app_path = params[:app_path] + app_zip_path = "#{app_path}.zip" + abs_app_path = File.absolute_path(app_path) + app_folder = File.dirname(abs_app_path) + sh "cd '#{app_folder}'; zip -r --symlinks '#{File.basename(app_zip_path)}' '#{File.basename(app_path)}'" + File.absolute_path(app_zip_path) end lane :build do gym( scheme: 'Buildasaur', output_name: 'Buildasaur', - output_directory: './build' + output_directory: './build', + export_method: 'developer-id' + ) +end + +private_lane :sparkle do |params| + + # Create release notes file + release_notes_html = render_github_markdown( + context_repository: "czechboy0/Buildasaur", + api_token: ENV["GITHUB_TOKEN"], + markdown_contents: params[:release_description] + ) + release_notes_html_path = File.absolute_path("../Meta/Sparkle_Release_Notes/#{params[:release_version_tag]}.html") + File.open(release_notes_html_path, "w") { |io| io.write(release_notes_html) } + # Now we need to commit this new file at the end of the workflow! + sh "cd .. && git add '#{release_notes_html_path}'" + + release_notes_html_url = "https://raw.githubusercontent.com/czechboy0/Buildasaur/master/Meta/Sparkle_Release_Notes/#{params[:release_version_tag]}.html" + app_download_url = "https://github.com/czechboy0/Buildasaur/releases/download/#{params[:release_version_tag]}/Buildasaur.app.zip" + + UI.message "Successfully created release notes file at path #{release_notes_html_path}" + + sparkle_add_update( + feed_file: "sparkle.xml", + app_download_url: app_download_url, + app_size: "#{File.size(params[:app_zip_path])}", + machine_version: params[:machine_version], + human_version: params[:human_version], + title: params[:release_title], + release_notes_link: release_notes_html_url, + deployment_target: "10.11" ) + + UI.message "Successfully added a release item to the Sparkle XML file (review before committing)" end private_lane :github do |params| @@ -117,6 +180,7 @@ private_lane :github do |params| title = prompt(text: 'Release Title: ') description = prompt(text: "Release changelog: ", multi_line_end_keyword: "END") + release_name = [version_tag, title].join(" - ") # create a new release on GitHub repo_url = "czechboy0/Buildasaur" @@ -124,7 +188,7 @@ private_lane :github do |params| release = set_github_release( repository_name: repo_url, upload_assets: assets, - name: [version_tag, title].join(" - "), + name: release_name, tag_name: version_tag, description: description, is_draft: false, @@ -146,5 +210,10 @@ private_lane :github do |params| # } # ) + { + title: release_name, + description: description, + version_tag: version_tag + } end diff --git a/fastlane/README.md b/fastlane/README.md index 78b560a..7106a74 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -38,6 +38,6 @@ fastlane build ---- -This README.md is auto-generated and will be re-generated every time to run [fastlane](https://fastlane.tools) -More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools). -The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane) \ No newline at end of file +This README.md is auto-generated and will be re-generated every time to run [fastlane](https://fastlane.tools). +More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools). +The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane). \ No newline at end of file diff --git a/fastlane/actions/render_github_markdown.rb b/fastlane/actions/render_github_markdown.rb new file mode 100644 index 0000000..454a563 --- /dev/null +++ b/fastlane/actions/render_github_markdown.rb @@ -0,0 +1,89 @@ +module Fastlane + module Actions + module SharedValues + end + + class RenderGithubMarkdownAction < Action + def self.run(params) + + contents = params[:markdown_contents] || File.read(params[:markdown_file]) + raise "You must pass either the markdown contents or a file path" unless contents + + require 'json' + body = { + text: contents, + mode: "gfm", + context: params[:context_repository] + }.to_json + + require 'base64' + headers = { + 'User-Agent' => 'fastlane-render_github_markdown', + 'Authorization' => "Basic #{Base64.strict_encode64(params[:api_token])}" + } + + response = Excon.post("https://api.github.com/markdown", headers: headers, body: body) + + raise response[:headers].to_s unless response[:status] == 200 + html_markdown = response.body + + ENV['RENDER_GITHUB_MARKDOWN_HTML'] = html_markdown + return html_markdown + end + + ##################################################### + # @!group Documentation + ##################################################### + + def self.description + "Uses the GitHub API to render your GitHub-flavored Markdown as HTML" + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new(key: :markdown_file, + env_name: "FL_RENDER_GITHUB_MARKDOWN_FILE", + description: "The path to your markdown file", + optional: true, + verify_block: proc do |value| + raise "File doesn't exist '#{value}'".red unless File.exists?(value) + end), + FastlaneCore::ConfigItem.new(key: :markdown_contents, + env_name: "FL_RENDER_GITHUB_MARKDOWN_CONTENTS", + optional: true, + description: "The markdown contents"), + FastlaneCore::ConfigItem.new(key: :context_repository, + env_name: "FL_RENDER_GITHUB_MARKDOWN_CONTEXT_REPOSITORY", + description: "The path to your repo, e.g. 'fastlane/fastlane'", + verify_block: proc do |value| + raise "Please only pass the path, e.g. 'fastlane/fastlane'".red if value.include? "github.com" + raise "Please only pass the path, e.g. 'fastlane/fastlane'".red if value.split('/').count != 2 + end), + FastlaneCore::ConfigItem.new(key: :api_token, + env_name: "FL_RENDER_GITHUB_MARKDOWN_API_TOKEN", + description: "Personal API Token for GitHub - generate one at https://github.com/settings/tokens", + is_string: true, + optional: false), + ] + end + + def self.output + [ + ['RENDER_GITHUB_MARKDOWN_HTML', 'Rendered HTML'] + ] + end + + def self.return_value + "Returns the GFM Markdown contents rendered as HTML" + end + + def self.authors + ["czechboy0"] + end + + def self.is_supported?(platform) + true + end + end + end +end diff --git a/fastlane/actions/sparkle_add_update.rb b/fastlane/actions/sparkle_add_update.rb new file mode 100644 index 0000000..0d95032 --- /dev/null +++ b/fastlane/actions/sparkle_add_update.rb @@ -0,0 +1,132 @@ +module Fastlane + module Actions + module SharedValues + end + + class SparkleAddUpdateAction < Action + + # inspired by https://github.com/CocoaPods/CocoaPods-app/blob/578555e8e86a5f7fe3e56deeb5406ffb24e1541e/Rakefile#L1069 + + def self.run(params) + + # UI.message "#{params[:feed_file]}" + # UI.message "#{params[:app_download_url]}" + # UI.message "#{params[:app_size]}" + # UI.message "#{params[:machine_version]}" + # UI.message "#{params[:human_version]}" + # UI.message "#{params[:title]}" + # UI.message "#{params[:release_notes_link]}" + # UI.message "#{params[:deployment_target]}" + + xml_file = params[:feed_file] + + # Load existing sparkle xml feed file + require 'rexml/document' + doc = REXML::Document.new(File.read(xml_file)) + channel = doc.elements['/rss/channel'] + + # Verify that the new version is strictly greater than the last one in the list + last_version = channel.elements.select { |e| e.name == 'item' }.last.get_elements('enclosure').first.attributes['version'] + raise "You must update the machine version to be above #{last_version}!" unless params[:machine_version] > last_version + + # Add a new item to the Appcast feed + item = channel.add_element('item') + item.add_element("title").add_text(params[:title]) + item.add_element("sparkle:minimumSystemVersion").add_text(params[:deployment_target]) if params[:deployment_target] + item.add_element("sparkle:releaseNotesLink").add_text(params[:release_notes_link]) + item.add_element("pubDate").add_text(DateTime.now.strftime("%a, %d %h %Y %H:%M:%S %z")) + + enclosure = item.add_element("enclosure") + enclosure.attributes["type"] = "application/octet-stream" + enclosure.attributes["sparkle:version"] = params[:machine_version] + enclosure.attributes["sparkle:shortVersionString"] = params[:human_version] + enclosure.attributes["length"] = params[:app_size] + enclosure.attributes["url"] = params[:app_download_url] + + # Write it back out + formatter = REXML::Formatters::Pretty.new(2) + formatter.compact = true + new_xml = "" + formatter.write(doc, new_xml) + File.open(xml_file, 'w') { |file| file.write new_xml } + + end + + ##################################################### + # @!group Documentation + #########################################s############ + + def self.description + "Adds a new version entry into your Sparkle XML feed file" + end + + def self.details + "" + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new(key: :feed_file, + env_name: "FL_SPARKLE_ADD_UPDATE_FEED_FILE", + description: "Path to the xml feed file", + default_value: "sparkle.xml", + verify_block: proc do |value| + raise "Couldn't find file at path '#{value}'".red unless File.exist?(value) + end), + FastlaneCore::ConfigItem.new(key: :app_download_url, + env_name: "FL_SPARKLE_ADD_UPDATE_APP_DOWNLOAD_URL", + description: "Download URL of the app update", + verify_block: proc do |value| + raise "Invalid URL '#{value}'".red unless (value and !value.empty?) + end), + FastlaneCore::ConfigItem.new(key: :app_size, + env_name: "FL_SPARKLE_ADD_UPDATE_APP_SIZE", + description: "App's size in bytes"), + FastlaneCore::ConfigItem.new(key: :title, + env_name: "FL_SPARKLE_ADD_UPDATE_TITLE", + description: "Update title", + verify_block: proc do |value| + raise "Invalid title '#{value}'".red unless (value and !value.empty?) + end), + FastlaneCore::ConfigItem.new(key: :release_notes_link, + env_name: "FL_SPARKLE_ADD_UPDATE_RELEASE_NOTES_LINK", + description: "Update release notes link", + verify_block: proc do |value| + raise "Invalid release notes link '#{value}'".red unless (value and !value.empty?) + end), + FastlaneCore::ConfigItem.new(key: :machine_version, + env_name: "FL_SPARKLE_ADD_UPDATE_MACHINE_VERSION", + description: "Machine version, must be strictly greater than the previous one", + verify_block: proc do |value| + raise "Invalid machine version '#{value}'".red unless (value and !value.empty?) + end), + FastlaneCore::ConfigItem.new(key: :human_version, + env_name: "FL_SPARKLE_ADD_UPDATE_HUMAN_VERSION", + description: "Human version string, defaults to machine version", + verify_block: proc do |value| + raise "Invalid human version '#{value}'".red unless (value and !value.empty?) + end), + FastlaneCore::ConfigItem.new(key: :deployment_target, + env_name: "FL_SPARKLE_ADD_UPDATE_DEPLOYMENT_TARGET", + description: "Update's deployment target", + optional: true) + ] + end + + def self.output + [] + end + + def self.return_value + end + + def self.authors + ["czechboy0"] + end + + def self.is_supported?(platform) + platform == :mac + end + end + end +end diff --git a/sparkle.xml b/sparkle.xml new file mode 100644 index 0000000..a94fc39 --- /dev/null +++ b/sparkle.xml @@ -0,0 +1,16 @@ + + + + Buildasaur Changelog + https://raw.githubusercontent.com/czechboy0/Buildasaur/master/sparkle.xml + Most recent changes with links to updates. + en + + Version 0.8.0 + https://github.com/czechboy0/Buildasaur/releases/tag/v0.8.0 + Thu, 28 Jan 2016 22:40:00 +0000 + + 10.11 + + + \ No newline at end of file