diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-13 09:10:52 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-13 09:10:52 +0000 |
commit | ab9c1dbb2dc0e591a6ce4466e15766d99f4abf4b (patch) | |
tree | 228f0953c110a7a2a4438666994995c702bac6de | |
parent | e6f170581eddc84da845d4f2e511f4776848e9f7 (diff) | |
download | gitlab-ce-ab9c1dbb2dc0e591a6ce4466e15766d99f4abf4b.tar.gz |
Add latest changes from gitlab-org/gitlab@master
33 files changed, 399 insertions, 357 deletions
@@ -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 |