Files
XCRemoteCache/Rakefile
T
2022-01-27 22:43:49 +01:00

228 lines
7.2 KiB
Ruby

# encoding: utf-8
require 'json'
################################
# Rake configuration
################################
# Paths
DERIVED_DATA_DIR = File.join('.build').freeze
RELEASES_ROOT_DIR = File.join('releases').freeze
EXECUTABLE_NAME = 'XCRemoteCache'
EXECUTABLE_NAMES = ['xclibtool', 'xcpostbuild', 'xcprebuild', 'xcprepare', 'xcswiftc', 'xcld']
PROJECT_NAME = 'XCRemoteCache'
SWIFTLINT_ENABLED = true
SWIFTFORMAT_ENABLED = true
################################
# Tasks
################################
task :prepare do
Dir.mkdir(DERIVED_DATA_DIR) unless File.exists?(DERIVED_DATA_DIR)
end
desc 'lint'
task :lint => [:prepare] do
puts 'Run linting'
system("swiftformat --lint --config .swiftformat --cache ignore .") or abort "swiftformat failure" if SWIFTFORMAT_ENABLED
system("swiftlint lint --config .swiftlint.yml --strict") or abort "swiftlint failure" if SWIFTLINT_ENABLED
end
task :autocorrect => [:prepare] do
puts 'Run autocorrect'
system("swiftformat --config .swiftformat --cache ignore .") or abort "swiftformat failure" if SWIFTFORMAT_ENABLED
system("swiftlint autocorrect --config .swiftlint.yml") or abort "swiftlint failure" if SWIFTLINT_ENABLED
end
desc 'build package artifacts'
task :build, [:configuration, :arch, :sdks, :is_archive] do |task, args|
# Set task defaults
args.with_defaults(:configuration => 'debug', :sdks => ['macos'])
unless args.configuration == 'Debug'.downcase || args.configuration == 'Release'.downcase
fail("Unsupported configuration. Valid values: ['Debug', 'Release']. Found '#{args.configuration}''")
end
# Clean data generated by SPM
# FIXME: dangerous recursive rm
system("rm -rf #{DERIVED_DATA_DIR} > /dev/null 2>&1")
# Build
build_paths = []
args.sdks.each do |sdk|
spm_build(args.configuration, args.arch)
# Path of the executable looks like: `.build/(debug|release)/XCRemoteCache`
build_path_base = File.join(DERIVED_DATA_DIR, args.configuration)
sdk_build_paths = EXECUTABLE_NAMES.map {|e| File.join(build_path_base, e)}
build_paths.push(sdk_build_paths)
end
puts "Build products: #{build_paths}"
if args.configuration == 'Release'.downcase
puts "Creating release zip"
create_release_zip(build_paths[0])
end
end
desc 'run tests with SPM'
task :test do
# Running tests
spm_test()
end
desc 'run E2E tests with CocoaPods plugin'
task :e2e => [:build, :e2e_only]
desc 'run E2E tests without building the XCRemoteCache binary'
task :e2e_only do
# Build a plugin
cocoapods_dir = 'cocoapods-plugin'
Dir.chdir(cocoapods_dir) do
gemspec_path = "cocoapods-xcremotecache.gemspec"
gemfile_path = "cocoapods-xcremotecache.gem"
system("gem build #{gemspec_path} -o #{gemfile_path}")
system("gem install #{gemfile_path}")
end
# Build a docker image
system('docker build -t xcremotecache-demo-server backend-example')
current_branch = `git rev-parse --abbrev-ref HEAD`.chomp
producer_configuration = %{xcremotecache({
'cache_addresses' => ['http://localhost:8080/cache/pods'],
'primary_repo' => '.',
'primary_branch' => '#{current_branch}',
'mode' => 'producer',
'final_target' => 'XCRemoteCacheSample',
'artifact_maximum_age' => 0
})}
consumer_configuration = %{xcremotecache({
'cache_addresses' => ['http://localhost:8080/cache/pods'],
'primary_repo' => '.',
'primary_branch' => '#{current_branch}',
'mode' => 'consumer',
'final_target' => 'XCRemoteCacheSample',
'artifact_maximum_age' => 0
})}
# Configure remote
system('git remote add self . ; git fetch self')
log_name = "xcodebuild.log"
# initalize Pods
for podfile_path in Dir.glob('e2eTests/**/*.Podfile')
p "****** Scenario: #{podfile_path}"
# Revert any local changes
system('git clean -xdf e2eTests/XCRemoteCacheSample')
# Link prebuild binaries to the Project
system('ln -s $(pwd)/releases e2eTests/XCRemoteCacheSample/XCRC')
# Run a docker server
system('docker run -it --rm -d -p 8080:8080 --name xcremotecache xcremotecache-demo-server')
# Create producer Podfile
File.open('e2eTests/XCRemoteCacheSample/Podfile', 'w') do |f|
# Copy podfile
File.foreach(podfile_path) { |line| f.puts line }
f.write(producer_configuration)
end
Dir.chdir('e2eTests/XCRemoteCacheSample') do
system('pod install')
p "Building producer ..."
system("xcodebuild -workspace 'XCRemoteCacheSample.xcworkspace' -scheme 'XCRemoteCacheSample' -configuration 'Debug' -sdk 'iphonesimulator' -destination 'generic/platform=iOS Simulator' -derivedDataPath ./DerivedData EXCLUDED_ARCHS='arm64 i386' clean build > #{log_name}")
# reset stats
system('XCRC/xcprepare stats --reset --format json')
# clean DerivedData
system('rm -rf ./build')
end
# Create consumer Podfile
File.open('e2eTests/XCRemoteCacheSample/Podfile', 'w') do |f|
# Copy podfile
File.foreach(podfile_path) { |line| f.puts line; p }
f.write(consumer_configuration)
end
Dir.chdir('e2eTests/XCRemoteCacheSample') do
system('pod install')
p "Building consumer ..."
system("xcodebuild -workspace 'XCRemoteCacheSample.xcworkspace' -scheme 'XCRemoteCacheSample' -configuration 'Debug' -sdk 'iphonesimulator' -destination 'generic/platform=iOS Simulator' -derivedDataPath ./DerivedData EXCLUDED_ARCHS='arm64 i386' clean build > #{log_name}")
# clean DerivedData
system('rm -rf ./build')
# validate 100% hit rate
stats_json_string = JSON.parse(`XCRC/xcprepare stats --format json`)
misses = stats_json_string.fetch('miss_count', 0)
hits = stats_json_string.fetch('hit_count', 0)
all_targets = misses + hits
raise "Failure: XCRemoteCache is disabled" if all_targets == 0
hit_rate = hits * 100 / all_targets
raise "Failure: Hit rate is only #{hit_rate}%" if misses != 0
p "hit rate: #{hit_rate}% (#{hits}/#{all_targets})"
end
# Kill a docker
system('docker kill xcremotecache')
end
# Revert remote
system('git origin delete self')
end
################################
# Helper functions
################################
def spm_build(configuration, arch)
spm_cmd = "swift build "\
"-c #{configuration} "\
"#{arch.nil? ? "" : "--triple #{arch}"} "
system(spm_cmd) or abort "Build failure"
end
def bash(command)
system "bash -c \"#{command}\""
end
def spm_test()
tests_output_file = File.join(DERIVED_DATA_DIR, 'tests.log')
# Redirect error stream with to a file and pass to the second stream output
spm_cmd = "swift test --enable-code-coverage 2> >(tee #{tests_output_file})"
test_succeeded = bash(spm_cmd)
abort "Test failure" unless test_succeeded
end
def create_release_zip(build_paths)
release_dir = RELEASES_ROOT_DIR
# Create and move files into the release directory
mkdir_p release_dir
build_paths.each {|p|
cp_r p, release_dir
}
output_artifact_basename = "#{PROJECT_NAME}.zip"
Dir.chdir(release_dir) do
# -X: no extras (uid, gid, file times, ...)
# -x: exclude .DS_Store
# -r: recursive
system("zip -X -x '*.DS_Store' -r #{output_artifact_basename} .") or abort "zip failure"
# List contents of zip file
system("unzip -l #{output_artifact_basename}") or abort "unzip failure"
end
end