module Fastlane module Actions class AppaloosaAction < Action APPALOOSA_SERVER = 'https://www.appaloosa-store.com/api/v2'.freeze def self.run(params) api_key = params[:api_token] store_id = params[:store_id] binary = params[:binary] remove_extra_screenshots_file(params[:screenshots]) binary_url = get_binary_link(binary, api_key, store_id, params[:group_ids]) return if binary_url.nil? screenshots_url = get_screenshots_links(api_key, store_id, params[:screenshots], params[:locale], params[:device]) upload_on_appaloosa(api_key, store_id, binary_url, screenshots_url, params[:group_ids]) end def self.get_binary_link(binary, api_key, store_id, group_ids) key_s3 = upload_on_s3(binary, api_key, store_id, group_ids) return if key_s3.nil? get_s3_url(api_key, store_id, key_s3) end def self.upload_on_s3(file, api_key, store_id, group_ids = '') file_name = file.split('/').last uri = URI("#{APPALOOSA_SERVER}/upload_services/presign_form") params = { file: file_name, store_id: store_id, group_ids: group_ids } uri.query = URI.encode_www_form(params) presign_form_response = Net::HTTP.get_response(uri) json_res = JSON.parse(presign_form_response.body) return if error_detected json_res['errors'] s3_sign = json_res['s3_sign'] path = json_res['path'] uri = URI.parse(Base64.decode64(s3_sign)) File.open(file, 'rb') do |f| Net::HTTP.start(uri.host) do |http| http.send_request('PUT', uri.request_uri, f.read, 'content-type' => '') end end path end def self.get_s3_url(api_key, store_id, path) uri = URI("#{APPALOOSA_SERVER}/#{store_id}/upload_services/url_for_download") params = { store_id: store_id, api_key: api_key, key: path } uri.query = URI.encode_www_form(params) url_for_download_response = Net::HTTP.get_response(uri) if url_for_download_response.kind_of?(Net::HTTPNotFound) UI.user_error!("ERROR: A problem occurred with your API token and your store id. Please try again.") end json_res = JSON.parse(url_for_download_response.body) return if error_detected(json_res['errors']) json_res['binary_url'] end def self.remove_extra_screenshots_file(screenshots_env) extra_file = "#{screenshots_env}/screenshots.html" File.unlink(extra_file) if File.exist?(extra_file) end def self.upload_screenshots(screenshots, api_key, store_id) return if screenshots.nil? list = [] list << screenshots.map do |screen| upload_on_s3(screen, api_key, store_id) end end def self.get_uploaded_links(uploaded_screenshots, api_key, store_id) return if uploaded_screenshots.nil? urls = [] urls << uploaded_screenshots.flatten.map do |url| get_s3_url(api_key, store_id, url) end end def self.get_screenshots_links(api_key, store_id, screenshots_path, locale, device) screenshots = get_screenshots(screenshots_path, locale, device) return if screenshots.nil? uploaded = upload_screenshots(screenshots, api_key, store_id) links = get_uploaded_links(uploaded, api_key, store_id) links.kind_of?(Array) ? links.flatten : nil end def self.get_screenshots(screenshots_path, locale, device) get_env_value('screenshots').nil? ? locale = '' : locale.concat('/') device.nil? ? device = '' : device.concat('-') !screenshots_path.strip.empty? ? screenshots_list(screenshots_path, locale, device) : nil end def self.screenshots_list(path, locale, device) return warning_detected("screenshots folder not found") unless Dir.exist?("#{path}/#{locale}") list = Dir.entries("#{path}/#{locale}") - ['.', '..'] list.map do |screen| next if screen.match(device).nil? "#{path}/#{locale}#{screen}" unless Dir.exist?("#{path}/#{locale}#{screen}") end.compact end def self.upload_on_appaloosa(api_key, store_id, binary_path, screenshots, group_ids) screenshots = all_screenshots_links(screenshots) uri = URI("#{APPALOOSA_SERVER}/#{store_id}/mobile_application_updates/upload") http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/json' }) req.body = { store_id: store_id, api_key: api_key, mobile_application_update: { binary_path: binary_path, screenshot1: screenshots[0], screenshot2: screenshots[1], screenshot3: screenshots[2], screenshot4: screenshots[3], screenshot5: screenshots[4], group_ids: group_ids, provider: 'fastlane' } }.to_json uoa_response = http.request(req) json_res = JSON.parse(uoa_response.body) if json_res['errors'] UI.error "App: #{json_res['errors']}" else UI.success "Binary processing: Check your app': #{json_res['link']}" end end def self.all_screenshots_links(screenshots) if screenshots.nil? screens = %w(screenshot1 screenshot2 screenshot3 screenshot4 screenshot5) screenshots = screens.map do |_k, _v| '' end else missings = 5 - screenshots.count (1..missings).map do |_i| screenshots << '' end end screenshots end def self.get_env_value(option) available_options.map do |opt| opt if opt.key == option.to_sym end.compact[0].default_value end def self.error_detected(errors) if errors UI.user_error!("ERROR: #{errors}") else false end end def self.warning_detected(warning) UI.important("WARNING: #{warning}") nil end ##################################################### # @!group Documentation ##################################################### def self.description 'Upload your app to Appaloosa Store' end def self.details [ "Appaloosa is a private mobile application store. This action ", "offers a quick deployment on the platform. You can create an ", "account, push to your existing account, or manage your user ", "groups. We accept iOS and Android applications." ].join("\n") end def self.available_options [ FastlaneCore::ConfigItem.new(key: :binary, env_name: 'FL_APPALOOSA_BINARY', description: 'Binary path. Optional for ipa if you use the `ipa` or `xcodebuild` action', default_value: Actions.lane_context[SharedValues::IPA_OUTPUT_PATH], verify_block: proc do |value| raise "Couldn't find ipa || apk file at path '#{value}'".red unless File.exist?(value) end), FastlaneCore::ConfigItem.new(key: :api_token, env_name: 'FL_APPALOOSA_API_TOKEN', description: "Your API token"), FastlaneCore::ConfigItem.new(key: :store_id, env_name: 'FL_APPALOOSA_STORE_ID', description: "Your Store id"), FastlaneCore::ConfigItem.new(key: :group_ids, env_name: 'FL_APPALOOSA_GROUPS', description: 'Your app is limited to special users? Give us the group ids', default_value: '', optional: true), FastlaneCore::ConfigItem.new(key: :screenshots, env_name: 'FL_APPALOOSA_SCREENSHOTS', description: 'Add some screenshots application to your store or hit [enter]', default_value: Actions.lane_context[SharedValues::SNAPSHOT_SCREENSHOTS_PATH]), FastlaneCore::ConfigItem.new(key: :locale, env_name: 'FL_APPALOOSA_LOCALE', description: 'Select the folder locale for yours screenshots', default_value: 'en-US', optional: true), FastlaneCore::ConfigItem.new(key: :device, env_name: 'FL_APPALOOSA_DEVICE', description: 'Select the device format for yours screenshots', optional: true) ] end def self.authors ['Appaloosa'] end def self.is_supported?(platform) [:ios, :mac, :android].include? platform end end end end