require 'net/scp' require 'colorize' module Nixenvironment class Deployer def self.deploy(deploy_host, deploy_dir, deploy_user, deploy_password, deploy_itunesconnect_user, deliver_deploy) build_env_vars = BuildEnvVarsLoader.load raise 'Error! Working copy is not clean!' unless BuildEnvVarsLoader.working_copy_is_clean? ipa_product = build_env_vars[IPA_PRODUCT_KEY] ipa_product_resigned_device = build_env_vars['IPA_PRODUCT_RESIGNED_DEVICE'] ipa_product_resigned_adhoc = build_env_vars['IPA_PRODUCT_RESIGNED_ADHOC'] ipa_product_resigned_appstore = build_env_vars['IPA_PRODUCT_RESIGNED_APPSTORE'] ipa_bundle_id = build_env_vars[IPA_BUNDLE_ID_KEY] ipa_bundle_id_resigned_device = build_env_vars['IPA_BUNDLE_ID_RESIGNED_DEVICE'] ipa_bundle_id_resigned_adhoc = build_env_vars['IPA_BUNDLE_ID_RESIGNED_ADHOC'] ipa_bundle_id_resigned_appstore = build_env_vars['IPA_BUNDLE_ID_RESIGNED_APPSTORE'] current_app_version = build_env_vars[CURRENT_APP_VERSION_KEY] current_build_version = build_env_vars[CURRENT_BUILD_VERSION_KEY] name_for_deployment = build_env_vars[NAME_FOR_DEPLOYMENT_KEY] name_for_deployment_resigned_device = build_env_vars['NAME_FOR_DEPLOYMENT_RESIGNED_DEVICE'] name_for_deployment_resigned_adhoc = build_env_vars['NAME_FOR_DEPLOYMENT_RESIGNED_ADHOC'] name_for_deployment_resigned_appstore = build_env_vars['NAME_FOR_DEPLOYMENT_RESIGNED_APPSTORE'] executable_name = build_env_vars[EXECUTABLE_NAME_KEY] app_dsym = build_env_vars[APP_DSYM_KEY] sdk = build_env_vars[SDK_NAME_KEY] ipa_count = 0 if ipa_product.present? && File.exist?(ipa_product) ipa_count += 1 deploy_internal(deploy_host, deploy_dir, deploy_user, deploy_password, deploy_itunesconnect_user, deliver_deploy, ipa_bundle_id, ipa_product, current_app_version, current_build_version, name_for_deployment, executable_name, app_dsym, sdk) end if ipa_product_resigned_device.present? && File.exist?(ipa_product_resigned_device) ipa_count += 1 ipa_bundle_id_resigned_device = ipa_bundle_id if ipa_bundle_id_resigned_device.blank? deploy_internal(deploy_host, deploy_dir, deploy_user, deploy_password, deploy_itunesconnect_user, deliver_deploy, ipa_bundle_id_resigned_device, ipa_product_resigned_device, current_app_version, current_build_version, name_for_deployment_resigned_device, executable_name, app_dsym, sdk) end if ipa_product_resigned_adhoc.present? && File.exist?(ipa_product_resigned_adhoc) ipa_count += 1 ipa_bundle_id_resigned_adhoc = ipa_bundle_id if ipa_bundle_id_resigned_adhoc.blank? deploy_internal(deploy_host, deploy_dir, deploy_user, deploy_password, deploy_itunesconnect_user, deliver_deploy, ipa_bundle_id_resigned_adhoc, ipa_product_resigned_adhoc, current_app_version, current_build_version, name_for_deployment_resigned_adhoc, executable_name, app_dsym, sdk) end if ipa_product_resigned_appstore.present? && File.exist?(ipa_product_resigned_appstore) ipa_count += 1 ipa_bundle_id_resigned_appstore = ipa_bundle_id if ipa_bundle_id_resigned_appstore.blank? deploy_internal(deploy_host, deploy_dir, deploy_user, deploy_password, deploy_itunesconnect_user, deliver_deploy, ipa_bundle_id_resigned_appstore, ipa_product_resigned_appstore, current_app_version, current_build_version, name_for_deployment_resigned_appstore, executable_name, app_dsym, sdk) end raise 'Nothing to upload!' if ipa_count == 0 end def self.deploy_internal(deploy_host, deploy_dir, deploy_user, deploy_password, deploy_itunesconnect_user, deliver_deploy, ipa_bundle_id, ipa_product, current_app_version, current_build_version, name_for_deployment, executable_name, app_dsym, sdk) is_macos_build = sdk.include?('macos') local_path_to_app = File.join(Dir.tmpdir, ipa_bundle_id) local_path_to_build = File.join(local_path_to_app, "v.#{current_app_version}_#{current_build_version}") configuration_full_path = File.join(local_path_to_build, name_for_deployment) destination_ipa_product = File.join(configuration_full_path, executable_name + (is_macos_build ? ZIP_EXT : IPA_EXT)) FileUtils.rm_rf(local_path_to_build) FileUtils.mkdir_p(configuration_full_path) FileUtils.cp_r(ipa_product, destination_ipa_product) unless is_macos_build if deploy_itunesconnect_user.present? puts print 'Starting pilot ...'.blue puts skip_submission = deliver_deploy ? '' : '--skip_submission' system("pilot upload -i '#{ipa_product}' -u '#{deploy_itunesconnect_user}' #{skip_submission}") end # zip dsym dsym_path = executable_name + APP_EXT + DSYM_EXT zipped_dsym_path = File.join(configuration_full_path, dsym_path + ZIP_EXT) if File.exist?(app_dsym) Dir.chdir(File.dirname(app_dsym)) do system("/usr/bin/zip --symlinks --verbose --recurse-paths '#{zipped_dsym_path}' '#{File.basename(app_dsym)}'") end end end FileUtils.chmod_R(0775, local_path_to_app) scp(deploy_host, deploy_dir, deploy_user, deploy_password, local_path_to_app) FileUtils.rm_rf(local_path_to_app) end def self.scp(deploy_host, deploy_dir, deploy_user, deploy_password, local_path_to_app) puts puts "Uploading build from '#{local_path_to_app}' ...".blue puts max_percentage = 100 progress_step = 5 max_progress = max_percentage / progress_step Net::SCP.upload!(deploy_host, deploy_user, local_path_to_app, deploy_dir, :ssh => { :password => deploy_password }, :recursive => true, :preserve => true) do |_ch, _name, sent, total| percentage = (sent.to_f / total.to_f * max_percentage).round(1) current_progress = (percentage / progress_step).floor progress_bar = '|' + '#' * current_progress + '_' * (max_progress - current_progress) + '|' print "#{percentage}% #{progress_bar}\r" end puts end private_class_method :deploy_internal, :scp end end