diff options
76 files changed, 505 insertions, 367 deletions
diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue index a0416100e49..97af597e2f6 100644 --- a/app/assets/javascripts/analytics/cycle_analytics/components/base.vue +++ b/app/assets/javascripts/analytics/cycle_analytics/components/base.vue @@ -164,7 +164,6 @@ export default { <div> <h3>{{ $options.i18n.pageTitle }}</h3> <value-stream-filters - :group-id="endpoints.groupId" :group-path="endpoints.groupPath" :has-project-filter="false" :start-date="createdAfter" diff --git a/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue b/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue index 82bb1f77cbb..4c7e18f9895 100644 --- a/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue +++ b/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_filters.vue @@ -31,10 +31,6 @@ export default { required: false, default: true, }, - groupId: { - type: Number, - required: true, - }, groupPath: { type: String, required: true, diff --git a/app/assets/javascripts/analytics/cycle_analytics/store/getters.js b/app/assets/javascripts/analytics/cycle_analytics/store/getters.js index 83068cabf0f..30e0ac24ce2 100644 --- a/app/assets/javascripts/analytics/cycle_analytics/store/getters.js +++ b/app/assets/javascripts/analytics/cycle_analytics/store/getters.js @@ -19,7 +19,7 @@ export const requestParams = (state) => { selectedValueStream: { id: valueStreamId }, selectedStage: { id: stageId = null }, } = state; - return { requestPath: fullPath, valueStreamId, stageId }; + return { namespacePath: fullPath, valueStreamId, stageId }; }; export const paginationParams = ({ pagination: { page, sort, direction } }) => ({ diff --git a/app/assets/javascripts/analytics/cycle_analytics/utils.js b/app/assets/javascripts/analytics/cycle_analytics/utils.js index 0326aa1e70e..ab8251d4ba3 100644 --- a/app/assets/javascripts/analytics/cycle_analytics/utils.js +++ b/app/assets/javascripts/analytics/cycle_analytics/utils.js @@ -91,7 +91,6 @@ export const buildCycleAnalyticsInitialData = ({ fullPath, requestPath, projectId, - groupId, groupPath, labelsPath, milestonesPath, @@ -107,8 +106,7 @@ export const buildCycleAnalyticsInitialData = ({ fullPath, labelsPath, milestonesPath, - groupId: parseInt(groupId, 10), - groupPath, + groupPath: `groups/${groupPath}`, }, createdAfter: new Date(createdAfter), createdBefore: new Date(createdBefore), diff --git a/app/assets/javascripts/analytics/shared/utils.js b/app/assets/javascripts/analytics/shared/utils.js index 701cdcf0a2d..a7533f1f21d 100644 --- a/app/assets/javascripts/analytics/shared/utils.js +++ b/app/assets/javascripts/analytics/shared/utils.js @@ -133,7 +133,7 @@ export const generateValueStreamsDashboardLink = (groupPath, projectPaths = []) if (groupPath.length) { const query = projectPaths.length ? `?query=${projectPaths.join(',')}` : ''; const dashboardsSlug = '/-/analytics/dashboards'; - const segments = [gon.relative_url_root || '', '/groups', groupPath, dashboardsSlug]; + const segments = [gon.relative_url_root || '', '/', groupPath, dashboardsSlug]; return joinPaths(...segments).concat(query); } return ''; diff --git a/app/assets/javascripts/api/analytics_api.js b/app/assets/javascripts/api/analytics_api.js index 66ed30130bb..35c9fa20e56 100644 --- a/app/assets/javascripts/api/analytics_api.js +++ b/app/assets/javascripts/api/analytics_api.js @@ -2,8 +2,8 @@ import axios from '~/lib/utils/axios_utils'; import { joinPaths } from '~/lib/utils/url_utility'; import { buildApiUrl } from './api_utils'; -const PROJECT_VSA_METRICS_BASE = '/:request_path/-/analytics/value_stream_analytics'; -const PROJECT_VSA_PATH_BASE = '/:request_path/-/analytics/value_stream_analytics/value_streams'; +const PROJECT_VSA_METRICS_BASE = '/:namespace_path/-/analytics/value_stream_analytics'; +const PROJECT_VSA_PATH_BASE = '/:namespace_path/-/analytics/value_stream_analytics/value_streams'; const PROJECT_VSA_STAGES_PATH = `${PROJECT_VSA_PATH_BASE}/:value_stream_id/stages`; const PROJECT_VSA_STAGE_DATA_PATH = `${PROJECT_VSA_STAGES_PATH}/:stage_id`; @@ -15,71 +15,77 @@ export const DEPLOYS_METRIC_TYPE = 'deploys'; export const METRIC_TYPE_SUMMARY = 'summary'; export const METRIC_TYPE_TIME_SUMMARY = 'time_summary'; -const buildProjectMetricsPath = (requestPath) => - buildApiUrl(PROJECT_VSA_METRICS_BASE).replace(':request_path', requestPath); +const buildProjectMetricsPath = (namespacePath) => + buildApiUrl(PROJECT_VSA_METRICS_BASE).replace(':namespace_path', namespacePath); -const buildProjectValueStreamPath = (requestPath, valueStreamId = null) => { +const buildProjectValueStreamPath = (namespacePath, valueStreamId = null) => { if (valueStreamId) { return buildApiUrl(PROJECT_VSA_STAGES_PATH) - .replace(':request_path', requestPath) + .replace(':namespace_path', namespacePath) .replace(':value_stream_id', valueStreamId); } - return buildApiUrl(PROJECT_VSA_PATH_BASE).replace(':request_path', requestPath); + return buildApiUrl(PROJECT_VSA_PATH_BASE).replace(':namespace_path', namespacePath); }; -const buildValueStreamStageDataPath = ({ requestPath, valueStreamId = null, stageId = null }) => +const buildValueStreamStageDataPath = ({ namespacePath, valueStreamId = null, stageId = null }) => buildApiUrl(PROJECT_VSA_STAGE_DATA_PATH) - .replace(':request_path', requestPath) + .replace(':namespace_path', namespacePath) .replace(':value_stream_id', valueStreamId) .replace(':stage_id', stageId); -export const getProjectValueStreams = (requestPath) => { - const url = buildProjectValueStreamPath(requestPath); +export const getProjectValueStreams = (namespacePath) => { + const url = buildProjectValueStreamPath(namespacePath); return axios.get(url); }; -export const getProjectValueStreamStages = (requestPath, valueStreamId) => { - const url = buildProjectValueStreamPath(requestPath, valueStreamId); +export const getProjectValueStreamStages = (namespacePath, valueStreamId) => { + const url = buildProjectValueStreamPath(namespacePath, valueStreamId); return axios.get(url); }; // NOTE: legacy VSA request use a different path -// the `requestPath` provides a full url for the request -export const getProjectValueStreamStageData = ({ requestPath, stageId, params }) => - axios.get(joinPaths(requestPath, 'events', stageId), { params }); +// the `namespacePath` provides a full url for the request +export const getProjectValueStreamStageData = ({ namespacePath, stageId, params }) => + axios.get(joinPaths(namespacePath, 'events', stageId), { params }); /** * Dedicated project VSA paths */ -export const getValueStreamStageMedian = ({ requestPath, valueStreamId, stageId }, params = {}) => { - const stageBase = buildValueStreamStageDataPath({ requestPath, valueStreamId, stageId }); +export const getValueStreamStageMedian = ( + { namespacePath, valueStreamId, stageId }, + params = {}, +) => { + const stageBase = buildValueStreamStageDataPath({ namespacePath, valueStreamId, stageId }); return axios.get(joinPaths(stageBase, 'median'), { params }); }; export const getValueStreamStageRecords = ( - { requestPath, valueStreamId, stageId }, + { namespacePath, valueStreamId, stageId }, params = {}, ) => { - const stageBase = buildValueStreamStageDataPath({ requestPath, valueStreamId, stageId }); + const stageBase = buildValueStreamStageDataPath({ namespacePath, valueStreamId, stageId }); return axios.get(joinPaths(stageBase, 'records'), { params }); }; -export const getValueStreamStageCounts = ({ requestPath, valueStreamId, stageId }, params = {}) => { - const stageBase = buildValueStreamStageDataPath({ requestPath, valueStreamId, stageId }); +export const getValueStreamStageCounts = ( + { namespacePath, valueStreamId, stageId }, + params = {}, +) => { + const stageBase = buildValueStreamStageDataPath({ namespacePath, valueStreamId, stageId }); return axios.get(joinPaths(stageBase, 'count'), { params }); }; export const getValueStreamMetrics = ({ endpoint = METRIC_TYPE_SUMMARY, - requestPath, + requestPath: namespacePath, params = {}, }) => { - const metricBase = buildProjectMetricsPath(requestPath); + const metricBase = buildProjectMetricsPath(namespacePath); return axios.get(joinPaths(metricBase, endpoint), { params }); }; -export const getValueStreamSummaryMetrics = (requestPath, params = {}) => { - const metricBase = buildProjectMetricsPath(requestPath); +export const getValueStreamSummaryMetrics = (namespacePath, params = {}) => { + const metricBase = buildProjectMetricsPath(namespacePath); return axios.get(joinPaths(metricBase, 'summary'), { params }); }; diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index d4ee84f0255..f8818d07c08 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -299,10 +299,7 @@ export default { return this.isWidgetPresent(WIDGET_TYPE_NOTES); }, fetchByIid() { - return ( - (this.glFeatures.useIidInWorkItemsPath && parseBoolean(getParameterByName('iid_path'))) || - false - ); + return parseBoolean(getParameterByName('iid_path')); }, queryVariables() { return this.fetchByIid diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue index 49574fe8846..620d86bb363 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue @@ -3,7 +3,6 @@ import { GlButton, GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { __, s__ } from '~/locale'; import { createAlert } from '~/alert'; -import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import RichTimestampTooltip from '~/vue_shared/components/rich_timestamp_tooltip.vue'; import WorkItemLinkChildMetadata from 'ee_else_ce/work_items/components/work_item_links/work_item_link_child_metadata.vue'; @@ -110,7 +109,7 @@ export default { return this.isItemOpen ? __('Created') : __('Closed'); }, childPath() { - return `/${this.projectPath}/-/work_items/${getIdFromGraphQLId(this.childItem.id)}`; + return `/${this.projectPath}/-/work_items/${this.childItem.iid}?iid_path=true`; }, hasChildren() { return this.getWidgetByType(this.childItem, WIDGET_TYPE_HIERARCHY)?.hasChildren; diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue index 696f198fb0c..86c764b4044 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue @@ -143,7 +143,7 @@ export default { return this.isLoading && this.children.length === 0 ? '...' : this.children.length; }, fetchByIid() { - return this.glFeatures.useIidInWorkItemsPath && parseBoolean(getParameterByName('iid_path')); + return parseBoolean(getParameterByName('iid_path')); }, childUrlParams() { const params = {}; diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue index aa12df424f1..97eaf2c0422 100644 --- a/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue +++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue @@ -78,7 +78,7 @@ export default { }, computed: { fetchByIid() { - return this.glFeatures.useIidInWorkItemsPath && parseBoolean(getParameterByName('iid_path')); + return parseBoolean(getParameterByName('iid_path')); }, childrenIds() { return this.children.map((c) => c.id); diff --git a/app/assets/javascripts/work_items/pages/create_work_item.vue b/app/assets/javascripts/work_items/pages/create_work_item.vue index 2245f984174..ed0163ced3c 100644 --- a/app/assets/javascripts/work_items/pages/create_work_item.vue +++ b/app/assets/javascripts/work_items/pages/create_work_item.vue @@ -74,7 +74,7 @@ export default { return sprintfWorkItem(I18N_WORK_ITEM_ERROR_CREATING, workItemType); }, fetchByIid() { - return this.glFeatures.useIidInWorkItemsPath; + return true; }, }, methods: { diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 5d03281a30a..3639b7f1eea 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -270,7 +270,7 @@ $system-note-svg-size: 1rem; } &.is-editing { - .note-header, + .note-actions, .note-text, .edited-text { display: none; diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb index 77043e174b4..9ee8e59053f 100644 --- a/app/controllers/import/fogbugz_controller.rb +++ b/app/controllers/import/fogbugz_controller.rb @@ -19,7 +19,7 @@ class Import::FogbugzController < Import::BaseController # If the URI is invalid various errors can occur return redirect_to new_import_fogbugz_path(namespace_id: params[:namespace_id]), alert: _('Could not connect to FogBugz, check your URL') end - session[:fogbugz_token] = res.get_token + session[:fogbugz_token] = res.get_token.to_s session[:fogbugz_uri] = params[:uri] redirect_to new_user_map_import_fogbugz_path(namespace_id: params[:namespace_id]) diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 37b76257128..e2682fcbc17 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -65,7 +65,6 @@ class Projects::IssuesController < Projects::ApplicationController push_force_frontend_feature_flag(:work_items_mvc, project&.work_items_mvc_feature_flag_enabled?) push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?) push_frontend_feature_flag(:epic_widget_edit_confirmation, project) - push_frontend_feature_flag(:use_iid_in_work_items_path, project&.group) push_frontend_feature_flag(:incident_event_tags, project) end @@ -444,11 +443,7 @@ class Projects::IssuesController < Projects::ApplicationController def redirect_if_work_item return unless use_work_items_path?(issue) - if Feature.enabled?(:use_iid_in_work_items_path, project.group) - redirect_to project_work_items_path(project, issue.iid, params: request.query_parameters.merge(iid_path: true)) - else - redirect_to project_work_items_path(project, issue.id, params: request.query_parameters) - end + redirect_to project_work_items_path(project, issue.iid, params: request.query_parameters.merge(iid_path: true)) end def require_incident_for_incident_routes diff --git a/app/controllers/projects/work_items_controller.rb b/app/controllers/projects/work_items_controller.rb index db9dca14aab..74563ec08b4 100644 --- a/app/controllers/projects/work_items_controller.rb +++ b/app/controllers/projects/work_items_controller.rb @@ -5,7 +5,6 @@ class Projects::WorkItemsController < Projects::ApplicationController push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?) push_force_frontend_feature_flag(:work_items_mvc, project&.work_items_mvc_feature_flag_enabled?) push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?) - push_frontend_feature_flag(:use_iid_in_work_items_path, project&.group) end feature_category :team_planning diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index edc74dd71fc..92a00618ef5 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -29,6 +29,8 @@ class RegistrationsController < Devise::RegistrationsController feature_category :user_management + helper_method :arkose_labs_enabled? + def new @resource = build_resource set_invite_params @@ -299,6 +301,10 @@ class RegistrationsController < Devise::RegistrationsController def send_custom_confirmation_instructions # overridden by EE module end + + def arkose_labs_enabled? + false + end end RegistrationsController.prepend_mod_with('RegistrationsController') diff --git a/app/helpers/registrations_helper.rb b/app/helpers/registrations_helper.rb index a9b7ad7a3e5..fcd560dbe8c 100644 --- a/app/helpers/registrations_helper.rb +++ b/app/helpers/registrations_helper.rb @@ -11,10 +11,6 @@ module RegistrationsHelper } end - def arkose_labs_challenge_enabled? - false - end - def signup_box_template 'devise/shared/signup_box' end diff --git a/app/helpers/routing/projects_helper.rb b/app/helpers/routing/projects_helper.rb index d632bccf43e..a0073f9c5ba 100644 --- a/app/helpers/routing/projects_helper.rb +++ b/app/helpers/routing/projects_helper.rb @@ -48,10 +48,6 @@ module Routing # see https://gitlab.com/gitlab-org/gitlab/-/work_items/393987?iid_path=true return unless entity.project.present? - unless Feature.enabled?(:use_iid_in_work_items_path, entity.project.group) - return project_work_items_url(entity.project, entity.id, *args) - end - options = args.first || {} options[:iid_path] = true diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index f4f3965bdc1..57cd819cb89 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -66,7 +66,7 @@ = render_if_exists 'devise/shared/phone_verification', form: f %div - - if arkose_labs_challenge_enabled? + - if arkose_labs_enabled? = render_if_exists 'devise/registrations/arkose_labs' - elsif show_recaptcha_sign_up? = recaptcha_tags nonce: content_security_policy_nonce diff --git a/config/feature_flags/development/use_iid_in_work_items_path.yml b/config/feature_flags/development/use_iid_in_work_items_path.yml deleted file mode 100644 index d2d328bbbc1..00000000000 --- a/config/feature_flags/development/use_iid_in_work_items_path.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: use_iid_in_work_items_path -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101451 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378349 -milestone: '15.5' -type: development -group: group::project management -default_enabled: false diff --git a/config/initializers/safe_session_store_patch.rb b/config/initializers/safe_session_store_patch.rb new file mode 100644 index 00000000000..7d3b9d0ae36 --- /dev/null +++ b/config/initializers/safe_session_store_patch.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +# The Rails and Rack session stores allow developers to store arbitrary +# Ruby objects in the Hash, which gets serialized to Redis. However, +# serializing objects may lead to multi-version incompatibilities +# (https://docs.gitlab.com/ee/development/multi_version_compatibility.html) +# because there is no guarantee that the Ruby object is present in an +# older version. +# +# To safeguard against this problem, this patch checks that objects +# stored in the session are in an allow list. Note that these checks are +# restricted to test and development environments at the moment. Only +# add to the allow list if you know that the object should be handled +# gracefully in a mixed deployment. +return unless Rails.env.test? || Rails.env.development? + +module Rack + module Session + module Abstract + class SessionHash + module BlockRubyObjectSerialization + ALLOWED_OBJECTS = [ + Symbol, String, Integer, Float, NilClass, TrueClass, FalseClass, ActiveSupport::SafeBuffer, + # Used in app/controllers/import/bitbucket_controller.rb + ActiveSupport::Duration, ActiveSupport::TimeWithZone, + # Used in ee/app/controllers/groups/omniauth_callbacks_controller.rb + OmniAuth::AuthHash, OmniAuth::AuthHash::InfoHash, OneLogin::RubySaml::Attributes, + OneLogin::RubySaml::Response + ].freeze + + def []=(key, value) + unless safe_object?(value) + # rubocop:disable Gitlab/DocUrl + raise "Session attempted to store type #{value.class} with key '#{key}': #{value.inspect}.\n" \ + "Serializing novel Ruby objects can cause uninitialized constants in mixed deployments.\n" \ + "See https://docs.gitlab.com/ee/development/multi_version_compatibility.html" + # rubocop:enable Gitlab/DocUrl + end + + super + end + + private + + def safe_object?(value) + return allowed_mock?(value) if Rails.env.test? && value.is_a?(RSpec::Mocks::InstanceVerifyingDouble) + + case value + when Array + value.all? { |entry| safe_object?(entry) } + when Hash + safe_hash?(value) + else + ALLOWED_OBJECTS.include?(value.class) + end + end + + def safe_hash?(value) + value.each do |key, val| + return false unless safe_object?(key) + return false unless safe_object?(val) + end + end + + def allowed_mock?(value) + doubled_module = value.to_s + + # We don't have access to the @doubled_module variable, but the output + # string will be in the form: "#[InstanceDouble(OneLogin::RubySaml::Response) (anonymous)]" + ALLOWED_OBJECTS.any? { |allowed| doubled_module.include?("InstanceDouble(#{allowed})") } + end + end + + prepend BlockRubyObjectSerialization + end + end + end +end + +ActionDispatch::Request::Session.prepend(Rack::Session::Abstract::SessionHash::BlockRubyObjectSerialization) diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md index 4654a4cf5e2..cd4dd111476 100644 --- a/doc/administration/gitaly/configure_gitaly.md +++ b/doc/administration/gitaly/configure_gitaly.md @@ -863,7 +863,8 @@ When these limits are reached, performance may be reduced and users may be disco ### Configure repository cgroups (new method) -> This method of configuring repository cgroups was introduced in GitLab 15.1. +> - This method of configuring repository cgroups was introduced in GitLab 15.1. +> - `cpu_quota_us`[introduced](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/5422) in GitLab 15.10. To configure repository cgroups in Gitaly using the new method, use the following settings for the new configuration method to `gitaly['cgroups']` in `/etc/gitlab/gitlab.rb`: @@ -878,6 +879,10 @@ to `gitaly['cgroups']` in `/etc/gitlab/gitlab.rb`: - `cgroups_cpu_shares` is the CPU limit that is imposed collectively on all Git processes that Gitaly spawns. 0 implies no limit. The maximum is 1024 shares, which represents 100% of CPU. +- `cgroups_cpu_quota_us` is the + [`cfs_quota_us`](https://docs.kernel.org/scheduler/sched-bwc.html#management) + to throttle the cgroups' processes if they exceed this quota value. We set + `cfs_period_us` to `100ms` so 1 core is `100000`. 0 implies no limit. - `cgroups_repositories_count` is the number of cgroups in the cgroups pool. Each time a new Git command is spawned, Gitaly assigns it to one of these cgroups based on the repository the command is for. A circular hashing algorithm assigns @@ -888,18 +893,30 @@ to `gitaly['cgroups']` in `/etc/gitlab/gitlab.rb`: - `cgroups_repositories_cpu_shares` is the CPU limit that is imposed on all Git processes contained in a repository cgroup. 0 implies no limit. The maximum is 1024 shares, which represents 100% of CPU. This value cannot exceed that of the top level`cgroups_cpu_shares`. +- `cgroups_repositories_cpu_quota_us` is the + [`cfs_quota_us`](https://docs.kernel.org/scheduler/sched-bwc.html#management) + that is imposed on all Git processes contained in a repository cgroup. A Git + process can't use more then the given quota. We set + `cfs_period_us` to `100ms` so 1 core is `100000`. 0 implies no limit. For example: ```ruby # in /etc/gitlab/gitlab.rb -gitaly['cgroups_mountpoint'] = "/sys/fs/cgroup" -gitaly['cgroups_hierarchy_root'] => "gitaly" -gitaly['cgroups_memory_bytes'] = 64424509440, # 60gb -gitaly['cgroups_cpu_shares'] = 1024 -gitaly['cgroups_repositories_count'] => 1000, -gitaly['cgroups_repositories_memory_bytes'] => 32212254720 # 20gb -gitaly['cgroups_repositories_cpu_shares'] => 512 +gitaly['configuration'] = { + cgroups: { + mountpoint: '/sys/fs/cgroup', + hierarchy_root: 'gitaly', + memory_bytes: 64424509440, # 60gb, + cpu_quota_us: 400000 # 4 cores + repositories: { + count: 1000, + memory_bytes: 32212254720 # 20gb, + cpu_shares: 512, + cpu_quota_us: 200000 # 2 cores + }, + }, +} ``` ### Configure repository cgroups (legacy method) diff --git a/doc/administration/gitaly/monitoring.md b/doc/administration/gitaly/monitoring.md index 0fd34d5c89f..5bd1e01755f 100644 --- a/doc/administration/gitaly/monitoring.md +++ b/doc/administration/gitaly/monitoring.md @@ -54,6 +54,9 @@ You can observe the status of [control groups (cgroups)](configure_gitaly.md#con - `gitaly_cgroups_cpu_usage`, a gauge that measures CPU usage per cgroup. - `gitaly_cgroup_procs_total`, a gauge that measures the total number of processes Gitaly has spawned under the control of cgroups. +- `gitaly_cgroup_cpu_cfs_periods_total`, a counter that for the value of [`nr_periods`](https://docs.kernel.org/scheduler/sched-bwc.html#statistics). +- `gitaly_cgroup_cpu_cfs_throttled_periods_total`, a counter for the value of [`nr_throttled`](https://docs.kernel.org/scheduler/sched-bwc.html#statistics). +- `gitaly_cgroup_cpu_cfs_throttled_seconds_total`, a counter for the value of [`throttled_time`](https://docs.kernel.org/scheduler/sched-bwc.html#statistics) in seconds. ## `pack-objects` cache diff --git a/doc/ci/jobs/ci_job_token.md b/doc/ci/jobs/ci_job_token.md index 772c71657cc..c82904b04ea 100644 --- a/doc/ci/jobs/ci_job_token.md +++ b/doc/ci/jobs/ci_job_token.md @@ -78,14 +78,14 @@ see [epic 3559](https://gitlab.com/groups/gitlab-org/-/epics/3559). > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346298/) in GitLab 15.9. [Deployed behind the `:inbound_ci_scoped_job_token` feature flag](../../user/feature_flags.md), enabled by default. -Control your project's job token scope by creating an **inbound** allowlist of projects which can -access your project through its `CI_JOB_TOKEN`. +Create an **inbound** allowlist of projects which can access your project through +their `CI_JOB_TOKEN`. -For example, you can add project `B` to the inbound allowlist for project `A`. Jobs -in the pipeline for "allowed project" `B` can now use the CI/CD job token to authenticate -API calls to access project `A`. +For example, project `A` can add project `B` to the inbound allowlist. CI/CD jobs +in project `B` (the "allowed project") can now use their CI/CD job token to +authenticate API calls to access project `A`. -By default the allowlist includes your current project. +By default the inbound allowlist of any project only includes itself. It is a security risk to disable this feature, so project maintainers or owners should keep this setting enabled at all times. Add projects to the allowlist only when cross-project diff --git a/doc/ci/pipelines/downstream_pipelines.md b/doc/ci/pipelines/downstream_pipelines.md index bdc81e64f88..8031ce751ec 100644 --- a/doc/ci/pipelines/downstream_pipelines.md +++ b/doc/ci/pipelines/downstream_pipelines.md @@ -671,7 +671,7 @@ the child pipeline must [use `workflow:rules` or `rules` to ensure the jobs run] If no jobs in the child pipeline can run due to missing or incorrect `rules` configuration: - The child pipeline fails to start. -- The parent pipeline's trigger job fails with: `downstream pipeline can not be creaed, Pipeline will not run for the selected trigger. The rules configuration prevented any jobs from being added to the pipeline.` +- The parent pipeline's trigger job fails with: `downstream pipeline can not be created, Pipeline will not run for the selected trigger. The rules configuration prevented any jobs from being added to the pipeline.` ### `Ref is ambiguous` diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md index c57a598a8c2..47abc088fcd 100644 --- a/doc/development/ee_features.md +++ b/doc/development/ee_features.md @@ -580,11 +580,11 @@ Resolving an EE template path that is relative to the CE view path doesn't work. For `render` and `render_if_exists`, they search for the EE partial first, and then CE partial. They would only render a particular partial, not all partials with the same name. We could take the advantage of this, so that -the same partial path (for example, `shared/issuable/form/default_templates`) could +the same partial path (for example, `projects/settings/archive`) could be referring to the CE partial in CE (that is, -`app/views/shared/issuable/form/_default_templates.html.haml`), while EE +`app/views/projects/settings/_archive.html.haml`), while EE partial in EE (that is, -`ee/app/views/shared/issuable/form/_default_templates.html.haml`). This way, +`ee/app/views/projects/settings/_archive.html.haml`). This way, we could show different things between CE and EE. However sometimes we would also want to reuse the CE partial in EE partial @@ -594,21 +594,19 @@ would be tedious to do so. In this case, we could as well just use `render_ce` which would ignore any EE partials. One example would be -`ee/app/views/shared/issuable/form/_default_templates.html.haml`: +`ee/app/views/projects/settings/_archive.html.haml`: ```haml -- if @project.feature_available?(:issuable_default_templates) - = render_ce 'shared/issuable/form/default_templates' -- elsif show_promotions? - = render 'shared/promotions/promote_issue_templates' +- return if @project.marked_for_deletion? += render_ce 'projects/settings/archive' ``` In the above example, we can't use -`render 'shared/issuable/form/default_templates'` because it would find the +`render 'projects/settings/archive'` because it would find the same EE partial, causing infinite recursion. Instead, we could use `render_ce` so it ignores any partials in `ee/` and then it would render the CE partial -(that is, `app/views/shared/issuable/form/_default_templates.html.haml`) -for the same path (that is, `shared/issuable/form/default_templates`). This way +(that is, `app/views/projects/settings/_archive.html.haml`) +for the same path (that is, `projects/settings/archive`). This way we could easily wrap around the CE partial. ### Code in `lib/gitlab/background_migration/` diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 48797d7a384..0fe7d051bc0 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -34727,9 +34727,6 @@ msgstr "" msgid "Promotions|Contact your Administrator to upgrade your license." msgstr "" -msgid "Promotions|Description templates allow you to define context-specific templates for issue and merge request description fields for your project." -msgstr "" - msgid "Promotions|Dismiss Service Desk promotion" msgstr "" @@ -34838,12 +34835,6 @@ msgstr "" msgid "Promotions|You can restrict access to protected branches by choosing a role (Maintainers, Developers) as well as certain users." msgstr "" -msgid "Promotions|description templates" -msgstr "" - -msgid "Promotions|to help your contributors communicate effectively!" -msgstr "" - msgid "Prompt users to upload SSH keys" msgstr "" diff --git a/qa/qa/page/project/monitor/alerts/index.rb b/qa/qa/page/project/monitor/alerts/index.rb index aa4d780b5a2..1738ce170f2 100644 --- a/qa/qa/page/project/monitor/alerts/index.rb +++ b/qa/qa/page/project/monitor/alerts/index.rb @@ -17,6 +17,14 @@ module QA def go_to_alert(title) click_link_with_text(title) end + + def has_no_alert_with_title?(title) + has_no_link?(title, wait: 5) + end + + def go_to_tab(name) + click_link_with_text(name) + end end end end diff --git a/qa/qa/page/project/monitor/incidents/index.rb b/qa/qa/page/project/monitor/incidents/index.rb index 1b30e484723..04cb23da389 100644 --- a/qa/qa/page/project/monitor/incidents/index.rb +++ b/qa/qa/page/project/monitor/incidents/index.rb @@ -15,8 +15,16 @@ module QA click_element :create_incident_button end - def has_incident?(wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME) - wait_until(max_duration: wait) { has_element?(:incident_link) } + def has_incident?(wait: Support::Repeater::DEFAULT_MAX_WAIT_TIME, title: nil) + wait_until(max_duration: wait) { has_element?(:incident_link, text: title) } + end + + def has_no_incident?(title: nil) + has_no_element?(:incident_link, text: title) + end + + def go_to_tab(tab) + click_link_with_text(tab) end end end diff --git a/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb new file mode 100644 index 00000000000..433d286686b --- /dev/null +++ b/qa/qa/specs/features/browser_ui/8_monitor/alert_management/recovery_alert_resolves_correct_alert_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Monitor', product_group: :respond do + describe 'Recovery alert' do + shared_examples 'triggers recovery alert' do + it 'only resolves the correct alert', :aggregate_failures do + Page::Project::Menu.perform(&:go_to_monitor_alerts) + Page::Project::Monitor::Alerts::Index.perform do |index| + # Open tab is displayed by default + expect(index).to have_alert_with_title(unresolve_title) + expect(index).to have_no_alert_with_title(resolve_title) + + index.go_to_tab('Resolved') + expect(index).to have_alert_with_title(resolve_title) + expect(index).to have_no_alert_with_title(unresolve_title) + end + end + end + + before do + Flow::Login.sign_in + project.visit! + Flow::AlertSettings.go_to_monitor_settings + end + + context( + 'when using HTTP endpoint integration', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393589' + ) do + include_context 'sends and resolves test alerts' + + it_behaves_like 'triggers recovery alert' + end + + context( + 'when using Prometheus integration', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393590' + ) do + include_context 'sends and resolves test alerts' + + let(:http) { false } + + it_behaves_like 'triggers recovery alert' + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb new file mode 100644 index 00000000000..fe3cd5a432b --- /dev/null +++ b/qa/qa/specs/features/browser_ui/8_monitor/incident_management/recovery_alert_closes_correct_incident.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Monitor', product_group: :respond do + describe 'Recovery alert' do + shared_examples 'triggers recovery alert' do + it 'only closes the correct incident', :aggregate_failures do + Page::Project::Menu.perform(&:go_to_monitor_incidents) + Page::Project::Monitor::Incidents::Index.perform do |index| + # Open tab is displayed by default + expect(index).to have_incident(title: unresolve_title) + expect(index).to have_no_incident(title: resolve_title) + + index.go_to_tab('Closed') + expect(index).to have_incident(title: resolve_title) + expect(index).to have_no_incident(title: unresolve_title) + end + end + end + + before do + Flow::Login.sign_in + project.visit! + Flow::AlertSettings.go_to_monitor_settings + Flow::AlertSettings.enable_create_incident + end + + context( + 'when using HTTP endpoint integration', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393842' + ) do + include_context 'sends and resolves test alerts' + + it_behaves_like 'triggers recovery alert' + end + + context( + 'when using Prometheus integration', + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/393843' + ) do + include_context 'sends and resolves test alerts' + + let(:http) { false } + + it_behaves_like 'triggers recovery alert' + end + end + end +end diff --git a/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb new file mode 100644 index 00000000000..a72140f41e0 --- /dev/null +++ b/qa/qa/specs/features/shared_contexts/sends_and_resolves_test_alerts.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +module QA + RSpec.shared_context 'sends and resolves test alerts' do + let(:project) do + Resource::Project.fabricate_via_api! do |project| + project.name = 'project-for-alerts' + project.description = 'Project for alerts' + end + end + + let(:resolve_title) { Faker::Lorem.sentence } + let(:unresolve_title) { Faker::Lorem.sentence } + let(:http) { true } + + let(:payload_to_be_resolved) do + payload(resolve_title, http) + end + + let(:unresolved_payload) do + payload(unresolve_title, http) + end + + before do + http ? Flow::AlertSettings.setup_http_endpoint_integration : Flow::AlertSettings.setup_prometheus_integration + + [payload_to_be_resolved, unresolved_payload].each do |payload| + Flow::AlertSettings.send_test_alert(payload: payload) + end + + mark_as_resolved(payload_to_be_resolved, http) + Flow::AlertSettings.send_test_alert(payload: payload_to_be_resolved) + end + + private + + def mark_as_resolved(payload, http) + if http + payload[:end_time] = Time.now + else + payload[:alerts][0][:status] = 'resolved' + payload[:alerts][0][:endsAt] = Time.now + end + end + + def payload(title, http) + if http + { title: title, description: title } + else + { + version: '4', + groupKey: nil, + status: 'firing', + receiver: '', + groupLabels: {}, + commonLabels: {}, + commonAnnotations: {}, + externalURL: '', + alerts: [ + { + startsAt: Time.now, + generatorURL: Faker::Internet.url, + endsAt: nil, + status: nil, + labels: { gitlab_environment_name: Faker::Lorem.word }, + annotations: { title: title } + } + ] + } + end + end + end +end diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb index 15daf9f5b39..d843949e6b2 100644 --- a/qa/qa/support/matchers/have_matcher.rb +++ b/qa/qa/support/matchers/have_matcher.rb @@ -26,6 +26,8 @@ module QA label variable system_note + alert_with_title + incident ].each do |predicate| RSpec::Matchers.define "have_#{predicate}" do |*args, **kwargs| match do |page_object| diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index d0680fb379e..f1fe1940414 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -183,18 +183,6 @@ RSpec.describe Projects::IssuesController, feature_category: :team_planning do let_it_be(:task) { create(:issue, :task, project: project) } shared_examples 'redirects to show work item page' do - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'redirects to work item page' do - make_request - - expect(response).to redirect_to(project_work_items_path(project, task.id, query)) - end - end - it 'redirects to work item page using iid' do make_request diff --git a/spec/frontend/admin/broadcast_messages/components/base_spec.js b/spec/frontend/admin/broadcast_messages/components/base_spec.js index d69bf4a22bf..13619f536c8 100644 --- a/spec/frontend/admin/broadcast_messages/components/base_spec.js +++ b/spec/frontend/admin/broadcast_messages/components/base_spec.js @@ -4,7 +4,7 @@ import AxiosMockAdapter from 'axios-mock-adapter'; import { TEST_HOST } from 'helpers/test_constants'; import waitForPromises from 'helpers/wait_for_promises'; import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status'; import { redirectTo } from '~/lib/utils/url_utility'; @@ -12,7 +12,7 @@ import BroadcastMessagesBase from '~/admin/broadcast_messages/components/base.vu import MessagesTable from '~/admin/broadcast_messages/components/messages_table.vue'; import { generateMockMessages, MOCK_MESSAGES } from '../mock_data'; -jest.mock('~/flash'); +jest.mock('~/alert'); jest.mock('~/lib/utils/url_utility'); describe('BroadcastMessagesBase', () => { diff --git a/spec/frontend/admin/broadcast_messages/components/message_form_spec.js b/spec/frontend/admin/broadcast_messages/components/message_form_spec.js index 36c0ac303ba..292575c984b 100644 --- a/spec/frontend/admin/broadcast_messages/components/message_form_spec.js +++ b/spec/frontend/admin/broadcast_messages/components/message_form_spec.js @@ -1,7 +1,7 @@ import { mount } from '@vue/test-utils'; import { GlBroadcastMessage, GlForm } from '@gitlab/ui'; import AxiosMockAdapter from 'axios-mock-adapter'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { HTTP_STATUS_BAD_REQUEST } from '~/lib/utils/http_status'; import MessageForm from '~/admin/broadcast_messages/components/message_form.vue'; @@ -15,7 +15,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { MOCK_TARGET_ACCESS_LEVELS } from '../mock_data'; -jest.mock('~/flash'); +jest.mock('~/alert'); describe('MessageForm', () => { let wrapper; diff --git a/spec/frontend/admin/deploy_keys/components/table_spec.js b/spec/frontend/admin/deploy_keys/components/table_spec.js index 4d4a2caedde..ef5796f634b 100644 --- a/spec/frontend/admin/deploy_keys/components/table_spec.js +++ b/spec/frontend/admin/deploy_keys/components/table_spec.js @@ -9,10 +9,10 @@ import { stubComponent } from 'helpers/stub_component'; import DeployKeysTable from '~/admin/deploy_keys/components/table.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import Api, { DEFAULT_PER_PAGE } from '~/api'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; jest.mock('~/api'); -jest.mock('~/flash'); +jest.mock('~/alert'); jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' })); describe('DeployKeysTable', () => { @@ -242,7 +242,7 @@ describe('DeployKeysTable', () => { itRendersTheEmptyState(); - it('displays flash', () => { + it('displays alert', () => { expect(createAlert).toHaveBeenCalledWith({ message: DeployKeysTable.i18n.apiErrorMessage, captureError: true, diff --git a/spec/frontend/admin/users/components/users_table_spec.js b/spec/frontend/admin/users/components/users_table_spec.js index a0aec347b6b..3d3cdadb382 100644 --- a/spec/frontend/admin/users/components/users_table_spec.js +++ b/spec/frontend/admin/users/components/users_table_spec.js @@ -10,12 +10,12 @@ import AdminUserActions from '~/admin/users/components/user_actions.vue'; import AdminUserAvatar from '~/admin/users/components/user_avatar.vue'; import AdminUsersTable from '~/admin/users/components/users_table.vue'; import getUsersGroupCountsQuery from '~/admin/users/graphql/queries/get_users_group_counts.query.graphql'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import AdminUserDate from '~/vue_shared/components/user_date.vue'; import { users, paths, createGroupCountResponse } from '../mock_data'; -jest.mock('~/flash'); +jest.mock('~/alert'); Vue.use(VueApollo); @@ -134,7 +134,7 @@ describe('AdminUsersTable component', () => { await waitForPromises(); }); - it('creates a flash message and captures the error', () => { + it('creates an alert message and captures the error', () => { expect(createAlert).toHaveBeenCalledWith({ message: 'Could not load user group counts. Please refresh the page to try again.', captureError: true, diff --git a/spec/frontend/analytics/cycle_analytics/base_spec.js b/spec/frontend/analytics/cycle_analytics/base_spec.js index f27c3746c76..978970d1526 100644 --- a/spec/frontend/analytics/cycle_analytics/base_spec.js +++ b/spec/frontend/analytics/cycle_analytics/base_spec.js @@ -31,13 +31,14 @@ Vue.use(Vuex); let wrapper; -const { id: groupId, path: groupPath } = currentGroup; +const { path } = currentGroup; +const groupPath = `groups/${path}`; const defaultState = { currentGroup, createdBefore, createdAfter, stageCounts, - endpoints: { fullPath, groupId, groupPath }, + endpoints: { fullPath, groupPath }, }; function createStore({ initialState = {}, initialGetters = {} }) { @@ -139,7 +140,6 @@ describe('Value stream analytics component', () => { it('passes the paths to the filter bar', () => { expect(findFilters().props()).toEqual({ - groupId, groupPath, endDate: createdBefore, hasDateRangeFilter: true, diff --git a/spec/frontend/analytics/cycle_analytics/utils_spec.js b/spec/frontend/analytics/cycle_analytics/utils_spec.js index a79abff1dff..25edd5af622 100644 --- a/spec/frontend/analytics/cycle_analytics/utils_spec.js +++ b/spec/frontend/analytics/cycle_analytics/utils_spec.js @@ -91,7 +91,6 @@ describe('Value stream analytics utils', () => { const projectId = '5'; const createdAfter = '2021-09-01'; const createdBefore = '2021-11-06'; - const groupId = '146'; const groupPath = 'fake-group'; const fullPath = 'fake-group/fake-project'; const labelsPath = '/fake-group/fake-project/-/labels.json'; @@ -106,7 +105,6 @@ describe('Value stream analytics utils', () => { requestPath, labelsPath, milestonesPath, - groupId, groupPath, }; @@ -130,8 +128,7 @@ describe('Value stream analytics utils', () => { expect(endpoints.requestPath).toBe(requestPath); expect(endpoints.labelsPath).toBe(labelsPath); expect(endpoints.milestonesPath).toBe(milestonesPath); - expect(endpoints.groupId).toBe(parseInt(groupId, 10)); - expect(endpoints.groupPath).toBe(groupPath); + expect(endpoints.groupPath).toBe(`groups/${groupPath}`); }); it('returns null when there is no stage', () => { diff --git a/spec/frontend/analytics/shared/utils_spec.js b/spec/frontend/analytics/shared/utils_spec.js index 0b4346de9dc..e020ff999fc 100644 --- a/spec/frontend/analytics/shared/utils_spec.js +++ b/spec/frontend/analytics/shared/utils_spec.js @@ -216,11 +216,11 @@ describe('prepareTimeMetricsData', () => { describe('generateValueStreamsDashboardLink', () => { it.each` - groupPath | projectPaths | result - ${''} | ${[]} | ${''} - ${'fake-group'} | ${[]} | ${'/groups/fake-group/-/analytics/dashboards'} - ${'fake-group'} | ${['fake-path/project_1']} | ${'/groups/fake-group/-/analytics/dashboards?query=fake-path/project_1'} - ${'fake-group'} | ${['fake-path/project_1', 'fake-path/project_2']} | ${'/groups/fake-group/-/analytics/dashboards?query=fake-path/project_1,fake-path/project_2'} + groupPath | projectPaths | result + ${''} | ${[]} | ${''} + ${'groups/fake-group'} | ${[]} | ${'/groups/fake-group/-/analytics/dashboards'} + ${'groups/fake-group'} | ${['fake-path/project_1']} | ${'/groups/fake-group/-/analytics/dashboards?query=fake-path/project_1'} + ${'groups/fake-group'} | ${['fake-path/project_1', 'fake-path/project_2']} | ${'/groups/fake-group/-/analytics/dashboards?query=fake-path/project_1,fake-path/project_2'} `( 'generates the dashboard link when groupPath=$groupPath and projectPaths=$projectPaths', ({ groupPath, projectPaths, result }) => { @@ -234,7 +234,7 @@ describe('generateValueStreamsDashboardLink', () => { }); it('with includes a relative path if one is set', () => { - expect(generateValueStreamsDashboardLink('fake-path', ['project_1'])).toBe( + expect(generateValueStreamsDashboardLink('groups/fake-path', ['project_1'])).toBe( '/foobar/groups/fake-path/-/analytics/dashboards?query=project_1', ); }); diff --git a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js index 6e6ef7e9a8a..87192006efc 100644 --- a/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js +++ b/spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js @@ -4,7 +4,7 @@ import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { resolvers } from '~/ci/ci_variable_list/graphql/settings'; import { TYPENAME_GROUP } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; @@ -41,7 +41,7 @@ import { mockAdminVariables, } from '../mocks'; -jest.mock('~/flash'); +jest.mock('~/alert'); Vue.use(VueApollo); diff --git a/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js b/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js index cf8009e388f..bec9e6947f3 100644 --- a/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js +++ b/spec/frontend/ci/pipeline_new/components/refs_dropdown_spec.js @@ -13,7 +13,7 @@ const projectRefsEndpoint = '/root/project/refs'; const refShortName = 'main'; const refFullName = 'refs/heads/main'; -jest.mock('~/flash'); +jest.mock('~/alert'); describe('Pipeline New Form', () => { let wrapper; diff --git a/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js index 7fc240e520b..39ec24f38d5 100644 --- a/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js +++ b/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js @@ -9,7 +9,7 @@ import { mountExtended, } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { s__ } from '~/locale'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { updateHistory } from '~/lib/utils/url_utility'; @@ -70,7 +70,7 @@ const mockRunnersCount = runnersCountData.data.runners.count; const mockRunnersHandler = jest.fn(); const mockRunnersCountHandler = jest.fn(); -jest.mock('~/flash'); +jest.mock('~/alert'); jest.mock('~/ci/runner/sentry_utils'); jest.mock('~/lib/utils/url_utility', () => ({ ...jest.requireActual('~/lib/utils/url_utility'), diff --git a/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js b/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js index 39ea5cade28..9f4ac68a4e9 100644 --- a/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js +++ b/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js @@ -9,7 +9,7 @@ import { mountExtended, } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { s__ } from '~/locale'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { updateHistory } from '~/lib/utils/url_utility'; @@ -74,7 +74,7 @@ const mockGroupRunnersCount = mockGroupRunnersEdges.length; const mockGroupRunnersHandler = jest.fn(); const mockGroupRunnersCountHandler = jest.fn(); -jest.mock('~/flash'); +jest.mock('~/alert'); jest.mock('~/ci/runner/sentry_utils'); jest.mock('~/lib/utils/url_utility', () => ({ ...jest.requireActual('~/lib/utils/url_utility'), diff --git a/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js b/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js index a9369a5e626..477eb1a8fdf 100644 --- a/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js +++ b/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js @@ -3,7 +3,7 @@ import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import RunnerHeader from '~/ci/runner/components/runner_header.vue'; @@ -15,7 +15,7 @@ import { I18N_STATUS_NEVER_CONTACTED, I18N_INSTANCE_TYPE } from '~/ci/runner/con import { runnerFormData } from '../mock_data'; -jest.mock('~/flash'); +jest.mock('~/alert'); jest.mock('~/ci/runner/sentry_utils'); const mockRunner = runnerFormData.data.runner; diff --git a/spec/frontend/environments/delete_environment_modal_spec.js b/spec/frontend/environments/delete_environment_modal_spec.js index cc18bf754eb..96f6ce52a9c 100644 --- a/spec/frontend/environments/delete_environment_modal_spec.js +++ b/spec/frontend/environments/delete_environment_modal_spec.js @@ -6,10 +6,10 @@ import { s__, sprintf } from '~/locale'; import DeleteEnvironmentModal from '~/environments/components/delete_environment_modal.vue'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { resolvedEnvironment } from './graphql/mock_data'; -jest.mock('~/flash'); +jest.mock('~/alert'); Vue.use(VueApollo); describe('~/environments/components/delete_environment_modal.vue', () => { @@ -67,7 +67,7 @@ describe('~/environments/components/delete_environment_modal.vue', () => { ); }); - it('should flash a message on error', async () => { + it('should alert a message on error', async () => { createComponent({ apolloProvider: mockApollo }); deleteResolver.mockRejectedValue(); diff --git a/spec/frontend/environments/edit_environment_spec.js b/spec/frontend/environments/edit_environment_spec.js index fb1a8b8c00a..956d68a14f3 100644 --- a/spec/frontend/environments/edit_environment_spec.js +++ b/spec/frontend/environments/edit_environment_spec.js @@ -3,13 +3,13 @@ import MockAdapter from 'axios-mock-adapter'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; import EditEnvironment from '~/environments/components/edit_environment.vue'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status'; import { visitUrl } from '~/lib/utils/url_utility'; jest.mock('~/lib/utils/url_utility'); -jest.mock('~/flash'); +jest.mock('~/alert'); const DEFAULT_OPTS = { provide: { diff --git a/spec/frontend/environments/new_environment_spec.js b/spec/frontend/environments/new_environment_spec.js index a8cc05b297b..257bf76baba 100644 --- a/spec/frontend/environments/new_environment_spec.js +++ b/spec/frontend/environments/new_environment_spec.js @@ -3,13 +3,13 @@ import MockAdapter from 'axios-mock-adapter'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; import NewEnvironment from '~/environments/components/new_environment.vue'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '~/lib/utils/http_status'; import { visitUrl } from '~/lib/utils/url_utility'; jest.mock('~/lib/utils/url_utility'); -jest.mock('~/flash'); +jest.mock('~/alert'); const DEFAULT_OPTS = { provide: { diff --git a/spec/frontend/operation_settings/components/metrics_settings_spec.js b/spec/frontend/operation_settings/components/metrics_settings_spec.js index 732dfdd42fb..ee450dfc851 100644 --- a/spec/frontend/operation_settings/components/metrics_settings_spec.js +++ b/spec/frontend/operation_settings/components/metrics_settings_spec.js @@ -2,7 +2,7 @@ import { GlButton, GlLink, GlFormGroup, GlFormInput, GlFormSelect } from '@gitla import { mount, shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; import { TEST_HOST } from 'helpers/test_constants'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { refreshCurrentPage } from '~/lib/utils/url_utility'; import { timezones } from '~/monitoring/format_date'; @@ -13,7 +13,7 @@ import MetricsSettings from '~/operation_settings/components/metrics_settings.vu import store from '~/operation_settings/store'; jest.mock('~/lib/utils/url_utility'); -jest.mock('~/flash'); +jest.mock('~/alert'); describe('operation settings external dashboard component', () => { let wrapper; @@ -198,7 +198,7 @@ describe('operation settings external dashboard component', () => { expect(refreshCurrentPage).toHaveBeenCalled(); }); - it('creates flash banner on error', async () => { + it('creates alert banner on error', async () => { mountComponent(false); const message = 'mockErrorMessage'; axios.patch.mockRejectedValue({ response: { data: { message } } }); diff --git a/spec/frontend/projects/commit/store/actions_spec.js b/spec/frontend/projects/commit/store/actions_spec.js index 1502985cfc7..d48f9fd6fc0 100644 --- a/spec/frontend/projects/commit/store/actions_spec.js +++ b/spec/frontend/projects/commit/store/actions_spec.js @@ -1,6 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { PROJECT_BRANCHES_ERROR } from '~/projects/commit/constants'; import * as actions from '~/projects/commit/store/actions'; @@ -8,7 +8,7 @@ import * as types from '~/projects/commit/store/mutation_types'; import getInitialState from '~/projects/commit/store/state'; import mockData from '../mock_data'; -jest.mock('~/flash'); +jest.mock('~/alert'); describe('Commit form modal store actions', () => { let axiosMock; @@ -63,7 +63,7 @@ describe('Commit form modal store actions', () => { ); }); - it('should show flash error and set error in state on fetchBranches failure', async () => { + it('should show alert error and set error in state on fetchBranches failure', async () => { jest.spyOn(axios, 'get').mockRejectedValue(); await testAction(actions.fetchBranches, {}, state, [], [{ type: 'requestBranches' }]); diff --git a/spec/frontend/projects/commits/store/actions_spec.js b/spec/frontend/projects/commits/store/actions_spec.js index bae9c48fc1e..f5184e59420 100644 --- a/spec/frontend/projects/commits/store/actions_spec.js +++ b/spec/frontend/projects/commits/store/actions_spec.js @@ -1,13 +1,13 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status'; import actions from '~/projects/commits/store/actions'; import * as types from '~/projects/commits/store/mutation_types'; import createState from '~/projects/commits/store/state'; -jest.mock('~/flash'); +jest.mock('~/alert'); describe('Project commits actions', () => { let state; @@ -34,8 +34,8 @@ describe('Project commits actions', () => { ])); }); - describe('shows a flash message when there is an error', () => { - it('creates a flash', () => { + describe('shows an alert message when there is an error', () => { + it('creates an alert', () => { const mockDispatchContext = { dispatch: () => {}, commit: () => {}, state }; actions.receiveAuthorsError(mockDispatchContext); diff --git a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js index 2304e936dc6..892e43afd94 100644 --- a/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js +++ b/spec/frontend/projects/compare/components/revision_dropdown_legacy_spec.js @@ -2,7 +2,7 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import AxiosMockAdapter from 'axios-mock-adapter'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status'; import RevisionDropdown from '~/projects/compare/components/revision_dropdown_legacy.vue'; @@ -14,7 +14,7 @@ const defaultProps = { paramsBranch: 'main', }; -jest.mock('~/flash'); +jest.mock('~/alert'); describe('RevisionDropdown component', () => { let wrapper; @@ -91,7 +91,7 @@ describe('RevisionDropdown component', () => { expect(findTagsDropdownItem()).toHaveLength(0); }); - it('shows flash message on error', async () => { + it('shows alert message on error', async () => { axiosMock.onGet('some/invalid/path').replyOnce(HTTP_STATUS_NOT_FOUND); await waitForPromises(); diff --git a/spec/frontend/projects/compare/components/revision_dropdown_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_spec.js index 50779063d6b..455cd84afd4 100644 --- a/spec/frontend/projects/compare/components/revision_dropdown_spec.js +++ b/spec/frontend/projects/compare/components/revision_dropdown_spec.js @@ -3,13 +3,13 @@ import { shallowMount } from '@vue/test-utils'; import AxiosMockAdapter from 'axios-mock-adapter'; import { nextTick } from 'vue'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status'; import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vue'; import { revisionDropdownDefaultProps as defaultProps } from './mock_data'; -jest.mock('~/flash'); +jest.mock('~/alert'); describe('RevisionDropdown component', () => { let wrapper; @@ -79,7 +79,7 @@ describe('RevisionDropdown component', () => { }); }); - it('shows flash message on error', async () => { + it('shows alert message on error', async () => { axiosMock.onGet('some/invalid/path').replyOnce(HTTP_STATUS_NOT_FOUND); createComponent(); @@ -105,7 +105,7 @@ describe('RevisionDropdown component', () => { }); describe('search', () => { - it('shows flash message on error', async () => { + it('shows alert message on error', async () => { axiosMock.onGet('some/invalid/path').replyOnce(HTTP_STATUS_NOT_FOUND); createComponent(); diff --git a/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js index 11f219c1f90..12b92db9427 100644 --- a/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js +++ b/spec/frontend/projects/settings/branch_rules/components/edit/branch_dropdown_spec.js @@ -8,10 +8,10 @@ import BranchDropdown, { import createMockApollo from 'helpers/mock_apollo_helper'; import branchesQuery from '~/projects/settings/branch_rules/queries/branches.query.graphql'; import waitForPromises from 'helpers/wait_for_promises'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; Vue.use(VueApollo); -jest.mock('~/flash'); +jest.mock('~/alert'); describe('Branch dropdown', () => { let wrapper; diff --git a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js index f82ad80135e..e53b6b76534 100644 --- a/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js +++ b/spec/frontend/projects/settings/components/shared_runners_toggle_spec.js @@ -9,7 +9,7 @@ import SharedRunnersToggleComponent from '~/projects/settings/components/shared_ const TEST_UPDATE_PATH = '/test/update_shared_runners'; -jest.mock('~/flash'); +jest.mock('~/alert'); describe('projects/settings/components/shared_runners', () => { let wrapper; diff --git a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js index 661f842066e..dd534bec25d 100644 --- a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js +++ b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js @@ -7,7 +7,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper'; import BranchRules from '~/projects/settings/repository/branch_rules/app.vue'; import BranchRule from '~/projects/settings/repository/branch_rules/components/branch_rule.vue'; import branchRulesQuery from 'ee_else_ce/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { branchRulesMockResponse, appProvideMock, @@ -22,7 +22,7 @@ import { expandSection } from '~/settings_panels'; import { scrollToElement } from '~/lib/utils/common_utils'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; -jest.mock('~/flash'); +jest.mock('~/alert'); jest.mock('~/settings_panels'); jest.mock('~/lib/utils/common_utils'); diff --git a/spec/frontend/work_items/components/work_item_detail_spec.js b/spec/frontend/work_items/components/work_item_detail_spec.js index 38e1903ad47..6984e385e42 100644 --- a/spec/frontend/work_items/components/work_item_detail_spec.js +++ b/spec/frontend/work_items/components/work_item_detail_spec.js @@ -101,7 +101,6 @@ describe('WorkItemDetail component', () => { error = undefined, workItemsMvcEnabled = false, workItemsMvc2Enabled = false, - fetchByIid = false, } = {}) => { const handlers = [ [workItemQuery, handler], @@ -126,7 +125,6 @@ describe('WorkItemDetail component', () => { glFeatures: { workItemsMvc: workItemsMvcEnabled, workItemsMvc2: workItemsMvc2Enabled, - useIidInWorkItemsPath: fetchByIid, }, hasIssueWeightsFeature: true, hasIterationsFeature: true, @@ -637,7 +635,7 @@ describe('WorkItemDetail component', () => { }); }); - it('calls the global ID work item query when `useIidInWorkItemsPath` feature flag is false', async () => { + it('calls the global ID work item query when there is no `iid_path` parameter in URL', async () => { createComponent(); await waitForPromises(); @@ -647,20 +645,10 @@ describe('WorkItemDetail component', () => { expect(successByIidHandler).not.toHaveBeenCalled(); }); - it('calls the global ID work item query when `useIidInWorkItemsPath` feature flag is true but there is no `iid_path` parameter in URL', async () => { - createComponent({ fetchByIid: true }); - await waitForPromises(); - - expect(successHandler).toHaveBeenCalledWith({ - id: workItemQueryResponse.data.workItem.id, - }); - expect(successByIidHandler).not.toHaveBeenCalled(); - }); - - it('calls the IID work item query when `useIidInWorkItemsPath` feature flag is true and `iid_path` route parameter is present', async () => { + it('calls the IID work item query when `iid_path` route parameter is present', async () => { setWindowLocation(`?iid_path=true`); - createComponent({ fetchByIid: true, iidPathQueryParam: 'true' }); + createComponent(); await waitForPromises(); expect(successHandler).not.toHaveBeenCalled(); @@ -670,10 +658,10 @@ describe('WorkItemDetail component', () => { }); }); - it('calls the IID work item query when `useIidInWorkItemsPath` feature flag is true and `iid_path` route parameter is present and is a modal', async () => { + it('calls the IID work item query when `iid_path` route parameter is present and is a modal', async () => { setWindowLocation(`?iid_path=true`); - createComponent({ fetchByIid: true, iidPathQueryParam: 'true', isModal: true }); + createComponent({ isModal: true }); await waitForPromises(); expect(successHandler).not.toHaveBeenCalled(); diff --git a/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js index 26446dc5451..254d94bab28 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_link_child_spec.js @@ -109,7 +109,9 @@ describe('WorkItemLinkChild', () => { }); it('renders item title', () => { - expect(titleEl.attributes('href')).toBe('/gitlab-org/gitlab-test/-/work_items/4'); + expect(titleEl.attributes('href')).toBe( + '/gitlab-org/gitlab-test/-/work_items/4?iid_path=true', + ); expect(titleEl.text()).toBe(workItemTask.title); }); diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js index 563f2c7f716..99e44b4d89c 100644 --- a/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js +++ b/spec/frontend/work_items/components/work_item_links/work_item_links_spec.js @@ -54,7 +54,6 @@ describe('WorkItemLinks', () => { mutationHandler = mutationChangeParentHandler, issueDetailsQueryHandler = jest.fn().mockResolvedValue(getIssueDetailsResponse()), hasIterationsFeature = false, - fetchByIid = false, } = {}) => { mockApollo = createMockApollo( [ @@ -77,9 +76,6 @@ describe('WorkItemLinks', () => { provide: { projectPath: 'project/path', hasIterationsFeature, - glFeatures: { - useIidInWorkItemsPath: fetchByIid, - }, }, propsData: { issuableId: 1 }, apolloProvider: mockApollo, @@ -350,7 +346,7 @@ describe('WorkItemLinks', () => { beforeEach(async () => { setWindowLocation('?iid_path=true'); - await createComponent({ fetchByIid: true }); + await createComponent(); firstChild = findFirstWorkItemLinkChild(); }); @@ -390,7 +386,7 @@ describe('WorkItemLinks', () => { it('starts prefetching work item by iid if URL contains work item id', async () => { setWindowLocation('?work_item_iid=5&iid_path=true'); - await createComponent({ fetchByIid: true }); + await createComponent(); expect(childWorkItemByIidHandler).toHaveBeenCalledWith({ iid: '5', @@ -401,7 +397,7 @@ describe('WorkItemLinks', () => { it('does not open the modal if work item iid URL parameter is not found in child items', async () => { setWindowLocation('?work_item_iid=555&iid_path=true'); - await createComponent({ fetchByIid: true }); + await createComponent(); expect(showModal).not.toHaveBeenCalled(); expect(wrapper.findComponent(WorkItemDetailModal).props('workItemIid')).toBe(null); @@ -409,7 +405,7 @@ describe('WorkItemLinks', () => { it('opens the modal if work item iid URL parameter is found in child items', async () => { setWindowLocation('?work_item_iid=2&iid_path=true'); - await createComponent({ fetchByIid: true }); + await createComponent(); expect(showModal).toHaveBeenCalled(); expect(wrapper.findComponent(WorkItemDetailModal).props('workItemIid')).toBe('2'); diff --git a/spec/frontend/work_items/components/work_item_notes_spec.js b/spec/frontend/work_items/components/work_item_notes_spec.js index 09d0022fa1e..a067923b9fc 100644 --- a/spec/frontend/work_items/components/work_item_notes_spec.js +++ b/spec/frontend/work_items/components/work_item_notes_spec.js @@ -113,11 +113,6 @@ describe('WorkItemNotes component', () => { fetchByIid, workItemType: 'task', }, - provide: { - glFeatures: { - useIidInWorkItemsPath: fetchByIid, - }, - }, stubs: { GlModal: stubComponent(GlModal, { methods: { show: showModal } }), }, diff --git a/spec/frontend/work_items/pages/create_work_item_spec.js b/spec/frontend/work_items/pages/create_work_item_spec.js index 387c8a355fa..0a168f1ade5 100644 --- a/spec/frontend/work_items/pages/create_work_item_spec.js +++ b/spec/frontend/work_items/pages/create_work_item_spec.js @@ -37,7 +37,6 @@ describe('Create work item component', () => { props = {}, queryHandler = querySuccessHandler, mutationHandler = createWorkItemSuccessHandler, - fetchByIid = false, } = {}) => { fakeApollo = createMockApollo( [ @@ -66,9 +65,6 @@ describe('Create work item component', () => { }, provide: { fullPath: 'full-path', - glFeatures: { - useIidInWorkItemsPath: fetchByIid, - }, }, }); }; @@ -109,9 +105,8 @@ describe('Create work item component', () => { expect(wrapper.vm.$router.push).toHaveBeenCalledWith({ name: 'workItem', - params: { - id: '1', - }, + params: { id: '1' }, + query: { iid_path: 'true' }, }); }); @@ -210,18 +205,4 @@ describe('Create work item component', () => { 'Something went wrong when creating work item. Please try again.', ); }); - - it('performs a correct redirect when `useIidInWorkItemsPath` feature flag is enabled', async () => { - createComponent({ fetchByIid: true }); - findTitleInput().vm.$emit('title-input', 'Test title'); - - wrapper.find('form').trigger('submit'); - await waitForPromises(); - - expect(wrapper.vm.$router.push).toHaveBeenCalledWith({ - name: 'workItem', - params: { id: '1' }, - query: { iid_path: 'true' }, - }); - }); }); diff --git a/spec/helpers/registrations_helper_spec.rb b/spec/helpers/registrations_helper_spec.rb index eec87bc8712..b2f9a794cb3 100644 --- a/spec/helpers/registrations_helper_spec.rb +++ b/spec/helpers/registrations_helper_spec.rb @@ -8,20 +8,4 @@ RSpec.describe RegistrationsHelper do expect(helper.signup_username_data_attributes.keys).to include(:min_length, :min_length_message, :max_length, :max_length_message, :qa_selector) end end - - describe '#arkose_labs_challenge_enabled?' do - before do - stub_application_setting( - arkose_labs_private_api_key: nil, - arkose_labs_public_api_key: nil, - arkose_labs_namespace: nil - ) - stub_env('ARKOSE_LABS_PRIVATE_KEY', nil) - stub_env('ARKOSE_LABS_PUBLIC_KEY', nil) - end - - it 'is false' do - expect(helper.arkose_labs_challenge_enabled?).to eq false - end - end end diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 26951b0c1e7..8d24e9576e0 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -135,18 +135,6 @@ RSpec.describe TodosHelper do context 'when given a task' do let(:todo) { task_todo } - context 'when the use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'responds with an appropriate path' do - path = helper.todo_target_path(todo) - - expect(path).to eq("/#{todo.project.full_path}/-/work_items/#{todo.target.id}") - end - end - it 'responds with an appropriate path using iid' do path = helper.todo_target_path(todo) diff --git a/spec/initializers/safe_session_store_patch_spec.rb b/spec/initializers/safe_session_store_patch_spec.rb new file mode 100644 index 00000000000..b48aae02e9a --- /dev/null +++ b/spec/initializers/safe_session_store_patch_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'safe_sesion_store_patch', feature_category: :integrations do + shared_examples 'safe session store' do + it 'allows storing a String' do + session[:good_data] = 'hello world' + + expect(session[:good_data]).to eq('hello world') + end + + it 'raises error when session attempts to store an unsafe object' do + expect { session[:test] = Struct.new(:test) } + .to raise_error(/Serializing novel Ruby objects can cause uninitialized constants in mixed deployments/) + end + + it 'allows instance double of OneLogin::RubySaml::Response' do + response_double = instance_double(OneLogin::RubySaml::Response) + + session[:response_double] = response_double + + expect(session[:response_double]).to eq(response_double) + end + + it 'raises an error for instance double of REXML::Document' do + response_double = instance_double(REXML::Document) + + expect { session[:response_double] = response_double } + .to raise_error(/Serializing novel Ruby objects can cause uninitialized constants in mixed deployments/) + end + end + + context 'with ActionController::TestSession' do + let(:session) { ActionController::TestSession.new } + + it_behaves_like 'safe session store' + end + + context 'with ActionDispatch::Request::Session' do + let(:dummy_store) do + Class.new do + def load_session(_env) + [1, {}] + end + + def session_exists?(_env) + true + end + + def delete_session(_env, _id, _options) + 123 + end + end.new + end + + let(:request) { ActionDispatch::Request.new({}) } + let(:session) { ActionDispatch::Request::Session.create(dummy_store, request, {}) } + + it_behaves_like 'safe session store' + end +end diff --git a/spec/lib/gitlab/seeders/ci/runner/runner_fleet_pipeline_seeder_spec.rb b/spec/lib/gitlab/seeders/ci/runner/runner_fleet_pipeline_seeder_spec.rb index 2862bcc9719..a15dbccc80c 100644 --- a/spec/lib/gitlab/seeders/ci/runner/runner_fleet_pipeline_seeder_spec.rb +++ b/spec/lib/gitlab/seeders/ci/runner/runner_fleet_pipeline_seeder_spec.rb @@ -28,7 +28,8 @@ RSpec.describe ::Gitlab::Seeders::Ci::Runner::RunnerFleetPipelineSeeder, feature context 'with job_count specified' do let(:job_count) { 20 } - it 'creates expected jobs', :aggregate_failures do + it 'creates expected jobs', :aggregate_failures, + quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/394721' do expect { seeder.seed }.to change { Ci::Build.count }.by(job_count) .and change { Ci::Pipeline.count }.by(4) diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index 2e9a444bd24..08a25666ae9 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -227,27 +227,5 @@ RSpec.describe Gitlab::UrlBuilder do expect(subject.build(object, only_path: true)).to eq("/#{project.full_path}") end end - - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - context 'when a task issue is passed' do - it 'returns a path using the work item\'s ID and no query params' do - task = create(:issue, :task) - - expect(subject.build(task, only_path: true)).to eq("/#{task.project.full_path}/-/work_items/#{task.id}") - end - end - - context 'when a work item is passed' do - it 'returns a path using the work item\'s ID and no query params' do - work_item = create(:work_item) - - expect(subject.build(work_item, only_path: true)).to eq("/#{work_item.project.full_path}/-/work_items/#{work_item.id}") - end - end - end end end diff --git a/spec/presenters/issue_presenter_spec.rb b/spec/presenters/issue_presenter_spec.rb index 22a86d04a5a..1e8fda08bdb 100644 --- a/spec/presenters/issue_presenter_spec.rb +++ b/spec/presenters/issue_presenter_spec.rb @@ -35,16 +35,6 @@ RSpec.describe IssuePresenter do context 'when issue type is task' do let(:presented_issue) { task } - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'returns a work item url for the task' do - expect(presenter.web_url).to eq(project_work_items_url(project, work_items_path: presented_issue.id)) - end - end - it 'returns a work item url using iid for the task' do expect(presenter.web_url).to eq( project_work_items_url(project, work_items_path: presented_issue.iid, iid_path: true) @@ -75,16 +65,6 @@ RSpec.describe IssuePresenter do context 'when issue type is task' do let(:presented_issue) { task } - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'returns a work item path for the task' do - expect(presenter.issue_path).to eq(project_work_items_path(project, work_items_path: presented_issue.id)) - end - end - it 'returns a work item path using iid for the task' do expect(presenter.issue_path).to eq( project_work_items_path(project, work_items_path: presented_issue.iid, iid_path: true) diff --git a/spec/requests/projects/issue_links_controller_spec.rb b/spec/requests/projects/issue_links_controller_spec.rb index 0535156b4b8..5678a81a4b0 100644 --- a/spec/requests/projects/issue_links_controller_spec.rb +++ b/spec/requests/projects/issue_links_controller_spec.rb @@ -28,22 +28,6 @@ RSpec.describe Projects::IssueLinksController, feature_category: :team_planning context 'when linked issue is a task' do let(:issue_b) { create :issue, :task, project: project } - context 'when the use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'returns a work item path for the linked task' do - get namespace_project_issue_links_path(issue_links_params) - - expect(json_response.count).to eq(1) - expect(json_response.first).to include( - 'path' => project_work_items_path(issue_b.project, issue_b.id), - 'type' => 'TASK' - ) - end - end - it 'returns a work item path for the linked task using the iid in the path' do get namespace_project_issue_links_path(issue_links_params) diff --git a/spec/serializers/issue_board_entity_spec.rb b/spec/serializers/issue_board_entity_spec.rb index 0c9c8f05e17..75aee7f04f0 100644 --- a/spec/serializers/issue_board_entity_spec.rb +++ b/spec/serializers/issue_board_entity_spec.rb @@ -57,16 +57,6 @@ RSpec.describe IssueBoardEntity do context 'when issue is of type task' do let(:resource) { create(:issue, :task, project: project) } - context 'when the use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'has a work item path' do - expect(subject[:real_path]).to eq(project_work_items_path(project, resource.id)) - end - end - it 'has a work item path with iid' do expect(subject[:real_path]).to eq(project_work_items_path(project, resource.iid, iid_path: true)) end diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb index 06d8523b2e7..795cc357a67 100644 --- a/spec/serializers/issue_entity_spec.rb +++ b/spec/serializers/issue_entity_spec.rb @@ -17,17 +17,7 @@ RSpec.describe IssueEntity do context 'when issue is of type task' do let(:resource) { create(:issue, :task, project: project) } - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - # This was already a path and not a url when the work items change was introduced - it 'has a work item path' do - expect(subject[:web_url]).to eq(project_work_items_path(project, resource.id)) - end - end - + # This was already a path and not a url when the work items change was introduced it 'has a work item path with iid' do expect(subject[:web_url]).to eq(project_work_items_path(project, resource.iid, iid_path: true)) end diff --git a/spec/serializers/linked_project_issue_entity_spec.rb b/spec/serializers/linked_project_issue_entity_spec.rb index d415d1cbcb2..b863ccde40e 100644 --- a/spec/serializers/linked_project_issue_entity_spec.rb +++ b/spec/serializers/linked_project_issue_entity_spec.rb @@ -47,16 +47,6 @@ RSpec.describe LinkedProjectIssueEntity do context 'when related issue is a task' do let_it_be(:issue_link) { create(:issue_link, target: create(:issue, :task)) } - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - end - - it 'returns a work items path' do - expect(serialized_entity).to include(path: project_work_items_path(related_issue.project, related_issue.id)) - end - end - it 'returns a work items path using iid' do expect(serialized_entity).to include( path: project_work_items_path(related_issue.project, related_issue.iid, iid_path: true) diff --git a/spec/views/devise/shared/_signup_box.html.haml_spec.rb b/spec/views/devise/shared/_signup_box.html.haml_spec.rb index ee9ccbf6ff5..94a5871cb97 100644 --- a/spec/views/devise/shared/_signup_box.html.haml_spec.rb +++ b/spec/views/devise/shared/_signup_box.html.haml_spec.rb @@ -20,6 +20,7 @@ RSpec.describe 'devise/shared/_signup_box' do before do stub_devise + allow(view).to receive(:arkose_labs_enabled?).and_return(false) allow(view).to receive(:show_omniauth_providers).and_return(false) allow(view).to receive(:url).and_return('_url_') allow(view).to receive(:terms_path).and_return(terms_path) diff --git a/spec/views/events/event/_common.html.haml_spec.rb b/spec/views/events/event/_common.html.haml_spec.rb index 2160245fb63..cff1ec43a14 100644 --- a/spec/views/events/event/_common.html.haml_spec.rb +++ b/spec/views/events/event/_common.html.haml_spec.rb @@ -18,19 +18,6 @@ RSpec.describe 'events/event/_common.html.haml' do create(:event, :created, project: project, target: work_item, target_type: 'WorkItem', author: user) end - context 'when use_iid_in_work_items_path feature flag is disabled' do - before do - stub_feature_flags(use_iid_in_work_items_path: false) - render partial: 'events/event/common', locals: { event: event.present } - end - - it 'renders the correct url' do - expect(rendered).to have_link( - work_item.reference_link_text, href: "/#{project.full_path}/-/work_items/#{work_item.id}" - ) - end - end - it 'renders the correct url with iid' do expect(rendered).to have_link( work_item.reference_link_text, href: "/#{project.full_path}/-/work_items/#{work_item.iid}?iid_path=true" diff --git a/workhorse/go.mod b/workhorse/go.mod index 35b11235089..34b326c86a8 100644 --- a/workhorse/go.mod +++ b/workhorse/go.mod @@ -7,7 +7,7 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/FZambia/sentinel v1.1.1 github.com/alecthomas/chroma/v2 v2.5.0 - github.com/aws/aws-sdk-go v1.44.211 + github.com/aws/aws-sdk-go v1.44.212 github.com/disintegration/imaging v1.6.2 github.com/getsentry/raven-go v0.2.0 github.com/golang-jwt/jwt/v4 v4.5.0 diff --git a/workhorse/go.sum b/workhorse/go.sum index 14c34e73471..fe8ddb0a339 100644 --- a/workhorse/go.sum +++ b/workhorse/go.sum @@ -569,8 +569,8 @@ github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4 github.com/aws/aws-sdk-go v1.44.156/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go v1.44.187/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go v1.44.200/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go v1.44.211 h1:YNr5DwdzG/8y9Tl0QrPTnC99aFUHgT5hhy6GpnnzHK4= -github.com/aws/aws-sdk-go v1.44.211/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.212 h1:IRstlErdeKeQ8qBsCwWt4MG2RihUOcUJVqYwbvqpE28= +github.com/aws/aws-sdk-go v1.44.212/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2 v1.17.4 h1:wyC6p9Yfq6V2y98wfDsj6OnNQa4w2BLGCLIxzNhwOGY= github.com/aws/aws-sdk-go-v2 v1.17.4/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= |