#!/usr/bin/env ruby require 'rubygems' require 'nixenvironment' require 'commander/import' require 'yaml' require 'fileutils' require 'shellwords' include Nixenvironment # :name is optional, otherwise uses the basename of this executable 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 } 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 ('--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_bundle_name VALUE') { |value| $resigned_bundle_name = value } global_option ('--resigned_entitlements_path VALUE') { |value| $resigned_entitlements_path = value } 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 TYPE', String, 'Select sign (ipa, resigned_ipa_for_device, resigned_ipa_for_adhoc_distribution or resigned_ipa_for_appstore)' c.option '--ci_build', 'Define NIXENV_CI_BUILD environment variable' c.option '--unity TARGET PLATFORM', String, 'Select target platform for unity build (ios or android)' c.action do |args, options| options.default :config => 'Debug', :ipa => 'ipa' need_to_build_ios = true if options.unity and options.unity.length > 0 need_to_build_ios, root_working_dir, need_chdir_to_root_working_dir = unity_build(options.unity) end if need_to_build_ios begin read_config_settings enable_ci_build(options.ci_build) supplement_config_settings(options.config) prebuild(options.config) build(options.config, options.ipa) 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 end end end end command :deploy do |c| c.syntax = 'nixenvironment deploy' c.description = 'Deploy built artifacts to given server' c.option '--unity TARGET PLATFORM', String, 'Select target platform for unity deploy (ios or android)' c.action do |args, options| if options.unity and options.unity.length > 0 need_to_deploy_ios, root_working_dir, need_chdir_to_root_working_dir = unity_deploy(options.unity) return unless need_to_deploy_ios end begin read_config_settings 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 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 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 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 end command :code_duplication_report do |c| c.syntax = 'nixenvironment code_duplication_report' c.description = 'Generate code duplication report for xctest' c.action do |args, options| read_config_settings code_duplication_report end 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 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 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 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 end Dir.chdir(repo_name) if repo_name == BUILD_SCRIPTS if ninbas system("git checkout #{ninbas}") Dir.chdir('..') next end end system("git fetch -t") tags = IO.popen('git tag').readlines tags.map! { |tag| tag.strip! } 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!") 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) end end def read_config_settings begin @config_settings = YAML.load(File.read(File.join(File.dirname(__FILE__), 'Config'))) rescue abort('Config file processing error!') 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('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_BUNDLE_NAME', $resigned_bundle_name) update_config_settings('RESIGNED_ENTITLEMENTS_PATH', $resigned_entitlements_path) end def update_config_settings(key, value) if value @config_settings[key] = value p("#{key} |SPECIFIED| directly: #{value}") else p("#{key} |NOT specified| directly. Used from Config: #{@config_settings[key]}") 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 end def working_copy_is_clean? system(" LAST_REVISION_FILE=\"_last_revision.sh\" source ${LAST_REVISION_FILE} 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)\" exit 1 fi") end def supplement_config_settings(config) abort("Build error! Configuration #{config} doesn't exist") unless xcode_project_contains_config?(config) 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 cmd_output = %x[ xcodebuild -project \"#{@config_settings['PROJECT_TO_BUILD']}\"\ -target \"#{@config_settings['PROJECT_TARGET_TO_BUILD']}\"\ -configuration \"#{config}\"\ -sdk \"#{@config_settings['SDK']}\"\ -showBuildSettings ] else cmd_output = %x[ xcodebuild -project \"#{@config_settings['PROJECT_TO_BUILD']}\"\ -scheme \"#{@config_settings['WORKSPACE_SCHEME_TO_BUILD']}\"\ -configuration \"#{config}\"\ -sdk \"#{@config_settings['SDK']}\"\ -showBuildSettings ] end elsif @config_settings['WORKSPACE_TO_BUILD'] and @config_settings['WORKSPACE_TO_BUILD'].length > 0 cmd_output = %x[ xcodebuild -workspace \"#{@config_settings['WORKSPACE_TO_BUILD']}\"\ -scheme \"#{@config_settings['WORKSPACE_SCHEME_TO_BUILD']}\"\ -configuration \"#{config}\"\ -sdk \"#{@config_settings['SDK']}\"\ -showBuildSettings ] 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 end def xcode_project_contains_config?(config) # Parse information about project cmd_output = %x[ xcodebuild -list 2>&1 ] abort("Validate configuration 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['Build Configurations'].include?(config) end def save_build_env_vars app_product = File.join(@config_settings['BUILT_PRODUCTS_DIR'], @config_settings['EXECUTABLE_NAME']) + '.app' 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} 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_BUNDLE_NAME=#{@config_settings['RESIGNED_BUNDLE_NAME']} RESIGNED_ENTITLEMENTS_PATH=#{@config_settings['RESIGNED_ENTITLEMENTS_PATH']}\" > _last_build_vars.sh ") end def prebuild(config) save_revision = File.join(BUILD_SCRIPTS_PATH, 'SaveRevision.sh') tag_icons = File.join(BUILD_SCRIPTS_PATH, 'XcodeIconTagger/tagIcons.sh') system("#{save_revision}") abort unless working_copy_is_clean? backup_info_plist save_build_env_vars update_info_plist(config) # TODO: rewrite tagIcons.sh # system("#{tag_icons} #{@config_settings['ICONS_PATH']}") end def build(config, ipa) build = File.join(BUILD_SCRIPTS_PATH, 'Build.py') 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'] 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=\"dwarf-with-dsym\"\ 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=\"dwarf-with-dsym\"\ 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=\"dwarf-with-dsym\"\ DWARF_DSYM_FOLDER_PATH=\"#{dwarf_dsym_folder_path}\"\ CONFIGURATION_BUILD_DIR=\"#{configuration_build_dir}\"\ BUILT_PRODUCTS_DIR=\"#{built_products_dir}\"") end unless build_success restore_info_plist abort('Build error!') end case ipa # create .ipa file from last built app product when 'ipa' 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_ipa_for_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_ipa_for_adhoc_distribution' 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_ipa_for_appstore' make = File.join(BUILD_SCRIPTS_PATH, 'MakeResignedIPAForAppstore.sh') else abort("Error: Unknown ipa '#{ipa}'!") end make_success = system("#{make}") if defined? make unless make_success restore_info_plist abort("#{make} error!") end end def unity_build(unity) 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}") 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) else abort("Copy UnityBuildAutomationScripts error! #{unity_editor_dir} doesn't exist!") end case unity when 'ios' need_to_build_ios = true root_working_dir = Dir.pwd ios_project_path = File.join(root_working_dir, UNITY_BUILDS_IOS_PATH) p('Generating IOS project from UNITY project ...') unity_success = system("unity -executeMethod NIXBuilder.MakeiOSBuild -projectPath #{root_working_dir.shellescape} -batchmode -logFile -quit -customArgs:path='#{ios_project_path}'") abort('iOS build unity error!') unless unity_success p('IOS project was generated.') need_chdir_to_root_working_dir = true clean_working_copy(false) Dir.chdir(ios_project_path) $project_to_build = 'Unity-iPhone.xcodeproj' $project_target_to_build = 'Unity-iPhone' when 'android' build_success = system(File.join(BUILD_SCRIPTS_PATH, 'UnityBuildAndroid.py')) abort('Android build unity error!') unless build_success clean_working_copy(false) else abort("Error: Unknown unity target platform '#{unity}'!") end return need_to_build_ios, root_working_dir, need_chdir_to_root_working_dir end def backup_info_plist p('Backuping Info.plist ...') @info_plist_backup_name = @unescaped_product_settings_path + '.backup' FileUtils.cp(@unescaped_product_settings_path, @info_plist_backup_name) p('Info.plist was backuped.') end def update_info_plist(config) p('Updating Info.plist ...') revision = %x[ source _last_revision.sh && echo ${REVISION} ].strip! monotonic_revision = %x[ source _last_revision.sh && echo ${MONOTONIC_REVISION} ].strip! update_success = system("/usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier \"#{@config_settings['BUNDLE_ID']}\"' \"#{@unescaped_product_settings_path}\"") update_success &&= system("/usr/libexec/PlistBuddy -c 'Set :CFBundleVersion \"#{monotonic_revision}\"' \"#{@unescaped_product_settings_path}\"") 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}\"") unless update_success restore_info_plist abort('Update Info.plist error!') end p('Info.plist was updated.') end def restore_info_plist p('Restoring Info.plist ...') File.delete(@unescaped_product_settings_path) File.rename(@info_plist_backup_name, @unescaped_product_settings_path) p('Info.plist was restored.') end def deploy deploy = File.join(BUILD_SCRIPTS_PATH, 'DeployIPA.sh') deploy_host = @config_settings['DEPLOY_HOST'].nil? || @config_settings['DEPLOY_HOST'].empty? ? ENV['DEPLOY_HOST'] : @config_settings['DEPLOY_HOST'] deploy_path = @config_settings['DEPLOY_PATH'].nil? || @config_settings['DEPLOY_PATH'].empty? ? ENV['DEPLOY_PATH'] : @config_settings['DEPLOY_PATH'] deploy_username = @config_settings['DEPLOY_USERNAME'].nil? || @config_settings['DEPLOY_USERNAME'].empty? ? ENV['DEPLOY_USERNAME'] : @config_settings['DEPLOY_USERNAME'] deploy_password = @config_settings['DEPLOY_PASSWORD'].nil? || @config_settings['DEPLOY_PASSWORD'].empty? ? ENV['DEPLOY_PASSWORD'] : @config_settings['DEPLOY_PASSWORD'] deploy_success = system("#{deploy} #{deploy_host} #{deploy_path} #{deploy_username} #{deploy_password}") abort('Deploy error!') unless deploy_success end def unity_deploy(unity) root_working_dir = nil need_chdir_to_root_working_dir = false need_to_deploy_ios = false case unity 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}'!") end return need_to_deploy_ios, root_working_dir, need_chdir_to_root_working_dir end def clean remove_temporary_files = File.join(BUILD_SCRIPTS_PATH, 'RemoveTemporaryFiles.sh') system("#{remove_temporary_files}") system('rm -rf test-results/') system("find . -name \"*.pyc\" -exec rm -rf {} \;") system('xcodebuild -alltargets clean') 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') 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}\"") abort('Run test error!') unless run_tests_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 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 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 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 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) ] 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 end