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-01 21:11:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-01 21:11:21 +0300
commit69f0d90aad454a2b8f3c4e2f2ca31886a14a8642 (patch)
treef79279c4c77d6938350afdd0dbc4b360d286a2ed /spec
parentdff63567c3bdad66d092989f9bf85b6faa32da65 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb1
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb1
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_spec.js39
-rw-r--r--spec/frontend/pipelines/pipelines_table_spec.js73
-rw-r--r--spec/frontend/pipelines/time_ago_spec.js14
-rw-r--r--spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js18
-rw-r--r--spec/frontend/sidebar/user_data_mock.js1
-rw-r--r--spec/frontend/vue_shared/components/multiselect_dropdown_spec.js4
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb10
-rw-r--r--spec/serializers/merge_request_user_entity_spec.rb53
-rw-r--r--spec/services/merge_requests/build_service_spec.rb123
-rw-r--r--spec/tasks/admin_mode_spec.rb32
-rw-r--r--spec/views/projects/settings/operations/show.html.haml_spec.rb4
13 files changed, 297 insertions, 76 deletions
diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
index 708ce53b4fe..ad0e9b48903 100644
--- a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb
@@ -26,6 +26,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
end
before do
+ stub_feature_flags(new_pipelines_table: false)
stub_application_setting(auto_devops_enabled: false)
stub_ci_pipeline_yaml_file(YAML.dump(config))
project.add_maintainer(user)
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 2b407868f35..9037aa5c9a8 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe 'Pipelines', :js do
sign_in(user)
stub_feature_flags(graphql_pipeline_details: false)
stub_feature_flags(graphql_pipeline_details_users: false)
+ stub_feature_flags(new_pipelines_table: false)
project.add_developer(user)
project.update!(auto_devops_attributes: { enabled: false })
diff --git a/spec/frontend/import_entities/import_groups/components/import_table_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
index 14445132f48..496c5cda7c7 100644
--- a/spec/frontend/import_entities/import_groups/components/import_table_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
@@ -1,7 +1,15 @@
-import { GlEmptyState, GlLoadingIcon, GlSearchBoxByClick, GlSprintf } from '@gitlab/ui';
+import {
+ GlEmptyState,
+ GlLoadingIcon,
+ GlSearchBoxByClick,
+ GlSprintf,
+ GlDropdown,
+ GlDropdownItem,
+} from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
+import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import { STATUSES } from '~/import_entities/constants';
import ImportTable from '~/import_entities/import_groups/components/import_table.vue';
@@ -16,10 +24,15 @@ import { availableNamespacesFixture, generateFakeEntry } from '../graphql/fixtur
const localVue = createLocalVue();
localVue.use(VueApollo);
+const GlDropdownStub = stubComponent(GlDropdown, {
+ template: '<div><h1 ref="text"><slot name="button-content"></slot></h1><slot></slot></div>',
+});
+
describe('import table', () => {
let wrapper;
let apolloProvider;
+ const SOURCE_URL = 'https://demo.host';
const FAKE_GROUP = generateFakeEntry({ id: 1, status: STATUSES.NONE });
const FAKE_GROUPS = [
generateFakeEntry({ id: 1, status: STATUSES.NONE }),
@@ -27,6 +40,9 @@ describe('import table', () => {
];
const FAKE_PAGE_INFO = { page: 1, perPage: 20, total: 40, totalPages: 2 };
+ const findPaginationDropdown = () => wrapper.findComponent(GlDropdown);
+ const findPaginationDropdownText = () => findPaginationDropdown().find({ ref: 'text' }).text();
+
const createComponent = ({ bulkImportSourceGroups }) => {
apolloProvider = createMockApollo([], {
Query: {
@@ -42,11 +58,12 @@ describe('import table', () => {
wrapper = shallowMount(ImportTable, {
propsData: {
- sourceUrl: 'https://demo.host',
groupPathRegex: /.*/,
+ sourceUrl: SOURCE_URL,
},
stubs: {
GlSprintf,
+ GlDropdown: GlDropdownStub,
},
localVue,
apolloProvider,
@@ -152,6 +169,20 @@ describe('import table', () => {
expect(wrapper.find(PaginationLinks).props().pageInfo).toStrictEqual(FAKE_PAGE_INFO);
});
+ it('renders pagination dropdown', () => {
+ expect(findPaginationDropdown().exists()).toBe(true);
+ });
+
+ it('updates page size when selected in Dropdown', async () => {
+ const otherOption = wrapper.findAllComponents(GlDropdownItem).at(1);
+ expect(otherOption.text()).toMatchInterpolatedText('50 items per page');
+
+ otherOption.vm.$emit('click');
+ await waitForPromises();
+
+ expect(findPaginationDropdownText()).toMatchInterpolatedText('50 items per page');
+ });
+
it('updates page when page change is requested', async () => {
const REQUESTED_PAGE = 2;
wrapper.find(PaginationLinks).props().change(REQUESTED_PAGE);
@@ -179,7 +210,7 @@ describe('import table', () => {
wrapper.find(PaginationLinks).props().change(REQUESTED_PAGE);
await waitForPromises();
- expect(wrapper.text()).toContain('Showing 21-21 of 38');
+ expect(wrapper.text()).toContain('Showing 21-21 of 38 groups from');
});
});
@@ -225,7 +256,7 @@ describe('import table', () => {
findFilterInput().vm.$emit('submit', FILTER_VALUE);
await waitForPromises();
- expect(wrapper.text()).toContain('Showing 1-1 of 40 groups matching filter "foo"');
+ expect(wrapper.text()).toContain('Showing 1-1 of 40 groups matching filter "foo" from');
});
it('properly resets filter in graphql query when search box is cleared', async () => {
diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js
index 64febd7311c..9541461097b 100644
--- a/spec/frontend/pipelines/pipelines_table_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_spec.js
@@ -1,4 +1,6 @@
+import { GlTable } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import PipelinesTable from '~/pipelines/components/pipelines_list/pipelines_table.vue';
describe('Pipelines Table', () => {
@@ -12,20 +14,28 @@ describe('Pipelines Table', () => {
viewType: 'root',
};
- const createComponent = (props = defaultProps) => {
- wrapper = mount(PipelinesTable, {
- propsData: props,
- });
+ const createComponent = (props = defaultProps, flagState = false) => {
+ wrapper = extendedWrapper(
+ mount(PipelinesTable, {
+ propsData: props,
+ provide: {
+ glFeatures: {
+ newPipelinesTable: flagState,
+ },
+ },
+ }),
+ );
};
+
const findRows = () => wrapper.findAll('.commit.gl-responsive-table-row');
+ const findGlTable = () => wrapper.findComponent(GlTable);
+ const findLegacyTable = () => wrapper.findByTestId('ci-table');
preloadFixtures(jsonFixtureName);
beforeEach(() => {
const { pipelines } = getJSONFixture(jsonFixtureName);
pipeline = pipelines.find((p) => p.user !== null && p.commit !== null);
-
- createComponent();
});
afterEach(() => {
@@ -33,33 +43,50 @@ describe('Pipelines Table', () => {
wrapper = null;
});
- describe('table', () => {
- it('should render a table', () => {
- expect(wrapper.classes()).toContain('ci-table');
- });
+ describe('table with feature flag off', () => {
+ describe('renders the table correctly', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should render a table', () => {
+ expect(wrapper.classes()).toContain('ci-table');
+ });
- it('should render table head with correct columns', () => {
- expect(wrapper.find('.table-section.js-pipeline-status').text()).toEqual('Status');
+ it('should render table head with correct columns', () => {
+ expect(wrapper.find('.table-section.js-pipeline-status').text()).toEqual('Status');
- expect(wrapper.find('.table-section.js-pipeline-info').text()).toEqual('Pipeline');
+ expect(wrapper.find('.table-section.js-pipeline-info').text()).toEqual('Pipeline');
- expect(wrapper.find('.table-section.js-pipeline-commit').text()).toEqual('Commit');
+ expect(wrapper.find('.table-section.js-pipeline-commit').text()).toEqual('Commit');
- expect(wrapper.find('.table-section.js-pipeline-stages').text()).toEqual('Stages');
+ expect(wrapper.find('.table-section.js-pipeline-stages').text()).toEqual('Stages');
+ });
});
- });
- describe('without data', () => {
- it('should render an empty table', () => {
- expect(findRows()).toHaveLength(0);
+ describe('without data', () => {
+ it('should render an empty table', () => {
+ createComponent();
+
+ expect(findRows()).toHaveLength(0);
+ });
+ });
+
+ describe('with data', () => {
+ it('should render rows', () => {
+ createComponent({ pipelines: [pipeline], viewType: 'root' });
+
+ expect(findRows()).toHaveLength(1);
+ });
});
});
- describe('with data', () => {
- it('should render rows', () => {
- createComponent({ pipelines: [pipeline], viewType: 'root' });
+ describe('table with feature flag on', () => {
+ it('displays new table', () => {
+ createComponent(defaultProps, true);
- expect(findRows()).toHaveLength(1);
+ expect(findGlTable().exists()).toBe(true);
+ expect(findLegacyTable().exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/pipelines/time_ago_spec.js b/spec/frontend/pipelines/time_ago_spec.js
index 55a19ef5165..4919efbb4c6 100644
--- a/spec/frontend/pipelines/time_ago_spec.js
+++ b/spec/frontend/pipelines/time_ago_spec.js
@@ -8,7 +8,11 @@ describe('Timeago component', () => {
const createComponent = (props = {}) => {
wrapper = shallowMount(TimeAgo, {
propsData: {
- ...props,
+ pipeline: {
+ details: {
+ ...props,
+ },
+ },
},
data() {
return {
@@ -28,7 +32,7 @@ describe('Timeago component', () => {
describe('with duration', () => {
beforeEach(() => {
- createComponent({ duration: 10, finishedTime: '' });
+ createComponent({ duration: 10, finished_at: '' });
});
it('should render duration and timer svg', () => {
@@ -41,7 +45,7 @@ describe('Timeago component', () => {
describe('without duration', () => {
beforeEach(() => {
- createComponent({ duration: 0, finishedTime: '' });
+ createComponent({ duration: 0, finished_at: '' });
});
it('should not render duration and timer svg', () => {
@@ -51,7 +55,7 @@ describe('Timeago component', () => {
describe('with finishedTime', () => {
beforeEach(() => {
- createComponent({ duration: 0, finishedTime: '2017-04-26T12:40:23.277Z' });
+ createComponent({ duration: 0, finished_at: '2017-04-26T12:40:23.277Z' });
});
it('should render time and calendar icon', () => {
@@ -66,7 +70,7 @@ describe('Timeago component', () => {
describe('without finishedTime', () => {
beforeEach(() => {
- createComponent({ duration: 0, finishedTime: '' });
+ createComponent({ duration: 0, finished_at: '' });
});
it('should not render time and calendar icon', () => {
diff --git a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
index 7c67149b517..9f6878db785 100644
--- a/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
+++ b/spec/frontend/sidebar/components/reviewers/uncollapsed_reviewer_list_spec.js
@@ -7,6 +7,8 @@ import userDataMock from '../../user_data_mock';
describe('UncollapsedReviewerList component', () => {
let wrapper;
+ const reviewerApprovalIcons = () => wrapper.findAll('[data-testid="re-approved"]');
+
function createComponent(props = {}) {
const propsData = {
users: [],
@@ -58,19 +60,29 @@ describe('UncollapsedReviewerList component', () => {
const user = userDataMock();
createComponent({
- users: [user, { ...user, id: 2, username: 'hello-world' }],
+ users: [user, { ...user, id: 2, username: 'hello-world', approved: true }],
});
});
- it('only has one user', () => {
+ it('has both users', () => {
expect(wrapper.findAll(ReviewerAvatarLink).length).toBe(2);
});
- it('shows one user with avatar, username and author name', () => {
+ it('shows both users with avatar, username and author name', () => {
expect(wrapper.text()).toContain(`@root`);
expect(wrapper.text()).toContain(`@hello-world`);
});
+ it('renders approval icon', () => {
+ expect(reviewerApprovalIcons().length).toBe(1);
+ });
+
+ it('shows that hello-world approved', () => {
+ const icon = reviewerApprovalIcons().at(0);
+
+ expect(icon.attributes('title')).toEqual('Approved by @hello-world');
+ });
+
it('renders re-request loading icon', async () => {
await wrapper.setData({ loadingStates: { 2: 'loading' } });
diff --git a/spec/frontend/sidebar/user_data_mock.js b/spec/frontend/sidebar/user_data_mock.js
index 41d0331f34a..7c11551b0be 100644
--- a/spec/frontend/sidebar/user_data_mock.js
+++ b/spec/frontend/sidebar/user_data_mock.js
@@ -10,4 +10,5 @@ export default () => ({
can_merge: true,
can_update_merge_request: true,
reviewed: true,
+ approved: false,
});
diff --git a/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js b/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js
index 99671f1ffb7..566ca1817f2 100644
--- a/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js
@@ -1,3 +1,4 @@
+import { GlDropdown } from '@gitlab/ui';
import { getByText } from '@testing-library/dom';
import { shallowMount } from '@vue/test-utils';
import MultiSelectDropdown from '~/vue_shared/components/sidebar/multiselect_dropdown.vue';
@@ -25,6 +26,9 @@ describe('MultiSelectDropdown Component', () => {
slots: {
search: '<p>Search</p>',
},
+ stubs: {
+ GlDropdown,
+ },
});
expect(getByText(wrapper.element, 'Search')).toBeDefined();
});
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index ea63406e615..366c3f68e1d 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -511,20 +511,23 @@ RSpec.describe PrometheusService, :use_clean_rails_memory_store_caching, :snowpl
type: 'checkbox',
name: 'manual_configuration',
title: s_('PrometheusService|Active'),
+ help: s_('PrometheusService|Select this checkbox to override the auto configuration settings with your own settings.'),
required: true
},
{
type: 'text',
name: 'api_url',
title: 'API URL',
- placeholder: s_('PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/'),
+ placeholder: s_('PrometheusService|https://prometheus.example.com/'),
+ help: s_('PrometheusService|The Prometheus API base URL.'),
required: true
},
{
type: 'text',
name: 'google_iap_audience_client_id',
title: 'Google IAP Audience Client ID',
- placeholder: s_('PrometheusService|Client ID of the IAP secured resource (looks like IAP_CLIENT_ID.apps.googleusercontent.com)'),
+ placeholder: s_('PrometheusService|IAP_CLIENT_ID.apps.googleusercontent.com'),
+ help: s_('PrometheusService|PrometheusService|The ID of the IAP-secured resource.'),
autocomplete: 'off',
required: false
},
@@ -532,7 +535,8 @@ RSpec.describe PrometheusService, :use_clean_rails_memory_store_caching, :snowpl
type: 'textarea',
name: 'google_iap_service_account_json',
title: 'Google IAP Service Account JSON',
- placeholder: s_('PrometheusService|Contents of the credentials.json file of your service account, like: { "type": "service_account", "project_id": ... }'),
+ placeholder: s_('PrometheusService|{ "type": "service_account", "project_id": ... }'),
+ help: s_('PrometheusService|The contents of the credentials.json file of your service account.'),
required: false
}
]
diff --git a/spec/serializers/merge_request_user_entity_spec.rb b/spec/serializers/merge_request_user_entity_spec.rb
index dcd4ef6acfb..697fa3001e3 100644
--- a/spec/serializers/merge_request_user_entity_spec.rb
+++ b/spec/serializers/merge_request_user_entity_spec.rb
@@ -3,19 +3,22 @@
require 'spec_helper'
RSpec.describe MergeRequestUserEntity do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
- let(:request) { EntityRequest.new(project: project, current_user: user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:merge_request) { create(:merge_request) }
+ let(:request) { EntityRequest.new(project: merge_request.target_project, current_user: user) }
let(:entity) do
- described_class.new(user, request: request)
+ described_class.new(user, request: request, merge_request: merge_request)
end
- context 'as json' do
+ describe '#as_json' do
subject { entity.as_json }
it 'exposes needed attributes' do
- expect(subject).to include(:id, :name, :username, :state, :avatar_url, :web_url, :can_merge)
+ is_expected.to include(
+ :id, :name, :username, :state, :avatar_url, :web_url,
+ :can_merge, :can_update_merge_request, :reviewed, :approved
+ )
end
context 'when `status` is not preloaded' do
@@ -24,6 +27,22 @@ RSpec.describe MergeRequestUserEntity do
end
end
+ context 'when the user has not approved the merge-request' do
+ it 'exposes that the user has not approved the MR' do
+ expect(subject).to include(approved: false)
+ end
+ end
+
+ context 'when the user has approved the merge-request' do
+ before do
+ merge_request.approvals.create!(user: user)
+ end
+
+ it 'exposes that the user has approved the MR' do
+ expect(subject).to include(approved: true)
+ end
+ end
+
context 'when `status` is preloaded' do
before do
user.create_status!(availability: :busy)
@@ -35,5 +54,27 @@ RSpec.describe MergeRequestUserEntity do
expect(subject[:availability]).to eq('busy')
end
end
+
+ describe 'performance' do
+ let_it_be(:user_a) { create(:user) }
+ let_it_be(:user_b) { create(:user) }
+ let_it_be(:merge_request_b) { create(:merge_request) }
+
+ it 'is linear in the number of merge requests' do
+ pending "See: https://gitlab.com/gitlab-org/gitlab/-/issues/322549"
+ baseline = ActiveRecord::QueryRecorder.new do
+ ent = described_class.new(user_a, request: request, merge_request: merge_request)
+ ent.as_json
+ end
+
+ expect do
+ a = described_class.new(user_a, request: request, merge_request: merge_request_b)
+ b = described_class.new(user_b, request: request, merge_request: merge_request_b)
+
+ a.as_json
+ b.as_json
+ end.not_to exceed_query_limit(baseline)
+ end
+ end
end
end
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 22b3456708f..8adf6d69f73 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -19,8 +19,21 @@ RSpec.describe MergeRequests::BuildService do
let(:label_ids) { [] }
let(:merge_request) { service.execute }
let(:compare) { double(:compare, commits: commits) }
- let(:commit_1) { double(:commit_1, sha: 'f00ba7', safe_message: "Initial commit\n\nCreate the app") }
- let(:commit_2) { double(:commit_2, sha: 'f00ba7', safe_message: 'This is a bad commit message!') }
+ let(:commit_1) do
+ double(:commit_1, sha: 'f00ba6', safe_message: 'Initial commit',
+ gitaly_commit?: false, id: 'f00ba6', parent_ids: ['f00ba5'])
+ end
+
+ let(:commit_2) do
+ double(:commit_2, sha: 'f00ba7', safe_message: "Closes #1234 Second commit\n\nCreate the app",
+ gitaly_commit?: false, id: 'f00ba7', parent_ids: ['f00ba6'])
+ end
+
+ let(:commit_3) do
+ double(:commit_3, sha: 'f00ba8', safe_message: 'This is a bad commit message!',
+ gitaly_commit?: false, id: 'f00ba8', parent_ids: ['f00ba7'])
+ end
+
let(:commits) { nil }
let(:params) do
@@ -47,6 +60,7 @@ RSpec.describe MergeRequests::BuildService do
allow(CompareService).to receive_message_chain(:new, :execute).and_return(compare)
allow(project).to receive(:commit).and_return(commit_1)
allow(project).to receive(:commit).and_return(commit_2)
+ allow(project).to receive(:commit).and_return(commit_3)
end
shared_examples 'allows the merge request to be created' do
@@ -137,7 +151,7 @@ RSpec.describe MergeRequests::BuildService do
context 'when target branch is missing' do
let(:target_branch) { nil }
- let(:commits) { Commit.decorate([commit_1], project) }
+ let(:commits) { Commit.decorate([commit_2], project) }
before do
stub_compare
@@ -199,8 +213,8 @@ RSpec.describe MergeRequests::BuildService do
end
context 'one commit in the diff' do
- let(:commits) { Commit.decorate([commit_1], project) }
- let(:commit_description) { commit_1.safe_message.split(/\n+/, 2).last }
+ let(:commits) { Commit.decorate([commit_2], project) }
+ let(:commit_description) { commit_2.safe_message.split(/\n+/, 2).last }
before do
stub_compare
@@ -209,7 +223,7 @@ RSpec.describe MergeRequests::BuildService do
it_behaves_like 'allows the merge request to be created'
it 'uses the title of the commit as the title of the merge request' do
- expect(merge_request.title).to eq(commit_1.safe_message.split("\n").first)
+ expect(merge_request.title).to eq(commit_2.safe_message.split("\n").first)
end
it 'uses the description of the commit as the description of the merge request' do
@@ -225,10 +239,10 @@ RSpec.describe MergeRequests::BuildService do
end
context 'commit has no description' do
- let(:commits) { Commit.decorate([commit_2], project) }
+ let(:commits) { Commit.decorate([commit_3], project) }
it 'uses the title of the commit as the title of the merge request' do
- expect(merge_request.title).to eq(commit_2.safe_message)
+ expect(merge_request.title).to eq(commit_3.safe_message)
end
it 'sets the description to nil' do
@@ -257,7 +271,7 @@ RSpec.describe MergeRequests::BuildService do
end
it 'uses the title of the commit as the title of the merge request' do
- expect(merge_request.title).to eq('Initial commit')
+ expect(merge_request.title).to eq('Closes #1234 Second commit')
end
it 'appends the closing description' do
@@ -310,8 +324,8 @@ RSpec.describe MergeRequests::BuildService do
end
end
- context 'more than one commit in the diff' do
- let(:commits) { Commit.decorate([commit_1, commit_2], project) }
+ context 'no multi-line commit messages in the diff' do
+ let(:commits) { Commit.decorate([commit_1, commit_3], project) }
before do
stub_compare
@@ -365,6 +379,55 @@ RSpec.describe MergeRequests::BuildService do
end
end
end
+ end
+
+ context 'a multi-line commit message in the diff' do
+ let(:commits) { Commit.decorate([commit_1, commit_2, commit_3], project) }
+
+ before do
+ stub_compare
+ end
+
+ it_behaves_like 'allows the merge request to be created'
+
+ it 'uses the first line of the first multi-line commit message as the title' do
+ expect(merge_request.title).to eq('Closes #1234 Second commit')
+ end
+
+ it 'adds the remaining lines of the first multi-line commit message as the description' do
+ expect(merge_request.description).to eq('Create the app')
+ end
+
+ context 'when the source branch matches an issue' do
+ where(:issue_tracker, :source_branch, :title, :closing_message) do
+ :jira | 'FOO-123-fix-issue' | 'Resolve FOO-123 "Fix issue"' | 'Closes FOO-123'
+ :jira | 'fix-issue' | 'Fix issue' | nil
+ :custom_issue_tracker | '123-fix-issue' | 'Resolve #123 "Fix issue"' | 'Closes #123'
+ :custom_issue_tracker | 'fix-issue' | 'Fix issue' | nil
+ :internal | '123-fix-issue' | 'Resolve "A bug"' | 'Closes #123'
+ :internal | 'fix-issue' | 'Fix issue' | nil
+ :internal | '124-fix-issue' | '124 fix issue' | nil
+ end
+
+ with_them do
+ before do
+ if issue_tracker == :internal
+ issue.update!(iid: 123)
+ else
+ create(:"#{issue_tracker}_service", project: project)
+ project.reload
+ end
+ end
+
+ it 'sets the correct title' do
+ expect(merge_request.title).to eq('Closes #1234 Second commit')
+ end
+
+ it 'sets the closing description' do
+ expect(merge_request.description).to eq("Create the app#{closing_message ? "\n\n" + closing_message : ''}")
+ end
+ end
+ end
context 'when the issue is not accessible to user' do
let(:source_branch) { "#{issue.iid}-fix-issue" }
@@ -373,12 +436,12 @@ RSpec.describe MergeRequests::BuildService do
project.team.truncate
end
- it 'uses branch title as the merge request title' do
- expect(merge_request.title).to eq("#{issue.iid} fix issue")
+ it 'uses the first line of the first multi-line commit message as the title' do
+ expect(merge_request.title).to eq('Closes #1234 Second commit')
end
- it 'does not set a description' do
- expect(merge_request.description).to be_nil
+ it 'adds the remaining lines of the first multi-line commit message as the description' do
+ expect(merge_request.description).to eq('Create the app')
end
end
@@ -386,12 +449,12 @@ RSpec.describe MergeRequests::BuildService do
let(:source_branch) { "#{issue.iid}-fix-issue" }
let(:issue_confidential) { true }
- it 'uses the title of the branch as the merge request title' do
- expect(merge_request.title).to eq("#{issue.iid} fix issue")
+ it 'uses the first line of the first multi-line commit message as the title' do
+ expect(merge_request.title).to eq('Closes #1234 Second commit')
end
- it 'does not set a description' do
- expect(merge_request.description).to be_nil
+ it 'adds the remaining lines of the first multi-line commit message as the description' do
+ expect(merge_request.description).to eq('Create the app')
end
end
end
@@ -399,7 +462,7 @@ RSpec.describe MergeRequests::BuildService do
context 'source branch does not exist' do
before do
allow(project).to receive(:commit).with(source_branch).and_return(nil)
- allow(project).to receive(:commit).with(target_branch).and_return(commit_1)
+ allow(project).to receive(:commit).with(target_branch).and_return(commit_2)
end
it_behaves_like 'forbids the merge request from being created' do
@@ -409,7 +472,7 @@ RSpec.describe MergeRequests::BuildService do
context 'target branch does not exist' do
before do
- allow(project).to receive(:commit).with(source_branch).and_return(commit_1)
+ allow(project).to receive(:commit).with(source_branch).and_return(commit_2)
allow(project).to receive(:commit).with(target_branch).and_return(nil)
end
@@ -433,7 +496,7 @@ RSpec.describe MergeRequests::BuildService do
context 'upstream project has disabled merge requests' do
let(:upstream_project) { create(:project, :merge_requests_disabled) }
let(:project) { create(:project, forked_from_project: upstream_project) }
- let(:commits) { Commit.decorate([commit_1], project) }
+ let(:commits) { Commit.decorate([commit_2], project) }
it 'sets target project correctly' do
expect(merge_request.target_project).to eq(project)
@@ -441,8 +504,8 @@ RSpec.describe MergeRequests::BuildService do
end
context 'target_project is set and accessible by current_user' do
- let(:target_project) { create(:project, :public, :repository)}
- let(:commits) { Commit.decorate([commit_1], project) }
+ let(:target_project) { create(:project, :public, :repository) }
+ let(:commits) { Commit.decorate([commit_2], project) }
it 'sets target project correctly' do
expect(merge_request.target_project).to eq(target_project)
@@ -450,8 +513,8 @@ RSpec.describe MergeRequests::BuildService do
end
context 'target_project is set but not accessible by current_user' do
- let(:target_project) { create(:project, :private, :repository)}
- let(:commits) { Commit.decorate([commit_1], project) }
+ let(:target_project) { create(:project, :private, :repository) }
+ let(:commits) { Commit.decorate([commit_2], project) }
it 'sets target project correctly' do
expect(merge_request.target_project).to eq(project)
@@ -469,8 +532,8 @@ RSpec.describe MergeRequests::BuildService do
end
context 'source_project is set and accessible by current_user' do
- let(:source_project) { create(:project, :public, :repository)}
- let(:commits) { Commit.decorate([commit_1], project) }
+ let(:source_project) { create(:project, :public, :repository) }
+ let(:commits) { Commit.decorate([commit_2], project) }
before do
# To create merge requests _from_ a project the user needs at least
@@ -484,8 +547,8 @@ RSpec.describe MergeRequests::BuildService do
end
context 'source_project is set but not accessible by current_user' do
- let(:source_project) { create(:project, :private, :repository)}
- let(:commits) { Commit.decorate([commit_1], project) }
+ let(:source_project) { create(:project, :private, :repository) }
+ let(:commits) { Commit.decorate([commit_2], project) }
it 'sets source project correctly' do
expect(merge_request.source_project).to eq(project)
diff --git a/spec/tasks/admin_mode_spec.rb b/spec/tasks/admin_mode_spec.rb
new file mode 100644
index 00000000000..9dd35650ab6
--- /dev/null
+++ b/spec/tasks/admin_mode_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'rake_helper'
+
+RSpec.describe 'admin mode on tasks' do
+ before do
+ allow(::Gitlab::Runtime).to receive(:test_suite?).and_return(false)
+ allow(::Gitlab::Runtime).to receive(:rake?).and_return(true)
+ end
+
+ shared_examples 'verify admin mode' do |state|
+ it 'matches the expected admin mode' do
+ Rake::Task.define_task :verify_admin_mode do
+ expect(Gitlab::Auth::CurrentUserMode.new(user).admin_mode?).to be(state)
+ end
+
+ run_rake_task('verify_admin_mode')
+ end
+ end
+
+ describe 'with a regular user' do
+ let(:user) { create(:user) }
+
+ include_examples 'verify admin mode', false
+ end
+
+ describe 'with an admin' do
+ let(:user) { create(:admin) }
+
+ include_examples 'verify admin mode', true
+ end
+end
diff --git a/spec/views/projects/settings/operations/show.html.haml_spec.rb b/spec/views/projects/settings/operations/show.html.haml_spec.rb
index a22853d40d8..b2dd3556098 100644
--- a/spec/views/projects/settings/operations/show.html.haml_spec.rb
+++ b/spec/views/projects/settings/operations/show.html.haml_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe 'projects/settings/operations/show' do
expect(rendered).to have_content _('Prometheus')
expect(rendered).to have_content _('Link Prometheus monitoring to GitLab.')
- expect(rendered).to have_content _('To enable the installation of Prometheus on your clusters, deactivate the manual configuration below')
+ expect(rendered).to have_content _('To enable the installation of Prometheus on your clusters, deactivate the manual configuration.')
end
end
@@ -71,7 +71,7 @@ RSpec.describe 'projects/settings/operations/show' do
it 'renders the Operations Settings page' do
render
- expect(rendered).not_to have_content _('Select the Active checkbox to override the Auto Configuration with custom settings. If unchecked, Auto Configuration settings are used.')
+ expect(rendered).not_to have_content _('Auto configuration settings are used unless you override their values here.')
end
end
end