Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-12 15:09:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-12 15:09:33 +0300
commit26e44c6225a19c3ec4e7d607f92b16d42b437c80 (patch)
tree03c97705ad836eb6a89df451c7f4216d6eb9779a /spec
parent3159925155a86dfd41000c1467576927c18c8f58 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/ide/components/commit_sidebar/form_spec.js5
-rw-r--r--spec/frontend/ide/components/ide_spec.js3
-rw-r--r--spec/frontend/ide/services/index_spec.js4
-rw-r--r--spec/frontend/ide/stores/getters_spec.js70
-rw-r--r--spec/helpers/groups_helper_spec.rb8
-rw-r--r--spec/lib/gitlab/utils/usage_data_spec.rb11
-rw-r--r--spec/models/board_spec.rb1
-rw-r--r--spec/models/ci/build_spec.rb2
-rw-r--r--spec/models/project_spec.rb28
-rw-r--r--spec/services/namespaces/in_product_marketing_emails_service_spec.rb16
-rw-r--r--spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb6
-rw-r--r--spec/tooling/danger/base_linter_spec.rb192
-rw-r--r--spec/tooling/danger/changelog_spec.rb35
-rw-r--r--spec/tooling/danger/commit_linter_spec.rb241
-rw-r--r--spec/tooling/danger/danger_spec_helper.rb17
-rw-r--r--spec/tooling/danger/emoji_checker_spec.rb37
-rw-r--r--spec/tooling/danger/feature_flag_spec.rb23
-rw-r--r--spec/tooling/danger/helper_spec.rb781
-rw-r--r--spec/tooling/danger/merge_request_linter_spec.rb54
-rw-r--r--spec/tooling/danger/project_helper_spec.rb260
-rw-r--r--spec/tooling/danger/roulette_spec.rb429
-rw-r--r--spec/tooling/danger/sidekiq_queues_spec.rb11
-rw-r--r--spec/tooling/danger/teammate_spec.rb225
-rw-r--r--spec/tooling/danger/title_linting_spec.rb91
-rw-r--r--spec/tooling/danger/weightage/maintainers_spec.rb34
-rw-r--r--spec/tooling/danger/weightage/reviewers_spec.rb63
-rw-r--r--spec/tooling/gitlab_danger_spec.rb76
27 files changed, 414 insertions, 2309 deletions
diff --git a/spec/frontend/ide/components/commit_sidebar/form_spec.js b/spec/frontend/ide/components/commit_sidebar/form_spec.js
index 2b567816ce8..083a2a73b24 100644
--- a/spec/frontend/ide/components/commit_sidebar/form_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/form_spec.js
@@ -14,6 +14,7 @@ import {
createBranchChangedCommitError,
branchAlreadyExistsCommitError,
} from '~/ide/lib/errors';
+import { MSG_CANNOT_PUSH_CODE_SHORT } from '~/ide/messages';
import { createStore } from '~/ide/stores';
import { COMMIT_TO_NEW_BRANCH } from '~/ide/stores/modules/commit/constants';
@@ -84,8 +85,8 @@ describe('IDE commit form', () => {
${'when there are no changes'} | ${[]} | ${{ pushCode: true }} | ${goToEditView} | ${findBeginCommitButtonData} | ${true} | ${''}
${'when there are changes'} | ${['test']} | ${{ pushCode: true }} | ${goToEditView} | ${findBeginCommitButtonData} | ${false} | ${''}
${'when there are changes'} | ${['test']} | ${{ pushCode: true }} | ${goToCommitView} | ${findCommitButtonData} | ${false} | ${''}
- ${'when user cannot push'} | ${['test']} | ${{ pushCode: false }} | ${goToEditView} | ${findBeginCommitButtonData} | ${true} | ${CommitForm.MSG_CANNOT_PUSH_CODE}
- ${'when user cannot push'} | ${['test']} | ${{ pushCode: false }} | ${goToCommitView} | ${findCommitButtonData} | ${true} | ${CommitForm.MSG_CANNOT_PUSH_CODE}
+ ${'when user cannot push'} | ${['test']} | ${{ pushCode: false }} | ${goToEditView} | ${findBeginCommitButtonData} | ${true} | ${MSG_CANNOT_PUSH_CODE_SHORT}
+ ${'when user cannot push'} | ${['test']} | ${{ pushCode: false }} | ${goToCommitView} | ${findCommitButtonData} | ${true} | ${MSG_CANNOT_PUSH_CODE_SHORT}
`('$desc', ({ stagedFiles, userPermissions, viewFn, buttonFn, disabled, tooltip }) => {
beforeEach(async () => {
store.state.stagedFiles = stagedFiles;
diff --git a/spec/frontend/ide/components/ide_spec.js b/spec/frontend/ide/components/ide_spec.js
index c9d19c18d03..bd251f78654 100644
--- a/spec/frontend/ide/components/ide_spec.js
+++ b/spec/frontend/ide/components/ide_spec.js
@@ -4,6 +4,7 @@ import Vuex from 'vuex';
import waitForPromises from 'helpers/wait_for_promises';
import ErrorMessage from '~/ide/components/error_message.vue';
import Ide from '~/ide/components/ide.vue';
+import { MSG_CANNOT_PUSH_CODE } from '~/ide/messages';
import { createStore } from '~/ide/stores';
import { file } from '../helpers';
import { projectData } from '../mock_data';
@@ -158,7 +159,7 @@ describe('WebIDE', () => {
expect(findAlert().props()).toMatchObject({
dismissible: false,
});
- expect(findAlert().text()).toBe(Ide.MSG_CANNOT_PUSH_CODE);
+ expect(findAlert().text()).toBe(MSG_CANNOT_PUSH_CODE);
});
it.each`
diff --git a/spec/frontend/ide/services/index_spec.js b/spec/frontend/ide/services/index_spec.js
index 678d58cba34..3503834e24b 100644
--- a/spec/frontend/ide/services/index_spec.js
+++ b/spec/frontend/ide/services/index_spec.js
@@ -1,7 +1,7 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
+import getIdeProject from 'ee_else_ce/ide/queries/get_ide_project.query.graphql';
import Api from '~/api';
-import getUserPermissions from '~/ide/queries/getUserPermissions.query.graphql';
import services from '~/ide/services';
import { query } from '~/ide/services/gql';
import { escapeFileUrl } from '~/lib/utils/url_utility';
@@ -228,7 +228,7 @@ describe('IDE services', () => {
expect(response).toEqual({ data: { ...projectData, ...gqlProjectData } });
expect(Api.project).toHaveBeenCalledWith(TEST_PROJECT_ID);
expect(query).toHaveBeenCalledWith({
- query: getUserPermissions,
+ query: getIdeProject,
variables: {
projectPath: TEST_PROJECT_ID,
},
diff --git a/spec/frontend/ide/stores/getters_spec.js b/spec/frontend/ide/stores/getters_spec.js
index 450f5592026..6b66c87e205 100644
--- a/spec/frontend/ide/stores/getters_spec.js
+++ b/spec/frontend/ide/stores/getters_spec.js
@@ -1,7 +1,17 @@
import { TEST_HOST } from 'helpers/test_constants';
+import {
+ DEFAULT_PERMISSIONS,
+ PERMISSION_PUSH_CODE,
+ PUSH_RULE_REJECT_UNSIGNED_COMMITS,
+} from '~/ide/constants';
+import {
+ MSG_CANNOT_PUSH_CODE,
+ MSG_CANNOT_PUSH_CODE_SHORT,
+ MSG_CANNOT_PUSH_UNSIGNED,
+ MSG_CANNOT_PUSH_UNSIGNED_SHORT,
+} from '~/ide/messages';
import { createStore } from '~/ide/stores';
import * as getters from '~/ide/stores/getters';
-import { DEFAULT_PERMISSIONS } from '../../../../app/assets/javascripts/ide/constants';
import { file } from '../helpers';
const TEST_PROJECT_ID = 'test_project';
@@ -385,22 +395,23 @@ describe('IDE store getters', () => {
);
});
- describe('findProjectPermissions', () => {
- it('returns false if project not found', () => {
- expect(localStore.getters.findProjectPermissions(TEST_PROJECT_ID)).toEqual(
- DEFAULT_PERMISSIONS,
- );
+ describe.each`
+ getterName | projectField | defaultValue
+ ${'findProjectPermissions'} | ${'userPermissions'} | ${DEFAULT_PERMISSIONS}
+ ${'findPushRules'} | ${'pushRules'} | ${{}}
+ `('$getterName', ({ getterName, projectField, defaultValue }) => {
+ const callGetter = (...args) => localStore.getters[getterName](...args);
+
+ it('returns default if project not found', () => {
+ expect(callGetter(TEST_PROJECT_ID)).toEqual(defaultValue);
});
- it('finds permission in given project', () => {
- const userPermissions = {
- readMergeRequest: true,
- createMergeRequestsIn: false,
- };
+ it('finds field in given project', () => {
+ const obj = { test: 'foo' };
- localState.projects[TEST_PROJECT_ID] = { userPermissions };
+ localState.projects[TEST_PROJECT_ID] = { [projectField]: obj };
- expect(localStore.getters.findProjectPermissions(TEST_PROJECT_ID)).toBe(userPermissions);
+ expect(callGetter(TEST_PROJECT_ID)).toBe(obj);
});
});
@@ -408,7 +419,6 @@ describe('IDE store getters', () => {
getterName | permissionKey
${'canReadMergeRequests'} | ${'readMergeRequest'}
${'canCreateMergeRequests'} | ${'createMergeRequestIn'}
- ${'canPushCode'} | ${'pushCode'}
`('$getterName', ({ getterName, permissionKey }) => {
it.each([true, false])('finds permission for current project (%s)', (val) => {
localState.projects[TEST_PROJECT_ID] = {
@@ -422,6 +432,38 @@ describe('IDE store getters', () => {
});
});
+ describe('canPushCodeStatus', () => {
+ it.each`
+ pushCode | rejectUnsignedCommits | expected
+ ${true} | ${false} | ${{ isAllowed: true, message: '', messageShort: '' }}
+ ${false} | ${false} | ${{ isAllowed: false, message: MSG_CANNOT_PUSH_CODE, messageShort: MSG_CANNOT_PUSH_CODE_SHORT }}
+ ${false} | ${true} | ${{ isAllowed: false, message: MSG_CANNOT_PUSH_UNSIGNED, messageShort: MSG_CANNOT_PUSH_UNSIGNED_SHORT }}
+ `(
+ 'with pushCode="$pushCode" and rejectUnsignedCommits="$rejectUnsignedCommits"',
+ ({ pushCode, rejectUnsignedCommits, expected }) => {
+ localState.projects[TEST_PROJECT_ID] = {
+ pushRules: {
+ [PUSH_RULE_REJECT_UNSIGNED_COMMITS]: rejectUnsignedCommits,
+ },
+ userPermissions: {
+ [PERMISSION_PUSH_CODE]: pushCode,
+ },
+ };
+ localState.currentProjectId = TEST_PROJECT_ID;
+
+ expect(localStore.getters.canPushCodeStatus).toEqual(expected);
+ },
+ );
+ });
+
+ describe('canPushCode', () => {
+ it.each([true, false])('with canPushCodeStatus.isAllowed = $s', (isAllowed) => {
+ const canPushCodeStatus = { isAllowed };
+
+ expect(getters.canPushCode({}, { canPushCodeStatus })).toBe(isAllowed);
+ });
+ });
+
describe('entryExists', () => {
beforeEach(() => {
localState.entries = {
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 61aaa618c45..e022595fb9a 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -18,11 +18,17 @@ RSpec.describe GroupsHelper do
it 'gives default avatar_icon when no avatar is present' do
group = create(:group)
- group.save!
expect(group_icon_url(group.path)).to match_asset_path('group_avatar.png')
end
end
+ describe 'group_dependency_proxy_url' do
+ it 'converts uppercase letters to lowercase' do
+ group = create(:group, path: 'GroupWithUPPERcaseLetters')
+ expect(group_dependency_proxy_url(group)).to end_with("/groupwithuppercaseletters#{DependencyProxy::URL_SUFFIX}")
+ end
+ end
+
describe 'group_lfs_status' do
let(:group) { create(:group) }
let!(:project) { create(:project, namespace_id: group.id) }
diff --git a/spec/lib/gitlab/utils/usage_data_spec.rb b/spec/lib/gitlab/utils/usage_data_spec.rb
index 011d1f4ae57..45e57428141 100644
--- a/spec/lib/gitlab/utils/usage_data_spec.rb
+++ b/spec/lib/gitlab/utils/usage_data_spec.rb
@@ -246,6 +246,13 @@ RSpec.describe Gitlab::Utils::UsageData do
end
describe '#with_prometheus_client' do
+ it 'returns fallback with for an exception in yield block' do
+ allow(described_class).to receive(:prometheus_client).and_return(Gitlab::PrometheusClient.new('http://localhost:9090'))
+ result = described_class.with_prometheus_client(fallback: -42) { |client| raise StandardError }
+
+ expect(result).to be(-42)
+ end
+
shared_examples 'query data from Prometheus' do
it 'yields a client instance and returns the block result' do
result = described_class.with_prometheus_client { |client| client }
@@ -255,10 +262,10 @@ RSpec.describe Gitlab::Utils::UsageData do
end
shared_examples 'does not query data from Prometheus' do
- it 'returns nil by default' do
+ it 'returns {} by default' do
result = described_class.with_prometheus_client { |client| client }
- expect(result).to be_nil
+ expect(result).to eq({})
end
it 'returns fallback if provided' do
diff --git a/spec/models/board_spec.rb b/spec/models/board_spec.rb
index d309b4dbdb9..c8a9504d4fc 100644
--- a/spec/models/board_spec.rb
+++ b/spec/models/board_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Board do
end
describe 'validations' do
+ it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_presence_of(:project) }
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 811decf42d7..5b07bd8923f 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -2482,7 +2482,7 @@ RSpec.describe Ci::Build do
{ key: 'CI_PAGES_URL', value: project.pages_url, public: true, masked: false },
{ key: 'CI_DEPENDENCY_PROXY_SERVER', value: Gitlab.host_with_port, public: true, masked: false },
{ key: 'CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX',
- value: "#{Gitlab.host_with_port}/#{project.namespace.root_ancestor.path}#{DependencyProxy::URL_SUFFIX}",
+ value: "#{Gitlab.host_with_port}/#{project.namespace.root_ancestor.path.downcase}#{DependencyProxy::URL_SUFFIX}",
public: true,
masked: false },
{ key: 'CI_API_V4_URL', value: 'http://localhost/api/v4', public: true, masked: false },
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index b4010ba6e31..56c0e635447 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -4488,6 +4488,34 @@ RSpec.describe Project, factory_default: :keep do
end
end
+ describe '#dependency_proxy_variables' do
+ let_it_be(:namespace) { create(:namespace, path: 'NameWithUPPERcaseLetters') }
+ let_it_be(:project) { create(:project, :repository, namespace: namespace) }
+
+ subject { project.dependency_proxy_variables.to_runner_variables }
+
+ context 'when dependency_proxy is enabled' do
+ before do
+ stub_config(dependency_proxy: { enabled: true })
+ end
+
+ it 'contains the downcased name' do
+ expect(subject).to include({ key: 'CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX',
+ value: "#{Gitlab.host_with_port}/namewithuppercaseletters#{DependencyProxy::URL_SUFFIX}",
+ public: true,
+ masked: false })
+ end
+ end
+
+ context 'when dependency_proxy is disabled' do
+ before do
+ stub_config(dependency_proxy: { enabled: false })
+ end
+
+ it { expect(subject).to be_empty }
+ end
+ end
+
describe '#auto_devops_enabled?' do
before do
Feature.enable_percentage_of_actors(:force_autodevops_on_by_default, 0)
diff --git a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
index 2581cab5d1a..28b2e699e5e 100644
--- a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
+++ b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
@@ -159,4 +159,20 @@ RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute' do
it { expect { subject }.to raise_error(NotImplementedError, 'No ability defined for track foo') }
end
+
+ context 'when group is a sub-group' do
+ let(:root_group) { create(:group) }
+ let(:group) { create(:group) }
+
+ before do
+ group.parent = root_group
+ group.save!
+
+ allow(Ability).to receive(:allowed?).and_call_original
+ end
+
+ it 'does not raise an exception' do
+ expect { execute_service }.not_to raise_error
+ end
+ end
end
diff --git a/spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb
index 2b93d174653..2e3a3ce6b41 100644
--- a/spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb
@@ -66,9 +66,7 @@ RSpec.shared_examples 'boards create mutation' do
context 'when the Boards::CreateService returns an error response' do
before do
- allow_next_instance_of(Boards::CreateService) do |service|
- allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'There was an error.'))
- end
+ params[:name] = ''
end
it 'does not create a board' do
@@ -80,7 +78,7 @@ RSpec.shared_examples 'boards create mutation' do
expect(mutation_response).to have_key('board')
expect(mutation_response['board']).to be_nil
- expect(mutation_response['errors'].first).to eq('There was an error.')
+ expect(mutation_response['errors'].first).to eq('There was an error when creating a board.')
end
end
end
diff --git a/spec/tooling/danger/base_linter_spec.rb b/spec/tooling/danger/base_linter_spec.rb
deleted file mode 100644
index 54d8f3dc1f7..00000000000
--- a/spec/tooling/danger/base_linter_spec.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-# frozen_string_literal: true
-
-require 'rspec-parameterized'
-require_relative 'danger_spec_helper'
-
-require_relative '../../../tooling/danger/base_linter'
-
-RSpec.describe Tooling::Danger::BaseLinter do
- let(:commit_class) do
- Struct.new(:message, :sha, :diff_parent)
- end
-
- let(:commit_message) { 'A commit message' }
- let(:commit) { commit_class.new(commit_message, anything, anything) }
-
- subject(:commit_linter) { described_class.new(commit) }
-
- describe '#failed?' do
- context 'with no failures' do
- it { expect(commit_linter).not_to be_failed }
- end
-
- context 'with failures' do
- before do
- commit_linter.add_problem(:subject_too_long, described_class.subject_description)
- end
-
- it { expect(commit_linter).to be_failed }
- end
- end
-
- describe '#add_problem' do
- it 'stores messages in #failures' do
- commit_linter.add_problem(:subject_too_long, '%s')
-
- expect(commit_linter.problems).to eq({ subject_too_long: described_class.problems_mapping[:subject_too_long] })
- end
- end
-
- shared_examples 'a valid commit' do
- it 'does not have any problem' do
- commit_linter.lint_subject
-
- expect(commit_linter.problems).to be_empty
- end
- end
-
- describe '#lint_subject' do
- context 'when subject valid' do
- it_behaves_like 'a valid commit'
- end
-
- context 'when subject is too short' do
- let(:commit_message) { 'A B' }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:subject_too_short, described_class.subject_description)
-
- commit_linter.lint_subject
- end
- end
-
- context 'when subject is too long' do
- let(:commit_message) { 'A B ' + 'C' * described_class::MAX_LINE_LENGTH }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:subject_too_long, described_class.subject_description)
-
- commit_linter.lint_subject
- end
- end
-
- context 'when ignoring length issues for subject having not-ready wording' do
- using RSpec::Parameterized::TableSyntax
-
- let(:final_message) { 'A B C' }
-
- context 'when used as prefix' do
- where(prefix: [
- 'WIP: ',
- 'WIP:',
- 'wIp:',
- '[WIP] ',
- '[WIP]',
- '[draft]',
- '[draft] ',
- '(draft)',
- '(draft) ',
- 'draft - ',
- 'draft: ',
- 'draft:',
- 'DRAFT:'
- ])
-
- with_them do
- it 'does not have any problems' do
- commit_message = prefix + final_message + 'D' * (described_class::MAX_LINE_LENGTH - final_message.size)
- commit = commit_class.new(commit_message, anything, anything)
-
- linter = described_class.new(commit).lint_subject
-
- expect(linter.problems).to be_empty
- end
- end
- end
-
- context 'when used as suffix' do
- where(suffix: %w[WIP draft])
-
- with_them do
- it 'does not have any problems' do
- commit_message = final_message + 'D' * (described_class::MAX_LINE_LENGTH - final_message.size) + suffix
- commit = commit_class.new(commit_message, anything, anything)
-
- linter = described_class.new(commit).lint_subject
-
- expect(linter.problems).to be_empty
- end
- end
- end
- end
-
- context 'when subject does not have enough words and is too long' do
- let(:commit_message) { 'A ' + 'B' * described_class::MAX_LINE_LENGTH }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:subject_too_short, described_class.subject_description)
- expect(commit_linter).to receive(:add_problem).with(:subject_too_long, described_class.subject_description)
-
- commit_linter.lint_subject
- end
- end
-
- context 'when subject starts with lowercase' do
- let(:commit_message) { 'a B C' }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:subject_starts_with_lowercase, described_class.subject_description)
-
- commit_linter.lint_subject
- end
- end
-
- [
- '[ci skip] A commit message',
- '[Ci skip] A commit message',
- '[API] A commit message',
- 'api: A commit message',
- 'API: A commit message',
- 'API: a commit message',
- 'API: a commit message'
- ].each do |message|
- context "when subject is '#{message}'" do
- let(:commit_message) { message }
-
- it 'does not add a problem' do
- expect(commit_linter).not_to receive(:add_problem)
-
- commit_linter.lint_subject
- end
- end
- end
-
- [
- '[ci skip]A commit message',
- '[Ci skip] A commit message',
- '[ci skip] a commit message',
- 'api: a commit message',
- '! A commit message'
- ].each do |message|
- context "when subject is '#{message}'" do
- let(:commit_message) { message }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:subject_starts_with_lowercase, described_class.subject_description)
-
- commit_linter.lint_subject
- end
- end
- end
-
- context 'when subject ends with a period' do
- let(:commit_message) { 'A B C.' }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:subject_ends_with_a_period, described_class.subject_description)
-
- commit_linter.lint_subject
- end
- end
- end
-end
diff --git a/spec/tooling/danger/changelog_spec.rb b/spec/tooling/danger/changelog_spec.rb
index 8d056b8a78e..b74039b3cd1 100644
--- a/spec/tooling/danger/changelog_spec.rb
+++ b/spec/tooling/danger/changelog_spec.rb
@@ -1,26 +1,23 @@
# frozen_string_literal: true
-require_relative 'danger_spec_helper'
+require 'gitlab-dangerfiles'
+require 'gitlab/dangerfiles/spec_helper'
-require_relative '../../../tooling/danger/helper'
require_relative '../../../tooling/danger/changelog'
+require_relative '../../../tooling/danger/project_helper'
RSpec.describe Tooling::Danger::Changelog do
- include DangerSpecHelper
+ include_context "with dangerfile"
- let(:change_class) { Tooling::Danger::Helper::Change }
- let(:changes_class) { Tooling::Danger::Helper::Changes }
- let(:changes) { changes_class.new([]) }
-
- let(:mr_labels) { [] }
- let(:sanitize_mr_title) { 'Fake Title' }
-
- let(:fake_helper) { double('fake-helper', changes: changes, mr_iid: 1234, mr_title: sanitize_mr_title, mr_labels: mr_labels) }
-
- let(:fake_danger) { new_fake_danger.include(described_class) }
+ let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+ let(:fake_project_helper) { double('fake-project-helper', helper: fake_helper).tap { |h| h.class.include(Tooling::Danger::ProjectHelper) } }
subject(:changelog) { fake_danger.new(helper: fake_helper) }
+ before do
+ allow(changelog).to receive(:project_helper).and_return(fake_project_helper)
+ end
+
describe '#required_reasons' do
subject { changelog.required_reasons }
@@ -165,7 +162,7 @@ RSpec.describe Tooling::Danger::Changelog do
subject { changelog.modified_text }
context "when title is not changed from sanitization", :aggregate_failures do
- let(:sanitize_mr_title) { 'Fake Title' }
+ let(:mr_title) { 'Fake Title' }
specify do
expect(subject).to include('CHANGELOG.md was edited')
@@ -175,7 +172,7 @@ RSpec.describe Tooling::Danger::Changelog do
end
context "when title needs sanitization", :aggregate_failures do
- let(:sanitize_mr_title) { 'DRAFT: Fake Title' }
+ let(:mr_title) { 'DRAFT: Fake Title' }
specify do
expect(subject).to include('CHANGELOG.md was edited')
@@ -186,7 +183,7 @@ RSpec.describe Tooling::Danger::Changelog do
end
describe '#required_texts' do
- let(:sanitize_mr_title) { 'Fake Title' }
+ let(:mr_title) { 'Fake Title' }
subject { changelog.required_texts }
@@ -207,7 +204,7 @@ RSpec.describe Tooling::Danger::Changelog do
end
context "when title needs sanitization", :aggregate_failures do
- let(:sanitize_mr_title) { 'DRAFT: Fake Title' }
+ let(:mr_title) { 'DRAFT: Fake Title' }
it_behaves_like 'changelog required text', :db_changes
end
@@ -224,7 +221,7 @@ RSpec.describe Tooling::Danger::Changelog do
subject { changelog.optional_text }
context "when title is not changed from sanitization", :aggregate_failures do
- let(:sanitize_mr_title) { 'Fake Title' }
+ let(:mr_title) { 'Fake Title' }
specify do
expect(subject).to include('CHANGELOG missing')
@@ -234,7 +231,7 @@ RSpec.describe Tooling::Danger::Changelog do
end
context "when title needs sanitization", :aggregate_failures do
- let(:sanitize_mr_title) { 'DRAFT: Fake Title' }
+ let(:mr_title) { 'DRAFT: Fake Title' }
specify do
expect(subject).to include('CHANGELOG missing')
diff --git a/spec/tooling/danger/commit_linter_spec.rb b/spec/tooling/danger/commit_linter_spec.rb
deleted file mode 100644
index 694e524af21..00000000000
--- a/spec/tooling/danger/commit_linter_spec.rb
+++ /dev/null
@@ -1,241 +0,0 @@
-# frozen_string_literal: true
-
-require 'rspec-parameterized'
-require_relative 'danger_spec_helper'
-
-require_relative '../../../tooling/danger/commit_linter'
-
-RSpec.describe Tooling::Danger::CommitLinter do
- using RSpec::Parameterized::TableSyntax
-
- let(:total_files_changed) { 2 }
- let(:total_lines_changed) { 10 }
- let(:stats) { { total: { files: total_files_changed, lines: total_lines_changed } } }
- let(:diff_parent) { Struct.new(:stats).new(stats) }
- let(:commit_class) do
- Struct.new(:message, :sha, :diff_parent)
- end
-
- let(:commit_message) { 'A commit message' }
- let(:commit_sha) { 'abcd1234' }
- let(:commit) { commit_class.new(commit_message, commit_sha, diff_parent) }
-
- subject(:commit_linter) { described_class.new(commit) }
-
- describe '#fixup?' do
- where(:commit_message, :is_fixup) do
- 'A commit message' | false
- 'fixup!' | true
- 'fixup! A commit message' | true
- 'squash!' | true
- 'squash! A commit message' | true
- end
-
- with_them do
- it 'is true when commit message starts with "fixup!" or "squash!"' do
- expect(commit_linter.fixup?).to be(is_fixup)
- end
- end
- end
-
- describe '#suggestion?' do
- where(:commit_message, :is_suggestion) do
- 'A commit message' | false
- 'Apply suggestion to' | true
- 'Apply suggestion to "A commit message"' | true
- end
-
- with_them do
- it 'is true when commit message starts with "Apply suggestion to"' do
- expect(commit_linter.suggestion?).to be(is_suggestion)
- end
- end
- end
-
- describe '#merge?' do
- where(:commit_message, :is_merge) do
- 'A commit message' | false
- 'Merge branch' | true
- 'Merge branch "A commit message"' | true
- end
-
- with_them do
- it 'is true when commit message starts with "Merge branch"' do
- expect(commit_linter.merge?).to be(is_merge)
- end
- end
- end
-
- describe '#revert?' do
- where(:commit_message, :is_revert) do
- 'A commit message' | false
- 'Revert' | false
- 'Revert "' | true
- 'Revert "A commit message"' | true
- end
-
- with_them do
- it 'is true when commit message starts with "Revert \""' do
- expect(commit_linter.revert?).to be(is_revert)
- end
- end
- end
-
- describe '#multi_line?' do
- where(:commit_message, :is_multi_line) do
- "A commit message" | false
- "A commit message\n" | false
- "A commit message\n\n" | false
- "A commit message\n\nSigned-off-by: User Name <user@name.me>" | false
- "A commit message\n\nWith details" | true
- end
-
- with_them do
- it 'is true when commit message contains details' do
- expect(commit_linter.multi_line?).to be(is_multi_line)
- end
- end
- end
-
- shared_examples 'a valid commit' do
- it 'does not have any problem' do
- commit_linter.lint
-
- expect(commit_linter.problems).to be_empty
- end
- end
-
- describe '#lint' do
- describe 'separator' do
- context 'when separator is missing' do
- let(:commit_message) { "A B C\n" }
-
- it_behaves_like 'a valid commit'
- end
-
- context 'when separator is a blank line' do
- let(:commit_message) { "A B C\n\nMore details." }
-
- it_behaves_like 'a valid commit'
- end
-
- context 'when separator is missing' do
- let(:commit_message) { "A B C\nMore details." }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:separator_missing)
-
- commit_linter.lint
- end
- end
- end
-
- describe 'details' do
- context 'when details are valid' do
- let(:commit_message) { "A B C\n\nMore details." }
-
- it_behaves_like 'a valid commit'
- end
-
- context 'when no details are given and many files are changed' do
- let(:total_files_changed) { described_class::MAX_CHANGED_FILES_IN_COMMIT + 1 }
-
- it_behaves_like 'a valid commit'
- end
-
- context 'when no details are given and many lines are changed' do
- let(:total_lines_changed) { described_class::MAX_CHANGED_LINES_IN_COMMIT + 1 }
-
- it_behaves_like 'a valid commit'
- end
-
- context 'when no details are given and many files and lines are changed' do
- let(:total_files_changed) { described_class::MAX_CHANGED_FILES_IN_COMMIT + 1 }
- let(:total_lines_changed) { described_class::MAX_CHANGED_LINES_IN_COMMIT + 1 }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:details_too_many_changes)
-
- commit_linter.lint
- end
- end
-
- context 'when details exceeds the max line length' do
- let(:commit_message) { "A B C\n\n" + 'D' * (described_class::MAX_LINE_LENGTH + 1) }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:details_line_too_long)
-
- commit_linter.lint
- end
- end
-
- context 'when details exceeds the max line length including URLs' do
- let(:commit_message) do
- "A B C\n\nsome message with https://example.com and https://gitlab.com" + 'D' * described_class::MAX_LINE_LENGTH
- end
-
- it_behaves_like 'a valid commit'
- end
- end
-
- describe 'message' do
- context 'when message includes a text emoji' do
- let(:commit_message) { "A commit message :+1:" }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:message_contains_text_emoji)
-
- commit_linter.lint
- end
- end
-
- context 'when message includes a unicode emoji' do
- let(:commit_message) { "A commit message 🚀" }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:message_contains_unicode_emoji)
-
- commit_linter.lint
- end
- end
-
- context 'when message includes a value that is surrounded by backticks' do
- let(:commit_message) { "A commit message `%20`" }
-
- it 'does not add a problem' do
- expect(commit_linter).not_to receive(:add_problem)
-
- commit_linter.lint
- end
- end
-
- context 'when message includes a short reference' do
- [
- 'A commit message to fix #1234',
- 'A commit message to fix !1234',
- 'A commit message to fix &1234',
- 'A commit message to fix %1234',
- 'A commit message to fix gitlab#1234',
- 'A commit message to fix gitlab!1234',
- 'A commit message to fix gitlab&1234',
- 'A commit message to fix gitlab%1234',
- 'A commit message to fix gitlab-org/gitlab#1234',
- 'A commit message to fix gitlab-org/gitlab!1234',
- 'A commit message to fix gitlab-org/gitlab&1234',
- 'A commit message to fix gitlab-org/gitlab%1234',
- 'A commit message to fix "gitlab-org/gitlab%1234"',
- 'A commit message to fix `gitlab-org/gitlab%1234'
- ].each do |message|
- let(:commit_message) { message }
-
- it 'adds a problem' do
- expect(commit_linter).to receive(:add_problem).with(:message_contains_short_reference)
-
- commit_linter.lint
- end
- end
- end
- end
- end
-end
diff --git a/spec/tooling/danger/danger_spec_helper.rb b/spec/tooling/danger/danger_spec_helper.rb
deleted file mode 100644
index b1e84b3c13d..00000000000
--- a/spec/tooling/danger/danger_spec_helper.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module DangerSpecHelper
- def new_fake_danger
- Class.new do
- attr_reader :git, :gitlab, :helper
-
- # rubocop:disable Gitlab/ModuleWithInstanceVariables
- def initialize(git: nil, gitlab: nil, helper: nil)
- @git = git
- @gitlab = gitlab
- @helper = helper
- end
- # rubocop:enable Gitlab/ModuleWithInstanceVariables
- end
- end
-end
diff --git a/spec/tooling/danger/emoji_checker_spec.rb b/spec/tooling/danger/emoji_checker_spec.rb
deleted file mode 100644
index bbd957b3d00..00000000000
--- a/spec/tooling/danger/emoji_checker_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-require 'rspec-parameterized'
-
-require_relative '../../../tooling/danger/emoji_checker'
-
-RSpec.describe Tooling::Danger::EmojiChecker do
- using RSpec::Parameterized::TableSyntax
-
- describe '#includes_text_emoji?' do
- where(:text, :includes_emoji) do
- 'Hello World!' | false
- ':+1:' | true
- 'Hello World! :+1:' | true
- end
-
- with_them do
- it 'is true when text includes a text emoji' do
- expect(subject.includes_text_emoji?(text)).to be(includes_emoji)
- end
- end
- end
-
- describe '#includes_unicode_emoji?' do
- where(:text, :includes_emoji) do
- 'Hello World!' | false
- '🚀' | true
- 'Hello World! 🚀' | true
- end
-
- with_them do
- it 'is true when text includes a text emoji' do
- expect(subject.includes_unicode_emoji?(text)).to be(includes_emoji)
- end
- end
- end
-end
diff --git a/spec/tooling/danger/feature_flag_spec.rb b/spec/tooling/danger/feature_flag_spec.rb
index db63116cc37..5e495cd43c6 100644
--- a/spec/tooling/danger/feature_flag_spec.rb
+++ b/spec/tooling/danger/feature_flag_spec.rb
@@ -1,29 +1,16 @@
# frozen_string_literal: true
-require_relative 'danger_spec_helper'
+require 'gitlab-dangerfiles'
+require 'gitlab/dangerfiles/spec_helper'
require_relative '../../../tooling/danger/feature_flag'
RSpec.describe Tooling::Danger::FeatureFlag do
- include DangerSpecHelper
+ include_context "with dangerfile"
- let(:added_files) { nil }
- let(:modified_files) { nil }
- let(:deleted_files) { nil }
- let(:fake_git) { double('fake-git', added_files: added_files, modified_files: modified_files, deleted_files: deleted_files) }
+ let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
- let(:mr_labels) { nil }
- let(:mr_json) { nil }
- let(:fake_gitlab) { double('fake-gitlab', mr_labels: mr_labels, mr_json: mr_json) }
-
- let(:changes_by_category) { nil }
- let(:sanitize_mr_title) { nil }
- let(:ee?) { false }
- let(:fake_helper) { double('fake-helper', changes_by_category: changes_by_category, sanitize_mr_title: sanitize_mr_title, ee?: ee?) }
-
- let(:fake_danger) { new_fake_danger.include(described_class) }
-
- subject(:feature_flag) { fake_danger.new(git: fake_git, gitlab: fake_gitlab, helper: fake_helper) }
+ subject(:feature_flag) { fake_danger.new(git: fake_git) }
describe '#feature_flag_files' do
let(:feature_flag_files) do
diff --git a/spec/tooling/danger/helper_spec.rb b/spec/tooling/danger/helper_spec.rb
deleted file mode 100644
index 9783705dca0..00000000000
--- a/spec/tooling/danger/helper_spec.rb
+++ /dev/null
@@ -1,781 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-require 'rspec-parameterized'
-require_relative 'danger_spec_helper'
-
-require_relative '../../../tooling/danger/helper'
-
-RSpec.describe Tooling::Danger::Helper do
- using RSpec::Parameterized::TableSyntax
- include DangerSpecHelper
-
- let(:mr_author) { nil }
- let(:fake_gitlab) { double('fake-gitlab', mr_author: mr_author) }
-
- let(:fake_danger) { new_fake_danger.include(described_class) }
-
- let(:added_files) { %w[added1] }
- let(:modified_files) { %w[modified1] }
- let(:deleted_files) { %w[deleted1] }
- let(:renamed_before_file) { 'renamed_before' }
- let(:renamed_after_file) { 'renamed_after' }
- let(:renamed_files) { [{ before: renamed_before_file, after: renamed_after_file }] }
-
- let(:fake_git) { double('fake-git') }
-
- before do
- allow(fake_git).to receive(:added_files) { added_files }
- allow(fake_git).to receive(:modified_files) { modified_files }
- allow(fake_git).to receive(:deleted_files) { deleted_files }
- allow(fake_git).to receive(:renamed_files).at_least(:twice) { renamed_files }
- end
-
- subject(:helper) { fake_danger.new(git: fake_git, gitlab: fake_gitlab) }
-
- describe '#gitlab_helper' do
- context 'when gitlab helper is not available' do
- let(:fake_gitlab) { nil }
-
- it 'returns nil' do
- expect(helper.gitlab_helper).to be_nil
- end
- end
-
- context 'when gitlab helper is available' do
- it 'returns the gitlab helper' do
- expect(helper.gitlab_helper).to eq(fake_gitlab)
- end
- end
-
- context 'when danger gitlab plugin is not available' do
- it 'returns nil' do
- invalid_danger = Class.new do
- include Tooling::Danger::Helper
- end.new
-
- expect(invalid_danger.gitlab_helper).to be_nil
- end
- end
- end
-
- describe '#release_automation?' do
- context 'when gitlab helper is not available' do
- it 'returns false' do
- expect(helper.release_automation?).to be_falsey
- end
- end
-
- context 'when gitlab helper is available' do
- context "but the MR author isn't the RELEASE_TOOLS_BOT" do
- let(:mr_author) { 'johnmarston' }
-
- it 'returns false' do
- expect(helper.release_automation?).to be_falsey
- end
- end
-
- context 'and the MR author is the RELEASE_TOOLS_BOT' do
- let(:mr_author) { described_class::RELEASE_TOOLS_BOT }
-
- it 'returns true' do
- expect(helper.release_automation?).to be_truthy
- end
- end
- end
- end
-
- describe '#all_changed_files' do
- subject { helper.all_changed_files }
-
- it 'interprets a list of changes from the danger git plugin' do
- expect(fake_git).to receive(:added_files) { %w[a b c.old] }
- expect(fake_git).to receive(:modified_files) { %w[d e] }
- expect(fake_git)
- .to receive(:renamed_files)
- .at_least(:once)
- .and_return([{ before: 'c.old', after: 'c.new' }])
-
- is_expected.to contain_exactly('a', 'b', 'c.new', 'd', 'e')
- end
- end
-
- describe '#changed_lines' do
- subject { helper.changed_lines('changed_file.rb') }
-
- before do
- allow(fake_git).to receive(:diff_for_file).with('changed_file.rb').and_return(diff)
- end
-
- context 'when file has diff' do
- let(:diff) { double(:diff, patch: "+ # New change here\n+ # New change there") }
-
- it 'returns file changes' do
- is_expected.to eq(['+ # New change here', '+ # New change there'])
- end
- end
-
- context 'when file has no diff (renamed without changes)' do
- let(:diff) { nil }
-
- it 'returns a blank array' do
- is_expected.to eq([])
- end
- end
- end
-
- describe "changed_files" do
- it 'returns list of changed files matching given regex' do
- expect(helper).to receive(:all_changed_files).and_return(%w[migration.rb usage_data.rb])
-
- expect(helper.changed_files(/usage_data/)).to contain_exactly('usage_data.rb')
- end
- end
-
- describe '#all_ee_changes' do
- subject { helper.all_ee_changes }
-
- it 'returns all changed files starting with ee/' do
- expect(helper).to receive(:all_changed_files).and_return(%w[fr/ee/beer.rb ee/wine.rb ee/lib/ido.rb ee.k])
-
- is_expected.to match_array(%w[ee/wine.rb ee/lib/ido.rb])
- end
- end
-
- describe '#ee?' do
- subject { helper.ee? }
-
- it 'returns true if CI_PROJECT_NAME if set to gitlab' do
- stub_env('CI_PROJECT_NAME', 'gitlab')
- expect(Dir).not_to receive(:exist?)
-
- is_expected.to be_truthy
- end
-
- it 'delegates to CHANGELOG-EE.md existence if CI_PROJECT_NAME is set to something else' do
- stub_env('CI_PROJECT_NAME', 'something else')
- expect(Dir).to receive(:exist?).with(File.expand_path('../../../../ee', __dir__)) { true }
-
- is_expected.to be_truthy
- end
-
- it 'returns true if ee exists' do
- stub_env('CI_PROJECT_NAME', nil)
- expect(Dir).to receive(:exist?).with(File.expand_path('../../../../ee', __dir__)) { true }
-
- is_expected.to be_truthy
- end
-
- it "returns false if ee doesn't exist" do
- stub_env('CI_PROJECT_NAME', nil)
- expect(Dir).to receive(:exist?).with(File.expand_path('../../../../ee', __dir__)) { false }
-
- is_expected.to be_falsy
- end
- end
-
- describe '#project_name' do
- subject { helper.project_name }
-
- it 'returns gitlab if ee? returns true' do
- expect(helper).to receive(:ee?) { true }
-
- is_expected.to eq('gitlab')
- end
-
- it 'returns gitlab-ce if ee? returns false' do
- expect(helper).to receive(:ee?) { false }
-
- is_expected.to eq('gitlab-foss')
- end
- end
-
- describe '#markdown_list' do
- it 'creates a markdown list of items' do
- items = %w[a b]
-
- expect(helper.markdown_list(items)).to eq("* `a`\n* `b`")
- end
-
- it 'wraps items in <details> when there are more than 10 items' do
- items = ('a'..'k').to_a
-
- expect(helper.markdown_list(items)).to match(%r{<details>[^<]+</details>})
- end
- end
-
- describe '#changes_by_category' do
- let(:added_files) { %w[foo foo.md foo.rb foo.js] }
- let(:modified_files) { %w[db/migrate/foo lib/gitlab/database/foo.rb] }
- let(:renamed_files) { [{ before: '', after: 'qa/foo' }, { before: '', after: 'ee/changelogs/foo.yml' }] }
-
- it 'categorizes changed files' do
- expect(helper.changes_by_category).to eq(
- backend: %w[foo.rb],
- database: %w[db/migrate/foo lib/gitlab/database/foo.rb],
- frontend: %w[foo.js],
- migration: %w[db/migrate/foo],
- none: %w[ee/changelogs/foo.yml foo.md],
- qa: %w[qa/foo],
- unknown: %w[foo]
- )
- end
- end
-
- describe 'Tooling::Danger::Helper::Changes', :aggregate_failures do
- let(:added_files) { %w[db/migrate/foo ee/changelogs/unreleased/foo.yml] }
-
- describe '#has_category?' do
- it 'returns true when changes include given category, false otherwise' do
- changes = helper.changes
-
- expect(changes.has_category?(:migration)).to eq(true)
- expect(changes.has_category?(:changelog)).to eq(true)
- expect(changes.has_category?(:backend)).to eq(false)
- end
- end
-
- describe '#by_category' do
- it 'returns an array of Change objects' do
- expect(helper.changes.by_category(:migration)).to all(be_an(described_class::Change))
- end
-
- it 'returns an array of Change objects with the given category' do
- changes = helper.changes
-
- expect(changes.by_category(:migration).files).to eq(['db/migrate/foo'])
- expect(changes.by_category(:changelog).files).to eq(['ee/changelogs/unreleased/foo.yml'])
- expect(changes.by_category(:backend)).to be_empty
- end
- end
-
- describe '#categories' do
- it 'returns an array of category symbols' do
- expect(helper.changes.categories).to contain_exactly(:database, :migration, :changelog, :unknown)
- end
- end
-
- describe '#files' do
- it 'returns an array of files' do
- expect(helper.changes.files).to include(*added_files)
- end
- end
- end
-
- describe '#changes' do
- it 'returns an array of Change objects' do
- expect(helper.changes).to all(be_an(described_class::Change))
- end
-
- it 'groups changes by change type' do
- changes = helper.changes
-
- expect(changes.added.files).to eq(added_files)
- expect(changes.modified.files).to eq(modified_files)
- expect(changes.deleted.files).to eq(deleted_files)
- expect(changes.renamed_before.files).to eq([renamed_before_file])
- expect(changes.renamed_after.files).to eq([renamed_after_file])
- end
- end
-
- describe '#categories_for_file' do
- before do
- allow(fake_git).to receive(:diff_for_file).with('usage_data.rb') { double(:diff, patch: "+ count(User.active)") }
- end
-
- where(:path, :expected_categories) do
- 'usage_data.rb' | [:database, :backend]
- 'doc/foo.md' | [:docs]
- 'CONTRIBUTING.md' | [:docs]
- 'LICENSE' | [:docs]
- 'MAINTENANCE.md' | [:docs]
- 'PHILOSOPHY.md' | [:docs]
- 'PROCESS.md' | [:docs]
- 'README.md' | [:docs]
-
- 'ee/doc/foo' | [:unknown]
- 'ee/README' | [:unknown]
-
- 'app/assets/foo' | [:frontend]
- 'app/views/foo' | [:frontend]
- 'public/foo' | [:frontend]
- 'scripts/frontend/foo' | [:frontend]
- 'spec/javascripts/foo' | [:frontend]
- 'spec/frontend/bar' | [:frontend]
- 'vendor/assets/foo' | [:frontend]
- 'babel.config.js' | [:frontend]
- 'jest.config.js' | [:frontend]
- 'package.json' | [:frontend]
- 'yarn.lock' | [:frontend]
- 'config/foo.js' | [:frontend]
- 'config/deep/foo.js' | [:frontend]
-
- 'ee/app/assets/foo' | [:frontend]
- 'ee/app/views/foo' | [:frontend]
- 'ee/spec/javascripts/foo' | [:frontend]
- 'ee/spec/frontend/bar' | [:frontend]
-
- '.gitlab/ci/frontend.gitlab-ci.yml' | %i[frontend engineering_productivity]
-
- 'app/models/foo' | [:backend]
- 'bin/foo' | [:backend]
- 'config/foo' | [:backend]
- 'lib/foo' | [:backend]
- 'rubocop/foo' | [:backend]
- '.rubocop.yml' | [:backend]
- '.rubocop_todo.yml' | [:backend]
- '.rubocop_manual_todo.yml' | [:backend]
- 'spec/foo' | [:backend]
- 'spec/foo/bar' | [:backend]
-
- 'ee/app/foo' | [:backend]
- 'ee/bin/foo' | [:backend]
- 'ee/spec/foo' | [:backend]
- 'ee/spec/foo/bar' | [:backend]
-
- 'spec/features/foo' | [:test]
- 'ee/spec/features/foo' | [:test]
- 'spec/support/shared_examples/features/foo' | [:test]
- 'ee/spec/support/shared_examples/features/foo' | [:test]
- 'spec/support/shared_contexts/features/foo' | [:test]
- 'ee/spec/support/shared_contexts/features/foo' | [:test]
- 'spec/support/helpers/features/foo' | [:test]
- 'ee/spec/support/helpers/features/foo' | [:test]
-
- 'generator_templates/foo' | [:backend]
- 'vendor/languages.yml' | [:backend]
- 'file_hooks/examples/' | [:backend]
-
- 'Gemfile' | [:backend]
- 'Gemfile.lock' | [:backend]
- 'Rakefile' | [:backend]
- 'FOO_VERSION' | [:backend]
-
- 'Dangerfile' | [:engineering_productivity]
- 'danger/commit_messages/Dangerfile' | [:engineering_productivity]
- 'ee/danger/commit_messages/Dangerfile' | [:engineering_productivity]
- 'danger/commit_messages/' | [:engineering_productivity]
- 'ee/danger/commit_messages/' | [:engineering_productivity]
- '.gitlab-ci.yml' | [:engineering_productivity]
- '.gitlab/ci/cng.gitlab-ci.yml' | [:engineering_productivity]
- '.gitlab/ci/ee-specific-checks.gitlab-ci.yml' | [:engineering_productivity]
- 'scripts/foo' | [:engineering_productivity]
- 'tooling/danger/foo' | [:engineering_productivity]
- 'ee/tooling/danger/foo' | [:engineering_productivity]
- 'lefthook.yml' | [:engineering_productivity]
- '.editorconfig' | [:engineering_productivity]
- 'tooling/bin/find_foss_tests' | [:engineering_productivity]
- '.codeclimate.yml' | [:engineering_productivity]
- '.gitlab/CODEOWNERS' | [:engineering_productivity]
-
- 'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | [:ci_template]
- 'lib/gitlab/ci/templates/dotNET-Core.yml' | [:ci_template]
-
- 'ee/FOO_VERSION' | [:unknown]
-
- 'db/schema.rb' | [:database]
- 'db/structure.sql' | [:database]
- 'db/migrate/foo' | [:database, :migration]
- 'db/post_migrate/foo' | [:database, :migration]
- 'ee/db/geo/migrate/foo' | [:database, :migration]
- 'ee/db/geo/post_migrate/foo' | [:database, :migration]
- 'app/models/project_authorization.rb' | [:database]
- 'app/services/users/refresh_authorized_projects_service.rb' | [:database]
- 'lib/gitlab/background_migration.rb' | [:database]
- 'lib/gitlab/background_migration/foo' | [:database]
- 'ee/lib/gitlab/background_migration/foo' | [:database]
- 'lib/gitlab/database.rb' | [:database]
- 'lib/gitlab/database/foo' | [:database]
- 'ee/lib/gitlab/database/foo' | [:database]
- 'lib/gitlab/github_import.rb' | [:database]
- 'lib/gitlab/github_import/foo' | [:database]
- 'lib/gitlab/sql/foo' | [:database]
- 'rubocop/cop/migration/foo' | [:database]
-
- 'db/fixtures/foo.rb' | [:backend]
- 'ee/db/fixtures/foo.rb' | [:backend]
-
- 'qa/foo' | [:qa]
- 'ee/qa/foo' | [:qa]
-
- 'changelogs/foo' | [:none]
- 'ee/changelogs/foo' | [:none]
- 'locale/gitlab.pot' | [:none]
-
- 'FOO' | [:unknown]
- 'foo' | [:unknown]
-
- 'foo/bar.rb' | [:backend]
- 'foo/bar.js' | [:frontend]
- 'foo/bar.txt' | [:none]
- 'foo/bar.md' | [:none]
- end
-
- with_them do
- subject { helper.categories_for_file(path) }
-
- it { is_expected.to eq(expected_categories) }
- end
-
- context 'having specific changes' do
- where(:expected_categories, :patch, :changed_files) do
- [:database, :backend] | '+ count(User.active)' | ['usage_data.rb', 'lib/gitlab/usage_data.rb', 'ee/lib/ee/gitlab/usage_data.rb']
- [:database, :backend] | '+ estimate_batch_distinct_count(User.active)' | ['usage_data.rb']
- [:backend] | '+ alt_usage_data(User.active)' | ['usage_data.rb']
- [:backend] | '+ count(User.active)' | ['user.rb']
- [:backend] | '+ count(User.active)' | ['usage_data/topology.rb']
- [:backend] | '+ foo_count(User.active)' | ['usage_data.rb']
- end
-
- with_them do
- it 'has the correct categories' do
- changed_files.each do |file|
- allow(fake_git).to receive(:diff_for_file).with(file) { double(:diff, patch: patch) }
-
- expect(helper.categories_for_file(file)).to eq(expected_categories)
- end
- end
- end
- end
- end
-
- describe '#label_for_category' do
- where(:category, :expected_label) do
- :backend | '~backend'
- :database | '~database'
- :docs | '~documentation'
- :foo | '~foo'
- :frontend | '~frontend'
- :none | ''
- :qa | '~QA'
- :engineering_productivity | '~"Engineering Productivity" for CI, Danger'
- :ci_template | '~"ci::templates"'
- end
-
- with_them do
- subject { helper.label_for_category(category) }
-
- it { is_expected.to eq(expected_label) }
- end
- end
-
- describe '#new_teammates' do
- it 'returns an array of Teammate' do
- usernames = %w[filipa iamphil]
-
- teammates = helper.new_teammates(usernames)
-
- expect(teammates.map(&:username)).to eq(usernames)
- end
- end
-
- describe '#mr_iid' do
- it 'returns "" when `gitlab_helper` is unavailable' do
- expect(helper).to receive(:gitlab_helper).and_return(nil)
-
- expect(helper.mr_iid).to eq('')
- end
-
- it 'returns the MR IID when `gitlab_helper` is available' do
- mr_iid = '1234'
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('iid' => mr_iid)
-
- expect(helper.mr_iid).to eq(mr_iid)
- end
- end
-
- describe '#mr_title' do
- it 'returns "" when `gitlab_helper` is unavailable' do
- expect(helper).to receive(:gitlab_helper).and_return(nil)
-
- expect(helper.mr_title).to eq('')
- end
-
- it 'returns the MR title when `gitlab_helper` is available' do
- mr_title = 'My MR title'
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => mr_title)
-
- expect(helper.mr_title).to eq(mr_title)
- end
- end
-
- describe '#mr_web_url' do
- it 'returns "" when `gitlab_helper` is unavailable' do
- expect(helper).to receive(:gitlab_helper).and_return(nil)
-
- expect(helper.mr_web_url).to eq('')
- end
-
- it 'returns the MR web_url when `gitlab_helper` is available' do
- mr_web_url = 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1'
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('web_url' => mr_web_url)
-
- expect(helper.mr_web_url).to eq(mr_web_url)
- end
- end
-
- describe '#mr_labels' do
- it 'returns "" when `gitlab_helper` is unavailable' do
- expect(helper).to receive(:gitlab_helper).and_return(nil)
-
- expect(helper.mr_labels).to eq([])
- end
-
- it 'returns the MR labels when `gitlab_helper` is available' do
- mr_labels = %w[foo bar baz]
- expect(fake_gitlab).to receive(:mr_labels)
- .and_return(mr_labels)
-
- expect(helper.mr_labels).to eq(mr_labels)
- end
- end
-
- describe '#mr_target_branch' do
- it 'returns "" when `gitlab_helper` is unavailable' do
- expect(helper).to receive(:gitlab_helper).and_return(nil)
-
- expect(helper.mr_target_branch).to eq('')
- end
-
- it 'returns the MR web_url when `gitlab_helper` is available' do
- mr_target_branch = 'main'
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('target_branch' => mr_target_branch)
-
- expect(helper.mr_target_branch).to eq(mr_target_branch)
- end
- end
-
- describe '#security_mr?' do
- it 'returns false when on a normal merge request' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('web_url' => 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1')
-
- expect(helper).not_to be_security_mr
- end
-
- it 'returns true when on a security merge request' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('web_url' => 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/1')
-
- expect(helper).to be_security_mr
- end
- end
-
- describe '#draft_mr?' do
- it 'returns true for a draft MR' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => 'Draft: My MR title')
-
- expect(helper).to be_draft_mr
- end
-
- it 'returns false for non draft MR' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => 'My MR title')
-
- expect(helper).not_to be_draft_mr
- end
- end
-
- describe '#cherry_pick_mr?' do
- context 'when MR title does not mention a cherry-pick' do
- it 'returns false' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => 'Add feature xyz')
-
- expect(helper).not_to be_cherry_pick_mr
- end
- end
-
- context 'when MR title mentions a cherry-pick' do
- [
- 'Cherry Pick !1234',
- 'cherry-pick !1234',
- 'CherryPick !1234'
- ].each do |mr_title|
- it 'returns true' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => mr_title)
-
- expect(helper).to be_cherry_pick_mr
- end
- end
- end
- end
-
- describe '#run_all_rspec_mr?' do
- context 'when MR title does not mention RUN ALL RSPEC' do
- it 'returns false' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => 'Add feature xyz')
-
- expect(helper).not_to be_run_all_rspec_mr
- end
- end
-
- context 'when MR title mentions RUN ALL RSPEC' do
- it 'returns true' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => 'Add feature xyz RUN ALL RSPEC')
-
- expect(helper).to be_run_all_rspec_mr
- end
- end
- end
-
- describe '#run_as_if_foss_mr?' do
- context 'when MR title does not mention RUN AS-IF-FOSS' do
- it 'returns false' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => 'Add feature xyz')
-
- expect(helper).not_to be_run_as_if_foss_mr
- end
- end
-
- context 'when MR title mentions RUN AS-IF-FOSS' do
- it 'returns true' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('title' => 'Add feature xyz RUN AS-IF-FOSS')
-
- expect(helper).to be_run_as_if_foss_mr
- end
- end
- end
-
- describe '#stable_branch?' do
- it 'returns false when `gitlab_helper` is unavailable' do
- expect(helper).to receive(:gitlab_helper).and_return(nil)
-
- expect(helper).not_to be_stable_branch
- end
-
- context 'when MR target branch is not a stable branch' do
- it 'returns false' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('target_branch' => 'my-feature-branch')
-
- expect(helper).not_to be_stable_branch
- end
- end
-
- context 'when MR target branch is a stable branch' do
- %w[
- 13-1-stable-ee
- 13-1-stable-ee-patch-1
- ].each do |target_branch|
- it 'returns true' do
- expect(fake_gitlab).to receive(:mr_json)
- .and_return('target_branch' => target_branch)
-
- expect(helper).to be_stable_branch
- end
- end
- end
- end
-
- describe '#mr_has_label?' do
- it 'returns false when `gitlab_helper` is unavailable' do
- expect(helper).to receive(:gitlab_helper).and_return(nil)
-
- expect(helper.mr_has_labels?('telemetry')).to be_falsey
- end
-
- context 'when mr has labels' do
- before do
- mr_labels = ['telemetry', 'telemetry::reviewed']
- expect(fake_gitlab).to receive(:mr_labels).and_return(mr_labels)
- end
-
- it 'returns true with a matched label' do
- expect(helper.mr_has_labels?('telemetry')).to be_truthy
- end
-
- it 'returns false with unmatched label' do
- expect(helper.mr_has_labels?('database')).to be_falsey
- end
-
- it 'returns true with an array of labels' do
- expect(helper.mr_has_labels?(['telemetry', 'telemetry::reviewed'])).to be_truthy
- end
-
- it 'returns true with multi arguments with matched labels' do
- expect(helper.mr_has_labels?('telemetry', 'telemetry::reviewed')).to be_truthy
- end
-
- it 'returns false with multi arguments with unmatched labels' do
- expect(helper.mr_has_labels?('telemetry', 'telemetry::non existing')).to be_falsey
- end
- end
- end
-
- describe '#labels_list' do
- let(:labels) { ['telemetry', 'telemetry::reviewed'] }
-
- it 'composes the labels string' do
- expect(helper.labels_list(labels)).to eq('~"telemetry", ~"telemetry::reviewed"')
- end
-
- context 'when passing a separator' do
- it 'composes the labels string with the given separator' do
- expect(helper.labels_list(labels, sep: ' ')).to eq('~"telemetry" ~"telemetry::reviewed"')
- end
- end
-
- it 'returns empty string for empty array' do
- expect(helper.labels_list([])).to eq('')
- end
- end
-
- describe '#prepare_labels_for_mr' do
- it 'composes the labels string' do
- mr_labels = ['telemetry', 'telemetry::reviewed']
-
- expect(helper.prepare_labels_for_mr(mr_labels)).to eq('/label ~"telemetry" ~"telemetry::reviewed"')
- end
-
- it 'returns empty string for empty array' do
- expect(helper.prepare_labels_for_mr([])).to eq('')
- end
- end
-
- describe '#has_ci_changes?' do
- context 'when .gitlab/ci is changed' do
- it 'returns true' do
- expect(helper).to receive(:all_changed_files).and_return(%w[migration.rb .gitlab/ci/test.yml])
-
- expect(helper.has_ci_changes?).to be_truthy
- end
- end
-
- context 'when .gitlab-ci.yml is changed' do
- it 'returns true' do
- expect(helper).to receive(:all_changed_files).and_return(%w[migration.rb .gitlab-ci.yml])
-
- expect(helper.has_ci_changes?).to be_truthy
- end
- end
-
- context 'when neither .gitlab/ci/ or .gitlab-ci.yml is changed' do
- it 'returns false' do
- expect(helper).to receive(:all_changed_files).and_return(%w[migration.rb nested/.gitlab-ci.yml])
-
- expect(helper.has_ci_changes?).to be_falsey
- end
- end
- end
-
- describe '#group_label' do
- it 'returns nil when no group label is present' do
- expect(helper.group_label(%w[foo bar])).to be_nil
- end
-
- it 'returns the group label when a group label is present' do
- expect(helper.group_label(['foo', 'group::source code', 'bar'])).to eq('group::source code')
- end
- end
-end
diff --git a/spec/tooling/danger/merge_request_linter_spec.rb b/spec/tooling/danger/merge_request_linter_spec.rb
deleted file mode 100644
index 3273b6b3d07..00000000000
--- a/spec/tooling/danger/merge_request_linter_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# frozen_string_literal: true
-
-require 'rspec-parameterized'
-require_relative 'danger_spec_helper'
-
-require_relative '../../../tooling/danger/merge_request_linter'
-
-RSpec.describe Tooling::Danger::MergeRequestLinter do
- using RSpec::Parameterized::TableSyntax
-
- let(:mr_class) do
- Struct.new(:message, :sha, :diff_parent)
- end
-
- let(:mr_title) { 'A B ' + 'C' }
- let(:merge_request) { mr_class.new(mr_title, anything, anything) }
-
- describe '#lint_subject' do
- subject(:mr_linter) { described_class.new(merge_request) }
-
- shared_examples 'a valid mr title' do
- it 'does not have any problem' do
- mr_linter.lint
-
- expect(mr_linter.problems).to be_empty
- end
- end
-
- context 'when subject valid' do
- it_behaves_like 'a valid mr title'
- end
-
- context 'when it is too long' do
- let(:mr_title) { 'A B ' + 'C' * described_class::MAX_LINE_LENGTH }
-
- it 'adds a problem' do
- expect(mr_linter).to receive(:add_problem).with(:subject_too_long, described_class.subject_description)
-
- mr_linter.lint
- end
- end
-
- describe 'using magic mr run options' do
- where(run_option: described_class.mr_run_options_regex.split('|') +
- described_class.mr_run_options_regex.split('|').map! { |x| "[#{x}]" })
-
- with_them do
- let(:mr_title) { run_option + ' A B ' + 'C' * (described_class::MAX_LINE_LENGTH - 5) }
-
- it_behaves_like 'a valid mr title'
- end
- end
- end
-end
diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb
new file mode 100644
index 00000000000..ff4afcf6863
--- /dev/null
+++ b/spec/tooling/danger/project_helper_spec.rb
@@ -0,0 +1,260 @@
+# frozen_string_literal: true
+
+require 'rspec-parameterized'
+require 'gitlab-dangerfiles'
+require 'danger/helper'
+require 'gitlab/dangerfiles/spec_helper'
+
+require_relative '../../../danger/plugins/project_helper'
+
+RSpec.describe Tooling::Danger::ProjectHelper do
+ include_context "with dangerfile"
+
+ let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+ let(:fake_helper) { Danger::Helper.new(project_helper) }
+
+ subject(:project_helper) { fake_danger.new(git: fake_git) }
+
+ before do
+ allow(project_helper).to receive(:helper).and_return(fake_helper)
+ end
+
+ describe '#changes' do
+ it 'returns an array of Change objects' do
+ expect(project_helper.changes).to all(be_an(Gitlab::Dangerfiles::Change))
+ end
+
+ it 'groups changes by change type' do
+ changes = project_helper.changes
+
+ expect(changes.added.files).to eq(added_files)
+ expect(changes.modified.files).to eq(modified_files)
+ expect(changes.deleted.files).to eq(deleted_files)
+ expect(changes.renamed_before.files).to eq([renamed_before_file])
+ expect(changes.renamed_after.files).to eq([renamed_after_file])
+ end
+ end
+
+ describe '#categories_for_file' do
+ using RSpec::Parameterized::TableSyntax
+
+ before do
+ allow(fake_git).to receive(:diff_for_file).with('usage_data.rb') { double(:diff, patch: "+ count(User.active)") }
+ end
+
+ where(:path, :expected_categories) do
+ 'usage_data.rb' | [:database, :backend]
+ 'doc/foo.md' | [:docs]
+ 'CONTRIBUTING.md' | [:docs]
+ 'LICENSE' | [:docs]
+ 'MAINTENANCE.md' | [:docs]
+ 'PHILOSOPHY.md' | [:docs]
+ 'PROCESS.md' | [:docs]
+ 'README.md' | [:docs]
+
+ 'ee/doc/foo' | [:unknown]
+ 'ee/README' | [:unknown]
+
+ 'app/assets/foo' | [:frontend]
+ 'app/views/foo' | [:frontend]
+ 'public/foo' | [:frontend]
+ 'scripts/frontend/foo' | [:frontend]
+ 'spec/javascripts/foo' | [:frontend]
+ 'spec/frontend/bar' | [:frontend]
+ 'vendor/assets/foo' | [:frontend]
+ 'babel.config.js' | [:frontend]
+ 'jest.config.js' | [:frontend]
+ 'package.json' | [:frontend]
+ 'yarn.lock' | [:frontend]
+ 'config/foo.js' | [:frontend]
+ 'config/deep/foo.js' | [:frontend]
+
+ 'ee/app/assets/foo' | [:frontend]
+ 'ee/app/views/foo' | [:frontend]
+ 'ee/spec/javascripts/foo' | [:frontend]
+ 'ee/spec/frontend/bar' | [:frontend]
+
+ '.gitlab/ci/frontend.gitlab-ci.yml' | %i[frontend engineering_productivity]
+
+ 'app/models/foo' | [:backend]
+ 'bin/foo' | [:backend]
+ 'config/foo' | [:backend]
+ 'lib/foo' | [:backend]
+ 'rubocop/foo' | [:backend]
+ '.rubocop.yml' | [:backend]
+ '.rubocop_todo.yml' | [:backend]
+ '.rubocop_manual_todo.yml' | [:backend]
+ 'spec/foo' | [:backend]
+ 'spec/foo/bar' | [:backend]
+
+ 'ee/app/foo' | [:backend]
+ 'ee/bin/foo' | [:backend]
+ 'ee/spec/foo' | [:backend]
+ 'ee/spec/foo/bar' | [:backend]
+
+ 'spec/features/foo' | [:test]
+ 'ee/spec/features/foo' | [:test]
+ 'spec/support/shared_examples/features/foo' | [:test]
+ 'ee/spec/support/shared_examples/features/foo' | [:test]
+ 'spec/support/shared_contexts/features/foo' | [:test]
+ 'ee/spec/support/shared_contexts/features/foo' | [:test]
+ 'spec/support/helpers/features/foo' | [:test]
+ 'ee/spec/support/helpers/features/foo' | [:test]
+
+ 'generator_templates/foo' | [:backend]
+ 'vendor/languages.yml' | [:backend]
+ 'file_hooks/examples/' | [:backend]
+
+ 'Gemfile' | [:backend]
+ 'Gemfile.lock' | [:backend]
+ 'Rakefile' | [:backend]
+ 'FOO_VERSION' | [:backend]
+
+ 'Dangerfile' | [:engineering_productivity]
+ 'danger/commit_messages/Dangerfile' | [:engineering_productivity]
+ 'ee/danger/commit_messages/Dangerfile' | [:engineering_productivity]
+ 'danger/commit_messages/' | [:engineering_productivity]
+ 'ee/danger/commit_messages/' | [:engineering_productivity]
+ '.gitlab-ci.yml' | [:engineering_productivity]
+ '.gitlab/ci/cng.gitlab-ci.yml' | [:engineering_productivity]
+ '.gitlab/ci/ee-specific-checks.gitlab-ci.yml' | [:engineering_productivity]
+ 'scripts/foo' | [:engineering_productivity]
+ 'tooling/danger/foo' | [:engineering_productivity]
+ 'ee/tooling/danger/foo' | [:engineering_productivity]
+ 'lefthook.yml' | [:engineering_productivity]
+ '.editorconfig' | [:engineering_productivity]
+ 'tooling/bin/find_foss_tests' | [:engineering_productivity]
+ '.codeclimate.yml' | [:engineering_productivity]
+ '.gitlab/CODEOWNERS' | [:engineering_productivity]
+
+ 'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | [:ci_template]
+ 'lib/gitlab/ci/templates/dotNET-Core.yml' | [:ci_template]
+
+ 'ee/FOO_VERSION' | [:unknown]
+
+ 'db/schema.rb' | [:database]
+ 'db/structure.sql' | [:database]
+ 'db/migrate/foo' | [:database, :migration]
+ 'db/post_migrate/foo' | [:database, :migration]
+ 'ee/db/geo/migrate/foo' | [:database, :migration]
+ 'ee/db/geo/post_migrate/foo' | [:database, :migration]
+ 'app/models/project_authorization.rb' | [:database]
+ 'app/services/users/refresh_authorized_projects_service.rb' | [:database]
+ 'lib/gitlab/background_migration.rb' | [:database]
+ 'lib/gitlab/background_migration/foo' | [:database]
+ 'ee/lib/gitlab/background_migration/foo' | [:database]
+ 'lib/gitlab/database.rb' | [:database]
+ 'lib/gitlab/database/foo' | [:database]
+ 'ee/lib/gitlab/database/foo' | [:database]
+ 'lib/gitlab/github_import.rb' | [:database]
+ 'lib/gitlab/github_import/foo' | [:database]
+ 'lib/gitlab/sql/foo' | [:database]
+ 'rubocop/cop/migration/foo' | [:database]
+
+ 'db/fixtures/foo.rb' | [:backend]
+ 'ee/db/fixtures/foo.rb' | [:backend]
+
+ 'qa/foo' | [:qa]
+ 'ee/qa/foo' | [:qa]
+
+ 'changelogs/foo' | [:none]
+ 'ee/changelogs/foo' | [:none]
+ 'locale/gitlab.pot' | [:none]
+
+ 'FOO' | [:unknown]
+ 'foo' | [:unknown]
+
+ 'foo/bar.rb' | [:backend]
+ 'foo/bar.js' | [:frontend]
+ 'foo/bar.txt' | [:none]
+ 'foo/bar.md' | [:none]
+ end
+
+ with_them do
+ subject { project_helper.categories_for_file(path) }
+
+ it { is_expected.to eq(expected_categories) }
+ end
+
+ context 'having specific changes' do
+ where(:expected_categories, :patch, :changed_files) do
+ [:database, :backend] | '+ count(User.active)' | ['usage_data.rb', 'lib/gitlab/usage_data.rb', 'ee/lib/ee/gitlab/usage_data.rb']
+ [:database, :backend] | '+ estimate_batch_distinct_count(User.active)' | ['usage_data.rb']
+ [:backend] | '+ alt_usage_data(User.active)' | ['usage_data.rb']
+ [:backend] | '+ count(User.active)' | ['user.rb']
+ [:backend] | '+ count(User.active)' | ['usage_data/topology.rb']
+ [:backend] | '+ foo_count(User.active)' | ['usage_data.rb']
+ end
+
+ with_them do
+ it 'has the correct categories' do
+ changed_files.each do |file|
+ allow(fake_git).to receive(:diff_for_file).with(file) { double(:diff, patch: patch) }
+
+ expect(project_helper.categories_for_file(file)).to eq(expected_categories)
+ end
+ end
+ end
+ end
+ end
+
+ describe '.local_warning_message' do
+ it 'returns an informational message with rules that can run' do
+ expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changes_size, commit_messages, database, documentation, duplicate_yarn_dependencies, eslint, karma, pajamas, pipeline, prettier, product_intelligence, utility_css')
+ end
+ end
+
+ describe '.success_message' do
+ it 'returns an informational success message' do
+ expect(described_class.success_message).to eq('==> No Danger rule violations!')
+ end
+ end
+
+ describe '#rule_names' do
+ context 'when running locally' do
+ before do
+ expect(fake_helper).to receive(:ci?).and_return(false)
+ end
+
+ it 'returns local only rules' do
+ expect(project_helper.rule_names).to match_array(described_class::LOCAL_RULES)
+ end
+ end
+
+ context 'when running under CI' do
+ before do
+ expect(fake_helper).to receive(:ci?).and_return(true)
+ end
+
+ it 'returns all rules' do
+ expect(project_helper.rule_names).to eq(described_class::LOCAL_RULES | described_class::CI_ONLY_RULES)
+ end
+ end
+ end
+
+ describe '#all_ee_changes' do
+ subject { project_helper.all_ee_changes }
+
+ it 'returns all changed files starting with ee/' do
+ expect(project_helper).to receive(:all_changed_files).and_return(%w[fr/ee/beer.rb ee/wine.rb ee/lib/ido.rb ee.k])
+
+ is_expected.to match_array(%w[ee/wine.rb ee/lib/ido.rb])
+ end
+ end
+
+ describe '#project_name' do
+ subject { project_helper.project_name }
+
+ it 'returns gitlab if ee? returns true' do
+ expect(project_helper).to receive(:ee?) { true }
+
+ is_expected.to eq('gitlab')
+ end
+
+ it 'returns gitlab-ce if ee? returns false' do
+ expect(project_helper).to receive(:ee?) { false }
+
+ is_expected.to eq('gitlab-foss')
+ end
+ end
+end
diff --git a/spec/tooling/danger/roulette_spec.rb b/spec/tooling/danger/roulette_spec.rb
deleted file mode 100644
index 1e500a1ed08..00000000000
--- a/spec/tooling/danger/roulette_spec.rb
+++ /dev/null
@@ -1,429 +0,0 @@
-# frozen_string_literal: true
-
-require 'webmock/rspec'
-require 'timecop'
-
-require_relative '../../../tooling/danger/roulette'
-require 'active_support/testing/time_helpers'
-
-RSpec.describe Tooling::Danger::Roulette do
- include ActiveSupport::Testing::TimeHelpers
-
- around do |example|
- travel_to(Time.utc(2020, 06, 22, 10)) { example.run }
- end
-
- let(:backend_available) { true }
- let(:backend_tz_offset_hours) { 2.0 }
- let(:backend_maintainer) do
- Tooling::Danger::Teammate.new(
- 'username' => 'backend-maintainer',
- 'name' => 'Backend maintainer',
- 'role' => 'Backend engineer',
- 'projects' => { 'gitlab' => 'maintainer backend' },
- 'available' => backend_available,
- 'tz_offset_hours' => backend_tz_offset_hours
- )
- end
-
- let(:frontend_reviewer) do
- Tooling::Danger::Teammate.new(
- 'username' => 'frontend-reviewer',
- 'name' => 'Frontend reviewer',
- 'role' => 'Frontend engineer',
- 'projects' => { 'gitlab' => 'reviewer frontend' },
- 'available' => true,
- 'tz_offset_hours' => 2.0
- )
- end
-
- let(:frontend_maintainer) do
- Tooling::Danger::Teammate.new(
- 'username' => 'frontend-maintainer',
- 'name' => 'Frontend maintainer',
- 'role' => 'Frontend engineer',
- 'projects' => { 'gitlab' => "maintainer frontend" },
- 'available' => true,
- 'tz_offset_hours' => 2.0
- )
- end
-
- let(:software_engineer_in_test) do
- Tooling::Danger::Teammate.new(
- 'username' => 'software-engineer-in-test',
- 'name' => 'Software Engineer in Test',
- 'role' => 'Software Engineer in Test, Create:Source Code',
- 'projects' => { 'gitlab' => 'maintainer qa', 'gitlab-qa' => 'maintainer' },
- 'available' => true,
- 'tz_offset_hours' => 2.0
- )
- end
-
- let(:engineering_productivity_reviewer) do
- Tooling::Danger::Teammate.new(
- 'username' => 'eng-prod-reviewer',
- 'name' => 'EP engineer',
- 'role' => 'Engineering Productivity',
- 'projects' => { 'gitlab' => 'reviewer backend' },
- 'available' => true,
- 'tz_offset_hours' => 2.0
- )
- end
-
- let(:ci_template_reviewer) do
- Tooling::Danger::Teammate.new(
- 'username' => 'ci-template-maintainer',
- 'name' => 'CI Template engineer',
- 'role' => '~"ci::templates"',
- 'projects' => { 'gitlab' => 'reviewer ci_template' },
- 'available' => true,
- 'tz_offset_hours' => 2.0
- )
- end
-
- let(:teammates) do
- [
- backend_maintainer.to_h,
- frontend_maintainer.to_h,
- frontend_reviewer.to_h,
- software_engineer_in_test.to_h,
- engineering_productivity_reviewer.to_h,
- ci_template_reviewer.to_h
- ]
- end
-
- let(:teammate_json) do
- teammates.to_json
- end
-
- subject(:roulette) { Object.new.extend(described_class) }
-
- describe 'Spin#==' do
- it 'compares Spin attributes' do
- spin1 = described_class::Spin.new(:backend, frontend_reviewer, frontend_maintainer, false, false)
- spin2 = described_class::Spin.new(:backend, frontend_reviewer, frontend_maintainer, false, false)
- spin3 = described_class::Spin.new(:backend, frontend_reviewer, frontend_maintainer, false, true)
- spin4 = described_class::Spin.new(:backend, frontend_reviewer, frontend_maintainer, true, false)
- spin5 = described_class::Spin.new(:backend, frontend_reviewer, backend_maintainer, false, false)
- spin6 = described_class::Spin.new(:backend, backend_maintainer, frontend_maintainer, false, false)
- spin7 = described_class::Spin.new(:frontend, frontend_reviewer, frontend_maintainer, false, false)
-
- expect(spin1).to eq(spin2)
- expect(spin1).not_to eq(spin3)
- expect(spin1).not_to eq(spin4)
- expect(spin1).not_to eq(spin5)
- expect(spin1).not_to eq(spin6)
- expect(spin1).not_to eq(spin7)
- end
- end
-
- describe '#spin' do
- let!(:project) { 'gitlab' }
- let!(:mr_source_branch) { 'a-branch' }
- let!(:mr_labels) { ['backend', 'devops::create'] }
- let!(:author) { Tooling::Danger::Teammate.new('username' => 'johndoe') }
- let(:timezone_experiment) { false }
- let(:spins) do
- # Stub the request at the latest time so that we can modify the raw data, e.g. available fields.
- WebMock
- .stub_request(:get, described_class::ROULETTE_DATA_URL)
- .to_return(body: teammate_json)
-
- subject.spin(project, categories, timezone_experiment: timezone_experiment)
- end
-
- before do
- allow(subject).to receive(:mr_author_username).and_return(author.username)
- allow(subject).to receive(:mr_labels).and_return(mr_labels)
- allow(subject).to receive(:mr_source_branch).and_return(mr_source_branch)
- end
-
- context 'when timezone_experiment == false' do
- context 'when change contains backend category' do
- let(:categories) { [:backend] }
-
- it 'assigns backend reviewer and maintainer' do
- expect(spins[0].reviewer).to eq(engineering_productivity_reviewer)
- expect(spins[0].maintainer).to eq(backend_maintainer)
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, backend_maintainer, false, false)])
- end
-
- context 'when teammate is not available' do
- let(:backend_available) { false }
-
- it 'assigns backend reviewer and no maintainer' do
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, nil, false, false)])
- end
- end
- end
-
- context 'when change contains frontend category' do
- let(:categories) { [:frontend] }
-
- it 'assigns frontend reviewer and maintainer' do
- expect(spins).to eq([described_class::Spin.new(:frontend, frontend_reviewer, frontend_maintainer, false, false)])
- end
- end
-
- context 'when change contains many categories' do
- let(:categories) { [:frontend, :test, :qa, :engineering_productivity, :ci_template, :backend] }
-
- it 'has a deterministic sorting order' do
- expect(spins.map(&:category)).to eq categories.sort
- end
- end
-
- context 'when change contains QA category' do
- let(:categories) { [:qa] }
-
- it 'assigns QA maintainer' do
- expect(spins).to eq([described_class::Spin.new(:qa, nil, software_engineer_in_test, false, false)])
- end
- end
-
- context 'when change contains QA category and another category' do
- let(:categories) { [:backend, :qa] }
-
- it 'assigns QA maintainer' do
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, backend_maintainer, false, false), described_class::Spin.new(:qa, nil, software_engineer_in_test, :maintainer, false)])
- end
-
- context 'and author is an SET' do
- let!(:author) { Tooling::Danger::Teammate.new('username' => software_engineer_in_test.username) }
-
- it 'assigns QA reviewer' do
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, backend_maintainer, false, false), described_class::Spin.new(:qa, nil, nil, false, false)])
- end
- end
- end
-
- context 'when change contains Engineering Productivity category' do
- let(:categories) { [:engineering_productivity] }
-
- it 'assigns Engineering Productivity reviewer and fallback to backend maintainer' do
- expect(spins).to eq([described_class::Spin.new(:engineering_productivity, engineering_productivity_reviewer, backend_maintainer, false, false)])
- end
- end
-
- context 'when change contains CI/CD Template category' do
- let(:categories) { [:ci_template] }
-
- it 'assigns CI/CD Template reviewer and fallback to backend maintainer' do
- expect(spins).to eq([described_class::Spin.new(:ci_template, ci_template_reviewer, backend_maintainer, false, false)])
- end
- end
-
- context 'when change contains test category' do
- let(:categories) { [:test] }
-
- it 'assigns corresponding SET' do
- expect(spins).to eq([described_class::Spin.new(:test, software_engineer_in_test, nil, :maintainer, false)])
- end
- end
- end
-
- context 'when timezone_experiment == true' do
- let(:timezone_experiment) { true }
-
- context 'when change contains backend category' do
- let(:categories) { [:backend] }
-
- it 'assigns backend reviewer and maintainer' do
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, backend_maintainer, false, true)])
- end
-
- context 'when teammate is not in a good timezone' do
- let(:backend_tz_offset_hours) { 5.0 }
-
- it 'assigns backend reviewer and no maintainer' do
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, nil, false, true)])
- end
- end
- end
-
- context 'when change includes a category with timezone disabled' do
- let(:categories) { [:backend] }
-
- before do
- stub_const("#{described_class}::INCLUDE_TIMEZONE_FOR_CATEGORY", backend: false)
- end
-
- it 'assigns backend reviewer and maintainer' do
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, backend_maintainer, false, false)])
- end
-
- context 'when teammate is not in a good timezone' do
- let(:backend_tz_offset_hours) { 5.0 }
-
- it 'assigns backend reviewer and maintainer' do
- expect(spins).to eq([described_class::Spin.new(:backend, engineering_productivity_reviewer, backend_maintainer, false, false)])
- end
- end
- end
- end
- end
-
- RSpec::Matchers.define :match_teammates do |expected|
- match do |actual|
- expected.each do |expected_person|
- actual_person_found = actual.find { |actual_person| actual_person.name == expected_person.username }
-
- actual_person_found &&
- actual_person_found.name == expected_person.name &&
- actual_person_found.role == expected_person.role &&
- actual_person_found.projects == expected_person.projects
- end
- end
- end
-
- describe '#team' do
- subject(:team) { roulette.team }
-
- context 'HTTP failure' do
- before do
- WebMock
- .stub_request(:get, described_class::ROULETTE_DATA_URL)
- .to_return(status: 404)
- end
-
- it 'raises a pretty error' do
- expect { team }.to raise_error(/Failed to read/)
- end
- end
-
- context 'JSON failure' do
- before do
- WebMock
- .stub_request(:get, described_class::ROULETTE_DATA_URL)
- .to_return(body: 'INVALID JSON')
- end
-
- it 'raises a pretty error' do
- expect { team }.to raise_error(/Failed to parse/)
- end
- end
-
- context 'success' do
- before do
- WebMock
- .stub_request(:get, described_class::ROULETTE_DATA_URL)
- .to_return(body: teammate_json)
- end
-
- it 'returns an array of teammates' do
- is_expected.to match_teammates([
- backend_maintainer,
- frontend_reviewer,
- frontend_maintainer,
- software_engineer_in_test,
- engineering_productivity_reviewer,
- ci_template_reviewer
- ])
- end
-
- it 'memoizes the result' do
- expect(team.object_id).to eq(roulette.team.object_id)
- end
- end
- end
-
- describe '#project_team' do
- subject { roulette.project_team('gitlab-qa') }
-
- before do
- WebMock
- .stub_request(:get, described_class::ROULETTE_DATA_URL)
- .to_return(body: teammate_json)
- end
-
- it 'filters team by project_name' do
- is_expected.to match_teammates([
- software_engineer_in_test
- ])
- end
- end
-
- describe '#spin_for_person' do
- let(:person_tz_offset_hours) { 0.0 }
- let(:person1) do
- Tooling::Danger::Teammate.new(
- 'username' => 'user1',
- 'available' => true,
- 'tz_offset_hours' => person_tz_offset_hours
- )
- end
-
- let(:person2) do
- Tooling::Danger::Teammate.new(
- 'username' => 'user2',
- 'available' => true,
- 'tz_offset_hours' => person_tz_offset_hours)
- end
-
- let(:author) do
- Tooling::Danger::Teammate.new(
- 'username' => 'johndoe',
- 'available' => true,
- 'tz_offset_hours' => 0.0)
- end
-
- let(:unavailable) do
- Tooling::Danger::Teammate.new(
- 'username' => 'janedoe',
- 'available' => false,
- 'tz_offset_hours' => 0.0)
- end
-
- before do
- allow(subject).to receive(:mr_author_username).and_return(author.username)
- end
-
- (-4..4).each do |utc_offset|
- context "when local hour for person is #{10 + utc_offset} (offset: #{utc_offset})" do
- let(:person_tz_offset_hours) { utc_offset }
-
- [false, true].each do |timezone_experiment|
- context "with timezone_experiment == #{timezone_experiment}" do
- it 'returns a random person' do
- persons = [person1, person2]
-
- selected = subject.spin_for_person(persons, random: Random.new, timezone_experiment: timezone_experiment)
-
- expect(persons.map(&:username)).to include(selected.username)
- end
- end
- end
- end
- end
-
- ((-12..-5).to_a + (5..12).to_a).each do |utc_offset|
- context "when local hour for person is #{10 + utc_offset} (offset: #{utc_offset})" do
- let(:person_tz_offset_hours) { utc_offset }
-
- [false, true].each do |timezone_experiment|
- context "with timezone_experiment == #{timezone_experiment}" do
- it 'returns a random person or nil' do
- persons = [person1, person2]
-
- selected = subject.spin_for_person(persons, random: Random.new, timezone_experiment: timezone_experiment)
-
- if timezone_experiment
- expect(selected).to be_nil
- else
- expect(persons.map(&:username)).to include(selected.username)
- end
- end
- end
- end
- end
- end
-
- it 'excludes unavailable persons' do
- expect(subject.spin_for_person([unavailable], random: Random.new)).to be_nil
- end
-
- it 'excludes mr.author' do
- expect(subject.spin_for_person([author], random: Random.new)).to be_nil
- end
- end
-end
diff --git a/spec/tooling/danger/sidekiq_queues_spec.rb b/spec/tooling/danger/sidekiq_queues_spec.rb
index c5fc8592621..9bffc7ee93d 100644
--- a/spec/tooling/danger/sidekiq_queues_spec.rb
+++ b/spec/tooling/danger/sidekiq_queues_spec.rb
@@ -1,20 +1,21 @@
# frozen_string_literal: true
require 'rspec-parameterized'
-require_relative 'danger_spec_helper'
+require 'gitlab-dangerfiles'
+require 'gitlab/dangerfiles/spec_helper'
require_relative '../../../tooling/danger/sidekiq_queues'
RSpec.describe Tooling::Danger::SidekiqQueues do
- using RSpec::Parameterized::TableSyntax
- include DangerSpecHelper
+ include_context "with dangerfile"
- let(:fake_git) { double('fake-git') }
- let(:fake_danger) { new_fake_danger.include(described_class) }
+ let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
subject(:sidekiq_queues) { fake_danger.new(git: fake_git) }
describe '#changed_queue_files' do
+ using RSpec::Parameterized::TableSyntax
+
where(:modified_files, :changed_queue_files) do
%w(app/workers/all_queues.yml ee/app/workers/all_queues.yml foo) | %w(app/workers/all_queues.yml ee/app/workers/all_queues.yml)
%w(app/workers/all_queues.yml ee/app/workers/all_queues.yml) | %w(app/workers/all_queues.yml ee/app/workers/all_queues.yml)
diff --git a/spec/tooling/danger/teammate_spec.rb b/spec/tooling/danger/teammate_spec.rb
deleted file mode 100644
index f3afdc6e912..00000000000
--- a/spec/tooling/danger/teammate_spec.rb
+++ /dev/null
@@ -1,225 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../../tooling/danger/teammate'
-require 'active_support/testing/time_helpers'
-require 'rspec-parameterized'
-
-RSpec.describe Tooling::Danger::Teammate do
- using RSpec::Parameterized::TableSyntax
-
- subject { described_class.new(options) }
-
- let(:tz_offset_hours) { 2.0 }
- let(:options) do
- {
- 'username' => 'luigi',
- 'projects' => projects,
- 'role' => role,
- 'markdown_name' => '[Luigi](https://gitlab.com/luigi) (`@luigi`)',
- 'tz_offset_hours' => tz_offset_hours
- }
- end
-
- let(:capabilities) { ['reviewer backend'] }
- let(:projects) { { project => capabilities } }
- let(:role) { 'Engineer, Manage' }
- let(:labels) { [] }
- let(:project) { double }
-
- describe '#==' do
- it 'compares Teammate username' do
- joe1 = described_class.new('username' => 'joe', 'projects' => projects)
- joe2 = described_class.new('username' => 'joe', 'projects' => [])
- jane1 = described_class.new('username' => 'jane', 'projects' => projects)
- jane2 = described_class.new('username' => 'jane', 'projects' => [])
-
- expect(joe1).to eq(joe2)
- expect(jane1).to eq(jane2)
- expect(jane1).not_to eq(nil)
- expect(described_class.new('username' => nil)).not_to eq(nil)
- end
- end
-
- describe '#to_h' do
- it 'returns the given options' do
- expect(subject.to_h).to eq(options)
- end
- end
-
- context 'when having multiple capabilities' do
- let(:capabilities) { ['reviewer backend', 'maintainer frontend', 'trainee_maintainer qa'] }
-
- it '#any_capability? returns true if the person has any capability for the category in the given project' do
- expect(subject.any_capability?(project, :backend)).to be_truthy
- expect(subject.any_capability?(project, :frontend)).to be_truthy
- expect(subject.any_capability?(project, :qa)).to be_truthy
- expect(subject.any_capability?(project, :engineering_productivity)).to be_falsey
- end
-
- it '#reviewer? supports multiple roles per project' do
- expect(subject.reviewer?(project, :backend, labels)).to be_truthy
- end
-
- it '#traintainer? supports multiple roles per project' do
- expect(subject.traintainer?(project, :qa, labels)).to be_truthy
- end
-
- it '#maintainer? supports multiple roles per project' do
- expect(subject.maintainer?(project, :frontend, labels)).to be_truthy
- end
-
- context 'when labels contain devops::create and the category is test' do
- let(:labels) { ['devops::create'] }
-
- context 'when role is Software Engineer in Test, Create' do
- let(:role) { 'Software Engineer in Test, Create' }
-
- it '#reviewer? returns true' do
- expect(subject.reviewer?(project, :test, labels)).to be_truthy
- end
-
- it '#maintainer? returns false' do
- expect(subject.maintainer?(project, :test, labels)).to be_falsey
- end
-
- context 'when hyperlink is mangled in the role' do
- let(:role) { '<a href="#">Software Engineer in Test</a>, Create' }
-
- it '#reviewer? returns true' do
- expect(subject.reviewer?(project, :test, labels)).to be_truthy
- end
- end
- end
-
- context 'when role is Software Engineer in Test' do
- let(:role) { 'Software Engineer in Test' }
-
- it '#reviewer? returns false' do
- expect(subject.reviewer?(project, :test, labels)).to be_falsey
- end
- end
-
- context 'when role is Software Engineer in Test, Manage' do
- let(:role) { 'Software Engineer in Test, Manage' }
-
- it '#reviewer? returns false' do
- expect(subject.reviewer?(project, :test, labels)).to be_falsey
- end
- end
-
- context 'when role is Backend Engineer, Engineering Productivity' do
- let(:role) { 'Backend Engineer, Engineering Productivity' }
-
- it '#reviewer? returns true' do
- expect(subject.reviewer?(project, :engineering_productivity, labels)).to be_truthy
- end
-
- it '#maintainer? returns false' do
- expect(subject.maintainer?(project, :engineering_productivity, labels)).to be_falsey
- end
-
- context 'when capabilities include maintainer backend' do
- let(:capabilities) { ['maintainer backend'] }
-
- it '#maintainer? returns true' do
- expect(subject.maintainer?(project, :engineering_productivity, labels)).to be_truthy
- end
- end
-
- context 'when capabilities include maintainer engineering productivity' do
- let(:capabilities) { ['maintainer engineering_productivity'] }
-
- it '#maintainer? returns true' do
- expect(subject.maintainer?(project, :engineering_productivity, labels)).to be_truthy
- end
- end
-
- context 'when capabilities include trainee_maintainer backend' do
- let(:capabilities) { ['trainee_maintainer backend'] }
-
- it '#traintainer? returns true' do
- expect(subject.traintainer?(project, :engineering_productivity, labels)).to be_truthy
- end
- end
- end
- end
- end
-
- context 'when having single capability' do
- let(:capabilities) { 'reviewer backend' }
-
- it '#reviewer? supports one role per project' do
- expect(subject.reviewer?(project, :backend, labels)).to be_truthy
- end
-
- it '#traintainer? supports one role per project' do
- expect(subject.traintainer?(project, :database, labels)).to be_falsey
- end
-
- it '#maintainer? supports one role per project' do
- expect(subject.maintainer?(project, :frontend, labels)).to be_falsey
- end
- end
-
- describe '#local_hour' do
- include ActiveSupport::Testing::TimeHelpers
-
- around do |example|
- travel_to(Time.utc(2020, 6, 23, 10)) { example.run }
- end
-
- context 'when author is given' do
- where(:tz_offset_hours, :expected_local_hour) do
- -12 | 22
- -10 | 0
- 2 | 12
- 4 | 14
- 12 | 22
- end
-
- with_them do
- it 'returns the correct local_hour' do
- expect(subject.local_hour).to eq(expected_local_hour)
- end
- end
- end
- end
-
- describe '#markdown_name' do
- it 'returns markdown name with timezone info' do
- expect(subject.markdown_name).to eq("#{options['markdown_name']} (UTC+2)")
- end
-
- context 'when offset is 1.5' do
- let(:tz_offset_hours) { 1.5 }
-
- it 'returns markdown name with timezone info, not truncated' do
- expect(subject.markdown_name).to eq("#{options['markdown_name']} (UTC+1.5)")
- end
- end
-
- context 'when author is given' do
- where(:tz_offset_hours, :author_offset, :diff_text) do
- -12 | -10 | "2 hours behind `@mario`"
- -10 | -12 | "2 hours ahead of `@mario`"
- -10 | 2 | "12 hours behind `@mario`"
- 2 | 4 | "2 hours behind `@mario`"
- 4 | 2 | "2 hours ahead of `@mario`"
- 2 | 3 | "1 hour behind `@mario`"
- 3 | 2 | "1 hour ahead of `@mario`"
- 2 | 2 | "same timezone as `@mario`"
- end
-
- with_them do
- it 'returns markdown name with timezone info' do
- author = described_class.new(options.merge('username' => 'mario', 'tz_offset_hours' => author_offset))
-
- floored_offset_hours = subject.__send__(:floored_offset_hours)
- utc_offset = floored_offset_hours >= 0 ? "+#{floored_offset_hours}" : floored_offset_hours
-
- expect(subject.markdown_name(author: author)).to eq("#{options['markdown_name']} (UTC#{utc_offset}, #{diff_text})")
- end
- end
- end
- end
-end
diff --git a/spec/tooling/danger/title_linting_spec.rb b/spec/tooling/danger/title_linting_spec.rb
deleted file mode 100644
index 7bc1684cd87..00000000000
--- a/spec/tooling/danger/title_linting_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-require 'rspec-parameterized'
-
-require_relative '../../../tooling/danger/title_linting'
-
-RSpec.describe Tooling::Danger::TitleLinting do
- using RSpec::Parameterized::TableSyntax
-
- describe '#sanitize_mr_title' do
- where(:mr_title, :expected_mr_title) do
- '`My MR title`' | "\\`My MR title\\`"
- 'WIP: My MR title' | 'My MR title'
- 'Draft: My MR title' | 'My MR title'
- '(Draft) My MR title' | 'My MR title'
- '[Draft] My MR title' | 'My MR title'
- '[DRAFT] My MR title' | 'My MR title'
- 'DRAFT: My MR title' | 'My MR title'
- 'DRAFT: `My MR title`' | "\\`My MR title\\`"
- end
-
- with_them do
- subject { described_class.sanitize_mr_title(mr_title) }
-
- it { is_expected.to eq(expected_mr_title) }
- end
- end
-
- describe '#remove_draft_flag' do
- where(:mr_title, :expected_mr_title) do
- 'WIP: My MR title' | 'My MR title'
- 'Draft: My MR title' | 'My MR title'
- '(Draft) My MR title' | 'My MR title'
- '[Draft] My MR title' | 'My MR title'
- '[DRAFT] My MR title' | 'My MR title'
- 'DRAFT: My MR title' | 'My MR title'
- end
-
- with_them do
- subject { described_class.remove_draft_flag(mr_title) }
-
- it { is_expected.to eq(expected_mr_title) }
- end
- end
-
- describe '#has_draft_flag?' do
- it 'returns true for a draft title' do
- expect(described_class.has_draft_flag?('Draft: My MR title')).to be true
- end
-
- it 'returns false for non draft title' do
- expect(described_class.has_draft_flag?('My MR title')).to be false
- end
- end
-
- describe '#has_cherry_pick_flag?' do
- [
- 'Cherry Pick !1234',
- 'cherry-pick !1234',
- 'CherryPick !1234'
- ].each do |mr_title|
- it 'returns true for cherry-pick title' do
- expect(described_class.has_cherry_pick_flag?(mr_title)).to be true
- end
- end
-
- it 'returns false for non cherry-pick title' do
- expect(described_class.has_cherry_pick_flag?('My MR title')).to be false
- end
- end
-
- describe '#has_run_all_rspec_flag?' do
- it 'returns true for a title that includes RUN ALL RSPEC' do
- expect(described_class.has_run_all_rspec_flag?('My MR title RUN ALL RSPEC')).to be true
- end
-
- it 'returns true for a title that does not include RUN ALL RSPEC' do
- expect(described_class.has_run_all_rspec_flag?('My MR title')).to be false
- end
- end
-
- describe '#has_run_as_if_foss_flag?' do
- it 'returns true for a title that includes RUN AS-IF-FOSS' do
- expect(described_class.has_run_as_if_foss_flag?('My MR title RUN AS-IF-FOSS')).to be true
- end
-
- it 'returns true for a title that does not include RUN AS-IF-FOSS' do
- expect(described_class.has_run_as_if_foss_flag?('My MR title')).to be false
- end
- end
-end
diff --git a/spec/tooling/danger/weightage/maintainers_spec.rb b/spec/tooling/danger/weightage/maintainers_spec.rb
deleted file mode 100644
index b99ffe706a4..00000000000
--- a/spec/tooling/danger/weightage/maintainers_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../../../tooling/danger/weightage/maintainers'
-
-RSpec.describe Tooling::Danger::Weightage::Maintainers do
- let(:multiplier) { Tooling::Danger::Weightage::CAPACITY_MULTIPLIER }
- let(:regular_maintainer) { double('Teammate', reduced_capacity: false) }
- let(:reduced_capacity_maintainer) { double('Teammate', reduced_capacity: true) }
- let(:maintainers) do
- [
- regular_maintainer,
- reduced_capacity_maintainer
- ]
- end
-
- let(:maintainer_count) { Tooling::Danger::Weightage::BASE_REVIEWER_WEIGHT * multiplier }
- let(:reduced_capacity_maintainer_count) { Tooling::Danger::Weightage::BASE_REVIEWER_WEIGHT }
-
- subject(:weighted_maintainers) { described_class.new(maintainers).execute }
-
- describe '#execute' do
- it 'weights the maintainers overall' do
- expect(weighted_maintainers.count).to eq maintainer_count + reduced_capacity_maintainer_count
- end
-
- it 'has total count of regular maintainers' do
- expect(weighted_maintainers.count { |r| r.object_id == regular_maintainer.object_id }).to eq maintainer_count
- end
-
- it 'has count of reduced capacity maintainers' do
- expect(weighted_maintainers.count { |r| r.object_id == reduced_capacity_maintainer.object_id }).to eq reduced_capacity_maintainer_count
- end
- end
-end
diff --git a/spec/tooling/danger/weightage/reviewers_spec.rb b/spec/tooling/danger/weightage/reviewers_spec.rb
deleted file mode 100644
index 5693ce7a10c..00000000000
--- a/spec/tooling/danger/weightage/reviewers_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../../../tooling/danger/weightage/reviewers'
-
-RSpec.describe Tooling::Danger::Weightage::Reviewers do
- let(:multiplier) { Tooling::Danger::Weightage::CAPACITY_MULTIPLIER }
- let(:regular_reviewer) { double('Teammate', hungry: false, reduced_capacity: false) }
- let(:hungry_reviewer) { double('Teammate', hungry: true, reduced_capacity: false) }
- let(:reduced_capacity_reviewer) { double('Teammate', hungry: false, reduced_capacity: true) }
- let(:reviewers) do
- [
- hungry_reviewer,
- regular_reviewer,
- reduced_capacity_reviewer
- ]
- end
-
- let(:regular_traintainer) { double('Teammate', hungry: false, reduced_capacity: false) }
- let(:hungry_traintainer) { double('Teammate', hungry: true, reduced_capacity: false) }
- let(:reduced_capacity_traintainer) { double('Teammate', hungry: false, reduced_capacity: true) }
- let(:traintainers) do
- [
- hungry_traintainer,
- regular_traintainer,
- reduced_capacity_traintainer
- ]
- end
-
- let(:hungry_reviewer_count) { Tooling::Danger::Weightage::BASE_REVIEWER_WEIGHT * multiplier + described_class::DEFAULT_REVIEWER_WEIGHT }
- let(:hungry_traintainer_count) { described_class::TRAINTAINER_WEIGHT * multiplier + described_class::DEFAULT_REVIEWER_WEIGHT }
- let(:reviewer_count) { Tooling::Danger::Weightage::BASE_REVIEWER_WEIGHT * multiplier }
- let(:traintainer_count) { Tooling::Danger::Weightage::BASE_REVIEWER_WEIGHT * described_class::TRAINTAINER_WEIGHT * multiplier }
- let(:reduced_capacity_reviewer_count) { Tooling::Danger::Weightage::BASE_REVIEWER_WEIGHT }
- let(:reduced_capacity_traintainer_count) { described_class::TRAINTAINER_WEIGHT }
-
- subject(:weighted_reviewers) { described_class.new(reviewers, traintainers).execute }
-
- describe '#execute', :aggregate_failures do
- it 'weights the reviewers overall' do
- reviewers_count = hungry_reviewer_count + reviewer_count + reduced_capacity_reviewer_count
- traintainers_count = hungry_traintainer_count + traintainer_count + reduced_capacity_traintainer_count
-
- expect(weighted_reviewers.count).to eq reviewers_count + traintainers_count
- end
-
- it 'has total count of hungry reviewers and traintainers' do
- expect(weighted_reviewers.count(&:hungry)).to eq hungry_reviewer_count + hungry_traintainer_count
- expect(weighted_reviewers.count { |r| r.object_id == hungry_reviewer.object_id }).to eq hungry_reviewer_count
- expect(weighted_reviewers.count { |r| r.object_id == hungry_traintainer.object_id }).to eq hungry_traintainer_count
- end
-
- it 'has total count of regular reviewers and traintainers' do
- expect(weighted_reviewers.count { |r| r.object_id == regular_reviewer.object_id }).to eq reviewer_count
- expect(weighted_reviewers.count { |r| r.object_id == regular_traintainer.object_id }).to eq traintainer_count
- end
-
- it 'has count of reduced capacity reviewers' do
- expect(weighted_reviewers.count(&:reduced_capacity)).to eq reduced_capacity_reviewer_count + reduced_capacity_traintainer_count
- expect(weighted_reviewers.count { |r| r.object_id == reduced_capacity_reviewer.object_id }).to eq reduced_capacity_reviewer_count
- expect(weighted_reviewers.count { |r| r.object_id == reduced_capacity_traintainer.object_id }).to eq reduced_capacity_traintainer_count
- end
- end
-end
diff --git a/spec/tooling/gitlab_danger_spec.rb b/spec/tooling/gitlab_danger_spec.rb
deleted file mode 100644
index 20ac40d1d2a..00000000000
--- a/spec/tooling/gitlab_danger_spec.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../tooling/gitlab_danger'
-
-RSpec.describe GitlabDanger do
- let(:gitlab_danger_helper) { nil }
-
- subject { described_class.new(gitlab_danger_helper) }
-
- describe '.local_warning_message' do
- it 'returns an informational message with rules that can run' do
- expect(described_class.local_warning_message).to eq("==> Only the following Danger rules can be run locally: #{described_class::LOCAL_RULES.join(', ')}")
- end
- end
-
- describe '.success_message' do
- it 'returns an informational success message' do
- expect(described_class.success_message).to eq('==> No Danger rule violations!')
- end
- end
-
- describe '#rule_names' do
- context 'when running locally' do
- it 'returns local only rules' do
- expect(subject.rule_names).to eq(described_class::LOCAL_RULES)
- end
- end
-
- context 'when running under CI' do
- let(:gitlab_danger_helper) { double('danger_gitlab_helper') }
-
- it 'returns all rules' do
- expect(subject.rule_names).to eq(described_class::LOCAL_RULES | described_class::CI_ONLY_RULES)
- end
- end
- end
-
- describe '#html_link' do
- context 'when running locally' do
- it 'returns the same string' do
- str = 'something'
-
- expect(subject.html_link(str)).to eq(str)
- end
- end
-
- context 'when running under CI' do
- let(:gitlab_danger_helper) { double('danger_gitlab_helper') }
-
- it 'returns a HTML link formatted version of the string' do
- str = 'something'
- html_formatted_str = %Q{<a href="#{str}">#{str}</a>}
-
- expect(gitlab_danger_helper).to receive(:html_link).with(str).and_return(html_formatted_str)
-
- expect(subject.html_link(str)).to eq(html_formatted_str)
- end
- end
- end
-
- describe '#ci?' do
- context 'when gitlab_danger_helper is not available' do
- it 'returns false' do
- expect(subject.ci?).to be_falsey
- end
- end
-
- context 'when gitlab_danger_helper is available' do
- let(:gitlab_danger_helper) { double('danger_gitlab_helper') }
-
- it 'returns true' do
- expect(subject.ci?).to be_truthy
- end
- end
- end
-end