217 lines
7.5 KiB
Ruby
217 lines
7.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'fast_spec_helper'
|
|
require_relative '../../../tooling/ci/changed_files'
|
|
|
|
RSpec.describe CI::ChangedFiles, feature_category: :tooling do
|
|
let(:instance) { described_class.new }
|
|
|
|
describe '#should_run_checks_for_changed_files' do
|
|
# The mock values are based on allowed values from the docs
|
|
# https://docs.gitlab.com/ci/variables/predefined_variables/
|
|
let(:pipeline_source) { 'merge_request_event' }
|
|
let(:merge_request_event_type) { 'merged_result' }
|
|
let(:commit_ref_name) { 'feature-branch' }
|
|
|
|
before do
|
|
stub_env('CI_PIPELINE_SOURCE', pipeline_source)
|
|
stub_env('CI_MERGE_REQUEST_EVENT_TYPE', merge_request_event_type)
|
|
stub_env('CI_COMMIT_REF_NAME', commit_ref_name)
|
|
end
|
|
|
|
context 'when in a valid merge request environment' do
|
|
it 'returns true when no tier labels exist' do
|
|
stub_env('CI_MERGE_REQUEST_LABELS', nil)
|
|
expect(instance.should_run_checks_for_changed_files).to be true
|
|
end
|
|
|
|
it 'returns true when tier-1 label exists' do
|
|
stub_env('CI_MERGE_REQUEST_LABELS', 'pipeline::tier-1,other-label')
|
|
expect(instance.should_run_checks_for_changed_files).to be true
|
|
end
|
|
|
|
it 'returns false when other tier label exists' do
|
|
stub_env('CI_MERGE_REQUEST_LABELS', 'pipeline::tier-2,other-label')
|
|
expect(instance.should_run_checks_for_changed_files).to be false
|
|
end
|
|
end
|
|
|
|
context 'when not in a valid merge request environment' do
|
|
context 'when the merge request event type is merge_train' do
|
|
let(:merge_request_event_type) { 'merge_train' }
|
|
|
|
it 'returns false' do
|
|
expect(instance.should_run_checks_for_changed_files).to be false
|
|
end
|
|
end
|
|
|
|
context 'when the pipeline source is not merged_request_event' do
|
|
let(:pipeline_source) { 'push' }
|
|
|
|
it 'returns false when pipeline source is push' do
|
|
expect(instance.should_run_checks_for_changed_files).to be false
|
|
end
|
|
end
|
|
|
|
context 'when the current branch is CI_DEFAULT_BRANCH' do
|
|
let(:commit_ref_name) { 'master' }
|
|
|
|
it 'returns false' do
|
|
stub_env('CI_DEFAULT_BRANCH', 'master')
|
|
expect(instance.should_run_checks_for_changed_files).to be false
|
|
end
|
|
end
|
|
|
|
context 'when the environment variables are not set' do
|
|
let(:pipeline_source) { nil }
|
|
let(:merge_request_event_type) { nil }
|
|
let(:commit_ref_name) { nil }
|
|
|
|
it 'returns false' do
|
|
expect(instance.should_run_checks_for_changed_files).to be false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#get_changed_files_in_merged_results_pipeline' do
|
|
let(:git_diff_output) { "file1.js\nfile2.rb\nfile3.vue" }
|
|
|
|
before do
|
|
allow(instance).to receive(:`)
|
|
.with('git diff --name-only --diff-filter=d HEAD~..HEAD')
|
|
.and_return(git_diff_output)
|
|
end
|
|
|
|
context 'when git diff is run in a merged results pipeline' do
|
|
it 'returns an array when there are changed files' do
|
|
expect(instance.get_changed_files_in_merged_results_pipeline)
|
|
.to match_array(['file1.js', 'file2.rb', 'file3.vue'])
|
|
end
|
|
|
|
context "when there are no changed files" do
|
|
let(:git_diff_output) { "" }
|
|
|
|
it 'returns an empty array' do
|
|
expect(instance.get_changed_files_in_merged_results_pipeline).to eq([])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#filter_and_get_changed_files_in_mr' do
|
|
context 'when checks should run for changed files' do \
|
|
let(:changed_files_output) { ['file1.js', 'file2.rb', 'file3.vue'] }
|
|
|
|
before do
|
|
allow(instance).to receive_messages(
|
|
should_run_checks_for_changed_files: true,
|
|
get_changed_files_in_merged_results_pipeline: changed_files_output
|
|
)
|
|
end
|
|
|
|
context 'when changed files exist' do
|
|
it 'returns filtered files' do
|
|
expect(instance.filter_and_get_changed_files_in_mr(filter_pattern: /\.(js|vue)$/))
|
|
.to match_array(['file1.js', 'file3.vue'])
|
|
end
|
|
|
|
it 'returns all files when filter is empty' do
|
|
expect(instance.filter_and_get_changed_files_in_mr)
|
|
.to match_array(changed_files_output)
|
|
end
|
|
|
|
it 'returns empty array and prints warning when no files match filter' do
|
|
allow(instance).to receive(:get_changed_files_in_merged_results_pipeline).and_return(['file1.txt',
|
|
'file2.rb'])
|
|
expect(instance).to receive(:puts).with('No files were changed. Skipping...')
|
|
|
|
expect(instance.filter_and_get_changed_files_in_mr(filter_pattern: /\.(js|vue)$/)).to eq([])
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when checks should not run for changed files' do
|
|
before do
|
|
allow(instance).to receive(:should_run_checks_for_changed_files).and_return(false)
|
|
end
|
|
|
|
it 'returns ["."] and prints warning' do
|
|
expect(instance).to receive(:puts).with("Changed file criteria didn't match... Command will run for all files")
|
|
|
|
expect(instance.filter_and_get_changed_files_in_mr(filter_pattern: /\.(js|vue)$/)).to eq(['.'])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#run_eslint_for_changed_files' do
|
|
let(:files) { ['file1.js', 'file2.vue'] }
|
|
let(:eslint_command) { ['yarn', 'run', 'lint:eslint', '--format', 'gitlab', 'file1.js', 'file2.vue'] }
|
|
|
|
before do
|
|
allow(instance).to receive(:puts).with('Running ESLint...')
|
|
end
|
|
|
|
context 'when there are changed files to lint' do
|
|
before do
|
|
allow(instance).to receive(:filter_and_get_changed_files_in_mr).and_return(files)
|
|
end
|
|
|
|
it 'runs eslint with the correct arguments and returns exit 0 on success' do
|
|
expect(instance).to receive(:system).with(*eslint_command).and_return(true)
|
|
|
|
status = instance_double(Process::Status, exitstatus: 0)
|
|
allow(instance).to receive(:last_command_status).and_return(status)
|
|
|
|
expect(instance.run_eslint_for_changed_files).to eq(0)
|
|
end
|
|
|
|
it 'runs eslint with the correct arguments and returns exit 1 on failure' do
|
|
expect(instance).to receive(:system).with(*eslint_command).and_return(false)
|
|
|
|
status = instance_double(Process::Status, exitstatus: 1)
|
|
allow(instance).to receive(:last_command_status).and_return(status)
|
|
|
|
expect(instance.run_eslint_for_changed_files).to eq(1)
|
|
end
|
|
end
|
|
|
|
context 'when there are no changed files to lint' do
|
|
it 'does not run eslint and returns exit code 0' do
|
|
allow(instance).to receive(:filter_and_get_changed_files_in_mr).and_return([])
|
|
expect(instance).not_to receive(:system)
|
|
|
|
expect(instance.run_eslint_for_changed_files).to eq(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'Run CLI commands' do
|
|
it 'returns 0 for empty args' do
|
|
allow(ARGV).to receive(:empty?).and_return(true)
|
|
|
|
expect(instance.process_command_and_determine_exit_status).to eq(0)
|
|
end
|
|
|
|
it 'returns 0 when eslint succeeds' do
|
|
allow(ARGV).to receive(:first).and_return('eslint')
|
|
allow(instance).to receive(:run_eslint_for_changed_files).and_return(0)
|
|
|
|
expect(instance.process_command_and_determine_exit_status).to eq(0)
|
|
end
|
|
|
|
it 'returns exit code when eslint fails' do
|
|
allow(ARGV).to receive(:first).and_return('eslint')
|
|
allow(instance).to receive(:run_eslint_for_changed_files).and_return(11)
|
|
|
|
expect(instance.process_command_and_determine_exit_status).to eq(11)
|
|
end
|
|
|
|
it 'returns 1 for unknown commands' do
|
|
allow(ARGV).to receive(:first).and_return('unknown')
|
|
|
|
expect(instance.process_command_and_determine_exit_status).to eq(1)
|
|
end
|
|
end
|
|
end
|