require 'rake/tasklib' require 'open3' module XCJobs module Distribute def upload(url, form_data = {}, header = {}) @before_action.call if @before_action curl_options = ['curl', '-sSf', "#{url}"] form_fields = form_data.flat_map { |k, v| ['-F', "#{k}=#{v}"] } header_fields = header.flat_map { |k, v| ['-H', "#{k}:#{v}"] } puts (curl_options + form_fields + header_fields).join(' ') Open3.popen2e(*(curl_options + form_fields + header_fields)) do |stdin, stdout_err, wait_thr| output = '' while line = stdout_err.gets puts line output << line end status = wait_thr.value if status.success? @after_action.call(output, status) if @after_action else fail "upload failed (exited with status: #{status.exitstatus})" end end end def before_action(&block) @before_action = block end def after_action(&block) @after_action = block end class TestFlight < Rake::TaskLib include Rake::DSL if defined?(Rake::DSL) include Distribute attr_accessor :file attr_accessor :api_token attr_accessor :team_token attr_accessor :notify attr_accessor :replace attr_accessor :distribution_lists attr_accessor :notes def initialize() yield self if block_given? define end private def define namespace :distribute do desc 'upload IPA to TestFlight' task :testflight do upload('http://testflightapp.com/api/builds.json', form_data) end end end def form_data {}.tap do |fields| fields[:file] = "@#{file}" if file fields[:api_token] = api_token if api_token fields[:team_token] = team_token if team_token fields[:notify] = notify if notify fields[:replace] = replace if replace fields[:distribution_lists] = distribution_lists if distribution_lists fields[:notes] = notes if notes end end end class DeployGate < Rake::TaskLib include Rake::DSL if defined?(Rake::DSL) include Distribute attr_accessor :owner_name attr_accessor :token attr_accessor :file attr_accessor :message attr_accessor :distribution_key attr_accessor :release_note attr_accessor :disable_notify attr_accessor :visibility def initialize() yield self if block_given? define end private def define namespace :distribute do desc 'upload IPA to DeployGate' task :deploygate do upload("https://deploygate.com/api/users/#{owner_name}/apps", form_data) end end end def form_data {}.tap do |fields| fields[:token] = token if token fields[:file] = "@#{file}" if file fields[:message] = message if message fields[:distribution_key] = distribution_key if distribution_key fields[:release_note] = release_note if release_note fields[:disable_notify] = 'yes' if disable_notify fields[:visibility] = visibility if visibility end end end class Crashlytics < Rake::TaskLib include Rake::DSL if defined?(Rake::DSL) include Distribute attr_accessor :framework_path attr_accessor :file attr_accessor :api_key attr_accessor :build_secret attr_accessor :notes attr_accessor :notifications def initialize() @notifications = true @emails = [] @group_aliases = [] yield self if block_given? define end def add_email(email) @emails << email end def add_group_alias(group_alias) @group_aliases << group_alias end private def define namespace :distribute do desc 'upload IPA to Beta by Crashlytics' task :crashlytics do @before_action.call if @before_action sh *(["#{File.join(framework_path, 'submit')}"] + options) @after_action.call('', SystemExit.new) if @after_action end end end def options [].tap do |opts| opts << api_key opts << build_secret opts.concat(['-ipaPath', file]) if file opts.concat(['-notifications', 'NO']) unless notifications opts.concat(['-emails', @emails.join(',')]) unless @emails.empty? opts.concat(['-groupAliases', @group_aliases.join(',')]) unless @group_aliases.empty? if notes temp = Tempfile.new('release_notes.txt') temp.puts(notes) temp.flush opts.concat(['-notesPath', temp.path]) end end end end class HockeyApp < Rake::TaskLib include Rake::DSL if defined?(Rake::DSL) include Distribute attr_accessor :file attr_accessor :dsym attr_accessor :token attr_accessor :identifier attr_accessor :notes attr_accessor :notes_type attr_accessor :notify attr_accessor :status attr_accessor :tags attr_accessor :teams attr_accessor :users attr_accessor :mandatory attr_accessor :commit_sha attr_accessor :build_server_url attr_accessor :repository_url def initialize() yield self if block_given? define end private def define namespace :distribute do desc 'upload IPA & dSYMs to HockeyApp' task :hockeyapp do upload("https://rink.hockeyapp.net/api/2/apps/#{identifier}/app_versions/upload", form_data, header) end end end def form_data {}.tap do |fields| fields[:ipa] = "@#{file}" if file fields[:dsym] = "@#{dsym}" if dsym fields[:notes] = notes if notes fields[:notes_type] = notes_type if notes_type fields[:notify] = notify if notify fields[:status] = status if status fields[:tags] = tags.join(',') if tags fields[:teams] = teams.join(',') if teams fields[:users] = users.join(',') if users fields[:mandatory] = mandatory if mandatory fields[:commit_sha] = commit_sha if commit_sha fields[:build_server_url] = build_server_url if build_server_url fields[:repository_url] = repository_url if repository_url end end def header {}.tap do |fields| fields["X-HockeyAppToken"] = token if token end end end class Crittercism < Rake::TaskLib include Rake::DSL if defined?(Rake::DSL) include Distribute attr_accessor :app_id attr_accessor :dsym attr_accessor :key def initialize() yield self if block_given? define end private def define namespace :distribute do desc 'upload dSYMs to Crittercism' task :crittercism do upload("https://api.crittercism.com/api_beta/dsym/#{app_id}", form_data) end end end def form_data {}.tap do |fields| fields[:dsym] = "@#{dsym}" if dsym fields[:key] = key if key end end end class ITC < Rake::TaskLib include Rake::DSL if defined?(Rake::DSL) include Distribute attr_accessor :file attr_accessor :username attr_accessor :password attr_accessor :altool def initialize() yield self if block_given? define end def altool @altool || '/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Support/altool' end private def define namespace :distribute do desc 'upload ipa to iTunes Connect' task :itc do sh *["#{altool}", '--upload-app', '--file', "#{file}", '--username', "#{username}", '--password', "#{password}"] end end end end end end