summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/setup.gitlab-ci.yml1
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_KAS_VERSION2
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue17
-rw-r--r--app/assets/javascripts/ci/ci_variable_list/constants.js2
-rw-r--r--app/assets/javascripts/notes/components/note_actions.vue2
-rw-r--r--app/assets/javascripts/notes/components/notes_activity_header.vue2
-rw-r--r--app/assets/javascripts/pages/abuse_reports/index.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue2
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss4
-rw-r--r--app/controllers/abuse_reports_controller.rb2
-rw-r--r--app/controllers/admin/background_migrations_controller.rb1
-rw-r--r--app/controllers/concerns/uploads_actions.rb2
-rw-r--r--app/controllers/uploads_controller.rb1
-rw-r--r--app/finders/data_transfer/group_data_transfer_finder.rb34
-rw-r--r--app/finders/data_transfer/mocked_transfer_finder.rb27
-rw-r--r--app/finders/data_transfer/project_data_transfer_finder.rb25
-rw-r--r--app/graphql/mutations/award_emojis/base.rb2
-rw-r--r--app/graphql/mutations/boards/update.rb6
-rw-r--r--app/graphql/mutations/ci/runner/delete.rb6
-rw-r--r--app/graphql/mutations/ci/runner/update.rb6
-rw-r--r--app/graphql/mutations/clusters/agent_tokens/create.rb6
-rw-r--r--app/graphql/mutations/clusters/agent_tokens/revoke.rb6
-rw-r--r--app/graphql/mutations/clusters/agents/delete.rb6
-rw-r--r--app/graphql/mutations/concerns/mutations/finds_by_gid.rb9
-rw-r--r--app/graphql/mutations/container_repositories/destroy_base.rb6
-rw-r--r--app/graphql/mutations/design_management/update.rb6
-rw-r--r--app/graphql/mutations/discussions/toggle_resolve.rb4
-rw-r--r--app/graphql/mutations/environments/canary_ingress/update.rb4
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/create.rb4
-rw-r--r--app/graphql/mutations/notes/base.rb6
-rw-r--r--app/graphql/mutations/notes/create/base.rb4
-rw-r--r--app/graphql/mutations/packages/destroy.rb6
-rw-r--r--app/graphql/mutations/packages/destroy_file.rb6
-rw-r--r--app/graphql/mutations/release_asset_links/delete.rb6
-rw-r--r--app/graphql/mutations/release_asset_links/update.rb6
-rw-r--r--app/graphql/mutations/terraform/state/base.rb6
-rw-r--r--app/graphql/mutations/todos/base.rb13
-rw-r--r--app/graphql/mutations/todos/create.rb10
-rw-r--r--app/graphql/mutations/todos/mark_all_done.rb2
-rw-r--r--app/graphql/mutations/todos/mark_done.rb2
-rw-r--r--app/graphql/mutations/todos/restore.rb2
-rw-r--r--app/graphql/mutations/todos/restore_many.rb2
-rw-r--r--app/graphql/mutations/work_items/create_from_task.rb6
-rw-r--r--app/graphql/mutations/work_items/delete.rb6
-rw-r--r--app/graphql/mutations/work_items/delete_task.rb5
-rw-r--r--app/graphql/mutations/work_items/update.rb4
-rw-r--r--app/graphql/resolvers/data_transfer/data_transfer_arguments.rb19
-rw-r--r--app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb34
-rw-r--r--app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb34
-rw-r--r--app/graphql/resolvers/data_transfer_resolver.rb59
-rw-r--r--app/graphql/resolvers/design_management/version_resolver.rb4
-rw-r--r--app/graphql/resolvers/notes/synthetic_note_resolver.rb4
-rw-r--r--app/graphql/resolvers/work_item_resolver.rb6
-rw-r--r--app/graphql/types/data_transfer/base_type.rb2
-rw-r--r--app/graphql/types/data_transfer/egress_node_type.rb6
-rw-r--r--app/graphql/types/data_transfer/project_data_transfer_type.rb10
-rw-r--r--app/graphql/types/group_type.rb2
-rw-r--r--app/graphql/types/project_type.rb4
-rw-r--r--app/helpers/abuse_reports_helper.rb9
-rw-r--r--app/helpers/admin/background_migrations_helper.rb1
-rw-r--r--app/models/abuse_report.rb41
-rw-r--r--app/models/pages_deployment.rb2
-rw-r--r--app/models/projects/data_transfer.rb8
-rw-r--r--app/views/abuse_reports/new.html.haml11
-rw-r--r--app/views/admin/background_migrations/index.html.haml3
-rw-r--r--app/views/shared/_file_picker_button.html.haml5
-rw-r--r--app/views/shared/hook_logs/_index.html.haml2
-rw-r--r--app/views/shared/web_hooks/_web_hook_disabled_alert.html.haml2
-rw-r--r--config/feature_flags/development/data_transfer_monitoring_mock_data.yml (renamed from config/feature_flags/development/codeowners_default_owners.yml)6
-rw-r--r--config/metrics/counts_28d/20210216174910_analytics_unique_visits_for_any_target_monthly.yml1
-rw-r--r--config/metrics/counts_7d/20210216174908_analytics_unique_visits_for_any_target.yml1
-rw-r--r--config/routes/uploads.rb6
-rw-r--r--data/deprecations/15-8-jira-connect-app-cookie-auth.yml4
-rw-r--r--db/migrate/20230315053635_add_screenshot_to_abuse_reports.rb10
-rw-r--r--db/migrate/20230321161218_add_project_access_token_limit_to_plan_limits.rb7
-rw-r--r--db/migrate/20230321161441_insert_project_access_token_limit.rb15
-rw-r--r--db/migrate/20230322151605_rerun_remove_invalid_deploy_access_level.rb26
-rw-r--r--db/migrate/20230327074932_add_text_limit_to_abuse_reports_screenshot.rb13
-rw-r--r--db/post_migrate/20230131194959_remove_invalid_deploy_access_level.rb11
-rw-r--r--db/post_migrate/20230313031629_ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb29
-rw-r--r--db/post_migrate/20230319105436_remove_member_role_download_code.rb7
-rw-r--r--db/post_migrate/20230321003252_swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com.rb68
-rw-r--r--db/schema_migrations/202303130316291
-rw-r--r--db/schema_migrations/202303150536351
-rw-r--r--db/schema_migrations/202303191054361
-rw-r--r--db/schema_migrations/202303210032521
-rw-r--r--db/schema_migrations/202303211612181
-rw-r--r--db/schema_migrations/202303211614411
-rw-r--r--db/schema_migrations/202303221516051
-rw-r--r--db/schema_migrations/202303270749321
-rw-r--r--db/structure.sql10
-rw-r--r--doc/administration/server_hooks.md50
-rw-r--r--doc/api/graphql/reference/index.md6
-rw-r--r--doc/development/database/table_partitioning.md82
-rw-r--r--doc/integration/jenkins.md27
-rw-r--r--doc/integration/jira/connect-app.md95
-rw-r--r--doc/update/deprecations.md4
-rw-r--r--doc/user/application_security/dependency_scanning/index.md22
-rw-r--r--doc/user/project/code_owners.md14
-rw-r--r--doc/user/project/integrations/bamboo.md2
-rw-r--r--doc/user/project/integrations/bugzilla.md2
-rw-r--r--doc/user/project/integrations/index.md4
-rw-r--r--doc/user/project/integrations/webhooks.md15
-rw-r--r--lib/gitlab/database/background_migration/batched_migration.rb1
-rw-r--r--lib/gitlab/graphql/authorize/authorize_resource.rb4
-rw-r--r--lib/gitlab/pagination/keyset.rb4
-rw-r--r--locale/gitlab.pot25
-rw-r--r--qa/qa/support/wait_for_requests.rb2
-rw-r--r--spec/factories/abuse_reports.rb4
-rw-r--r--spec/factories/projects/data_transfers.rb4
-rw-r--r--spec/features/abuse_report_spec.rb2
-rw-r--r--spec/finders/data_transfer/group_data_transfer_finder_spec.rb84
-rw-r--r--spec/finders/data_transfer/mocked_transfer_finder_spec.rb22
-rw-r--r--spec/finders/data_transfer/project_data_transfer_finder_spec.rb80
-rw-r--r--spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js3
-rw-r--r--spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb26
-rw-r--r--spec/graphql/resolvers/data_transfer/group_data_transfer_resolver_spec.rb65
-rw-r--r--spec/graphql/resolvers/data_transfer/project_data_transfer_resolver_spec.rb68
-rw-r--r--spec/graphql/resolvers/data_transfer_resolver_spec.rb31
-rw-r--r--spec/graphql/types/data_transfer/project_data_transfer_type_spec.rb38
-rw-r--r--spec/helpers/abuse_reports_helper_spec.rb13
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_spec.rb13
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb10
-rw-r--r--spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb35
-rw-r--r--spec/migrations/remove_invalid_deploy_access_level_spec.rb48
-rw-r--r--spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb86
-rw-r--r--spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb66
-rw-r--r--spec/models/abuse_report_spec.rb35
-rw-r--r--spec/models/plan_limits_spec.rb1
-rw-r--r--spec/models/projects/data_transfer_spec.rb26
-rw-r--r--spec/requests/abuse_reports_controller_spec.rb1
-rw-r--r--spec/requests/admin/background_migrations_controller_spec.rb11
-rw-r--r--spec/requests/api/graphql/group/data_transfer_spec.rb115
-rw-r--r--spec/requests/api/graphql/project/data_transfer_spec.rb112
-rw-r--r--spec/support/finder_collection_allowlist.yml1
-rw-r--r--spec/support/helpers/every_sidekiq_worker_test_helper.rb9
-rw-r--r--spec/support/shared_examples/controllers/unique_hll_events_examples.rb3
-rw-r--r--spec/support/shared_examples/features/abuse_report_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/features/reportable_note_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/graphql/resolvers/data_transfer_resolver_shared_examples.rb23
-rw-r--r--spec/tooling/lib/tooling/mappings/graphql_base_type_mappings_spec.rb249
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb4
-rwxr-xr-xtooling/bin/graphql_base_type_mappings9
-rw-r--r--tooling/lib/tooling/mappings/graphql_base_type_mappings.rb119
-rw-r--r--workhorse/go.mod6
-rw-r--r--workhorse/go.sum16
147 files changed, 2065 insertions, 523 deletions
diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml
index 35172faa6df..3ebbe1e0fed 100644
--- a/.gitlab/ci/setup.gitlab-ci.yml
+++ b/.gitlab/ci/setup.gitlab-ci.yml
@@ -123,6 +123,7 @@ detect-tests:
tooling/bin/partial_to_views_mappings ${RSPEC_CHANGED_FILES_PATH} ${RSPEC_VIEWS_INCLUDING_PARTIALS_PATH};
tooling/bin/find_tests ${RSPEC_VIEWS_INCLUDING_PARTIALS_PATH} ${RSPEC_MATCHING_TESTS_PATH};
tooling/bin/js_to_system_specs_mappings ${RSPEC_CHANGED_FILES_PATH} ${RSPEC_MATCHING_TESTS_PATH};
+ tooling/bin/graphql_base_type_mappings ${RSPEC_CHANGED_FILES_PATH} ${RSPEC_MATCHING_TESTS_PATH};
tooling/bin/find_changes ${RSPEC_CHANGED_FILES_PATH} ${RSPEC_MATCHING_TESTS_PATH} ${FRONTEND_FIXTURES_MAPPING_PATH};
filter_rspec_matched_foss_tests ${RSPEC_MATCHING_TESTS_PATH} ${RSPEC_MATCHING_TESTS_FOSS_PATH};
filter_rspec_matched_ee_tests ${RSPEC_MATCHING_TESTS_PATH} ${RSPEC_MATCHING_TESTS_EE_PATH};
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 799039087c5..0ce6459713f 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-28a95b4b97a1f2b2187cccfa05feebf073d0696b
+0c5b7fc851773654a7e2dedf195eb55409967284
diff --git a/GITLAB_KAS_VERSION b/GITLAB_KAS_VERSION
index 1a42a9dbc96..332da5068c6 100644
--- a/GITLAB_KAS_VERSION
+++ b/GITLAB_KAS_VERSION
@@ -1 +1 @@
-v15.10.0
+v15.11.0-rc1
diff --git a/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue b/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue
index 6095ba79281..09b02068388 100644
--- a/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue
+++ b/app/assets/javascripts/ci/ci_variable_list/components/ci_environments_dropdown.vue
@@ -1,16 +1,18 @@
<script>
import { debounce, uniq } from 'lodash';
-import { GlDropdownDivider, GlDropdownItem, GlCollapsibleListbox } from '@gitlab/ui';
+import { GlDropdownDivider, GlDropdownItem, GlCollapsibleListbox, GlSprintf } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { __, s__, sprintf } from '~/locale';
import { convertEnvironmentScope } from '../utils';
+import { ENVIRONMENT_QUERY_LIMIT } from '../constants';
export default {
name: 'CiEnvironmentsDropdown',
components: {
+ GlCollapsibleListbox,
GlDropdownDivider,
GlDropdownItem,
- GlCollapsibleListbox,
+ GlSprintf,
},
mixins: [glFeatureFlagsMixin()],
props: {
@@ -95,9 +97,10 @@ export default {
this.selectEnvironment(this.searchTerm);
},
},
+ ENVIRONMENT_QUERY_LIMIT,
i18n: {
maxEnvsNote: s__(
- 'CiVariable|Maximum of 20 environments listed. For more environments, enter a search query.',
+ 'CiVariable|Maximum of %{limit} environments listed. For more environments, enter a search query.',
),
},
};
@@ -117,9 +120,11 @@ export default {
<gl-dropdown-divider v-if="shouldRenderDivider" />
<div v-if="isEnvScopeLimited" data-testid="max-envs-notice">
<gl-dropdown-item class="gl-list-style-none" disabled>
- <span class="gl-font-sm">
- {{ $options.i18n.maxEnvsNote }}
- </span>
+ <gl-sprintf :message="$options.i18n.maxEnvsNote" class="gl-font-sm">
+ <template #limit>
+ {{ $options.ENVIRONMENT_QUERY_LIMIT }}
+ </template>
+ </gl-sprintf>
</gl-dropdown-item>
</div>
<div v-if="shouldRenderCreateButton">
diff --git a/app/assets/javascripts/ci/ci_variable_list/constants.js b/app/assets/javascripts/ci/ci_variable_list/constants.js
index e6874a5cde6..03374162b79 100644
--- a/app/assets/javascripts/ci/ci_variable_list/constants.js
+++ b/app/assets/javascripts/ci/ci_variable_list/constants.js
@@ -1,7 +1,7 @@
import { __, s__ } from '~/locale';
export const ADD_CI_VARIABLE_MODAL_ID = 'add-ci-variable';
-export const ENVIRONMENT_QUERY_LIMIT = 20;
+export const ENVIRONMENT_QUERY_LIMIT = 30;
export const SORT_DIRECTIONS = {
ASC: 'KEY_ASC',
diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue
index 89cd252b94b..14497a239ca 100644
--- a/app/assets/javascripts/notes/components/note_actions.vue
+++ b/app/assets/javascripts/notes/components/note_actions.vue
@@ -21,7 +21,7 @@ export default {
editCommentLabel: __('Edit comment'),
deleteCommentLabel: __('Delete comment'),
moreActionsLabel: __('More actions'),
- reportAbuse: __('Report abuse to administrator'),
+ reportAbuse: __('Report abuse'),
},
name: 'NoteActions',
components: {
diff --git a/app/assets/javascripts/notes/components/notes_activity_header.vue b/app/assets/javascripts/notes/components/notes_activity_header.vue
index 9c3b2139a5d..95c02884ace 100644
--- a/app/assets/javascripts/notes/components/notes_activity_header.vue
+++ b/app/assets/javascripts/notes/components/notes_activity_header.vue
@@ -27,7 +27,7 @@ export default {
<template>
<div
- class="gl-display-flex gl-sm-align-items-center gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between gl-pt-5"
+ class="gl-display-flex gl-sm-align-items-center gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between gl-pt-5 gl-pb-3"
>
<h2 class="gl-font-size-h1 gl-m-0">{{ __('Activity') }}</h2>
<div class="gl-display-flex gl-gap-3 gl-w-full gl-sm-w-auto gl-mt-3 gl-sm-mt-0">
diff --git a/app/assets/javascripts/pages/abuse_reports/index.js b/app/assets/javascripts/pages/abuse_reports/index.js
index feceeb0b10a..ea7c9042e6d 100644
--- a/app/assets/javascripts/pages/abuse_reports/index.js
+++ b/app/assets/javascripts/pages/abuse_reports/index.js
@@ -1,3 +1,5 @@
import { initLinkToSpam } from '~/abuse_reports';
+import initFilePickers from '~/file_pickers';
initLinkToSpam();
+initFilePickers();
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
index c69e047aedd..6976bfcc989 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
@@ -106,7 +106,7 @@ export default {
v-if="userPermissions.canMerge"
size="small"
variant="confirm"
- category="secondary"
+ category="tertiary"
data-testid="merge-locally-button"
class="js-check-out-modal-trigger gl-align-self-start"
>
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index c9a937e21a7..d54b18a18c4 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -983,8 +983,8 @@ $tabs-holder-z-index: 250;
.merge-request-overview {
@include media-breakpoint-up(lg) {
display: grid;
- grid-template-columns: calc(95% - 285px) auto;
- grid-gap: 5%;
+ grid-template-columns: calc(97% - 285px) auto;
+ grid-gap: 3%;
}
}
diff --git a/app/controllers/abuse_reports_controller.rb b/app/controllers/abuse_reports_controller.rb
index f6b4fbac8d5..edeac57bc42 100644
--- a/app/controllers/abuse_reports_controller.rb
+++ b/app/controllers/abuse_reports_controller.rb
@@ -55,7 +55,7 @@ class AbuseReportsController < ApplicationController
private
def report_params
- params.require(:abuse_report).permit(:message, :user_id, :category, :reported_from_url, links_to_spam: [])
+ params.require(:abuse_report).permit(:message, :user_id, :category, :reported_from_url, :screenshot, links_to_spam: [])
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/admin/background_migrations_controller.rb b/app/controllers/admin/background_migrations_controller.rb
index b904196c5ab..a5211961d81 100644
--- a/app/controllers/admin/background_migrations_controller.rb
+++ b/app/controllers/admin/background_migrations_controller.rb
@@ -10,6 +10,7 @@ module Admin
def index
@relations_by_tab = {
'queued' => batched_migration_class.queued.queue_order,
+ 'finalizing' => batched_migration_class.finalizing.queue_order,
'failed' => batched_migration_class.with_status(:failed).queue_order,
'finished' => batched_migration_class.with_status(:finished).queue_order.reverse_order
}
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index e53d0bc65a0..db756ae336f 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -5,7 +5,7 @@ module UploadsActions
include Gitlab::Utils::StrongMemoize
include SendFileUpload
- UPLOAD_MOUNTS = %w[avatar attachment file logo pwa_icon header_logo favicon].freeze
+ UPLOAD_MOUNTS = %w[avatar attachment file logo pwa_icon header_logo favicon screenshot].freeze
included do
prepend_before_action :set_request_format_from_path_extension
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index ea99aa12350..1a966739401 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -16,6 +16,7 @@ class UploadsController < ApplicationController
"projects/topic" => Projects::Topic,
'alert_management_metric_image' => ::AlertManagement::MetricImage,
"achievements/achievement" => Achievements::Achievement,
+ "abuse_report" => AbuseReport,
nil => PersonalSnippet
}.freeze
diff --git a/app/finders/data_transfer/group_data_transfer_finder.rb b/app/finders/data_transfer/group_data_transfer_finder.rb
new file mode 100644
index 00000000000..19ab99d4477
--- /dev/null
+++ b/app/finders/data_transfer/group_data_transfer_finder.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module DataTransfer
+ class GroupDataTransferFinder
+ def initialize(group:, from:, to:, user:)
+ @group = group
+ @from = from
+ @to = to
+ @user = user
+ end
+
+ def execute
+ return ::Projects::DataTransfer.none unless Ability.allowed?(user, :read_usage_quotas, group)
+
+ ::Projects::DataTransfer
+ .with_namespace_between_dates(group, from, to)
+ .select('SUM(repository_egress
+ + artifacts_egress
+ + packages_egress
+ + registry_egress
+ ) as total_egress,
+ SUM(repository_egress) as repository_egress,
+ SUM(artifacts_egress) as artifacts_egress,
+ SUM(packages_egress) as packages_egress,
+ SUM(registry_egress) as registry_egress,
+ date,
+ namespace_id')
+ end
+
+ private
+
+ attr_reader :group, :from, :to, :user
+ end
+end
diff --git a/app/finders/data_transfer/mocked_transfer_finder.rb b/app/finders/data_transfer/mocked_transfer_finder.rb
new file mode 100644
index 00000000000..9c5551005ea
--- /dev/null
+++ b/app/finders/data_transfer/mocked_transfer_finder.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+# Mocked data for data transfer
+# Follow this epic for recent progress: https://gitlab.com/groups/gitlab-org/-/epics/9330
+module DataTransfer
+ class MockedTransferFinder
+ def execute
+ start_date = Date.new(2023, 0o1, 0o1)
+ date_for_index = ->(i) { (start_date + i.months).strftime('%Y-%m-%d') }
+
+ 0.upto(11).map do |i|
+ {
+ date: date_for_index.call(i),
+ repository_egress: rand(70000..550000),
+ artifacts_egress: rand(70000..550000),
+ packages_egress: rand(70000..550000),
+ registry_egress: rand(70000..550000)
+ }.tap do |hash|
+ hash[:total_egress] = hash
+ .slice(:repository_egress, :artifacts_egress, :packages_egress, :registry_egress)
+ .values
+ .sum
+ end
+ end
+ end
+ end
+end
diff --git a/app/finders/data_transfer/project_data_transfer_finder.rb b/app/finders/data_transfer/project_data_transfer_finder.rb
new file mode 100644
index 00000000000..bcabbdb00a5
--- /dev/null
+++ b/app/finders/data_transfer/project_data_transfer_finder.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module DataTransfer
+ class ProjectDataTransferFinder
+ def initialize(project:, from:, to:, user:)
+ @project = project
+ @from = from
+ @to = to
+ @user = user
+ end
+
+ def execute
+ return ::Projects::DataTransfer.none unless Ability.allowed?(user, :read_usage_quotas, project)
+
+ ::Projects::DataTransfer
+ .with_project_between_dates(project, from, to)
+ .select(:project_id, :date, :repository_egress, :artifacts_egress, :packages_egress, :registry_egress,
+ "repository_egress + artifacts_egress + packages_egress + registry_egress as total_egress")
+ end
+
+ private
+
+ attr_reader :project, :from, :to, :user
+ end
+end
diff --git a/app/graphql/mutations/award_emojis/base.rb b/app/graphql/mutations/award_emojis/base.rb
index dc2d46269e6..65065de0de4 100644
--- a/app/graphql/mutations/award_emojis/base.rb
+++ b/app/graphql/mutations/award_emojis/base.rb
@@ -3,8 +3,6 @@
module Mutations
module AwardEmojis
class Base < BaseMutation
- include ::Mutations::FindsByGid
-
NOT_EMOJI_AWARDABLE = 'You cannot award emoji to this resource.'
authorize :award_emoji
diff --git a/app/graphql/mutations/boards/update.rb b/app/graphql/mutations/boards/update.rb
index 7cfce9d2d91..f611608d1b6 100644
--- a/app/graphql/mutations/boards/update.rb
+++ b/app/graphql/mutations/boards/update.rb
@@ -29,12 +29,6 @@ module Mutations
errors: errors_on_object(board)
}
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/ci/runner/delete.rb b/app/graphql/mutations/ci/runner/delete.rb
index db68914a4eb..ba309ca754d 100644
--- a/app/graphql/mutations/ci/runner/delete.rb
+++ b/app/graphql/mutations/ci/runner/delete.rb
@@ -15,16 +15,12 @@ module Mutations
description: 'ID of the runner to delete.'
def resolve(id:, **runner_attrs)
- runner = authorized_find!(id)
+ runner = authorized_find!(id: id)
::Ci::Runners::UnregisterRunnerService.new(runner, current_user).execute
{ errors: runner.errors.full_messages }
end
-
- def find_object(id)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb
index 70f08e03553..00865b177a8 100644
--- a/app/graphql/mutations/ci/runner/update.rb
+++ b/app/graphql/mutations/ci/runner/update.rb
@@ -27,7 +27,7 @@ module Mutations
description: 'Runner after mutation.'
def resolve(id:, **runner_attrs)
- runner = authorized_find!(id)
+ runner = authorized_find!(id: id)
associated_projects_ids = runner_attrs.delete(:associated_projects)
@@ -40,10 +40,6 @@ module Mutations
response
end
- def find_object(id)
- GitlabSchema.find_by_gid(id)
- end
-
private
def associate_runner_projects(response, runner, associated_project_ids)
diff --git a/app/graphql/mutations/clusters/agent_tokens/create.rb b/app/graphql/mutations/clusters/agent_tokens/create.rb
index 1b104652bd2..e717ff4d798 100644
--- a/app/graphql/mutations/clusters/agent_tokens/create.rb
+++ b/app/graphql/mutations/clusters/agent_tokens/create.rb
@@ -54,12 +54,6 @@ module Mutations
errors: Array.wrap(result.message)
}
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/clusters/agent_tokens/revoke.rb b/app/graphql/mutations/clusters/agent_tokens/revoke.rb
index 6e988799921..c4187746464 100644
--- a/app/graphql/mutations/clusters/agent_tokens/revoke.rb
+++ b/app/graphql/mutations/clusters/agent_tokens/revoke.rb
@@ -21,12 +21,6 @@ module Mutations
{ errors: errors_on_object(token) }
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/clusters/agents/delete.rb b/app/graphql/mutations/clusters/agents/delete.rb
index fb482e02794..ddb4e36a68e 100644
--- a/app/graphql/mutations/clusters/agents/delete.rb
+++ b/app/graphql/mutations/clusters/agents/delete.rb
@@ -24,12 +24,6 @@ module Mutations
errors: Array.wrap(result.message)
}
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/concerns/mutations/finds_by_gid.rb b/app/graphql/mutations/concerns/mutations/finds_by_gid.rb
deleted file mode 100644
index 157f87a413d..00000000000
--- a/app/graphql/mutations/concerns/mutations/finds_by_gid.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-module Mutations
- module FindsByGid
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
- end
-end
diff --git a/app/graphql/mutations/container_repositories/destroy_base.rb b/app/graphql/mutations/container_repositories/destroy_base.rb
index 1c2c4d87a5f..46851c15702 100644
--- a/app/graphql/mutations/container_repositories/destroy_base.rb
+++ b/app/graphql/mutations/container_repositories/destroy_base.rb
@@ -4,12 +4,6 @@ module Mutations
module ContainerRepositories
class DestroyBase < Mutations::BaseMutation
include ::Mutations::PackageEventable
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/design_management/update.rb b/app/graphql/mutations/design_management/update.rb
index 5dc20730a90..67732b70f29 100644
--- a/app/graphql/mutations/design_management/update.rb
+++ b/app/graphql/mutations/design_management/update.rb
@@ -28,12 +28,6 @@ module Mutations
errors: errors_on_object(design)
}
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/discussions/toggle_resolve.rb b/app/graphql/mutations/discussions/toggle_resolve.rb
index fce6e4f416f..dc5731add3a 100644
--- a/app/graphql/mutations/discussions/toggle_resolve.rb
+++ b/app/graphql/mutations/discussions/toggle_resolve.rb
@@ -53,10 +53,6 @@ module Mutations
end
end
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
-
def resolve!(discussion)
::Discussions::ResolveService.new(
discussion.project,
diff --git a/app/graphql/mutations/environments/canary_ingress/update.rb b/app/graphql/mutations/environments/canary_ingress/update.rb
index 1cddfdd815b..43e9b6c0881 100644
--- a/app/graphql/mutations/environments/canary_ingress/update.rb
+++ b/app/graphql/mutations/environments/canary_ingress/update.rb
@@ -35,10 +35,6 @@ module Mutations
{ errors: Array.wrap(result[:message]) }
end
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
-
private
def certificate_based_clusters_enabled?
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
index d458bdcf82b..225d313c487 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
@@ -83,10 +83,6 @@ module Mutations
super(**args)
end
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
-
def annotation_create_params(args)
annotation_source = AnnotationSource.new(object: annotation_source(args))
diff --git a/app/graphql/mutations/notes/base.rb b/app/graphql/mutations/notes/base.rb
index fb74805db17..d656835c335 100644
--- a/app/graphql/mutations/notes/base.rb
+++ b/app/graphql/mutations/notes/base.rb
@@ -13,12 +13,6 @@ module Mutations
Types::Notes::NoteType,
null: true,
description: 'Note after mutation.'
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index f48e62af767..69cd1426218 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -47,10 +47,6 @@ module Mutations
private
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
-
def create_note_params(noteable, args)
{
noteable: noteable,
diff --git a/app/graphql/mutations/packages/destroy.rb b/app/graphql/mutations/packages/destroy.rb
index a398b1ff9dc..95832ec8b85 100644
--- a/app/graphql/mutations/packages/destroy.rb
+++ b/app/graphql/mutations/packages/destroy.rb
@@ -23,12 +23,6 @@ module Mutations
errors: errors
}
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/packages/destroy_file.rb b/app/graphql/mutations/packages/destroy_file.rb
index f2a8f2b853a..c7dd2df704e 100644
--- a/app/graphql/mutations/packages/destroy_file.rb
+++ b/app/graphql/mutations/packages/destroy_file.rb
@@ -21,12 +21,6 @@ module Mutations
{ errors: package_file.errors.full_messages }
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/release_asset_links/delete.rb b/app/graphql/mutations/release_asset_links/delete.rb
index 9a75b472411..891d8e5a4d8 100644
--- a/app/graphql/mutations/release_asset_links/delete.rb
+++ b/app/graphql/mutations/release_asset_links/delete.rb
@@ -19,7 +19,7 @@ module Mutations
description: 'Deleted release asset link.'
def resolve(id:)
- link = authorized_find!(id)
+ link = authorized_find!(id: id)
result = ::Releases::Links::DestroyService
.new(link.release, current_user)
@@ -31,10 +31,6 @@ module Mutations
{ link: nil, errors: result.message }
end
end
-
- def find_object(id)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/release_asset_links/update.rb b/app/graphql/mutations/release_asset_links/update.rb
index 2e9054c290d..3df2d28b88c 100644
--- a/app/graphql/mutations/release_asset_links/update.rb
+++ b/app/graphql/mutations/release_asset_links/update.rb
@@ -44,7 +44,7 @@ module Mutations
end
def resolve(id:, **link_attrs)
- link = authorized_find!(id)
+ link = authorized_find!(id: id)
result = ::Releases::Links::UpdateService
.new(link.release, current_user, link_attrs)
@@ -56,10 +56,6 @@ module Mutations
{ link: nil, errors: result.message }
end
end
-
- def find_object(id)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/terraform/state/base.rb b/app/graphql/mutations/terraform/state/base.rb
index 01f69934ea3..9a264836ef5 100644
--- a/app/graphql/mutations/terraform/state/base.rb
+++ b/app/graphql/mutations/terraform/state/base.rb
@@ -10,12 +10,6 @@ module Mutations
Types::GlobalIDType[::Terraform::State],
required: true,
description: 'Global ID of the Terraform state.'
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/todos/base.rb b/app/graphql/mutations/todos/base.rb
deleted file mode 100644
index 9a94c5d1e6d..00000000000
--- a/app/graphql/mutations/todos/base.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module Mutations
- module Todos
- class Base < ::Mutations::BaseMutation
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
- end
- end
-end
diff --git a/app/graphql/mutations/todos/create.rb b/app/graphql/mutations/todos/create.rb
index 489d2f490ff..8a0906da724 100644
--- a/app/graphql/mutations/todos/create.rb
+++ b/app/graphql/mutations/todos/create.rb
@@ -2,7 +2,7 @@
module Mutations
module Todos
- class Create < ::Mutations::Todos::Base
+ class Create < ::Mutations::BaseMutation
graphql_name 'TodoCreate'
authorize :create_todo
@@ -17,7 +17,7 @@ module Mutations
description: 'To-do item created.'
def resolve(target_id:)
- target = authorized_find!(target_id)
+ target = authorized_find!(id: target_id)
todo = TodoService.new.mark_todo(target, current_user)&.first
errors = errors_on_object(todo) if todo
@@ -27,12 +27,6 @@ module Mutations
errors: errors
}
end
-
- private
-
- def find_object(id)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/todos/mark_all_done.rb b/app/graphql/mutations/todos/mark_all_done.rb
index fe4023515a4..7f8d15e033a 100644
--- a/app/graphql/mutations/todos/mark_all_done.rb
+++ b/app/graphql/mutations/todos/mark_all_done.rb
@@ -2,7 +2,7 @@
module Mutations
module Todos
- class MarkAllDone < ::Mutations::Todos::Base
+ class MarkAllDone < ::Mutations::BaseMutation
graphql_name 'TodosMarkAllDone'
authorize :update_user
diff --git a/app/graphql/mutations/todos/mark_done.rb b/app/graphql/mutations/todos/mark_done.rb
index 4fecba55242..05d69fbc969 100644
--- a/app/graphql/mutations/todos/mark_done.rb
+++ b/app/graphql/mutations/todos/mark_done.rb
@@ -2,7 +2,7 @@
module Mutations
module Todos
- class MarkDone < ::Mutations::Todos::Base
+ class MarkDone < ::Mutations::BaseMutation
graphql_name 'TodoMarkDone'
authorize :update_todo
diff --git a/app/graphql/mutations/todos/restore.rb b/app/graphql/mutations/todos/restore.rb
index def24cb71bc..a169ec58a9a 100644
--- a/app/graphql/mutations/todos/restore.rb
+++ b/app/graphql/mutations/todos/restore.rb
@@ -2,7 +2,7 @@
module Mutations
module Todos
- class Restore < ::Mutations::Todos::Base
+ class Restore < ::Mutations::BaseMutation
graphql_name 'TodoRestore'
authorize :update_todo
diff --git a/app/graphql/mutations/todos/restore_many.rb b/app/graphql/mutations/todos/restore_many.rb
index f2f944860c2..106ba18b852 100644
--- a/app/graphql/mutations/todos/restore_many.rb
+++ b/app/graphql/mutations/todos/restore_many.rb
@@ -2,7 +2,7 @@
module Mutations
module Todos
- class RestoreMany < ::Mutations::Todos::Base
+ class RestoreMany < ::Mutations::BaseMutation
graphql_name 'TodoRestoreMany'
MAX_UPDATE_AMOUNT = 50
diff --git a/app/graphql/mutations/work_items/create_from_task.rb b/app/graphql/mutations/work_items/create_from_task.rb
index 4ef8269a42f..23ae09b23fd 100644
--- a/app/graphql/mutations/work_items/create_from_task.rb
+++ b/app/graphql/mutations/work_items/create_from_task.rb
@@ -46,12 +46,6 @@ module Mutations
response
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/work_items/delete.rb b/app/graphql/mutations/work_items/delete.rb
index ec0244fa65e..bce59448412 100644
--- a/app/graphql/mutations/work_items/delete.rb
+++ b/app/graphql/mutations/work_items/delete.rb
@@ -29,12 +29,6 @@ module Mutations
errors: result.errors
}
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/work_items/delete_task.rb b/app/graphql/mutations/work_items/delete_task.rb
index 47ab3748ab4..b13d7e2e3bf 100644
--- a/app/graphql/mutations/work_items/delete_task.rb
+++ b/app/graphql/mutations/work_items/delete_task.rb
@@ -53,11 +53,6 @@ module Mutations
raise_resource_not_available_error!
end
end
-
- # method used by `authorized_find!(id: id)`
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/mutations/work_items/update.rb b/app/graphql/mutations/work_items/update.rb
index 60b5536df56..3bcec7ebb1c 100644
--- a/app/graphql/mutations/work_items/update.rb
+++ b/app/graphql/mutations/work_items/update.rb
@@ -42,10 +42,6 @@ module Mutations
private
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
-
def interpret_quick_actions!(work_item, current_user, widget_params, attributes = {})
return unless work_item.work_item_type.widgets.include?(::WorkItems::Widgets::Description)
diff --git a/app/graphql/resolvers/data_transfer/data_transfer_arguments.rb b/app/graphql/resolvers/data_transfer/data_transfer_arguments.rb
new file mode 100644
index 00000000000..da75a78b2ac
--- /dev/null
+++ b/app/graphql/resolvers/data_transfer/data_transfer_arguments.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DataTransfer
+ module DataTransferArguments
+ extend ActiveSupport::Concern
+
+ included do
+ argument :from, Types::DateType,
+ description:
+ 'Retain egress data for one year. Data for the current month will increase dynamically as egress occurs.',
+ required: false
+ argument :to, Types::DateType,
+ description: 'End date for the data.',
+ required: false
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb b/app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb
new file mode 100644
index 00000000000..83bb144017c
--- /dev/null
+++ b/app/graphql/resolvers/data_transfer/group_data_transfer_resolver.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DataTransfer
+ class GroupDataTransferResolver < BaseResolver
+ include DataTransferArguments
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ authorizes_object!
+ authorize :read_usage_quotas
+
+ type Types::DataTransfer::GroupDataTransferType, null: false
+
+ alias_method :group, :object
+
+ def resolve(**args)
+ return { egress_nodes: [] } unless Feature.enabled?(:data_transfer_monitoring, group)
+
+ results = if Feature.enabled?(:data_transfer_monitoring_mock_data, group)
+ ::DataTransfer::MockedTransferFinder.new.execute
+ else
+ ::DataTransfer::GroupDataTransferFinder.new(
+ group: group,
+ from: args[:from],
+ to: args[:to],
+ user: current_user
+ ).execute.map(&:attributes)
+ end
+
+ { egress_nodes: results.to_a }
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb b/app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb
new file mode 100644
index 00000000000..c3296f7d4c3
--- /dev/null
+++ b/app/graphql/resolvers/data_transfer/project_data_transfer_resolver.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module DataTransfer
+ class ProjectDataTransferResolver < BaseResolver
+ include DataTransferArguments
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ authorizes_object!
+ authorize :read_usage_quotas
+
+ type Types::DataTransfer::ProjectDataTransferType, null: false
+
+ alias_method :project, :object
+
+ def resolve(**args)
+ return { egress_nodes: [] } unless Feature.enabled?(:data_transfer_monitoring, project.group)
+
+ results = if Feature.enabled?(:data_transfer_monitoring_mock_data, project.group)
+ ::DataTransfer::MockedTransferFinder.new.execute
+ else
+ ::DataTransfer::ProjectDataTransferFinder.new(
+ project: project,
+ from: args[:from],
+ to: args[:to],
+ user: current_user
+ ).execute
+ end
+
+ { egress_nodes: results }
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/data_transfer_resolver.rb b/app/graphql/resolvers/data_transfer_resolver.rb
deleted file mode 100644
index ed97de0a256..00000000000
--- a/app/graphql/resolvers/data_transfer_resolver.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
- class DataTransferResolver < BaseResolver
- argument :from, Types::DateType,
- description: 'Retain egress data for 1 year. Current month will increase dynamically as egress occurs.',
- required: false
- argument :to, Types::DateType,
- description: 'End date for the data.',
- required: false
-
- type ::Types::DataTransfer::BaseType, null: false
-
- def self.source
- raise NotImplementedError
- end
-
- def self.project
- Class.new(self) do
- type Types::DataTransfer::ProjectDataTransferType, null: false
-
- def self.source
- "Project"
- end
- end
- end
-
- def self.group
- Class.new(self) do
- type Types::DataTransfer::GroupDataTransferType, null: false
-
- def self.source
- "Group"
- end
- end
- end
-
- def resolve(**_args)
- return unless Feature.enabled?(:data_transfer_monitoring)
-
- # TODO: This is mock data as this feature is in development
- # Follow this epic for recent progress: https://gitlab.com/groups/gitlab-org/-/epics/9330
- start_date = Date.new(2023, 0o1, 0o1)
- date_for_index = ->(i) { (start_date + i.months).strftime('%Y-%m-%d') }
-
- nodes = 0.upto(11).map do |i|
- {
- date: date_for_index.call(i),
- repository_egress: rand(70000..550000),
- artifacts_egress: rand(70000..550000),
- packages_egress: rand(70000..550000),
- registry_egress: rand(70000..550000)
- }
- end
-
- { egress_nodes: nodes }
- end
- end
-end
diff --git a/app/graphql/resolvers/design_management/version_resolver.rb b/app/graphql/resolvers/design_management/version_resolver.rb
index 7895981d67c..0d2479ded40 100644
--- a/app/graphql/resolvers/design_management/version_resolver.rb
+++ b/app/graphql/resolvers/design_management/version_resolver.rb
@@ -16,10 +16,6 @@ module Resolvers
def resolve(id:)
authorized_find!(id: id)
end
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/resolvers/notes/synthetic_note_resolver.rb b/app/graphql/resolvers/notes/synthetic_note_resolver.rb
index d4eafcd2c49..619f54d80b4 100644
--- a/app/graphql/resolvers/notes/synthetic_note_resolver.rb
+++ b/app/graphql/resolvers/notes/synthetic_note_resolver.rb
@@ -26,10 +26,6 @@ module Resolvers
synthetic_notes.find { |note| note.discussion_id == sha }
end
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
end
diff --git a/app/graphql/resolvers/work_item_resolver.rb b/app/graphql/resolvers/work_item_resolver.rb
index b174a0d2693..34e2f329efd 100644
--- a/app/graphql/resolvers/work_item_resolver.rb
+++ b/app/graphql/resolvers/work_item_resolver.rb
@@ -13,11 +13,5 @@ module Resolvers
def resolve(id:)
authorized_find!(id: id)
end
-
- private
-
- def find_object(id:)
- GitlabSchema.find_by_gid(id)
- end
end
end
diff --git a/app/graphql/types/data_transfer/base_type.rb b/app/graphql/types/data_transfer/base_type.rb
index e077612bfd5..5031bd5c612 100644
--- a/app/graphql/types/data_transfer/base_type.rb
+++ b/app/graphql/types/data_transfer/base_type.rb
@@ -7,7 +7,7 @@ module Types
field :egress_nodes, type: Types::DataTransfer::EgressNodeType.connection_type,
description: 'Data nodes.',
- null: true # disallow null once data_transfer_monitoring feature flag is rolled-out!
+ null: true # disallow null once data_transfer_monitoring feature flag is rolled-out! https://gitlab.com/gitlab-org/gitlab/-/issues/397693
end
end
end
diff --git a/app/graphql/types/data_transfer/egress_node_type.rb b/app/graphql/types/data_transfer/egress_node_type.rb
index a050540999f..f0ad3d15b53 100644
--- a/app/graphql/types/data_transfer/egress_node_type.rb
+++ b/app/graphql/types/data_transfer/egress_node_type.rb
@@ -26,12 +26,8 @@ module Types
null: false
field :registry_egress, GraphQL::Types::BigInt,
- description: 'Registery egress for that project in that period of time.',
+ description: 'Registry egress for that project in that period of time.',
null: false
-
- def total_egress
- object.values.select { |x| x.is_a?(Integer) }.sum
- end
end
end
end
diff --git a/app/graphql/types/data_transfer/project_data_transfer_type.rb b/app/graphql/types/data_transfer/project_data_transfer_type.rb
index f385aa20a7e..36afa20194e 100644
--- a/app/graphql/types/data_transfer/project_data_transfer_type.rb
+++ b/app/graphql/types/data_transfer/project_data_transfer_type.rb
@@ -8,12 +8,14 @@ module Types
field :total_egress, GraphQL::Types::BigInt,
description: 'Total egress for that project in that period of time.',
- null: true # disallow null once data_transfer_monitoring feature flag is rolled-out!
+ null: true, # disallow null once data_transfer_monitoring feature flag is rolled-out! https://gitlab.com/gitlab-org/gitlab/-/issues/397693
+ extras: [:parent]
- def total_egress(**_)
- return unless Feature.enabled?(:data_transfer_monitoring)
+ def total_egress(parent:)
+ return unless Feature.enabled?(:data_transfer_monitoring, parent.group)
+ return 40_000_000 if Feature.enabled?(:data_transfer_monitoring_mock_data, parent.group)
- 40_000_000
+ object[:egress_nodes].sum('repository_egress + artifacts_egress + packages_egress + registry_egress')
end
end
end
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 3543ac29c17..d352d82a52e 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -241,7 +241,7 @@ module Types
field :data_transfer, Types::DataTransfer::GroupDataTransferType,
null: true,
- resolver: Resolvers::DataTransferResolver.group,
+ resolver: Resolvers::DataTransfer::GroupDataTransferResolver,
description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.'
def label(title:)
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 4ca2bc8b1b5..a67ead051c2 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -567,8 +567,8 @@ module Types
description: "Find runners visible to the current user."
field :data_transfer, Types::DataTransfer::ProjectDataTransferType,
- null: true, # disallow null once data_transfer_monitoring feature flag is rolled-out!
- resolver: Resolvers::DataTransferResolver.project,
+ null: true, # disallow null once data_transfer_monitoring feature flag is rolled-out! https://gitlab.com/gitlab-org/gitlab/-/issues/391682
+ resolver: Resolvers::DataTransfer::ProjectDataTransferResolver,
description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.'
field :visible_forks, Types::ProjectType.connection_type,
diff --git a/app/helpers/abuse_reports_helper.rb b/app/helpers/abuse_reports_helper.rb
new file mode 100644
index 00000000000..c18c78b26c7
--- /dev/null
+++ b/app/helpers/abuse_reports_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module AbuseReportsHelper
+ def valid_image_mimetypes
+ Gitlab::FileTypeDetection::SAFE_IMAGE_EXT
+ .map { |extension| "image/#{extension}" }
+ .to_sentence(last_word_connector: ' or ')
+ end
+end
diff --git a/app/helpers/admin/background_migrations_helper.rb b/app/helpers/admin/background_migrations_helper.rb
index 79bb13810bb..cea9cd704c3 100644
--- a/app/helpers/admin/background_migrations_helper.rb
+++ b/app/helpers/admin/background_migrations_helper.rb
@@ -5,6 +5,7 @@ module Admin
def batched_migration_status_badge_variant(migration)
variants = {
active: :info,
+ finalizing: :info,
paused: :warning,
failed: :danger,
finished: :success
diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb
index 5ae5367ca5a..716738e87c9 100644
--- a/app/models/abuse_report.rb
+++ b/app/models/abuse_report.rb
@@ -3,8 +3,11 @@
class AbuseReport < ApplicationRecord
include CacheMarkdownField
include Sortable
+ include Gitlab::FileTypeDetection
+ include WithUploads
MAX_CHAR_LIMIT_URL = 512
+ MAX_FILE_SIZE = 1.megabyte
cache_markdown_field :message, pipeline: :single_line
@@ -42,6 +45,10 @@ class AbuseReport < ApplicationRecord
before_validation :filter_empty_strings_from_links_to_spam
validate :links_to_spam_contains_valid_urls
+ mount_uploader :screenshot, AttachmentUploader
+ validates :screenshot, file_size: { maximum: MAX_FILE_SIZE }
+ validate :validate_screenshot_is_image
+
scope :by_user_id, ->(id) { where(user_id: id) }
scope :by_reporter_id, ->(id) { where(reporter_id: id) }
scope :by_category, ->(category) { where(category: category) }
@@ -84,6 +91,20 @@ class AbuseReport < ApplicationRecord
AbuseReportMailer.notify(id).deliver_later
end
+ def screenshot_path
+ return unless screenshot
+ return screenshot.url unless screenshot.upload
+
+ asset_host = ActionController::Base.asset_host || Gitlab.config.gitlab.base_url
+ local_path = Gitlab::Routing.url_helpers.abuse_report_upload_path(
+ filename: screenshot.filename,
+ id: screenshot.upload.model_id,
+ model: 'abuse_report',
+ mounted_as: 'screenshot')
+
+ Gitlab::Utils.append_path(asset_host, local_path)
+ end
+
private
def filter_empty_strings_from_links_to_spam
@@ -113,4 +134,24 @@ class AbuseReport < ApplicationRecord
rescue ::Gitlab::UrlBlocker::BlockedUrlError
errors.add(:links_to_spam, _('only supports valid HTTP(S) URLs'))
end
+
+ def filename
+ screenshot&.filename
+ end
+
+ def valid_image_extensions
+ Gitlab::FileTypeDetection::SAFE_IMAGE_EXT
+ end
+
+ def validate_screenshot_is_image
+ return if screenshot.blank?
+ return if image?
+
+ errors.add(
+ :screenshot,
+ format(
+ _('must match one of the following file types: %{extension_list}'),
+ extension_list: valid_image_extensions.to_sentence(last_word_connector: ' or '))
+ )
+ end
end
diff --git a/app/models/pages_deployment.rb b/app/models/pages_deployment.rb
index 125a86c68f6..fa29cbf8352 100644
--- a/app/models/pages_deployment.rb
+++ b/app/models/pages_deployment.rb
@@ -37,7 +37,7 @@ class PagesDeployment < ApplicationRecord
end
def store_after_commit?
- Feature.enabled?(:pages_deploy_upload_file_outside_transaction)
+ Feature.enabled?(:pages_deploy_upload_file_outside_transaction, project)
end
strong_memoize_attr :store_after_commit?
diff --git a/app/models/projects/data_transfer.rb b/app/models/projects/data_transfer.rb
index faab0bb6db2..c7f5132fbc7 100644
--- a/app/models/projects/data_transfer.rb
+++ b/app/models/projects/data_transfer.rb
@@ -13,6 +13,14 @@ module Projects
belongs_to :namespace
scope :current_month, -> { where(date: beginning_of_month) }
+ scope :with_project_between_dates, ->(project, from, to) {
+ where(project: project, date: from..to)
+ }
+ scope :with_namespace_between_dates, ->(namespace, from, to) {
+ where(namespace: namespace, date: from..to)
+ .group(:date, :namespace_id)
+ .order(date: :desc)
+ }
counter_attribute :repository_egress, returns_current: true
counter_attribute :artifacts_egress, returns_current: true
diff --git a/app/views/abuse_reports/new.html.haml b/app/views/abuse_reports/new.html.haml
index 8b9bbfd0a59..39b8fe26c7b 100644
--- a/app/views/abuse_reports/new.html.haml
+++ b/app/views/abuse_reports/new.html.haml
@@ -26,6 +26,17 @@
= f.label :reported_from
= f.text_field :reported_from_url, class: "form-control", readonly: true
#js-links-to-spam{ data: { links: Array(@abuse_report.links_to_spam) } }
+
+ .form-group.row
+ .col-lg-8
+ = f.label :screenshot do
+ %span
+ = s_('ReportAbuse|Screenshot')
+ .gl-font-weight-normal
+ = s_('ReportAbuse|Screenshot of abuse')
+ %div
+ = render 'shared/file_picker_button', f: f, field: :screenshot, help_text: _("Screenshot must be less than 1 MB."), mime_types: valid_image_mimetypes
+
.form-group.row
.col-lg-8
= f.label :reason
diff --git a/app/views/admin/background_migrations/index.html.haml b/app/views/admin/background_migrations/index.html.haml
index 00859bf6b66..9550ea2884e 100644
--- a/app/views/admin/background_migrations/index.html.haml
+++ b/app/views/admin/background_migrations/index.html.haml
@@ -17,6 +17,9 @@
= gl_tab_link_to admin_background_migrations_path({ tab: nil, database: params[:database] }), item_active: @current_tab == 'queued' do
= _('Queued')
= gl_tab_counter_badge limited_counter_with_delimiter(@relations_by_tab['queued'])
+ = gl_tab_link_to admin_background_migrations_path({ tab: 'finalizing', database: params[:database] }), item_active: @current_tab == 'finalizing' do
+ = _('Finalizing')
+ = gl_tab_counter_badge limited_counter_with_delimiter(@relations_by_tab['finalizing'])
= gl_tab_link_to admin_background_migrations_path({ tab: 'failed', database: params[:database] }), item_active: @current_tab == 'failed' do
= _('Failed')
= gl_tab_counter_badge limited_counter_with_delimiter(@relations_by_tab['failed'])
diff --git a/app/views/shared/_file_picker_button.html.haml b/app/views/shared/_file_picker_button.html.haml
index 8d76e9c1b7d..beb564f7c7c 100644
--- a/app/views/shared/_file_picker_button.html.haml
+++ b/app/views/shared/_file_picker_button.html.haml
@@ -1,9 +1,10 @@
- classes = local_assigns.fetch(:classes, '')
+- mime_types = local_assigns.fetch(:mime_types, '')
%span.js-filepicker
= render Pajamas::ButtonComponent.new(button_options: { class: "js-filepicker-button #{classes}" }) do
= _("Choose file…")
- %span.file_name.js-filepicker-filename= _("No file chosen.")
- = f.file_field field, class: "js-filepicker-input hidden"
+ %span.file_name.gl-ml-3.js-filepicker-filename= _("No file chosen.")
+ = f.file_field field, class: "js-filepicker-input hidden", accept: mime_types
- if help_text.present?
.form-text.text-muted= help_text
diff --git a/app/views/shared/hook_logs/_index.html.haml b/app/views/shared/hook_logs/_index.html.haml
index 6a46b0b3510..7dab14b95c1 100644
--- a/app/views/shared/hook_logs/_index.html.haml
+++ b/app/views/shared/hook_logs/_index.html.haml
@@ -1,4 +1,4 @@
-- docs_link_url = help_page_path('user/project/integrations/webhooks', anchor: 'troubleshoot-webhooks')
+- docs_link_url = help_page_path('user/project/integrations/webhooks', anchor: 'troubleshooting')
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: docs_link_url }
- link_end = '</a>'.html_safe
diff --git a/app/views/shared/web_hooks/_web_hook_disabled_alert.html.haml b/app/views/shared/web_hooks/_web_hook_disabled_alert.html.haml
index d9155b397b8..f8e2dc3d8dd 100644
--- a/app/views/shared/web_hooks/_web_hook_disabled_alert.html.haml
+++ b/app/views/shared/web_hooks/_web_hook_disabled_alert.html.haml
@@ -8,6 +8,6 @@
= c.body do
= s_('Webhooks|A webhook in this project was automatically disabled after being retried multiple times.')
= succeed '.' do
- = link_to _('Learn more'), help_page_path('user/project/integrations/webhooks', anchor: 'troubleshoot-webhooks'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('Learn more'), help_page_path('user/project/integrations/webhooks', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer'
= c.actions do
= link_to s_('Webhooks|Go to webhooks'), project_hooks_path(@project, anchor: 'webhooks-index'), class: 'btn gl-alert-action btn-confirm gl-button'
diff --git a/config/feature_flags/development/codeowners_default_owners.yml b/config/feature_flags/development/data_transfer_monitoring_mock_data.yml
index df8c24ed689..77a43426e74 100644
--- a/config/feature_flags/development/codeowners_default_owners.yml
+++ b/config/feature_flags/development/data_transfer_monitoring_mock_data.yml
@@ -1,7 +1,7 @@
---
-name: codeowners_default_owners
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113594
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/394811
+name: data_transfer_monitoring_mock_data
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113392
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/397693
milestone: '15.11'
type: development
group: group::source code
diff --git a/config/metrics/counts_28d/20210216174910_analytics_unique_visits_for_any_target_monthly.yml b/config/metrics/counts_28d/20210216174910_analytics_unique_visits_for_any_target_monthly.yml
index df64125b058..6acbd280138 100644
--- a/config/metrics/counts_28d/20210216174910_analytics_unique_visits_for_any_target_monthly.yml
+++ b/config/metrics/counts_28d/20210216174910_analytics_unique_visits_for_any_target_monthly.yml
@@ -43,6 +43,7 @@ options:
- g_analytics_ci_cd_lead_time
- g_analytics_ci_cd_time_to_restore_service
- g_analytics_ci_cd_change_failure_rate
+ - g_metrics_comparison_page
distribution:
- ce
- ee
diff --git a/config/metrics/counts_7d/20210216174908_analytics_unique_visits_for_any_target.yml b/config/metrics/counts_7d/20210216174908_analytics_unique_visits_for_any_target.yml
index 424552f54e4..a087a329cce 100644
--- a/config/metrics/counts_7d/20210216174908_analytics_unique_visits_for_any_target.yml
+++ b/config/metrics/counts_7d/20210216174908_analytics_unique_visits_for_any_target.yml
@@ -36,6 +36,7 @@ options:
- p_analytics_ci_cd_pipelines
- p_analytics_ci_cd_deployment_frequency
- p_analytics_ci_cd_lead_time
+ - g_metrics_comparison_page
distribution:
- ce
- ee
diff --git a/config/routes/uploads.rb b/config/routes/uploads.rb
index 52c67a705dc..e65a4805a20 100644
--- a/config/routes/uploads.rb
+++ b/config/routes/uploads.rb
@@ -37,6 +37,12 @@ scope path: :uploads do
to: "uploads#show",
constraints: { model: /alert_management_metric_image/, mounted_as: /file/, filename: %r{[^/]+} },
as: 'alert_metric_image_upload'
+
+ # Abuse Reports Images
+ get "-/system/:model/:mounted_as/:id/:filename",
+ to: "uploads#show",
+ constraints: { model: /abuse_report/, mounted_as: /screenshot/, filename: %r{[^/]+} },
+ as: 'abuse_report_upload'
end
# Redirect old note attachments path to new uploads path.
diff --git a/data/deprecations/15-8-jira-connect-app-cookie-auth.yml b/data/deprecations/15-8-jira-connect-app-cookie-auth.yml
index a9fe6e727ea..ac25d06859c 100644
--- a/data/deprecations/15-8-jira-connect-app-cookie-auth.yml
+++ b/data/deprecations/15-8-jira-connect-app-cookie-auth.yml
@@ -7,6 +7,6 @@
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/387299 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
Cookie authentication in the GitLab for Jira Cloud app is now deprecated in favor of OAuth authentication.
- You must [set up OAuth authentication](https://docs.gitlab.com/ee/integration/jira/connect-app.html#set-up-oauth-authentication)
- to continue to use the GitLab for Jira Cloud app. Without OAuth, you will not be able to manage linked namespaces.
+ On self-managed, you must [set up OAuth authentication](https://docs.gitlab.com/ee/integration/jira/connect-app.html#set-up-oauth-authentication-for-self-managed-instances)
+ to continue to use the GitLab for Jira Cloud app. Without OAuth, you can't manage linked namespaces.
tiers: [Core, Premium, Ultimate] # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
diff --git a/db/migrate/20230315053635_add_screenshot_to_abuse_reports.rb b/db/migrate/20230315053635_add_screenshot_to_abuse_reports.rb
new file mode 100644
index 00000000000..421878967c4
--- /dev/null
+++ b/db/migrate/20230315053635_add_screenshot_to_abuse_reports.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddScreenshotToAbuseReports < Gitlab::Database::Migration[2.1]
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20230327074932_add_text_limit_to_abuse_reports_screenshot
+ def change
+ add_column :abuse_reports, :screenshot, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20230321161218_add_project_access_token_limit_to_plan_limits.rb b/db/migrate/20230321161218_add_project_access_token_limit_to_plan_limits.rb
new file mode 100644
index 00000000000..5f9400b9498
--- /dev/null
+++ b/db/migrate/20230321161218_add_project_access_token_limit_to_plan_limits.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddProjectAccessTokenLimitToPlanLimits < Gitlab::Database::Migration[2.1]
+ def change
+ add_column(:plan_limits, :project_access_token_limit, :integer, default: 0, null: false)
+ end
+end
diff --git a/db/migrate/20230321161441_insert_project_access_token_limit.rb b/db/migrate/20230321161441_insert_project_access_token_limit.rb
new file mode 100644
index 00000000000..a449e6f8e7c
--- /dev/null
+++ b/db/migrate/20230321161441_insert_project_access_token_limit.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class InsertProjectAccessTokenLimit < Gitlab::Database::Migration[2.1]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ create_or_update_plan_limit('project_access_token_limit', 'premium_trial', 1)
+ create_or_update_plan_limit('project_access_token_limit', 'ultimate_trial', 1)
+ end
+
+ def down
+ create_or_update_plan_limit('project_access_token_limit', 'premium_trial', 0)
+ create_or_update_plan_limit('project_access_token_limit', 'ultimate_trial', 0)
+ end
+end
diff --git a/db/migrate/20230322151605_rerun_remove_invalid_deploy_access_level.rb b/db/migrate/20230322151605_rerun_remove_invalid_deploy_access_level.rb
new file mode 100644
index 00000000000..e140ecc58c7
--- /dev/null
+++ b/db/migrate/20230322151605_rerun_remove_invalid_deploy_access_level.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class RerunRemoveInvalidDeployAccessLevel < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ # clean up any rows with invalid access_level entries
+ def up
+ update_column_in_batches(:protected_environment_deploy_access_levels, :access_level, nil) do |table, query|
+ query.where(
+ table.grouping(table[:user_id].not_eq(nil).or(table[:group_id].not_eq(nil)))
+ .and(table[:access_level].not_eq(nil)))
+ end
+
+ update_column_in_batches(:protected_environment_deploy_access_levels, :group_id, nil) do |table, query|
+ query.where(table[:user_id].not_eq(nil).and(table[:group_id].not_eq(nil)))
+ end
+ end
+
+ def down
+ # no-op
+
+ # we are setting access_level to NULL if group_id or user_id are present
+ end
+end
diff --git a/db/migrate/20230327074932_add_text_limit_to_abuse_reports_screenshot.rb b/db/migrate/20230327074932_add_text_limit_to_abuse_reports_screenshot.rb
new file mode 100644
index 00000000000..3bb9722188f
--- /dev/null
+++ b/db/migrate/20230327074932_add_text_limit_to_abuse_reports_screenshot.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddTextLimitToAbuseReportsScreenshot < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :abuse_reports, :screenshot, 255
+ end
+
+ def down
+ remove_text_limit :abuse_reports, :screenshot
+ end
+end
diff --git a/db/post_migrate/20230131194959_remove_invalid_deploy_access_level.rb b/db/post_migrate/20230131194959_remove_invalid_deploy_access_level.rb
index 57364e2200b..13e49ca087d 100644
--- a/db/post_migrate/20230131194959_remove_invalid_deploy_access_level.rb
+++ b/db/post_migrate/20230131194959_remove_invalid_deploy_access_level.rb
@@ -3,20 +3,11 @@
class RemoveInvalidDeployAccessLevel < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
- restrict_gitlab_migration gitlab_schema: :gitlab_main
-
- # clean up any rows with invalid access_level entries
def up
- update_column_in_batches(:protected_environment_deploy_access_levels, :access_level, nil) do |table, query|
- query.where(
- table.grouping(table[:user_id].not_eq(nil).or(table[:group_id].not_eq(nil)))
- .and(table[:access_level].not_eq(nil)))
- end
+ # no-op, moved to 20230322151605_rerun_remove_invalid_deploy_access_level.rb
end
def down
# no-op
-
- # we are setting access_level to NULL if group_id or user_id are present
end
end
diff --git a/db/post_migrate/20230313031629_ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb b/db/post_migrate/20230313031629_ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb
new file mode 100644
index 00000000000..d651ca463af
--- /dev/null
+++ b/db/post_migrate/20230313031629_ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class EnsureCommitUserMentionsNoteIdBigintBackfillIsFinishedForGitlabDotCom < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ return unless should_run?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'commit_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ )
+ end
+
+ def down
+ # no-op
+ end
+
+ private
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/post_migrate/20230319105436_remove_member_role_download_code.rb b/db/post_migrate/20230319105436_remove_member_role_download_code.rb
new file mode 100644
index 00000000000..34921b8d806
--- /dev/null
+++ b/db/post_migrate/20230319105436_remove_member_role_download_code.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class RemoveMemberRoleDownloadCode < Gitlab::Database::Migration[2.1]
+ def change
+ remove_column :member_roles, :download_code, :boolean, default: false
+ end
+end
diff --git a/db/post_migrate/20230321003252_swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com.rb b/db/post_migrate/20230321003252_swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com.rb
new file mode 100644
index 00000000000..6b75ca44cc2
--- /dev/null
+++ b/db/post_migrate/20230321003252_swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+class SwapCommitUserMentionsNoteIdToBigintForGitlabDotCom < Gitlab::Database::Migration[2.1]
+ include Gitlab::Database::MigrationHelpers::ConvertToBigint
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'commit_user_mentions'
+
+ def up
+ return unless should_run?
+
+ swap
+ end
+
+ def down
+ return unless should_run?
+
+ swap
+ end
+
+ def swap
+ # This will replace the existing commit_user_mentions_on_commit_id_and_note_id_unique_index
+ add_concurrent_index TABLE_NAME, [:commit_id, :note_id_convert_to_bigint], unique: true,
+ name: 'commit_user_mentions_on_commit_id_and_note_id_convert_to_bigint'
+
+ # This will replace the existing index_commit_user_mentions_on_note_id
+ add_concurrent_index TABLE_NAME, :note_id_convert_to_bigint, unique: true,
+ name: 'index_commit_user_mentions_on_note_id_convert_to_bigint'
+
+ # This will replace the existing fk_rails_a6760813e0
+ add_concurrent_foreign_key TABLE_NAME, :notes, column: :note_id_convert_to_bigint,
+ name: 'fk_commit_user_mentions_note_id_convert_to_bigint',
+ on_delete: :cascade
+
+ with_lock_retries(raise_on_exhaustion: true) do
+ execute "LOCK TABLE notes, #{TABLE_NAME} IN ACCESS EXCLUSIVE MODE"
+
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id TO note_id_tmp"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_convert_to_bigint TO note_id"
+ execute "ALTER TABLE #{TABLE_NAME} RENAME COLUMN note_id_tmp TO note_id_convert_to_bigint"
+
+ function_name = Gitlab::Database::UnidirectionalCopyTrigger
+ .on_table(TABLE_NAME, connection: connection)
+ .name(:note_id, :note_id_convert_to_bigint)
+ execute "ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL"
+
+ # Swap defaults
+ change_column_default TABLE_NAME, :note_id, nil
+ change_column_default TABLE_NAME, :note_id_convert_to_bigint, 0
+
+ execute 'DROP INDEX IF EXISTS commit_user_mentions_on_commit_id_and_note_id_unique_index'
+ rename_index TABLE_NAME, 'commit_user_mentions_on_commit_id_and_note_id_convert_to_bigint',
+ 'commit_user_mentions_on_commit_id_and_note_id_unique_index'
+
+ execute 'DROP INDEX IF EXISTS index_commit_user_mentions_on_note_id'
+ rename_index TABLE_NAME, 'index_commit_user_mentions_on_note_id_convert_to_bigint',
+ 'index_commit_user_mentions_on_note_id'
+
+ execute "ALTER TABLE #{TABLE_NAME} DROP CONSTRAINT IF EXISTS fk_rails_a6760813e0"
+ rename_constraint(TABLE_NAME, 'fk_commit_user_mentions_note_id_convert_to_bigint', 'fk_rails_a6760813e0')
+ end
+ end
+
+ def should_run?
+ com_or_dev_or_test_but_not_jh?
+ end
+end
diff --git a/db/schema_migrations/20230313031629 b/db/schema_migrations/20230313031629
new file mode 100644
index 00000000000..c7a27b58cff
--- /dev/null
+++ b/db/schema_migrations/20230313031629
@@ -0,0 +1 @@
+86ffe1f3b8048cf01b96f66683fa68f889051c8633c6b803ffdb03aa0a8d2864 \ No newline at end of file
diff --git a/db/schema_migrations/20230315053635 b/db/schema_migrations/20230315053635
new file mode 100644
index 00000000000..751f52c2ccd
--- /dev/null
+++ b/db/schema_migrations/20230315053635
@@ -0,0 +1 @@
+aedea3dd398210eb2d98a3ecefe3b02b518bce53d63d75160796eb0414574087 \ No newline at end of file
diff --git a/db/schema_migrations/20230319105436 b/db/schema_migrations/20230319105436
new file mode 100644
index 00000000000..47338a038b1
--- /dev/null
+++ b/db/schema_migrations/20230319105436
@@ -0,0 +1 @@
+198cf0597e4a513c6c47b9cd576765d40f564838d5c54e33216fd7a5d25220ae \ No newline at end of file
diff --git a/db/schema_migrations/20230321003252 b/db/schema_migrations/20230321003252
new file mode 100644
index 00000000000..85515872922
--- /dev/null
+++ b/db/schema_migrations/20230321003252
@@ -0,0 +1 @@
+82c5c661c3fad14a0466e5669b59dca92084b8c77500d8ae3b97b34029277c94 \ No newline at end of file
diff --git a/db/schema_migrations/20230321161218 b/db/schema_migrations/20230321161218
new file mode 100644
index 00000000000..57365b47898
--- /dev/null
+++ b/db/schema_migrations/20230321161218
@@ -0,0 +1 @@
+efbe3f66fecfb275f8b4276cedc2210a141f4c63cc10242daafb445b352a4b70 \ No newline at end of file
diff --git a/db/schema_migrations/20230321161441 b/db/schema_migrations/20230321161441
new file mode 100644
index 00000000000..fe0b5fbeee4
--- /dev/null
+++ b/db/schema_migrations/20230321161441
@@ -0,0 +1 @@
+7e3a9281e624341301d937d2422f0ff2d71367bfb42bf45ddcde7216e84ecb93 \ No newline at end of file
diff --git a/db/schema_migrations/20230322151605 b/db/schema_migrations/20230322151605
new file mode 100644
index 00000000000..cb47c2629a8
--- /dev/null
+++ b/db/schema_migrations/20230322151605
@@ -0,0 +1 @@
+5300b4b70078fe3dadbdf42e7884dee84794c0de5b32c26b6ec46622b2a433c4 \ No newline at end of file
diff --git a/db/schema_migrations/20230327074932 b/db/schema_migrations/20230327074932
new file mode 100644
index 00000000000..7093e3aa4bf
--- /dev/null
+++ b/db/schema_migrations/20230327074932
@@ -0,0 +1 @@
+48f6ba4288122f400a0a2ef53a679cf6b4e9dc3052ec64e959066f6e30b3cd3a \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index c471cd3068a..d78ccaccda1 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -10745,7 +10745,9 @@ CREATE TABLE abuse_reports (
links_to_spam text[] DEFAULT '{}'::text[] NOT NULL,
status smallint DEFAULT 1 NOT NULL,
resolved_at timestamp with time zone,
+ screenshot text,
CONSTRAINT abuse_reports_links_to_spam_length_check CHECK ((cardinality(links_to_spam) <= 20)),
+ CONSTRAINT check_4b0a5120e0 CHECK ((char_length(screenshot) <= 255)),
CONSTRAINT check_ab1260fa6c CHECK ((char_length(reported_from_url) <= 512))
);
@@ -14462,12 +14464,12 @@ ALTER SEQUENCE clusters_kubernetes_namespaces_id_seq OWNED BY clusters_kubernete
CREATE TABLE commit_user_mentions (
id bigint NOT NULL,
- note_id integer NOT NULL,
+ note_id_convert_to_bigint integer DEFAULT 0 NOT NULL,
mentioned_users_ids integer[],
mentioned_projects_ids integer[],
mentioned_groups_ids integer[],
commit_id character varying NOT NULL,
- note_id_convert_to_bigint bigint DEFAULT 0 NOT NULL
+ note_id bigint NOT NULL
);
CREATE SEQUENCE commit_user_mentions_id_seq
@@ -17824,7 +17826,6 @@ CREATE TABLE member_roles (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
base_access_level integer NOT NULL,
- download_code boolean DEFAULT false,
read_code boolean DEFAULT false
);
@@ -19987,7 +19988,8 @@ CREATE TABLE plan_limits (
enforcement_limit integer DEFAULT 0 NOT NULL,
notification_limit integer DEFAULT 0 NOT NULL,
dashboard_limit_enabled_at timestamp with time zone,
- web_hook_calls integer DEFAULT 0 NOT NULL
+ web_hook_calls integer DEFAULT 0 NOT NULL,
+ project_access_token_limit integer DEFAULT 0 NOT NULL
);
CREATE SEQUENCE plan_limits_id_seq
diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md
index e7066d2538b..f3d5acb312d 100644
--- a/doc/administration/server_hooks.md
+++ b/doc/administration/server_hooks.md
@@ -27,7 +27,43 @@ alternatives to server hooks include:
[Geo](geo/index.md) doesn't replicate server hooks to secondary nodes.
-## Create server hooks for a repository
+## Set server hooks for a repository
+
+::Tabs
+
+:::TabTitle GitLab 15.11 and later
+
+> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4629) in GitLab 15.11, `hooks set` command replaces direct file system access.
+
+Prerequisites:
+
+- The [storage name and relative path](repository_storage_types.md#from-project-name-to-hashed-path) for the repository.
+
+To set server hooks for a repository:
+
+1. Create tarball containing custom hooks:
+ 1. Write the code to make the server hook function as expected. Git server hooks can be in any programming language.
+ Ensure the [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) at the top reflects the language type. For
+ example, if the script is in Ruby the shebang is probably `#!/usr/bin/env ruby`.
+
+ - To create a single server hook, create a file with a name that matches the hook type. For example, for a
+ `pre-receive` server hook, the filename should be `pre-receive` with no extension.
+ - To create many server hooks, create a directory for the hooks that matches the hook type. For example, for a
+ `pre-receive` server hook, the directory name should be `pre-receive.d`. Put the files for the hook in that
+ directory.
+
+ 1. Ensure the server hook files are executable and do not match the backup file pattern (`*~`). The server hooks be
+ in a `custom_hooks` directory that is at the root of the tarball.
+ 1. Create the custom hooks archive with the tar command. For example, `tar -cf custom_hooks.tar custom_hooks`.
+1. Run the `hooks set` command with required options to set the Git hooks for the repository. For example,
+ `cat hooks.tar | gitaly hooks set --storage <storage> --repository <relative path> --config <config path>`.
+
+ - A path to a valid Gitaly configuration for the node is required to connect to the node and provided to the `--config` flag.
+ - Custom hooks tarball must be passed via `stdin`. For example, `cat hooks.tar | gitaly hooks set --storage <storage> --repository <relative path> --config <config path>`.
+
+If you implemented the server hook code correctly, it should execute when the Git hook is next triggered.
+
+:::TabTitle GitLab 15.10 and earlier
To create server hooks for a repository:
@@ -55,6 +91,8 @@ To create server hooks for a repository:
If the server hook code is properly implemented, it should execute when the Git hook is next triggered.
+::EndTabs
+
### Gitaly Cluster
If you use [Gitaly Cluster](gitaly/index.md), the scripts must be copied to every Gitaly node that has a replica of the repository. Every Gitaly node
@@ -112,6 +150,16 @@ To create a global server hook for all repositories:
If the server hook code is properly implemented, it should execute when the Git hook is next triggered. Hooks are executed in alphabetical order by filename in the hook type
subdirectories.
+## Remove server hooks for a repository using Gitaly CLI
+
+> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4629) in GitLab 15.11, `hooks set` command replaces direct file system access.
+
+To remove hooks using the Gitaly CLI, pass an empty tarball to `hook set` to indicate that the repository should contain no hooks. For example:
+
+```shell
+cat empty_hooks.tar | gitaly hooks set --storage <storage> --repository <relative path> --config <config path>`.
+```
+
## Chained server hooks
GitLab can execute server hooks in a chain. GitLab searches for and executes server hooks in the following order:
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a2d70dfaeef..126ba7f16e7 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -13355,7 +13355,7 @@ Returns [`[DoraMetric!]`](#dorametric).
| <a id="egressnodeartifactsegress"></a>`artifactsEgress` | [`BigInt!`](#bigint) | Artifacts egress for that project in that period of time. |
| <a id="egressnodedate"></a>`date` | [`String!`](#string) | First day of the node range. There is one node per month. |
| <a id="egressnodepackagesegress"></a>`packagesEgress` | [`BigInt!`](#bigint) | Packages egress for that project in that period of time. |
-| <a id="egressnoderegistryegress"></a>`registryEgress` | [`BigInt!`](#bigint) | Registery egress for that project in that period of time. |
+| <a id="egressnoderegistryegress"></a>`registryEgress` | [`BigInt!`](#bigint) | Registry egress for that project in that period of time. |
| <a id="egressnoderepositoryegress"></a>`repositoryEgress` | [`BigInt!`](#bigint) | Repository egress for that project in that period of time. |
| <a id="egressnodetotalegress"></a>`totalEgress` | [`BigInt!`](#bigint) | Total egress for that project in that period of time. |
@@ -14574,7 +14574,7 @@ Returns [`GroupDataTransfer`](#groupdatatransfer).
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="groupdatatransferfrom"></a>`from` | [`Date`](#date) | Retain egress data for 1 year. Current month will increase dynamically as egress occurs. |
+| <a id="groupdatatransferfrom"></a>`from` | [`Date`](#date) | Retain egress data for one year. Data for the current month will increase dynamically as egress occurs. |
| <a id="groupdatatransferto"></a>`to` | [`Date`](#date) | End date for the data. |
##### `Group.descendantGroups`
@@ -18604,7 +18604,7 @@ Returns [`ProjectDataTransfer`](#projectdatatransfer).
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="projectdatatransferfrom"></a>`from` | [`Date`](#date) | Retain egress data for 1 year. Current month will increase dynamically as egress occurs. |
+| <a id="projectdatatransferfrom"></a>`from` | [`Date`](#date) | Retain egress data for one year. Data for the current month will increase dynamically as egress occurs. |
| <a id="projectdatatransferto"></a>`to` | [`Date`](#date) | End date for the data. |
##### `Project.deployment`
diff --git a/doc/development/database/table_partitioning.md b/doc/development/database/table_partitioning.md
index 2ff7ee74f8d..a0a3139daa3 100644
--- a/doc/development/database/table_partitioning.md
+++ b/doc/development/database/table_partitioning.md
@@ -39,31 +39,38 @@ several releases. Due to the limitations of partitioning and the related
migrations, you should understand how partitioning fits your use case
before attempting to leverage this feature.
-## Determining when to use partitioning
+## Determine when to use partitioning
While partitioning can be very useful when properly applied, it's
imperative to identify if the data and workload of a table naturally fit a
-partitioning scheme. There are a few details you have to understand
-to decide if partitioning is a good fit for your particular
-problem.
-
-First, a table is partitioned on a partition key, which is a column or
-set of columns which determine how the data is split across the
-partitions. The partition key is used by the database when reading or
-writing data, to decide which partitions must be accessed. The
-partition key should be a column that would be included in a `WHERE`
-clause on almost all queries accessing that table.
-
-Second, it's necessary to understand the strategy the database uses
-to split the data across the partitions. The scheme supported by the
-GitLab migration helpers is date-range partitioning, where each partition
-in the table contains data for a single month. In this case, the partitioning
-key must be a timestamp or date column. In order for this type of
+partitioning scheme. Understand a few details to decide if partitioning
+is a good fit for your particular problem:
+
+- **Table partitioning**. A table is partitioned on a partition key, which is a
+ column or set of columns which determine how the data is split across the
+ partitions. The partition key is used by the database when reading or
+ writing data, to decide which partitions must be accessed. The
+ partition key should be a column that would be included in a `WHERE`
+ clause on almost all queries accessing that table.
+
+- **How the data is split**. What strategy does the database use
+ to split the data across the partitions? The available choices are `range`,
+ `hash`, and `list`.
+
+## Determine the appropriate partitioning strategy
+
+The available partitioning strategy choices are `range`, `hash`, and `list`.
+
+### Range partitioning
+
+The scheme best supported by the GitLab migration helpers is date-range partitioning,
+where each partition in the table contains data for a single month. In this case,
+the partitioning key must be a timestamp or date column. For this type of
partitioning to work well, most queries must access data in a
certain date range.
-For a more concrete example, the `audit_events` table can be used, which
-was the first table to be partitioned in the application database
+For a more concrete example, consider using the `audit_events` table.
+It was the first table to be partitioned in the application database
(scheduled for deployment with the GitLab 13.5 release). This
table tracks audit entries of security events that happen in the
application. In almost all cases, users want to see audit activity that
@@ -149,6 +156,31 @@ substantial. Partitioning should only be leveraged if the access patterns
of the data support the partitioning strategy, otherwise performance
suffers.
+### Hash Partitioning
+
+Hash partitioning splits a logical table into a series of partitioned
+tables. Each partition corresponds to the ID range that matches
+a hash and remainder. For example, if partitioning `BY HASH(id)`, rows
+with `hash(id) % 64 == 1` would end up in the partition
+`WITH (MODULUS 64, REMAINDER 1)`.
+
+When hash partitioning, you must include a `WHERE hashed_column = ?` condition in
+every performance-sensitive query issued by the application. If this is not possible,
+hash partitioning may not be the correct fit for your use case.
+
+Hash partitioning has one main advantage: it is the only type of partitioning that
+can enforce uniqueness on a single numeric `id` column. (While also possible with
+range partitioning, it's rarely the correct choice).
+
+Hash partitioning has downsides:
+
+- The number of partitions must be known up-front.
+- It's difficult to move new data to an extra partition if current partitions become too large.
+- Range queries, such as `WHERE id BETWEEN ? and ?`, are unsupported.
+- Lookups by other keys, such as `WHERE other_id = ?`, are unsupported.
+
+For this reason, it's often best to choose a large number of hash partitions to accommodate future table growth.
+
## Partitioning a table (Range)
Unfortunately, tables can only be partitioned at their creation, making
@@ -264,6 +296,18 @@ for use by the application. This section will be updated when the
migration helper is ready, for now development can be followed in the
[Tracking Issue](https://gitlab.com/gitlab-org/gitlab/-/issues/241267).
+## Partitioning a table (Hash)
+
+Hash partitioning divides data into partitions based on a hash of their ID.
+It works well only if most queries against the table include a clause like `WHERE id = ?`,
+so that PostgreSQL can decide which partition to look in based on the ID or ids being requested.
+
+Another key downside is that hash partitioning does not allow adding additional partitions after table creation.
+The correct number of partitions must be chosen up-front.
+
+Hash partitioning is the only type of partitioning (aside from some complex uses of list partitioning) that can guarantee
+uniqueness of an ID across multiple partitions at the database level.
+
## Partitioning a table (List)
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96815) in GitLab 15.4.
diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md
index 668038ef386..d24cdc983bc 100644
--- a/doc/integration/jenkins.md
+++ b/doc/integration/jenkins.md
@@ -190,26 +190,21 @@ This issue can occur when the request exceeds the
[webhook timeout](../user/project/integrations/webhooks.md#webhook-fails-or-multiple-webhook-requests-are-triggered),
which is set to 10 seconds by default.
-Check the [service hook logs](../user/project/integrations/index.md#troubleshooting-integrations)
-for request failures or check the `/var/log/gitlab/gitlab-rails/production.log`
-file for messages like:
+For this issue, check:
-```plaintext
-WebHook Error => Net::ReadTimeout
-```
+- [Integration webhook logs](../user/project/integrations/index.md#troubleshooting)
+for request failures.
+- `/var/log/gitlab/gitlab-rails/production.log` for messages like:
-or
+ ```plaintext
+ WebHook Error => Net::ReadTimeout
+ ```
-```plaintext
-WebHook Error => execution expired
-```
+ or
-Or check for duplicate messages in `/var/log/gitlab/gitlab-rail`, like:
-
-```plaintext
-2019-10-25_04:22:41.25630 2019-10-25T04:22:41.256Z 1584 TID-ovowh4tek WebHookWorker JID-941fb7f40b69dff3d833c99b INFO: start
-2019-10-25_04:22:41.25630 2019-10-25T04:22:41.256Z 1584 TID-ovowh4tek WebHookWorker JID-941fb7f40b69dff3d833c99b INFO: start
-```
+ ```plaintext
+ WebHook Error => execution expired
+ ```
On self-managed GitLab instances, you can fix this issue by [increasing the webhook timeout value](../administration/instance_limits.md#webhook-timeout).
diff --git a/doc/integration/jira/connect-app.md b/doc/integration/jira/connect-app.md
index 8bbac021849..c39f8275786 100644
--- a/doc/integration/jira/connect-app.md
+++ b/doc/integration/jira/connect-app.md
@@ -6,9 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab for Jira Cloud app **(FREE)**
-You can integrate GitLab and Jira Cloud using the
-[GitLab for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud)
-app in the Atlassian Marketplace.
+With the [GitLab for Jira Cloud](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud) app,
+you can integrate GitLab and Jira Cloud.
Only Jira users with administrator access can install or configure
the GitLab for Jira Cloud app.
@@ -18,7 +17,7 @@ the GitLab for Jira Cloud app.
If you use GitLab.com and Jira Cloud, you can install the GitLab for Jira Cloud app.
If you do not use both of these environments, use the [Jira DVCS Connector](dvcs/index.md) or
[install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually).
-We recommend the GitLab for Jira Cloud app, because data is
+You should use the GitLab for Jira Cloud app because data is
synchronized in real time. The DVCS connector updates data only once per hour.
To configure the GitLab for Jira Cloud app, you must have
@@ -61,9 +60,9 @@ After a namespace is added:
- All future commits, branches, and merge requests of all projects under that namespace
are synced to Jira.
-- From GitLab 13.8, past merge request data is synced to Jira.
+- In GitLab 13.8 and later, past merge request data is synced to Jira.
-Support for syncing past branch and commit data is tracked [in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/263240).
+For more information about syncing past branch and commit data, see [issue 263240](https://gitlab.com/gitlab-org/gitlab/-/issues/263240).
## Update the GitLab for Jira Cloud app
@@ -73,15 +72,15 @@ for details.
If the app requires additional permissions, [the update must first be manually approved in Jira](https://developer.atlassian.com/platform/marketplace/upgrading-and-versioning-cloud-apps/#changes-that-require-manual-customer-approval).
-## Set up OAuth authentication
+## Set up OAuth authentication for self-managed instances **(FREE SELF)**
The GitLab for Jira Cloud app is [switching to OAuth authentication](https://gitlab.com/gitlab-org/gitlab/-/issues/387299).
To enable OAuth authentication, you must create an OAuth application on the GitLab instance.
-Enabling OAuth authentication is:
+You must enable OAuth authentication to:
-- Required to [connect the GitLab for Jira Cloud app for self-managed instances](#connect-the-gitlab-for-jira-cloud-app-for-self-managed-instances).
-- Recommended to [install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually).
+- [Connect the GitLab for Jira Cloud app for self-managed instances](#connect-the-gitlab-for-jira-cloud-app-for-self-managed-instances).
+- [Install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually).
To create an OAuth application:
@@ -110,6 +109,7 @@ Prerequisites:
- GitLab.com must serve as a proxy for the instance.
- The instance must be publicly available.
- The instance must be on version 15.7 or later.
+- You must set up [OAuth authentication](#set-up-oauth-authentication-for-self-managed-instances).
You can link self-managed instances after installing the GitLab for Jira Cloud app from the marketplace.
Jira apps can only link to one URL per marketplace listing. The official listing links to GitLab.com.
@@ -123,7 +123,7 @@ It's not possible to create branches from Jira for self-managed instances. For m
To set up your self-managed instance for the GitLab for Jira Cloud app in GitLab 15.7 and later:
-1. [Set up OAuth authentication](#set-up-oauth-authentication).
+1. [Set up OAuth authentication](#set-up-oauth-authentication-for-self-managed-instances).
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General** (`/admin/application_settings/general`).
1. Expand the **GitLab for Jira App** section.
@@ -147,7 +147,7 @@ you can install the app manually.
Prerequisites:
- The instance must be publicly available.
-- You must set up [OAuth authentication](#set-up-oauth-authentication).
+- You must set up [OAuth authentication](#set-up-oauth-authentication-for-self-managed-instances).
### Set up your Jira app
@@ -202,9 +202,9 @@ For full instructions, review the Atlassian [guide to creating a marketplace lis
To create a Marketplace listing:
1. Register as a Marketplace vendor.
-1. List your application using the application descriptor URL.
+1. List your application with the application descriptor URL.
- Your manifest file is located at: `https://your.domain/your-path/-/jira_connect/app_descriptor.json`
- - We recommend you list your application as `private`, because public
+ - You should list your application as `private` because public
applications can be viewed and installed by any user.
1. Generate test license tokens for your application.
@@ -212,11 +212,11 @@ NOTE:
This method uses [automated updates](#update-the-gitlab-for-jira-cloud-app)
the same way as our GitLab.com Marketplace listing.
-## Configure your GitLab instance to serve as a proxy for the GitLab for Jira Cloud app
+## Configure your GitLab instance to serve as a proxy for the GitLab for Jira Cloud app **(FREE SELF)**
-A GitLab instance can serve as a proxy for other GitLab instances using the GitLab for Jira Cloud app.
-This can be useful if you are managing multiple GitLab instance but only want to [manually install](#install-the-gitlab-for-jira-cloud-app-manually)
-the GitLab for Jira app once.
+A GitLab instance can serve as a proxy for other GitLab instances through the GitLab for Jira Cloud app.
+You might want to use a proxy if you're managing multiple GitLab instances but only want to
+[manually install](#install-the-gitlab-for-jira-cloud-app-manually) the GitLab for Jira Cloud app once.
To configure your GitLab instance to serve as a proxy:
@@ -225,9 +225,36 @@ To configure your GitLab instance to serve as a proxy:
1. Expand the **GitLab for Jira App** section.
1. Select **Enable public key storage**.
1. Select **Save changes**.
-1. [Install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually)
+1. [Install the GitLab for Jira Cloud app manually](#install-the-gitlab-for-jira-cloud-app-manually).
-Other GitLab instances using the proxy must configure the **Jira Connect Proxy URL** setting and the [OAuth application](#set-up-oauth-authentication) **Redirect URI** to point to the proxy instance.
+Other GitLab instances that use the proxy must configure the **Jira Connect Proxy URL** and the [OAuth application](#set-up-oauth-authentication-for-self-managed-instances) **Redirect URI** settings to point to the proxy instance.
+
+## Security considerations
+
+The GitLab for Jira Cloud app connects GitLab and Jira. Data must be shared between the two applications, and access must be granted in both directions.
+
+### Access to GitLab through OAuth **(FREE SELF)**
+
+GitLab does not share an access token with Jira. However, users must authenticate through OAuth to configure the app.
+
+An access token is retrieved through a [PKCE](https://www.rfc-editor.org/rfc/rfc7636) OAuth flow and stored only on the client side.
+The app frontend that initializes the OAuth flow is a JavaScript application that's loaded from GitLab through an iframe on Jira.
+
+The OAuth application must have the `api` scope, which grants complete read and write access to the API.
+This access includes all groups and projects, the container registry, and the package registry.
+However, the GitLab for Jira Cloud app only uses this access to:
+
+- Display namespaces to be linked.
+- Link namespaces.
+
+Access through OAuth is only needed for the time a user configures the GitLab for Jira Cloud app. For more information, see [Access token expiration](../oauth_provider.md#access-token-expiration).
+
+### Access to Jira through access token
+
+Jira shares an access token with GitLab to authenticate and authorize data pushes to Jira.
+As part of the app installation process, Jira sends a handshake request to GitLab containing the access token.
+The handshake is signed with an [asymmetric JWT](https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/),
+and the access token is stored encrypted with `AES256-GCM` on GitLab.
## Troubleshooting
@@ -243,7 +270,7 @@ You need to sign in or sign up before continuing.
The GitLab for Jira Cloud app uses an iframe to add namespaces on the
settings page. Some browsers block cross-site cookies, which can lead to this issue.
-To resolve this issue, set up [OAuth authentication](#set-up-oauth-authentication) and enable the `jira_connect_oauth` [feature flag](../../administration/feature_flags.md).
+To resolve this issue, set up [OAuth authentication](#set-up-oauth-authentication-for-self-managed-instances) and enable the `jira_connect_oauth` [feature flag](../../administration/feature_flags.md).
### Manual installation fails
@@ -285,29 +312,3 @@ To resolve this issue on GitLab self-managed, follow one of the solutions below,
- Contact the [Jira Software Cloud support](https://support.atlassian.com/jira-software-cloud/) and ask to trigger a new installed lifecycle event for the GitLab for Jira Cloud app in your namespace.
- In all GitLab versions:
- Re-install the GitLab for Jira Cloud app. This might remove all already synced development panel data.
-
-## Security considerations
-
-The GitLab for Jira Cloud app connects GitLab and Jira, as data must be shared between the two applications and access must be granted in both directions.
-
-## Access to GitLab through OAuth
-
-GitLab does not share an access token with Jira. However, users must authenticate via OAuth to configure the app.
-
-An access token is retrieved via [PKCE](https://www.rfc-editor.org/rfc/rfc7636) OAuth flow, and stored only on the client side.
-The app-frontend that initializes the OAuth flow is a JavaScript application, which is loaded from GitLab through an iframe on Jira.
-
-The OAuth application requires the `api` scope that grants complete read/write access to the API, including to all groups and projects, the container registry, and the package registry.
-However, the GitLab for Jira Cloud app only uses this access to:
-
-- Display namespaces to be linked.
-- Link namespaces.
-
-Access through OAuth is only needed for the time a user configures the GitLab for Jira Cloud app. For more information, see [Access token expiration](../oauth_provider.md#access-token-expiration).
-
-## Access to Jira through access token
-
-Jira shares an access token with GitLab to authenticate and authorize data pushes to Jira.
-As part of the app installation process, Jira sends a handshake request to GitLab containing the access token.
-The handshake is signed with an [asymmetric JWT](https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/)
-and the access token is stored encrypted with `AES256-GCM` on GitLab.
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 56f5565e7a1..cbefaf9ba77 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -976,8 +976,8 @@ This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_g
Review the details carefully before upgrading.
Cookie authentication in the GitLab for Jira Cloud app is now deprecated in favor of OAuth authentication.
-You must [set up OAuth authentication](https://docs.gitlab.com/ee/integration/jira/connect-app.html#set-up-oauth-authentication)
-to continue to use the GitLab for Jira Cloud app. Without OAuth, you will not be able to manage linked namespaces.
+On self-managed, you must [set up OAuth authentication](https://docs.gitlab.com/ee/integration/jira/connect-app.html#set-up-oauth-authentication-for-self-managed-instances)
+to continue to use the GitLab for Jira Cloud app. Without OAuth, you can't manage linked namespaces.
</div>
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 70e05125f96..7501aefa158 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -359,7 +359,7 @@ The following package managers use lockfiles that GitLab analyzers are capable o
| Go | Not applicable | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/go-modules/gosum/default/go.sum) <sup><strong><a href="#notes-regarding-parsing-lockfiles-1">1</a></strong></sup> |
| NuGet | v1 | [4.9](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/csharp-nuget-dotnetcore/default/src/web.api/packages.lock.json#L2) |
| npm | v1, v2, v3<sup><b><a href="#notes-regarding-parsing-lockfiles-2">2</a></b></sup> | [6.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-npm/default/package-lock.json#L4), [7.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-npm/lockfileVersion2/package-lock.json#L4), [9.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/scanner/parser/npm/fixtures/lockfile-v3/simple/package-lock.json#L4) |
-| yarn | v1 | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/default/yarn.lock#L2) |
+| yarn | v1, v2<sup><b><a href="#notes-regarding-parsing-lockfiles-3">3</a></b></sup>, v3<sup><b><a href="#notes-regarding-parsing-lockfiles-3">3</a></b></sup> | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn/default/yarn.lock#L2), [2.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn-v2/default/yarn.lock), [3.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/js-yarn-v3/default/yarn.lock) |
| Poetry | v1 | [1.x](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/blob/master/qa/fixtures/python-poetry/default/poetry.lock) |
<!-- markdownlint-disable MD044 -->
@@ -377,6 +377,26 @@ The following package managers use lockfiles that GitLab analyzers are capable o
Support for <code>lockfileVersion = 3</code> was <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/365176">introduced</a> in GitLab 15.7.
</p>
</li>
+ <li>
+ <a id="notes-regarding-parsing-lockfiles-3"></a>
+ <p>
+ Support for Yarn <code>v2</code> and <code>v3</code> was <a href="https://gitlab.com/gitlab-org/gitlab/-/issues/263358">introduced in GitLab 15.11</a>. However, this feature is also available to versions of GitLab 15.0 and later.
+ </p>
+ <p>
+ The following features are not supported for Yarn <code>v2</code> or <code>v3</code>:
+ </p>
+ <ul>
+ <li>
+ <a href="https://yarnpkg.com/features/workspaces">workspaces</a>
+ </li>
+ <li>
+ <a href="https://yarnpkg.com/cli/patch">yarn patch</a>
+ </li>
+ </ul>
+ <p>
+ Yarn files that contain a patch, a workspace, or both, are still processed, but these features are ignored.
+ </p>
+ </li>
</ol>
<!-- markdownlint-enable MD044 -->
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index 0994bff4aa2..f66ff0e599d 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -220,18 +220,10 @@ The following image shows a **Groups** and **Documentation** section:
![MR widget - Sectional Code Owners](img/sectional_code_owners_v13.2.png)
-#### Set default owner for a section **(PREMIUM SELF)**
+#### Set default owner for a section
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371711) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `codeowners_default_owners`. Disabled by default.
-
-FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available,
-ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `codeowners_default_owners`.
-The feature is not ready for production use.
-
-WARNING:
-To disable this feature flag after setting default owners per section, edit your
-CODEOWNERS file to [list Code Owners per line](#set-up-code-owners).
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371711) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `codeowners_default_owners`. Disabled by default.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/115888) in GitLab 15.11. Feature flag `codeowners_default_owners` removed.
If multiple file paths inside a section share the same ownership, define a default
Code Owner for the section. All paths in that section inherit this default, unless
diff --git a/doc/user/project/integrations/bamboo.md b/doc/user/project/integrations/bamboo.md
index 12039a70d0e..419849ae5a0 100644
--- a/doc/user/project/integrations/bamboo.md
+++ b/doc/user/project/integrations/bamboo.md
@@ -125,7 +125,7 @@ For example:
### Builds not triggered
If builds are not triggered, ensure you entered the right GitLab IP address in
-Bamboo under **Trigger IP addresses**. Also check [service hook logs](index.md#troubleshooting-integrations) for request failures.
+Bamboo under **Trigger IP addresses**. Also check [integration webhook logs](index.md#troubleshooting) for request failures.
### Advanced Atlassian Bamboo features not available in GitLab UI
diff --git a/doc/user/project/integrations/bugzilla.md b/doc/user/project/integrations/bugzilla.md
index 2933203c593..aeb8871d257 100644
--- a/doc/user/project/integrations/bugzilla.md
+++ b/doc/user/project/integrations/bugzilla.md
@@ -57,4 +57,4 @@ internal issue tracker, the internal issue is linked.
## Troubleshooting
-To see recent service hook deliveries, check [service hook logs](index.md#troubleshooting-integrations).
+For recent integration webhook deliveries, check [integration webhook logs](index.md#troubleshooting).
diff --git a/doc/user/project/integrations/index.md b/doc/user/project/integrations/index.md
index 9ff6ad2a237..2bc4512a22e 100644
--- a/doc/user/project/integrations/index.md
+++ b/doc/user/project/integrations/index.md
@@ -103,9 +103,9 @@ supported by `push_hooks` and `tag_push_hooks` events aren't executed.
You can change the number of supported branches or tags by changing the
[`push_event_hooks_limit` application setting](../../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
-## Troubleshooting integrations
+## Troubleshooting
-Some integrations use hooks to integrate with external applications. To confirm which ones use integration hooks, see the [available integrations](#available-integrations). For more information, see [Troubleshooting webhooks](webhooks.md#troubleshoot-webhooks).
+Some integrations use hooks to integrate with external applications. To confirm which ones use integration hooks, see the [available integrations](#available-integrations). For more information, see [webhook troubleshooting](webhooks.md#troubleshooting).
### `Test Failed. Save Anyway` error
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index 004dfbc6953..1c65ab78ee0 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -129,18 +129,17 @@ FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `auto_disabling_web_hooks`.
On GitLab.com, this feature is available.
-Webhooks that fail four consecutive times are automatically disabled.
+Project or group webhooks that fail four consecutive times are automatically disabled.
-Webhooks that return response codes in the `5xx` range are understood to be failing
+Project or group webhooks that return response codes in the `5xx` range are understood to be failing
intermittently and are temporarily disabled. These webhooks are initially disabled
for one minute, which is extended on each subsequent failure up to a maximum of 24 hours.
-Webhooks that return response codes in the `4xx` range are understood to be
+Project or group webhooks that return response codes in the `4xx` range are understood to be
misconfigured and are permanently disabled until you manually re-enable
them yourself.
-See [Troubleshooting](#troubleshoot-webhooks) for more information on
-disabled webhooks and how to re-enable them.
+For more information about disabled webhooks, see [troubleshooting](#troubleshooting).
## Test a webhook
@@ -151,7 +150,7 @@ For example, to test `push events`, your project should have at least one commit
NOTE:
Testing is not supported for some types of events for project and groups webhooks.
-Read more in [issue 379201](https://gitlab.com/gitlab-org/gitlab/-/issues/379201).
+For more information, see [issue 379201](https://gitlab.com/gitlab-org/gitlab/-/issues/379201).
Prerequisites:
@@ -259,7 +258,7 @@ Image URLs are not rewritten if:
## Events
-For more information about supported events for Webhooks, go to [Webhook events](webhook_events.md).
+For more information about supported events for webhooks, see [webhook events](webhook_events.md).
## Delivery headers
@@ -275,7 +274,7 @@ Webhook requests to your endpoint include the following headers:
| `X-Gitlab-Event` | Name of the webhook type. Corresponds to [event types](webhook_events.md) but in the format `"<EVENT> Hook"`. | `"Push Hook"` |
| `X-Gitlab-Event-UUID` | Unique ID per webhook that is not recursive. A hook is recursive if triggered by an earlier webhook that hit the GitLab instance. Recursive webhooks have the same value for this header. | `"13792a34-cac6-4fda-95a8-c58e00a3954e"` |
-## Troubleshoot webhooks
+## Troubleshooting
> **Recent events** for group webhooks [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325642) in GitLab 15.3.
diff --git a/lib/gitlab/database/background_migration/batched_migration.rb b/lib/gitlab/database/background_migration/batched_migration.rb
index 429dc79e170..3c09ec3bd91 100644
--- a/lib/gitlab/database/background_migration/batched_migration.rb
+++ b/lib/gitlab/database/background_migration/batched_migration.rb
@@ -25,6 +25,7 @@ module Gitlab
scope :queue_order, -> { order(id: :asc) }
scope :queued, -> { with_statuses(:active, :paused) }
+ scope :finalizing, -> { with_status(:finalizing) }
scope :ordered_by_created_at_desc, -> { order(created_at: :desc) }
# on_hold_until is a temporary runtime status which puts execution "on hold"
diff --git a/lib/gitlab/graphql/authorize/authorize_resource.rb b/lib/gitlab/graphql/authorize/authorize_resource.rb
index 983bdb9c0a2..e3548b97ebf 100644
--- a/lib/gitlab/graphql/authorize/authorize_resource.rb
+++ b/lib/gitlab/graphql/authorize/authorize_resource.rb
@@ -45,8 +45,8 @@ module Gitlab
end
end
- def find_object(*args)
- raise NotImplementedError, "Implement #find_object in #{self.class.name}"
+ def find_object(id:)
+ GitlabSchema.find_by_gid(id)
end
def authorized_find!(*args, **kwargs)
diff --git a/lib/gitlab/pagination/keyset.rb b/lib/gitlab/pagination/keyset.rb
index 67a5530d46c..56017ba846c 100644
--- a/lib/gitlab/pagination/keyset.rb
+++ b/lib/gitlab/pagination/keyset.rb
@@ -3,12 +3,12 @@
module Gitlab
module Pagination
module Keyset
- SUPPORTED_TYPES = [
+ SUPPORTED_TYPES = %w[
Project
].freeze
def self.available_for_type?(relation)
- SUPPORTED_TYPES.include?(relation.klass)
+ SUPPORTED_TYPES.include?(relation.klass.to_s)
end
def self.available?(request_context, relation)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 75ce826e1be..a1a9f8bebbb 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -9182,7 +9182,7 @@ msgstr ""
msgid "CiVariable|Define a CI/CD variable in the UI"
msgstr ""
-msgid "CiVariable|Maximum of 20 environments listed. For more environments, enter a search query."
+msgid "CiVariable|Maximum of %{limit} environments listed. For more environments, enter a search query."
msgstr ""
msgid "CiVariable|New environment"
@@ -18108,6 +18108,9 @@ msgstr ""
msgid "Filter..."
msgstr ""
+msgid "Finalizing"
+msgstr ""
+
msgid "Find File"
msgstr ""
@@ -36606,6 +36609,9 @@ msgstr ""
msgid "Report Finding not found"
msgstr ""
+msgid "Report abuse"
+msgstr ""
+
msgid "Report abuse to administrator"
msgstr ""
@@ -36630,6 +36636,12 @@ msgstr ""
msgid "ReportAbuse|Report abuse to administrator"
msgstr ""
+msgid "ReportAbuse|Screenshot"
+msgstr ""
+
+msgid "ReportAbuse|Screenshot of abuse"
+msgstr ""
+
msgid "ReportAbuse|Something else."
msgstr ""
@@ -38545,6 +38557,9 @@ msgstr ""
msgid "Scopes: %{scope_list}"
msgstr ""
+msgid "Screenshot must be less than 1 MB."
+msgstr ""
+
msgid "Scroll down"
msgstr ""
@@ -39461,7 +39476,10 @@ msgstr ""
msgid "SecurityOrchestration|branches"
msgstr ""
-msgid "SecurityOrchestration|group level branch"
+msgid "SecurityOrchestration|group level branch input"
+msgstr ""
+
+msgid "SecurityOrchestration|group level branch selector"
msgstr ""
msgid "SecurityOrchestration|or from:"
@@ -52478,6 +52496,9 @@ msgstr ""
msgid "must match %{association}.project_id"
msgstr ""
+msgid "must match one of the following file types: %{extension_list}"
+msgstr ""
+
msgid "must not be an owner of the namespace"
msgstr ""
diff --git a/qa/qa/support/wait_for_requests.rb b/qa/qa/support/wait_for_requests.rb
index af36db62726..2856602629a 100644
--- a/qa/qa/support/wait_for_requests.rb
+++ b/qa/qa/support/wait_for_requests.rb
@@ -16,7 +16,7 @@ module QA
end
def finished_all_ajax_requests?
- requests = %w[window.pendingRequests window.pendingRailsUJSRequests 0]
+ requests = %w[window.pendingRequests window.pendingApolloRequests window.pendingRailsUJSRequests 0]
if Runtime::Env.can_intercept?
requests.unshift('(window.Interceptor && window.Interceptor.activeFetchRequests)')
diff --git a/spec/factories/abuse_reports.rb b/spec/factories/abuse_reports.rb
index 9f05d183ba4..699da744fab 100644
--- a/spec/factories/abuse_reports.rb
+++ b/spec/factories/abuse_reports.rb
@@ -11,5 +11,9 @@ FactoryBot.define do
trait :closed do
status { 'closed' }
end
+
+ trait :with_screenshot do
+ screenshot { fixture_file_upload('spec/fixtures/dk.png') }
+ end
end
end
diff --git a/spec/factories/projects/data_transfers.rb b/spec/factories/projects/data_transfers.rb
index 4184f475663..3c335c876e4 100644
--- a/spec/factories/projects/data_transfers.rb
+++ b/spec/factories/projects/data_transfers.rb
@@ -5,5 +5,9 @@ FactoryBot.define do
project factory: :project
namespace { project.root_namespace }
date { Time.current.utc.beginning_of_month }
+ repository_egress { 1 }
+ artifacts_egress { 2 }
+ packages_egress { 3 }
+ registry_egress { 4 }
end
end
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb
index 474ab4c7b8e..272656fb4ca 100644
--- a/spec/features/abuse_report_spec.rb
+++ b/spec/features/abuse_report_spec.rb
@@ -124,7 +124,7 @@ RSpec.describe 'Abuse reports', :js, feature_category: :insider_threat do
private
def fill_and_submit_abuse_category_form(category = "They're posting spam.")
- click_button 'Report abuse to administrator'
+ click_button 'Report abuse'
choose category
click_button 'Next'
diff --git a/spec/finders/data_transfer/group_data_transfer_finder_spec.rb b/spec/finders/data_transfer/group_data_transfer_finder_spec.rb
new file mode 100644
index 00000000000..0c54e6504e8
--- /dev/null
+++ b/spec/finders/data_transfer/group_data_transfer_finder_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DataTransfer::GroupDataTransferFinder, feature_category: :source_code_management do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:namespace_1) { create(:group) }
+ let_it_be(:project_1) { create(:project, group: namespace_1) }
+ let_it_be(:project_2) { create(:project, group: namespace_1) }
+ let(:from_date) { Date.new(2022, 2, 1) }
+ let(:to_date) { Date.new(2023, 1, 1) }
+
+ before_all do
+ namespace_1.add_owner(user)
+ end
+
+ describe '#execute' do
+ let(:subject) { described_class.new(group: namespace_1, from: from_date, to: to_date, user: user) }
+
+ before do
+ create(:project_data_transfer, project: project_1, date: '2022-01-01')
+ create(:project_data_transfer, project: project_1, date: '2022-02-01')
+ create(:project_data_transfer, project: project_2, date: '2022-02-01')
+ end
+
+ it 'returns the correct number of egress' do
+ expect(subject.execute.to_a.size).to eq(1)
+ end
+
+ it 'returns the correct values grouped by date' do
+ first_result = subject.execute.first
+ expect(first_result.attributes).to include(
+ {
+ 'namespace_id' => namespace_1.id,
+ 'date' => from_date,
+ 'repository_egress' => 2,
+ 'artifacts_egress' => 4,
+ 'packages_egress' => 6,
+ 'registry_egress' => 8,
+ 'total_egress' => 20
+ }
+ )
+ end
+
+ context 'when there are no results for specified namespace' do
+ let_it_be(:namespace_2) { create(:group) }
+ let(:subject) { described_class.new(group: namespace_2, from: from_date, to: to_date, user: user) }
+
+ it 'returns nothing' do
+ expect(subject.execute).to be_empty
+ end
+ end
+
+ context 'when there are no results for specified dates' do
+ let(:from_date) { Date.new(2021, 1, 1) }
+ let(:to_date) { Date.new(2021, 1, 1) }
+
+ it 'returns nothing' do
+ expect(subject.execute).to be_empty
+ end
+ end
+
+ context 'when dates are not provided' do
+ let(:from_date) { nil }
+ let(:to_date) { nil }
+
+ it 'return all values for a namespace', :aggregate_failures do
+ results = subject.execute
+ expect(results.to_a.size).to eq(2)
+ results.each do |result|
+ expect(result.namespace).to eq(namespace_1)
+ end
+ end
+ end
+
+ context 'when user does not have permissions' do
+ let(:user) { build(:user) }
+
+ it 'returns nothing' do
+ expect(subject.execute).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/finders/data_transfer/mocked_transfer_finder_spec.rb b/spec/finders/data_transfer/mocked_transfer_finder_spec.rb
new file mode 100644
index 00000000000..f60bc98f587
--- /dev/null
+++ b/spec/finders/data_transfer/mocked_transfer_finder_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DataTransfer::MockedTransferFinder, feature_category: :source_code_management do
+ describe '#execute' do
+ subject(:execute) { described_class.new.execute }
+
+ it 'returns mock data' do
+ expect(execute.first).to include(
+ date: '2023-01-01',
+ repository_egress: be_a(Integer),
+ artifacts_egress: be_a(Integer),
+ packages_egress: be_a(Integer),
+ registry_egress: be_a(Integer),
+ total_egress: be_a(Integer)
+ )
+
+ expect(execute.size).to eq(12)
+ end
+ end
+end
diff --git a/spec/finders/data_transfer/project_data_transfer_finder_spec.rb b/spec/finders/data_transfer/project_data_transfer_finder_spec.rb
new file mode 100644
index 00000000000..1d5cd0f3339
--- /dev/null
+++ b/spec/finders/data_transfer/project_data_transfer_finder_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DataTransfer::ProjectDataTransferFinder, feature_category: :source_code_management do
+ let_it_be(:project_1) { create(:project) }
+ let_it_be(:project_2) { create(:project) }
+ let_it_be(:user) { project_1.first_owner }
+ let(:from_date) { Date.new(2022, 2, 1) }
+ let(:to_date) { Date.new(2023, 1, 1) }
+
+ describe '#execute' do
+ let(:subject) { described_class.new(project: project_1, from: from_date, to: to_date, user: user) }
+
+ before do
+ create(:project_data_transfer, project: project_1, date: '2022-01-01')
+ create(:project_data_transfer, project: project_1, date: '2022-02-01')
+ create(:project_data_transfer, project: project_1, date: '2022-03-01')
+ create(:project_data_transfer, project: project_2, date: '2022-01-01')
+ end
+
+ it 'returns the correct number of egress' do
+ expect(subject.execute.size).to eq(2)
+ end
+
+ it 'returns the correct values' do
+ first_result = subject.execute.first
+ expect(first_result.attributes).to include(
+ {
+ 'project_id' => project_1.id,
+ 'date' => from_date,
+ 'repository_egress' => 1,
+ 'artifacts_egress' => 2,
+ 'packages_egress' => 3,
+ 'registry_egress' => 4,
+ 'total_egress' => 10
+ }
+ )
+ end
+
+ context 'when there are no results for specified dates' do
+ let(:from_date) { Date.new(2021, 1, 1) }
+ let(:to_date) { Date.new(2021, 1, 1) }
+
+ it 'returns nothing' do
+ expect(subject.execute).to be_empty
+ end
+ end
+
+ context 'when there are no results for specified project' do
+ let_it_be(:project_3) { create(:project, :repository) }
+ let(:subject) { described_class.new(project: project_3, from: from_date, to: to_date, user: user) }
+
+ it 'returns nothing' do
+ expect(subject.execute).to be_empty
+ end
+ end
+
+ context 'when dates are not provided' do
+ let(:from_date) { nil }
+ let(:to_date) { nil }
+
+ it 'return all values for a project', :aggregate_failures do
+ results = subject.execute
+ expect(results.size).to eq(3)
+ results.each do |result|
+ expect(result.project).to eq(project_1)
+ end
+ end
+ end
+
+ context 'when user does not have permissions' do
+ let(:user) { build(:user) }
+
+ it 'returns nothing' do
+ expect(subject.execute).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js b/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
index ebfe6e8842b..193f7babdb7 100644
--- a/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
+++ b/spec/frontend/ci/ci_variable_list/components/ci_environments_dropdown_spec.js
@@ -1,6 +1,6 @@
import { GlListboxItem, GlCollapsibleListbox, GlDropdownItem, GlIcon } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
-import { allEnvironments } from '~/ci/ci_variable_list/constants';
+import { allEnvironments, ENVIRONMENT_QUERY_LIMIT } from '~/ci/ci_variable_list/constants';
import CiEnvironmentsDropdown from '~/ci/ci_variable_list/components/ci_environments_dropdown.vue';
describe('Ci environments dropdown', () => {
@@ -148,6 +148,7 @@ describe('Ci environments dropdown', () => {
it('displays note about max environments shown', () => {
expect(findMaxEnvNote().exists()).toBe(true);
+ expect(findMaxEnvNote().text()).toContain(String(ENVIRONMENT_QUERY_LIMIT));
});
});
diff --git a/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb b/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb
deleted file mode 100644
index 451f6d1fe06..00000000000
--- a/spec/graphql/mutations/concerns/mutations/finds_by_gid_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Mutations::FindsByGid do
- include GraphqlHelpers
-
- let(:mutation_class) do
- Class.new(Mutations::BaseMutation) do
- authorize :read_user
-
- include Mutations::FindsByGid
- end
- end
-
- let(:query) { query_double(schema: GitlabSchema) }
- let(:context) { GraphQL::Query::Context.new(query: query, object: nil, values: { current_user: user }) }
- let(:user) { create(:user) }
- let(:gid) { user.to_global_id }
-
- subject(:mutation) { mutation_class.new(object: nil, context: context, field: nil) }
-
- it 'calls GitlabSchema.find_by_gid to find objects during authorized_find!' do
- expect(mutation.authorized_find!(id: gid)).to eq(user)
- end
-end
diff --git a/spec/graphql/resolvers/data_transfer/group_data_transfer_resolver_spec.rb b/spec/graphql/resolvers/data_transfer/group_data_transfer_resolver_spec.rb
new file mode 100644
index 00000000000..4ea3d287454
--- /dev/null
+++ b/spec/graphql/resolvers/data_transfer/group_data_transfer_resolver_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::DataTransfer::GroupDataTransferResolver, feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:current_user) { create(:user) }
+
+ let(:from) { Date.new(2022, 1, 1) }
+ let(:to) { Date.new(2023, 1, 1) }
+ let(:finder_results) do
+ [
+ build(:project_data_transfer, date: to, repository_egress: 250000)
+ ]
+ end
+
+ context 'with anonymous access' do
+ let_it_be(:current_user) { nil }
+
+ it 'does not raise an error and returns no data' do
+ expect { resolve_egress }.not_to raise_error
+ expect(resolve_egress).to be_nil
+ end
+ end
+
+ context 'with authorized user but without enough permissions' do
+ it 'does not raise an error and returns no data' do
+ group.add_developer(current_user)
+
+ expect { resolve_egress }.not_to raise_error
+ expect(resolve_egress).to be_nil
+ end
+ end
+
+ context 'when user has permissions to see data transfer' do
+ before do
+ group.add_owner(current_user)
+ end
+
+ include_examples 'Data transfer resolver'
+
+ context 'when data_transfer_monitoring_mock_data is disabled' do
+ let(:finder) { instance_double(::DataTransfer::GroupDataTransferFinder) }
+
+ before do
+ stub_feature_flags(data_transfer_monitoring_mock_data: false)
+ end
+
+ it 'calls GroupDataTransferFinder with expected arguments' do
+ expect(::DataTransfer::GroupDataTransferFinder).to receive(:new).with(
+ group: group, from: from, to: to, user: current_user
+ ).once.and_return(finder)
+ allow(finder).to receive(:execute).once.and_return(finder_results)
+
+ expect(resolve_egress).to eq({ egress_nodes: finder_results.map(&:attributes) })
+ end
+ end
+ end
+
+ def resolve_egress
+ resolve(described_class, obj: group, args: { from: from, to: to }, ctx: { current_user: current_user })
+ end
+end
diff --git a/spec/graphql/resolvers/data_transfer/project_data_transfer_resolver_spec.rb b/spec/graphql/resolvers/data_transfer/project_data_transfer_resolver_spec.rb
new file mode 100644
index 00000000000..7307c1a54a9
--- /dev/null
+++ b/spec/graphql/resolvers/data_transfer/project_data_transfer_resolver_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::DataTransfer::ProjectDataTransferResolver, feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:current_user) { create(:user) }
+
+ let(:from) { Date.new(2022, 1, 1) }
+ let(:to) { Date.new(2023, 1, 1) }
+ let(:finder_results) do
+ [
+ {
+ date: to,
+ repository_egress: 250000
+ }
+ ]
+ end
+
+ context 'with anonymous access' do
+ let_it_be(:current_user) { nil }
+
+ it 'does not raise an error and returns no data' do
+ expect { resolve_egress }.not_to raise_error
+ expect(resolve_egress).to be_nil
+ end
+ end
+
+ context 'with authorized user but without enough permissions' do
+ it 'does not raise an error and returns no data' do
+ project.add_developer(current_user)
+
+ expect { resolve_egress }.not_to raise_error
+ expect(resolve_egress).to be_nil
+ end
+ end
+
+ context 'when user has permissions to see data transfer' do
+ before do
+ project.add_owner(current_user)
+ end
+
+ include_examples 'Data transfer resolver'
+
+ context 'when data_transfer_monitoring_mock_data is disabled' do
+ let(:finder) { instance_double(::DataTransfer::ProjectDataTransferFinder) }
+
+ before do
+ stub_feature_flags(data_transfer_monitoring_mock_data: false)
+ end
+
+ it 'calls ProjectDataTransferFinder with expected arguments' do
+ expect(::DataTransfer::ProjectDataTransferFinder).to receive(:new).with(
+ project: project, from: from, to: to, user: current_user
+ ).once.and_return(finder)
+ allow(finder).to receive(:execute).once.and_return(finder_results)
+
+ expect(resolve_egress).to eq({ egress_nodes: finder_results })
+ end
+ end
+ end
+
+ def resolve_egress
+ resolve(described_class, obj: project, args: { from: from, to: to }, ctx: { current_user: current_user })
+ end
+end
diff --git a/spec/graphql/resolvers/data_transfer_resolver_spec.rb b/spec/graphql/resolvers/data_transfer_resolver_spec.rb
deleted file mode 100644
index f5a088dc1c3..00000000000
--- a/spec/graphql/resolvers/data_transfer_resolver_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Resolvers::DataTransferResolver, feature_category: :source_code_management do
- include GraphqlHelpers
-
- describe '.source' do
- context 'with base DataTransferResolver' do
- it 'raises NotImplementedError' do
- expect { described_class.source }.to raise_error ::NotImplementedError
- end
- end
-
- context 'with projects DataTransferResolver' do
- let(:source) { described_class.project.source }
-
- it 'outputs "Project"' do
- expect(source).to eq 'Project'
- end
- end
-
- context 'with groups DataTransferResolver' do
- let(:source) { described_class.group.source }
-
- it 'outputs "Group"' do
- expect(source).to eq 'Group'
- end
- end
- end
-end
diff --git a/spec/graphql/types/data_transfer/project_data_transfer_type_spec.rb b/spec/graphql/types/data_transfer/project_data_transfer_type_spec.rb
new file mode 100644
index 00000000000..a93da279b7f
--- /dev/null
+++ b/spec/graphql/types/data_transfer/project_data_transfer_type_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['ProjectDataTransfer'], feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ it 'includes the specific fields' do
+ expect(described_class).to have_graphql_fields(
+ :total_egress, :egress_nodes)
+ end
+
+ describe '#total_egress' do
+ let_it_be(:project) { create(:project) }
+ let(:from) { Date.new(2022, 1, 1) }
+ let(:to) { Date.new(2023, 1, 1) }
+ let(:finder_result) { 40_000_000 }
+
+ it 'returns mock data' do
+ expect(resolve_field(:total_egress, { from: from, to: to }, extras: { parent: project },
+ arg_style: :internal)).to eq(finder_result)
+ end
+
+ context 'when data_transfer_monitoring_mock_data is disabled' do
+ let(:relation) { instance_double(ActiveRecord::Relation) }
+
+ before do
+ allow(relation).to receive(:sum).and_return(10)
+ stub_feature_flags(data_transfer_monitoring_mock_data: false)
+ end
+
+ it 'calls sum on active record relation' do
+ expect(resolve_field(:total_egress, { egress_nodes: relation }, extras: { parent: project },
+ arg_style: :internal)).to eq(10)
+ end
+ end
+ end
+end
diff --git a/spec/helpers/abuse_reports_helper_spec.rb b/spec/helpers/abuse_reports_helper_spec.rb
new file mode 100644
index 00000000000..6d381b7eb56
--- /dev/null
+++ b/spec/helpers/abuse_reports_helper_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe AbuseReportsHelper, feature_category: :insider_threat do
+ describe '#valid_image_mimetypes' do
+ subject(:valid_image_mimetypes) { helper.valid_image_mimetypes }
+
+ it {
+ is_expected.to eq('image/png, image/jpg, image/jpeg, image/gif, image/bmp, image/tiff, image/ico or image/webp')
+ }
+ end
+end
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
index d132559acea..546f9353808 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :model do
+RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :model, feature_category: :database do
it_behaves_like 'having unique enum values'
it { is_expected.to be_a Gitlab::Database::SharedModel }
@@ -328,6 +328,17 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
end
end
+ describe '.finalizing' do
+ let!(:migration1) { create(:batched_background_migration, :active) }
+ let!(:migration2) { create(:batched_background_migration, :paused) }
+ let!(:migration3) { create(:batched_background_migration, :finalizing) }
+ let!(:migration4) { create(:batched_background_migration, :finished) }
+
+ it 'returns only finalizing migrations' do
+ expect(described_class.finalizing).to contain_exactly(migration3)
+ end
+ end
+
describe '.successful_rows_counts' do
let!(:migration1) { create(:batched_background_migration) }
let!(:migration2) { create(:batched_background_migration) }
diff --git a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
index ac512e28e7b..1cd93d7b364 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
@@ -76,13 +76,17 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
end
- context 'when the class does not define #find_object' do
+ describe '#find_object' do
let(:fake_class) do
Class.new { include Gitlab::Graphql::Authorize::AuthorizeResource }
end
- it 'raises a comprehensive error message' do
- expect { fake_class.new.find_object }.to raise_error(/Implement #find_object in #{fake_class.name}/)
+ let(:id) { "id" }
+ let(:return_value) { "return value" }
+
+ it 'calls GitlabSchema.find_by_gid' do
+ expect(GitlabSchema).to receive(:find_by_gid).with(id).and_return(return_value)
+ expect(fake_class.new.find_object(id: id)).to be return_value
end
end
diff --git a/spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
new file mode 100644
index 00000000000..89e14650034
--- /dev/null
+++ b/spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureCommitUserMentionsNoteIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do
+ describe '#up' do
+ let(:migration_arguments) do
+ {
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: 'commit_user_mentions',
+ column_name: 'id',
+ job_arguments: [['note_id'], ['note_id_convert_to_bigint']]
+ }
+ end
+
+ it 'ensures the migration is completed for GitLab.com, dev, or test' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+ expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments)
+ end
+
+ migrate!
+ end
+
+ it 'skips the check for other instances' do
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+ expect(instance).not_to receive(:ensure_batched_background_migration_is_finished)
+ end
+
+ migrate!
+ end
+ end
+end
diff --git a/spec/migrations/remove_invalid_deploy_access_level_spec.rb b/spec/migrations/remove_invalid_deploy_access_level_spec.rb
deleted file mode 100644
index cc0f5679dda..00000000000
--- a/spec/migrations/remove_invalid_deploy_access_level_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-require_migration!
-
-RSpec.describe RemoveInvalidDeployAccessLevel, :migration, feature_category: :continuous_integration do
- let(:users) { table(:users) }
- let(:groups) { table(:namespaces) }
- let(:protected_environments) { table(:protected_environments) }
- let(:deploy_access_levels) { table(:protected_environment_deploy_access_levels) }
-
- let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) }
- let(:group) { groups.create!(name: 'test-group', path: 'test-group') }
- let(:pe) do
- protected_environments.create!(name: 'test-pe', group_id: group.id)
- end
-
- let!(:invalid_access_level) do
- deploy_access_levels.create!(
- access_level: 40,
- user_id: user.id,
- group_id: group.id,
- protected_environment_id: pe.id)
- end
-
- let!(:group_access_level) do
- deploy_access_levels.create!(
- group_id: group.id,
- protected_environment_id: pe.id)
- end
-
- let!(:user_access_level) do
- deploy_access_levels.create!(
- user_id: user.id,
- protected_environment_id: pe.id)
- end
-
- it 'removes invalid access_level entries' do
- expect { migrate! }.to change {
- deploy_access_levels.where(
- protected_environment_id: pe.id,
- access_level: nil).count
- }.from(2).to(3)
-
- expect(invalid_access_level.reload.access_level).to be_nil
- end
-end
diff --git a/spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb b/spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb
new file mode 100644
index 00000000000..72663e63996
--- /dev/null
+++ b/spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe RerunRemoveInvalidDeployAccessLevel, :migration, feature_category: :continuous_integration do
+ let(:users) { table(:users) }
+ let(:groups) { table(:namespaces) }
+ let(:protected_environments) { table(:protected_environments) }
+ let(:deploy_access_levels) { table(:protected_environment_deploy_access_levels) }
+
+ let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) }
+ let(:group) { groups.create!(name: 'test-group', path: 'test-group') }
+ let(:pe) do
+ protected_environments.create!(name: 'test-pe', group_id: group.id)
+ end
+
+ let!(:invalid_access_level) do
+ deploy_access_levels.create!(
+ access_level: 40,
+ user_id: user.id,
+ group_id: group.id,
+ protected_environment_id: pe.id)
+ end
+
+ let!(:access_level) do
+ deploy_access_levels.create!(
+ access_level: 40,
+ user_id: nil,
+ group_id: nil,
+ protected_environment_id: pe.id)
+ end
+
+ let!(:group_access_level) do
+ deploy_access_levels.create!(
+ group_id: group.id,
+ protected_environment_id: pe.id)
+ end
+
+ let!(:user_access_level) do
+ deploy_access_levels.create!(
+ user_id: user.id,
+ protected_environment_id: pe.id)
+ end
+
+ let!(:user_and_group_access_level) do
+ deploy_access_levels.create!(
+ user_id: user.id,
+ group_id: group.id,
+ protected_environment_id: pe.id)
+ end
+
+ it 'fixes invalid access_level entries and does not affect others' do
+ expect { migrate! }.to change {
+ deploy_access_levels.where(protected_environment_id: pe.id)
+ .where("num_nonnulls(user_id, group_id, access_level) = 1").count
+ }.from(3).to(5)
+
+ invalid_access_level.reload
+ access_level.reload
+ group_access_level.reload
+ user_access_level.reload
+ user_and_group_access_level.reload
+
+ expect(invalid_access_level.access_level).to be_nil
+ expect(invalid_access_level.user_id).to eq(user.id)
+ expect(invalid_access_level.group_id).to be_nil
+
+ expect(access_level.access_level).to eq(40)
+ expect(access_level.user_id).to be_nil
+ expect(access_level.group_id).to be_nil
+
+ expect(group_access_level.access_level).to be_nil
+ expect(group_access_level.user_id).to be_nil
+ expect(group_access_level.group_id).to eq(group.id)
+
+ expect(user_access_level.access_level).to be_nil
+ expect(user_access_level.user_id).to eq(user.id)
+ expect(user_access_level.group_id).to be_nil
+
+ expect(user_and_group_access_level.access_level).to be_nil
+ expect(user_and_group_access_level.user_id).to eq(user.id)
+ expect(user_and_group_access_level.group_id).to be_nil
+ end
+end
diff --git a/spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb
new file mode 100644
index 00000000000..d219d544033
--- /dev/null
+++ b/spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SwapCommitUserMentionsNoteIdToBigintForGitlabDotCom, feature_category: :database do
+ describe '#up' do
+ before do
+ # A we call `schema_migrate_down!` before each example, and for this migration
+ # `#down` is same as `#up`, we need to ensure we start from the expected state.
+ connection = described_class.new.connection
+ connection.execute('ALTER TABLE commit_user_mentions ALTER COLUMN note_id TYPE integer')
+ connection.execute('ALTER TABLE commit_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint')
+ end
+
+ # rubocop: disable RSpec/AnyInstanceOf
+ it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true)
+
+ user_mentions = table(:commit_user_mentions)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ user_mentions.reset_column_information
+
+ expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ user_mentions.reset_column_information
+
+ expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint')
+ expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer')
+ }
+ end
+ end
+ end
+
+ it 'is a no-op for other instances' do
+ allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false)
+
+ user_mentions = table(:commit_user_mentions)
+
+ disable_migrations_output do
+ reversible_migration do |migration|
+ migration.before -> {
+ user_mentions.reset_column_information
+
+ expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+
+ migration.after -> {
+ user_mentions.reset_column_information
+
+ expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer')
+ expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint')
+ }
+ end
+ end
+ end
+ # rubocop: enable RSpec/AnyInstanceOf
+ end
+end
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index 9026a870138..8a9ac618e00 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -68,6 +68,17 @@ RSpec.describe AbuseReport, feature_category: :insider_threat do
"https://gitlab.com/#{SecureRandom.alphanumeric(494)}"
]).for(:links_to_spam)
}
+
+ context 'for screenshot' do
+ let(:txt_file) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
+ let(:img_file) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
+
+ it { is_expected.not_to allow_value(txt_file).for(:screenshot) }
+ it { is_expected.to allow_value(img_file).for(:screenshot) }
+
+ it { is_expected.to allow_value(nil).for(:screenshot) }
+ it { is_expected.to allow_value('').for(:screenshot) }
+ end
end
describe 'scopes' do
@@ -145,6 +156,30 @@ RSpec.describe AbuseReport, feature_category: :insider_threat do
end
end
+ describe '#screenshot_path' do
+ let(:report) { create(:abuse_report, :with_screenshot) }
+
+ context 'with asset host configured' do
+ let(:asset_host) { 'https://gitlab-assets.example.com' }
+
+ before do
+ allow(ActionController::Base).to receive(:asset_host) { asset_host }
+ end
+
+ it 'returns a full URL with the asset host and system path' do
+ expect(report.screenshot_path).to eq("#{asset_host}#{report.screenshot.url}")
+ end
+ end
+
+ context 'when no asset path configured' do
+ let(:base_url) { Gitlab.config.gitlab.base_url }
+
+ it 'returns a full URL with the base url and system path' do
+ expect(report.screenshot_path).to eq("#{base_url}#{report.screenshot.url}")
+ end
+ end
+ end
+
describe 'enums' do
let(:categories) do
{
diff --git a/spec/models/plan_limits_spec.rb b/spec/models/plan_limits_spec.rb
index 3705cab7ef5..eb17a66a103 100644
--- a/spec/models/plan_limits_spec.rb
+++ b/spec/models/plan_limits_spec.rb
@@ -221,6 +221,7 @@ RSpec.describe PlanLimits do
security_policy_scan_execution_schedules
enforcement_limit
notification_limit
+ project_access_token_limit
] + disabled_max_artifact_size_columns
end
diff --git a/spec/models/projects/data_transfer_spec.rb b/spec/models/projects/data_transfer_spec.rb
index ab798185bbb..49be35662c8 100644
--- a/spec/models/projects/data_transfer_spec.rb
+++ b/spec/models/projects/data_transfer_spec.rb
@@ -19,6 +19,12 @@ RSpec.describe Projects::DataTransfer, feature_category: :source_code_management
end
describe 'scopes' do
+ let(:dates) { %w[2023-01-01 2023-02-01 2023-03-01] }
+
+ before do
+ dates.each { |date| create(:project_data_transfer, project: project, date: date) }
+ end
+
describe '.current_month' do
subject { described_class.current_month }
@@ -31,6 +37,26 @@ RSpec.describe Projects::DataTransfer, feature_category: :source_code_management
end
end
end
+
+ describe '.with_project_between_dates' do
+ subject do
+ described_class.with_project_between_dates(project, Date.new(2023, 2, 1), Date.new(2023, 3, 1))
+ end
+
+ it 'returns the correct number of results' do
+ expect(subject.size).to eq(2)
+ end
+ end
+
+ describe '.with_namespace_between_dates' do
+ subject do
+ described_class.with_namespace_between_dates(project.namespace, Date.new(2023, 2, 1), Date.new(2023, 3, 1))
+ end
+
+ it 'returns the correct number of results' do
+ expect(subject.select(:namespace_id).to_a.size).to eq(2)
+ end
+ end
end
describe '.beginning_of_month' do
diff --git a/spec/requests/abuse_reports_controller_spec.rb b/spec/requests/abuse_reports_controller_spec.rb
index 934f123e45b..4b81394aea3 100644
--- a/spec/requests/abuse_reports_controller_spec.rb
+++ b/spec/requests/abuse_reports_controller_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe AbuseReportsController, feature_category: :insider_threat do
attributes_for(:abuse_report) do |hash|
hash[:user_id] = user.id
hash[:category] = abuse_category
+ hash[:screenshot] = fixture_file_upload('spec/fixtures/dk.png')
end
end
diff --git a/spec/requests/admin/background_migrations_controller_spec.rb b/spec/requests/admin/background_migrations_controller_spec.rb
index 88d81766e67..2681ece7d8a 100644
--- a/spec/requests/admin/background_migrations_controller_spec.rb
+++ b/spec/requests/admin/background_migrations_controller_spec.rb
@@ -67,6 +67,17 @@ RSpec.describe Admin::BackgroundMigrationsController, :enable_admin_mode, featur
expect(assigns(:migrations)).to match_array([main_database_migration])
end
+
+ context 'for finalizing tab' do
+ let!(:finalizing_migration) { create(:batched_background_migration, :finalizing) }
+
+ it 'returns only finalizing migration' do
+ get admin_background_migrations_path(tab: 'finalizing')
+
+ expect(Gitlab::Database::BackgroundMigration::BatchedMigration.queued).not_to be_empty
+ expect(assigns(:migrations)).to match_array(Array.wrap(finalizing_migration))
+ end
+ end
end
context 'when multiple database is enabled', :add_ci_connection do
diff --git a/spec/requests/api/graphql/group/data_transfer_spec.rb b/spec/requests/api/graphql/group/data_transfer_spec.rb
new file mode 100644
index 00000000000..b7c038afa54
--- /dev/null
+++ b/spec/requests/api/graphql/group/data_transfer_spec.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'group data transfers', feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project_1) { create(:project, group: group) }
+ let_it_be(:project_2) { create(:project, group: group) }
+
+ let(:fields) do
+ <<~QUERY
+ #{all_graphql_fields_for('GroupDataTransfer'.classify)}
+ QUERY
+ end
+
+ let(:query) do
+ graphql_query_for(
+ 'group',
+ { fullPath: group.full_path },
+ query_graphql_field('DataTransfer', params, fields)
+ )
+ end
+
+ let(:from) { Date.new(2022, 1, 1) }
+ let(:to) { Date.new(2023, 1, 1) }
+ let(:params) { { from: from, to: to } }
+ let(:egress_data) do
+ graphql_data.dig('group', 'dataTransfer', 'egressNodes', 'nodes')
+ end
+
+ before do
+ create(:project_data_transfer, project: project_1, date: '2022-01-01', repository_egress: 1)
+ create(:project_data_transfer, project: project_1, date: '2022-02-01', repository_egress: 2)
+ create(:project_data_transfer, project: project_2, date: '2022-02-01', repository_egress: 4)
+ end
+
+ subject { post_graphql(query, current_user: current_user) }
+
+ context 'with anonymous access' do
+ let_it_be(:current_user) { nil }
+
+ before do
+ subject
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns no data' do
+ expect(graphql_data_at(:group, :data_transfer)).to be_nil
+ expect(graphql_errors).to be_nil
+ end
+ end
+
+ context 'with authorized user but without enough permissions' do
+ before do
+ group.add_developer(current_user)
+ subject
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns empty results' do
+ expect(graphql_data_at(:group, :data_transfer)).to be_nil
+ expect(graphql_errors).to be_nil
+ end
+ end
+
+ context 'when user has enough permissions' do
+ before do
+ group.add_owner(current_user)
+ end
+
+ context 'when data_transfer_monitoring_mock_data is NOT enabled' do
+ before do
+ stub_feature_flags(data_transfer_monitoring_mock_data: false)
+ subject
+ end
+
+ it 'returns real results' do
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(egress_data.count).to eq(2)
+
+ expect(egress_data.first.keys).to match_array(
+ %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
+ )
+
+ expect(egress_data.pluck('repositoryEgress')).to match_array(%w[1 6])
+ end
+
+ it_behaves_like 'a working graphql query'
+ end
+
+ context 'when data_transfer_monitoring_mock_data is enabled' do
+ before do
+ stub_feature_flags(data_transfer_monitoring_mock_data: true)
+ subject
+ end
+
+ it 'returns mock results' do
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(egress_data.count).to eq(12)
+ expect(egress_data.first.keys).to match_array(
+ %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
+ )
+ end
+
+ it_behaves_like 'a working graphql query'
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/data_transfer_spec.rb b/spec/requests/api/graphql/project/data_transfer_spec.rb
new file mode 100644
index 00000000000..aafa8d65eb9
--- /dev/null
+++ b/spec/requests/api/graphql/project/data_transfer_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'project data transfers', feature_category: :source_code_management do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+
+ let(:fields) do
+ <<~QUERY
+ #{all_graphql_fields_for('ProjectDataTransfer'.classify)}
+ QUERY
+ end
+
+ let(:query) do
+ graphql_query_for(
+ 'project',
+ { fullPath: project.full_path },
+ query_graphql_field('DataTransfer', params, fields)
+ )
+ end
+
+ let(:from) { Date.new(2022, 1, 1) }
+ let(:to) { Date.new(2023, 1, 1) }
+ let(:params) { { from: from, to: to } }
+ let(:egress_data) do
+ graphql_data.dig('project', 'dataTransfer', 'egressNodes', 'nodes')
+ end
+
+ before do
+ create(:project_data_transfer, project: project, date: '2022-01-01', repository_egress: 1)
+ create(:project_data_transfer, project: project, date: '2022-02-01', repository_egress: 2)
+ end
+
+ subject { post_graphql(query, current_user: current_user) }
+
+ context 'with anonymous access' do
+ let_it_be(:current_user) { nil }
+
+ before do
+ subject
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns no data' do
+ expect(graphql_data_at(:project, :data_transfer)).to be_nil
+ expect(graphql_errors).to be_nil
+ end
+ end
+
+ context 'with authorized user but without enough permissions' do
+ before do
+ project.add_developer(current_user)
+ subject
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns empty results' do
+ expect(graphql_data_at(:project, :data_transfer)).to be_nil
+ expect(graphql_errors).to be_nil
+ end
+ end
+
+ context 'when user has enough permissions' do
+ before do
+ project.add_owner(current_user)
+ end
+
+ context 'when data_transfer_monitoring_mock_data is NOT enabled' do
+ before do
+ stub_feature_flags(data_transfer_monitoring_mock_data: false)
+ subject
+ end
+
+ it 'returns real results' do
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(egress_data.count).to eq(2)
+
+ expect(egress_data.first.keys).to match_array(
+ %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
+ )
+
+ expect(egress_data.pluck('repositoryEgress')).to match_array(%w[1 2])
+ end
+
+ it_behaves_like 'a working graphql query'
+ end
+
+ context 'when data_transfer_monitoring_mock_data is enabled' do
+ before do
+ stub_feature_flags(data_transfer_monitoring_mock_data: true)
+ subject
+ end
+
+ it 'returns mock results' do
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(egress_data.count).to eq(12)
+ expect(egress_data.first.keys).to match_array(
+ %w[date totalEgress repositoryEgress artifactsEgress packagesEgress registryEgress]
+ )
+ end
+
+ it_behaves_like 'a working graphql query'
+ end
+ end
+end
diff --git a/spec/support/finder_collection_allowlist.yml b/spec/support/finder_collection_allowlist.yml
index 750295e16c4..1b1c98af80d 100644
--- a/spec/support/finder_collection_allowlist.yml
+++ b/spec/support/finder_collection_allowlist.yml
@@ -69,3 +69,4 @@
- UploaderFinder
- UserGroupNotificationSettingsFinder
- UserGroupsCounter
+- DataTransfer::MockedTransferFinder # Can be removed when https://gitlab.com/gitlab-org/gitlab/-/issues/397693 is closed
diff --git a/spec/support/helpers/every_sidekiq_worker_test_helper.rb b/spec/support/helpers/every_sidekiq_worker_test_helper.rb
new file mode 100644
index 00000000000..b053ed04b58
--- /dev/null
+++ b/spec/support/helpers/every_sidekiq_worker_test_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module EverySidekiqWorkerTestHelper
+ def extra_retry_exceptions
+ {}
+ end
+end
+
+EverySidekiqWorkerTestHelper.prepend_mod
diff --git a/spec/support/shared_examples/controllers/unique_hll_events_examples.rb b/spec/support/shared_examples/controllers/unique_hll_events_examples.rb
index 38c3157e898..b5528afa0b5 100644
--- a/spec/support/shared_examples/controllers/unique_hll_events_examples.rb
+++ b/spec/support/shared_examples/controllers/unique_hll_events_examples.rb
@@ -7,6 +7,9 @@
RSpec.shared_examples 'tracking unique hll events' do
it 'tracks unique event' do
+ # Allow any event tracking before we expect the specific event we want to check below
+ allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).and_call_original
+
expect(Gitlab::UsageDataCounters::HLLRedisCounter).to(
receive(:track_event)
.with(target_event, values: expected_value)
diff --git a/spec/support/shared_examples/features/abuse_report_shared_examples.rb b/spec/support/shared_examples/features/abuse_report_shared_examples.rb
index 7a520fb0cd2..ea9b4e9f4b2 100644
--- a/spec/support/shared_examples/features/abuse_report_shared_examples.rb
+++ b/spec/support/shared_examples/features/abuse_report_shared_examples.rb
@@ -2,10 +2,14 @@
RSpec.shared_examples 'reports the user with an abuse category' do
it 'creates abuse report' do
- click_button 'Report abuse to administrator'
+ click_button 'Report abuse'
choose "They're posting spam."
click_button 'Next'
+ page.attach_file('spec/fixtures/dk.png') do
+ click_button "Choose file"
+ end
+
fill_in 'abuse_report_message', with: 'This user sends spam'
click_button 'Send report'
diff --git a/spec/support/shared_examples/features/reportable_note_shared_examples.rb b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
index bb3fab5b23e..45ad4d5cf71 100644
--- a/spec/support/shared_examples/features/reportable_note_shared_examples.rb
+++ b/spec/support/shared_examples/features/reportable_note_shared_examples.rb
@@ -20,7 +20,7 @@ RSpec.shared_examples 'reportable note' do |type|
dropdown = comment.find(more_actions_selector)
open_dropdown(dropdown)
- expect(dropdown).to have_button('Report abuse to administrator')
+ expect(dropdown).to have_button('Report abuse')
if type == 'issue' || type == 'merge_request'
expect(dropdown).to have_button('Delete comment')
@@ -33,7 +33,7 @@ RSpec.shared_examples 'reportable note' do |type|
dropdown = comment.find(more_actions_selector)
open_dropdown(dropdown)
- dropdown.click_button('Report abuse to administrator')
+ dropdown.click_button('Report abuse')
choose "They're posting spam."
click_button "Next"
diff --git a/spec/support/shared_examples/graphql/resolvers/data_transfer_resolver_shared_examples.rb b/spec/support/shared_examples/graphql/resolvers/data_transfer_resolver_shared_examples.rb
new file mode 100644
index 00000000000..8551bd052ce
--- /dev/null
+++ b/spec/support/shared_examples/graphql/resolvers/data_transfer_resolver_shared_examples.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Data transfer resolver' do
+ it 'returns mock data' do |_query_object|
+ mocked_data = ['mocked_data']
+
+ allow_next_instance_of(DataTransfer::MockedTransferFinder) do |instance|
+ allow(instance).to receive(:execute).and_return(mocked_data)
+ end
+
+ expect(resolve_egress[:egress_nodes]).to eq(mocked_data)
+ end
+
+ context 'when data_transfer_monitoring is disabled' do
+ before do
+ stub_feature_flags(data_transfer_monitoring: false)
+ end
+
+ it 'returns empty result' do
+ expect(resolve_egress).to eq(egress_nodes: [])
+ end
+ end
+end
diff --git a/spec/tooling/lib/tooling/mappings/graphql_base_type_mappings_spec.rb b/spec/tooling/lib/tooling/mappings/graphql_base_type_mappings_spec.rb
new file mode 100644
index 00000000000..521958573fd
--- /dev/null
+++ b/spec/tooling/lib/tooling/mappings/graphql_base_type_mappings_spec.rb
@@ -0,0 +1,249 @@
+# frozen_string_literal: true
+
+require 'tempfile'
+require_relative '../../../../../tooling/lib/tooling/mappings/graphql_base_type_mappings'
+
+RSpec.describe Tooling::Mappings::GraphqlBaseTypeMappings, feature_category: :tooling do
+ # We set temporary folders, and those readers give access to those folder paths
+ attr_accessor :foss_folder, :ee_folder, :jh_folder
+ attr_accessor :changes_file, :matching_tests_paths
+
+ around do |example|
+ self.changes_file = Tempfile.new('changes')
+ self.matching_tests_paths = Tempfile.new('matching_tests')
+
+ Dir.mktmpdir('FOSS') do |foss_folder|
+ Dir.mktmpdir('EE') do |ee_folder|
+ Dir.mktmpdir('JH') do |jh_folder|
+ self.foss_folder = foss_folder
+ self.ee_folder = ee_folder
+ self.jh_folder = jh_folder
+
+ # See https://ruby-doc.org/stdlib-1.9.3/libdoc/tempfile/rdoc/
+ # Tempfile.html#class-Tempfile-label-Explicit+close
+ begin
+ example.run
+ ensure
+ changes_file.close
+ matching_tests_paths.close
+ changes_file.unlink
+ matching_tests_paths.unlink
+ end
+ end
+ end
+ end
+ end
+
+ let(:instance) { described_class.new(changes_file, matching_tests_paths) }
+ let(:changes_file_content) { "changed_file1 changed_file2" }
+ let(:matching_tests_paths_initial_content) { "previously_matching_spec.rb" }
+
+ before do
+ stub_const("Tooling::Mappings::GraphqlBaseTypeMappings::GRAPHQL_TYPES_FOLDERS", {
+ nil => [foss_folder],
+ 'ee' => [foss_folder, ee_folder],
+ 'jh' => [foss_folder, ee_folder, jh_folder]
+ })
+
+ # We write into the temp files initially, to later check how the code modified those files
+ File.write(changes_file, changes_file_content)
+ File.write(matching_tests_paths, matching_tests_paths_initial_content)
+ end
+
+ describe '#execute' do
+ subject { instance.execute }
+
+ context 'when no GraphQL files were changed' do
+ let(:changes_file_content) { '' }
+
+ it 'does not change the output file' do
+ expect { subject }.not_to change { File.read(matching_tests_paths) }
+ end
+ end
+
+ context 'when some GraphQL files were changed' do
+ let(:changes_file_content) do
+ [
+ "#{foss_folder}/my_graphql_file.rb",
+ "#{foss_folder}/my_other_graphql_file.rb"
+ ].join(' ')
+ end
+
+ context 'when none of those GraphQL types are included in other GraphQL types' do
+ before do
+ File.write("#{foss_folder}/my_graphql_file.rb", "some graphQL code; implements-test MyOtherGraphqlFile")
+ File.write("#{foss_folder}/my_other_graphql_file.rb", "some graphQL code")
+ end
+
+ it 'does not change the output file' do
+ expect { subject }.not_to change { File.read(matching_tests_paths) }
+ end
+ end
+
+ context 'when the GraphQL types are included in other GraphQL types' do
+ before do
+ File.write("#{foss_folder}/my_graphql_file.rb", "some graphQL code; implements MyOtherGraphqlFile")
+ File.write("#{foss_folder}/my_other_graphql_file.rb", "some graphQL code")
+
+ # We mock this because we are using temp directories, so we cannot rely on just replacing `app`` with `spec`
+ allow(instance).to receive(:filename_to_spec_filename)
+ .with("#{foss_folder}/my_graphql_file.rb")
+ .and_return('spec/my_graphql_file_spec.rb')
+ end
+
+ it 'writes the correct specs in the output' do
+ expect { subject }.to change { File.read(matching_tests_paths) }
+ .from(matching_tests_paths_initial_content)
+ .to("#{matching_tests_paths_initial_content} spec/my_graphql_file_spec.rb")
+ end
+ end
+ end
+ end
+
+ describe '#filter_files' do
+ subject { instance.filter_files }
+
+ before do
+ File.write("#{foss_folder}/my_graphql_file.rb", "my_graphql_file.rb")
+ File.write("#{foss_folder}/my_other_graphql_file.rb", "my_other_graphql_file.rb")
+ File.write("#{foss_folder}/another_file.erb", "another_file.erb")
+ end
+
+ context 'when no files were changed' do
+ let(:changes_file_content) { '' }
+
+ it 'returns an empty array' do
+ expect(subject).to match_array([])
+ end
+ end
+
+ context 'when GraphQL files were changed' do
+ let(:changes_file_content) do
+ [
+ "#{foss_folder}/my_graphql_file.rb",
+ "#{foss_folder}/my_other_graphql_file.rb",
+ "#{foss_folder}/another_file.erb"
+ ].join(' ')
+ end
+
+ it 'returns the path to the GraphQL files' do
+ expect(subject).to match_array([
+ "#{foss_folder}/my_graphql_file.rb",
+ "#{foss_folder}/my_other_graphql_file.rb"
+ ])
+ end
+ end
+
+ context 'when files are deleted' do
+ let(:changes_file_content) { "#{foss_folder}/deleted.rb" }
+
+ it 'returns an empty array' do
+ expect(subject).to match_array([])
+ end
+ end
+ end
+
+ describe '#types_hierarchies' do
+ subject { instance.types_hierarchies }
+
+ context 'when no types are implementing other types' do
+ before do
+ File.write("#{foss_folder}/foss_file.rb", "some graphQL code")
+ File.write("#{ee_folder}/ee_file.rb", "some graphQL code")
+ File.write("#{jh_folder}/jh_file.rb", "some graphQL code")
+ end
+
+ it 'returns nothing' do
+ expect(subject).to eq(
+ nil => {},
+ 'ee' => {},
+ 'jh' => {}
+ )
+ end
+ end
+
+ context 'when types are implementing other types' do
+ before do
+ File.write("#{foss_folder}/foss_file.rb", "some graphQL code; implements NoteableInterface")
+ File.write("#{ee_folder}/ee_file.rb", "some graphQL code; implements NoteableInterface")
+ File.write("#{jh_folder}/jh_file.rb", "some graphQL code; implements NoteableInterface")
+ end
+
+ context 'when FOSS' do
+ it 'returns only FOSS types' do
+ expect(subject).to include(
+ nil => {
+ 'NoteableInterface' => [
+ "#{foss_folder}/foss_file.rb"
+ ]
+ }
+ )
+ end
+ end
+
+ context 'when EE' do
+ it 'returns the correct children types' do
+ expect(subject).to include(
+ 'ee' => {
+ 'NoteableInterface' => [
+ "#{foss_folder}/foss_file.rb",
+ "#{ee_folder}/ee_file.rb"
+ ]
+ }
+ )
+ end
+ end
+
+ context 'when JH' do
+ it 'returns the correct children types' do
+ expect(subject).to include(
+ 'jh' => {
+ 'NoteableInterface' => [
+ "#{foss_folder}/foss_file.rb",
+ "#{ee_folder}/ee_file.rb",
+ "#{jh_folder}/jh_file.rb"
+ ]
+ }
+ )
+ end
+ end
+ end
+ end
+
+ describe '#filename_to_class_name' do
+ let(:filename) { 'app/graphql/types/user_merge_request_interaction_type.rb' }
+
+ subject { instance.filename_to_class_name(filename) }
+
+ it 'returns the correct class name' do
+ expect(subject).to eq('UserMergeRequestInteractionType')
+ end
+ end
+
+ describe '#filename_to_spec_filename' do
+ let(:filename) { 'ee/app/graphql/ee/types/application_type.rb' }
+ let(:expected_spec_filename) { 'ee/spec/graphql/ee/types/application_type_spec.rb' }
+
+ subject { instance.filename_to_spec_filename(filename) }
+
+ context 'when the spec file exists' do
+ before do
+ allow(File).to receive(:exist?).with(expected_spec_filename).and_return(true)
+ end
+
+ it 'returns the correct spec filename' do
+ expect(subject).to eq(expected_spec_filename)
+ end
+ end
+
+ context 'when the spec file does not exist' do
+ before do
+ allow(File).to receive(:exist?).with(expected_spec_filename).and_return(false)
+ end
+
+ it 'returns nil' do
+ expect(subject).to eq(nil)
+ end
+ end
+ end
+end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index ece36ad39a5..133c06086e5 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
+ include EverySidekiqWorkerTestHelper
+
let(:workers_without_defaults) do
Gitlab::SidekiqConfig.workers - Gitlab::SidekiqConfig::DEFAULT_WORKERS.values
end
@@ -481,7 +483,7 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'WorkItems::ImportWorkItemsCsvWorker' => 3,
'X509CertificateRevokeWorker' => 3,
'ComplianceManagement::MergeRequests::ComplianceViolationsWorker' => 3
- }
+ }.merge(extra_retry_exceptions)
end
it 'uses the default number of retries for new jobs' do
diff --git a/tooling/bin/graphql_base_type_mappings b/tooling/bin/graphql_base_type_mappings
new file mode 100755
index 00000000000..2fc06ab639f
--- /dev/null
+++ b/tooling/bin/graphql_base_type_mappings
@@ -0,0 +1,9 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+
+require_relative '../lib/tooling/mappings/graphql_base_type_mappings'
+
+changes_file = ARGV.shift
+matching_tests_paths = ARGV.shift
+
+Tooling::Mappings::GraphqlBaseTypeMappings.new(changes_file, matching_tests_paths).execute
diff --git a/tooling/lib/tooling/mappings/graphql_base_type_mappings.rb b/tooling/lib/tooling/mappings/graphql_base_type_mappings.rb
new file mode 100644
index 00000000000..cd8b55d5820
--- /dev/null
+++ b/tooling/lib/tooling/mappings/graphql_base_type_mappings.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require 'active_support/inflector'
+
+require_relative 'base'
+require_relative '../../../../lib/gitlab_edition'
+
+# If a GraphQL type class changed, we try to identify the other GraphQL types that potentially include this type.
+module Tooling
+ module Mappings
+ class GraphqlBaseTypeMappings < Base
+ # Checks for the implements keyword, and graphql_base_types the class name
+ GRAPHQL_IMPLEMENTS_REGEXP = /implements[( ]([\w:]+)[)]?$/
+
+ # GraphQL types are a bit scattered in the codebase based on the edition.
+ #
+ # Also, a higher edition is able to include lower editions.
+ # e.g. EE can include FOSS GraphQL types, and JH can include all GraphQL types
+ GRAPHQL_TYPES_FOLDERS_FOSS = ['app/graphql/types'].freeze
+ GRAPHQL_TYPES_FOLDERS_EE = GRAPHQL_TYPES_FOLDERS_FOSS + ['ee/app/graphql/types', 'ee/app/graphql/ee/types']
+ GRAPHQL_TYPES_FOLDERS_JH = GRAPHQL_TYPES_FOLDERS_EE + ['jh/app/graphql/types', 'jh/app/graphql/jh/types']
+ GRAPHQL_TYPES_FOLDERS = {
+ nil => GRAPHQL_TYPES_FOLDERS_FOSS,
+ 'ee' => GRAPHQL_TYPES_FOLDERS_EE,
+ 'jh' => GRAPHQL_TYPES_FOLDERS_JH
+ }.freeze
+
+ def initialize(changes_file, matching_tests_paths)
+ @matching_tests_paths = matching_tests_paths
+ @changed_files = read_array_from_file(changes_file)
+ end
+
+ def execute
+ # We go through the available editions when searching for base types
+ #
+ # `nil` is the FOSS edition
+ matching_graphql_tests = ([nil] + ::GitlabEdition.extensions).flat_map do |edition|
+ hierarchy = types_hierarchies[edition]
+
+ filter_files.flat_map do |graphql_file|
+ children_types = hierarchy[filename_to_class_name(graphql_file)]
+ next if children_types.empty?
+
+ # We find the specs for the children GraphQL types that are implementing the current GraphQL Type
+ children_types.map { |filename| filename_to_spec_filename(filename) }
+ end
+ end.compact.uniq
+
+ write_array_to_file(matching_tests_paths, matching_graphql_tests)
+ end
+
+ def filter_files
+ changed_files.select do |filename|
+ filename.start_with?(*GRAPHQL_TYPES_FOLDERS.values.flatten.uniq) &&
+ filename.end_with?('.rb') &&
+ File.exist?(filename)
+ end
+ end
+
+ # Regroup all GraphQL types (by edition) that are implementing another GraphQL type.
+ #
+ # The key is the type that is being implemented (e.g. NoteableInterface, TodoableInterface below)
+ # The value is an array of GraphQL type files that are implementing those types.
+ #
+ # Example output:
+ #
+ # {
+ # nil => {
+ # "NoteableInterface" => [
+ # "app/graphql/types/alert_management/alert_type.rb",
+ # "app/graphql/types/design_management/design_type.rb"
+ # , "TodoableInterface" => [...]
+ # },
+ # "ee" => {
+ # "NoteableInterface" => [
+ # "app/graphql/types/alert_management/alert_type.rb",
+ # "app/graphql/types/design_management/design_type.rb",
+ # "ee/app/graphql/types/epic_type.rb"],
+ # "TodoableInterface"=> [...]
+ # }
+ # }
+ def types_hierarchies
+ return @types_hierarchies if @types_hierarchies
+
+ @types_hierarchies = {}
+ GRAPHQL_TYPES_FOLDERS.each_key do |edition|
+ @types_hierarchies[edition] = Hash.new { |h, k| h[k] = [] }
+
+ graphql_files_for_edition_glob = File.join("{#{GRAPHQL_TYPES_FOLDERS[edition].join(',')}}", '**', '*.rb')
+ Dir[graphql_files_for_edition_glob].each do |graphql_file|
+ graphql_base_types = File.read(graphql_file).scan(GRAPHQL_IMPLEMENTS_REGEXP)
+ next if graphql_base_types.empty?
+
+ graphql_base_classes = graphql_base_types.flatten.map { |class_name| class_name.split('::').last }
+ graphql_base_classes.each do |graphql_base_class|
+ @types_hierarchies[edition][graphql_base_class] += [graphql_file]
+ end
+ end
+ end
+
+ @types_hierarchies
+ end
+
+ def filename_to_class_name(filename)
+ File.basename(filename, '.*').camelize
+ end
+
+ def filename_to_spec_filename(filename)
+ spec_file = filename.sub('app', 'spec').sub('.rb', '_spec.rb')
+
+ return spec_file if File.exist?(spec_file)
+ end
+
+ private
+
+ attr_reader :changed_files, :matching_tests_paths
+ end
+ end
+end
diff --git a/workhorse/go.mod b/workhorse/go.mod
index 989aa5b02df..9242b14c407 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -26,7 +26,7 @@ require (
github.com/sirupsen/logrus v1.9.0
github.com/smartystreets/goconvey v1.7.2
github.com/stretchr/testify v1.8.2
- gitlab.com/gitlab-org/gitaly/v15 v15.9.3
+ gitlab.com/gitlab-org/gitaly/v15 v15.10.0
gitlab.com/gitlab-org/golang-archive-zip v0.1.1
gitlab.com/gitlab-org/labkit v1.18.0
gocloud.dev v0.29.0
@@ -58,7 +58,7 @@ require (
github.com/AzureAD/microsoft-authentication-library-for-go v0.8.1 // indirect
github.com/DataDog/datadog-go v4.4.0+incompatible // indirect
github.com/DataDog/sketches-go v1.0.0 // indirect
- github.com/Microsoft/go-winio v0.5.1 // indirect
+ github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/beevik/ntp v0.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -111,7 +111,7 @@ require (
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
- golang.org/x/sys v0.5.0 // indirect
+ golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
diff --git a/workhorse/go.sum b/workhorse/go.sum
index 77769e7b221..df1c1403c77 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -504,8 +504,9 @@ github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugX
github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
-github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
+github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
@@ -1495,8 +1496,8 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
-github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
+github.com/miekg/dns v1.1.51 h1:0+Xg7vObnhrz/4ZCZcZh7zPXlmU0aveS2HDBd0m0qSo=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
@@ -1917,8 +1918,8 @@ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
-gitlab.com/gitlab-org/gitaly/v15 v15.9.3 h1:jloqZdc+TkpZHU2pr4grHKNAp+zg6NeB4vQZgRrOvCE=
-gitlab.com/gitlab-org/gitaly/v15 v15.9.3/go.mod h1:MLAmjPsXan0TixWBOnF2GUTjHcNLoAiYv1x1LRx7gHQ=
+gitlab.com/gitlab-org/gitaly/v15 v15.10.0 h1:l6K7AuaK3LPB9FaVk0tLtpPEX7eXEvVgPzRQGRq1FJc=
+gitlab.com/gitlab-org/gitaly/v15 v15.10.0/go.mod h1:ZsyTd8zGxT4WuSZJ0G8ydJb60mauzEP0XJtZJEy/7bc=
gitlab.com/gitlab-org/golang-archive-zip v0.1.1 h1:35k9giivbxwF03+8A05Cm8YoxoakU8FBCj5gysjCTCE=
gitlab.com/gitlab-org/golang-archive-zip v0.1.1/go.mod h1:ZDtqpWPGPB9qBuZnZDrKQjIdJtkN7ZAoVwhT6H2o2kE=
gitlab.com/gitlab-org/labkit v1.18.0 h1:uYCIqDt/5V1hLIecTR4UNc1sD2+xiYplyKeyfpNN26A=
@@ -2015,8 +2016,8 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
-go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
+go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -2091,7 +2092,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230124195608-d38c7dcee874/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
-golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w=
+golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI=
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
@@ -2426,8 +2427,9 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=