summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-01-13 09:10:52 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-01-13 09:10:52 +0000
commitab9c1dbb2dc0e591a6ce4466e15766d99f4abf4b (patch)
tree228f0953c110a7a2a4438666994995c702bac6de
parente6f170581eddc84da845d4f2e511f4776848e9f7 (diff)
downloadgitlab-ce-ab9c1dbb2dc0e591a6ce4466e15766d99f4abf4b.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock13
-rw-r--r--app/assets/javascripts/groups/members/components/app.vue4
-rw-r--r--app/assets/javascripts/jira_connect/components/app.vue10
-rw-r--r--app/assets/javascripts/jira_connect/index.js26
-rw-r--r--app/assets/javascripts/jira_connect/store/index.js9
-rw-r--r--app/assets/javascripts/jira_connect/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/jira_connect/store/mutations.js7
-rw-r--r--app/assets/javascripts/jira_connect/store/state.js3
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/new/index.js22
-rw-r--r--app/assets/stylesheets/framework/highlight.scss3
-rw-r--r--app/controllers/application_controller.rb21
-rw-r--r--app/controllers/groups/group_members_controller.rb4
-rw-r--r--app/controllers/projects_controller.rb2
-rw-r--r--app/views/admin/dev_ops_report/show.html.haml2
-rw-r--r--app/views/groups/group_members/index.html.haml31
-rw-r--r--changelogs/unreleased/247477-fix-double-render-errors-in-rescue-from.yml5
-rw-r--r--changelogs/unreleased/247936-fix-cut-off-file-blame-line-number.yml5
-rw-r--r--changelogs/unreleased/nfriend-remove-pagination-from-deployment-frequency-api.yml5
-rw-r--r--config/feature_flags/development/devops_adoption_feature.yml (renamed from config/feature_flags/development/group_members_filtered_search.yml)12
-rw-r--r--doc/administration/integration/plantuml.md10
-rw-r--r--doc/api/merge_requests.md44
-rw-r--r--doc/user/admin_area/analytics/dev_ops_report.md20
-rw-r--r--doc/user/group/index.md29
-rw-r--r--lib/api/helpers/merge_requests_helpers.rb12
-rw-r--r--locale/gitlab.pot15
-rw-r--r--spec/controllers/projects_controller_spec.rb17
-rw-r--r--spec/features/groups/members/sort_members_spec.rb196
-rw-r--r--spec/frontend/groups/members/components/app_spec.js22
-rw-r--r--spec/frontend/jira_connect/components/app_spec.js22
-rw-r--r--spec/frontend/jira_connect/store/mutations_spec.js18
-rw-r--r--spec/requests/api/merge_requests_spec.rb139
-rw-r--r--spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb24
33 files changed, 399 insertions, 357 deletions
diff --git a/Gemfile b/Gemfile
index d3e4293d500..768d28fa9b2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -352,8 +352,9 @@ end
group :development, :test do
gem 'deprecation_toolkit', '~> 1.5.1', require: false
gem 'bullet', '~> 6.1.0'
- gem 'pry-byebug', '~> 3.9.0', platform: :mri
+ gem 'gitlab-pry-byebug', platform: :mri, require: ['pry-byebug', 'pry-byebug/pry_remote_ext']
gem 'pry-rails', '~> 0.3.9'
+ gem 'pry-remote'
gem 'awesome_print', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 9c0896891a7..a39a504e34b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -445,6 +445,9 @@ GEM
gitlab-markup (1.7.1)
gitlab-net-dns (0.9.1)
gitlab-pg_query (1.3.1)
+ gitlab-pry-byebug (3.9.0)
+ byebug (~> 11.0)
+ pry (~> 0.13.0)
gitlab-sidekiq-fetcher (0.5.2)
sidekiq (~> 5)
gitlab-styles (6.0.0)
@@ -864,11 +867,11 @@ GEM
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
- pry-byebug (3.9.0)
- byebug (~> 11.0)
- pry (~> 0.13.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
+ pry-remote (0.1.8)
+ pry (~> 0.9)
+ slop (~> 3.0)
public_suffix (4.0.6)
puma (5.1.1)
nio4r (~> 2.0)
@@ -1131,6 +1134,7 @@ GEM
simplecov-html (0.12.2)
sixarm_ruby_unaccent (1.2.0)
slack-messenger (2.3.4)
+ slop (3.6.0)
snowplow-tracker (0.6.1)
contracts (~> 0.7, <= 0.11)
spring (2.1.1)
@@ -1364,6 +1368,7 @@ DEPENDENCIES
gitlab-mail_room (~> 0.0.8)
gitlab-markup (~> 1.7.1)
gitlab-net-dns (~> 0.9.1)
+ gitlab-pry-byebug
gitlab-sidekiq-fetcher (= 0.5.2)
gitlab-styles (~> 6.0.0)
gitlab_chronic_duration (~> 0.10.6.2)
@@ -1455,8 +1460,8 @@ DEPENDENCIES
png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.12.0)
- pry-byebug (~> 3.9.0)
pry-rails (~> 0.3.9)
+ pry-remote
puma (~> 5.1.1)
puma_worker_killer (~> 0.3.1)
rack (~> 2.2.3)
diff --git a/app/assets/javascripts/groups/members/components/app.vue b/app/assets/javascripts/groups/members/components/app.vue
index f6f3a955813..34a2c67fa9f 100644
--- a/app/assets/javascripts/groups/members/components/app.vue
+++ b/app/assets/javascripts/groups/members/components/app.vue
@@ -5,12 +5,10 @@ import MembersTable from '~/members/components/table/members_table.vue';
import FilterSortContainer from '~/members/components/filter_sort/filter_sort_container.vue';
import { scrollToElement } from '~/lib/utils/common_utils';
import { HIDE_ERROR } from '~/members/store/mutation_types';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
name: 'GroupMembersApp',
components: { MembersTable, FilterSortContainer, GlAlert },
- mixins: [glFeatureFlagsMixin()],
computed: {
...mapState(['showError', 'errorMessage']),
},
@@ -36,7 +34,7 @@ export default {
<gl-alert v-if="showError" ref="errorAlert" variant="danger" @dismiss="hideError">{{
errorMessage
}}</gl-alert>
- <filter-sort-container v-if="glFeatures.groupMembersFilteredSearch" />
+ <filter-sort-container />
<members-table />
</div>
</template>
diff --git a/app/assets/javascripts/jira_connect/components/app.vue b/app/assets/javascripts/jira_connect/components/app.vue
index 4a58113db1f..275a66d5956 100644
--- a/app/assets/javascripts/jira_connect/components/app.vue
+++ b/app/assets/javascripts/jira_connect/components/app.vue
@@ -1,16 +1,12 @@
<script>
+import { mapState } from 'vuex';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
name: 'JiraConnectApp',
mixins: [glFeatureFlagsMixin()],
computed: {
- state() {
- return this.$root.$data.state || {};
- },
- error() {
- return this.state.error;
- },
+ ...mapState(['errorMessage']),
showNewUi() {
return this.glFeatures.newJiraConnectUi;
},
@@ -21,7 +17,7 @@ export default {
<template>
<div>
<div v-if="showNewUi">
- <h3>{{ s__('Integrations|Linked namespaces') }}</h3>
+ <h3 data-testid="new-jira-connect-ui-heading">{{ s__('Integrations|Linked namespaces') }}</h3>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/jira_connect/index.js b/app/assets/javascripts/jira_connect/index.js
index bd261750ccd..05f13de6f53 100644
--- a/app/assets/javascripts/jira_connect/index.js
+++ b/app/assets/javascripts/jira_connect/index.js
@@ -1,23 +1,21 @@
import Vue from 'vue';
+import Vuex from 'vuex';
import $ from 'jquery';
import setConfigs from '@gitlab/ui/dist/config';
import Translate from '~/vue_shared/translate';
import GlFeatureFlagsPlugin from '~/vue_shared/gl_feature_flags_plugin';
-import App from './components/app.vue';
+import JiraConnectApp from './components/app.vue';
import { addSubscription, removeSubscription } from '~/jira_connect/api';
+import createStore from './store';
+import { SET_ERROR_MESSAGE } from './store/mutation_types';
-const store = {
- state: {
- error: '',
- },
- setErrorMessage(errorMessage) {
- this.state.error = errorMessage;
- },
-};
+Vue.use(Vuex);
+
+const store = createStore();
/**
- * Initialize necessary form handlers for the Jira Connect app
+ * Initialize form handlers for the Jira Connect app
*/
const initJiraFormHandlers = () => {
const reqComplete = () => {
@@ -27,7 +25,7 @@ const initJiraFormHandlers = () => {
const reqFailed = (res, fallbackErrorMessage) => {
const { responseJSON: { error = fallbackErrorMessage } = {} } = res || {};
- store.setErrorMessage(error);
+ store.commit(SET_ERROR_MESSAGE, error);
// eslint-disable-next-line no-alert
alert(error);
};
@@ -79,11 +77,9 @@ function initJiraConnect() {
return new Vue({
el,
- data: {
- state: store.state,
- },
+ store,
render(createElement) {
- return createElement(App, {});
+ return createElement(JiraConnectApp, {});
},
});
}
diff --git a/app/assets/javascripts/jira_connect/store/index.js b/app/assets/javascripts/jira_connect/store/index.js
new file mode 100644
index 00000000000..aa7e14269a4
--- /dev/null
+++ b/app/assets/javascripts/jira_connect/store/index.js
@@ -0,0 +1,9 @@
+import Vuex from 'vuex';
+import mutations from './mutations';
+import state from './state';
+
+export default () =>
+ new Vuex.Store({
+ state,
+ mutations,
+ });
diff --git a/app/assets/javascripts/jira_connect/store/mutation_types.js b/app/assets/javascripts/jira_connect/store/mutation_types.js
new file mode 100644
index 00000000000..7f6ff1256bb
--- /dev/null
+++ b/app/assets/javascripts/jira_connect/store/mutation_types.js
@@ -0,0 +1 @@
+export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE';
diff --git a/app/assets/javascripts/jira_connect/store/mutations.js b/app/assets/javascripts/jira_connect/store/mutations.js
new file mode 100644
index 00000000000..c3acd07f89f
--- /dev/null
+++ b/app/assets/javascripts/jira_connect/store/mutations.js
@@ -0,0 +1,7 @@
+import { SET_ERROR_MESSAGE } from './mutation_types';
+
+export default {
+ [SET_ERROR_MESSAGE](state, errorMessage) {
+ state.errorMessage = errorMessage;
+ },
+};
diff --git a/app/assets/javascripts/jira_connect/store/state.js b/app/assets/javascripts/jira_connect/store/state.js
new file mode 100644
index 00000000000..079b8350770
--- /dev/null
+++ b/app/assets/javascripts/jira_connect/store/state.js
@@ -0,0 +1,3 @@
+export default () => ({
+ errorMessage: undefined,
+});
diff --git a/app/assets/javascripts/pages/projects/pipelines/new/index.js b/app/assets/javascripts/pages/projects/pipelines/new/index.js
index d5563143f0c..08c31f2b3c6 100644
--- a/app/assets/javascripts/pages/projects/pipelines/new/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/new/index.js
@@ -3,17 +3,15 @@ import NewBranchForm from '~/new_branch_form';
import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list';
import initNewPipeline from '~/pipeline_new/index';
-document.addEventListener('DOMContentLoaded', () => {
- const el = document.getElementById('js-new-pipeline');
+const el = document.getElementById('js-new-pipeline');
- if (el) {
- initNewPipeline();
- } else {
- new NewBranchForm($('.js-new-pipeline-form')); // eslint-disable-line no-new
+if (el) {
+ initNewPipeline();
+} else {
+ new NewBranchForm($('.js-new-pipeline-form')); // eslint-disable-line no-new
- setupNativeFormVariableList({
- container: $('.js-ci-variable-list-section'),
- formField: 'variables_attributes',
- });
- }
-});
+ setupNativeFormVariableList({
+ container: $('.js-ci-variable-list-section'),
+ formField: 'variables_attributes',
+ });
+}
diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss
index 73a2170fc68..28577e2801e 100644
--- a/app/assets/stylesheets/framework/highlight.scss
+++ b/app/assets/stylesheets/framework/highlight.scss
@@ -45,7 +45,8 @@
a {
font-family: $monospace-font;
- display: block;
+ display: flex;
+ justify-content: flex-end;
font-size: $code-font-size !important;
white-space: nowrap;
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 24282a50cce..3cb7373a970 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -103,14 +103,6 @@ class ApplicationController < ActionController::Base
head :forbidden, retry_after: Gitlab::Auth::UniqueIpsLimiter.config.unique_ips_limit_time_window
end
- rescue_from GRPC::Unavailable, Gitlab::Git::CommandError do |exception|
- log_exception(exception)
-
- headers['Retry-After'] = exception.retry_after if exception.respond_to?(:retry_after)
-
- render_503
- end
-
def redirect_back_or_default(default: root_path, options: {})
redirect_back(fallback_location: default, **options)
end
@@ -246,19 +238,6 @@ class ApplicationController < ActionController::Base
head :unprocessable_entity
end
- def render_503
- respond_to do |format|
- format.html do
- render(
- file: Rails.root.join("public", "503"),
- layout: false,
- status: :service_unavailable
- )
- end
- format.any { head :service_unavailable }
- end
- end
-
def no_cache_headers
DEFAULT_GITLAB_NO_CACHE_HEADERS.each do |k, v|
headers[k] = v
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index d1b09e1b49e..5df7ff0632a 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -14,10 +14,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
# Authorize
before_action :authorize_admin_group_member!, except: admin_not_required_endpoints
- before_action do
- push_frontend_feature_flag(:group_members_filtered_search, @group, default_enabled: true)
- end
-
skip_before_action :check_two_factor_requirement, only: :leave
skip_cross_project_access_check :index, :create, :update, :destroy, :request_access,
:approve_access_request, :leave, :resend_invite,
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 3744517934a..2635a93433f 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -94,7 +94,7 @@ class ProjectsController < Projects::ApplicationController
redirect_to(edit_project_path(@project, anchor: 'js-general-project-settings'))
end
else
- flash.now[:alert] = result[:message]
+ flash[:alert] = result[:message]
@project.reset
format.html { render_edit }
diff --git a/app/views/admin/dev_ops_report/show.html.haml b/app/views/admin/dev_ops_report/show.html.haml
index 19ce285162f..733c0de9fe9 100644
--- a/app/views/admin/dev_ops_report/show.html.haml
+++ b/app/views/admin/dev_ops_report/show.html.haml
@@ -3,7 +3,7 @@
.container
.gl-mt-3
- - if Gitlab.ee? && License.feature_available?(:devops_adoption)
+ - if Gitlab.ee? && Feature.enabled?(:devops_adoption_feature, default_enabled: false) && License.feature_available?(:devops_adoption)
= render_if_exists 'admin/dev_ops_report/devops_tabs'
- else
= render 'report'
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 9a7cfc0a573..e3fd9d4bb17 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -3,8 +3,6 @@
- show_invited_members = can_manage_members && @invited_members.exists?
- show_access_requests = can_manage_members && @requesters.exists?
- invited_active = params[:search_invited].present? || params[:invited_members_page].present?
-- filtered_search_enabled = Feature.enabled?(:group_members_filtered_search, @group, default_enabled: true)
-- form_item_label_css_class = 'label-bold gl-mr-2 gl-mb-0 gl-py-2 align-self-md-center'
.js-remove-member-modal
.project-members-page.gl-mt-3
@@ -51,52 +49,23 @@
%span.badge.badge-pill= @requesters.count
.tab-content
#tab-members.tab-pane{ class: ('active' unless invited_active) }
- - unless filtered_search_enabled
- = render 'shared/members/tab_pane/header' do
- = render 'shared/members/tab_pane/title' do
- = html_escape(_('Members with access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
- = form_tag group_group_members_path(@group), method: :get, class: 'user-search-form gl-display-flex gl-md-align-items-center gl-flex-wrap gl-flex-direction-column gl-md-flex-direction-row gl-mx-n3 gl-my-n3', data: { testid: 'user-search-form' } do
- .gl-px-3.gl-py-2
- .search-control-wrap.gl-relative
- = render 'shared/members/search_field'
- - if can_manage_members
- = render 'shared/members/tab_pane/form_item' do
- = label_tag '2fa', _('2FA'), class: form_item_label_css_class
- = render 'shared/members/filter_2fa_dropdown'
- = render 'shared/members/tab_pane/form_item' do
- = label_tag :sort_by, _('Sort by'), class: form_item_label_css_class
- = render 'shared/members/sort_dropdown'
.js-group-members-list{ data: group_members_list_data_attributes(@group, @members) }
.loading
.spinner.spinner-md
= paginate @members, theme: 'gitlab', params: { invited_members_page: nil, search_invited: nil }
- if @group.shared_with_group_links.any?
#tab-groups.tab-pane
- - unless filtered_search_enabled
- = render 'shared/members/tab_pane/header' do
- = render 'shared/members/tab_pane/title' do
- = html_escape(_('Groups with access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
.js-group-linked-list{ data: linked_groups_list_data_attributes(@group) }
.loading
.spinner.spinner-md
- if show_invited_members
#tab-invited-members.tab-pane{ class: ('active' if invited_active) }
- - unless filtered_search_enabled
- = render 'shared/members/tab_pane/header' do
- = render 'shared/members/tab_pane/title' do
- = html_escape(_('Members invited to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
- = form_tag group_group_members_path(@group), method: :get, class: 'user-search-form', data: { testid: 'user-search-form' } do
- = render 'shared/members/search_field', name: 'search_invited'
.js-group-invited-members-list{ data: group_members_list_data_attributes(@group, @invited_members) }
.loading
.spinner.spinner-md
= paginate @invited_members, param_name: 'invited_members_page', theme: 'gitlab', params: { page: nil }
- if show_access_requests
#tab-access-requests.tab-pane
- - unless filtered_search_enabled
- = render 'shared/members/tab_pane/header' do
- = render 'shared/members/tab_pane/title' do
- = html_escape(_('Users requesting access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
.js-group-access-requests-list{ data: group_members_list_data_attributes(@group, @requesters) }
.loading
.spinner.spinner-md
diff --git a/changelogs/unreleased/247477-fix-double-render-errors-in-rescue-from.yml b/changelogs/unreleased/247477-fix-double-render-errors-in-rescue-from.yml
new file mode 100644
index 00000000000..f6aa283b54b
--- /dev/null
+++ b/changelogs/unreleased/247477-fix-double-render-errors-in-rescue-from.yml
@@ -0,0 +1,5 @@
+---
+title: Correctly handle Gitaly being unavailable in more locations
+merge_request: 51222
+author:
+type: fixed
diff --git a/changelogs/unreleased/247936-fix-cut-off-file-blame-line-number.yml b/changelogs/unreleased/247936-fix-cut-off-file-blame-line-number.yml
new file mode 100644
index 00000000000..ba25f348cc1
--- /dev/null
+++ b/changelogs/unreleased/247936-fix-cut-off-file-blame-line-number.yml
@@ -0,0 +1,5 @@
+---
+title: Fix cut off line number in file blame
+merge_request: 51259
+author:
+type: fixed
diff --git a/changelogs/unreleased/nfriend-remove-pagination-from-deployment-frequency-api.yml b/changelogs/unreleased/nfriend-remove-pagination-from-deployment-frequency-api.yml
new file mode 100644
index 00000000000..960f04a8741
--- /dev/null
+++ b/changelogs/unreleased/nfriend-remove-pagination-from-deployment-frequency-api.yml
@@ -0,0 +1,5 @@
+---
+title: Remove pagination from Deployment Frequency API endpoint
+merge_request: 51137
+author:
+type: changed
diff --git a/config/feature_flags/development/group_members_filtered_search.yml b/config/feature_flags/development/devops_adoption_feature.yml
index 8a30bdd3d92..0b643b4e60e 100644
--- a/config/feature_flags/development/group_members_filtered_search.yml
+++ b/config/feature_flags/development/devops_adoption_feature.yml
@@ -1,8 +1,8 @@
---
-name: group_members_filtered_search
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48272
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/289911
-milestone: '13.7'
+name: devops_adoption_feature
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46005
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/271568
+milestone: '13.6'
type: development
-group: group::access
-default_enabled: true
+group: group::optimize
+default_enabled: false
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index a5997bee2db..cd61dc9a2bf 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -90,8 +90,8 @@ the configuration below accordingly.
### Making local PlantUML accessible using custom GitLab setup
The PlantUML server runs locally on your server, so it is not accessible
-externally. As such, it is necessary to catch external PlantUML calls and
-redirect them to the local server.
+externally by default. As such, it is necessary to catch external PlantUML
+calls and redirect them to the local server.
The idea is to redirect each call to `https://gitlab.example.com/-/plantuml/`
to the local PlantUML server `http://plantuml:8080/` or `http://localhost:8080/plantuml/`, depending on your setup.
@@ -112,6 +112,12 @@ To activate the changes, run the following command:
sudo gitlab-ctl reconfigure
```
+Note that the redirection through GitLab **must** be configured
+when running [GitLab with TLS](https://docs.gitlab.com/omnibus/settings/ssl.html)
+due to PlantUML's use of the insecure HTTP protocol. Newer browsers such
+as [Google Chrome 86+](https://www.chromestatus.com/feature/4926989725073408)
+do not load insecure HTTP resources on a page served over HTTPS.
+
### Security
PlantUML has features that allows fetching network resources.
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 533bfa542c0..c43ac96a42f 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -14,6 +14,7 @@ type: reference, api
> - `author_username` and `author_username` were [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13060) in GitLab 12.10.
> - `reference` was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354) in GitLab 12.10 in favour of `references`.
> - `with_merge_status_recheck` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31890) in GitLab 13.0.
+> - `reviewer_username` and `reviewer_id` were [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49341) in GitLab 13.8.
Every API call to merge requests must be authenticated.
@@ -92,13 +93,15 @@ Parameters:
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved_by_ids` **(STARTER)** | integer array | no | Returns merge requests which have been approved by all the users with the given `id`s (Max: 5). `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
+| `reviewer_id` | integer | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#reviewer) with the given user `id`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_username`. |
+| `reviewer_username` | string | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#reviewer) with the given `username`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_id`. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `source_branch` | string | no | Return merge requests with the given source branch. |
| `target_branch` | string | no | Return merge requests with the given target branch. |
| `search` | string | no | Search merge requests against their `title` and `description`. |
| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description`. |
| `wip` | string | no | Filter merge requests against their `wip` status. `yes` to return *only* WIP merge requests, `no` to return *non* WIP merge requests. |
-| `not` | Hash | no | Return merge requests that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji`. |
+| `not` | Hash | no | Return merge requests that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `reviewer_id`, `reviewer_username`, `my_reaction_emoji`. |
| `environment` | string | no | Returns merge requests deployed to the given environment. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `deployed_before` | datetime | no | Return merge requests deployed before the given date/time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `deployed_after` | datetime | no | Return merge requests deployed after the given date/time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
@@ -153,6 +156,14 @@ Parameters:
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
"web_url": "https://gitlab.example.com/axel.block"
}],
+ "reviewers": [{
+ "id": 2,
+ "name": "Sam Bauch",
+ "username": "kenyatta_oconnell",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon",
+ "web_url": "http://gitlab.example.com//kenyatta_oconnell"
+ }],
"source_project_id": 2,
"target_project_id": 3,
"labels": [
@@ -268,11 +279,15 @@ Parameters:
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved_by_ids` **(STARTER)** | integer array | no | Returns merge requests which have been approved by all the users with the given `id`s (Max: 5). `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
+| `reviewer_id` | integer | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#reviewer) with the given user `id`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_username`. |
+| `reviewer_username` | string | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#reviewer) with the given `username`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_id`. |
+
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `source_branch` | string | no | Return merge requests with the given source branch. |
| `target_branch` | string | no | Return merge requests with the given target branch. |
| `search` | string | no | Search merge requests against their `title` and `description`. |
| `wip` | string | no | Filter merge requests against their `wip` status. `yes` to return *only* WIP merge requests, `no` to return *non* WIP merge requests. |
+| `not` | Hash | no | Return merge requests that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `reviewer_id`, `reviewer_username`, `my_reaction_emoji`. |
```json
[
@@ -324,6 +339,14 @@ Parameters:
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
"web_url": "https://gitlab.example.com/axel.block"
}],
+ "reviewers": [{
+ "id": 2,
+ "name": "Sam Bauch",
+ "username": "kenyatta_oconnell",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon",
+ "web_url": "http://gitlab.example.com//kenyatta_oconnell"
+ }],
"source_project_id": 2,
"target_project_id": 3,
"labels": [
@@ -432,11 +455,14 @@ Parameters:
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13060) in GitLab 9.5)_. |
| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved_by_ids` **(STARTER)** | integer array | no | Returns merge requests which have been approved by all the users with the given `id`s (Max: 5). `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
+| `reviewer_id` | integer | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#enable-or-disable-merge-request-reviewers) with the given user `id`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_username`. |
+| `reviewer_username` | string | no | Returns merge requests which have the user as a [reviewer](../user/project/merge_requests/getting_started.md#enable-or-disable-merge-request-reviewers) with the given `username`. `None` returns merge requests with no reviewers. `Any` returns merge requests with any reviewer. Mutually exclusive with `reviewer_id`. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_. |
| `source_branch` | string | no | Return merge requests with the given source branch. |
| `target_branch` | string | no | Return merge requests with the given target branch. |
| `search` | string | no | Search merge requests against their `title` and `description`. |
| `non_archived` | boolean | no | Return merge requests from non archived projects only. Default is true. _(Introduced in [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23809))_. |
+| `not` | Hash | no | Return merge requests that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `reviewer_id`, `reviewer_username`, `my_reaction_emoji`. |
```json
[
@@ -488,6 +514,14 @@ Parameters:
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
"web_url": "https://gitlab.example.com/axel.block"
}],
+ "reviewers": [{
+ "id": 2,
+ "name": "Sam Bauch",
+ "username": "kenyatta_oconnell",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon",
+ "web_url": "http://gitlab.example.com//kenyatta_oconnell"
+ }],
"source_project_id": 2,
"target_project_id": 3,
"labels": [
@@ -618,6 +652,14 @@ Parameters:
"avatar_url": "http://www.gravatar.com/avatar/46f6f7dc858ada7be1853f7fb96e81da?s=80&d=identicon",
"web_url": "https://gitlab.example.com/axel.block"
}],
+ "reviewers": [{
+ "id": 2,
+ "name": "Sam Bauch",
+ "username": "kenyatta_oconnell",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon",
+ "web_url": "http://gitlab.example.com//kenyatta_oconnell"
+ }],
"source_project_id": 2,
"target_project_id": 3,
"labels": [
diff --git a/doc/user/admin_area/analytics/dev_ops_report.md b/doc/user/admin_area/analytics/dev_ops_report.md
index 75b99afa526..80108fba060 100644
--- a/doc/user/admin_area/analytics/dev_ops_report.md
+++ b/doc/user/admin_area/analytics/dev_ops_report.md
@@ -38,7 +38,7 @@ collected before this feature is available.
## DevOps Adoption **(ULTIMATE)**
-[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247112) in GitLab 13.7.
+[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/247112) in GitLab 13.7 as a [Beta feature](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta).
The DevOps Adoption tab shows you which segments of your organization are using the most essential features of GitLab:
@@ -61,3 +61,21 @@ DevOps Adoption allows you to:
- Find the groups that have adopted certain features and can provide guidance to other groups on how to use those features.
![DevOps Report](img/dev_ops_adoption_v13_7.png)
+
+### Disable or enable DevOps Adoption
+
+DevOps Adoption is deployed behind a feature flag that is **disabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
+can opt to enable it.
+
+To enable it:
+
+```ruby
+Feature.enable(:devops_adoption_feature)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:devops_adoption_feature)
+```
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index eba1ed78d2b..74406d3e5cf 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -215,10 +215,7 @@ To remove a member from a group:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21727) in GitLab 12.6.
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/228675) in GitLab 13.7.
-> - Improvements are [deployed behind a feature flag](../feature_flags.md), enabled by default.
-> - Improvements are enabled on GitLab.com.
-> - Improvements are recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can opt to [disable improvements](#enable-or-disable-improvements-to-the-ability-to-filter-and-sort-group-members). **(CORE ONLY)**
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289911) in GitLab 13.8.
The following sections illustrate how you can filter and sort members in a group. To view these options,
navigate to your desired group, go to **Members**, and include the noted search terms.
@@ -269,30 +266,6 @@ You can sort members by **Account**, **Access granted**, **Max role**, or **Last
![Group members sort](img/group_members_sort_13_7.png)
-### Enable or disable improvements to the ability to filter and sort group members **(CORE ONLY)**
-
-Group member filtering and sorting improvements are deployed behind a feature flag that is **enabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
-can opt to disable the improvements.
-
-To disable them:
-
-```ruby
-# For the instance
-Feature.disable(:group_members_filtered_search)
-# For a single group
-Feature.disable(:group_members_filtered_search, Group.find(<group id>))
-```
-
-To enable them:
-
-```ruby
-# For the instance
-Feature.enable(:group_members_filtered_search)
-# For a single group
-Feature.enable(:group_members_filtered_search, Group.find(<group id>))
-```
-
## Changing the default branch protection of a group
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7583) in GitLab 12.9.
diff --git a/lib/api/helpers/merge_requests_helpers.rb b/lib/api/helpers/merge_requests_helpers.rb
index 9b38eeb1e72..f8fe40f7135 100644
--- a/lib/api/helpers/merge_requests_helpers.rb
+++ b/lib/api/helpers/merge_requests_helpers.rb
@@ -21,6 +21,9 @@ module API
coerce_with: Validations::Validators::CheckAssigneesCount.coerce,
desc: 'Return merge requests which are assigned to the user with the given username'
mutually_exclusive :assignee_id, :assignee_username
+ optional :reviewer_username,
+ type: String,
+ desc: 'Return merge requests which have the user as a reviewer with the given username'
optional :labels,
type: Array[String],
@@ -32,6 +35,11 @@ module API
params :merge_requests_base_params do
use :merge_requests_negatable_params
+ optional :reviewer_id,
+ types: [Integer, String],
+ integer_none_any: true,
+ desc: 'Return merge requests which have the user as a reviewer with the given ID'
+ mutually_exclusive :reviewer_id, :reviewer_username
optional :state,
type: String,
values: %w[opened closed locked merged all],
@@ -72,6 +80,10 @@ module API
optional :wip, type: String, values: %w[yes no], desc: 'Search merge requests for WIP in the title'
optional :not, type: Hash, desc: 'Parameters to negate' do
use :merge_requests_negatable_params
+ optional :reviewer_id,
+ types: Integer,
+ desc: 'Return merge requests which have the user as a reviewer with the given ID'
+ mutually_exclusive :reviewer_id, :reviewer_username
end
optional :deployed_before,
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 7885615e6d7..34d6742bd59 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -14114,9 +14114,6 @@ msgstr ""
msgid "Groups with access to %{strong_open}%{project_name}%{strong_close}"
msgstr ""
-msgid "Groups with access to %{strong_start}%{group_name}%{strong_end}"
-msgstr ""
-
msgid "GroupsDropdown|Frequently visited"
msgstr ""
@@ -17367,9 +17364,6 @@ msgstr ""
msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
msgstr ""
-msgid "Members invited to %{strong_start}%{group_name}%{strong_end}"
-msgstr ""
-
msgid "Members invited to %{strong_start}%{project_name}%{strong_end}"
msgstr ""
@@ -17388,9 +17382,6 @@ msgstr ""
msgid "Members of a group may only view projects they have permission to access"
msgstr ""
-msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
-msgstr ""
-
msgid "Members|%{time} by %{user}"
msgstr ""
@@ -30911,9 +30902,6 @@ msgstr ""
msgid "Users requesting access to"
msgstr ""
-msgid "Users requesting access to %{strong_start}%{group_name}%{strong_end}"
-msgstr ""
-
msgid "Users requesting access to %{strong_start}%{project_name}%{strong_end}"
msgstr ""
@@ -32938,6 +32926,9 @@ msgstr ""
msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
msgstr ""
+msgid "can't be enabled because signed commits are required for this project"
+msgstr ""
+
msgid "cannot be a date in the past"
msgstr ""
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 51ac005883e..8e738af7dd0 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -211,21 +211,6 @@ RSpec.describe ProjectsController do
end
end
- context 'when the storage is not available', :broken_storage do
- let_it_be(:project) { create(:project, :broken_storage) }
-
- before do
- project.add_developer(user)
- sign_in(user)
- end
-
- it 'renders a 503' do
- get :show, params: { namespace_id: project.namespace, id: project }
-
- expect(response).to have_gitlab_http_status(:service_unavailable)
- end
- end
-
context "project with empty repo" do
let_it_be(:empty_project) { create(:project_empty_repo, :public) }
@@ -616,7 +601,7 @@ RSpec.describe ProjectsController do
expect { update_project path: 'renamed_path' }
.not_to change { project.reload.path }
- expect(controller).to set_flash.now[:alert].to(s_('UpdateProject|Cannot rename project because it contains container registry tags!'))
+ expect(controller).to set_flash[:alert].to(s_('UpdateProject|Cannot rename project because it contains container registry tags!'))
expect(response).to have_gitlab_http_status(:ok)
end
end
diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb
index 68a748aa76a..03758e0d401 100644
--- a/spec/features/groups/members/sort_members_spec.rb
+++ b/spec/features/groups/members/sort_members_spec.rb
@@ -16,174 +16,92 @@ RSpec.describe 'Groups > Members > Sort members', :js do
sign_in(owner)
end
- context 'when `group_members_filtered_search` feature flag is enabled' do
- def expect_sort_by(text, sort_direction)
- within('[data-testid="members-sort-dropdown"]') do
- expect(page).to have_css('button[aria-haspopup="true"]', text: text)
- expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}")
- end
- end
-
- it 'sorts by account by default' do
- visit_members_list(sort: nil)
-
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
-
- expect_sort_by('Account', :asc)
- end
-
- it 'sorts by max role ascending' do
- visit_members_list(sort: :access_level_asc)
-
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
-
- expect_sort_by('Max role', :asc)
- end
-
- it 'sorts by max role descending' do
- visit_members_list(sort: :access_level_desc)
-
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
-
- expect_sort_by('Max role', :desc)
- end
-
- it 'sorts by access granted ascending' do
- visit_members_list(sort: :last_joined)
-
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
-
- expect_sort_by('Access granted', :asc)
- end
-
- it 'sorts by access granted descending' do
- visit_members_list(sort: :oldest_joined)
-
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
-
- expect_sort_by('Access granted', :desc)
- end
-
- it 'sorts by account ascending' do
- visit_members_list(sort: :name_asc)
-
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
-
- expect_sort_by('Account', :asc)
+ def expect_sort_by(text, sort_direction)
+ within('[data-testid="members-sort-dropdown"]') do
+ expect(page).to have_css('button[aria-haspopup="true"]', text: text)
+ expect(page).to have_button("Sorting Direction: #{sort_direction == :asc ? 'Ascending' : 'Descending'}")
end
+ end
- it 'sorts by account descending' do
- visit_members_list(sort: :name_desc)
+ it 'sorts by account by default' do
+ visit_members_list(sort: nil)
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
- expect_sort_by('Account', :desc)
- end
+ expect_sort_by('Account', :asc)
+ end
- it 'sorts by last sign-in ascending', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :recent_sign_in)
+ it 'sorts by max role ascending' do
+ visit_members_list(sort: :access_level_asc)
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
- expect_sort_by('Last sign-in', :asc)
- end
+ expect_sort_by('Max role', :asc)
+ end
- it 'sorts by last sign-in descending', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :oldest_sign_in)
+ it 'sorts by max role descending' do
+ visit_members_list(sort: :access_level_desc)
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
- expect_sort_by('Last sign-in', :desc)
- end
+ expect_sort_by('Max role', :desc)
end
- context 'when `group_members_filtered_search` feature flag is disabled' do
- dropdown_toggle_selector = '[data-testid="user-sort-dropdown"] [data-testid="dropdown-toggle"]'
+ it 'sorts by access granted ascending' do
+ visit_members_list(sort: :last_joined)
- before do
- stub_feature_flags(group_members_filtered_search: false)
- end
-
- it 'sorts alphabetically by default' do
- visit_members_list(sort: nil)
-
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending')
- end
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
- it 'sorts by access level ascending' do
- visit_members_list(sort: :access_level_asc)
+ expect_sort_by('Access granted', :asc)
+ end
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, ascending')
- end
+ it 'sorts by access granted descending' do
+ visit_members_list(sort: :oldest_joined)
- it 'sorts by access level descending' do
- visit_members_list(sort: :access_level_desc)
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, descending')
- end
+ expect_sort_by('Access granted', :desc)
+ end
- it 'sorts by last joined' do
- visit_members_list(sort: :last_joined)
+ it 'sorts by account ascending' do
+ visit_members_list(sort: :name_asc)
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Last joined')
- end
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
- it 'sorts by oldest joined' do
- visit_members_list(sort: :oldest_joined)
+ expect_sort_by('Account', :asc)
+ end
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest joined')
- end
+ it 'sorts by account descending' do
+ visit_members_list(sort: :name_desc)
- it 'sorts by name ascending' do
- visit_members_list(sort: :name_asc)
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending')
- end
+ expect_sort_by('Account', :desc)
+ end
- it 'sorts by name descending' do
- visit_members_list(sort: :name_desc)
+ it 'sorts by last sign-in ascending', :clean_gitlab_redis_shared_state do
+ visit_members_list(sort: :recent_sign_in)
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Name, descending')
- end
+ expect(first_row.text).to include(owner.name)
+ expect(second_row.text).to include(developer.name)
- it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :recent_sign_in)
+ expect_sort_by('Last sign-in', :asc)
+ end
- expect(first_row.text).to include(owner.name)
- expect(second_row.text).to include(developer.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Recent sign in')
- end
+ it 'sorts by last sign-in descending', :clean_gitlab_redis_shared_state do
+ visit_members_list(sort: :oldest_sign_in)
- it 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do
- visit_members_list(sort: :oldest_sign_in)
+ expect(first_row.text).to include(developer.name)
+ expect(second_row.text).to include(owner.name)
- expect(first_row.text).to include(developer.name)
- expect(second_row.text).to include(owner.name)
- expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest sign in')
- end
+ expect_sort_by('Last sign-in', :desc)
end
def visit_members_list(sort:)
diff --git a/spec/frontend/groups/members/components/app_spec.js b/spec/frontend/groups/members/components/app_spec.js
index 208e2fc35b6..9847dacbec8 100644
--- a/spec/frontend/groups/members/components/app_spec.js
+++ b/spec/frontend/groups/members/components/app_spec.js
@@ -87,21 +87,9 @@ describe('GroupMembersApp', () => {
});
});
- describe.each`
- featureFlagValue | exists
- ${true} | ${true}
- ${false} | ${false}
- `(
- 'when `group_members_filtered_search` feature flag is $featureFlagValue',
- ({ featureFlagValue, exists }) => {
- it(`${exists ? 'renders' : 'does not render'} FilterSortContainer`, () => {
- createComponent(
- {},
- { provide: { glFeatures: { groupMembersFilteredSearch: featureFlagValue } } },
- );
-
- expect(findFilterSortContainer().exists()).toBe(exists);
- });
- },
- );
+ it('renders `FilterSortContainer`', () => {
+ createComponent();
+
+ expect(findFilterSortContainer().exists()).toBe(true);
+ });
});
diff --git a/spec/frontend/jira_connect/components/app_spec.js b/spec/frontend/jira_connect/components/app_spec.js
index d2d0ced8d16..42ce14e397a 100644
--- a/spec/frontend/jira_connect/components/app_spec.js
+++ b/spec/frontend/jira_connect/components/app_spec.js
@@ -1,17 +1,22 @@
import { shallowMount } from '@vue/test-utils';
-
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import JiraConnectApp from '~/jira_connect/components/app.vue';
describe('JiraConnectApp', () => {
let wrapper;
+ const findHeader = () => wrapper.findByTestId('new-jira-connect-ui-heading');
+ const findHeaderText = () => findHeader().text();
+
const createComponent = (options = {}) => {
- wrapper = shallowMount(JiraConnectApp, {
- provide: {
- glFeatures: { newJiraConnectUi: true },
- },
- ...options,
- });
+ wrapper = extendedWrapper(
+ shallowMount(JiraConnectApp, {
+ provide: {
+ glFeatures: { newJiraConnectUi: true },
+ },
+ ...options,
+ }),
+ );
};
afterEach(() => {
@@ -19,9 +24,6 @@ describe('JiraConnectApp', () => {
wrapper = null;
});
- const findHeader = () => wrapper.find('h3');
- const findHeaderText = () => findHeader().text();
-
describe('template', () => {
it('renders new UI', () => {
createComponent();
diff --git a/spec/frontend/jira_connect/store/mutations_spec.js b/spec/frontend/jira_connect/store/mutations_spec.js
new file mode 100644
index 00000000000..d1f9d22b3de
--- /dev/null
+++ b/spec/frontend/jira_connect/store/mutations_spec.js
@@ -0,0 +1,18 @@
+import mutations from '~/jira_connect/store/mutations';
+import state from '~/jira_connect/store/state';
+
+describe('JiraConnect store mutations', () => {
+ let localState;
+
+ beforeEach(() => {
+ localState = state();
+ });
+
+ describe('SET_ERROR_MESSAGE', () => {
+ it('sets error message', () => {
+ mutations.SET_ERROR_MESSAGE(localState, 'test error');
+
+ expect(localState.errorMessage).toBe('test error');
+ });
+ });
+});
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 4339f1dd830..3a3eae73932 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -440,6 +440,7 @@ RSpec.describe API::MergeRequests do
milestone: milestone,
author: user,
assignees: [user],
+ reviewers: [user2],
source_project: project,
target_project: project,
source_branch: 'what',
@@ -498,6 +499,71 @@ RSpec.describe API::MergeRequests do
expect(mr['assignee']['id']).not_to eq(user2.id)
end
end
+
+ context 'filter by reviewer' do
+ context 'with reviewer_id' do
+ context 'with an id' do
+ let(:params) { { not: { reviewer_id: user2.id } } }
+
+ it 'returns merge requests that do not have the given reviewer' do
+ get api(endpoint_path, user), params: { not: { reviewer_id: user2.id } }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an(Array)
+ expect(json_response.length).to eq(4)
+ expect(json_response.map { |mr| mr['id'] }).not_to include(merge_request2)
+ end
+ end
+
+ context 'with Any' do
+ let(:params) { { not: { reviewer_id: 'Any' } } }
+
+ it 'returns a 400' do
+ # Any is not supported for negated filter
+ get api(endpoint_path, user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('not[reviewer_id] is invalid')
+ end
+ end
+
+ context 'with None' do
+ let(:params) { { not: { reviewer_id: 'None' } } }
+
+ it 'returns a 400' do
+ # None is not supported for negated filter
+ get api(endpoint_path, user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('not[reviewer_id] is invalid')
+ end
+ end
+ end
+
+ context 'with reviewer_username' do
+ let(:params) { { not: { reviewer_username: user2.username } } }
+
+ it 'returns merge requests that do not have the given reviewer' do
+ get api(endpoint_path, user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an(Array)
+ expect(json_response.length).to eq(4)
+ expect(json_response.map { |mr| mr['id'] }).not_to include(merge_request2)
+ end
+ end
+
+ context 'when both reviewer_id and reviewer_username' do
+ let(:params) { { not: { reviewer_id: user2.id, reviewer_username: user2.username } } }
+
+ it 'returns a 400' do
+ get api('/merge_requests', user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('not[reviewer_id], not[reviewer_username] are mutually exclusive')
+ end
+ end
+ end
end
context 'source_branch param' do
@@ -666,6 +732,79 @@ RSpec.describe API::MergeRequests do
end
end
+ context 'filter by reviewer' do
+ let_it_be(:review_requested_mr1) do
+ create(:merge_request, :unique_branches, author: user, reviewers: [user2], source_project: project2, target_project: project2)
+ end
+
+ let_it_be(:review_requested_mr2) do
+ create(:merge_request, :unique_branches, author: user2, reviewers: [user], source_project: project2, target_project: project2)
+ end
+
+ let(:params) { { scope: :all } }
+
+ context 'with reviewer_id' do
+ let(:params) { super().merge(reviewer_id: reviewer_id) }
+
+ context 'with an id' do
+ let(:reviewer_id) { user2.id }
+
+ it 'returns review requested merge requests for the given user' do
+ get api('/merge_requests', user), params: params
+
+ expect_response_contain_exactly(review_requested_mr1.id)
+ end
+ end
+
+ context 'with Any' do
+ let(:reviewer_id) { 'Any' }
+
+ it 'returns review requested merge requests for any user' do
+ get api('/merge_requests', user), params: params
+
+ expect_response_contain_exactly(review_requested_mr1.id, review_requested_mr2.id)
+ end
+ end
+
+ context 'with None' do
+ let(:reviewer_id) { 'None' }
+
+ it 'returns merge requests that has no assigned reviewers' do
+ get api('/merge_requests', user), params: params
+
+ expect_response_contain_exactly(
+ merge_request.id,
+ merge_request_closed.id,
+ merge_request_merged.id,
+ merge_request_locked.id,
+ merge_request2.id
+ )
+ end
+ end
+ end
+
+ context 'with reviewer_username' do
+ let(:params) { super().merge(reviewer_username: user2.username) }
+
+ it 'returns review requested merge requests for the given user' do
+ get api('/merge_requests', user), params: params
+
+ expect_response_contain_exactly(review_requested_mr1.id)
+ end
+ end
+
+ context 'with both reviewer_id and reviewer_username' do
+ let(:params) { super().merge(reviewer_id: user2.id, reviewer_username: user2.username) }
+
+ it 'returns a 400' do
+ get api('/merge_requests', user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('reviewer_id, reviewer_username are mutually exclusive')
+ end
+ end
+ end
+
it 'returns an array of merge requests assigned to the given user' do
merge_request3 = create(:merge_request, :simple, author: user, assignees: [user2], source_project: project2, target_project: project2, source_branch: 'other-branch')
diff --git a/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb b/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb
index 9b738a4b002..00a0fb7e4c5 100644
--- a/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/repositories/git_http_controller_shared_examples.rb
@@ -77,30 +77,6 @@ RSpec.shared_examples Repositories::GitHttpController do
end
end
end
-
- context 'with exceptions' do
- before do
- allow(controller).to receive(:authenticate_user).and_return(true)
- allow(controller).to receive(:verify_workhorse_api!).and_return(true)
- end
-
- it 'returns 503 with GRPC Unavailable' do
- allow(controller).to receive(:access_check).and_raise(GRPC::Unavailable)
-
- get :info_refs, params: params
-
- expect(response).to have_gitlab_http_status(:service_unavailable)
- end
-
- it 'returns 503 with timeout error' do
- allow(controller).to receive(:access_check).and_raise(Gitlab::GitAccess::TimeoutError)
-
- get :info_refs, params: params
-
- expect(response).to have_gitlab_http_status(:service_unavailable)
- expect(response.body).to eq 'Gitlab::GitAccess::TimeoutError'
- end
- end
end
describe 'POST #git_upload_pack' do