diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e4d81ccf3509820a0c4fbd133c9e19f7bc4beffb..fc1e43fcd4489dbd133dbe72b3b8559ac4efaade 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,7 @@ image: "ruby:2.1" services: - mysql:latest - - redis:latest + - redis:alpine cache: key: "ruby21" @@ -13,234 +13,199 @@ variables: MYSQL_ALLOW_EMPTY_PASSWORD: "1" # retry tests only in CI environment RSPEC_RETRY_RETRY_COUNT: "3" + RAILS_ENV: "test" + SIMPLECOV: "true" + USE_DB: "true" + USE_BUNDLE_INSTALL: "true" before_script: - source ./scripts/prepare_build.sh - - ruby -v - - which ruby - - retry gem install bundler --no-ri --no-rdoc - cp config/gitlab.yml.example config/gitlab.yml - - touch log/application.log - - touch log/test.log - - retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}" - - RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load db:migrate + - bundle --version + - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"' + - retry gem install knapsack + - '[ "$USE_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate' stages: +- prepare - test -- notifications +- post-test -spec:feature: - stage: test - script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature - -spec:api: - stage: test - script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api - -spec:models: - stage: test - script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models - -spec:lib: - stage: test - script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib - -spec:services: - stage: test - script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services - -spec:other: - stage: test - script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other - -spinach:project:half: - stage: test - script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half - -spinach:project:rest: - stage: test - script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest - -spinach:other: - stage: test - script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other - -teaspoon: - stage: test - script: - - RAILS_ENV=test bundle exec teaspoon - -rubocop: - stage: test - script: - - bundle exec rubocop - -scss-lint: - stage: test - script: - - bundle exec rake scss_lint - -license-finder: - stage: test - script: - - bundle exec license_finder - -brakeman: - stage: test - script: - - bundle exec rake brakeman - -flog: - stage: test - script: - - bundle exec rake flog - -flay: - stage: test - script: - - bundle exec rake flay - -bundler:audit: - stage: test - only: - - master - script: - - "bundle exec bundle-audit check --update --ignore OSVDB-115941" - -db-migrate-reset: - stage: test - script: - - RAILS_ENV=test bundle exec rake db:migrate:reset +# Prepare and merge knapsack tests -# Ruby 2.2 jobs - -spec:feature:ruby22: - stage: test - image: ruby:2.2 - only: - - master - script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature +.knapsack-state: &knapsack-state + services: [] + variables: + USE_DB: "false" + USE_BUNDLE_INSTALL: "false" cache: - key: "ruby22" + key: "knapsack" paths: - - vendor - -spec:api:ruby22: - stage: test - image: ruby:2.2 - only: - - master - script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api - cache: - key: "ruby22" + - knapsack/ + artifacts: paths: - - vendor + - knapsack/ -spec:models:ruby22: - stage: test - image: ruby:2.2 - only: - - master +knapsack: + <<: *knapsack-state + stage: prepare script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models - cache: - key: "ruby22" - paths: - - vendor + - mkdir -p knapsack/ + - '[[ -f knapsack/rspec_report.json ]] || echo "{}" > knapsack/rspec_report.json' + - '[[ -f knapsack/spinach_report.json ]] || echo "{}" > knapsack/spinach_report.json' -spec:lib:ruby22: - stage: test - image: ruby:2.2 - only: - - master +update-knapsack: + <<: *knapsack-state + stage: post-test script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib - cache: - key: "ruby22" - paths: - - vendor + - scripts/merge-reports knapsack/rspec_report.json knapsack/rspec_node_*.json + - scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json + - rm -f knapsack/*_node_*.json -spec:services:ruby22: - stage: test - image: ruby:2.2 - only: - - master - script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services - cache: - key: "ruby22" - paths: - - vendor +# Execute all testing suites -spec:other:ruby22: +.rspec-knapsack: &rspec-knapsack stage: test - image: ruby:2.2 - only: - - master script: - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other - cache: - key: "ruby22" + - bundle exec rake assets:precompile 2>/dev/null + - JOB_NAME=( $CI_BUILD_NAME ) + - export CI_NODE_INDEX=${JOB_NAME[1]} + - export CI_NODE_TOTAL=${JOB_NAME[2]} + - export KNAPSACK_REPORT_PATH=knapsack/rspec_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json + - export KNAPSACK_GENERATE_REPORT=true + - cp knapsack/rspec_report.json ${KNAPSACK_REPORT_PATH} + - knapsack rspec + artifacts: paths: - - vendor - -spinach:project:half:ruby22: - stage: test - image: ruby:2.2 - only: - - master - script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half - cache: - key: "ruby22" + - knapsack/ + +.spinach-knapsack: &spinach-knapsack + stage: test + script: + - bundle exec rake assets:precompile 2>/dev/null + - JOB_NAME=( $CI_BUILD_NAME ) + - export CI_NODE_INDEX=${JOB_NAME[1]} + - export CI_NODE_TOTAL=${JOB_NAME[2]} + - export KNAPSACK_REPORT_PATH=knapsack/spinach_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json + - export KNAPSACK_GENERATE_REPORT=true + - cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH} + - knapsack spinach "-r rerun" + # retry failed tests 3 times + - retry '[ ! -e tmp/spinach-rerun.txt ] || bin/spinach -r rerun $(cat tmp/spinach-rerun.txt)' + artifacts: paths: - - vendor - -spinach:project:rest:ruby22: - stage: test - image: ruby:2.2 + - knapsack/ + +rspec 0 20: *rspec-knapsack +rspec 1 20: *rspec-knapsack +rspec 2 20: *rspec-knapsack +rspec 3 20: *rspec-knapsack +rspec 4 20: *rspec-knapsack +rspec 5 20: *rspec-knapsack +rspec 6 20: *rspec-knapsack +rspec 7 20: *rspec-knapsack +rspec 8 20: *rspec-knapsack +rspec 9 20: *rspec-knapsack +rspec 10 20: *rspec-knapsack +rspec 11 20: *rspec-knapsack +rspec 12 20: *rspec-knapsack +rspec 13 20: *rspec-knapsack +rspec 14 20: *rspec-knapsack +rspec 15 20: *rspec-knapsack +rspec 16 20: *rspec-knapsack +rspec 17 20: *rspec-knapsack +rspec 18 20: *rspec-knapsack +rspec 19 20: *rspec-knapsack + +spinach 0 10: *spinach-knapsack +spinach 1 10: *spinach-knapsack +spinach 2 10: *spinach-knapsack +spinach 3 10: *spinach-knapsack +spinach 4 10: *spinach-knapsack +spinach 5 10: *spinach-knapsack +spinach 6 10: *spinach-knapsack +spinach 7 10: *spinach-knapsack +spinach 8 10: *spinach-knapsack +spinach 9 10: *spinach-knapsack + +# Execute all testing suites against Ruby 2.2 + +.ruby-22: &ruby-22 + image: "ruby:2.2" only: - - master - script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest + - master cache: key: "ruby22" paths: - vendor -spinach:other:ruby22: +.rspec-knapsack-ruby22: &rspec-knapsack-ruby22 + <<: *rspec-knapsack + <<: *ruby-22 + +.spinach-knapsack-ruby22: &spinach-knapsack-ruby22 + <<: *rspec-knapsack + <<: *ruby-22 + +rspec 0 20 ruby22: *rspec-knapsack-ruby22 +rspec 1 20 ruby22: *rspec-knapsack-ruby22 +rspec 2 20 ruby22: *rspec-knapsack-ruby22 +rspec 3 20 ruby22: *rspec-knapsack-ruby22 +rspec 4 20 ruby22: *rspec-knapsack-ruby22 +rspec 5 20 ruby22: *rspec-knapsack-ruby22 +rspec 6 20 ruby22: *rspec-knapsack-ruby22 +rspec 7 20 ruby22: *rspec-knapsack-ruby22 +rspec 8 20 ruby22: *rspec-knapsack-ruby22 +rspec 9 20 ruby22: *rspec-knapsack-ruby22 +rspec 10 20 ruby22: *rspec-knapsack-ruby22 +rspec 11 20 ruby22: *rspec-knapsack-ruby22 +rspec 12 20 ruby22: *rspec-knapsack-ruby22 +rspec 13 20 ruby22: *rspec-knapsack-ruby22 +rspec 14 20 ruby22: *rspec-knapsack-ruby22 +rspec 15 20 ruby22: *rspec-knapsack-ruby22 +rspec 16 20 ruby22: *rspec-knapsack-ruby22 +rspec 17 20 ruby22: *rspec-knapsack-ruby22 +rspec 18 20 ruby22: *rspec-knapsack-ruby22 +rspec 19 20 ruby22: *rspec-knapsack-ruby22 + +spinach 0 10 ruby22: *spinach-knapsack-ruby22 +spinach 1 10 ruby22: *spinach-knapsack-ruby22 +spinach 2 10 ruby22: *spinach-knapsack-ruby22 +spinach 3 10 ruby22: *spinach-knapsack-ruby22 +spinach 4 10 ruby22: *spinach-knapsack-ruby22 +spinach 5 10 ruby22: *spinach-knapsack-ruby22 +spinach 6 10 ruby22: *spinach-knapsack-ruby22 +spinach 7 10 ruby22: *spinach-knapsack-ruby22 +spinach 8 10 ruby22: *spinach-knapsack-ruby22 +spinach 9 10 ruby22: *spinach-knapsack-ruby22 + +# Other generic tests + +.exec: &exec + stage: test + script: + - bundle exec $CI_BUILD_NAME + +teaspoon: *exec +rubocop: *exec +rake scss_lint: *exec +rake brakeman: *exec +rake flog: *exec +rake flay: *exec +rake db:migrate:reset: *exec +license_finder: *exec + +bundler:audit: stage: test - image: ruby:2.2 only: - - master + - master script: - - RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null - - RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other - cache: - key: "ruby22" - paths: - - vendor + - "bundle exec bundle-audit check --update --ignore OSVDB-115941" + +# Notify slack in the end notify:slack: - stage: notifications + stage: post-test script: - ./scripts/notify_slack.sh "#builds" "Build on \`$CI_BUILD_REF_NAME\` failed! Commit \`$(git log -1 --oneline)\` See <https://gitlab.com/gitlab-org/$(basename "$PWD")/commit/"$CI_BUILD_REF"/builds>" when: on_failure diff --git a/Gemfile b/Gemfile index 9af2ac8a9c17a4833e2ee461729a0560c043ab44..482a6c18dd721e8f703c3bfce6033db72626de02 100644 --- a/Gemfile +++ b/Gemfile @@ -316,6 +316,7 @@ group :test do gem 'webmock', '~> 1.21.0' gem 'test_after_commit', '~> 0.4.2' gem 'sham_rack' + gem 'knapsack' end group :production do diff --git a/Gemfile.lock b/Gemfile.lock index 0eab33ec5ca401c043cfba08bd5b09deae7ed25a..c85f9be77839e1d1819574252c770f50edd5d0c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -358,6 +358,9 @@ GEM actionpack (>= 3.0.0) activesupport (>= 3.0.0) kgio (2.10.0) + knapsack (1.11.0) + rake + timecop (>= 0.1.0) launchy (2.4.3) addressable (~> 2.3) letter_opener (1.4.1) @@ -735,6 +738,7 @@ GEM thor (0.19.1) thread_safe (0.3.5) tilt (2.0.2) + timecop (0.8.1) timfel-krb5-auth (0.8.3) tinder (1.10.1) eventmachine (~> 1.0) @@ -882,6 +886,7 @@ DEPENDENCIES jquery-ui-rails (~> 5.0.0) jwt kaminari (~> 0.17.0) + knapsack letter_opener_web (~> 1.3.0) license_finder licensee (~> 8.0.0) diff --git a/Rakefile b/Rakefile index 5dd389d5678e1e7aeb90b4c879d1dbe150b96b40..16261bf8ae20aeefb968c87e7a9245edcd1c6786 100755 --- a/Rakefile +++ b/Rakefile @@ -3,8 +3,11 @@ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path('../config/application', __FILE__) +require 'knapsack' relative_url_conf = File.expand_path('../config/initializers/relative_url', __FILE__) require relative_url_conf if File.exist?("#{relative_url_conf}.rb") Gitlab::Application.load_tasks + +Knapsack.load_tasks diff --git a/features/support/env.rb b/features/support/env.rb index 357d164d87f73d0af44146f10f4d6c327222feab..4552db8ad7783fa6df836a104b37fad132485a52 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -11,11 +11,14 @@ ENV['RAILS_ENV'] = 'test' require './config/environment' require 'rspec/expectations' require 'sidekiq/testing/inline' +require 'knapsack' require_relative 'capybara' require_relative 'db_cleaner' require_relative 'rerun' +Knapsack::Adapters::SpinachAdapter.bind + %w(select2_helper test_env repo_helpers).each do |f| require Rails.root.join('spec', 'support', f) end diff --git a/scripts/merge-reports b/scripts/merge-reports new file mode 100755 index 0000000000000000000000000000000000000000..f7b574001acb1712c32a00dd50454e5bf0069818 --- /dev/null +++ b/scripts/merge-reports @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby + +require 'json' +require 'yaml' + +main_report_file = ARGV.shift +unless main_report_file + puts 'usage: merge_reports <main-report> [extra reports...]' + exit 1 +end + +puts "Loading #{main_report_file}..." +main_report = JSON.parse(File.read(main_report_file)) +new_report = main_report.dup + +ARGV.each do |report_file| + report = JSON.parse(File.read(report_file)) + + # Remove existing values + updates = report.delete_if do |key, value| + main_report[key] && main_report[key] == value + end + new_report.merge!(updates) + + puts "Merged #{report_file} adding #{updates.size} results." +end + +File.write(main_report_file, JSON.pretty_generate(new_report)) +puts "Saved #{main_report_file}." diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh index 247383aa46c6423486d9f864b6908a24129b27e1..d6fb1a34e8c35dc7c00a53b04d4e068f09f4ea99 100755 --- a/scripts/prepare_build.sh +++ b/scripts/prepare_build.sh @@ -1,12 +1,16 @@ #!/bin/bash retry() { - for i in $(seq 1 3); do + if eval "$@"; then + return 0 + fi + + for i in 2 1; do + sleep 3s + echo "Retrying $i..." if eval "$@"; then return 0 fi - sleep 3s - echo "Retrying..." done return 1 } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 576d16e7ea33fe7d2a652f709ca3e67ae4b1e100..a20f4c05971cb741b01fb5828287d69fe5fec90d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -15,6 +15,9 @@ require 'rspec/rails' require 'shoulda/matchers' require 'sidekiq/testing/inline' require 'rspec/retry' +require 'knapsack' + +Knapsack::Adapters::RSpecAdapter.bind # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories.