require 'net/scp' require 'colorize' module Nixenvironment class Deployer def self.deploy(deploy_host, deploy_dir, deploy_user, deploy_password, deploy_itunesconnect_user, deploy_team_name, deliver_deploy, deployment_names, skip_working_copy_check) build_env_vars = BuildEnvVarsLoader.load raise 'Error! Working copy is not clean!' unless BuildEnvVarsLoader.working_copy_is_clean? unless skip_working_copy_check ipa_product = build_env_vars[IPA_PRODUCT_KEY] ipa_product_resigned_device = build_env_vars[IPA_PRODUCT_RESIGNED_DEVICE_KEY] ipa_product_resigned_adhoc = build_env_vars[IPA_PRODUCT_RESIGNED_ADHOC_KEY] ipa_product_resigned_appstore = build_env_vars[IPA_PRODUCT_RESIGNED_APPSTORE_KEY] ipa_bundle_id = build_env_vars[IPA_BUNDLE_ID_KEY] ipa_bundle_id_resigned_device = build_env_vars[IPA_BUNDLE_ID_RESIGNED_DEVICE_KEY] ipa_bundle_id_resigned_adhoc = build_env_vars[IPA_BUNDLE_ID_RESIGNED_ADHOC_KEY] ipa_bundle_id_resigned_appstore = build_env_vars[IPA_BUNDLE_ID_RESIGNED_APPSTORE_KEY] 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_KEY] name_for_deployment_resigned_adhoc = build_env_vars[NAME_FOR_DEPLOYMENT_RESIGNED_ADHOC_KEY] name_for_deployment_resigned_appstore = build_env_vars[NAME_FOR_DEPLOYMENT_RESIGNED_APPSTORE_KEY] if deployment_names.present? names = deployment_names.scan(/(?:\w|'[^']*')+/).map! {|name| name.tr("'", '')} ipas_count = 0 ipas_count += 1 if name_for_deployment.present? ipas_count += 1 if name_for_deployment_resigned_device.present? ipas_count += 1 if name_for_deployment_resigned_adhoc.present? ipas_count += 1 if name_for_deployment_resigned_appstore.present? raise 'Deployment names count does not match ipa files count!' if ipas_count != names.count ipa_index = 0 if name_for_deployment.present? deployment_name = names[ipa_index] name_for_deployment = deployment_name if deployment_name != '_' ipa_index += 1 end if name_for_deployment_resigned_device.present? deployment_name = names[ipa_index] name_for_deployment_resigned_device = deployment_name if deployment_name != '_' ipa_index += 1 end if name_for_deployment_resigned_adhoc.present? deployment_name = names[ipa_index] name_for_deployment_resigned_adhoc = deployment_name if deployment_name != '_' ipa_index += 1 end if name_for_deployment_resigned_appstore.present? deployment_name = names[ipa_index] name_for_deployment_resigned_appstore = deployment_name if deployment_name != '_' end end 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, nil, nil, nil, 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, nil, nil, nil, 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, nil, nil, nil, 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, deploy_team_name, 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, deploy_team_name, deliver_deploy, ipa_bundle_id, ipa_product, current_app_version, current_build_version, name_for_deployment, executable_name, app_dsym, sdk) is_iphone_build = sdk.include?('iphone') 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_iphone_build ? IPA_EXT : ZIP_EXT)) FileUtils.rm_rf(local_path_to_build) FileUtils.mkdir_p(configuration_full_path) FileUtils.cp_r(ipa_product, destination_ipa_product) if is_iphone_build if deploy_itunesconnect_user.present? puts print 'Starting upload to TestFlight ...'.blue puts skip_submission = deliver_deploy ? '' : '--skip_submission' team_name = deploy_team_name.present? ? "-r '#{deploy_team_name}'" : '' system("pilot upload -i '#{ipa_product}' -u '#{deploy_itunesconnect_user}' #{team_name} #{skip_submission}") end # zip dsym dsym_path = File.dirname(app_dsym) zipped_dsym_name = executable_name + APP_EXT + DSYM_EXT zipped_dsym_path = File.join(configuration_full_path, zipped_dsym_name + ZIP_EXT) if File.exist?(app_dsym) Dir.chdir(dsym_path) do puts puts "--> Zip '#{app_dsym}' into '#{zipped_dsym_path}' ..." 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 raise 'Deploy error!' unless system("#{DEPLOY_SCRIPT_PATH} '#{deploy_host}' '#{deploy_dir}' '#{deploy_user}' '#{deploy_password}' '#{local_path_to_app}'") # TODO: Will use code below after fix https://github.com/net-ssh/net-scp/issues/24 # # max_percentage = 100 # progress_step = 5 # max_progress = max_percentage / progress_step # # prev_file_name = '' # prev_print_threshold = -1 # # 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" # # if name != prev_file_name # prev_file_name = name # puts # puts "#{File.basename(name)}:" # end # # percentage = sent.to_f / total.to_f * max_percentage # print_threshold = (percentage / max_progress).floor # # if print_threshold != prev_print_threshold # prev_print_threshold = print_threshold # print_percentage = print_threshold * max_progress # current_progress = (print_percentage / progress_step).floor # progress_bar = '|' + '#' * current_progress + '-' * (max_progress - current_progress) + '|' # print "#{print_percentage}% #{progress_bar}\r" # end # end puts end private_class_method :deploy_internal, :scp end end