Add new file crystalball predictor to enqueue complete re-run
closes OUT-4922 Test-plan: - Get a copy of crystalball_map.yml, copy it to canvas root - Available via #crystalball-noisy - Look at a file that has changes under a given spec - make changes to it, and add it to a new commit - verify via crystalball dry-run that specs are predicted and printed out to crystalball_spec_list.txt - create a new .rb file - run crystalball dry-run again and verify that the output warns about a "new file detected" and that the dry-run produces only a "." in the crystalball_spec_list.txt file Change-Id: Ia2a5754c02814d681f1d375f5bc7357774b08926 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/281613 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Manoel Quirino <manoel.quirino@instructure.com> Reviewed-by: Michael Hargiss <mhargiss@instructure.com> QA-Review: Michael Hargiss <mhargiss@instructure.com> Product-Review: Brian Watson <bwatson@instructure.com>
This commit is contained in:
parent
2bdee31fa0
commit
f87e9e352d
|
@ -5,7 +5,7 @@ execution_map_path: './crystalball_map.yml'
|
|||
# examples_limit: 1
|
||||
#
|
||||
# Custom prediction builder class to use. Default: 'Crystalball::RSpec::StandardPredictionBuilder'
|
||||
prediction_builder_class_name: 'Crystalball::RSpec::StandardPredictionBuilder'
|
||||
prediction_builder_class_name: 'Crystalball::RSpec::CanvasPredictionBuilder'
|
||||
# #
|
||||
# Set of requires. Usually used to require custom predictor class file. Default: []
|
||||
requires:
|
||||
|
|
|
@ -22,6 +22,9 @@ require "crystalball/rspec/prediction_builder"
|
|||
require "crystalball/rspec/filtering"
|
||||
require "crystalball/rspec/prediction_pruning"
|
||||
|
||||
require "crystalball/predictor/strategy"
|
||||
require "crystalball/predictor/helpers/affected_example_groups_detector"
|
||||
|
||||
module Crystalball
|
||||
module RSpec
|
||||
# Our custom RSpec runner to generate and save predictions to a file, i.e. "dry-run"
|
||||
|
@ -127,6 +130,73 @@ module Crystalball
|
|||
@options.configure(@configuration)
|
||||
end
|
||||
end
|
||||
|
||||
class CanvasPredictionBuilder < Crystalball::RSpec::PredictionBuilder
|
||||
def predictor
|
||||
super do |p|
|
||||
p.use Crystalball::Predictor::ModifiedSpecs.new
|
||||
p.use Crystalball::Predictor::ModifiedExecutionPaths.new
|
||||
p.use Crystalball::Predictor::NewFiles.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Predictor
|
||||
# Queues a total re-run if any files are added. If no new files, don't add any predictions
|
||||
# Possible git operation types for SourceDiff include: ['new', 'modified', 'moved', 'deleted]
|
||||
class NewFiles
|
||||
include Helpers::AffectedExampleGroupsDetector
|
||||
include Strategy
|
||||
|
||||
# @param [Crystalball::SourceDiff] diff - the diff from which to predict
|
||||
# which specs should run
|
||||
# @param [Crystalball::ExampleGroupMap] map - the map with the relations of
|
||||
# examples and used files
|
||||
# @return [Array<String>] the spec paths associated with the changes
|
||||
def call(diff, map)
|
||||
super do
|
||||
file_change_types = diff.map { |source_diff| [source_diff.relative_path, source_diff.type] }
|
||||
# Create a map of git operations to files
|
||||
# Hash["new"] = ["new_file1.rb", "new_file2.rb"]
|
||||
# Hash["modified"] = ["modified_file1.rb", "modified_file2.rb"]
|
||||
# etc...
|
||||
new_files = file_change_types.each_with_object(Hash.new { |h, k| h[k] = [] }) do |arr, change_map|
|
||||
change_path = arr[0]
|
||||
change_type = arr[1]
|
||||
change_map[change_type] << change_path
|
||||
end
|
||||
if new_files["new"].count.positive?
|
||||
Crystalball.log :warn, "Crystalball detected new .git files: #{new_files["new"]}"
|
||||
Crystalball.log :warn, "Crystalball requesting entire suite re-run"
|
||||
["."]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Override prediction mechanism based on NewFiles predictor. If we requeue an entire suite re-run
|
||||
# ENV["CRYSTALBALL_TEST_SUITE_ROOT"] should point to the root of selenium specs or whatever is deemed
|
||||
# relevant for a "complete crystalball-predicted run"
|
||||
class Predictor
|
||||
# @return [Crystalball::Prediction] list of examples which may fail
|
||||
def prediction
|
||||
root_suite_path = ENV["CRYSTALBALL_TEST_SUITE_ROOT"] || "."
|
||||
raw_prediction = raw_prediction(diff)
|
||||
prediction_list = includes_root?(raw_prediction) ? [root_suite_path] : raw_prediction
|
||||
Prediction.new(filter(prediction_list))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def includes_root?(prediction_list)
|
||||
prediction_list.include?(".") ||
|
||||
prediction_list.include?("./.") ||
|
||||
prediction_list.include?(ENV["CRYSTALBALL_TEST_SUITE_ROOT"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue