Commit cb4d67f0 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'alberts-mr-pipeline-failures' into 'master'

Add rake task to run RSpec on tests that failed in merge request

See merge request gitlab-org/gitlab!58569
parents ef0d9da0 28e435fe
......@@ -398,6 +398,8 @@ group :development, :test do
gem 'parallel', '~> 1.19', require: false
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
gem 'test_file_finder', '~> 0.1.3'
end
group :development, :test, :danger do
......
......@@ -1233,6 +1233,8 @@ GEM
terser (1.0.2)
execjs (>= 0.3.0, < 3)
test-prof (0.12.0)
test_file_finder (0.1.3)
faraday (~> 1.0.1)
text (1.3.1)
thin (1.8.0)
daemons (~> 1.0, >= 1.0.9)
......@@ -1601,6 +1603,7 @@ DEPENDENCIES
sys-filesystem (~> 1.1.6)
terser (= 1.0.2)
test-prof (~> 0.12.0)
test_file_finder (~> 0.1.3)
thin (~> 1.8.0)
thrift (>= 0.14.0)
timecop (~> 0.9.1)
......
......@@ -152,6 +152,24 @@ To run several tests inside one directory:
- `bin/rspec spec/requests/api/` for the RSpec tests if you want to test API only
### Run RSpec tests which failed in Merge Request pipeline on your machine
If your Merge Request pipeline failed with RSpec test failures,
you can run all the failed tests on your machine with the following Rake task:
```shell
bin/rake spec:merge_request_rspec_failure
```
There are a few caveats for this Rake task:
- You need to be on the same branch on your machine as the source branch of the Merge Request.
- The pipeline must have been completed.
- You may need to wait for the test report to be parsed and retry again.
This Rake task depends on the [unit test reports](../ci/unit_test_reports.md) feature,
which only gets parsed when it is requested for the first time.
### Speed up tests, Rake tasks, and migrations
[Spring](https://github.com/rails/spring) is a Rails application pre-loader. It
......
......@@ -2,6 +2,8 @@
return if Rails.env.production?
require_relative '../../tooling/merge_request_rspec_failure_rake_task'
namespace :spec do
desc 'GitLab | RSpec | Run unit tests'
RSpec::Core::RakeTask.new(:unit, :rspec_opts) do |t, args|
......@@ -24,11 +26,19 @@ namespace :spec do
t.rspec_opts = args[:rspec_opts]
end
desc 'GitLab | RSpec | Run merge request RSpec failures'
Tooling::MergeRequestRspecFailureRakeTask.new(:merge_request_rspec_failure, :rspec_opts) do |t, args|
t.pattern = t.rspec_failures_on_merge_request
t.rspec_opts = args[:rspec_opts]
end
desc 'Run the code examples in spec/requests/api'
RSpec::Core::RakeTask.new(:api) do |t|
t.pattern = 'spec/requests/api/**/*_spec.rb'
end
private
def require_test_level
require_relative '../../tooling/quality/test_level'
end
......
# frozen_string_literal: true
require 'webmock/rspec'
require_relative '../../tooling/merge_request'
require_relative '../support/helpers/next_instance_of'
RSpec.describe Tooling::MergeRequest do
let(:project_path) { 'gitlab-org/gitlab' }
let(:branch_name) { 'my-branch' }
let(:merge_request_iid) { 123 }
let(:merge_requests) { [{ 'iid' => merge_request_iid }] }
describe '.for' do
let(:stub_api) do
stub_request(:get, "https://gitlab.com/api/v4/projects/gitlab-org%2Fgitlab/merge_requests")
.and_return(body: merge_requests)
end
before do
stub_api.with(query: { source_branch: branch_name, order_by: 'updated_at', sort: 'desc' })
end
it 'fetches merge request for local branch in the given GitLab project path' do
merge_request = described_class.for(branch: branch_name, project_path: project_path)
expect(merge_request.iid).to eq(merge_request_iid)
expect(stub_api).to have_been_requested.once
end
end
end
# frozen_string_literal: true
require 'faraday'
require 'faraday_middleware'
module Tooling
class MergeRequest
GITLAB_API_URL_TEMPLATE = 'https://gitlab.com/api/v4/projects/%{project_path}/merge_requests'
def self.for(branch:, project_path:)
url = format(GITLAB_API_URL_TEMPLATE, { project_path: URI.encode_www_form_component(project_path) })
conn = Faraday.new(url) do |conn|
conn.request :json
conn.response :json, content_type: /\bjson$/
conn.adapter Faraday.default_adapter
end
response = conn.get do |req|
req.params[:source_branch] = branch
req.params[:order_by] = 'updated_at'
req.params[:sort] = 'desc'
end
new(response.body.first)
end
attr_reader :merge_request
def initialize(merge_request)
@merge_request = merge_request
end
def iid
merge_request['iid']
end
end
end
# frozen_string_literal: true
require 'test_file_finder'
require_relative './merge_request'
module Tooling
class MergeRequestRspecFailureRakeTask < RSpec::Core::RakeTask
PROJECT_PATH = 'gitlab-org/gitlab'
def run_task(_verbose)
if pattern.empty?
puts "No rspec failures in the merge request."
return
end
super
end
def rspec_failures_on_merge_request
test_file_finder = TestFileFinder::FileFinder.new
test_file_finder.use TestFileFinder::MappingStrategies::GitlabMergeRequestRspecFailure.new(project_path: PROJECT_PATH, merge_request_iid: merge_request.iid)
test_file_finder.test_files
rescue TestFileFinder::TestReportError => e
abort e.message
end
private
def merge_request
@merge_request ||= Tooling::MergeRequest.for(branch: current_branch, project_path: PROJECT_PATH)
end
def current_branch
@current_branch ||= `git branch --show-current`.strip
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment