summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-10-08 03:08:39 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-10-08 03:08:39 +0000
commitf77969819ac54a13966f16153cae23a66590cc35 (patch)
tree0dcd98d62f691240b94c4b908b19f4385c2ead23
parent5ae54edfa9d6200eb12f831ef56a6e80207ca281 (diff)
downloadgitlab-ce-f77969819ac54a13966f16153cae23a66590cc35.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop.yml2
-rw-r--r--.rubocop_todo.yml93
-rw-r--r--app/assets/javascripts/pages/search/show/search.js16
-rw-r--r--app/assets/stylesheets/pages/search.scss16
-rw-r--r--app/controllers/graphql_controller.rb4
-rw-r--r--app/graphql/mutations/award_emojis/base.rb7
-rw-r--r--app/graphql/mutations/design_management/move.rb2
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/create.rb17
-rw-r--r--app/graphql/mutations/notes/base.rb5
-rw-r--r--app/graphql/mutations/notes/create/base.rb9
-rw-r--r--app/graphql/mutations/notes/destroy.rb6
-rw-r--r--app/graphql/mutations/todos/base.rb7
-rw-r--r--app/graphql/mutations/todos/restore_many.rb18
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml3
-rw-r--r--app/views/search/_filter.html.haml24
-rw-r--r--app/views/search/_form.html.haml2
-rw-r--r--app/views/shared/issuable/_reviewers.html.haml11
-rw-r--r--changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml5
-rw-r--r--changelogs/unreleased/bw_update_global_id_checks.yml5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql93
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json138
-rw-r--r--doc/ci/yaml/README.md67
-rw-r--r--locale/gitlab.pot9
-rw-r--r--qa/qa/runtime/env.rb4
-rw-r--r--qa/qa/support/json_formatter.rb3
-rw-r--r--spec/features/merge_requests/user_lists_merge_requests_spec.rb37
-rw-r--r--spec/features/search/user_uses_search_filters_spec.rb38
-rw-r--r--spec/graphql/mutations/todos/mark_done_spec.rb3
-rw-r--r--spec/graphql/mutations/todos/restore_many_spec.rb33
-rw-r--r--spec/graphql/mutations/todos/restore_spec.rb11
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/add_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb32
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_done_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_spec.rb4
-rw-r--r--spec/support/shared_examples/graphql/notes_creation_shared_examples.rb8
37 files changed, 560 insertions, 191 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 47dc85a79f0..12469c40b51 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -293,7 +293,7 @@ Gitlab/AvoidFeatureGet:
Enabled: true
RSpec/TimecopFreeze:
- Enabled: false
+ Enabled: true
AutoCorrect: true
Include:
- 'spec/**/*.rb'
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index d655f8beb95..ce5f53c9f84 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1173,3 +1173,96 @@ Rails/SaveBang:
- 'spec/tasks/gitlab/web_hook_rake_spec.rb'
- 'spec/uploaders/file_uploader_spec.rb'
- 'spec/uploaders/object_storage_spec.rb'
+
+# Offense count: 187
+# Cop supports --auto-correct.
+RSpec/TimecopFreeze:
+ Exclude:
+ - 'ee/spec/controllers/admin/application_settings_controller_spec.rb'
+ - 'ee/spec/controllers/projects/security/network_policies_controller_spec.rb'
+ - 'ee/spec/features/admin/admin_reset_pipeline_minutes_spec.rb'
+ - 'ee/spec/features/boards/sidebar_spec.rb'
+ - 'ee/spec/features/groups/analytics/cycle_analytics/filters_and_data_spec.rb'
+ - 'ee/spec/features/groups/iteration_spec.rb'
+ - 'ee/spec/features/projects/mirror_spec.rb'
+ - 'ee/spec/features/projects/services/prometheus_custom_metrics_spec.rb'
+ - 'ee/spec/finders/productivity_analytics_finder_spec.rb'
+ - 'ee/spec/frontend/fixtures/analytics.rb'
+ - 'ee/spec/helpers/vulnerabilities_helper_spec.rb'
+ - 'ee/spec/lib/analytics/merge_request_metrics_refresh_spec.rb'
+ - 'ee/spec/lib/analytics/productivity_analytics_request_params_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/background_migration/populate_vulnerability_historical_statistics_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/cycle_analytics/data_collector_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/cycle_analytics/group_stage_time_summary_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/group/stage_time_summary_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/type_of_work/tasks_by_type_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/group_saml/sso_enforcer_spec.rb'
+ - 'ee/spec/lib/gitlab/database/load_balancing/host_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/base_request_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/event_gap_tracking_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/git_push_http_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/log_cursor/daemon_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_updated_event_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/oauth/login_state_spec.rb'
+ - 'ee/spec/lib/gitlab/insights/reducers/count_per_period_reducer_spec.rb'
+ - 'ee/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb'
+ - 'ee/spec/lib/gitlab/prometheus/queries/cluster_query_spec.rb'
+ - 'ee/spec/migrations/populate_vulnerability_historical_statistics_for_year_spec.rb'
+ - 'ee/spec/migrations/remove_duplicated_cs_findings_spec.rb'
+ - 'ee/spec/migrations/remove_duplicated_cs_findings_without_vulnerability_id_spec.rb'
+ - 'ee/spec/migrations/schedule_fix_orphan_promoted_issues_spec.rb'
+ - 'ee/spec/migrations/schedule_merge_request_any_approval_rule_migration_spec.rb'
+ - 'ee/spec/migrations/schedule_populate_resolved_on_default_branch_column_spec.rb'
+ - 'ee/spec/migrations/schedule_populate_vulnerability_historical_statistics_spec.rb'
+ - 'ee/spec/migrations/schedule_project_any_approval_rule_migration_spec.rb'
+ - 'ee/spec/migrations/set_resolved_state_on_vulnerabilities_spec.rb'
+ - 'ee/spec/migrations/20190926180443_schedule_epic_issues_after_epics_move_spec.rb'
+ - 'ee/spec/models/analytics/cycle_analytics/group_level_spec.rb'
+ - 'ee/spec/models/burndown_spec.rb'
+ - 'ee/spec/models/ee/namespace_spec.rb'
+ - 'ee/spec/models/geo/project_registry_spec.rb'
+ - 'ee/spec/models/merge_train_spec.rb'
+ - 'ee/spec/models/productivity_analytics_spec.rb'
+ - 'ee/spec/models/project_spec.rb'
+ - 'ee/spec/models/vulnerabilities/export_spec.rb'
+ - 'ee/spec/requests/api/vulnerabilities_spec.rb'
+ - 'ee/spec/services/geo/file_download_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/confirm_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/dismiss_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/resolve_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/revert_to_detected_service_spec.rb'
+ - 'ee/spec/services/vulnerability_exports/export_service_spec.rb'
+ - 'ee/spec/support/shared_contexts/lib/gitlab/insights/reducers/reducers_shared_contexts.rb'
+ - 'qa/spec/support/repeater_spec.rb'
+ - 'spec/features/profiles/active_sessions_spec.rb'
+ - 'spec/features/projects/environments/environment_metrics_spec.rb'
+ - 'spec/features/users/active_sessions_spec.rb'
+ - 'spec/lib/atlassian/jira_connect/client_spec.rb'
+ - 'spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb'
+ - 'spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb'
+ - 'spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb'
+ - 'spec/lib/gitlab/anonymous_session_spec.rb'
+ - 'spec/lib/gitlab/auth/unique_ips_limiter_spec.rb'
+ - 'spec/lib/gitlab/checks/timed_logger_spec.rb'
+ - 'spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb'
+ - 'spec/lib/gitlab/cycle_analytics/usage_data_spec.rb'
+ - 'spec/lib/gitlab/instrumentation_helper_spec.rb'
+ - 'spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb'
+ - 'spec/lib/gitlab/puma_logging/json_formatter_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb'
+ - 'spec/lib/json_web_token/hmac_token_spec.rb'
+ - 'spec/lib/rspec_flaky/flaky_example_spec.rb'
+ - 'spec/lib/rspec_flaky/listener_spec.rb'
+ - 'spec/models/active_session_spec.rb'
+ - 'spec/models/container_repository_spec.rb'
+ - 'spec/models/pages/lookup_path_spec.rb'
+ - 'spec/models/project_feature_usage_spec.rb'
+ - 'spec/requests/api/v3/github_spec.rb'
+ - 'spec/serializers/entity_date_helper_spec.rb'
+ - 'spec/support/cycle_analytics_helpers/test_generation.rb'
+ - 'spec/support/helpers/cycle_analytics_helpers.rb'
+ - 'spec/support/helpers/javascript_fixtures_helpers.rb'
+ - 'spec/support/shared_contexts/rack_attack_shared_context.rb'
+ - 'spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb'
+ - 'spec/workers/concerns/reenqueuer_spec.rb'
+ - 'spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb'
diff --git a/app/assets/javascripts/pages/search/show/search.js b/app/assets/javascripts/pages/search/show/search.js
index 6ff74325a5e..2cd333f26e1 100644
--- a/app/assets/javascripts/pages/search/show/search.js
+++ b/app/assets/javascripts/pages/search/show/search.js
@@ -4,6 +4,7 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
import Api from '~/api';
import { __ } from '~/locale';
import Project from '~/pages/projects/project';
+import { visitUrl } from '~/lib/utils/url_utility';
import refreshCounts from './refresh_counts';
import setHighlightClass from './highlight_blob_search_result';
@@ -86,6 +87,10 @@ export default class Search {
$(document)
.off('click', this.searchClear)
.on('click', this.searchClear, this.clearSearchField.bind(this));
+
+ $('a.js-search-clear')
+ .off('click', this.clearSearchFilter)
+ .on('click', this.clearSearchFilter);
}
static submitSearch() {
@@ -108,6 +113,17 @@ export default class Search {
.focus();
}
+ // We need to manually follow the link on the anchors
+ // that have this event bound, as their `click` default
+ // behavior is prevented by the toggle logic.
+ /* eslint-disable-next-line class-methods-use-this */
+ clearSearchFilter(ev) {
+ const $target = $(ev.currentTarget);
+
+ visitUrl($target.href);
+ ev.stopPropagation();
+ }
+
getProjectsData(term) {
return new Promise(resolve => {
if (this.groupId) {
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 86caed329b4..a62e28a9b8a 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -198,6 +198,15 @@ input[type='checkbox']:hover {
}
}
+ .search-clear {
+ position: absolute;
+ right: 10px;
+ top: 9px;
+ padding: 0;
+ line-height: 0;
+ background: none;
+ border: 0;
+ }
.search-icon {
position: absolute;
@@ -247,14 +256,7 @@ input[type='checkbox']:hover {
}
.search-clear {
- position: absolute;
- right: 10px;
- top: 9px;
- padding: 0;
color: $gray-darkest;
- line-height: 0;
- background: none;
- border: 0;
&:hover,
&:focus {
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 5edad410724..b5deed70380 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -48,6 +48,10 @@ class GraphqlController < ApplicationController
render_error(exception.message, status: :unprocessable_entity)
end
+ rescue_from ::GraphQL::CoercionError do |exception|
+ render_error(exception.message, status: :unprocessable_entity)
+ end
+
private
def set_user_last_activity
diff --git a/app/graphql/mutations/award_emojis/base.rb b/app/graphql/mutations/award_emojis/base.rb
index 583744c3884..df6b883529e 100644
--- a/app/graphql/mutations/award_emojis/base.rb
+++ b/app/graphql/mutations/award_emojis/base.rb
@@ -6,7 +6,7 @@ module Mutations
authorize :award_emoji
argument :awardable_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Awardable],
required: true,
description: 'The global id of the awardable resource'
@@ -23,7 +23,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Awardable].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
# Called by mutations methods after performing an authorization check
diff --git a/app/graphql/mutations/design_management/move.rb b/app/graphql/mutations/design_management/move.rb
index 43e2e542408..aed4cfec0fd 100644
--- a/app/graphql/mutations/design_management/move.rb
+++ b/app/graphql/mutations/design_management/move.rb
@@ -38,7 +38,7 @@ module Mutations
# TODO: remove this line when the compatibility layer is removed
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
id = DesignID.coerce_isolated_input(id)
- GitlabSchema.object_from_id(id)
+ GitlabSchema.find_by_gid(id)
end
def not_found(gid)
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
index 6f316e76e2a..b064f55825f 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
@@ -18,12 +18,12 @@ module Mutations
description: 'The created annotation'
argument :environment_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Environment],
required: false,
description: 'The global id of the environment to add an annotation to'
argument :cluster_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Clusters::Cluster],
required: false,
description: 'The global id of the cluster to add an annotation to'
@@ -84,7 +84,7 @@ module Mutations
end
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ GitlabSchema.find_by_gid(id)
end
def annotation_create_params(args)
@@ -96,7 +96,16 @@ module Mutations
end
def annotation_source(args)
- annotation_source_id = args[:cluster_id] || args[:environment_id]
+ # TODO: remove these lines when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ annotation_source_id = if args[:cluster_id]
+ ::Types::GlobalIDType[::Clusters::Cluster].coerce_isolated_input(args[:cluster_id])
+ else
+ ::Types::GlobalIDType[::Environment].coerce_isolated_input(args[:environment_id])
+ end
+
+ # TODO: uncomment following line once lines above are removed
+ # annotation_source_id = args[:cluster_id] || args[:environment_id]
authorized_find!(id: annotation_source_id)
end
end
diff --git a/app/graphql/mutations/notes/base.rb b/app/graphql/mutations/notes/base.rb
index 31dabc0a660..d6d5f1e760d 100644
--- a/app/graphql/mutations/notes/base.rb
+++ b/app/graphql/mutations/notes/base.rb
@@ -11,7 +11,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove explicit coercion once compatibility layer has been removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Note].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
def check_object_is_noteable!(object)
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index f081eac368e..530c15f0c10 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -9,7 +9,7 @@ module Mutations
authorize :create_note
argument :noteable_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Noteable],
required: true,
description: 'The global id of the resource to add a note to'
@@ -42,6 +42,13 @@ module Mutations
private
+ def find_object(id:)
+ # TODO: remove explicit coercion once compatibility layer has been removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Noteable].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+
def create_note_params(noteable, args)
{
noteable: noteable,
diff --git a/app/graphql/mutations/notes/destroy.rb b/app/graphql/mutations/notes/destroy.rb
index a81322bc9b7..83a91f07896 100644
--- a/app/graphql/mutations/notes/destroy.rb
+++ b/app/graphql/mutations/notes/destroy.rb
@@ -8,9 +8,9 @@ module Mutations
authorize :admin_note
argument :id,
- GraphQL::ID_TYPE,
- required: true,
- description: 'The global id of the note to destroy'
+ ::Types::GlobalIDType[::Note],
+ required: true,
+ description: 'The global id of the note to destroy'
def resolve(id:)
note = authorized_find!(id: id)
diff --git a/app/graphql/mutations/todos/base.rb b/app/graphql/mutations/todos/base.rb
index 2a72019fbac..6db863796bc 100644
--- a/app/graphql/mutations/todos/base.rb
+++ b/app/graphql/mutations/todos/base.rb
@@ -6,7 +6,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Todo].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
def map_to_global_ids(ids)
@@ -16,7 +19,7 @@ module Mutations
end
def to_global_id(id)
- ::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s
+ Gitlab::GlobalId.as_global_id(id, model_name: Todo.name).to_s
end
end
end
diff --git a/app/graphql/mutations/todos/restore_many.rb b/app/graphql/mutations/todos/restore_many.rb
index c5e2750768c..ea5f5414134 100644
--- a/app/graphql/mutations/todos/restore_many.rb
+++ b/app/graphql/mutations/todos/restore_many.rb
@@ -8,7 +8,7 @@ module Mutations
MAX_UPDATE_AMOUNT = 50
argument :ids,
- [GraphQL::ID_TYPE],
+ [::Types::GlobalIDType[::Todo]],
required: true,
description: 'The global ids of the todos to restore (a maximum of 50 is supported at once)'
@@ -37,24 +37,18 @@ module Mutations
private
def gids_of(ids)
- ids.map { |id| ::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s }
+ ids.map { |id| Gitlab::GlobalId.as_global_id(id, model_name: Todo.name).to_s }
end
def model_ids_of(ids)
ids.map do |gid|
- parsed_gid = ::URI::GID.parse(gid)
- parsed_gid.model_id.to_i if accessible_todo?(parsed_gid)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ gid = ::Types::GlobalIDType[::Todo].coerce_isolated_input(gid)
+ gid.model_id.to_i
end.compact
end
- def accessible_todo?(gid)
- gid.app == GlobalID.app && todo?(gid)
- end
-
- def todo?(gid)
- GlobalID.parse(gid)&.model_class&.ancestors&.include?(Todo)
- end
-
def raise_too_many_todos_requested_error
raise Gitlab::Graphql::Errors::ArgumentError, 'Too many todos requested.'
end
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index ad0f4d03f9a..d55850b5673 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -55,6 +55,9 @@
- if merge_request.assignees.any?
%li.d-flex
= render 'shared/issuable/assignees', project: merge_request.project, issuable: merge_request
+ - if Feature.enabled?(:merge_request_reviewers, @project) && merge_request.reviewers.any?
+ %li.gl-display-flex.issuable-reviewers
+ = render 'shared/issuable/reviewers', project: merge_request.project, issuable: merge_request
= render 'projects/merge_requests/approvals_count', merge_request: merge_request
= render 'shared/issuable_meta_data', issuable: merge_request
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index bee4aff605f..e7febd4638b 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -2,15 +2,14 @@
= hidden_field_tag :group_id, params[:group_id]
- if params[:project_id].present?
= hidden_field_tag :project_id, params[:project_id]
-.dropdown.form-group.mb-lg-0.mx-lg-1
+.dropdown.form-group.mb-lg-0.mx-lg-1{ data: { testid: "group-filter" } }
%label.d-block{ for: "dashboard_search_group" }
= _("Group")
- %button.dropdown-menu-toggle.js-search-group-dropdown.mt-0{ type: "button", id: "dashboard_search_group", data: { toggle: "dropdown", group_id: params[:group_id] } }
- %span.dropdown-toggle-text
- - if @group.present?
- = @group.name
- - else
- = _("Any")
+ %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-group-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_group", data: { toggle: "dropdown", group_id: params[:group_id] } }
+ %span.dropdown-toggle-text.gl-flex-grow-1.str-truncated-100
+ = @group&.name || _("Any")
+ - if @group.present?
+ = link_to sprite_icon("clear"), url_for(safe_params.except(:project_id, :group_id)), class: 'search-clear js-search-clear has-tooltip', title: _('Clear')
= icon("chevron-down")
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-right
= dropdown_title(_("Filter results by group"))
@@ -21,12 +20,11 @@
.dropdown.project-filter.form-group.mb-lg-0.mx-lg-1
%label.d-block{ for: "dashboard_search_project" }
= _("Project")
- %button.dropdown-menu-toggle.js-search-project-dropdown.mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown"} }
- %span.dropdown-toggle-text
- - if @project.present?
- = @project.full_name
- - else
- = _("Any")
+ %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-project-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown", target: '.project-filter' } }
+ %span.dropdown-toggle-text.gl-flex-grow-1.str-truncated-100
+ = @project&.full_name || _("Any")
+ - if @project.present?
+ = link_to sprite_icon("clear"), url_for(safe_params.except(:project_id)), class: 'search-clear js-search-clear has-tooltip', title: _('Clear')
= icon("chevron-down")
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-right
= dropdown_title(_("Filter results by project"))
diff --git a/app/views/search/_form.html.haml b/app/views/search/_form.html.haml
index 30ca9d3f5ab..c8fa016662f 100644
--- a/app/views/search/_form.html.haml
+++ b/app/views/search/_form.html.haml
@@ -10,7 +10,7 @@
.position-relative
= search_field_tag :search, params[:search], placeholder: _("Search for projects, issues, etc."), class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false
= sprite_icon('search', css_class: 'search-icon')
- %button.search-clear.js-search-clear{ class: ("hidden" if !params[:search].present?), type: "button", tabindex: "-1" }
+ %button.search-clear.js-search-clear{ class: [("hidden" if params[:search].blank?), "has-tooltip"], type: "button", tabindex: "-1", title: _('Clear') }
= sprite_icon('clear')
%span.sr-only
= _("Clear search")
diff --git a/app/views/shared/issuable/_reviewers.html.haml b/app/views/shared/issuable/_reviewers.html.haml
new file mode 100644
index 00000000000..8e66135a20b
--- /dev/null
+++ b/app/views/shared/issuable/_reviewers.html.haml
@@ -0,0 +1,11 @@
+- max_render = 4
+- reviewers_rendering_overflow = issuable.reviewers.size > max_render
+- render_count = reviewers_rendering_overflow ? max_render - 1 : max_render
+- more_reviewers_count = issuable.reviewers.size - render_count
+
+- issuable.reviewers.take(render_count).each do |reviewer| # rubocop: disable CodeReuse/ActiveRecord
+ = link_to_member(@project, reviewer, name: false, title: _("Review requested from %{name}") % { name: reviewer.name})
+
+- if more_reviewers_count > 0
+ %span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old' }, title: _("+%{more_reviewers_count} more reviewers") % { more_reviewers_count: more_reviewers_count} }
+ = _("+%{more_reviewers_count}") % { more_reviewers_count: more_reviewers_count}
diff --git a/changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml b/changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml
new file mode 100644
index 00000000000..b113ed96e18
--- /dev/null
+++ b/changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml
@@ -0,0 +1,5 @@
+---
+title: Add buttons in the Search page to clear Group and Project filters
+merge_request: 42897
+author:
+type: added
diff --git a/changelogs/unreleased/bw_update_global_id_checks.yml b/changelogs/unreleased/bw_update_global_id_checks.yml
new file mode 100644
index 00000000000..2c3d9e81755
--- /dev/null
+++ b/changelogs/unreleased/bw_update_global_id_checks.yml
@@ -0,0 +1,5 @@
+---
+title: Updated GraphQL mutation input ids to be more type specific
+merge_request: 44073
+author:
+type: changed
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 9bd305f769a..31e67f617ff 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -32,7 +32,7 @@ input AddAwardEmojiInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -77,7 +77,7 @@ input AddProjectToSecurityDashboardInput {
"""
ID of the project to be added to Instance Security Dashboard
"""
- id: ID!
+ id: ProjectID!
}
"""
@@ -792,7 +792,7 @@ input AwardEmojiAddInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -832,7 +832,7 @@ input AwardEmojiRemoveInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -872,7 +872,7 @@ input AwardEmojiToggleInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -910,6 +910,11 @@ type AwardEmojiTogglePayload {
toggledOn: Boolean!
}
+"""
+Identifier of Awardable
+"""
+scalar AwardableID
+
type BaseService implements Service {
"""
Indicates if the service is active
@@ -2459,6 +2464,11 @@ Identifier of Clusters::AgentToken
"""
scalar ClustersAgentTokenID
+"""
+Identifier of Clusters::Cluster
+"""
+scalar ClustersClusterID
+
type Commit {
"""
Author of the commit
@@ -3003,7 +3013,7 @@ input CreateAnnotationInput {
"""
The global id of the cluster to add an annotation to
"""
- clusterId: ID
+ clusterId: ClustersClusterID
"""
The path to a file defining the dashboard on which the annotation should be added
@@ -3023,7 +3033,7 @@ input CreateAnnotationInput {
"""
The global id of the environment to add an annotation to
"""
- environmentId: ID
+ environmentId: EnvironmentID
"""
Timestamp indicating starting moment to which the annotation relates
@@ -3158,7 +3168,7 @@ input CreateDiffNoteInput {
"""
The global id of the resource to add a note to
"""
- noteableId: ID!
+ noteableId: NoteableID!
"""
The position of this note on a diff
@@ -3288,7 +3298,7 @@ input CreateImageDiffNoteInput {
"""
The global id of the resource to add a note to
"""
- noteableId: ID!
+ noteableId: NoteableID!
"""
The position of this note on a diff
@@ -3403,7 +3413,7 @@ input CreateNoteInput {
"""
The global id of the resource to add a note to
"""
- noteableId: ID!
+ noteableId: NoteableID!
}
"""
@@ -5150,7 +5160,7 @@ input DestroyNoteInput {
"""
The global id of the note to destroy
"""
- id: ID!
+ id: NoteID!
}
"""
@@ -5624,7 +5634,7 @@ input DismissVulnerabilityInput {
"""
ID of the vulnerability to be dismissed
"""
- id: ID!
+ id: VulnerabilityID!
}
"""
@@ -5759,6 +5769,11 @@ type EnvironmentEdge {
}
"""
+Identifier of Environment
+"""
+scalar EnvironmentID
+
+"""
Represents an epic
"""
type Epic implements CurrentUserTodos & Noteable {
@@ -6886,17 +6901,17 @@ input EpicTreeNodeFieldsInputType {
"""
The id of the epic_issue or issue that the actual epic or issue is switched with
"""
- adjacentReferenceId: ID
+ adjacentReferenceId: EpicTreeSortingID
"""
The id of the epic_issue or epic that is being moved
"""
- id: ID!
+ id: EpicTreeSortingID!
"""
ID of the new parent epic
"""
- newParentId: ID
+ newParentId: EpicID
"""
The type of the switch, after or before allowed
@@ -6911,7 +6926,7 @@ input EpicTreeReorderInput {
"""
The id of the base epic of the tree
"""
- baseEpicId: ID!
+ baseEpicId: EpicID!
"""
A unique identifier for the client performing the mutation.
@@ -6940,6 +6955,11 @@ type EpicTreeReorderPayload {
}
"""
+Identifier of EpicTreeSorting
+"""
+scalar EpicTreeSortingID
+
+"""
Epic ID wildcard values
"""
enum EpicWildcardId {
@@ -12020,6 +12040,11 @@ type NamespaceEdge {
}
"""
+Identifier of Namespace
+"""
+scalar NamespaceID
+
+"""
Autogenerated input type of NamespaceIncreaseStorageTemporarily
"""
input NamespaceIncreaseStorageTemporarilyInput {
@@ -12031,7 +12056,7 @@ input NamespaceIncreaseStorageTemporarilyInput {
"""
The global id of the namespace to mutate
"""
- id: ID!
+ id: NamespaceID!
}
"""
@@ -12228,6 +12253,11 @@ type NoteEdge {
node: Note
}
+"""
+Identifier of Note
+"""
+scalar NoteID
+
type NotePermissions {
"""
Indicates the user can perform `admin_note` on this resource
@@ -12308,6 +12338,11 @@ interface Noteable {
}
"""
+Identifier of Noteable
+"""
+scalar NoteableID
+
+"""
Represents a package
"""
type Package {
@@ -14502,6 +14537,11 @@ type ProjectEdge {
}
"""
+Identifier of Project
+"""
+scalar ProjectID
+
+"""
Represents a Project Membership
"""
type ProjectMember implements MemberInterface {
@@ -15779,7 +15819,7 @@ input RemoveAwardEmojiInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -18267,6 +18307,11 @@ type TodoEdge {
}
"""
+Identifier of Todo
+"""
+scalar TodoID
+
+"""
Autogenerated input type of TodoMarkDone
"""
input TodoMarkDoneInput {
@@ -18328,7 +18373,7 @@ input TodoRestoreManyInput {
"""
The global ids of the todos to restore (a maximum of 50 is supported at once)
"""
- ids: [ID!]!
+ ids: [TodoID!]!
}
"""
@@ -18455,7 +18500,7 @@ input ToggleAwardEmojiInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -18772,7 +18817,7 @@ input UpdateBoardInput {
"""
The id of user to be assigned to the board.
"""
- assigneeId: ID
+ assigneeId: UserID
"""
A unique identifier for the client performing the mutation.
@@ -18792,7 +18837,7 @@ input UpdateBoardInput {
"""
The board global id.
"""
- id: ID!
+ id: BoardID!
"""
The IDs of labels to be added to the board.
@@ -18807,7 +18852,7 @@ input UpdateBoardInput {
"""
The id of milestone to be assigned to the board.
"""
- milestoneId: ID
+ milestoneId: MilestoneID
"""
Name of the board
@@ -20296,7 +20341,7 @@ input VulnerabilityDismissInput {
"""
ID of the vulnerability to be dismissed
"""
- id: ID!
+ id: VulnerabilityID!
}
"""
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index ddf0006f9e2..e3446f22e01 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -111,7 +111,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -227,7 +227,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "ProjectID",
"ofType": null
}
},
@@ -1993,7 +1993,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -2109,7 +2109,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -2225,7 +2225,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -2346,6 +2346,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "AwardableID",
+ "description": "Identifier of Awardable",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "BaseService",
"description": null,
@@ -6674,6 +6684,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "ClustersClusterID",
+ "description": "Identifier of Clusters::Cluster",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Commit",
"description": null,
@@ -8039,7 +8059,7 @@
"description": "The global id of the environment to add an annotation to",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EnvironmentID",
"ofType": null
},
"defaultValue": null
@@ -8049,7 +8069,7 @@
"description": "The global id of the cluster to add an annotation to",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "ClustersClusterID",
"ofType": null
},
"defaultValue": null
@@ -8448,7 +8468,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteableID",
"ofType": null
}
},
@@ -8796,7 +8816,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteableID",
"ofType": null
}
},
@@ -9084,7 +9104,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteableID",
"ofType": null
}
},
@@ -14068,7 +14088,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteID",
"ofType": null
}
},
@@ -15517,7 +15537,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "VulnerabilityID",
"ofType": null
}
},
@@ -16000,6 +16020,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "EnvironmentID",
+ "description": "Identifier of Environment",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Epic",
"description": "Represents an epic",
@@ -19077,7 +19107,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicTreeSortingID",
"ofType": null
}
},
@@ -19088,7 +19118,7 @@
"description": "The id of the epic_issue or issue that the actual epic or issue is switched with",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicTreeSortingID",
"ofType": null
},
"defaultValue": null
@@ -19108,7 +19138,7 @@
"description": "ID of the new parent epic",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicID",
"ofType": null
},
"defaultValue": null
@@ -19132,7 +19162,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicID",
"ofType": null
}
},
@@ -19221,6 +19251,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "EpicTreeSortingID",
+ "description": "Identifier of EpicTreeSorting",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "ENUM",
"name": "EpicWildcardId",
"description": "Epic ID wildcard values",
@@ -35420,6 +35460,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "NamespaceID",
+ "description": "Identifier of Namespace",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "INPUT_OBJECT",
"name": "NamespaceIncreaseStorageTemporarilyInput",
"description": "Autogenerated input type of NamespaceIncreaseStorageTemporarily",
@@ -35433,7 +35483,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NamespaceID",
"ofType": null
}
},
@@ -36041,6 +36091,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "NoteID",
+ "description": "Identifier of Note",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "NotePermissions",
"description": null,
@@ -36315,6 +36375,16 @@
]
},
{
+ "kind": "SCALAR",
+ "name": "NoteableID",
+ "description": "Identifier of Noteable",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Package",
"description": "Represents a package",
@@ -41986,6 +42056,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "ProjectID",
+ "description": "Identifier of Project",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "ProjectMember",
"description": "Represents a Project Membership",
@@ -45596,7 +45676,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -53289,6 +53369,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "TodoID",
+ "description": "Identifier of Todo",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "INPUT_OBJECT",
"name": "TodoMarkDoneInput",
"description": "Autogenerated input type of TodoMarkDone",
@@ -53449,7 +53539,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "TodoID",
"ofType": null
}
}
@@ -53858,7 +53948,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -54776,7 +54866,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "BoardID",
"ofType": null
}
},
@@ -54817,7 +54907,7 @@
"description": "The id of user to be assigned to the board.",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "UserID",
"ofType": null
},
"defaultValue": null
@@ -54827,7 +54917,7 @@
"description": "The id of milestone to be assigned to the board.",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "MilestoneID",
"ofType": null
},
"defaultValue": null
@@ -58883,7 +58973,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "VulnerabilityID",
"ofType": null
}
},
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 34cf25142e4..ab15faa4e1b 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1698,20 +1698,17 @@ while just `/issue/` would also match a branch called `severe-issues`.
#### Supported `only`/`except` regexp syntax
-CAUTION: **Warning:**
-This is a breaking change that was introduced with GitLab 11.9.4.
-
-In GitLab 11.9.4, GitLab begun internally converting regexp used
+In GitLab 11.9.4, GitLab began internally converting the regexp used
in `only` and `except` parameters to [RE2](https://github.com/google/re2/wiki/Syntax).
-This means that only subset of features provided by [Ruby Regexp](https://ruby-doc.org/core/Regexp.html)
-is supported. [RE2](https://github.com/google/re2/wiki/Syntax) limits the set of features
-provided due to computational complexity, which means some features became unavailable in GitLab 11.9.4.
-For example, negative lookaheads.
+[RE2](https://github.com/google/re2/wiki/Syntax) limits the set of available features
+due to computational complexity, and some features, like negative lookaheads, became unavailable.
+Only a subset of features provided by [Ruby Regexp](https://ruby-doc.org/core/Regexp.html)
+are now supported.
-For GitLab versions from 11.9.7 and up to GitLab 12.0, GitLab provides a feature flag that can be
-enabled by administrators that allows users to use unsafe regexp syntax. This brings compatibility
-with previously allowed syntax version and allows users to gracefully migrate to the new syntax.
+From GitLab 11.9.7 to GitLab 12.0, GitLab provided a feature flag to
+let you use the unsafe regexp syntax. This flag allowed
+compatibility with the previous syntax version so you could gracefully migrate to the new syntax.
```ruby
Feature.enable(:allow_unsafe_ruby_regexp)
@@ -1767,7 +1764,7 @@ added if the following is true:
- `(any listed refs are true) OR (any listed variables are true) OR (any listed changes are true) OR (a chosen Kubernetes status matches)`
-In the example below, the `test` job will **not** be created when **any** of the following are true:
+In the example below, the `test` job is **not** created when **any** of the following are true:
- The pipeline runs for the `master` branch.
- There are changes to the `README.md` file in the root directory of the repository.
@@ -1819,12 +1816,11 @@ deploy:
> `variables` policy introduced in GitLab 10.7.
-The `variables` keyword defines variables expressions. In other words,
-you can use predefined variables / project / group or
-environment-scoped variables to define an expression that GitLab
-evaluates to decide whether a job should be created or not.
+The `variables` keyword defines variable expressions.
+
+These expressions determine whether or not a job should be created.
-Examples of using variables expressions:
+Examples of using variable expressions:
```yaml
deploy:
@@ -1894,22 +1890,21 @@ docker build:
- more_scripts/*.{rb,py,sh}
```
-In the scenario above, when pushing commits to an existing branch in GitLab,
-it creates and triggers the `docker build` job, provided that one of the
-commits contains changes to any of the following:
+When you push commits to an existing branch,
+the `docker build` job is created, but only if changes were made to any of the following:
- The `Dockerfile` file.
-- Any of the files inside `docker/scripts/` directory.
-- Any of the files and subdirectories inside the `dockerfiles` directory.
-- Any of the files with `rb`, `py`, `sh` extensions inside the `more_scripts` directory.
+- Any of the files in the `docker/scripts/` directory.
+- Any of the files and subdirectories in the `dockerfiles` directory.
+- Any of the files with `rb`, `py`, `sh` extensions in the `more_scripts` directory.
CAUTION: **Warning:**
-If using `only:changes` with [only allow merge requests to be merged if the pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds),
-undesired behavior could result if you don't [also use `only:merge_requests`](#using-onlychanges-with-pipelines-for-merge-requests).
+If you use `only:changes` with [only allow merge requests to be merged if the pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds),
+undesired behavior can result if you don't [also use `only:merge_requests`](#using-onlychanges-with-pipelines-for-merge-requests).
You can also use glob patterns to match multiple files in either the root directory
-of the repository, or in _any_ directory within the repository, but they must be wrapped
-in double quotes or GitLab can't parse the `.gitlab-ci.yml`. For example:
+of the repository, or in _any_ directory within the repository. However, they must be wrapped
+in double quotes or GitLab can't parse them. For example:
```yaml
test:
@@ -1922,10 +1917,8 @@ test:
- "**/*.sql"
```
-The following example skips the `build` job if a change is detected in any file
-with a `.md` extension in the root directory of the repository. This means that if you change multiple files,
-but only one file is a `.md` file, the `build` job is still skipped and does
-not run for the other files.
+You can skip a job if a change is detected in any file with a
+`.md` extension in the root directory of the repository:
```yaml
build:
@@ -1935,13 +1928,13 @@ build:
- "*.md"
```
-CAUTION: **Warning:**
-There are some points to be aware of when
-[using this feature with new branches or tags *without* pipelines for merge requests](#using-onlychanges-without-pipelines-for-merge-requests).
+If you change multiple files, but only one file ends in `.md`,
+the `build` job is still skipped. The job does not run for any of the files.
-CAUTION: **Warning:**
-There are some points to be aware of when
-[using this feature with scheduled pipelines](#using-onlychanges-with-scheduled-pipelines).
+Read more about how to use this feature with:
+
+- [New branches or tags *without* pipelines for merge requests](#using-onlychanges-without-pipelines-for-merge-requests).
+- [Scheduled pipelines](#using-onlychanges-with-scheduled-pipelines).
##### Using `only:changes` with pipelines for merge requests
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 6d501c0db91..d54af0a471c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -997,6 +997,12 @@ msgstr[1] ""
msgid "+%{approvers} more approvers"
msgstr ""
+msgid "+%{more_reviewers_count}"
+msgstr ""
+
+msgid "+%{more_reviewers_count} more reviewers"
+msgstr ""
+
msgid "+%{tags} more"
msgstr ""
@@ -22196,6 +22202,9 @@ msgstr ""
msgid "Review App|View latest app"
msgstr ""
+msgid "Review requested from %{name}"
+msgstr ""
+
msgid "Review the process for configuring service providers in your identity provider — in this case, GitLab is the \"service provider\" or \"relying party\"."
msgstr ""
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index c254be4800b..709467eaf3c 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -81,6 +81,10 @@ module QA
ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN']
end
+ def ci_job_id
+ ENV['CI_JOB_ID']
+ end
+
def ci_project_name
ENV['CI_PROJECT_NAME']
end
diff --git a/qa/qa/support/json_formatter.rb b/qa/qa/support/json_formatter.rb
index f6e40436ec8..8abdee35c14 100644
--- a/qa/qa/support/json_formatter.rb
+++ b/qa/qa/support/json_formatter.rb
@@ -50,7 +50,8 @@ module QA
pending_message: example.execution_result.pending_message,
testcase: example.metadata[:testcase],
quarantine: example.metadata[:quarantine],
- screenshot: example.metadata[:screenshot]
+ screenshot: example.metadata[:screenshot],
+ ci_job_id: QA::Runtime::Env.ci_job_id
}
end
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
index 4531ef40901..36d28ae2822 100644
--- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
@@ -8,6 +8,10 @@ RSpec.describe 'Merge requests > User lists merge requests' do
let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:user3) { create(:user) }
+ let(:user4) { create(:user) }
+ let(:user5) { create(:user) }
before do
@fix = create(:merge_request,
@@ -15,6 +19,7 @@ RSpec.describe 'Merge requests > User lists merge requests' do
source_project: project,
source_branch: 'fix',
assignees: [user],
+ reviewers: [user, user2, user3, user4, user5],
milestone: create(:milestone, project: project, due_date: '2013-12-11'),
created_at: 1.minute.ago,
updated_at: 1.minute.ago)
@@ -23,6 +28,7 @@ RSpec.describe 'Merge requests > User lists merge requests' do
source_project: project,
source_branch: 'markdown',
assignees: [user],
+ reviewers: [user, user2, user3, user4],
milestone: create(:milestone, project: project, due_date: '2013-12-12'),
created_at: 2.minutes.ago,
updated_at: 2.minutes.ago)
@@ -34,6 +40,37 @@ RSpec.describe 'Merge requests > User lists merge requests' do
updated_at: 10.seconds.ago)
end
+ context 'when merge_request_reviewers is turned on' do
+ before do
+ stub_feature_flags(merge_request_reviewers: true)
+ visit_merge_requests(project, reviewer_id: user.id)
+ end
+
+ it 'has reviewers in MR list' do
+ expect(page).to have_css('.issuable-reviewers')
+ end
+
+ it 'shows reviewers avatar count badge if more_reviewers_count > 4' do
+ first_issuable_reviewers = first('.issuable-reviewers')
+
+ expect(first_issuable_reviewers).to have_content('2')
+ expect(first_issuable_reviewers).to have_css('.avatar-counter')
+ end
+
+ it 'does not show reviewers avatar count badge if more_reviewers_count <= 4' do
+ expect(page.all('.issuable-reviewers')[1]).not_to have_css('.avatar-counter')
+ end
+ end
+
+ context 'when merge_request_reviewers is turned false' do
+ it 'has no reviewers in MR list' do
+ stub_feature_flags(merge_request_reviewers: false)
+ visit_merge_requests(project, reviewer_id: user.id)
+
+ expect(page).not_to have_css('.issuable-reviewers')
+ end
+ end
+
it 'filters on no assignee' do
visit_merge_requests(project, assignee_id: IssuableFinder::Params::FILTER_NONE)
diff --git a/spec/features/search/user_uses_search_filters_spec.rb b/spec/features/search/user_uses_search_filters_spec.rb
index f39a1f8fe37..080cced21c3 100644
--- a/spec/features/search/user_uses_search_filters_spec.rb
+++ b/spec/features/search/user_uses_search_filters_spec.rb
@@ -12,12 +12,12 @@ RSpec.describe 'User uses search filters', :js do
project.add_reporter(user)
group.add_owner(user)
sign_in(user)
-
- visit(search_path)
end
context 'when filtering by group' do
it 'shows group projects' do
+ visit search_path
+
find('.js-search-group-dropdown').click
wait_for_requests
@@ -36,10 +36,27 @@ RSpec.describe 'User uses search filters', :js do
expect(page).to have_link(group_project.full_name)
end
end
+
+ context 'when the group filter is set' do
+ before do
+ visit search_path(search: "test", group_id: group.id, project_id: project.id)
+ end
+
+ describe 'clear filter button' do
+ it 'removes Group and Project filters' do
+ link = find('[data-testid="group-filter"] .js-search-clear')
+ params = CGI.parse(URI.parse(link[:href]).query)
+
+ expect(params).not_to include(:group_id, :project_id)
+ end
+ end
+ end
end
context 'when filtering by project' do
it 'shows a project' do
+ visit search_path
+
page.within('.project-filter') do
find('.js-search-project-dropdown').click
@@ -50,5 +67,22 @@ RSpec.describe 'User uses search filters', :js do
expect(find('.js-search-project-dropdown')).to have_content(project.full_name)
end
+
+ context 'when the project filter is set' do
+ before do
+ visit search_path(search: "test", project_id: project.id)
+ end
+
+ let(:query) { { project_id: project.id } }
+
+ describe 'clear filter button' do
+ it 'removes Project filters' do
+ link = find('.project-filter .js-search-clear')
+ params = CGI.parse(URI.parse(link[:href]).query)
+
+ expect(params).not_to include(:project_id)
+ end
+ end
+ end
end
end
diff --git a/spec/graphql/mutations/todos/mark_done_spec.rb b/spec/graphql/mutations/todos/mark_done_spec.rb
index 51ad3e1a5d7..b5f2ff5d044 100644
--- a/spec/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/graphql/mutations/todos/mark_done_spec.rb
@@ -52,7 +52,8 @@ RSpec.describe Mutations::Todos::MarkDone do
end
it 'ignores invalid GIDs' do
- expect { mutation.resolve(id: 'invalid_gid') }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ expect { mutation.resolve(id: author.to_global_id.to_s) }
+ .to raise_error(::GraphQL::CoercionError)
expect(todo1.reload.state).to eq('pending')
expect(todo2.reload.state).to eq('done')
diff --git a/spec/graphql/mutations/todos/restore_many_spec.rb b/spec/graphql/mutations/todos/restore_many_spec.rb
index b3b3e057745..59995e33f2d 100644
--- a/spec/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/graphql/mutations/todos/restore_many_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::Todos::RestoreMany do
+ include GraphqlHelpers
+
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
@@ -44,8 +46,9 @@ RSpec.describe Mutations::Todos::RestoreMany do
expect_states_were_not_changed
end
- it 'ignores invalid GIDs' do
- expect { mutation.resolve(ids: ['invalid_gid']) }.to raise_error(URI::BadURIError)
+ it 'raises an error with invalid or non-Todo GIDs' do
+ expect { mutation.resolve(ids: [author.to_global_id.to_s]) }
+ .to raise_error(GraphQL::CoercionError)
expect_states_were_not_changed
end
@@ -78,38 +81,12 @@ RSpec.describe Mutations::Todos::RestoreMany do
it 'fails if too many todos are requested for update' do
expect { restore_mutation([todo1] * 51) }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
end
-
- it 'does not update todos from another app' do
- todo4 = create(:todo)
- todo4_gid = ::URI::GID.parse("gid://otherapp/Todo/#{todo4.id}")
-
- result = mutation.resolve(ids: [todo4_gid.to_s])
-
- expect(result[:updated_ids]).to be_empty
-
- expect_states_were_not_changed
- end
-
- it 'does not update todos from another model' do
- todo4 = create(:todo)
- todo4_gid = ::URI::GID.parse("gid://#{GlobalID.app}/Project/#{todo4.id}")
-
- result = mutation.resolve(ids: [todo4_gid.to_s])
-
- expect(result[:updated_ids]).to be_empty
-
- expect_states_were_not_changed
- end
end
def restore_mutation(todos)
mutation.resolve(ids: todos.map { |todo| global_id_of(todo) } )
end
- def global_id_of(todo)
- todo.to_global_id.to_s
- end
-
def expect_states_were_not_changed
expect(todo1.reload.state).to eq('done')
expect(todo2.reload.state).to eq('pending')
diff --git a/spec/graphql/mutations/todos/restore_spec.rb b/spec/graphql/mutations/todos/restore_spec.rb
index 9043d7a44a8..22fb1bba7a8 100644
--- a/spec/graphql/mutations/todos/restore_spec.rb
+++ b/spec/graphql/mutations/todos/restore_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::Todos::Restore do
+ include GraphqlHelpers
+
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
@@ -49,8 +51,9 @@ RSpec.describe Mutations::Todos::Restore do
expect(other_user_todo.reload.state).to eq('done')
end
- it 'ignores invalid GIDs' do
- expect { mutation.resolve(id: 'invalid_gid') }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ it 'raises error for invalid GID' do
+ expect { mutation.resolve(id: author.to_global_id.to_s) }
+ .to raise_error(::GraphQL::CoercionError)
expect(todo1.reload.state).to eq('done')
expect(todo2.reload.state).to eq('pending')
@@ -61,8 +64,4 @@ RSpec.describe Mutations::Todos::Restore do
def restore_mutation(todo)
mutation.resolve(id: global_id_of(todo))
end
-
- def global_id_of(todo)
- todo.to_global_id.to_s
- end
end
diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
index 1d38bb39d59..3aaebb5095a 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
@@ -45,8 +45,9 @@ RSpec.describe 'Adding an AwardEmoji' do
it_behaves_like 'a mutation that does not create an AwardEmoji'
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ['Cannot award emoji to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/was provided invalid value for awardableId/) }
+ end
end
context 'when the given awardable is an Awardable but still cannot be awarded an emoji' do
diff --git a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
index c6e8800de1f..7cd39f93ae7 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
@@ -50,8 +50,9 @@ RSpec.describe 'Removing an AwardEmoji' do
it_behaves_like 'a mutation that does not destroy an AwardEmoji'
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ['Cannot award emoji to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/was provided invalid value for awardableId/) }
+ end
end
context 'when the given awardable is an Awardable' do
diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
index 2df59ce97ca..6910ad80a11 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -44,8 +44,9 @@ RSpec.describe 'Toggling an AwardEmoji' do
it_behaves_like 'a mutation that does not create or destroy an AwardEmoji'
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ['Cannot award emoji to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/was provided invalid value for awardableId/) }
+ end
end
context 'when the given awardable is an Awardable but still cannot be awarded an emoji' do
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
index 10ca2cf1cf8..81d13b29dde 100644
--- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
@@ -101,7 +101,9 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
graphql_mutation(:create_annotation, variables)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: ['invalid_id is not a valid GitLab ID.']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/is not a valid Global ID/) }
+ end
end
end
end
@@ -109,7 +111,7 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
context 'when annotation source is cluster' do
let(:mutation) do
variables = {
- cluster_id: GitlabSchema.id_from_object(cluster).to_s,
+ cluster_id: cluster.to_global_id.to_s,
starting_at: starting_at,
ending_at: ending_at,
dashboard_path: dashboard_path,
@@ -188,15 +190,17 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
graphql_mutation(:create_annotation, variables)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: ['invalid_id is not a valid GitLab ID.']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/is not a valid Global ID/) }
+ end
end
end
context 'when both environment_id and cluster_id are provided' do
let(:mutation) do
variables = {
- environment_id: GitlabSchema.id_from_object(environment).to_s,
- cluster_id: GitlabSchema.id_from_object(cluster).to_s,
+ environment_id: environment.to_global_id.to_s,
+ cluster_id: cluster.to_global_id.to_s,
starting_at: starting_at,
ending_at: ending_at,
dashboard_path: dashboard_path,
@@ -210,14 +214,14 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
end
context 'when a non-cluster or environment id is provided' do
+ let(:gid) { { environment_id: project.to_global_id.to_s } }
let(:mutation) do
variables = {
- environment_id: GitlabSchema.id_from_object(project).to_s,
starting_at: starting_at,
ending_at: ending_at,
dashboard_path: dashboard_path,
description: description
- }
+ }.merge!(gid)
graphql_mutation(:create_annotation, variables)
end
@@ -226,6 +230,18 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
project.add_developer(current_user)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: [described_class::INVALID_ANNOTATION_SOURCE_ERROR]
+ describe 'non-environment id' do
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/does not represent an instance of Environment/) }
+ end
+ end
+
+ describe 'non-cluster id' do
+ let(:gid) { { cluster_id: project.to_global_id.to_s } }
+
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/does not represent an instance of Clusters::Cluster/) }
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
index 8bf8b96aff5..2bc04713e08 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
@@ -76,8 +76,8 @@ RSpec.describe 'Marking todos done' do
end
context 'when using an invalid gid' do
- let(:input) { { id: 'invalid_gid' } }
- let(:invalid_gid_error) { 'invalid_gid is not a valid GitLab ID.' }
+ let(:input) { { id: GitlabSchema.id_from_object(author).to_s } }
+ let(:invalid_gid_error) { "\"#{input[:id]}\" does not represent an instance of #{todo1.class}" }
it 'contains the expected error' do
post_graphql_mutation(mutation, current_user: current_user)
diff --git a/spec/requests/api/graphql/mutations/todos/restore_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
index 8451dcdf587..6cae0492ac4 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
@@ -76,8 +76,8 @@ RSpec.describe 'Restoring Todos' do
end
context 'when using an invalid gid' do
- let(:input) { { id: 'invalid_gid' } }
- let(:invalid_gid_error) { 'invalid_gid is not a valid GitLab ID.' }
+ let(:input) { { id: GitlabSchema.id_from_object(author).to_s } }
+ let(:invalid_gid_error) { "\"#{input[:id]}\" does not represent an instance of #{todo1.class}" }
it 'contains the expected error' do
post_graphql_mutation(mutation, current_user: current_user)
diff --git a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
index 522211340ea..24c8a247c93 100644
--- a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
@@ -52,11 +52,15 @@ RSpec.shared_examples 'a Note mutation when the given resource id is not for a N
it_behaves_like 'a Note mutation that does not create a Note'
- it_behaves_like 'a mutation that returns top-level errors', errors: ['Cannot add notes to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/ does not represent an instance of Noteable/) }
+ end
end
RSpec.shared_examples 'a Note mutation when the given resource id is not for a Note' do
let(:note) { create(:issue) }
- it_behaves_like 'a mutation that returns top-level errors', errors: ['Resource is not a note']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/does not represent an instance of Note/) }
+ end
end