diff options
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:  -#### 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= |