require 'bundler/gem_tasks' require 'rspec/core/rake_task' require 'jars/installer' RSpec::Core::RakeTask.new(:spec) task :default => :spec desc "Install JAR dependencies" task :install_jars do Jars::Installer.vendor_jars! end desc "Generate travis-esque build matrix config" task :circleci do require 'yaml' class CircleCIConfig def self.generate(path) new.generate(path) end def generate(path) File.open(path, 'w:utf-8') do |f| f.write(YAML.dump(config)) end end def jruby_image_tags %w{9.2.9.0 9.1.17.0 9.2.10.0 9.2.11.1 9.2.12.0 9.2.13.0-SNAPSHOT-latest} end def jdk_image_tags { "8-jdk-slim" => "JDK 8", "11-jdk-slim" => "JDK 11", "13-jdk-slim" => "JDK 13" } end def alt_saxon_urls { "https://sourceforge.net/projects/saxon/files/Saxon-HE/9.8/SaxonHE9-8-0-15J.zip" => "saxon-he-9.8", "https://sourceforge.net/projects/saxon/files/Saxon-HE/10/Java/SaxonHE10-2J.zip" => "saxon-he-10.2" } end def skip_jdk_versions [ %w{9.1.17.0 11-jdk-slim}, %w{9.1.17.0 13-jdk-slim}, ] end def codeclimate_jobs (alt_saxon_urls.keys << nil).map { |alt_saxon_url| ["9.2.12.0", "8-jdk-slim", alt_saxon_url] } end def all_job_variants jruby_image_tags.product(jdk_image_tags.keys, alt_saxon_urls.keys << nil).reject { |jruby, jdk, _| skip_jdk_versions.include?([jruby, jdk]) } end def job_name(jruby_image_tag, jdk_image_tag, alt_saxon_url) [ "JRuby #{jruby_image_tag}, #{jdk_image_tags[jdk_image_tag]}", alt_saxon_urls[alt_saxon_url] ].compact.join(' ') end def all_job_names all_job_variants.map { |jruby_image_tag, jdk_image_tag, alt_saxon_url| job_name(jruby_image_tag, jdk_image_tag, alt_saxon_url) } end def jobs all_job_variants.map { |jruby_image_tag, jdk_image_tag, alt_saxon_url| run_codeclimate = codeclimate_jobs.include?([jruby_image_tag, jdk_image_tag, alt_saxon_url]) [ job_name(jruby_image_tag, jdk_image_tag, alt_saxon_url), job_config({ run_codeclimate: run_codeclimate, alt_saxon_url: alt_saxon_url, docker_image: docker_image(jruby_image_tag, jdk_image_tag) }) ] }.to_h.merge(report_test_coverage_job({ docker_image: "circleci/ruby:latest", run_codeclimate: true })) end def docker_image(jruby_image_tag, jdk_image_tag) "fidothe/circleci:jruby-#{jruby_image_tag}-#{jdk_image_tag}" end def job_config(opts = {}) job = { "docker" => [ {"image" => opts.fetch(:docker_image)} ], "environment" => environment(opts), "steps" => steps(opts) } end def environment(opts = {}) env = { "BUNDLE_JOBS" => 3, "BUNDLE_RETRY" => 3, "BUNDLE_PATH" => "vendor/bundle", "JRUBY_OPTS" => "--dev --debug" } env["ALTERNATE_SAXON_HOME"] = "/tmp/saxon" if opts.fetch(:alt_saxon_url) env end def steps(opts = {}) [ "checkout", alt_saxon_install(opts), { "run" => { "name" => "Bundle Install", "command" => "bundle check || bundle install" } }, install_codeclimate_reporter_step(opts), run_tests_step(opts), persist_test_coverage_to_workspace_step(opts), { "store_test_results" => {"path" => "/tmp/test-results"} }, { "store_artifacts" => {"path" => "/tmp/test-results", "destination" => "test-results"} } ].compact end def alt_saxon_install(opts) return nil unless opts.fetch(:alt_saxon_url) saxon_file = File.basename(opts[:alt_saxon_url]) { "run" => { "name" => "Download #{saxon_file}", "command" => [ "mkdir -p /tmp/saxon", "cd /tmp/saxon", "curl -L -O #{opts[:alt_saxon_url]}", "unzip #{saxon_file}", "rm -f #{saxon_file}" ].join("\n") } } end def attach_workspace_step(opts) return nil unless opts.fetch(:run_codeclimate) { "attach_workspace" => { "at" => "/tmp/workspace" } } end def install_codeclimate_reporter_step(opts) return nil unless opts.fetch(:run_codeclimate) { "run" => { "name" => "Install Code Climate Test Reporter", "command" => "curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter\n" + "chmod +x ./cc-test-reporter\n" } } end def persist_test_coverage_to_workspace_step(opts) return nil unless opts.fetch(:run_codeclimate) { "persist_to_workspace" => { "root" => "~/project", "paths" => [ "cc-coverage*" ] } } end def run_tests_step(opts) command = [ "mkdir -p /tmp/test-results", "VERIFY_SAXON_LAZY_LOADING=1 bundle exec rspec spec/jar_loading_spec.rb --options .rspec-jar-loading --profile 10 --format RspecJunitFormatter --out /tmp/test-results/rspec-jar-loading.xml" ] cc_suffix = opts.fetch(:alt_saxon_url) ? "-alt-#{alt_saxon_urls[opts.fetch(:alt_saxon_url)]}" : '' if opts.fetch(:run_codeclimate) command.prepend("./cc-test-reporter before-build") command.append("if [ $? -eq 0 ]; then ./cc-test-reporter format-coverage -t simplecov -o \"cc-coverage-jar-loading#{cc_suffix}.json\"; fi") end command.append("rm -rf coverage") command.append("bundle exec rspec spec --profile 10 --format RspecJunitFormatter --out /tmp/test-results/rspec.xml --format progress") if opts.fetch(:run_codeclimate) command.append("if [ $? -eq 0 ]; then ./cc-test-reporter format-coverage -t simplecov -o \"cc-coverage-main#{cc_suffix}.json\"; fi") end { "run" => { "name" => "Run the tests" + (opts.fetch(:run_codeclimate) ? ", and upload coverage data to Code Climate" : ""), "command" => command.join("\n") } } end def report_test_coverage_job(opts) { "Report test coverage to Code Climate" => { "docker" => [ {"image" => opts.fetch(:docker_image)} ], "steps" => [ { "attach_workspace" => { "at" => "/tmp/workspace" } }, install_codeclimate_reporter_step(opts), { "run" => { "name" => "Upload test coverage to Code Climate", "command" => "find /tmp/workspace -name 'cc-coverage*.json' &&\\\n ./cc-test-reporter sum-coverage /tmp/workspace/cc-coverage*.json &&\\\n ./cc-test-reporter upload-coverage" } } ] } } end def config { "version" => 2, "jobs" => jobs, "workflows" => { "version" => 2, "build_and_test" => { "jobs" => all_job_names << { "Report test coverage to Code Climate" => { "requires" => codeclimate_jobs.map { |args| job_name(*args) } } } } } } end end CircleCIConfig.generate('.circleci/config.yml') end