bin/nixenvironment in nixenvironment-0.0.59 vs bin/nixenvironment in nixenvironment-0.0.60

- old
+ new

@@ -3,398 +3,317 @@ require 'rubygems' require 'nixenvironment' require 'commander/import' require 'yaml' require 'fileutils' -require 'shellwords' require 'tmpdir' require 'active_support/core_ext/object/blank' +require 'terminal-table' +require 'colorize' include Nixenvironment -program :name, 'nixenvironment' -program :version, VERSION +CONFIG_SETTINGS_FILE_PATH = File.join(File.dirname(__FILE__), CONFIG_SETTINGS_FILE_NAME) + +program :name, 'nixenvironment' +program :version, VERSION program :description, 'NIX projects build and deploy utility' -global_option ('--project_to_build VALUE') { |value| $project_to_build = value } -global_option ('--project_target_to_build VALUE') { |value| $project_target_to_build = value } -global_option ('--project_target_to_test VALUE') { |value| $project_target_to_test = value } +default_command :help -global_option ('--workspace_to_build VALUE') { |value| $workspace_to_build = value } -global_option ('--workspace_scheme_to_build VALUE') { |value| $workspace_scheme_to_build = value } -global_option ('--workspace_scheme_to_test VALUE') { |value| $workspace_scheme_to_test = value } - -global_option ('--sdk VALUE') { |value| $sdk = value } -global_option ('--sdk_for_tests VALUE') { |value| $sdk_for_tests = value } - -global_option ('--exclude_pattern_for_code_coverage VALUE') { |value| $exclude_pattern_for_code_coverage = value } -global_option ('--exclude_pattern_for_code_duplication VALUE') { |value| $exclude_pattern_for_code_duplication = value } - -global_option ('--deploy_host VALUE') { |value| $deploy_host = value } -global_option ('--deploy_path VALUE') { |value| $deploy_path = value } -global_option ('--deploy_username VALUE') { |value| $deploy_username = value } -global_option ('--deploy_password VALUE') { |value| $deploy_password = value } -global_option ('--deploy_itunesconnect_username VALUE') { |value| $deploy_itunesconnect_username = value } - -global_option ('--icons_path VALUE') { |value| $icons_path = value } - -global_option ('--xctest_destination_device VALUE') { |value| $xctest_destination_device = value } - -global_option ('--configuration_files_path VALUE') { |value| $configuration_files_path = value } -global_option ('--code_coverage_configuration VALUE') { |value| $code_coverage_configuration = value } -global_option ('--code_coverage_output_directory VALUE') { |value| $code_coverage_output_directory = value } - -global_option ('--env_var_prefix VALUE') { |value| $env_var_prefix = value } - -global_option ('--bundle_id VALUE') { |value| $bundle_id = value } -global_option ('--resigned_bundle_id VALUE') { |value| $resigned_bundle_id = value } -global_option ('--resigned_watchkit_app_bundle_id VALUE') { |value| $resigned_watchkit_app_bundle_id = value } -global_option ('--resigned_watchkit_extension_bundle_id VALUE') { |value| $resigned_watchkit_extension_bundle_id = value } -global_option ('--resigned_widget_bundle_id VALUE') { |value| $resigned_widget_bundle_id = value } -global_option ('--resigned_bundle_name VALUE') { |value| $resigned_bundle_name = value } -global_option ('--resigned_entitlements_path VALUE') { |value| $resigned_entitlements_path = value } +global_option ('--project_to_build VALUE') { |value| $project_to_build = value } +global_option ('--project_target_to_build VALUE') { |value| $project_target_to_build = value } +global_option ('--project_target_to_test VALUE') { |value| $project_target_to_test = value } +global_option ('--workspace_to_build VALUE') { |value| $workspace_to_build = value } +global_option ('--workspace_scheme_to_build VALUE') { |value| $workspace_scheme_to_build = value } +global_option ('--workspace_scheme_to_test VALUE') { |value| $workspace_scheme_to_test = value } +global_option ('--sdk VALUE') { |value| $sdk = value } +global_option ('--sdk_for_tests VALUE') { |value| $sdk_for_tests = value } +global_option ('--exclude_pattern_for_code_coverage VALUE') { |value| $exclude_pattern_for_code_coverage = value } +global_option ('--exclude_pattern_for_code_duplication VALUE') { |value| $exclude_pattern_for_code_duplication = value } +global_option ('--deploy_host VALUE') { |value| $deploy_host = value } +global_option ('--deploy_path VALUE') { |value| $deploy_path = value } +global_option ('--deploy_username VALUE') { |value| $deploy_username = value } +global_option ('--deploy_password VALUE') { |value| $deploy_password = value } +global_option ('--deploy_itunesconnect_username VALUE') { |value| $deploy_itunesconnect_username = value } +global_option ('--icons_path VALUE') { |value| $icons_path = value } +global_option ('--xctest_destination_device VALUE') { |value| $xctest_destination_device = value } +global_option ('--configuration_files_path VALUE') { |value| $configuration_files_path = value } +global_option ('--code_coverage_configuration VALUE') { |value| $code_coverage_configuration = value } +global_option ('--code_coverage_output_directory VALUE') { |value| $code_coverage_output_directory = value } +global_option ('--env_var_prefix VALUE') { |value| $env_var_prefix = value } +global_option ('--bundle_id VALUE') { |value| $bundle_id = value } +global_option ('--resigned_bundle_id VALUE') { |value| $resigned_bundle_id = value } +global_option ('--resigned_watchkit_app_bundle_id VALUE') { |value| $resigned_watchkit_app_bundle_id = value } +global_option ('--resigned_watchkit_extension_bundle_id VALUE') { |value| $resigned_watchkit_extension_bundle_id = value } +global_option ('--resigned_widget_bundle_id VALUE') { |value| $resigned_widget_bundle_id = value } +global_option ('--resigned_bundle_name VALUE') { |value| $resigned_bundle_name = value } +global_option ('--resigned_entitlements_path VALUE') { |value| $resigned_entitlements_path = value } global_option ('--resigned_watchkit_extension_entitlements_path VALUE') { |value| $resigned_watchkit_extension_entitlements_path = value } -global_option ('--resigned_widget_entitlements_path VALUE') { |value| $resigned_widget_entitlements_path = value } +global_option ('--resigned_widget_entitlements_path VALUE') { |value| $resigned_widget_entitlements_path = value } command :init do |c| c.syntax = 'nixenvironment init' c.description = 'Initialize template project of selected type in the destination repository and clone it to current folder' - c.action do |args, options| - init - end + c.action { init } end -command :update do |c| - c.syntax = 'nixenvironment update' - c.description = 'Install or update ninbas and other environment stuff' - c.option '--ninbas NAME', String, 'Select ninbas branch, tag or revision to clone' - c.action do |args, options| - update(options.ninbas) - end -end - command :build do |c| c.syntax = 'nixenvironment build [options]' c.description = 'Build project for selected configuration and make signed/resigned ipa' c.option '--config NAME', String, 'Select configuration' c.option '--ipa TYPES', String, 'Select sign (device, resigned_device, resigned_adhoc, resigned_appstore)' - c.option '--ci_build', 'Define NIXENV_CI_BUILD environment variable' c.option '--unity_path PATH', String, 'Select unity executable path (UNITY, UNITY_4 or custom path)' c.option '--development_build', 'Enable Developmen flag in Unity project' c.option '--keystore_path PATH', String, 'Specify the path to .keystore file' c.option '--keystore_password PASSWORD', String, 'Specify the password for accessing a .keystore file' c.option '--key_alias_name NAME', String, 'Specify the alias name which should be used from .keystore file to sign a release version of an APK' c.option '--key_alias_password PASSWORD', String, 'Specify the password for accessing an alias name' c.option '--unity_platform TARGET PLATFORM', String, 'Select target platform for unity build (ios or android)' c.option '--ndsym', 'Disable .dsym generation for ios project' c.option '--icon_tagger MODE', String, 'Set XcodeIconTagger mode (full, short, off)' - c.action do |args, options| + c.action do |_args, options| options.default :config => 'Debug', :ipa => 'device', :icon_tagger => 'full', :unity_path => 'UNITY' need_to_build_ios = true - is_unity_platform = options.unity_platform and options.unity_platform.length > 0 + is_unity_platform = options.unity_platform.present? if is_unity_platform - unity_path = ENV[options.unity_path].nil? ? options.unity_path : ENV[options.unity_path] - need_to_build_ios, root_working_dir, need_chdir_to_root_working_dir = unity_build(options.config, options.unity_platform, unity_path, options.development_build, options.keystore_path, options.keystore_password, options.key_alias_name, options.key_alias_password) + unity_path = ENV[options.unity_path] || options.unity_path + need_to_build_ios = unity_build(options.config, options.unity_platform, unity_path, options.development_build, + options.keystore_path, options.keystore_password, options.key_alias_name, options.key_alias_password) end if need_to_build_ios + Dir.chdir(UNITY_IOS_PROJECT_PATH) if is_unity_platform + read_config_settings + @config_settings[CONFIGURATION_KEY] = options.config + + if is_unity_platform + @config_settings[WORKSPACE_TO_BUILD_KEY] = nil + @config_settings[PROJECT_TO_BUILD_KEY] = UNITY_BUILDS_IOS_PROJECT + @config_settings[WORKSPACE_SCHEME_TO_BUILD_KEY] = UNITY_BUILDS_IOS_SCHEME + @config_settings[PROJECT_TARGET_TO_BUILD_KEY] = nil + @config_settings[ICONS_PATH_KEY] = UNITY_BUILDS_ICONS_PATH + end + begin - read_config_settings + Xcodebuild.read_config_settings(@config_settings[WORKSPACE_TO_BUILD_KEY], @config_settings[PROJECT_TO_BUILD_KEY], + @config_settings[WORKSPACE_SCHEME_TO_BUILD_KEY], @config_settings[PROJECT_TARGET_TO_BUILD_KEY], + @config_settings[SDK_KEY], @config_settings[CONFIGURATION_KEY]) - if is_unity_platform - @config_settings['ICONS_PATH'] = 'Unity-iPhone/Images.xcassets' unless $icons_path - end + raise 'Failed read_config_settings!' unless Xcodebuild.last_cmd_success? + rescue => e + error('Build error!', e) + end - enable_ci_build(options.ci_build) - supplement_config_settings(options.config) + @config_settings.merge!(Xcodebuild.config_settings) + + begin prebuild(options.config) build(options.config, options.ipa, options.ndsym, options.icon_tagger) - restore_info_plist - rescue - raise # re-rise exception but chdir to root_working_dir in ensure block first if needed ensure - if need_chdir_to_root_working_dir and root_working_dir - Dir.chdir(root_working_dir) - end + restore_info_plists end end end end command :deploy do |c| c.syntax = 'nixenvironment deploy' c.description = 'Deploy built artifacts to given server' c.option '--unity_platform TARGET PLATFORM', String, 'Select target platform for unity deploy (ios or android)' c.option '--deliver_deploy', 'Not only verify but also submit the build on iTunes Connect. (resigned_appstore builds only)' - c.action do |args, options| + c.action do |_args, options| need_to_deploy_ios = true + is_unity_platform = options.unity_platform.present? + need_to_deploy_ios = unity_deploy(options.unity_platform) if is_unity_platform - if options.unity_platform and options.unity_platform.length > 0 - need_to_deploy_ios, root_working_dir, need_chdir_to_root_working_dir = unity_deploy(options.unity_platform) - end - if need_to_deploy_ios - begin - read_config_settings - deploy(options.deliver_deploy) - rescue - raise # re-rise exception but chdir to root_working_dir in ensure block first if needed - ensure - if need_chdir_to_root_working_dir and root_working_dir - Dir.chdir(root_working_dir) - end - end + Dir.chdir(UNITY_IOS_PROJECT_PATH) if is_unity_platform + read_config_settings + deploy(options.deliver_deploy) end end end command :clean do |c| c.syntax = 'nixenvironment clean' c.description = 'Remove temp files and clean all targets for xcode project' - c.action do |args, options| - clean - end + c.action { clean } end command :test do |c| c.syntax = 'nixenvironment test' c.description = 'Build xctest unit tests and run them in simulator' - c.action do |args, options| - read_config_settings - test - end + c.action { read_config_settings and test } end command :code_coverage do |c| c.syntax = 'nixenvironment code_coverage' c.description = 'Generate xctest unit tests code coverage report' - c.action do |args, options| - read_config_settings - code_coverage - end + c.action { read_config_settings and code_coverage } end command :code_duplication_report do |c| c.syntax = 'nixenvironment code_duplication_report' c.description = 'Generate code duplication report' - c.action do |args, options| - read_config_settings - code_duplication_report - end + c.action { read_config_settings and code_duplication_report } end command :tag do |c| c.syntax = 'nixenvironment tag' c.description = 'Make SVN/git/mercurial tag, SCM_USERNAME and SCM_PASSWORD must be defined on calling this target' - c.action do |args, options| - tag - end + c.action { tag } end command :svn_tag_from_jenkins do |c| c.syntax = 'nixenvironment svn_tag_from_jenkins' c.description = 'Make tag by finding the first credential in local credential storage' - c.action do |args, options| - svn_tag_from_jenkins - end + c.action { svn_tag_from_jenkins } end command :clean_working_copy do |c| c.syntax = 'nixenvironment clean_working_copy' c.description = 'Make working copy clean' c.option '--all', 'Remove ignored files too' - c.action do |args, options| - clean_working_copy(options.all) - end + c.action { |_args, options| clean_working_copy(options.all) } end def init - template_project_name = nil - template_project_url = nil + template_project_url = nil template_project_types = [] - p('Select project type (put index or name):') - TEMPLATES_REPO_LIST.each_with_index do |(key, value), index| + puts 'Select project type (put index or name):' + TEMPLATES_REPO_LIST.each_with_index do |(key, _value), index| selection_index = index + 1 - selection = "#{selection_index}. #{key}" + selection = "#{selection_index}. #{key}" template_project_types.push(selection) - p(selection) + puts selection end loop do - type = ask('> ', template_project_types) + type = ask('> ', template_project_types) type_index = type.to_i - 1 - if TEMPLATES_REPO_LIST.has_key?(type) + if TEMPLATES_REPO_LIST.key?(type) template_project_url = TEMPLATES_REPO_LIST[type] break - elsif type_index >= 0 and type_index < TEMPLATES_REPO_LIST.length + elsif (0...TEMPLATES_REPO_LIST.size).include?(type_index) template_project_url = TEMPLATES_REPO_LIST.values[type_index] break end end - dest_url = ask('Destination repository url: ') + puts + dest_url = ask('Destination repository url: ') local_directory_to_clone = ask('Directory to clone into: ') + repo_name = File.basename(dest_url, GIT_EXT) + template_project_name = File.basename(template_project_url, GIT_EXT) - repo_name = File.basename(dest_url, '.git') - template_project_name = File.basename(template_project_url, '.git') - - root_working_directory = Dir.pwd - begin - # TODO: do we need to rm_rf it every time? FileUtils.rm_rf(ADJUSTER_WORKING_COPY_PATH) + Dir.mkdir(ADJUSTER_WORKING_COPY_PATH) - Dir.chdir(ADJUSTER_WORKING_COPY_PATH) + Dir.chdir(ADJUSTER_WORKING_COPY_PATH) do + puts + puts 'Cloning template project ...' + Git.clone(template_project_url, nil, :r => true) + raise "Authentication failed for #{template_project_url}!" unless Git.last_cmd_success? - p('Cloning template project ...') - git_clone_success = system("git clone #{template_project_url} --recursive") - abort('Authentication failed for NIX template project! Please check your credentials and try again!') unless git_clone_success + tags = nil - Dir.chdir(template_project_name) - system('git fetch -t') - tags = %x[ git tag ].lines - abort('Failed to get last tag!') unless tags.length > 0 - - Dir.chdir('..') - FileUtils.rm_rf(ADJUSTER_TEMP_PROJECT_NAME) if Dir.exist?(ADJUSTER_TEMP_PROJECT_NAME) - FileUtils.cp_r(template_project_name, ADJUSTER_TEMP_PROJECT_NAME) - Dir.chdir(ADJUSTER_TEMP_PROJECT_NAME) - - p('Checkout newest template project tag ...') - system("git checkout --orphan #{tags[-1]}") - current_branch = 'HEAD' - - p("Push ... #{dest_url}") - system("git remote add #{repo_name}Remote #{dest_url}") - system("git commit -m 'Initial commit'") - git_push_success = system("git push #{repo_name}Remote #{current_branch}:refs/heads/master --force") - abort("Push failed for #{dest_url} repository! Please check the link and try again!") unless git_push_success - - p("Cloning new created project from #{dest_url} to #{local_directory_to_clone} ...") - Dir.chdir(root_working_directory) - Dir.chdir(root_working_directory) - git_clone_success = system("git clone #{dest_url} --recursive #{local_directory_to_clone}") - abort("Error cloning #{dest_url}!") unless git_clone_success - rescue - p('Project initialization failed!') - raise - end - - p('Project initialization complete!') -end - -def update(ninbas) - root_working_directory = Dir.pwd - target_directory = File.join(Dir.home, NIXENV_ROOT) - - begin - Dir.mkdir(target_directory) unless Dir.exist?(target_directory) - Dir.chdir(target_directory) - - REPO_LIST.each do |repo_name, repo_url| - unless Dir.exist?(repo_name) - clone_success = system("git clone #{repo_url} --recursive") - unless clone_success - p("Authentication failed for #{repo_name} project!") - next - end + Dir.chdir(template_project_name) do + puts 'Fetch available tags ...' + Git.fetch(:t => true) + tags = Git.tag end - Dir.chdir(repo_name) + raise 'Failed to get last tag!' if tags.blank? - if repo_name == BUILD_SCRIPTS - if ninbas - system("git checkout #{ninbas}") - Dir.chdir('..') - next - end - end + FileUtils.rm_rf(ADJUSTER_TEMP_PROJECT_NAME) if Dir.exist?(ADJUSTER_TEMP_PROJECT_NAME) + FileUtils.cp_r(template_project_name, ADJUSTER_TEMP_PROJECT_NAME) - system("git fetch -t") - tags = IO.popen('git tag').readlines - tags.map! { |tag| tag.strip! } - tags.sort_by!(&:to_i) + Dir.chdir(ADJUSTER_TEMP_PROJECT_NAME) do + puts 'Checkout newest template project tag ...' + Git.checkout(tags.last, :orphan => true) - if tags.size > 0 - p("Checkout newest #{repo_name} tag ...") - system("git checkout #{tags.last}") - else - abort("Error checkout #{repo_name}! There is no tags!") + puts "Push ... #{dest_url}" + Git.remote_add(repo_name, dest_url) + Git.commit(:m => 'Initial commit') + Git.push(repo_name, Git::DEFAULT_REFSPEC, :f => true) + raise "Push failed for #{dest_url} repository!" unless Git.last_cmd_success? end - - p("Checkout #{repo_name} #{tags.last} tag success!") - - Dir.chdir('..') end - rescue - @error_message = "#{$!}" - ensure - p(@error_message) if @error_message - Dir.chdir(root_working_directory) + + puts "Cloning new created project from #{dest_url} to #{local_directory_to_clone} ..." + Git.clone(dest_url, local_directory_to_clone, :r => true) + raise "Error cloning #{dest_url}!" unless Git.last_cmd_success? + rescue => e + error('Project initialization failed!', e) end + + success('Project initialization complete!') end def read_config_settings begin - @config_settings = YAML.load(File.read(File.join(File.dirname(__FILE__), 'Config'))) - rescue - abort('Config file processing error!') + @config_settings = YAML.load(File.read(CONFIG_SETTINGS_FILE_PATH)) + rescue => e + error("'#{CONFIG_SETTINGS_FILE_PATH}' file processing error!", e) end - update_config_settings('PROJECT_TO_BUILD', $project_to_build) - update_config_settings('PROJECT_TARGET_TO_BUILD', $project_target_to_build) - update_config_settings('PROJECT_TARGET_TO_TEST', $project_target_to_test) - update_config_settings('WORKSPACE_TO_BUILD', $workspace_to_build) - update_config_settings('WORKSPACE_SCHEME_TO_BUILD', $workspace_scheme_to_build) - update_config_settings('WORKSPACE_SCHEME_TO_TEST', $workspace_scheme_to_test) - update_config_settings('SDK', $sdk) - update_config_settings('SDK_FOR_TESTS', $sdk_for_tests) - update_config_settings('EXCLUDE_PATTERN_FOR_CODE_COVERAGE', $exclude_pattern_for_code_coverage) - update_config_settings('EXCLUDE_PATTERN_FOR_CODE_DUPLICATION', $exclude_pattern_for_code_duplication) - update_config_settings('DEPLOY_HOST', $deploy_host) - update_config_settings('DEPLOY_PATH', $deploy_path) - update_config_settings('DEPLOY_USERNAME', $deploy_username) - update_config_settings('DEPLOY_PASSWORD', $deploy_password) - update_config_settings('DEPLOY_ITUNESCONNECT_USERNAME', $deploy_itunesconnect_username) - update_config_settings('ICONS_PATH', $icons_path) - update_config_settings('XCTEST_DESTINATION_DEVICE', $xctest_destination_device) - update_config_settings('CONFIGURATION_FILES_PATH', $configuration_files_path) - update_config_settings('CODE_COVERAGE_CONFIGURATION', $code_coverage_configuration) - update_config_settings('CODE_COVERAGE_OUTPUT_DIRECTORY', $code_coverage_output_directory) - update_config_settings('ENV_VAR_PREFIX', $env_var_prefix) - update_config_settings('BUNDLE_ID', $bundle_id) - update_config_settings('RESIGNED_BUNDLE_ID', $resigned_bundle_id) - update_config_settings('RESIGNED_WATCHKIT_APP_BUNDLE_ID', $resigned_watchkit_app_bundle_id) - update_config_settings('RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID', $resigned_watchkit_extension_bundle_id) - update_config_settings('RESIGNED_WIDGET_BUNDLE_ID', $resigned_widget_bundle_id) - update_config_settings('RESIGNED_BUNDLE_NAME', $resigned_bundle_name) - update_config_settings('RESIGNED_ENTITLEMENTS_PATH', $resigned_entitlements_path) - update_config_settings('RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH', $resigned_watchkit_extension_entitlements_path) - update_config_settings('RESIGNED_WIDGET_ENTITLEMENTS_PATH', $resigned_widget_entitlements_path) + table = Terminal::Table.new + table.title = 'Configuration Settings' + table.headings = [{:value => 'Key', :alignment => :center}, + {:value => 'Specification', :alignment => :center}, + {:value => 'Value', :alignment => :center}] + + update_config_settings(PROJECT_TO_BUILD_KEY, $project_to_build, table, true) + update_config_settings(PROJECT_TARGET_TO_BUILD_KEY, $project_target_to_build, table, true) + update_config_settings(PROJECT_TARGET_TO_TEST_KEY, $project_target_to_test, table, true) + update_config_settings(WORKSPACE_TO_BUILD_KEY, $workspace_to_build, table, true) + update_config_settings(WORKSPACE_SCHEME_TO_BUILD_KEY, $workspace_scheme_to_build, table, true) + update_config_settings(WORKSPACE_SCHEME_TO_TEST_KEY, $workspace_scheme_to_test, table, true) + update_config_settings(SDK_KEY, $sdk, table, true) + update_config_settings(SDK_FOR_TESTS_KEY, $sdk_for_tests, table, true) + update_config_settings(EXCLUDE_PATTERN_FOR_CODE_COVERAGE_KEY, $exclude_pattern_for_code_coverage, table, true) + update_config_settings(EXCLUDE_PATTERN_FOR_CODE_DUPLICATION_KEY, $exclude_pattern_for_code_duplication, table, true) + update_config_settings(DEPLOY_HOST_KEY, $deploy_host, table, true) + update_config_settings(DEPLOY_PATH_KEY, $deploy_path, table, true) + update_config_settings(DEPLOY_USERNAME_KEY, $deploy_username, table, true) + update_config_settings(DEPLOY_PASSWORD_KEY, $deploy_password, table, true) + update_config_settings(DEPLOY_ITUNESCONNECT_USERNAME_KEY, $deploy_itunesconnect_username, table, true) + update_config_settings(ICONS_PATH_KEY, $icons_path, table, true) + update_config_settings(XCTEST_DESTINATION_DEVICE_KEY, $xctest_destination_device, table, true) + update_config_settings(CONFIGURATION_FILES_PATH_KEY, $configuration_files_path, table, true) + update_config_settings(CODE_COVERAGE_CONFIGURATION_KEY, $code_coverage_configuration, table, true) + update_config_settings(CODE_COVERAGE_OUTPUT_DIRECTORY_KEY, $code_coverage_output_directory, table, true) + update_config_settings(ENV_VAR_PREFIX_KEY, $env_var_prefix, table, true) + update_config_settings(BUNDLE_ID_KEY, $bundle_id, table, true) + update_config_settings(RESIGNED_BUNDLE_ID_KEY, $resigned_bundle_id, table, true) + update_config_settings(RESIGNED_WATCHKIT_APP_BUNDLE_ID_KEY, $resigned_watchkit_app_bundle_id, table, true) + update_config_settings(RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID_KEY, $resigned_watchkit_extension_bundle_id, table, true) + update_config_settings(RESIGNED_WIDGET_BUNDLE_ID_KEY, $resigned_widget_bundle_id, table, true) + update_config_settings(RESIGNED_BUNDLE_NAME_KEY, $resigned_bundle_name, table, true) + update_config_settings(RESIGNED_ENTITLEMENTS_PATH_KEY, $resigned_entitlements_path, table, true) + update_config_settings(RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH_KEY, $resigned_watchkit_extension_entitlements_path, table, true) + update_config_settings(RESIGNED_WIDGET_ENTITLEMENTS_PATH_KEY, $resigned_widget_entitlements_path, table, false) + + puts table end -def update_config_settings(key, value) +def update_config_settings(key, value, table, need_separator) if value @config_settings[key] = value - p("#{key} |SPECIFIED| directly: #{value}") + spec_column = "|SPECIFIED| directly" else - p("#{key} |NOT specified| directly. Used from Config: #{@config_settings[key]}") + spec_column = "|NOT specified| directly. Used from Config" end -end -def enable_ci_build(ci_build) - if ci_build - ENV['NIXENV_CI_BUILD'] = '1' - p('CI_BUILD enabled.') - else - ENV['NIXENV_CI_BUILD'] = nil - p('CI_BUILD disabled.') - end + table.add_row [key, spec_column, @config_settings[key]] + table.add_separator if need_separator end def working_copy_is_clean? system(" LAST_REVISION_FILE=\"_last_revision.sh\" @@ -404,723 +323,382 @@ if [ ${WORKING_COPY_IS_CLEAN} -eq 1 ]; then echo \"Working copy is clean. Continuing ...\" else echo \"error: working copy must not have local modifications.\" 1>&2 echo \"You must add following files and folders to .gitignore:\" - echo \"$(git status --porcelain)\" + echo \"#{Git.status(:porcelain => true)}\" exit 1 fi") end -def supplement_config_settings(config) - abort("Build error! Configuration #{config} doesn't exist") unless xcode_project_contains_config?(config) - - project = @config_settings['PROJECT_TO_BUILD'] - target = @config_settings['PROJECT_TARGET_TO_BUILD'] - scheme = @config_settings['WORKSPACE_SCHEME_TO_BUILD'] - workspace = @config_settings['WORKSPACE_TO_BUILD'] - sdk = @config_settings['SDK'] - - if project and project.length > 0 - if target and target.length > 0 - cmd_output = %x[ xcodebuild -project \"#{project}\"\ - -target \"#{target}\"\ - -configuration \"#{config}\"\ - -sdk \"#{sdk}\"\ - -showBuildSettings ] - else - abort("Build error! Scheme #{scheme} doesn't exist") unless xcode_project_contains_scheme?(scheme) - cmd_output = %x[ xcodebuild -project \"#{project}\"\ - -scheme \"#{scheme}\"\ - -configuration \"#{config}\"\ - -sdk \"#{sdk}\"\ - -showBuildSettings ] - end - elsif workspace and workspace.length > 0 - abort("Build error! Scheme #{scheme} doesn't exist") unless xcode_project_contains_scheme?(scheme) - cmd_output = %x[ xcodebuild -workspace \"#{workspace}\"\ - -scheme \"#{scheme}\"\ - -configuration \"#{config}\"\ - -sdk \"#{sdk}\"\ - -showBuildSettings ] - - @unescaped_watchkit_extension_product_settings_path = unescaped_product_settings_path(' WatchKit Extension', config) - @unescaped_watchkit_app_product_settings_path = unescaped_product_settings_path(' WatchKit App', config) - @unescaped_widget_product_settings_path = unescaped_product_settings_path(' Widget', config) - else - abort('Build error! Either PROJECT_TO_BUILD or WORKSPACE_TO_BUILD must be specified!') - end - - # $? - last cmd exit code - unless $? == 0 - abort('Build error!') - end - - # Parse build settings - env_vars_list = cmd_output.split(/\n/).reject(&:empty?) - - if env_vars_list and env_vars_list.length > 0 - build_settings_to_strip = Hash[env_vars_list.map { |it| it.split('=', 2) }] - build_settings_to_strip.each do |key, value| - if key and value - stripped_key = key.strip - stripped_value = value.strip - - # TODO: investigate and fix me! Brutal hack with PRODUCT_SETTINGS_PATH because ruby File & FileUtils can't work with escaped paths - if stripped_key == 'PRODUCT_SETTINGS_PATH' - @unescaped_product_settings_path = stripped_value - end - - @config_settings[stripped_key] ||= stripped_value.shellescape # Assign new value only if assignee is nil - end - end - end - - build_directory = File.join(Dir.pwd, 'build').shellescape - @config_settings['CONFIGURATION_BUILD_DIR'] = build_directory - @config_settings['BUILT_PRODUCTS_DIR'] = build_directory - @config_settings['DWARF_DSYM_FOLDER_PATH'] = build_directory - - plist_path = @unescaped_product_settings_path - bundle_display_name = %x[ /usr/libexec/PlistBuddy -c 'Print CFBundleDisplayName' '#{plist_path}' ].strip! - @config_settings['RESIGNED_BUNDLE_NAME'] ||= bundle_display_name.shellescape -end - -def unescaped_product_settings_path(scheme_suffix, config) - scheme = @config_settings['WORKSPACE_SCHEME_TO_BUILD'] + scheme_suffix - if xcode_project_contains_scheme?(scheme) - cmd_output = %x[ xcodebuild -workspace \"#{@config_settings['WORKSPACE_TO_BUILD']}\"\ - -scheme \"#{scheme}\"\ - -showBuildSettings ] - # Parse build settings - env_vars_list = cmd_output.split(/\n/).reject(&:empty?) - if env_vars_list and env_vars_list.length > 0 - build_settings_to_strip = Hash.new.compare_by_identity - env_vars_list.each do |it| - key_value = it.split('=', 2) - build_settings_to_strip[key_value[0]] = key_value[1] - end - - build_settings_to_strip.each do |key, value| - if key and value - stripped_key = key.strip - stripped_value = value.strip - if stripped_key == 'PRODUCT_SETTINGS_PATH' - if stripped_value.include?(scheme_suffix) - return stripped_value - end - end - end - end - end - end - - nil -end - -def xcode_project_contains_config?(config) - xcode_project_info['Build Configurations'] and xcode_project_info['Build Configurations'].include?(config) -end - -def xcode_project_contains_scheme?(scheme) - xcode_project_info['Schemes'] and xcode_project_info['Schemes'].include?(scheme) -end - -def xcode_project_info - # Parse information about project - cmd_output = %x[ xcodebuild -list 2>&1 ] - abort("Getting xcode_project_info error! #{cmd_output}") if cmd_output.include?('error') - - cmd_output = cmd_output.lines[1..-1].join # Get all lines except first in order to ignore description message - - info = {} - - cmd_output.split(/\n\n/).each do |pair| - key,value = pair.split(/:/) - next unless key and value - lines = value.lines.map { |line| line.strip } - lines.reject! { |line| line.empty? } - info[key.strip] = lines - end - - info -end - def save_build_env_vars - executable_name = @config_settings['EXECUTABLE_NAME'] - watchkit_app_executable = executable_name + ' WatchKit App.app' - watchkit_extension_executable = executable_name + ' WatchKit Extension.appex' - widget_executable = executable_name + ' Widget.appex' + executable_name = @config_settings[EXECUTABLE_NAME_KEY] + watchkit_app_executable = executable_name + WATCHKIT_APP_SUFFIX_WITH_EXT + watchkit_extension_executable = executable_name + WATCHKIT_EXTENSION_SUFFIX_WITH_EXT + widget_executable = executable_name + WIDGET_SUFFIX_WITH_EXT - app_product = File.join(@config_settings['BUILT_PRODUCTS_DIR'], executable_name) + '.app' - watchkit_extension_relative_product = @config_settings['RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID'].nil? ? nil : File.join('PlugIns', watchkit_extension_executable).shellescape - watchkit_app_relative_product = @config_settings['RESIGNED_WATCHKIT_APP_BUNDLE_ID'].nil? ? nil : File.join(watchkit_extension_relative_product, watchkit_app_executable).shellescape - widget_relative_product = @config_settings['RESIGNED_WIDGET_BUNDLE_ID'].nil? ? nil : File.join('PlugIns', widget_executable).shellescape + app_product = File.join(@config_settings[BUILT_PRODUCTS_DIR_KEY], executable_name) + APP_EXT + watchkit_extension_relative_product = @config_settings[RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID_KEY].nil? ? nil : File.join(IOS_PLUGINS_FOLDER_NAME, watchkit_extension_executable) + watchkit_app_relative_product = @config_settings[RESIGNED_WATCHKIT_APP_BUNDLE_ID_KEY].nil? ? nil : File.join(watchkit_extension_relative_product, watchkit_app_executable) + widget_relative_product = @config_settings[RESIGNED_WIDGET_BUNDLE_ID_KEY].nil? ? nil : File.join(IOS_PLUGINS_FOLDER_NAME, widget_executable) - resigned_watchkit_extension_entitlements_path = @config_settings['RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH'].nil? ? nil : @config_settings['RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH'].shellescape - resigned_widget_entitlements_path = @config_settings['RESIGNED_WIDGET_ENTITLEMENTS_PATH'].nil? ? nil : @config_settings['RESIGNED_WIDGET_ENTITLEMENTS_PATH'].shellescape + resigned_watchkit_extension_entitlements_path = @config_settings[RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH_KEY].nil? ? nil : @config_settings[RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH_KEY] + resigned_widget_entitlements_path = @config_settings[RESIGNED_WIDGET_ENTITLEMENTS_PATH_KEY].nil? ? nil : @config_settings[RESIGNED_WIDGET_ENTITLEMENTS_PATH_KEY] - system(" + system(" echo \"#!/bin/sh\ ### AUTOGENERATED BY Nixenvironment; DO NOT EDIT ### - PROJECT=#{@config_settings['PROJECT']} -BUILT_PRODUCTS_DIR=#{@config_settings['BUILT_PRODUCTS_DIR']} -OBJECTS_NORMAL_DIR=#{@config_settings['OBJECT_FILE_DIR_normal']} - EXECUTABLE_NAME=#{@config_settings['EXECUTABLE_NAME']} - APP_PRODUCT=#{app_product} -WATCHKIT_APP_RELATIVE_PRODUCT=#{watchkit_app_relative_product} -WATCHKIT_EXTENSION_RELATIVE_PRODUCT=#{watchkit_extension_relative_product} -WIDGET_RELATIVE_PRODUCT=#{widget_relative_product} - APP_DSYM=#{app_product}.dSYM -APP_INFOPLIST_FILE=#{@config_settings['PRODUCT_SETTINGS_PATH']} - EMBEDDED_PROFILE=#{app_product}/#{@config_settings['EMBEDDED_PROFILE_NAME']} - TARGET_NAME=#{@config_settings['TARGET_NAME']} - CONFIGURATION=#{@config_settings['CONFIGURATION']} - SDK_NAME=#{@config_settings['SDK_NAME']} -RESIGNED_BUNDLE_ID=#{@config_settings['RESIGNED_BUNDLE_ID']} -RESIGNED_WATCHKIT_APP_BUNDLE_ID=#{@config_settings['RESIGNED_WATCHKIT_APP_BUNDLE_ID']} -RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID=#{@config_settings['RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID']} -RESIGNED_WIDGET_BUNDLE_ID=#{@config_settings['RESIGNED_WIDGET_BUNDLE_ID']} -RESIGNED_BUNDLE_NAME=#{@config_settings['RESIGNED_BUNDLE_NAME']} -RESIGNED_ENTITLEMENTS_PATH=#{@config_settings['RESIGNED_ENTITLEMENTS_PATH']} -RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH=#{resigned_watchkit_extension_entitlements_path} -RESIGNED_WIDGET_ENTITLEMENTS_PATH=#{resigned_widget_entitlements_path}\" > _last_build_vars.sh + PROJECT='#{@config_settings[PROJECT_KEY]}' +BUILT_PRODUCTS_DIR='#{@config_settings[BUILT_PRODUCTS_DIR_KEY]}' +OBJECTS_NORMAL_DIR='#{@config_settings[OBJECT_FILE_DIR_NORMAL_KEY]}' + EXECUTABLE_NAME='#{@config_settings[EXECUTABLE_NAME_KEY]}' + APP_PRODUCT='#{app_product}' +WATCHKIT_APP_RELATIVE_PRODUCT='#{watchkit_app_relative_product}' +WATCHKIT_EXTENSION_RELATIVE_PRODUCT='#{watchkit_extension_relative_product}' +WIDGET_RELATIVE_PRODUCT='#{widget_relative_product}' + APP_DSYM='#{app_product + DSYM_EXT}' +APP_INFOPLIST_FILE='#{@config_settings[PRODUCT_SETTINGS_PATH_KEY]}' + EMBEDDED_PROFILE='#{app_product}/#{@config_settings[EMBEDDED_PROFILE_NAME_KEY]}' + TARGET_NAME='#{@config_settings[TARGET_NAME_KEY]}' + CONFIGURATION='#{@config_settings[CONFIGURATION_KEY]}' + SDK_NAME='#{@config_settings[SDK_NAME_KEY]}' +RESIGNED_BUNDLE_ID='#{@config_settings[RESIGNED_BUNDLE_ID_KEY]}' +RESIGNED_WATCHKIT_APP_BUNDLE_ID='#{@config_settings[RESIGNED_WATCHKIT_APP_BUNDLE_ID_KEY]}' +RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID='#{@config_settings[RESIGNED_WATCHKIT_EXTENSION_BUNDLE_ID_KEY]}' +RESIGNED_WIDGET_BUNDLE_ID='#{@config_settings[RESIGNED_WIDGET_BUNDLE_ID_KEY]}' +RESIGNED_BUNDLE_NAME='#{@config_settings[RESIGNED_BUNDLE_NAME_KEY]}' +RESIGNED_ENTITLEMENTS_PATH='#{@config_settings[RESIGNED_ENTITLEMENTS_PATH_KEY]}' +RESIGNED_WATCHKIT_EXTENSION_ENTITLEMENTS_PATH='#{resigned_watchkit_extension_entitlements_path}' +RESIGNED_WIDGET_ENTITLEMENTS_PATH='#{resigned_widget_entitlements_path}'\" > _last_build_vars.sh ") end def prebuild(config) - save_revision = File.join(BUILD_SCRIPTS_PATH, 'SaveRevision.sh') - - system("#{save_revision}") - - abort unless working_copy_is_clean? - - backup_info_plist - + system("#{SAVE_REVISION_SCRIPT_PATH}") + error('Error! Working copy is not clean!') unless working_copy_is_clean? + backup_info_plists save_build_env_vars - - update_info_plist(config) + update_info_plists(config) end def build(config, ipa, ndsym, icon_tagger) - build = File.join(BUILD_SCRIPTS_PATH, 'Build.py') + project_to_build = @config_settings[PROJECT_TO_BUILD_KEY] + project_target_to_build = @config_settings[PROJECT_TARGET_TO_BUILD_KEY] + workspace_to_build = @config_settings[WORKSPACE_TO_BUILD_KEY] + workspace_scheme_to_build = @config_settings[WORKSPACE_SCHEME_TO_BUILD_KEY] + sdk = @config_settings[SDK_KEY] + configuration_build_dir = @config_settings[CONFIGURATION_BUILD_DIR_KEY] + dwarf_dsym_folder_path = @config_settings[DWARF_DSYM_FOLDER_PATH_KEY] + built_products_dir = @config_settings[BUILT_PRODUCTS_DIR_KEY] + env_var_prefix = @config_settings[ENV_VAR_PREFIX_KEY] - build_success = nil - - configuration_build_dir = @config_settings['CONFIGURATION_BUILD_DIR'] - dwarf_dsym_folder_path = @config_settings['DWARF_DSYM_FOLDER_PATH'] - built_products_dir = @config_settings['BUILT_PRODUCTS_DIR'] - debug_information_format = ndsym ? 'dwarf' : 'dwarf-with-dsym' - if @config_settings['PROJECT_TO_BUILD'] and @config_settings['PROJECT_TO_BUILD'].length > 0 - if @config_settings['PROJECT_TARGET_TO_BUILD'] and @config_settings['PROJECT_TARGET_TO_BUILD'].length > 0 - build_success = system("#{build} --project \"#{@config_settings['PROJECT_TO_BUILD']}\"\ - --target \"#{@config_settings['PROJECT_TARGET_TO_BUILD']}\"\ - --configuration \"#{config}\"\ - --sdk \"#{@config_settings['SDK']}\"\ - --env-var-prefix \"#{@config_settings['ENV_VAR_PREFIX']}\"\ - DEBUG_INFORMATION_FORMAT=\"#{debug_information_format}\"\ - DWARF_DSYM_FOLDER_PATH=\"#{dwarf_dsym_folder_path}\"\ - CONFIGURATION_BUILD_DIR=\"#{configuration_build_dir}\"\ - BUILT_PRODUCTS_DIR=\"#{built_products_dir}\"") - else - build_success = system("#{build} --project \"#{@config_settings['PROJECT_TO_BUILD']}\"\ - --scheme \"#{@config_settings['WORKSPACE_SCHEME_TO_BUILD']}\"\ - --configuration \"#{config}\"\ - --sdk \"#{@config_settings['SDK']}\"\ - --env-var-prefix \"#{@config_settings['ENV_VAR_PREFIX']}\"\ - DEBUG_INFORMATION_FORMAT=\"#{debug_information_format}\"\ - DWARF_DSYM_FOLDER_PATH=\"#{dwarf_dsym_folder_path}\"\ - CONFIGURATION_BUILD_DIR=\"#{configuration_build_dir}\"\ - BUILT_PRODUCTS_DIR=\"#{built_products_dir}\"") - end - elsif @config_settings['WORKSPACE_TO_BUILD'] and @config_settings['WORKSPACE_TO_BUILD'].length > 0 - build_success = system("#{build} --workspace \"#{@config_settings['WORKSPACE_TO_BUILD']}\"\ - --scheme \"#{@config_settings['WORKSPACE_SCHEME_TO_BUILD']}\"\ - --configuration \"#{config}\"\ - --sdk \"#{@config_settings['SDK']}\"\ - --env-var-prefix \"#{@config_settings['ENV_VAR_PREFIX']}\"\ - DEBUG_INFORMATION_FORMAT=\"#{debug_information_format}\"\ - DWARF_DSYM_FOLDER_PATH=\"#{dwarf_dsym_folder_path}\"\ - CONFIGURATION_BUILD_DIR=\"#{configuration_build_dir}\"\ - BUILT_PRODUCTS_DIR=\"#{built_products_dir}\"") - end + other_args = { 'DEBUG_INFORMATION_FORMAT' => debug_information_format, 'DWARF_DSYM_FOLDER_PATH' => dwarf_dsym_folder_path, + 'CONFIGURATION_BUILD_DIR' => configuration_build_dir, 'BUILT_PRODUCTS_DIR' => built_products_dir } - unless build_success - restore_info_plist - abort('Build error!') - end + Xcodebuild.build(sdk, config, project_to_build, project_target_to_build, workspace_to_build, workspace_scheme_to_build, env_var_prefix, other_args) - if @config_settings['SDK'].include?('macos') - build_env_vars = load_build_env_vars - built_products_dir = build_env_vars['BUILT_PRODUCTS_DIR'] - executable_name = build_env_vars['EXECUTABLE_NAME'] - target_name = build_env_vars['TARGET_NAME'] - configuration = build_env_vars['CONFIGURATION'] - app_product = build_env_vars['APP_PRODUCT'] + error('Build error!') unless Xcodebuild.last_cmd_success? - new_ipa_name = "#{executable_name}-#{target_name}-#{configuration}" - new_ipa_path = "#{built_products_dir}/#{new_ipa_name}.zip" - p("IPA_PRODUCT = #{new_ipa_path}") - - root_working_dir = Dir.pwd - tmp_dir = Dir.mktmpdir - + if sdk.include?('macos') begin - dest_app_dir = File.join(tmp_dir, new_ipa_name) - dest_app_product = File.join(dest_app_dir, File.basename(app_product)) + Archiver.make_macos_zip + rescue => e + error("Make 'macos_zip' error!", e) + end - p("--> Create '#{dest_app_dir}' ...") - Dir.mkdir(dest_app_dir) - - p("--> Copy '#{app_product}' into '#{dest_app_product}' ...") - FileUtils.cp_r(app_product, dest_app_product) - - if Dir.exist?(new_ipa_path) - p("--> Remove old '#{new_ipa_path}' ...") - FileUtils.rm_rf(new_ipa_path) + success("Make 'macos_zip' complete!") + elsif sdk.include?('iphoneos') + if config == 'Release' + puts 'IconTagger: configuration is Release. Skipping ...' + else + case icon_tagger + when 'full' then tag_icon(false) + when 'short' then tag_icon(true) + when 'off' then puts 'IconTagger is disabled. Skipping ...' + else puts "Unknown IconTagger mode: '#{icon_tagger}'. Skipping ..." end - - p("--> Zip '#{tmp_dir}' into '#{new_ipa_path}' ...") - Dir.chdir(tmp_dir) - - zip_success = system("/usr/bin/zip --symlinks --verbose --recurse-paths \"#{new_ipa_path}\" .") - raise unless zip_success - rescue - abort('Make zip failed!') - ensure - Dir.chdir(root_working_dir) - FileUtils.remove_entry(tmp_dir) end - system(" - IPA_BUNDLE_ID=\"`/usr/libexec/PlistBuddy -c 'Print CFBundleIdentifier' \"#{app_product}/Contents/Info.plist\"`\" + ipa.split.each do |current_ipa| + begin + case current_ipa + when 'device' then Archiver.make_signed_ipa + when 'resigned_device' then Archiver.make_resigned_ipa_for_device + when 'resigned_adhoc' then Archiver.make_resigned_ipa_for_adhoc + when 'resigned_appstore' then Archiver.make_resigned_ipa_for_appstore + else raise "Unknown ipa '#{current_ipa}'!" + end + rescue => e + error("Make '#{current_ipa}' error!", e) + end - echo \"\n -IPA_PRODUCT=#{new_ipa_path.shellescape} -IPA_BUNDLE_ID=\"${IPA_BUNDLE_ID}\" -NAME_FOR_DEPLOYMENT=\"#{configuration}\" - \" >> _last_build_vars.sh") - - return - end - - if config == 'Release' - p('IconTagger: configuration is Release. Skipping ...') - else - case icon_tagger - when 'full' - tag_icon(false) - when 'short' - tag_icon(true) - when 'off' - p('IconTagger is disabled. Skipping ...') - else - p("Unknown IconTagger mode: '#{icon_tagger}'. Skipping ...") + success("Make '#{current_ipa}' complete!") end + else + error("Build error! Unknown sdk: #{sdk}!") end - ipa.split.each do |current_ipa| - case current_ipa - # create .ipa file from last built app product - when 'device' - make = File.join(BUILD_SCRIPTS_PATH, 'MakeIPA.sh') - # resign last built app product with iPhone Developer profile and package it into .ipa file - when 'resigned_device' - make = File.join(BUILD_SCRIPTS_PATH, 'MakeResignedIPAForDevice.sh') - # resign last built app product with iPhone Distribution AdHoc profile and package it into .ipa file - when 'resigned_adhoc' - make = File.join(BUILD_SCRIPTS_PATH, 'MakeResignedIPAForAdHocDistribution.sh') - # resign last built app product with Appstore distribution profile and package it into .ipa file - when 'resigned_appstore' - make = File.join(BUILD_SCRIPTS_PATH, 'MakeResignedIPAForAppstore.sh') - else - restore_info_plist - abort("Error: Unknown ipa '#{current_ipa}'!") - end - - make_success = system("#{make}") if defined? make - - unless make_success - restore_info_plist - abort("#{make} error!") - end - end + success('Build complete!') end def unity_build(configuration, unity_platform, unity_path, development_build, keystore_path, keystore_password, key_alias_name, key_alias_password) - root_working_dir = nil - need_chdir_to_root_working_dir = false need_to_build_ios = false - save_revision = File.join(BUILD_SCRIPTS_PATH, 'SaveRevision.sh') - system("#{save_revision}") + system("#{SAVE_REVISION_SCRIPT_PATH}") + error('Error! Working copy is not clean!') unless working_copy_is_clean? - abort unless working_copy_is_clean? - - unity_build_scripts_dir = File.join(BUILD_SCRIPTS_PATH, 'UnityBuildAutomationScripts') - unity_editor_dir = File.join(Dir.pwd, 'Assets/Editor') - - if File.directory?(unity_editor_dir) - FileUtils.cp_r(unity_build_scripts_dir, unity_editor_dir) + if File.directory?(UNITY_EDITOR_DIR) + FileUtils.cp_r(UNITY_BUILD_SCRIPTS_DIR, UNITY_EDITOR_DIR) else - abort("Copy UnityBuildAutomationScripts error! #{unity_editor_dir} doesn't exist!") + error("Copy #{UNITY_BUILD_SCRIPTS_PATH} error! #{UNITY_EDITOR_DIR} doesn't exist!") end case unity_platform - when 'ios' - need_to_build_ios = true - root_working_dir = Dir.pwd - ios_project_path = File.join(root_working_dir, UNITY_BUILDS_IOS_PATH) - development_build_arg = development_build ? ';developmentBuild=' : '' + when 'ios' + need_to_build_ios = true + development_build_arg = development_build ? ';developmentBuild=' : '' - p('Generating IOS project from UNITY project ...') - unity_success = system("#{unity_path} -projectPath '#{root_working_dir}' -executeMethod NIXBuilder.MakeiOSBuild -projectPath #{root_working_dir.shellescape} -batchmode -logFile -quit -customArgs:buildPath='#{ios_project_path}#{development_build_arg}'") - abort('iOS build unity error!') unless unity_success - p('IOS project was generated.') + puts 'Generating IOS project from UNITY project ...' + unity_success = system("#{unity_path} -executeMethod NIXBuilder.MakeiOSBuild -projectPath '#{Dir.pwd}'\ + -batchmode -logFile -quit -customArgs:buildPath='#{UNITY_IOS_PROJECT_PATH}#{development_build_arg}'") + error('iOS build unity error!') unless unity_success + success('IOS project was generated.') - need_chdir_to_root_working_dir = true - clean_working_copy(false) + clean_working_copy(false) - Dir.chdir(ios_project_path) + $project_to_build = 'Unity-iPhone.xcodeproj' + $project_target_to_build = 'Unity-iPhone' + when 'android' + development_build_arg = development_build ? '--development-build' : '' + keystore_path_arg = keystore_path ? "--keystore-path #{keystore_path}" : '' + keystore_password_arg = keystore_password ? "--keystore-password #{keystore_password}" : '' + key_alias_name_arg = key_alias_name ? "--key-alias-name #{key_alias_name}" : '' + key_alias_password_arg = key_alias_password ? "--key-alias-password #{key_alias_password}" : '' - $project_to_build = 'Unity-iPhone.xcodeproj' - $project_target_to_build = 'Unity-iPhone' - when 'android' - unity_build_android = File.join(BUILD_SCRIPTS_PATH, 'UnityBuildAndroid.py') - development_build_arg = development_build ? '--development-build' : '' - keystore_path_arg = keystore_path ? "--keystore-path #{keystore_path}" : '' - keystore_password_arg = keystore_password ? "--keystore-password #{keystore_password}" : '' - key_alias_name_arg = key_alias_name ? "--key-alias-name #{key_alias_name}" : '' - key_alias_password_arg = key_alias_password ? "--key-alias-password #{key_alias_password}" : '' + build_success = system("#{UNITY_BUILD_ANDROID_SCRIPT_PATH} --configuration #{configuration} --unity-path #{unity_path}\ + #{development_build_arg} #{keystore_path_arg} #{keystore_password_arg} #{key_alias_name_arg} #{key_alias_password_arg}") + error('Android build unity error!') unless build_success - build_success = system("#{unity_build_android} --configuration #{configuration} --unity-path #{unity_path} #{development_build_arg} #{keystore_path_arg} #{keystore_password_arg} #{key_alias_name_arg} #{key_alias_password_arg}") - abort('Android build unity error!') unless build_success - - clean_working_copy(false) - else - abort("Error: Unknown unity target platform '#{unity_platform}'!") + clean_working_copy(false) + else + error("Error: Unknown unity target platform '#{unity_platform}'!") end - return need_to_build_ios, root_working_dir, need_chdir_to_root_working_dir + success('Unity build complete!') + + need_to_build_ios end def tag_icon(short_version) - tagger_directory = File.join(BUILD_SCRIPTS_PATH, 'XcodeIconTagger') - utility = File.join(tagger_directory, 'IconTagger') - plist_path = @unescaped_product_settings_path - version = %x[ /usr/libexec/PlistBuddy -c 'Print CFBundleShortVersionString' '#{plist_path}' ].strip! + plist_path = @config_settings[PRODUCT_SETTINGS_PATH_KEY] + info_plist = Plist.from_file(plist_path) + version = info_plist['CFBundleShortVersionString'] monotonic_revision = %x[ source _last_revision.sh && echo ${MONOTONIC_REVISION} ].strip! - style = short_version ? 'OneLine' : 'TwoLine' - mask_path = File.join(tagger_directory, "masks/#{style}Mask.png") - icons_dir = File.join(Dir.pwd, @config_settings['ICONS_PATH']) - app_product = File.join(@config_settings['BUILT_PRODUCTS_DIR'], @config_settings['EXECUTABLE_NAME']) + '.app' + style = short_version ? 'OneLine' : 'TwoLine' + mask_path = File.join(TAGGER_UTILITY_DIRECTORY, "masks/#{style}Mask.png") + icons_dir = File.join(Dir.pwd, @config_settings[ICONS_PATH_KEY]) + app_product = File.join(@config_settings[BUILT_PRODUCTS_DIR_KEY], @config_settings[EXECUTABLE_NAME_KEY]) + APP_EXT - system("#{utility} --shortVersion=#{version}\ - --buildNumber=#{monotonic_revision}\ - --style=#{style}\ - --maskPath=\"#{mask_path}\"\ - --plist=\"#{plist_path}\"\ - --sourceIconsPath=\"#{icons_dir}\"\ - --destinationIconsPath=#{app_product}") + system("#{TAGGER_UTILITY_PATH} --shortVersion=#{version}\ + --buildNumber=#{monotonic_revision}\ + --style=#{style}\ + --maskPath=\"#{mask_path}\"\ + --plist=\"#{plist_path}\"\ + --sourceIconsPath=\"#{icons_dir}\"\ + --destinationIconsPath=#{app_product}") end -def load_build_env_vars - load_build_env_vars = File.join(BUILD_SCRIPTS_PATH, 'LoadBuildEnvVars.sh') - cmd_output = %x[ source \"#{load_build_env_vars}\" ].strip! - build_env_vars = {} - - vars_list = cmd_output.split(/\n/).reject(&:empty?) - if vars_list and vars_list.length > 0 - vars_to_strip = Hash[vars_list.map { |it| it.split('=', 2) }] - vars_to_strip.each do |key, value| - if key and value - stripped_key = key.strip - stripped_value = value.strip - - p("#{stripped_key} : #{stripped_value}") - build_env_vars[stripped_key] = stripped_value - end - end - end - - build_env_vars +def backup_info_plists + @info_plist_backup_name = backup_info_plist(@config_settings[PRODUCT_SETTINGS_PATH_KEY], nil) + @watchkit_app_info_plist_backup_name = backup_info_plist(@config_settings[WATCHKIT_APP_PRODUCT_SETTINGS_PATH_KEY], WATCHKIT_APP_PREFIX) + @watchkit_extension_info_plist_backup_name = backup_info_plist(@config_settings[WATCHKIT_EXTENSION_PRODUCT_SETTINGS_PATH_KEY], WATCHKIT_EXTENSION_PREFIX) + @widget_info_plist_backup_name = backup_info_plist(@config_settings[WIDGET_PRODUCT_SETTINGS_PATH_KEY], WIDGET_PREFIX) end -def backup_info_plist - p('Backuping Info.plist ...') +def backup_info_plist(product_settings_path, description) + return if product_settings_path.blank? - @info_plist_backup_name = @unescaped_product_settings_path + '.backup' - FileUtils.cp(@unescaped_product_settings_path, @info_plist_backup_name) + puts "Backuping #{description}Info.plist ..." + info_plist_backup_name = product_settings_path + '.backup' + FileUtils.cp(product_settings_path, info_plist_backup_name) + puts "#{description}Info.plist was backuped." - p('Info.plist was backuped.') - - unless @unescaped_watchkit_app_product_settings_path.nil? - p('Backuping WatchKit App Info.plist ...') - - @watchkit_app_info_plist_backup_name = @unescaped_watchkit_app_product_settings_path + '.backup' - FileUtils.cp(@unescaped_watchkit_app_product_settings_path, @watchkit_app_info_plist_backup_name) - - p('WatchKit App Info.plist was backuped.') - end - - unless @unescaped_watchkit_extension_product_settings_path.nil? - p('Backuping WatchKit Extension Info.plist ...') - - @watchkit_extension_info_plist_backup_name = @unescaped_watchkit_extension_product_settings_path + '.backup' - FileUtils.cp(@unescaped_watchkit_extension_product_settings_path, @watchkit_extension_info_plist_backup_name) - - p('WatchKit Extension Info.plist was backuped.') - end - - unless @unescaped_widget_product_settings_path.nil? - p('Backuping Widget Info.plist ...') - - @widget_info_plist_backup_name = @unescaped_widget_product_settings_path + '.backup' - FileUtils.cp(@unescaped_widget_product_settings_path, @widget_info_plist_backup_name) - - p('Widget Info.plist was backuped.') - end + info_plist_backup_name end -def update_info_plist(config) - p('Updating Info.plist ...') - - revision = %x[ source _last_revision.sh && echo ${REVISION} ].strip! +def update_info_plists(config) + revision = %x[ source _last_revision.sh && echo ${REVISION} ].strip! monotonic_revision = %x[ source _last_revision.sh && echo ${MONOTONIC_REVISION} ].strip! - bundle_id = @config_settings['BUNDLE_ID'] + bundle_id = @config_settings[BUNDLE_ID_KEY] - update_success = system("/usr/libexec/PlistBuddy -c 'Set :CFBundleVersion \"#{monotonic_revision}\"' \"#{@unescaped_product_settings_path}\"") + update_info_plist(@config_settings[PRODUCT_SETTINGS_PATH_KEY], monotonic_revision, revision, bundle_id, config, nil) + update_info_plist(@config_settings[WATCHKIT_APP_PRODUCT_SETTINGS_PATH_KEY], monotonic_revision, nil, nil, nil, WATCHKIT_APP_PREFIX) + update_info_plist(@config_settings[WATCHKIT_EXTENSION_PRODUCT_SETTINGS_PATH_KEY], monotonic_revision, nil, nil, nil, WATCHKIT_EXTENSION_PREFIX) + update_info_plist(@config_settings[WIDGET_PRODUCT_SETTINGS_PATH_KEY], monotonic_revision, nil, nil, nil, WIDGET_PREFIX) +end - if bundle_id - update_success &&= system("/usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier \"#{bundle_id}\"' \"#{@unescaped_product_settings_path}\"") - end +def update_info_plist(product_settings_path, monotonic_revision, revision, bundle_id, config, description) + return if product_settings_path.blank? - update_success &&= system("/usr/libexec/PlistBuddy -c 'Add :Configuration string \"#{config}\"' \"#{@unescaped_product_settings_path}\"") - update_success &&= system("/usr/libexec/PlistBuddy -c 'Add :RevisionNumber string \"#{revision}\"' \"#{@unescaped_product_settings_path}\"") + puts "Updating #{description}Info.plist ..." - unless update_success - restore_info_plist - abort('Update Info.plist error!') + begin + info_plist = Plist.from_file(product_settings_path) + info_plist['CFBundleVersion'] = monotonic_revision if monotonic_revision + info_plist['RevisionNumber'] = revision if revision + info_plist['CFBundleIdentifier'] = bundle_id if bundle_id + info_plist['Configuration'] = config if config + info_plist.save(product_settings_path, Plist::FORMAT_XML) + rescue => e + error("Update #{description}Info.plist error!", e) end - p('Info.plist was updated.') + success("#{description}Info.plist was updated.") +end - unless @unescaped_watchkit_app_product_settings_path.nil? - p('Updating WatchKit App Info.plist ...') - - update_success = system("/usr/libexec/PlistBuddy -c 'Set :CFBundleVersion \"#{monotonic_revision}\"' \"#{@unescaped_watchkit_app_product_settings_path}\"") - unless update_success - restore_info_plist - abort('Update WatchKit App Info.plist error!') - end - - p('WatchKit App Info.plist was updated.') - end - - unless @unescaped_watchkit_extension_product_settings_path.nil? - p('Updating Extension App Info.plist ...') - - update_success = system("/usr/libexec/PlistBuddy -c 'Set :CFBundleVersion \"#{monotonic_revision}\"' \"#{@unescaped_watchkit_extension_product_settings_path}\"") - unless update_success - restore_info_plist - abort('Update WatchKit Extension Info.plist error!') - end - - p('WatchKit Extension Info.plist was updated.') - end - - unless @unescaped_widget_product_settings_path.nil? - p('Updating Widget Info.plist ...') - - update_success = system("/usr/libexec/PlistBuddy -c 'Set :CFBundleVersion \"#{monotonic_revision}\"' \"#{@unescaped_widget_product_settings_path}\"") - unless update_success - restore_info_plist - abort('Update Widget Info.plist error!') - end - - p('Widget Info.plist was updated.') - end +def restore_info_plists + restore_info_plist(@config_settings[PRODUCT_SETTINGS_PATH_KEY], @info_plist_backup_name, nil) + restore_info_plist(@config_settings[WATCHKIT_APP_PRODUCT_SETTINGS_PATH_KEY], @watchkit_app_info_plist_backup_name, WATCHKIT_APP_PREFIX) + restore_info_plist(@config_settings[WATCHKIT_EXTENSION_PRODUCT_SETTINGS_PATH_KEY], @watchkit_extension_info_plist_backup_name, WATCHKIT_EXTENSION_PREFIX) + restore_info_plist(@config_settings[WIDGET_PRODUCT_SETTINGS_PATH_KEY], @widget_info_plist_backup_name, WIDGET_PREFIX) end -def restore_info_plist - p('Restoring Info.plist ...') +def restore_info_plist(product_settings_path, info_plist_backup_name, description) + return if product_settings_path.blank? || info_plist_backup_name.blank? - File.delete(@unescaped_product_settings_path) - File.rename(@info_plist_backup_name, @unescaped_product_settings_path) - - p('Info.plist was restored.') - - unless @unescaped_watchkit_app_product_settings_path.nil? - p('Restoring WatchKit App Info.plist ...') - - File.delete(@unescaped_watchkit_app_product_settings_path) - File.rename(@watchkit_app_info_plist_backup_name, @unescaped_watchkit_app_product_settings_path) - - p('WatchKit App Info.plist was restored.') - end - - unless @unescaped_watchkit_extension_product_settings_path.nil? - p('Restoring WatchKit Extension Info.plist ...') - - File.delete(@unescaped_watchkit_extension_product_settings_path) - File.rename(@watchkit_extension_info_plist_backup_name, @unescaped_watchkit_extension_product_settings_path) - - p('WatchKit Extension Info.plist was restored.') - end - - unless @unescaped_widget_product_settings_path.nil? - p('Restoring Widget Info.plist ...') - - File.delete(@unescaped_widget_product_settings_path) - File.rename(@widget_info_plist_backup_name, @unescaped_widget_product_settings_path) - - p('Widget Info.plist was restored.') - end + puts "Restoring #{description}Info.plist ..." + File.delete(product_settings_path) + File.rename(info_plist_backup_name, product_settings_path) + puts "#{description}Info.plist was restored." end def deploy(deliver_deploy) - deploy_host = @config_settings['DEPLOY_HOST'].blank? ? ENV['DEPLOY_HOST'] : @config_settings['DEPLOY_HOST'] - deploy_username = @config_settings['DEPLOY_USERNAME'].blank? ? ENV['DEPLOY_USERNAME'] : @config_settings['DEPLOY_USERNAME'] - deploy_password = @config_settings['DEPLOY_PASSWORD'].blank? ? ENV['DEPLOY_PASSWORD'] : @config_settings['DEPLOY_PASSWORD'] - deploy_itunesconnect_username = @config_settings['DEPLOY_ITUNESCONNECT_USERNAME'].blank? ? ENV['DEPLOY_ITUNESCONNECT_USERNAME'] : @config_settings['DEPLOY_ITUNESCONNECT_USERNAME'] + deploy_host = @config_settings[DEPLOY_HOST_KEY].blank? ? ENV[DEPLOY_HOST_KEY] : @config_settings[DEPLOY_HOST_KEY] + deploy_username = @config_settings[DEPLOY_USERNAME_KEY].blank? ? ENV[DEPLOY_USERNAME_KEY] : @config_settings[DEPLOY_USERNAME_KEY] + deploy_password = @config_settings[DEPLOY_PASSWORD_KEY].blank? ? ENV[DEPLOY_PASSWORD_KEY] : @config_settings[DEPLOY_PASSWORD_KEY] + deploy_itunesconnect_username = @config_settings[DEPLOY_ITUNESCONNECT_USERNAME_KEY].blank? ? ENV[DEPLOY_ITUNESCONNECT_USERNAME_KEY] : @config_settings[DEPLOY_ITUNESCONNECT_USERNAME_KEY] deploy_itunesconnect_username ||= 'unknown' deliver_deploy = deliver_deploy ? 1 : 0 - deploy_success = false - sdk_name = %x[ source _last_build_vars.sh && echo ${SDK_NAME} ].strip! if sdk_name.include?('macos') - build_env_vars = load_build_env_vars - ipa_bundle_id = build_env_vars['IPA_BUNDLE_ID'] - current_app_version = build_env_vars['CURRENT_APP_VERSION'] - current_build_version = build_env_vars['CURRENT_BUILD_VERSION'] - name_for_deployment = build_env_vars['NAME_FOR_DEPLOYMENT'] - executable_name = build_env_vars['EXECUTABLE_NAME'] - ipa_product = build_env_vars['IPA_PRODUCT'] - app_dsym = build_env_vars['APP_DSYM'] - built_products_dir = build_env_vars['BUILT_PRODUCTS_DIR'] + build_env_vars = BuildEnvVarsLoader.load + ipa_bundle_id = build_env_vars[IPA_BUNDLE_ID_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] + executable_name = build_env_vars[EXECUTABLE_NAME_KEY] + ipa_product = build_env_vars[IPA_PRODUCT_KEY] + app_dsym = build_env_vars[APP_DSYM_KEY] + built_products_dir = build_env_vars[BUILT_PRODUCTS_DIR_KEY] 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}") - FileUtils.rm_rf(local_path_to_build) # cleanup in case of previous releases + FileUtils.rm_rf(local_path_to_build) FileUtils.mkdir_p(local_path_to_build) configuration_full_path = File.join(local_path_to_build, name_for_deployment) FileUtils.mkdir(configuration_full_path) - FileUtils.cp(ipa_product, File.join(configuration_full_path, "#{executable_name}.zip")) + FileUtils.cp(ipa_product, File.join(configuration_full_path, executable_name) + ZIP_EXT) if File.exist?(app_dsym) Dir.chdir(built_products_dir) - destination = File.join(configuration_full_path, "#{executable_name}.app.dSYM.zip") - system("zip -r \"#{destination}\" \"#{executable_name}.app.dSYM\"") + destination = File.join(configuration_full_path, "#{executable_name + APP_EXT + DSYM_EXT + ZIP_EXT}") + system("zip -r \"#{destination}\" \"#{executable_name + APP_EXT + DSYM_EXT}\"") end - deploy_path = @config_settings['DEPLOY_PATH'].blank? ? 'Projects/macOSProjects' : @config_settings['DEPLOY_PATH'] - deploy = File.join(BUILD_SCRIPTS_PATH, 'Deploy.sh') - deploy_success = system("#{deploy} #{deploy_host} #{deploy_path} #{deploy_username} #{deploy_password} #{local_path_to_app}") + deploy_path = @config_settings[DEPLOY_PATH_KEY].blank? ? MACOS_PROJECTS_DEPLOY_PATH : @config_settings[DEPLOY_PATH_KEY] + deploy_success = system("#{DEPLOY_SCRIPT_PATH} #{deploy_host} #{deploy_path} #{deploy_username} #{deploy_password} #{local_path_to_app}") else - deploy_path = @config_settings['DEPLOY_PATH'].blank? ? ENV['DEPLOY_PATH'] : @config_settings['DEPLOY_PATH'] - deploy = File.join(BUILD_SCRIPTS_PATH, 'DeployIPA.sh') - deploy_success = system("#{deploy} #{deploy_host} #{deploy_path} #{deploy_username} #{deploy_password} #{deploy_itunesconnect_username} #{deliver_deploy}") + deploy_path = @config_settings[DEPLOY_PATH_KEY].blank? ? ENV[DEPLOY_PATH_KEY] : @config_settings[DEPLOY_PATH_KEY] + deploy_success = system("#{DEPLOY_IPA_SCRIPT_PATH} #{deploy_host} #{deploy_path} #{deploy_username} #{deploy_password} #{deploy_itunesconnect_username} #{deliver_deploy}") end - abort('Deploy error!') unless deploy_success + deploy_success ? success('Deploy complete!') : error('Deploy error!') end def unity_deploy(unity_platform) - root_working_dir = nil - need_chdir_to_root_working_dir = false need_to_deploy_ios = false case unity_platform - when 'ios' - root_working_dir = Dir.pwd - need_chdir_to_root_working_dir = true - need_to_deploy_ios = true - - ios_project_path = File.join(root_working_dir, UNITY_BUILDS_IOS_PATH) - Dir.chdir(ios_project_path) - when 'android' - deploy_success = system(File.join(BUILD_SCRIPTS_PATH, 'DeployAPK.py')) - abort('Android deploy unity error!') unless deploy_success - else - abort("Error: Unknown unity target platform '#{unity_platform}'!") + when 'ios' then need_to_deploy_ios = true + when 'android' then system(DEPLOY_APK_SCRIPT_PATH) ? success('Unity android deploy complete!') : error('Unity android deploy error!') + else error("Error: Unknown unity target platform '#{unity_platform}'!") end - return need_to_deploy_ios, root_working_dir, need_chdir_to_root_working_dir + need_to_deploy_ios end def clean - remove_temporary_files = File.join(BUILD_SCRIPTS_PATH, 'RemoveTemporaryFiles.sh') - - system("#{remove_temporary_files}") + system("#{REMOVE_TEMPORARY_FILES_SCRIPT_PATH}") system('rm -rf test-results/') system("find . -name \"*.pyc\" -exec rm -rf {} \;") - system('xcodebuild -alltargets clean') + Xcodebuild.clean_all_targets end def test - code_coverage_configuration = File.join(@config_settings['CONFIGURATION_FILES_PATH'], @config_settings['CODE_COVERAGE_CONFIGURATION']) - timeout = 10 - ocunit2junit = File.join(BUILD_SCRIPTS_PATH, 'Utils/ocunit2junit') + code_coverage_config = File.join(@config_settings[CONFIGURATION_FILES_PATH_KEY], @config_settings[CODE_COVERAGE_CONFIGURATION_KEY]) - run_tests_success = system("xcodebuild -workspace \"#{@config_settings['WORKSPACE_TO_BUILD']}\"\ - -scheme \"#{@config_settings['WORKSPACE_SCHEME_TO_TEST']}\"\ - -configuration \"Debug\"\ - -sdk \"#{@config_settings['SDK_FOR_TESTS']}\"\ - -xcconfig \"#{code_coverage_configuration}\"\ - -destination-timeout \"#{timeout}\"\ - -destination \"#{@config_settings['XCTEST_DESTINATION_DEVICE']}\"\ - test 2>&1 | \"#{ocunit2junit}\"") + Xcodebuild.test(@config_settings[SDK_FOR_TESTS_KEY], 'Debug', @config_settings[WORKSPACE_TO_BUILD_KEY], + @config_settings[WORKSPACE_SCHEME_TO_TEST_KEY], code_coverage_config) - abort('Run test error!') unless run_tests_success + error('Run test error!') unless Xcodebuild.last_cmd_success? end def code_coverage - generate_code_coverage_report = File.join(BUILD_SCRIPTS_PATH, 'GenerateCodeCoverageForXCTests.sh') - code_coverage_configuration = File.join(@config_settings['CONFIGURATION_FILES_PATH'], @config_settings['CODE_COVERAGE_CONFIGURATION']) - timeout = 10 + code_coverage_configuration = File.join(@config_settings[CONFIGURATION_FILES_PATH_KEY], @config_settings[CODE_COVERAGE_CONFIGURATION_KEY]) - report_success = system("#{generate_code_coverage_report} -workspace \"#{@config_settings['WORKSPACE_TO_BUILD']}\"\ - -scheme \"#{@config_settings['WORKSPACE_SCHEME_TO_TEST']}\"\ - -configuration \"Debug\"\ - -sdk \"#{@config_settings['SDK_FOR_TESTS']}\"\ - -xcconfig \"#{code_coverage_configuration}\"\ - -exclude \"#{@config_settings['EXCLUDE_PATTERN_FOR_CODE_COVERAGE']}\"\ - -output \"#{@config_settings['CODE_COVERAGE_OUTPUT_DIRECTORY']}\"\ - -destination-timeout \"#{timeout}\"\ - -destination \"#{@config_settings['XCTEST_DESTINATION_DEVICE']}\"") - abort('Code coverage error!') unless report_success + # TODO: move to Xcodebuild class + report_success = system("#{CODE_COVERAGE_REPORT_SCRIPT_PATH} -workspace \"#{@config_settings[WORKSPACE_TO_BUILD_KEY]}\"\ + -scheme \"#{@config_settings[WORKSPACE_SCHEME_TO_TEST_KEY]}\"\ + -configuration \"Debug\"\ + -sdk \"#{@config_settings[SDK_FOR_TESTS_KEY]}\"\ + -xcconfig \"#{code_coverage_configuration}\"\ + -exclude \"#{@config_settings[EXCLUDE_PATTERN_FOR_CODE_COVERAGE_KEY]}\"\ + -output \"#{@config_settings[CODE_COVERAGE_OUTPUT_DIRECTORY_KEY]}\"\ + -destination-timeout \"#{TESTS_AND_COVERAGE_TIMEOUT}\"\ + -destination \"#{@config_settings[XCTEST_DESTINATION_DEVICE_KEY]}\"") + error('Code coverage error!') unless report_success end def code_duplication_report - generate_code_duplication_report = File.join(BUILD_SCRIPTS_PATH, 'GenerateCodeDuplicationReport.sh') - duplication_success = system("#{generate_code_duplication_report} \"#{@config_settings['EXCLUDE_PATTERN_FOR_CODE_DUPLICATION']}\" duplication.xml") - abort('Generate code duplication error!') unless duplication_success + duplication_success = system("#{CODE_DUPLICATION_REPORT_SCRIPT_PATH} \"#{@config_settings[EXCLUDE_PATTERN_FOR_CODE_DUPLICATION_KEY]}\" duplication.xml") + error('Generate code duplication error!') unless duplication_success end def tag - make_tag = File.join(BUILD_SCRIPTS_PATH, 'MakeTag.sh') - tag_success = system("#{make_tag} \"#{ENV['SCM_USERNAME']}\" \"#{ENV['SCM_PASSWORD']}\"") - abort('Make tag error!') unless tag_success + tag_success = system("#{MAKE_TAG_SCRIPT_PATH} \"#{ENV[SCM_USERNAME_KEY]}\" \"#{ENV[SCM_PASSWORD_KEY]}\"") + error('Make tag error!') unless tag_success end # Jenkins stores SVN credentials locally in XML, so this command gets and uses them on making tag by finding the first credential in local credential storage # ATTENTION: if this command picks up wrong credentials, then you should manually edit subversion.credentials file on Jenkins in order to remove the wrong credential # Additional |echo| is needed in order to add newline, otherwise base64 encoding doesn't work def svn_tag_from_jenkins - ENV['SCM_USERNAME']=%x[ $(shell xpath ../subversion.credentials \(//userName\)[1]/text\(\)) ] - ENV['SCM_PASSWORD']=%x[ $(shell echo $$(xpath ../subversion.credentials \(//password\)[1]/text\(\) 2>/dev/null && echo) | openssl base64 -d) ] + ENV[SCM_USERNAME_KEY]=%x[ $(shell xpath ../subversion.credentials \(//userName\)[1]/text\(\)) ] + ENV[SCM_PASSWORD_KEY]=%x[ $(shell echo $$(xpath ../subversion.credentials \(//password\)[1]/text\(\) 2>/dev/null && echo) | openssl base64 -d) ] tag end def clean_working_copy(all) - clean_all = all ? 'all' : nil - clean_working_copy = File.join(BUILD_SCRIPTS_PATH, 'CleanWorkingCopy.sh') - clean_success = system("#{clean_working_copy} #{clean_all}") - abort('Clean working copy error!') unless clean_success + clean_all = all ? 'all' : nil + clean_success = system("#{CLEAN_WORKING_COPY_SCRIPT_PATH} #{clean_all}") + error('Clean working copy error!') unless clean_success +end + +def error(msg, e = nil) + if e.present? + puts e.inspect + puts e.backtrace + end + + abort "#{msg} #{e.to_s.strip}".red.on_yellow.bold +end + +def success(msg) + puts msg.green.on_blue.bold end \ No newline at end of file