107 lines
3.5 KiB
Text
107 lines
3.5 KiB
Text
|
#!/usr/bin/env ruby
|
||
|
# frozen_string_literal: true
|
||
|
|
||
|
require 'optparse'
|
||
|
|
||
|
# This script returns end-to-end tests or test directories. The returned value is stored in QA_TESTS
|
||
|
# variable for executing only those tests.
|
||
|
|
||
|
class DetermineQATests # rubocop:disable Gitlab/NamespacedClass
|
||
|
def initialize(options)
|
||
|
@changed_files = options.delete(:changed_files)
|
||
|
@mr_labels = options.delete(:mr_labels) || []
|
||
|
end
|
||
|
|
||
|
def execute
|
||
|
# If only e2e test files have changed, run only those tests
|
||
|
qa_tests = if has_qa_spec_only_changes?
|
||
|
changed_files
|
||
|
|
||
|
# If only non qa files have changed, use the devops MR label to run the files in the related directory
|
||
|
# However, if a feature flag file has changed, do not return any specific test/test directory
|
||
|
elsif has_non_qa_only_changes? && mr_labels.any? && !has_dev_ops_feature_flag_changes?
|
||
|
devops_stage = devops_stage_from_mr_labels
|
||
|
|
||
|
qa_spec_directories_for_devops_stage(devops_stage) if devops_stage
|
||
|
end
|
||
|
|
||
|
trim_path(qa_tests).join(' ') if qa_tests
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
attr_reader :changed_files, :mr_labels
|
||
|
|
||
|
# Are the changed files only qa specs?
|
||
|
#
|
||
|
# @return [Boolean] whether the changes files are only qa specs
|
||
|
def has_qa_spec_only_changes?
|
||
|
changed_files.all? { |file_path| file_path =~ %r{^qa/qa/specs/features/} }
|
||
|
end
|
||
|
|
||
|
# Are the changed files only outside the qa directory?
|
||
|
#
|
||
|
# @return [Boolean] whether the changes files are outside of qa directory
|
||
|
def has_non_qa_only_changes?
|
||
|
changed_files.none? { |file_path| file_path =~ %r{^qa/} }
|
||
|
end
|
||
|
|
||
|
# Are the changed files for development and ops feature flags?
|
||
|
#
|
||
|
# @return [Boolean] whether the changes files are for development and ops feature flags
|
||
|
def has_dev_ops_feature_flag_changes?
|
||
|
changed_files.any? { |file_path| file_path =~ %r{/feature_flags/(development|ops)/.*\.yml} }
|
||
|
end
|
||
|
|
||
|
# Remove the leading `qa/` from the file or directory paths
|
||
|
#
|
||
|
# @param [Array] paths Array of file or directory paths
|
||
|
# @return [Array] Array of files or directories with the first occurance of `qa/` removed
|
||
|
def trim_path(paths)
|
||
|
paths.map { |path| path.delete_prefix("qa/") }
|
||
|
end
|
||
|
|
||
|
# Extract devops stage from MR labels
|
||
|
#
|
||
|
# @return [String] a devops stage
|
||
|
def devops_stage_from_mr_labels
|
||
|
mr_labels.find { |label| label =~ /^devops::/ }&.delete_prefix('devops::')
|
||
|
end
|
||
|
|
||
|
# Get qa spec directories for devops stage
|
||
|
#
|
||
|
# @param [String] devops_stage a devops stage
|
||
|
# @return [Array] qa spec directories
|
||
|
def qa_spec_directories_for_devops_stage(devops_stage)
|
||
|
Dir.glob("qa/qa/specs/**/*/").select { |dir| dir =~ %r{\d+_#{devops_stage}/$} }
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if $0 == __FILE__
|
||
|
options = {}
|
||
|
|
||
|
OptionParser.new do |opts|
|
||
|
opts.on("-f", "--files CHANGED_FILES_PATH", String,
|
||
|
"A path to a file containing a list of changed files") do |value|
|
||
|
changed_files_path = value
|
||
|
abort("ERROR: The specified changed files path does not exist") unless File.exist?(changed_files_path)
|
||
|
|
||
|
changed_files = File.read(changed_files_path).split(' ')
|
||
|
abort("ERROR: There are no changed files") if changed_files.empty?
|
||
|
|
||
|
options[:changed_files] = changed_files
|
||
|
end
|
||
|
|
||
|
opts.on("-l", "--labels MR_LABELS", String, "A comma separated list of MR labels") do |value|
|
||
|
options[:mr_labels] = Array(value&.split(',')).compact
|
||
|
end
|
||
|
|
||
|
opts.on("-h", "--help", "Prints this help") do
|
||
|
puts opts
|
||
|
exit
|
||
|
end
|
||
|
end.parse!
|
||
|
|
||
|
puts DetermineQATests.new(options).execute
|
||
|
end
|