diff --git a/.circleci/config.yml b/.circleci/config.yml index e4e67d5..070ea93 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -26,10 +26,17 @@ jobs: docker: - image: circleci/ruby:2.7 environment: - HEROKU_TEST_STACK: << parameters.heroku-stack >> + PARALLEL_SPLIT_TEST_PROCESSES: 6 + # Hatchet Configuration (https://github.com/heroku/hatchet#env-vars) HATCHET_BUILDPACK_BASE: https://github.com/heroku/heroku-buildpack-gradle + HATCHET_BUILDPACK_BRANCH: << pipeline.git.branch >> HATCHET_APP_LIMIT: 100 - PARALLEL_SPLIT_TEST_PROCESSES: 8 + HATCHET_EXPENSIVE_MODE: 1 + HATCHET_RUN_MULTI: 1 + # Default stack for all Heroku apps created by Hatchet + DEFAULT_APP_STACK: << parameters.heroku-stack >> + # Default config variables for all Heroku apps created by Hatchet, prefixed with 'DEFAULT_APP_CONFIG_' + # DEFAULT_APP_CONFIG_FOO: "bar" steps: - checkout - heroku/install diff --git a/Gemfile b/Gemfile index 0dd811c..abe4216 100644 --- a/Gemfile +++ b/Gemfile @@ -4,3 +4,4 @@ gem 'heroku_hatchet' gem 'rspec-retry' gem 'rspec-expectations' gem 'parallel_split_test' +gem 'java-properties' diff --git a/Gemfile.lock b/Gemfile.lock index 06eb7db..dff1ef6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -15,6 +15,7 @@ GEM rrrretry (~> 1) thor (~> 1) threaded (~> 0) + java-properties (0.2.1) moneta (1.0.0) multi_json (1.15.0) parallel (1.19.2) @@ -50,6 +51,7 @@ PLATFORMS DEPENDENCIES heroku_hatchet + java-properties parallel_split_test rspec-expectations rspec-retry diff --git a/hatchet.json b/hatchet.json index 6803360..b56a6c4 100644 --- a/hatchet.json +++ b/hatchet.json @@ -1,6 +1,6 @@ { "hatchet": { - "directory": "spec/fixtures" + "directory": "test/spec/fixtures" }, "spring": [ "kissaten/spring-boot-gradle" diff --git a/hatchet.lock b/hatchet.lock index 88437e1..077273b 100644 --- a/hatchet.lock +++ b/hatchet.lock @@ -1,13 +1,13 @@ --- -- - spec/fixtures/repos/grails/grails3-example +- - test/spec/fixtures/repos/grails/grails3-example - c47a582e5b61dd069d17b7178697472d90fbc1bc -- - spec/fixtures/repos/kotlin/gradle-kotlin-dsl-sample +- - test/spec/fixtures/repos/kotlin/gradle-kotlin-dsl-sample - 57c0c86437ac17fdf8a416845eb8a34c014305bf -- - spec/fixtures/repos/kotlin/spring-boot-gradle-kotlin-dsl +- - test/spec/fixtures/repos/kotlin/spring-boot-gradle-kotlin-dsl - cd66c342c01377325eed141465586e473dc6e41f -- - spec/fixtures/repos/ratpack/example-ratpack-gradle-groovy-app +- - test/spec/fixtures/repos/ratpack/example-ratpack-gradle-groovy-app - 13c508d77f6ca910d4d1fd71586d3b1016a4faa0 -- - spec/fixtures/repos/ratpack/gradle-getting-started +- - test/spec/fixtures/repos/ratpack/gradle-getting-started - e73be20fda0ba4a0e5d972638acdb76eff1d66c2 -- - spec/fixtures/repos/spring/spring-boot-gradle +- - test/spec/fixtures/repos/spring/spring-boot-gradle - cc13b4b70fe49a8cae7c0ea6691dcf92d4a7b30e diff --git a/test/spec/gradle_spec.rb b/test/spec/gradle_spec.rb index e9ae868..646cbf2 100644 --- a/test/spec/gradle_spec.rb +++ b/test/spec/gradle_spec.rb @@ -1,25 +1,25 @@ require_relative 'spec_helper' -describe "Gradle" do - - before(:each) do - init_app(app) - end - - context "on JDK 8" do - let(:app) { Hatchet::Runner.new("gradle-getting-started") } - let(:jdk_version) { "1.8" } +describe "Gradle" do + context "on JDK #{DEFAULT_OPENJDK_VERSION}" do it "deploys successfully" do - app.deploy do |app| - expect(app.output).not_to include("Ratpack detected") - expect(app.output).to include("Spring Boot detected") - expect(app.output).not_to include("Spring Boot and Webapp Runner detected") - expect(app.output).to include("Building Gradle app") - expect(app.output).not_to include("executing ./gradlew stage") - expect(app.output).to include("executing ./gradlew build -x test") - expect(app.output).to include("BUILD SUCCESSFUL") + new_default_hatchet_runner("gradle-getting-started").tap do |app| + app.before_deploy do + set_java_version(DEFAULT_OPENJDK_VERSION) + end + + app.deploy do + expect(app.output).not_to include("Ratpack detected") + expect(app.output).to include("Spring Boot detected") + expect(app.output).not_to include("Spring Boot and Webapp Runner detected") + expect(app.output).to include("Building Gradle app") + expect(app.output).not_to include("executing ./gradlew stage") + expect(app.output).to include("executing ./gradlew build -x test") + expect(app.output).to include("BUILD SUCCESSFUL") + end end end end end + diff --git a/test/spec/grails_spec.rb b/test/spec/grails_spec.rb index c2dd5bd..7bea046 100644 --- a/test/spec/grails_spec.rb +++ b/test/spec/grails_spec.rb @@ -1,21 +1,20 @@ require_relative 'spec_helper' -describe "Grails" do - - before(:each) do - init_app(app) - end - - context "on JDK 8" do - let(:app) { Hatchet::Runner.new("grails3-example") } - let(:jdk_version) { "1.8" } +describe "Grails" do + context "on JDK #{DEFAULT_OPENJDK_VERSION}" do it "deploys successfully" do - app.deploy do |app| - expect(app.output).to include("Building Gradle app") - expect(app.output).to include("executing ./gradlew stage") - expect(app.output).to include("BUILD SUCCESSFUL") - expect(successful_body(app)).to include("Welcome to Grails") + new_default_hatchet_runner("grails3-example").tap do |app| + app.before_deploy do + set_java_version(DEFAULT_OPENJDK_VERSION) + end + + app.deploy do + expect(app.output).to include("Building Gradle app") + expect(app.output).to include("executing ./gradlew stage") + expect(app.output).to include("BUILD SUCCESSFUL") + expect(http_get(app)).to include("Welcome to Grails") + end end end end diff --git a/test/spec/kotlin_spec.rb b/test/spec/kotlin_spec.rb index 0415539..0215312 100644 --- a/test/spec/kotlin_spec.rb +++ b/test/spec/kotlin_spec.rb @@ -1,41 +1,42 @@ require_relative 'spec_helper' describe "Gradle" do - - before(:each) do - init_app(app) - end - - context "on JDK 8" do - let(:app) { Hatchet::Runner.new("gradle-kotlin-dsl-sample") } - let(:jdk_version) { "1.8" } - + context "on JDK #{DEFAULT_OPENJDK_VERSION}" do it "deploys successfully" do - app.deploy do |app| - expect(app.output).not_to include("Ratpack detected") - expect(app.output).not_to include("Spring Boot detected") - expect(app.output).not_to include("Spring Boot and Webapp Runner detected") - expect(app.output).to include("Building Gradle app") - expect(app.output).to include("executing ./gradlew stage") - expect(app.output).to include("BUILD SUCCESSFUL") - expect(successful_body(app)).to eq("Hello from Kotlin") + new_default_hatchet_runner("gradle-kotlin-dsl-sample").tap do |app| + app.before_deploy do + set_java_version(DEFAULT_OPENJDK_VERSION) + end + + app.deploy do + expect(app.output).not_to include("Ratpack detected") + expect(app.output).not_to include("Spring Boot detected") + expect(app.output).not_to include("Spring Boot and Webapp Runner detected") + expect(app.output).to include("Building Gradle app") + expect(app.output).to include("executing ./gradlew stage") + expect(app.output).to include("BUILD SUCCESSFUL") + expect(http_get(app)).to eq("Hello from Kotlin") + end end end end context "with Spring Boot" do - let(:app) { Hatchet::Runner.new("spring-boot-gradle-kotlin-dsl") } - let(:jdk_version) { "1.8" } - it "deploys successfully" do - app.deploy do |app| - expect(app.output).not_to include("Ratpack detected") - expect(app.output).not_to include("Spring Boot and Webapp Runner detected") - expect(app.output).to include("Spring Boot detected") - expect(app.output).to include("Building Gradle app") - expect(app.output).to include("executing ./gradlew build -x test") - expect(app.output).to include("BUILD SUCCESSFUL") - expect(successful_body(app)).to eq("Hello from Spring Boot") + new_default_hatchet_runner("spring-boot-gradle-kotlin-dsl").tap do |app| + app.before_deploy do + set_java_version(DEFAULT_OPENJDK_VERSION) + end + + app.deploy do + expect(app.output).not_to include("Ratpack detected") + expect(app.output).not_to include("Spring Boot and Webapp Runner detected") + expect(app.output).to include("Spring Boot detected") + expect(app.output).to include("Building Gradle app") + expect(app.output).to include("executing ./gradlew build -x test") + expect(app.output).to include("BUILD SUCCESSFUL") + expect(http_get(app)).to eq("Hello from Spring Boot") + end end end end diff --git a/test/spec/ratpack_spec.rb b/test/spec/ratpack_spec.rb index 3a98ccc..6a2227d 100644 --- a/test/spec/ratpack_spec.rb +++ b/test/spec/ratpack_spec.rb @@ -1,23 +1,22 @@ require_relative 'spec_helper' -describe "Ratpack" do - - before(:each) do - init_app(app) - end - - context "on JDK 8" do - let(:app) { Hatchet::Runner.new("example-ratpack-gradle-groovy-app") } - let(:jdk_version) { "1.8" } +describe "Ratpack" do + context "on JDK #{DEFAULT_OPENJDK_VERSION}" do it "deploys successfully" do - app.deploy do |app| - expect(app.output).to include("Ratpack detected") - expect(app.output).to include("Building Gradle app") - expect(app.output).to include("executing ./gradlew installDist -x test") - expect(app.output).not_to include(":test") - expect(app.output).to include("BUILD SUCCESSFUL") - expect(successful_body(app)).to include("Groovy Web Console") + new_default_hatchet_runner("example-ratpack-gradle-groovy-app").tap do |app| + app.before_deploy do + set_java_version(DEFAULT_OPENJDK_VERSION) + end + + app.deploy do + expect(app.output).to include("Ratpack detected") + expect(app.output).to include("Building Gradle app") + expect(app.output).to include("executing ./gradlew installDist -x test") + expect(app.output).not_to include(":test") + expect(app.output).to include("BUILD SUCCESSFUL") + expect(http_get(app)).to include("Groovy Web Console") + end end end end diff --git a/test/spec/spec_helper.rb b/test/spec/spec_helper.rb index eb20003..05d80e9 100644 --- a/test/spec/spec_helper.rb +++ b/test/spec/spec_helper.rb @@ -1,81 +1,64 @@ -require 'rspec/core' -require 'hatchet' -require 'fileutils' -require 'hatchet' -require 'rspec/retry' -require 'date' -require 'tmpdir' +require "rspec/core" +require "rspec/retry" +require "hatchet" +require "java-properties" -ENV['RACK_ENV'] = 'test' +DEFAULT_OPENJDK_VERSION="1.8" RSpec.configure do |config| - config.filter_run focused: true unless ENV['CI'] - config.run_all_when_everything_filtered = true - config.alias_example_to :fit, focused: true + config.fail_if_no_examples = true config.full_backtrace = true - config.verbose_retry = true # show retry status in spec process - config.default_retry_count = 2 if ENV['CI'] # retry all tests that fail again + # rspec-retry + config.verbose_retry = true + config.default_retry_count = 2 if ENV["CI"] +end + +def new_default_hatchet_runner(*args, **kwargs) + kwargs[:stack] ||= ENV["DEFAULT_APP_STACK"] + kwargs[:config] ||= {} - config.expect_with :rspec do |c| - c.syntax = :expect + ENV.keys.each do |key| + if key.start_with?("DEFAULT_APP_CONFIG_") + kwargs[:config][key.delete_prefix("DEFAULT_APP_CONFIG_")] ||= ENV[key] + end end - #config.mock_with :none + + Hatchet::Runner.new(*args, **kwargs) end -def git_repo - "https://github.com/heroku/heroku-buildpack-gradle.git" +def set_java_version(version_string) + set_system_properties_key("java.runtime.version", version_string) end -def init_app(app, stack="heroku-16") - app.setup! - app.platform_api.app.update(app.name, {"build_stack" => ENV["HEROKU_TEST_STACK"] || stack}) - unless ENV['JVM_COMMON_BUILDPACK'].nil? or ENV['JVM_COMMON_BUILDPACK'].empty? - app.set_config("JVM_COMMON_BUILDPACK" => ENV['JVM_COMMON_BUILDPACK']) - expect(app.get_config['JVM_COMMON_BUILDPACK']).to eq(ENV['JVM_COMMON_BUILDPACK']) - end +def set_maven_version(version_string) + set_system_properties_key("maven.version", version_string) end -def add_database(app, heroku) - Hatchet::RETRIES.times.retry do - heroku.post_addon(app.name, 'heroku-postgresql') - _, value = heroku.get_config_vars(app.name).body.detect {|key, value| key.match(/HEROKU_POSTGRESQL_[A-Z]+_URL/) } - heroku.put_config_vars(app.name, 'DATABASE_URL' => value) +def set_system_properties_key(key, value) + properties = {} + + if File.file?("system.properties") + properties = JavaProperties.load("system.properties") end -end -def successful_body(app, options = {}) - retry_limit = options[:retry_limit] || 50 - path = options[:path] ? "/#{options[:path]}" : '' - Excon.get("http://#{app.name}.herokuapp.com#{path}", :idempotent => true, :expects => 200, :retry_limit => retry_limit).body + properties[key.to_sym] = value + JavaProperties.write(properties, "system.properties") end -def create_file_with_size_in(size, dir) - name = File.join(dir, SecureRandom.hex(16)) - File.open(name, 'w') {|f| f.print([ 1 ].pack("C") * size) } - Pathname.new name +def write_to_procfile(content) + File.open("Procfile", "w") do |file| + file.write(content) + end end -def set_java_version(d, v) - Dir.chdir(d) do - File.open('system.properties', 'w') do |f| - f.puts "java.runtime.version=#{v}" - end - `git add system.properties` - `git commit -am "setting jdk version"` - end +def run(cmd) + out = `#{cmd}` + raise "Command #{cmd} failed with output #{out}" unless $?.success? + out end -def set_gradle_versions(gradle_version) - propsFile = "gradle/wrapper/gradle-wrapper.properties" - File.open(propsFile, 'w') do |f| - f.puts <<-EOF -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-#{gradle_version}-bin.zip -EOF - end - `git add #{propsFile}` - `git commit -m "setting gradle version"` +def http_get(app, options = {}) + retry_limit = options[:retry_limit] || 50 + path = options[:path] ? "/#{options[:path]}" : "" + Excon.get("https://#{app.name}.herokuapp.com#{path}", :idempotent => true, :expects => 200, :retry_limit => retry_limit).body end diff --git a/test/spec/spring_spec.rb b/test/spec/spring_spec.rb index 8f23692..e239934 100644 --- a/test/spec/spring_spec.rb +++ b/test/spec/spring_spec.rb @@ -1,35 +1,36 @@ require_relative 'spec_helper' -describe "Spring" do - before(:each) do - init_app(app) - end +describe "Spring" do + context "on JDK #{DEFAULT_OPENJDK_VERSION}" do + it "deploy twice" do + new_default_hatchet_runner("spring-boot-gradle").tap do |app| + app.before_deploy do + set_java_version(DEFAULT_OPENJDK_VERSION) + end - context "on JDK 8" do - let(:app) { Hatchet::Runner.new("spring-boot-gradle") } - let(:jdk_version) { "1.8" } + app.deploy do + expect(app.output).to include("Spring Boot detected") + expect(app.output).to include("Building Gradle app") + expect(app.output).to include("executing ./gradlew build -x test") + expect(app.output).to include("Downloading https://services.gradle.org/distributions/gradle-") + expect(app.output).not_to include(":test") + expect(app.output).to include("BUILD SUCCESSFUL") + expect(http_get(app)).to eq("Hello from Spring Boot") - it "deploy twice" do - app.deploy do |app| - expect(app.output).to include("Spring Boot detected") - expect(app.output).to include("Building Gradle app") - expect(app.output).to include("executing ./gradlew build -x test") - expect(app.output).to include("Downloading https://services.gradle.org/distributions/gradle-") - expect(app.output).not_to include(":test") - expect(app.output).to include("BUILD SUCCESSFUL") - expect(successful_body(app)).to eq("Hello from Spring Boot") + # make sure the cache has time to update + sleep 10 + app.commit! + app.push! - sleep 10 # make sure the cache has time to update - `git commit -am "redeploy" --allow-empty` - app.push! - expect(app.output).to include("Spring Boot detected") - expect(app.output).to include("Building Gradle app") - expect(app.output).to include("executing ./gradlew build -x test") - expect(app.output).not_to include("Downloading https://services.gradle.org/distributions/gradle-") - expect(app.output).not_to include(":test") - expect(app.output).to include("BUILD SUCCESSFUL") - expect(successful_body(app)).to eq("Hello from Spring Boot") + expect(app.output).to include("Spring Boot detected") + expect(app.output).to include("Building Gradle app") + expect(app.output).to include("executing ./gradlew build -x test") + expect(app.output).not_to include("Downloading https://services.gradle.org/distributions/gradle-") + expect(app.output).not_to include(":test") + expect(app.output).to include("BUILD SUCCESSFUL") + expect(http_get(app)).to eq("Hello from Spring Boot") + end end end end