Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--app/assets/javascripts/boards/constants.js1
-rw-r--r--app/assets/javascripts/boards/stores/actions.js15
-rw-r--r--app/assets/javascripts/boards/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js6
-rw-r--r--app/assets/javascripts/boards/stores/state.js1
-rw-r--r--app/graphql/resolvers/concerns/time_frame_arguments.rb8
-rw-r--r--app/graphql/resolvers/milestones_resolver.rb10
-rw-r--r--app/helpers/issuables_helper.rb4
-rw-r--r--app/services/merge_requests/refresh_service.rb3
-rw-r--r--app/views/projects/branches/index.html.haml2
-rw-r--r--app/views/search/results/_issuable.html.haml6
-rw-r--r--app/workers/build_queue_worker.rb1
-rw-r--r--config/feature_flags/development/branches_pagination_without_count.yml2
-rw-r--r--config/feature_flags/development/load_balancing_for_build_queue_worker.yml (renamed from config/feature_flags/development/ingress_modsecurity.yml)10
-rw-r--r--config/initializers/1_settings.rb3
-rw-r--r--config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml3
-rw-r--r--config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml3
-rw-r--r--config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml3
-rw-r--r--config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml3
-rw-r--r--config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml3
-rw-r--r--config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml3
-rw-r--r--config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml3
-rw-r--r--danger/feature_flag/Dangerfile10
-rw-r--r--doc/administration/consul.md9
-rw-r--r--doc/administration/geo/replication/faq.md10
-rw-r--r--doc/development/testing_guide/best_practices.md5
-rw-r--r--doc/development/usage_ping/dictionary.md2
-rw-r--r--doc/development/usage_ping/index.md1
-rw-r--r--doc/user/clusters/agent/repository.md65
-rw-r--r--lib/gitlab/usage_data.rb25
-rw-r--r--locale/gitlab.pot18
-rw-r--r--spec/features/search/user_searches_for_merge_requests_spec.rb5
-rw-r--r--spec/frontend/boards/stores/actions_spec.js45
-rw-r--r--spec/frontend/boards/stores/mutations_spec.js47
-rw-r--r--spec/helpers/issuables_helper_spec.rb14
-rw-r--r--spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb18
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb132
-rw-r--r--spec/requests/api/graphql/group/milestones_spec.rb7
-rw-r--r--spec/support/helpers/access_matchers_helpers.rb16
-rw-r--r--spec/support/helpers/usage_data_helpers.rb1
-rw-r--r--spec/workers/build_queue_worker_spec.rb31
-rw-r--r--workhorse/internal/objectstore/multipart.go11
43 files changed, 297 insertions, 271 deletions
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 5edffce6d57..32b7211cb61 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.39.0
+1.40.0
diff --git a/app/assets/javascripts/boards/constants.js b/app/assets/javascripts/boards/constants.js
index 0ad16002482..80a8fc99895 100644
--- a/app/assets/javascripts/boards/constants.js
+++ b/app/assets/javascripts/boards/constants.js
@@ -36,6 +36,7 @@ export const ListTypeTitles = {
milestone: __('Milestone'),
iteration: __('Iteration'),
label: __('Label'),
+ backlog: __('Open'),
};
export const formType = {
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index b8896185408..9842e3cb73a 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -12,6 +12,7 @@ import {
updateListQueries,
issuableTypes,
FilterFields,
+ ListTypeTitles,
} from 'ee_else_ce/boards/constants';
import createBoardListMutation from 'ee_else_ce/boards/graphql/board_list_create.mutation.graphql';
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
@@ -169,8 +170,11 @@ export default {
});
},
- addList: ({ commit }, list) => {
+ addList: ({ commit, dispatch, getters }, list) => {
commit(types.RECEIVE_ADD_LIST_SUCCESS, updateListPosition(list));
+ dispatch('fetchItemsForList', {
+ listId: getters.getListByTitle(ListTypeTitles.backlog).id,
+ });
},
fetchLabels: ({ state, commit, getters }, searchTerm) => {
@@ -261,7 +265,7 @@ export default {
commit(types.TOGGLE_LIST_COLLAPSED, { listId, collapsed });
},
- removeList: ({ state: { issuableType, boardLists }, commit }, listId) => {
+ removeList: ({ state: { issuableType, boardLists }, commit, dispatch, getters }, listId) => {
const listsBackup = { ...boardLists };
commit(types.REMOVE_LIST, listId);
@@ -281,6 +285,10 @@ export default {
}) => {
if (errors.length > 0) {
commit(types.REMOVE_LIST_FAILURE, listsBackup);
+ } else {
+ dispatch('fetchItemsForList', {
+ listId: getters.getListByTitle(ListTypeTitles.backlog).id,
+ });
}
},
)
@@ -290,6 +298,9 @@ export default {
},
fetchItemsForList: ({ state, commit }, { listId, fetchNext = false }) => {
+ if (!fetchNext) {
+ commit(types.RESET_ITEMS_FOR_LIST, listId);
+ }
commit(types.REQUEST_ITEMS_FOR_LIST, { listId, fetchNext });
const { fullPath, fullBoardId, boardType, filterParams } = state;
diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js
index ccea2917c2c..38c54bc8c5d 100644
--- a/app/assets/javascripts/boards/stores/mutation_types.js
+++ b/app/assets/javascripts/boards/stores/mutation_types.js
@@ -15,6 +15,7 @@ export const UPDATE_LIST_FAILURE = 'UPDATE_LIST_FAILURE';
export const TOGGLE_LIST_COLLAPSED = 'TOGGLE_LIST_COLLAPSED';
export const REMOVE_LIST = 'REMOVE_LIST';
export const REMOVE_LIST_FAILURE = 'REMOVE_LIST_FAILURE';
+export const RESET_ITEMS_FOR_LIST = 'RESET_ITEMS_FOR_LIST';
export const REQUEST_ITEMS_FOR_LIST = 'REQUEST_ITEMS_FOR_LIST';
export const RECEIVE_ITEMS_FOR_LIST_FAILURE = 'RECEIVE_ITEMS_FOR_LIST_FAILURE';
export const RECEIVE_ITEMS_FOR_LIST_SUCCESS = 'RECEIVE_ITEMS_FOR_LIST_SUCCESS';
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index 269357b14b5..6cd0a62657e 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -117,6 +117,11 @@ export default {
state.boardLists = listsBackup;
},
+ [mutationTypes.RESET_ITEMS_FOR_LIST]: (state, listId) => {
+ Vue.set(state, 'backupItemsList', state.boardItemsByListId[listId]);
+ Vue.set(state.boardItemsByListId, listId, []);
+ },
+
[mutationTypes.REQUEST_ITEMS_FOR_LIST]: (state, { listId, fetchNext }) => {
Vue.set(state.listsFlags, listId, { [fetchNext ? 'isLoadingMore' : 'isLoading']: true });
},
@@ -138,6 +143,7 @@ export default {
'Boards|An error occurred while fetching the board issues. Please reload the page.',
);
Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false });
+ Vue.set(state.boardItemsByListId, listId, state.backupItemsList);
},
[mutationTypes.RESET_ISSUES]: (state) => {
diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js
index 19ba2a5df83..7be5ae8b583 100644
--- a/app/assets/javascripts/boards/stores/state.js
+++ b/app/assets/javascripts/boards/stores/state.js
@@ -11,6 +11,7 @@ export default () => ({
boardLists: {},
listsFlags: {},
boardItemsByListId: {},
+ backupItemsList: [],
isSettingAssignees: false,
pageInfoByListId: {},
boardItems: {},
diff --git a/app/graphql/resolvers/concerns/time_frame_arguments.rb b/app/graphql/resolvers/concerns/time_frame_arguments.rb
index 6cac46a71d2..0ec3c642f29 100644
--- a/app/graphql/resolvers/concerns/time_frame_arguments.rb
+++ b/app/graphql/resolvers/concerns/time_frame_arguments.rb
@@ -39,4 +39,12 @@ module TimeFrameArguments
raise Gitlab::Graphql::Errors::ArgumentError, error_message
end
end
+
+ def transform_timeframe_parameters(args)
+ if args[:timeframe]
+ args[:timeframe].transform_keys { |k| :"#{k}_date" }
+ else
+ args.slice(:start_date, :end_date)
+ end
+ end
end
diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb
index c94e3d9e1d8..1241b41501d 100644
--- a/app/graphql/resolvers/milestones_resolver.rb
+++ b/app/graphql/resolvers/milestones_resolver.rb
@@ -44,15 +44,7 @@ module Resolvers
title: args[:title],
search_title: args[:search_title],
containing_date: args[:containing_date]
- }.merge!(timeframe_parameters(args)).merge!(parent_id_parameters(args))
- end
-
- def timeframe_parameters(args)
- if args[:timeframe]
- args[:timeframe].transform_keys { |k| :"#{k}_date" }
- else
- args.slice(:start_date, :end_date)
- end
+ }.merge!(transform_timeframe_parameters(args)).merge!(parent_id_parameters(args))
end
def parent
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index c662dabe453..c40feb42eea 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -220,6 +220,10 @@ module IssuablesHelper
@show_full_reference ? issuable.to_reference(full: true) : issuable.to_reference(@group || @project)
end
+ def issuable_project_reference(issuable)
+ "#{issuable.project.full_name} #{issuable.to_reference}"
+ end
+
def issuable_initial_data(issuable)
data = {
endpoint: issuable_path(issuable),
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index d5e2595a9c6..3a4e3ba38fd 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -27,7 +27,6 @@ module MergeRequests
merge_requests_for_source_branch.each do |mr|
outdate_suggestions(mr)
- refresh_pipelines_on_merge_requests(mr)
abort_auto_merges(mr)
mark_pending_todos_done(mr)
end
@@ -44,6 +43,8 @@ module MergeRequests
notify_about_push(mr)
mark_mr_as_draft_from_commits(mr)
execute_mr_web_hooks(mr)
+ # Run at the end of the loop to avoid any potential contention on the MR object
+ refresh_pipelines_on_merge_requests(mr)
merge_request_activity_counter.track_mr_including_ci_config(user: mr.author, merge_request: mr)
end
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 7cfe7d9d914..b1d465d0e75 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -46,7 +46,7 @@
%ul.content-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch, merged: @merged_branch_names.include?(branch.name), commit_status: @branch_pipeline_statuses[branch.name], show_commit_status: @branch_pipeline_statuses.any?
- - if Feature.enabled?(:branches_pagination_without_count, @project, default_enabled: true)
+ - if Feature.enabled?(:branches_pagination_without_count, @project, default_enabled: :yaml)
= render('kaminari/gitlab/without_count', previous_path: @prev_path, next_path: @next_path)
- else
= paginate @branches, theme: 'gitlab'
diff --git a/app/views/search/results/_issuable.html.haml b/app/views/search/results/_issuable.html.haml
index cb8bab7d0de..da0adba88db 100644
--- a/app/views/search/results/_issuable.html.haml
+++ b/app/views/search/results/_issuable.html.haml
@@ -5,6 +5,10 @@
= link_to issuable_path(issuable), data: { track_event: 'click_text', track_label: "#{issuable.class.name.downcase}_title", track_property: 'search_result' }, class: 'gl-w-full' do
%span.term.str-truncated.gl-font-weight-bold.gl-ml-2= issuable.title
.gl-text-gray-500.gl-my-3
- = sprintf(s_(' %{project_name}#%{issuable_iid} · created %{issuable_created} by %{author} · updated %{issuable_updated}'), { project_name: issuable.project.full_name, issuable_iid: issuable.iid, issuable_created: time_ago_with_tooltip(issuable.created_at, placement: 'bottom'), issuable_updated: time_ago_with_tooltip(issuable.updated_at, placement: 'bottom'), author: link_to_member(@project, issuable.author, avatar: false) }).html_safe
+ = issuable_project_reference(issuable)
+ ·
+ = sprintf(s_('created %{issuable_created} by %{author}'), { issuable_created: time_ago_with_tooltip(issuable.created_at, placement: 'bottom'), author: link_to_member(@project, issuable.author, avatar: false) }).html_safe
+ ·
+ = sprintf(s_('updated %{time_ago}'), { time_ago: time_ago_with_tooltip(issuable.updated_at, placement: 'bottom') }).html_safe
.description.term.col-sm-10.gl-px-0
= highlight_and_truncate_issuable(issuable, @search_term, @search_highlight)
diff --git a/app/workers/build_queue_worker.rb b/app/workers/build_queue_worker.rb
index e9b5459f850..aa3c03f773e 100644
--- a/app/workers/build_queue_worker.rb
+++ b/app/workers/build_queue_worker.rb
@@ -10,6 +10,7 @@ class BuildQueueWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :continuous_integration
urgency :high
worker_resource_boundary :cpu
+ data_consistency :sticky, feature_flag: :load_balancing_for_build_queue_worker
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
diff --git a/config/feature_flags/development/branches_pagination_without_count.yml b/config/feature_flags/development/branches_pagination_without_count.yml
index e342f302b2c..ed29caff812 100644
--- a/config/feature_flags/development/branches_pagination_without_count.yml
+++ b/config/feature_flags/development/branches_pagination_without_count.yml
@@ -5,4 +5,4 @@ rollout_issue_url:
milestone: '13.9'
type: development
group: group::source code
-default_enabled: true
+default_enabled: false
diff --git a/config/feature_flags/development/ingress_modsecurity.yml b/config/feature_flags/development/load_balancing_for_build_queue_worker.yml
index 1dc7a1d6a52..1b80372ab82 100644
--- a/config/feature_flags/development/ingress_modsecurity.yml
+++ b/config/feature_flags/development/load_balancing_for_build_queue_worker.yml
@@ -1,8 +1,8 @@
---
-name: ingress_modsecurity
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20194
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258554
-milestone: '12.5'
+name: load_balancing_for_build_queue_worker
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63212
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/332586
+milestone: '14.0'
type: development
-group: group::container security
+group: group::memory
default_enabled: false
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index a9f5c569823..12461791b38 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -678,9 +678,6 @@ Gitlab.ee do
Settings.cron_jobs['sync_seat_link_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['sync_seat_link_worker']['cron'] ||= "#{rand(60)} 3 * * * UTC"
Settings.cron_jobs['sync_seat_link_worker']['job_class'] = 'SyncSeatLinkWorker'
- Settings.cron_jobs['web_application_firewall_metrics_worker'] ||= Settingslogic.new({})
- Settings.cron_jobs['web_application_firewall_metrics_worker']['cron'] ||= '0 1 * * 0'
- Settings.cron_jobs['web_application_firewall_metrics_worker']['job_class'] = 'IngressModsecurityCounterMetricsWorker'
Settings.cron_jobs['users_create_statistics_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['users_create_statistics_worker']['cron'] ||= '2 15 * * *'
Settings.cron_jobs['users_create_statistics_worker']['job_class'] = 'Users::CreateStatisticsWorker'
diff --git a/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml b/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml
index 2257a325aa6..a5607b54d05 100644
--- a/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml
+++ b/config/metrics/counts_all/20210216175442_ingress_modsecurity_packets_processed.yml
@@ -7,7 +7,8 @@ product_stage: protect
product_group: group::container security
product_category: web_firewall
value_type: number
-status: deprecated
+status: removed
+milestone_removed: 14.0
time_frame: all
data_source: database
distribution:
diff --git a/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml b/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml
index b716862c512..b8f5b8e8371 100644
--- a/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml
+++ b/config/metrics/counts_all/20210216175444_ingress_modsecurity_packets_anomalous.yml
@@ -7,7 +7,8 @@ product_stage: protect
product_group: group::container security
product_category: web_firewall
value_type: number
-status: deprecated
+status: removed
+milestone_removed: 14.0
time_frame: all
data_source: database
distribution:
diff --git a/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml b/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml
index 74d2c99c5aa..0ab1020eadf 100644
--- a/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml
+++ b/config/metrics/counts_all/20210216175450_ingress_modsecurity_logging.yml
@@ -6,7 +6,8 @@ product_stage: protect
product_group: group::container security
product_category: web_firewall
value_type: number
-status: deprecated
+status: removed
+milestone_removed: 14.0
time_frame: all
data_source: database
distribution:
diff --git a/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml b/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml
index 7fce44b02cd..ecff0942267 100644
--- a/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml
+++ b/config/metrics/counts_all/20210216175452_ingress_modsecurity_blocking.yml
@@ -6,7 +6,8 @@ product_stage: protect
product_group: group::container security
product_category: web_firewall
value_type: number
-status: deprecated
+status: removed
+milestone_removed: 14.0
time_frame: all
data_source: database
distribution:
diff --git a/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml b/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml
index 838837e223d..230a4b45f7e 100644
--- a/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml
+++ b/config/metrics/counts_all/20210216175454_ingress_modsecurity_disabled.yml
@@ -6,7 +6,8 @@ product_stage: protect
product_group: group::container security
product_category: web_firewall
value_type: number
-status: deprecated
+status: removed
+milestone_removed: 14.0
time_frame: all
data_source: database
distribution:
diff --git a/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml b/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml
index 1e6ee0d40cb..19539659357 100644
--- a/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml
+++ b/config/metrics/counts_all/20210216175456_ingress_modsecurity_not_installed.yml
@@ -6,7 +6,8 @@ product_stage: protect
product_group: group::container security
product_category: web_firewall
value_type: number
-status: deprecated
+status: removed
+milestone_removed: 14.0
time_frame: all
data_source: database
distribution:
diff --git a/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml b/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml
index f76bd0593b6..a2552d1f465 100644
--- a/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml
+++ b/config/metrics/settings/20210216175459_ingress_modsecurity_enabled.yml
@@ -6,7 +6,8 @@ product_stage: protect
product_group: group::container security
product_category: web_firewall
value_type: boolean
-status: deprecated
+status: removed
+milestone_removed: 14.0
time_frame: none
data_source: system
distribution:
diff --git a/danger/feature_flag/Dangerfile b/danger/feature_flag/Dangerfile
index 88ce6393b64..bf2194724fc 100644
--- a/danger/feature_flag/Dangerfile
+++ b/danger/feature_flag/Dangerfile
@@ -53,14 +53,22 @@ def message_for_feature_flag_with_group!(feature_flag:, mr_group_label:)
end
end
+def feature_flag_file_added?
+ feature_flag.feature_flag_files(change_type: :added).any?
+end
+
def feature_flag_file_added_or_removed?
- feature_flag.feature_flag_files(change_type: :added).any? || feature_flag.feature_flag_files(change_type: :deleted).any?
+ feature_flag_file_added? || feature_flag.feature_flag_files(change_type: :deleted).any?
end
feature_flag.feature_flag_files(change_type: :added).each do |feature_flag|
check_feature_flag_yaml(feature_flag)
end
+if helper.security_mr? && feature_flag_file_added?
+ fail "Feature flags are discouraged from security merge requests. Read the [security documentation](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/utilities/feature_flags.md) for details."
+end
+
if feature_flag_file_added_or_removed?
new_mr_title = helper.mr_title.dup
new_mr_title << ' [RUN ALL RSPEC]' unless helper.run_all_rspec_mr?
diff --git a/doc/administration/consul.md b/doc/administration/consul.md
index a748259aff0..c7fe076dcce 100644
--- a/doc/administration/consul.md
+++ b/doc/administration/consul.md
@@ -80,6 +80,15 @@ within each node. The command will return an empty array if the cluster is healt
curl "http://127.0.0.1:8500/v1/health/state/critical"
```
+If the Consul version has changed, you'll see a notice at the end of `gitlab-ctl reconfigure`
+informing you that Consul needs to be restarted for the new version to be used.
+
+Restart Consul one node at a time:
+
+```shell
+sudo gitlab-ctl restart consul
+```
+
Consul nodes communicate using the raft protocol. If the current leader goes
offline, there needs to be a leader election. A leader node must exist to facilitate
synchronization across the cluster. If too many nodes go offline at the same time,
diff --git a/doc/administration/geo/replication/faq.md b/doc/administration/geo/replication/faq.md
index a83a1c22db6..ef41b2ff172 100644
--- a/doc/administration/geo/replication/faq.md
+++ b/doc/administration/geo/replication/faq.md
@@ -17,13 +17,13 @@ On each **secondary** site, there is a read-only replicated copy of the GitLab d
A **secondary** site also has a tracking database where it stores which projects have been synced.
Geo compares the two databases to find projects that are not yet tracked.
-At the start, this tracking database is empty, so Geo will start trying to update from every project that it can see in the GitLab database.
+At the start, this tracking database is empty, so Geo tries to update from every project that it can see in the GitLab database.
For each project to sync:
-1. Geo will issue a `git fetch geo --mirror` to get the latest information from the **primary** site.
- If there are no changes, the sync will be fast and end quickly. Otherwise, it will pull the latest commits.
-1. The **secondary** site will update the tracking database to store the fact that it has synced projects A, B, C, etc.
+1. Geo issues a `git fetch geo --mirror` to get the latest information from the **primary** site.
+ If there are no changes, the sync is fast. Otherwise, it has to pull the latest commits.
+1. The **secondary** site updates the tracking database to store the fact that it has synced projects A, B, C, etc.
1. Repeat until all projects are synced.
When someone pushes a commit to the **primary** site, it generates an event in the GitLab database that the repository has changed.
@@ -70,4 +70,4 @@ Yes. See [Docker Registry for a **secondary** site](docker_registry.md).
## Can I login to a secondary site?
-Yes, but secondary sites receive all authentication data (like user accounts and logins) from the primary instance. This means you will be re-directed to the primary for authentication and routed back afterwards.
+Yes, but secondary sites receive all authentication data (like user accounts and logins) from the primary instance. This means you are re-directed to the primary for authentication and then routed back.
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 41ec1fdfa02..01e1b23c113 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -864,10 +864,10 @@ Most tests for Elasticsearch logic relate to:
- Searching for that data.
- Ensuring that the test gives the expected result.
-There are some exceptions, such as checking for structural changes rather than individual records in an index.
+There are some exceptions, such as checking for structural changes rather than individual records in an index.
The `:elastic_with_delete_by_query` trait was added to reduce run time for pipelines by creating and deleting indices
-at the start and end of each context only. The [Elasticsearch DeleteByQuery API](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html)
+at the start and end of each context only. The [Elasticsearch DeleteByQuery API](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html)
is used to delete data in all indices in between examples to ensure a clean index.
Note that Elasticsearch indexing uses [`Gitlab::Redis::SharedState`](../../../ee/development/redis.md#gitlabrediscachesharedstatequeues).
@@ -994,6 +994,7 @@ Only use simple values as input in the `where` block. Using
objects, FactoryBot-created objects, and similar items can lead to
[unexpected results](https://github.com/tomykaira/rspec-parameterized/issues/8).
<!-- vale gitlab.Spelling = YES -->
+
### Prometheus tests
Prometheus metrics may be preserved from one test run to another. To ensure that metrics are
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index 0133d36a28c..5e8fc1f8078 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -7134,7 +7134,7 @@ Whether or not ModSecurity is enabled within Ingress
Group: `group::container security`
-Status: `deprecated`
+Status: `removed`
Tiers: `free`, `premium`, `ultimate`
diff --git a/doc/development/usage_ping/index.md b/doc/development/usage_ping/index.md
index 802521b3df6..30059a3cfd5 100644
--- a/doc/development/usage_ping/index.md
+++ b/doc/development/usage_ping/index.md
@@ -1354,7 +1354,6 @@ The following is example content of the Usage Ping payload.
"reply_by_email_enabled": "incoming+%{key}@incoming.gitlab.com",
"signup_enabled": true,
"web_ide_clientside_preview_enabled": true,
- "ingress_modsecurity_enabled": true,
"projects_with_expiration_policy_disabled": 999,
"projects_with_expiration_policy_enabled": 999,
...
diff --git a/doc/user/clusters/agent/repository.md b/doc/user/clusters/agent/repository.md
index 5bfeedff92d..cd40cc6810e 100644
--- a/doc/user/clusters/agent/repository.md
+++ b/doc/user/clusters/agent/repository.md
@@ -8,6 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/259669) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.7.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3834) in GitLab 13.11, the Kubernetes Agent became available on GitLab.com.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/332227) in GitLab 14.0, the `resource_inclusions` and `resource_exclusions` attributes were removed.
WARNING:
This feature might not be available to you. Check the **version history** note above for details.
@@ -38,16 +39,7 @@ with Kubernetes resource definitions in YAML or JSON format. The Agent monitors
each project you declare, and when the project changes, GitLab deploys the changes
using the Agent.
-To use multiple YAML files, specify a `paths` attribute in the `gitops` section.
-
-By default, the Agent monitors all
-[Kubernetes object types](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields).
-You can exclude some types of resources from monitoring. This enables you to reduce
-the permissions needed by the GitOps feature, through `resource_exclusions`.
-
-To enable a specific named resource, first use `resource_inclusions` to enable desired resources.
-The following file excerpt includes specific `api_groups` and `kinds`. The `resource_exclusions`
-which follow excludes all other `api_groups` and `kinds`:
+To use multiple YAML files, specify a `paths` attribute in the `gitops.manifest_projects` section.
```yaml
gitops:
@@ -58,28 +50,6 @@ gitops:
# The `id` is a path to a Git repository with Kubernetes resource definitions
# in YAML or JSON format.
- id: gitlab-org/cluster-integration/gitlab-agent
- # Holds the only API groups and kinds of resources that gitops will monitor.
- # Inclusion rules are evaluated first, then exclusion rules.
- # If there is still no match, resource is monitored.
- # Resources: https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/#required-fields
- # Groups: https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-groups-and-versioning
- resource_inclusions:
- - api_groups:
- - apps
- kinds:
- - '*'
- - api_groups:
- - ''
- kinds:
- - 'ConfigMap'
- # Holds the API groups and kinds of resources to exclude from gitops watch.
- # Inclusion rules are evaluated first, then exclusion rules.
- # If there is still no match, resource is monitored.
- resource_exclusions:
- - api_groups:
- - '*'
- kinds:
- - '*'
# Namespace to use if not set explicitly in object manifest.
default_namespace: my-ns
# Paths inside of the repository to scan for manifest files.
@@ -93,6 +63,37 @@ gitops:
- glob: '/team2/apps/**/*.yaml'
# If 'paths' is not specified or is an empty list, the configuration below is used
- glob: '/**/*.{yaml,yml,json}'
+ # Reconcile timeout defines whether the applier should wait
+ # until all applied resources have been reconciled, and if so,
+ # how long to wait.
+ reconcile_timeout: 3600s # 1 hour by default
+ # Dry run strategy defines whether changes should actually be performed,
+ # or if it is just talk and no action.
+ # https://github.com/kubernetes-sigs/cli-utils/blob/d6968048dcd80b1c7b55d9e4f31fc25f71c9b490/pkg/common/common.go#L68-L89
+ # Can be: none, client, server
+ dry_run_strategy: none # 'none' by default
+ # Prune defines whether pruning of previously applied
+ # objects should happen after apply.
+ prune: true # enabled by default
+ # Prune timeout defines whether we should wait for all resources
+ # to be fully deleted after pruning, and if so, how long we should
+ # wait.
+ prune_timeout: 3600s # 1 hour by default
+ # Prune propagation policy defines the deletion propagation policy
+ # that should be used for pruning.
+ # https://github.com/kubernetes/apimachinery/blob/44113beed5d39f1b261a12ec398a356e02358307/pkg/apis/meta/v1/types.go#L456-L470
+ # Can be: orphan, background, foreground
+ prune_propagation_policy: foreground # 'foreground' by default
+ # InventoryPolicy defines if an inventory object can take over
+ # objects that belong to another inventory object or don't
+ # belong to any inventory object.
+ # This is done by determining if the apply/prune operation
+ # can go through for a resource based on the comparison
+ # the inventory-id value in the package and the owning-inventory
+ # annotation in the live object.
+ # https://github.com/kubernetes-sigs/cli-utils/blob/d6968048dcd80b1c7b55d9e4f31fc25f71c9b490/pkg/inventory/policy.go#L12-L66
+ # Can be: must_match, adopt_if_no_inventory, adopt_all
+ inventory_policy: must_match # 'must_match' by default
```
### Using multiple manifest projects
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index f4bb29d56ea..cb913e74ce5 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -188,7 +188,6 @@ module Gitlab
services_usage,
usage_counters,
user_preferences_usage,
- ingress_modsecurity_usage,
container_expiration_policies_usage,
service_desk_counts,
email_campaign_counts
@@ -295,7 +294,6 @@ module Gitlab
reply_by_email_enabled: alt_usage_data(fallback: nil) { Gitlab::IncomingEmail.enabled? },
signup_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.allow_signup? },
web_ide_clientside_preview_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? },
- ingress_modsecurity_enabled: Feature.enabled?(:ingress_modsecurity),
grafana_link_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.grafana_enabled? },
gitpod_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.gitpod_enabled? }
}
@@ -377,29 +375,6 @@ module Gitlab
Gitlab::UsageData::Topology.new.topology_usage_data
end
- # rubocop: disable UsageData/DistinctCountByLargeForeignKey
- def ingress_modsecurity_usage
- ##
- # This method measures usage of the Modsecurity Web Application Firewall across the entire
- # instance's deployed environments.
- #
- # NOTE: this service is an approximation as it does not yet take into account if environment
- # is enabled and only measures applications installed using GitLab Managed Apps (disregards
- # CI-based managed apps).
- #
- # More details: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28331#note_318621786
- ##
-
- column = ::Deployment.arel_table[:environment_id]
- {
- ingress_modsecurity_logging: distinct_count(successful_deployments_with_cluster(::Clusters::Applications::Ingress.modsecurity_enabled.logging), column),
- ingress_modsecurity_blocking: distinct_count(successful_deployments_with_cluster(::Clusters::Applications::Ingress.modsecurity_enabled.blocking), column),
- ingress_modsecurity_disabled: distinct_count(successful_deployments_with_cluster(::Clusters::Applications::Ingress.modsecurity_disabled), column),
- ingress_modsecurity_not_installed: distinct_count(successful_deployments_with_cluster(::Clusters::Applications::Ingress.modsecurity_not_installed), column)
- }
- end
- # rubocop: enable UsageData/DistinctCountByLargeForeignKey
-
# rubocop: disable CodeReuse/ActiveRecord
def container_expiration_policies_usage
results = {}
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 968eddfe3d9..a8038716732 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -19,9 +19,6 @@ msgstr ""
msgid " %{name}, confirm your email address now! "
msgstr ""
-msgid " %{project_name}#%{issuable_iid} &middot; created %{issuable_created} by %{author} &middot; updated %{issuable_updated}"
-msgstr ""
-
msgid " %{start} to %{end}"
msgstr ""
@@ -21642,9 +21639,6 @@ msgstr ""
msgid "Multiple uploaders found: %{uploader_types}"
msgstr ""
-msgid "Must have a unique policy, status, and elapsed time"
-msgstr ""
-
msgid "Must match with the %{codeStart}external_url%{codeEnd} in %{codeStart}/etc/gitlab/gitlab.rb%{codeEnd}."
msgstr ""
@@ -29153,6 +29147,9 @@ msgstr ""
msgid "SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again."
msgstr ""
+msgid "SecurityReports|Error parsing security reports"
+msgstr ""
+
msgid "SecurityReports|Failed to get security report information. Please reload the page or try again later."
msgstr ""
@@ -29258,6 +29255,9 @@ msgstr ""
msgid "SecurityReports|Take survey"
msgstr ""
+msgid "SecurityReports|The security reports below contain one or more vulnerability findings that could not be parsed and were not recorded. Download the artifacts in the job output to investigate. Ensure any security report created conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
+msgstr ""
+
msgid "SecurityReports|There was an error adding the comment."
msgstr ""
@@ -38521,6 +38521,9 @@ msgstr ""
msgid "created"
msgstr ""
+msgid "created %{issuable_created} by %{author}"
+msgstr ""
+
msgid "created %{timeAgoString} by %{email} via %{user}"
msgstr ""
@@ -39249,6 +39252,9 @@ msgstr ""
msgid "must be greater than start date"
msgstr ""
+msgid "must have a unique schedule, status, and elapsed time"
+msgstr ""
+
msgid "my-awesome-group"
msgstr ""
diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb
index 0304259a1fd..32952a127d3 100644
--- a/spec/features/search/user_searches_for_merge_requests_spec.rb
+++ b/spec/features/search/user_searches_for_merge_requests_spec.rb
@@ -29,6 +29,11 @@ RSpec.describe 'User searches for merge requests', :js do
page.within('.results') do
expect(page).to have_link(merge_request1.title)
expect(page).not_to have_link(merge_request2.title)
+
+ # Each result should have MR refs like `gitlab-org/gitlab!1`
+ page.all('.search-result-row').each do |e|
+ expect(e.text).to match(/!\d+/)
+ end
end
end
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index e7859d48303..ad69dd4775a 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -15,6 +15,7 @@ import {
formatIssueInput,
formatIssue,
getMoveData,
+ updateListPosition,
} from '~/boards/boards_util';
import destroyBoardListMutation from '~/boards/graphql/board_list_destroy.mutation.graphql';
import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql';
@@ -36,6 +37,7 @@ import {
mockMoveIssueParams,
mockMoveState,
mockMoveData,
+ mockList,
} from '../mock_data';
jest.mock('~/flash');
@@ -374,6 +376,24 @@ describe('createIssueList', () => {
});
});
+describe('addList', () => {
+ const getters = {
+ getListByTitle: jest.fn().mockReturnValue(mockList),
+ };
+
+ it('should commit RECEIVE_ADD_LIST_SUCCESS mutation and dispatch fetchItemsForList action', () => {
+ testAction({
+ action: actions.addList,
+ payload: mockLists[1],
+ state: { ...getters },
+ expectedMutations: [
+ { type: types.RECEIVE_ADD_LIST_SUCCESS, payload: updateListPosition(mockLists[1]) },
+ ],
+ expectedActions: [{ type: 'fetchItemsForList', payload: { listId: mockList.id } }],
+ });
+ });
+});
+
describe('fetchLabels', () => {
it('should commit mutation RECEIVE_LABELS_SUCCESS on success', async () => {
const queryResponse = {
@@ -521,7 +541,8 @@ describe('toggleListCollapsed', () => {
describe('removeList', () => {
let state;
- const list = mockLists[0];
+ let getters;
+ const list = mockLists[1];
const listId = list.id;
const mutationVariables = {
mutation: destroyBoardListMutation,
@@ -535,6 +556,9 @@ describe('removeList', () => {
boardLists: mockListsById,
issuableType: issuableTypes.issue,
};
+ getters = {
+ getListByTitle: jest.fn().mockReturnValue(mockList),
+ };
});
afterEach(() => {
@@ -544,13 +568,15 @@ describe('removeList', () => {
it('optimistically deletes the list', () => {
const commit = jest.fn();
- actions.removeList({ commit, state }, listId);
+ actions.removeList({ commit, state, getters, dispatch: () => {} }, listId);
expect(commit.mock.calls).toEqual([[types.REMOVE_LIST, listId]]);
});
it('keeps the updated list if remove succeeds', async () => {
const commit = jest.fn();
+ const dispatch = jest.fn();
+
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: {
destroyBoardList: {
@@ -559,17 +585,18 @@ describe('removeList', () => {
},
});
- await actions.removeList({ commit, state }, listId);
+ await actions.removeList({ commit, state, getters, dispatch }, listId);
expect(gqlClient.mutate).toHaveBeenCalledWith(mutationVariables);
expect(commit.mock.calls).toEqual([[types.REMOVE_LIST, listId]]);
+ expect(dispatch.mock.calls).toEqual([['fetchItemsForList', { listId: mockList.id }]]);
});
it('restores the list if update fails', async () => {
const commit = jest.fn();
jest.spyOn(gqlClient, 'mutate').mockResolvedValue(Promise.reject());
- await actions.removeList({ commit, state }, listId);
+ await actions.removeList({ commit, state, getters, dispatch: () => {} }, listId);
expect(gqlClient.mutate).toHaveBeenCalledWith(mutationVariables);
expect(commit.mock.calls).toEqual([
@@ -588,7 +615,7 @@ describe('removeList', () => {
},
});
- await actions.removeList({ commit, state }, listId);
+ await actions.removeList({ commit, state, getters, dispatch: () => {} }, listId);
expect(gqlClient.mutate).toHaveBeenCalledWith(mutationVariables);
expect(commit.mock.calls).toEqual([
@@ -650,6 +677,10 @@ describe('fetchItemsForList', () => {
state,
[
{
+ type: types.RESET_ITEMS_FOR_LIST,
+ payload: listId,
+ },
+ {
type: types.REQUEST_ITEMS_FOR_LIST,
payload: { listId, fetchNext: false },
},
@@ -672,6 +703,10 @@ describe('fetchItemsForList', () => {
state,
[
{
+ type: types.RESET_ITEMS_FOR_LIST,
+ payload: listId,
+ },
+ {
type: types.REQUEST_ITEMS_FOR_LIST,
payload: { listId, fetchNext: false },
},
diff --git a/spec/frontend/boards/stores/mutations_spec.js b/spec/frontend/boards/stores/mutations_spec.js
index d89abcc79ae..5b38f04e77b 100644
--- a/spec/frontend/boards/stores/mutations_spec.js
+++ b/spec/frontend/boards/stores/mutations_spec.js
@@ -273,6 +273,53 @@ describe('Board Store Mutations', () => {
});
});
+ describe('RESET_ITEMS_FOR_LIST', () => {
+ it('should remove issues from boardItemsByListId state', () => {
+ const listId = 'gid://gitlab/List/1';
+ const boardItemsByListId = {
+ [listId]: [mockIssue.id],
+ };
+
+ state = {
+ ...state,
+ boardItemsByListId,
+ };
+
+ mutations[types.RESET_ITEMS_FOR_LIST](state, listId);
+
+ expect(state.boardItemsByListId[listId]).toEqual([]);
+ });
+ });
+
+ describe('REQUEST_ITEMS_FOR_LIST', () => {
+ const listId = 'gid://gitlab/List/1';
+ const boardItemsByListId = {
+ [listId]: [mockIssue.id],
+ };
+
+ it.each`
+ fetchNext | isLoading | isLoadingMore
+ ${true} | ${undefined} | ${true}
+ ${false} | ${true} | ${undefined}
+ `(
+ 'sets isLoading to $isLoading and isLoadingMore to $isLoadingMore when fetchNext is $fetchNext',
+ ({ fetchNext, isLoading, isLoadingMore }) => {
+ state = {
+ ...state,
+ boardItemsByListId,
+ listsFlags: {
+ [listId]: {},
+ },
+ };
+
+ mutations[types.REQUEST_ITEMS_FOR_LIST](state, { listId, fetchNext });
+
+ expect(state.listsFlags[listId].isLoading).toBe(isLoading);
+ expect(state.listsFlags[listId].isLoadingMore).toBe(isLoadingMore);
+ },
+ );
+ });
+
describe('RECEIVE_ITEMS_FOR_LIST_SUCCESS', () => {
it('updates boardItemsByListId and issues on state', () => {
const listIssues = {
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index b0338d80ee7..ecaee03eeea 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -202,6 +202,20 @@ RSpec.describe IssuablesHelper do
end
end
+ describe '#issuable_project_reference' do
+ it 'display project name and simple reference with `#` to an issue' do
+ issue = build_stubbed(:issue)
+
+ expect(helper.issuable_project_reference(issue)).to eq("#{issue.project.full_name} ##{issue.iid}")
+ end
+
+ it 'display project name and simple reference with `!` to an MR' do
+ merge_request = build_stubbed(:merge_request)
+
+ expect(helper.issuable_project_reference(merge_request)).to eq("#{merge_request.project.full_name} !#{merge_request.iid}")
+ end
+ end
+
describe '#updated_at_by' do
let(:user) { create(:user) }
let(:unedited_issuable) { create(:issue) }
diff --git a/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb b/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb
index 34b073b4729..b4ab9d4861b 100644
--- a/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/names_suggestions/generator_spec.rb
@@ -33,24 +33,6 @@ RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::Generator do
end
context 'joined relations' do
- context 'counted attribute comes from joined relation' do
- it_behaves_like 'name suggestion' do
- # corresponding metric is collected with:
- # distinct_count(
- # ::Clusters::Applications::Ingress.modsecurity_enabled.logging
- # .joins(cluster: :deployments)
- # .merge(::Clusters::Cluster.enabled)
- # .merge(Deployment.success),
- # ::Deployment.arel_table[:environment_id]
- # )
- let(:key_path) { 'counts.ingress_modsecurity_logging' }
- let(:name_suggestion) do
- constrains = /'\(clusters_applications_ingress\.modsecurity_enabled = TRUE AND clusters_applications_ingress\.modsecurity_mode = \d+ AND clusters.enabled = TRUE AND deployments.status = \d+\)'/
- /count_distinct_environment_id_from_<adjective describing\: #{constrains}>_deployments_<with>_<adjective describing\: #{constrains}>_clusters_<having>_<adjective describing\: #{constrains}>_clusters_applications_ingress/
- end
- end
- end
-
context 'counted attribute comes from source relation' do
it_behaves_like 'name suggestion' do
# corresponding metric is collected with count(Issue.with_alert_management_alerts.not_authored_by(::User.alert_bot), start: issue_minimum_id, finish: issue_maximum_id)
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 553bdf7034a..ea82de186f5 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -966,138 +966,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
end
- describe '.ingress_modsecurity_usage' do
- subject { described_class.ingress_modsecurity_usage }
-
- let(:environment) { create(:environment) }
- let(:project) { environment.project }
- let(:environment_scope) { '*' }
- let(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
- let(:cluster) { create(:cluster, environment_scope: environment_scope, projects: [project]) }
- let(:ingress_mode) { :modsecurity_blocking }
- let!(:ingress) { create(:clusters_applications_ingress, ingress_mode, cluster: cluster) }
-
- context 'when cluster is disabled' do
- let(:cluster) { create(:cluster, :disabled, projects: [project]) }
-
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(0)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'when deployment is unsuccessful' do
- let!(:deployment) { create(:deployment, :failed, environment: environment, project: project, cluster: cluster) }
-
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(0)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'when deployment is successful' do
- let!(:deployment) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
-
- context 'when modsecurity is in blocking mode' do
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(1)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'when modsecurity is in logging mode' do
- let(:ingress_mode) { :modsecurity_logging }
-
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(1)
- expect(subject[:ingress_modsecurity_blocking]).to eq(0)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'when modsecurity is disabled' do
- let(:ingress_mode) { :modsecurity_disabled }
-
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(0)
- expect(subject[:ingress_modsecurity_disabled]).to eq(1)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'when modsecurity is not installed' do
- let(:ingress_mode) { :modsecurity_not_installed }
-
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(0)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(1)
- end
- end
-
- context 'with multiple projects' do
- let(:environment_2) { create(:environment) }
- let(:project_2) { environment_2.project }
- let(:cluster_2) { create(:cluster, environment_scope: environment_scope, projects: [project_2]) }
- let!(:ingress_2) { create(:clusters_applications_ingress, :modsecurity_logging, cluster: cluster_2) }
- let!(:deployment_2) { create(:deployment, :success, environment: environment_2, project: project_2, cluster: cluster_2) }
-
- it 'gathers non-duplicated ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(1)
- expect(subject[:ingress_modsecurity_blocking]).to eq(1)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'with multiple deployments' do
- let!(:deployment_2) { create(:deployment, :success, environment: environment, project: project, cluster: cluster) }
-
- it 'gathers non-duplicated ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(1)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'with multiple projects' do
- let(:environment_2) { create(:environment) }
- let(:project_2) { environment_2.project }
- let!(:deployment_2) { create(:deployment, :success, environment: environment_2, project: project_2, cluster: cluster) }
- let(:cluster) { create(:cluster, environment_scope: environment_scope, projects: [project, project_2]) }
-
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(2)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
-
- context 'with multiple environments' do
- let!(:environment_2) { create(:environment, project: project) }
- let!(:deployment_2) { create(:deployment, :success, environment: environment_2, project: project, cluster: cluster) }
-
- it 'gathers ingress data' do
- expect(subject[:ingress_modsecurity_logging]).to eq(0)
- expect(subject[:ingress_modsecurity_blocking]).to eq(2)
- expect(subject[:ingress_modsecurity_disabled]).to eq(0)
- expect(subject[:ingress_modsecurity_not_installed]).to eq(0)
- end
- end
- end
- end
-
describe '.grafana_embed_usage_data' do
subject { described_class.grafana_embed_usage_data }
diff --git a/spec/requests/api/graphql/group/milestones_spec.rb b/spec/requests/api/graphql/group/milestones_spec.rb
index 601cab6aade..2b80b5239c8 100644
--- a/spec/requests/api/graphql/group/milestones_spec.rb
+++ b/spec/requests/api/graphql/group/milestones_spec.rb
@@ -40,6 +40,13 @@ RSpec.describe 'Milestones through GroupQuery' do
expect_array_response(milestone_2.to_global_id.to_s, milestone_3.to_global_id.to_s)
end
+
+ it 'fetches milestones between timeframe start and end arguments' do
+ today = Date.today
+ fetch_milestones(user, { timeframe: { start: today.to_s, end: (today + 2.days).to_s } })
+
+ expect_array_response(milestone_2.to_global_id.to_s, milestone_3.to_global_id.to_s)
+ end
end
context 'when filtering by state' do
diff --git a/spec/support/helpers/access_matchers_helpers.rb b/spec/support/helpers/access_matchers_helpers.rb
index 9100f245d36..035653172c1 100644
--- a/spec/support/helpers/access_matchers_helpers.rb
+++ b/spec/support/helpers/access_matchers_helpers.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module AccessMatchersHelpers
+ include Gitlab::Utils::StrongMemoize
+
USER_ACCESSOR_METHOD_NAME = 'user'
def provide_user(role, membership = nil)
@@ -61,11 +63,6 @@ module AccessMatchersHelpers
# (or defined by `method_name`) method generated by `let` definition in example group before it's used by `subject`.
# This override is per concrete example only because the example group class gets re-created for each example.
instance_eval(<<~CODE, __FILE__, __LINE__ + 1)
- if instance_variable_get(:@__#{USER_ACCESSOR_METHOD_NAME}_patched)
- raise ArgumentError, 'An access matcher be_allowed_for/be_denied_for can be used only once per example (`it` block)'
- end
- instance_variable_set(:@__#{USER_ACCESSOR_METHOD_NAME}_patched, true)
-
def #{USER_ACCESSOR_METHOD_NAME}
@#{USER_ACCESSOR_METHOD_NAME} ||= User.find(#{user.id})
end
@@ -81,6 +78,13 @@ module AccessMatchersHelpers
end
end
+ def reset_matcher_environment
+ instance_eval(<<~CODE, __FILE__, __LINE__ + 1)
+ clear_memoization(:#{USER_ACCESSOR_METHOD_NAME})
+ undef #{USER_ACCESSOR_METHOD_NAME} if defined? user
+ CODE
+ end
+
def run_matcher(action, role, membership, owned_objects)
raise_if_non_block_expectation!(action)
@@ -91,5 +95,7 @@ module AccessMatchersHelpers
else
action.call
end
+
+ reset_matcher_environment
end
end
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
index d21450e85c8..b1a9aade043 100644
--- a/spec/support/helpers/usage_data_helpers.rb
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -162,7 +162,6 @@ module UsageDataHelpers
database
prometheus_metrics_enabled
web_ide_clientside_preview_enabled
- ingress_modsecurity_enabled
object_store
topology
).freeze
diff --git a/spec/workers/build_queue_worker_spec.rb b/spec/workers/build_queue_worker_spec.rb
new file mode 100644
index 00000000000..5f8510abf23
--- /dev/null
+++ b/spec/workers/build_queue_worker_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BuildQueueWorker do
+ describe '#perform' do
+ context 'when build exists' do
+ let!(:build) { create(:ci_build) }
+
+ it 'ticks runner queue value' do
+ expect_next_instance_of(Ci::UpdateBuildQueueService) do |instance|
+ expect(instance).to receive(:tick).with(build)
+ end
+
+ described_class.new.perform(build.id)
+ end
+ end
+
+ context 'when build does not exist' do
+ it 'does not raise exception' do
+ expect { described_class.new.perform(123) }
+ .not_to raise_error
+ end
+ end
+ end
+
+ it_behaves_like 'worker with data consistency',
+ described_class,
+ feature_flag: :load_balancing_for_build_queue_worker,
+ data_consistency: :sticky
+end
diff --git a/workhorse/internal/objectstore/multipart.go b/workhorse/internal/objectstore/multipart.go
index fd1c0ed487d..4c5b64b27ee 100644
--- a/workhorse/internal/objectstore/multipart.go
+++ b/workhorse/internal/objectstore/multipart.go
@@ -11,7 +11,6 @@ import (
"net/http"
"os"
- "gitlab.com/gitlab-org/labkit/log"
"gitlab.com/gitlab-org/labkit/mask"
)
@@ -98,11 +97,11 @@ func (m *Multipart) readAndUploadOnePart(ctx context.Context, partURL string, pu
if err != nil {
return nil, fmt.Errorf("create temporary buffer file: %v", err)
}
- defer func(path string) {
- if err := os.Remove(path); err != nil {
- log.WithError(err).WithField("file", path).Warning("Unable to delete temporary file")
- }
- }(file.Name())
+ defer file.Close()
+
+ if err := os.Remove(file.Name()); err != nil {
+ return nil, err
+ }
n, err := io.Copy(file, src)
if err != nil {