module Fastlane module Actions module SharedValues DEPLOYGATE_URL = :DEPLOYGATE_URL DEPLOYGATE_REVISION = :DEPLOYGATE_REVISION # auto increment revision number DEPLOYGATE_APP_INFO = :DEPLOYGATE_APP_INFO # contains app revision, bundle identifier, etc. end class DeploygateAction < Action DEPLOYGATE_URL_BASE = 'https://deploygate.com' def self.is_supported?(platform) platform == :ios end def self.upload_build(api_token, user_name, ipa, options) require 'faraday' require 'faraday_middleware' connection = Faraday.new(url: DEPLOYGATE_URL_BASE, request: { timeout: 120 }) do |builder| builder.request :multipart builder.request :json builder.response :json, content_type: /\bjson$/ builder.use FaradayMiddleware::FollowRedirects builder.adapter :net_http end options.update({ token: api_token, file: Faraday::UploadIO.new(ipa, 'application/octet-stream'), message: options[:message] || '' }) connection.post("/api/users/#{user_name}/apps", options) rescue Faraday::Error::TimeoutError UI.crash! "Timed out while uploading build. Check https://deploygate.com/ to see if the upload was completed." end def self.run(options) # Available options: https://deploygate.com/docs/api UI.success('Starting with ipa upload to DeployGate... this could take some time ⏳') api_token = options[:api_token] user_name = options[:user] ipa = options[:ipa] upload_options = options.values.select do |key, _| [:message, :distribution_key, :release_note].include? key end return ipa if Helper.test? response = self.upload_build(api_token, user_name, ipa, upload_options) if parse_response(response) UI.message("DeployGate URL: #{Actions.lane_context[SharedValues::DEPLOYGATE_URL]}") UI.success("Build successfully uploaded to DeployGate as revision \##{Actions.lane_context[SharedValues::DEPLOYGATE_REVISION]}!") else UI.user_error!("Error when trying to upload ipa to DeployGate") end end def self.parse_response(response) if response.body && response.body.key?('error') if response.body['error'] UI.error("Error uploading to DeployGate: #{response.body['message']}") help_message(response) return else res = response.body['results'] url = DEPLOYGATE_URL_BASE + res['path'] Actions.lane_context[SharedValues::DEPLOYGATE_URL] = url Actions.lane_context[SharedValues::DEPLOYGATE_REVISION] = res['revision'] Actions.lane_context[SharedValues::DEPLOYGATE_APP_INFO] = res end else UI.error("Error uploading to DeployGate: #{response.body}") return end true end private_class_method :parse_response def self.help_message(response) message = case response.body['message'] when 'you are not authenticated' 'Invalid API Token specified.' when 'application create error: permit' 'Access denied: May be trying to upload to wrong user or updating app you join as a tester?' when 'application create error: limit' 'Plan limit: You have reached to the limit of current plan or your plan was expired.' end UI.error(message) if message end private_class_method :help_message def self.description "Upload a new build to [DeployGate](https://deploygate.com/)" end def self.details [ "You can retrieve your username and API token on [your settings page](https://deploygate.com/settings)", "More information about the available options can be found in the [DeployGate Push API document](https://deploygate.com/docs/api)." ].join("\n") end def self.available_options [ FastlaneCore::ConfigItem.new(key: :api_token, env_name: "DEPLOYGATE_API_TOKEN", description: "Deploygate API Token", sensitive: true, verify_block: proc do |value| UI.user_error!("No API Token for DeployGate given, pass using `api_token: 'token'`") unless value.to_s.length > 0 end), FastlaneCore::ConfigItem.new(key: :user, env_name: "DEPLOYGATE_USER", description: "Target username or organization name", verify_block: proc do |value| UI.user_error!("No User for app given, pass using `user: 'user'`") unless value.to_s.length > 0 end), FastlaneCore::ConfigItem.new(key: :ipa, env_name: "DEPLOYGATE_IPA_PATH", description: "Path to your IPA file. Optional if you use the _gym_ or _xcodebuild_ action", default_value: Actions.lane_context[SharedValues::IPA_OUTPUT_PATH], verify_block: proc do |value| UI.user_error!("Couldn't find ipa file at path '#{value}'") unless File.exist?(value) end), FastlaneCore::ConfigItem.new(key: :message, env_name: "DEPLOYGATE_MESSAGE", description: "Release Notes", default_value: "No changelog provided"), FastlaneCore::ConfigItem.new(key: :distribution_key, optional: true, env_name: "DEPLOYGATE_DISTRIBUTION_KEY", sensitive: true, description: "Target Distribution Key"), FastlaneCore::ConfigItem.new(key: :release_note, optional: true, env_name: "DEPLOYGATE_RELEASE_NOTE", description: "Release note for distribution page") ] end def self.output [ ['DEPLOYGATE_URL', 'URL of the newly uploaded build'], ['DEPLOYGATE_REVISION', 'auto incremented revision number'], ['DEPLOYGATE_APP_INFO', 'Contains app revision, bundle identifier, etc.'] ] end def self.example_code [ 'deploygate( api_token: "...", user: "target username or organization name", ipa: "./ipa_file.ipa", message: "Build #{lane_context[SharedValues::BUILD_NUMBER]}", distribution_key: "(Optional) Target Distribution Key" )' ] end def self.category :beta end def self.author "tnj" end end end end