From 91035102b4e313787a45217ff12bb88f7f48bf20 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 3 Aug 2022 12:11:38 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../block_given_with_explicit_block.yml | 43 ---------- app/controllers/concerns/redis_tracking.rb | 2 +- app/graphql/types/namespace_type.rb | 6 ++ app/graphql/types/project_type.rb | 10 +++ .../time_tracking/timelog_category_type.rb | 51 +++++++++++ app/helpers/badges_helper.rb | 2 +- app/helpers/instance_configuration_helper.rb | 2 +- app/helpers/labels_helper.rb | 2 +- app/helpers/tab_helper.rb | 8 +- app/models/namespace.rb | 2 + .../group_project_namespace_shared_policy.rb | 14 +++- .../namespaces/project_namespace_policy.rb | 6 +- .../time_tracking/timelog_category_policy.rb | 7 ++ app/services/base_count_service.rb | 2 +- app/services/error_tracking/base_service.rb | 2 +- app/services/users/update_service.rb | 2 +- app/services/webauthn/authenticate_service.rb | 2 + .../development/timelog_categories.yml | 8 ++ ...ate_index_vulnerabilities_common_finder.rb | 21 +++++ db/schema_migrations/20220728134255 | 1 + db/structure.sql | 2 +- doc/api/graphql/reference/index.md | 41 +++++++++ .../monitoring/background_migrations.md | 44 ++++++++++ .../prometheus.md | 30 ++----- .../management_project_applications/sentry.md | 73 ++-------------- lib/bulk_imports/clients/http.rb | 2 +- lib/gitlab/batch_pop_queueing.rb | 2 +- lib/gitlab/cache/request_cache.rb | 2 +- lib/gitlab/ci/trace/chunked_io.rb | 2 +- lib/gitlab/database/bulk_update.rb | 2 +- lib/gitlab/database/with_lock_retries.rb | 2 +- lib/gitlab/github_import/client.rb | 4 +- lib/gitlab/legacy_github_import/client.rb | 2 +- lib/gitlab/metrics/methods/metric_options.rb | 2 +- lib/gitlab/null_request_store.rb | 2 +- lib/gitlab/quick_actions/dsl.rb | 10 +-- lib/gitlab/redis/multi_store.rb | 2 +- lib/gitlab/safe_request_loader.rb | 2 +- lib/gitlab/search/query.rb | 2 +- lib/gitlab/string_placeholder_replacer.rb | 2 +- .../terraform/state_migration_helper.rb | 2 +- .../metrics/instrumentations/base_metric.rb | 2 +- .../instrumentations/database_metric.rb | 10 +-- .../instrumentations/numbers_metric.rb | 2 +- lib/gitlab/usage_data_queries.rb | 4 +- lib/gitlab/utils/usage_data.rb | 4 +- locale/gitlab.pot | 9 +- package.json | 2 +- qa/qa/page/view.rb | 2 +- spec/graphql/types/namespace_type_spec.rb | 1 + spec/graphql/types/project_type_spec.rb | 3 +- .../timelog_category_type_spec.rb | 22 +++++ spec/lib/api/helpers/authentication_spec.rb | 2 +- spec/lib/gitlab/slash_commands/deploy_spec.rb | 2 +- .../namespaces/project_namespace_spec.rb | 8 ++ spec/models/u2f_registration_spec.rb | 79 ++++++++++++++--- spec/policies/group_policy_spec.rb | 8 ++ .../project_namespace_policy_spec.rb | 42 +--------- spec/requests/api/graphql/group_query_spec.rb | 69 +++++++++++++++ .../api/graphql/project_query_spec.rb | 84 +++++++++++++++++++ .../webauthn/authenticate_service_spec.rb | 25 ++++-- spec/support/helpers/graphql_helpers.rb | 4 +- spec/support/helpers/query_recorder.rb | 2 +- spec/support/helpers/stub_method_calls.rb | 2 +- ...roject_namespace_policy_shared_examples.rb | 35 ++++++++ tooling/lib/tooling/helm3_client.rb | 4 +- tooling/lib/tooling/test_map_packer.rb | 2 +- yarn.lock | 18 ++-- 68 files changed, 608 insertions(+), 264 deletions(-) delete mode 100644 .rubocop_todo/performance/block_given_with_explicit_block.yml create mode 100644 app/graphql/types/time_tracking/timelog_category_type.rb create mode 100644 app/policies/time_tracking/timelog_category_policy.rb create mode 100644 config/feature_flags/development/timelog_categories.yml create mode 100644 db/post_migrate/20220728134255_update_index_vulnerabilities_common_finder.rb create mode 100644 db/schema_migrations/20220728134255 create mode 100644 spec/graphql/types/time_tracking/timelog_category_type_spec.rb create mode 100644 spec/support/shared_examples/policies/group_project_namespace_policy_shared_examples.rb diff --git a/.rubocop_todo/performance/block_given_with_explicit_block.yml b/.rubocop_todo/performance/block_given_with_explicit_block.yml deleted file mode 100644 index b919dbd19e6..00000000000 --- a/.rubocop_todo/performance/block_given_with_explicit_block.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- -# Cop supports --auto-correct. -Performance/BlockGivenWithExplicitBlock: - Exclude: - - 'app/controllers/concerns/redis_tracking.rb' - - 'app/helpers/badges_helper.rb' - - 'app/helpers/instance_configuration_helper.rb' - - 'app/helpers/labels_helper.rb' - - 'app/helpers/tab_helper.rb' - - 'app/services/base_count_service.rb' - - 'app/services/error_tracking/base_service.rb' - - 'app/services/users/update_service.rb' - - 'ee/lib/elastic/latest/query_context.rb' - - 'ee/lib/gitlab/geo.rb' - - 'lib/bulk_imports/clients/http.rb' - - 'lib/gitlab/batch_pop_queueing.rb' - - 'lib/gitlab/cache/request_cache.rb' - - 'lib/gitlab/ci/trace/chunked_io.rb' - - 'lib/gitlab/database/bulk_update.rb' - - 'lib/gitlab/database/with_lock_retries.rb' - - 'lib/gitlab/github_import/client.rb' - - 'lib/gitlab/legacy_github_import/client.rb' - - 'lib/gitlab/metrics/methods/metric_options.rb' - - 'lib/gitlab/null_request_store.rb' - - 'lib/gitlab/quick_actions/dsl.rb' - - 'lib/gitlab/redis/multi_store.rb' - - 'lib/gitlab/safe_request_loader.rb' - - 'lib/gitlab/search/query.rb' - - 'lib/gitlab/string_placeholder_replacer.rb' - - 'lib/gitlab/terraform/state_migration_helper.rb' - - 'lib/gitlab/usage/metrics/instrumentations/base_metric.rb' - - 'lib/gitlab/usage/metrics/instrumentations/database_metric.rb' - - 'lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb' - - 'lib/gitlab/usage_data_queries.rb' - - 'lib/gitlab/utils/usage_data.rb' - - 'qa/qa/page/view.rb' - - 'spec/lib/api/helpers/authentication_spec.rb' - - 'spec/lib/gitlab/slash_commands/deploy_spec.rb' - - 'spec/support/helpers/graphql_helpers.rb' - - 'spec/support/helpers/query_recorder.rb' - - 'spec/support/helpers/stub_method_calls.rb' - - 'tooling/lib/tooling/helm3_client.rb' - - 'tooling/lib/tooling/test_map_packer.rb' diff --git a/app/controllers/concerns/redis_tracking.rb b/app/controllers/concerns/redis_tracking.rb index c1135d2f759..445e72b8266 100644 --- a/app/controllers/concerns/redis_tracking.rb +++ b/app/controllers/concerns/redis_tracking.rb @@ -29,7 +29,7 @@ module RedisTracking private def track_unique_redis_hll_event(event_name, &block) - custom_id = block_given? ? yield(self) : nil + custom_id = block ? yield(self) : nil unique_id = custom_id || visitor_id diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index 088a3437f4a..b90226bd733 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -57,6 +57,12 @@ module Types null: true, description: "Shared runners availability for the namespace and its descendants." + field :timelog_categories, + Types::TimeTracking::TimelogCategoryType.connection_type, + null: true, + description: "Timelog categories for the namespace.", + feature_flag: :timelog_categories + markdown_field :description_html, null: true def cross_project_pipeline_available? diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 2a5ba3c7006..5bb8e613844 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -438,6 +438,16 @@ module Types ' Returns `null` if `work_items` feature flag is disabled.' \ ' This flag is disabled by default, because the feature is experimental and is subject to change without notice.' + field :timelog_categories, + Types::TimeTracking::TimelogCategoryType.connection_type, + null: true, + description: "Timelog categories for the project.", + feature_flag: :timelog_categories + + def timelog_categories + object.project_namespace.timelog_categories + end + def label(title:) BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args| LabelsFinder diff --git a/app/graphql/types/time_tracking/timelog_category_type.rb b/app/graphql/types/time_tracking/timelog_category_type.rb new file mode 100644 index 00000000000..c73a6fbd43b --- /dev/null +++ b/app/graphql/types/time_tracking/timelog_category_type.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module Types + module TimeTracking + class TimelogCategoryType < BaseObject + graphql_name 'TimeTrackingTimelogCategory' + + authorize :read_timelog_category + + field :id, + GraphQL::Types::ID, + null: false, + description: 'Internal ID of the timelog category.' + + field :name, + GraphQL::Types::String, + null: false, + description: 'Name of the category.' + + field :description, + GraphQL::Types::String, + null: true, + description: 'Description of the category.' + + field :color, + Types::ColorType, + null: true, + description: 'Color assigned to the category.' + + field :billable, + GraphQL::Types::Boolean, + null: true, + description: 'Whether the category is billable or not.' + + field :billing_rate, + GraphQL::Types::Float, + null: true, + description: 'Billing rate for the category.' + + field :created_at, + Types::TimeType, + null: false, + description: 'When the category was created.' + + field :updated_at, + Types::TimeType, + null: false, + description: 'When the category was last updated.' + end + end +end diff --git a/app/helpers/badges_helper.rb b/app/helpers/badges_helper.rb index 46f0b043770..d48eae26a90 100644 --- a/app/helpers/badges_helper.rb +++ b/app/helpers/badges_helper.rb @@ -53,7 +53,7 @@ module BadgesHelper # # See also https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-badge--default. def gl_badge_tag(*args, &block) - if block_given? + if block build_gl_badge_tag(capture(&block), *args) else build_gl_badge_tag(*args) diff --git a/app/helpers/instance_configuration_helper.rb b/app/helpers/instance_configuration_helper.rb index b06e3ff2904..7eb14d31dc7 100644 --- a/app/helpers/instance_configuration_helper.rb +++ b/app/helpers/instance_configuration_helper.rb @@ -4,7 +4,7 @@ module InstanceConfigurationHelper def instance_configuration_cell_html(value, &block) return '-' unless value.to_s.presence - block_given? ? yield(value) : value + block ? yield(value) : value end def instance_configuration_host(host) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 877785c9eaf..2d0bc1bc63f 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -39,7 +39,7 @@ module LabelsHelper def link_to_label(label, type: :issue, tooltip: true, small: false, css_class: nil, &block) link = label.filter_path(type: type) - if block_given? + if block link_to link, class: css_class, &block else render_label(label, link: link, tooltip: tooltip, small: small) diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index dbbe7069ca4..04619ad3bda 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -17,7 +17,7 @@ module TabHelper class: [*html_options[:class], gl_tabs_classes].join(' ') ) - content = capture(&block) if block_given? + content = capture(&block) if block content_tag(:ul, content, html_options) end @@ -35,7 +35,7 @@ module TabHelper link_classes = %w[nav-link gl-tab-nav-item] active_link_classes = %w[active gl-tab-nav-item-active] - if block_given? + if block # Shift params to skip the omitted "name" param html_options = options options = name @@ -54,7 +54,7 @@ module TabHelper tab_class = %w[nav-item].push(*extra_tab_classes) content_tag(:li, class: tab_class) do - if block_given? + if block link_to(options, html_options, &block) else link_to(name, options, html_options) @@ -150,7 +150,7 @@ module TabHelper o[:class] = [*o[:class], klass].join(' ') o[:class].strip! - if block_given? + if block content_tag(:li, capture(&block), o) else content_tag(:li, nil, o) diff --git a/app/models/namespace.rb b/app/models/namespace.rb index e8ccb78692b..eb310845584 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -82,6 +82,8 @@ class Namespace < ApplicationRecord has_many :work_items, inverse_of: :namespace has_many :issues, inverse_of: :namespace + has_many :timelog_categories, class_name: 'TimeTracking::TimelogCategory' + validates :owner, presence: true, if: ->(n) { n.owner_required? } validates :name, presence: true, diff --git a/app/policies/namespaces/group_project_namespace_shared_policy.rb b/app/policies/namespaces/group_project_namespace_shared_policy.rb index 1ed9f05306f..bfb1706bc5a 100644 --- a/app/policies/namespaces/group_project_namespace_shared_policy.rb +++ b/app/policies/namespaces/group_project_namespace_shared_policy.rb @@ -2,8 +2,20 @@ module Namespaces class GroupProjectNamespaceSharedPolicy < ::NamespacePolicy - # Nothing here at the moment, but as we move policies from ProjectPolicy to ProjectNamespacePolicy, + # As we move policies from ProjectPolicy to ProjectNamespacePolicy, # anything common with GroupPolicy but not with UserNamespacePolicy can go in here. # See https://gitlab.com/groups/gitlab-org/-/epics/6689 + + condition(:timelog_categories_enabled, score: 0, scope: :subject) do + Feature.enabled?(:timelog_categories, @subject) + end + + rule { ~timelog_categories_enabled }.policy do + prevent :read_timelog_category + end + + rule { can?(:reporter_access) }.policy do + enable :read_timelog_category + end end end diff --git a/app/policies/namespaces/project_namespace_policy.rb b/app/policies/namespaces/project_namespace_policy.rb index 33aadc7c411..500c325138e 100644 --- a/app/policies/namespaces/project_namespace_policy.rb +++ b/app/policies/namespaces/project_namespace_policy.rb @@ -2,8 +2,8 @@ module Namespaces class ProjectNamespacePolicy < Namespaces::GroupProjectNamespaceSharedPolicy - # For now users are not granted any permissions on project namespace - # as it's completely hidden to them. When we start using project - # namespaces in queries, we will have to extend this policy. + # TODO: once https://gitlab.com/gitlab-org/gitlab/-/issues/364277 is solved, this + # should not be necessary anymore, and should be replaced with `delegate(:project)`. + delegate(:reload_project) end end diff --git a/app/policies/time_tracking/timelog_category_policy.rb b/app/policies/time_tracking/timelog_category_policy.rb new file mode 100644 index 00000000000..89161cdacfb --- /dev/null +++ b/app/policies/time_tracking/timelog_category_policy.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module TimeTracking + class TimelogCategoryPolicy < BasePolicy + delegate { @subject.namespace } + end +end diff --git a/app/services/base_count_service.rb b/app/services/base_count_service.rb index ff1949ce4dd..eff3eb33c71 100644 --- a/app/services/base_count_service.rb +++ b/app/services/base_count_service.rb @@ -45,7 +45,7 @@ class BaseCountService end def update_cache_for_key(key, &block) - Rails.cache.write(key, block_given? ? yield : uncached_count, raw: raw?) + Rails.cache.write(key, block ? yield : uncached_count, raw: raw?) end end diff --git a/app/services/error_tracking/base_service.rb b/app/services/error_tracking/base_service.rb index d2ecd0a6d5a..8458eb1f3b8 100644 --- a/app/services/error_tracking/base_service.rb +++ b/app/services/error_tracking/base_service.rb @@ -25,7 +25,7 @@ module ErrorTracking errors = parse_errors(response) return errors if errors - yield if block_given? + yield if block track_usage_event(params[:tracking_event], current_user.id) if params[:tracking_event] diff --git a/app/services/users/update_service.rb b/app/services/users/update_service.rb index c3df9b153a1..cb2711b6fee 100644 --- a/app/services/users/update_service.rb +++ b/app/services/users/update_service.rb @@ -17,7 +17,7 @@ module Users end def execute(validate: true, check_password: false, &block) - yield(@user) if block_given? + yield(@user) if block user_exists = @user.persisted? @user.user_detail # prevent assignment diff --git a/app/services/webauthn/authenticate_service.rb b/app/services/webauthn/authenticate_service.rb index a575a853995..52437a77df8 100644 --- a/app/services/webauthn/authenticate_service.rb +++ b/app/services/webauthn/authenticate_service.rb @@ -30,6 +30,8 @@ module Webauthn false end + private + ## # Validates that webauthn_credential is syntactically valid # diff --git a/config/feature_flags/development/timelog_categories.yml b/config/feature_flags/development/timelog_categories.yml new file mode 100644 index 00000000000..64bb089bc97 --- /dev/null +++ b/config/feature_flags/development/timelog_categories.yml @@ -0,0 +1,8 @@ +--- +name: timelog_categories +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88462 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365829 +milestone: '15.3' +type: development +group: group::project management +default_enabled: false diff --git a/db/post_migrate/20220728134255_update_index_vulnerabilities_common_finder.rb b/db/post_migrate/20220728134255_update_index_vulnerabilities_common_finder.rb new file mode 100644 index 00000000000..617d7661b5b --- /dev/null +++ b/db/post_migrate/20220728134255_update_index_vulnerabilities_common_finder.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class UpdateIndexVulnerabilitiesCommonFinder < Gitlab::Database::Migration[2.0] + disable_ddl_transaction! + + NEW_INDEX_NAME = 'index_vulnerabilities_common_finder_query_on_default_branch' + OLD_INDEX_NAME = 'index_vulnerabilites_common_finder_query' + + def up + add_concurrent_index :vulnerabilities, [:project_id, :state, :report_type, :present_on_default_branch, + :severity, :id], name: NEW_INDEX_NAME + + remove_concurrent_index_by_name(:vulnerabilities, OLD_INDEX_NAME) + end + + def down + add_concurrent_index :vulnerabilities, [:project_id, :state, :report_type, :severity, :id], name: OLD_INDEX_NAME + + remove_concurrent_index_by_name(:vulnerabilities, NEW_INDEX_NAME) + end +end diff --git a/db/schema_migrations/20220728134255 b/db/schema_migrations/20220728134255 new file mode 100644 index 00000000000..f5ab53d70a0 --- /dev/null +++ b/db/schema_migrations/20220728134255 @@ -0,0 +1 @@ +c868a83176c8e0024ef16e0f95d8a16a0f1b7be0c1a5d58902397cc0462a7e34 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 0af3f9a8dec..3b36e4546cd 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -30098,7 +30098,7 @@ CREATE INDEX index_vuln_reads_on_namespace_id_state_severity_and_vuln_id ON vuln CREATE INDEX index_vuln_reads_on_project_id_state_severity_and_vuln_id ON vulnerability_reads USING btree (project_id, state, severity, vulnerability_id DESC); -CREATE INDEX index_vulnerabilites_common_finder_query ON vulnerabilities USING btree (project_id, state, report_type, severity, id); +CREATE INDEX index_vulnerabilities_common_finder_query_on_default_branch ON vulnerabilities USING btree (project_id, state, report_type, present_on_default_branch, severity, id); CREATE INDEX index_vulnerabilities_on_author_id ON vulnerabilities USING btree (author_id); diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index e50f9170a9d..ddafa3e086d 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -8925,6 +8925,29 @@ The edge type for [`TestSuiteSummary`](#testsuitesummary). | `cursor` | [`String!`](#string) | A cursor for use in pagination. | | `node` | [`TestSuiteSummary`](#testsuitesummary) | The item at the end of the edge. | +#### `TimeTrackingTimelogCategoryConnection` + +The connection type for [`TimeTrackingTimelogCategory`](#timetrackingtimelogcategory). + +##### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `edges` | [`[TimeTrackingTimelogCategoryEdge]`](#timetrackingtimelogcategoryedge) | A list of edges. | +| `nodes` | [`[TimeTrackingTimelogCategory]`](#timetrackingtimelogcategory) | A list of nodes. | +| `pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. | + +#### `TimeTrackingTimelogCategoryEdge` + +The edge type for [`TimeTrackingTimelogCategory`](#timetrackingtimelogcategory). + +##### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `cursor` | [`String!`](#string) | A cursor for use in pagination. | +| `node` | [`TimeTrackingTimelogCategory`](#timetrackingtimelogcategory) | The item at the end of the edge. | + #### `TimelineEventTypeConnection` The connection type for [`TimelineEventType`](#timelineeventtype). @@ -12157,6 +12180,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | `storageSizeLimit` | [`Float`](#float) | Total storage limit of the root namespace in bytes. | | `subgroupCreationLevel` | [`String`](#string) | Permission level required to create subgroups within the group. | | `temporaryStorageIncreaseEndsOn` | [`Time`](#time) | Date until the temporary storage increase is active. | +| `timelogCategories` | [`TimeTrackingTimelogCategoryConnection`](#timetrackingtimelogcategoryconnection) | Timelog categories for the namespace. Available only when feature flag `timelog_categories` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. (see [Connections](#connections)) | | `totalRepositorySize` | [`Float`](#float) | Total repository size of all projects in the root namespace in bytes. | | `totalRepositorySizeExcess` | [`Float`](#float) | Total excess repository size of all projects in the root namespace in bytes. | | `twoFactorGracePeriod` | [`Int`](#int) | Time before two-factor authentication is enforced. | @@ -14727,6 +14751,7 @@ Contains statistics about a milestone. | `sharedRunnersSetting` | [`SharedRunnersSetting`](#sharedrunnerssetting) | Shared runners availability for the namespace and its descendants. | | `storageSizeLimit` | [`Float`](#float) | Total storage limit of the root namespace in bytes. | | `temporaryStorageIncreaseEndsOn` | [`Time`](#time) | Date until the temporary storage increase is active. | +| `timelogCategories` | [`TimeTrackingTimelogCategoryConnection`](#timetrackingtimelogcategoryconnection) | Timelog categories for the namespace. Available only when feature flag `timelog_categories` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. (see [Connections](#connections)) | | `totalRepositorySize` | [`Float`](#float) | Total repository size of all projects in the root namespace in bytes. | | `totalRepositorySizeExcess` | [`Float`](#float) | Total excess repository size of all projects in the root namespace in bytes. | | `visibility` | [`String`](#string) | Visibility of the namespace. | @@ -15493,6 +15518,7 @@ Represents vulnerability finding of a security report on the pipeline. | `suggestionCommitMessage` | [`String`](#string) | Commit message used to apply merge request suggestions. | | `tagList` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.12. Use `topics`. | | `terraformStates` | [`TerraformStateConnection`](#terraformstateconnection) | Terraform states associated with the project. (see [Connections](#connections)) | +| `timelogCategories` | [`TimeTrackingTimelogCategoryConnection`](#timetrackingtimelogcategoryconnection) | Timelog categories for the project. Available only when feature flag `timelog_categories` is enabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. (see [Connections](#connections)) | | `topics` | [`[String!]`](#string) | List of project topics. | | `userPermissions` | [`ProjectPermissions!`](#projectpermissions) | Permissions for the current user on the resource. | | `visibility` | [`String`](#string) | Visibility of the project. | @@ -17733,6 +17759,21 @@ Represents the time report stats for timeboxes. | `incomplete` | [`TimeboxMetrics`](#timeboxmetrics) | Incomplete issues metrics. | | `total` | [`TimeboxMetrics`](#timeboxmetrics) | Total issues metrics. | +### `TimeTrackingTimelogCategory` + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `billable` | [`Boolean`](#boolean) | Whether the category is billable or not. | +| `billingRate` | [`Float`](#float) | Billing rate for the category. | +| `color` | [`Color`](#color) | Color assigned to the category. | +| `createdAt` | [`Time!`](#time) | When the category was created. | +| `description` | [`String`](#string) | Description of the category. | +| `id` | [`ID!`](#id) | Internal ID of the timelog category. | +| `name` | [`String!`](#string) | Name of the category. | +| `updatedAt` | [`Time!`](#time) | When the category was last updated. | + ### `TimeboxMetrics` Represents measured stats metrics for timeboxes. diff --git a/doc/user/admin_area/monitoring/background_migrations.md b/doc/user/admin_area/monitoring/background_migrations.md index 02d32099c63..87374849674 100644 --- a/doc/user/admin_area/monitoring/background_migrations.md +++ b/doc/user/admin_area/monitoring/background_migrations.md @@ -48,6 +48,50 @@ To disable it: Feature.disable(:execute_batched_migrations_on_schedule) ``` +### Pause batched background migrations in GitLab 14.x + +To pause an ongoing batched background migration, use the `disable` command above. +This command causes the migration to complete the current batch, and then wait to start the next batch. + +Use the following database queries to see the state of the current batched background migration: + +1. Obtain the ID of the running migration: + + ```sql + SELECT + id job_class_name, + table_name, + column_name, + job_arguments + FROM batched_background_migrations + WHERE status <> 3; + ``` + +1. Run this query, replacing `XX` with the ID you obtained in the previous step, + to see the status of the migration: + + ```sql + SELECT + started_at, + finished_at, + finished_at - started_at AS duration, + min_value, + max_value, + batch_size, + sub_batch_size + FROM batched_background_migration_jobs + WHERE batched_background_migration_id = XX + ORDER BY id DESC + limit 10; + ``` + +1. Run the query multiple times within a few minutes to ensure no new row has been added. + If no new row has been added, the migration has been paused. + +1. After confirming the migration has paused, restart the migration (using the `enable` + command above) to proceed with the batch when ready. On larger instances, + background migrations can take as long as 48 hours to complete each batch. + ## Automatic batch size optimization > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/60133) in GitLab 13.12. diff --git a/doc/user/infrastructure/clusters/manage/management_project_applications/prometheus.md b/doc/user/infrastructure/clusters/manage/management_project_applications/prometheus.md index 383e857bb20..64d325dedc6 100644 --- a/doc/user/infrastructure/clusters/manage/management_project_applications/prometheus.md +++ b/doc/user/infrastructure/clusters/manage/management_project_applications/prometheus.md @@ -1,27 +1,11 @@ --- -stage: Monitor -group: Respond -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +redirect_to: '../../../../../operations/metrics/index.md' +remove_date: '2022-11-03' --- -# Install Prometheus with a cluster management project **(FREE)** +This document was moved to [another location](../../../../../operations/metrics/index.md). -> [Introduced](https://gitlab.com/gitlab-org/project-templates/cluster-management/-/merge_requests/5) in GitLab 14.0. - -[Prometheus](https://prometheus.io/docs/introduction/overview/) is an -open-source monitoring and alerting system for supervising your -deployed applications. - -Assuming you already have a project created from a -[management project template](../../../../../user/clusters/management_project_template.md), to install Prometheus you should -uncomment this line from your `helmfile.yaml`: - -```yaml - - path: applications/prometheus/helmfile.yaml -``` - -You can customize the installation of Prometheus by updating the -`applications/prometheus/values.yaml` file in your cluster -management project. Refer to the -[Configuration section](https://github.com/helm/charts/tree/master/stable/prometheus#configuration) -of the Prometheus chart's README for the available configuration options. + + + + diff --git a/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md b/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md index d2d314b649e..f42e9c83120 100644 --- a/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md +++ b/doc/user/infrastructure/clusters/manage/management_project_applications/sentry.md @@ -1,70 +1,11 @@ --- -stage: Monitor -group: Respond -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +redirect_to: '../../../../../operations/error_tracking.md' +remove_date: '2022-11-03' --- -# Install Sentry with a cluster management project **(FREE)** +This document was moved to [another location](../../../../../operations/error_tracking.md). -> [Introduced](https://gitlab.com/gitlab-org/project-templates/cluster-management/-/merge_requests/5) in GitLab 14.0. - -The Sentry Helm chart [recommends](https://github.com/helm/charts/blob/f6e5784f265dd459c5a77430185d0302ed372665/stable/sentry/values.yaml#L284-L285) -at least 3 GB of available RAM for database migrations. - -Assuming you already have a project created from a -[management project template](../../../../../user/clusters/management_project_template.md), to install Sentry you should -uncomment this line from your `helmfile.yaml`: - -```yaml - - path: applications/sentry/helmfile.yaml -``` - -Sentry is installed by default into the `gitlab-managed-apps` namespace -of your cluster. - -You can customize the installation of Sentry by defining -`applications/sentry/values.yaml` file in your cluster -management project. Refer to the -[chart](https://github.com/helm/charts/tree/master/stable/sentry) -for the available configuration options. - -We recommend you pay close attention to the following configuration options: - -- `email`. Needed to invite users to your Sentry instance and to send error emails. -- `user`. Where you can set the login credentials for the default administrator user. -- `postgresql`. For a PostgreSQL password that can be used when running future updates. - -When upgrading, it's important to provide the existing PostgreSQL password (given -using the `postgresql.postgresqlPassword` key) to avoid authentication errors. -Read the [PostgreSQL chart documentation](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) -for more information. - -Here is an example configuration for Sentry: - -```yaml -# Admin user to create -user: - # Indicated to create the admin user or not, - # Default is true as the initial installation. - create: true - email: "" - password: "" - -email: - from_address: "" - host: smtp - port: 25 - use_tls: false - user: "" - password: "" - enable_replies: false - -ingress: - enabled: true - hostname: "" - -# Needs to be here between runs. -# See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more info -postgresql: - postgresqlPassword: example-postgresql-password -``` + + + + diff --git a/lib/bulk_imports/clients/http.rb b/lib/bulk_imports/clients/http.rb index 037da5e0816..3e940742de9 100644 --- a/lib/bulk_imports/clients/http.rb +++ b/lib/bulk_imports/clients/http.rb @@ -35,7 +35,7 @@ module BulkImports end def each_page(method, resource, query = {}, &block) - return to_enum(__method__, method, resource, query) unless block_given? + return to_enum(__method__, method, resource, query) unless block next_page = @page diff --git a/lib/gitlab/batch_pop_queueing.rb b/lib/gitlab/batch_pop_queueing.rb index 62fc8cd048e..103ce644f2b 100644 --- a/lib/gitlab/batch_pop_queueing.rb +++ b/lib/gitlab/batch_pop_queueing.rb @@ -73,7 +73,7 @@ module Gitlab begin all_args = pop_all - yield all_args if block_given? + yield all_args if block { status: :finished, new_items: peek_all } ensure diff --git a/lib/gitlab/cache/request_cache.rb b/lib/gitlab/cache/request_cache.rb index 3ad919fbba8..13b4cace08a 100644 --- a/lib/gitlab/cache/request_cache.rb +++ b/lib/gitlab/cache/request_cache.rb @@ -15,7 +15,7 @@ module Gitlab attr_accessor :request_cache_key_block def request_cache_key(&block) - if block_given? + if block self.request_cache_key_block = block else request_cache_key_block diff --git a/lib/gitlab/ci/trace/chunked_io.rb b/lib/gitlab/ci/trace/chunked_io.rb index 9f24ba99201..32f64948635 100644 --- a/lib/gitlab/ci/trace/chunked_io.rb +++ b/lib/gitlab/ci/trace/chunked_io.rb @@ -22,7 +22,7 @@ module Gitlab @chunks_cache = [] @tell = 0 @size = calculate_size - yield self if block_given? + yield self if block end def close diff --git a/lib/gitlab/database/bulk_update.rb b/lib/gitlab/database/bulk_update.rb index b1f9da30585..d68be19047e 100644 --- a/lib/gitlab/database/bulk_update.rb +++ b/lib/gitlab/database/bulk_update.rb @@ -157,7 +157,7 @@ module Gitlab def self.execute(columns, mapping, &to_class) raise ArgumentError if mapping.blank? - entries_by_class = mapping.group_by { |k, v| block_given? ? to_class.call(k) : k.class } + entries_by_class = mapping.group_by { |k, v| to_class ? to_class.call(k) : k.class } entries_by_class.each do |model, entries| Setter.new(model, columns, entries).update! diff --git a/lib/gitlab/database/with_lock_retries.rb b/lib/gitlab/database/with_lock_retries.rb index f2c5bb9088f..3206c5626c3 100644 --- a/lib/gitlab/database/with_lock_retries.rb +++ b/lib/gitlab/database/with_lock_retries.rb @@ -83,7 +83,7 @@ module Gitlab # @param [Boolean] raise_on_exhaustion whether to raise `AttemptsExhaustedError` when exhausting max attempts # @param [Proc] block of code that will be executed def run(raise_on_exhaustion: false, &block) - raise 'no block given' unless block_given? + raise 'no block given' unless block @block = block diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index d2495b32800..11a41149274 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -107,7 +107,7 @@ module Gitlab # # rubocop: disable GitlabSecurity/PublicSend def each_page(method, *args, &block) - return to_enum(__method__, method, *args) unless block_given? + return to_enum(__method__, method, *args) unless block page = if args.last.is_a?(Hash) && args.last[:page] @@ -134,7 +134,7 @@ module Gitlab # method - The method to send to Octokit for querying data. # args - Any arguments to pass to the Octokit method. def each_object(method, *args, &block) - return to_enum(__method__, method, *args) unless block_given? + return to_enum(__method__, method, *args) unless block each_page(method, *args) do |page| page.objects.each do |object| diff --git a/lib/gitlab/legacy_github_import/client.rb b/lib/gitlab/legacy_github_import/client.rb index 7a9dae3a3de..7d78c8dee25 100644 --- a/lib/gitlab/legacy_github_import/client.rb +++ b/lib/gitlab/legacy_github_import/client.rb @@ -136,7 +136,7 @@ module Gitlab last_response = api.last_response - if block_given? + if block yield data # api.last_response could change while we're yielding (e.g. fetching labels for each PR) # so we cache our own last response diff --git a/lib/gitlab/metrics/methods/metric_options.rb b/lib/gitlab/metrics/methods/metric_options.rb index 1e488df3e99..e93a90415c7 100644 --- a/lib/gitlab/metrics/methods/metric_options.rb +++ b/lib/gitlab/metrics/methods/metric_options.rb @@ -61,7 +61,7 @@ module Gitlab end def evaluate(&block) - instance_eval(&block) if block_given? + instance_eval(&block) if block self end diff --git a/lib/gitlab/null_request_store.rb b/lib/gitlab/null_request_store.rb index 8db331dcb9f..4642dcf9e91 100644 --- a/lib/gitlab/null_request_store.rb +++ b/lib/gitlab/null_request_store.rb @@ -35,7 +35,7 @@ module Gitlab end def delete(key, &block) - yield(key) if block_given? + yield(key) if block end end end diff --git a/lib/gitlab/quick_actions/dsl.rb b/lib/gitlab/quick_actions/dsl.rb index a2dfcc6de9a..dfbc00ef847 100644 --- a/lib/gitlab/quick_actions/dsl.rb +++ b/lib/gitlab/quick_actions/dsl.rb @@ -30,11 +30,11 @@ module Gitlab # # Awesome code block # end def desc(text = '', &block) - @description = block_given? ? block : text + @description = block || text end def warning(text = '', &block) - @warning = block_given? ? block : text + @warning = block || text end def icon(string = '') @@ -51,7 +51,7 @@ module Gitlab # # Awesome code block # end def params(*params, &block) - @params = block_given? ? block : params + @params = block || params end # Allows to give an explanation of what the command will do when @@ -67,7 +67,7 @@ module Gitlab # # Awesome code block # end def explanation(text = '', &block) - @explanation = block_given? ? block : text + @explanation = block || text end # Allows to provide a message about quick action execution result, success or failure. @@ -96,7 +96,7 @@ module Gitlab # end # def execution_message(text = '', &block) - @execution_message = block_given? ? block : text + @execution_message = block || text end # Allows to define type(s) that must be met in order for the command diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb index 94f06e957cf..cdd2ac6100e 100644 --- a/lib/gitlab/redis/multi_store.rb +++ b/lib/gitlab/redis/multi_store.rb @@ -274,7 +274,7 @@ module Gitlab # rubocop:disable GitlabSecurity/PublicSend def send_command(redis_instance, command_name, *args, **kwargs, &block) - if block_given? + if block # Make sure that block is wrapped and executed only on the redis instance that is executing the block redis_instance.send(command_name, *args, **kwargs) do |*params| with_instance(redis_instance, *params, &block) diff --git a/lib/gitlab/safe_request_loader.rb b/lib/gitlab/safe_request_loader.rb index 89eca16c272..4fc88322210 100644 --- a/lib/gitlab/safe_request_loader.rb +++ b/lib/gitlab/safe_request_loader.rb @@ -14,7 +14,7 @@ module Gitlab end def execute(&block) - raise ArgumentError, 'Block is mandatory' unless block_given? + raise ArgumentError, 'Block is mandatory' unless block load_resource_data remove_loaded_resource_ids diff --git a/lib/gitlab/search/query.rb b/lib/gitlab/search/query.rb index 97ee7c7817d..4c5fae87420 100644 --- a/lib/gitlab/search/query.rb +++ b/lib/gitlab/search/query.rb @@ -13,7 +13,7 @@ module Gitlab @filters = [] @filter_options = { default_parser: :downcase.to_proc }.merge(filter_opts) - self.instance_eval(&block) if block_given? + self.instance_eval(&block) if block @query = Gitlab::Search::ParsedQuery.new(*extract_filters) # set the ParsedQuery as our default delegator thanks to SimpleDelegator diff --git a/lib/gitlab/string_placeholder_replacer.rb b/lib/gitlab/string_placeholder_replacer.rb index 62621255a53..f77bd8e2d9f 100644 --- a/lib/gitlab/string_placeholder_replacer.rb +++ b/lib/gitlab/string_placeholder_replacer.rb @@ -10,7 +10,7 @@ module Gitlab # placeholder will be returned. def self.replace_string_placeholders(string, placeholder_regex = nil, &block) - return string if string.blank? || placeholder_regex.blank? || !block_given? + return string if string.blank? || placeholder_regex.blank? || !block replace_placeholders(string, placeholder_regex, &block) end diff --git a/lib/gitlab/terraform/state_migration_helper.rb b/lib/gitlab/terraform/state_migration_helper.rb index 04c1cbd0373..e86144f91a5 100644 --- a/lib/gitlab/terraform/state_migration_helper.rb +++ b/lib/gitlab/terraform/state_migration_helper.rb @@ -22,7 +22,7 @@ module Gitlab versions.find_each(batch_size: batch_size) do |version| # rubocop:disable CodeReuse/ActiveRecord version.file.migrate!(store) - yield version if block_given? + yield version if block end end end diff --git a/lib/gitlab/usage/metrics/instrumentations/base_metric.rb b/lib/gitlab/usage/metrics/instrumentations/base_metric.rb index f76ed1753b2..5e20766b1b4 100644 --- a/lib/gitlab/usage/metrics/instrumentations/base_metric.rb +++ b/lib/gitlab/usage/metrics/instrumentations/base_metric.rb @@ -13,7 +13,7 @@ module Gitlab class << self def available?(&block) - return @metric_available = block if block_given? + return @metric_available = block if block return @metric_available.call if instance_variable_defined?('@metric_available') diff --git a/lib/gitlab/usage/metrics/instrumentations/database_metric.rb b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb index 9ea5ba12b69..6dec0349a38 100644 --- a/lib/gitlab/usage/metrics/instrumentations/database_metric.rb +++ b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb @@ -23,25 +23,25 @@ module Gitlab private_constant :IMPLEMENTED_OPERATIONS def start(&block) - return @metric_start&.call unless block_given? + return @metric_start&.call unless block @metric_start = block end def finish(&block) - return @metric_finish&.call unless block_given? + return @metric_finish&.call unless block @metric_finish = block end def relation(&block) - return @metric_relation&.call unless block_given? + return @metric_relation&.call unless block @metric_relation = block end def metric_options(&block) - return @metric_options&.call.to_h unless block_given? + return @metric_options&.call.to_h unless block @metric_options = block end @@ -55,7 +55,7 @@ module Gitlab @metric_operation = symbol @column = column - @metric_operation_block = block if block_given? + @metric_operation_block = block if block end def cache_start_and_finish_as(cache_key) diff --git a/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb b/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb index 8504ee368fc..3b20e6ad100 100644 --- a/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb +++ b/lib/gitlab/usage/metrics/instrumentations/numbers_metric.rb @@ -26,7 +26,7 @@ module Gitlab private_constant :IMPLEMENTED_OPERATIONS def data(&block) - return @metric_data&.call unless block_given? + return @metric_data&.call unless block @metric_data = block end diff --git a/lib/gitlab/usage_data_queries.rb b/lib/gitlab/usage_data_queries.rb index fef5cd680cb..c2983779603 100644 --- a/lib/gitlab/usage_data_queries.rb +++ b/lib/gitlab/usage_data_queries.rb @@ -53,7 +53,7 @@ module Gitlab end def alt_usage_data(value = nil, fallback: FALLBACK, &block) - if block_given? + if block { alt_usage_data_block: "non-SQL usage data block" } else { alt_usage_data_value: value } @@ -61,7 +61,7 @@ module Gitlab end def redis_usage_data(counter = nil, &block) - if block_given? + if block { redis_usage_data_block: "non-SQL usage data block" } elsif counter.present? { redis_usage_data_counter: counter.to_s } diff --git a/lib/gitlab/utils/usage_data.rb b/lib/gitlab/utils/usage_data.rb index 4d1b234ae54..19bdeefed7e 100644 --- a/lib/gitlab/utils/usage_data.rb +++ b/lib/gitlab/utils/usage_data.rb @@ -196,7 +196,7 @@ module Gitlab def alt_usage_data(value = nil, fallback: FALLBACK, &block) with_duration do - if block_given? + if block yield else value @@ -209,7 +209,7 @@ module Gitlab def redis_usage_data(counter = nil, &block) with_duration do - if block_given? + if block redis_usage_counter(&block) elsif counter.present? redis_usage_data_totals(counter) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a3cef05e0a9..6ca4f353dda 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -16895,6 +16895,9 @@ msgstr "" msgid "Geo|%{component} verified" msgstr "" +msgid "Geo|%{label} %{timeAgo}" +msgstr "" + msgid "Geo|%{label} can't be blank" msgstr "" @@ -23016,9 +23019,6 @@ msgstr "" msgid "Last sign-in at:" msgstr "" -msgid "Last successful sync" -msgstr "" - msgid "Last successful update" msgstr "" @@ -26432,9 +26432,6 @@ msgstr "" msgid "Normal text" msgstr "" -msgid "Not Implemented" -msgstr "" - msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser." msgstr "" diff --git a/package.json b/package.json index 9bb0cb98a05..578689e4ed1 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "lowlight": "^2.6.1", "marked": "^0.3.12", "mathjax": "3", - "mermaid": "^9.1.1", + "mermaid": "^9.1.3", "micromatch": "^4.0.5", "minimatch": "^3.0.4", "monaco-editor": "^0.28.0", diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb index fa17b8fe302..6a6396b8ed4 100644 --- a/qa/qa/page/view.rb +++ b/qa/qa/page/view.rb @@ -37,7 +37,7 @@ module QA def self.evaluate(&block) Page::View::DSL.new.tap do |evaluator| - evaluator.instance_exec(&block) if block_given? + evaluator.instance_exec(&block) if block end end diff --git a/spec/graphql/types/namespace_type_spec.rb b/spec/graphql/types/namespace_type_spec.rb index 3b7f7e65e4b..168a6ba4eaa 100644 --- a/spec/graphql/types/namespace_type_spec.rb +++ b/spec/graphql/types/namespace_type_spec.rb @@ -9,6 +9,7 @@ RSpec.describe GitlabSchema.types['Namespace'] do expected_fields = %w[ id name path full_name full_path description description_html visibility lfs_enabled request_access_enabled projects root_storage_statistics shared_runners_setting + timelog_categories ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 6b769230d92..fbb3aca3376 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -36,8 +36,7 @@ RSpec.describe GitlabSchema.types['Project'] do pipeline_analytics squash_read_only sast_ci_configuration cluster_agent cluster_agents agent_configurations ci_template timelogs merge_commit_template squash_commit_template work_item_types - recent_issue_boards ci_config_path_or_default packages_cleanup_policy ci_variables - recent_issue_boards ci_config_path_or_default ci_variables + recent_issue_boards ci_config_path_or_default packages_cleanup_policy ci_variables timelog_categories ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/graphql/types/time_tracking/timelog_category_type_spec.rb b/spec/graphql/types/time_tracking/timelog_category_type_spec.rb new file mode 100644 index 00000000000..a14069e8b58 --- /dev/null +++ b/spec/graphql/types/time_tracking/timelog_category_type_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['TimeTrackingTimelogCategory'] do + let(:fields) do + %w[ + id + name + description + color + billable + billing_rate + created_at + updated_at + ] + end + + it { expect(described_class.graphql_name).to eq('TimeTrackingTimelogCategory') } + it { expect(described_class).to have_graphql_fields(fields) } + it { expect(described_class).to require_graphql_authorizations(:read_timelog_category) } +end diff --git a/spec/lib/api/helpers/authentication_spec.rb b/spec/lib/api/helpers/authentication_spec.rb index eea5c10d4f8..ac5886fdadd 100644 --- a/spec/lib/api/helpers/authentication_spec.rb +++ b/spec/lib/api/helpers/authentication_spec.rb @@ -34,7 +34,7 @@ RSpec.describe API::Helpers::Authentication do class << cls def helpers(*modules, &block) modules.each { |m| include m } - include Module.new.tap { |m| m.class_eval(&block) } if block_given? + include Module.new.tap { |m| m.class_eval(&block) } if block end end diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb index 5167523ff58..5af234ff88e 100644 --- a/spec/lib/gitlab/slash_commands/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb @@ -165,7 +165,7 @@ RSpec.describe Gitlab::SlashCommands::Deploy do context 'with ReDoS attempts' do def duration_for(&block) start = Time.zone.now - yield if block_given? + yield if block Time.zone.now - start end diff --git a/spec/models/namespaces/project_namespace_spec.rb b/spec/models/namespaces/project_namespace_spec.rb index c995571c3c9..78403db7fa8 100644 --- a/spec/models/namespaces/project_namespace_spec.rb +++ b/spec/models/namespaces/project_namespace_spec.rb @@ -5,6 +5,14 @@ require 'spec_helper' RSpec.describe Namespaces::ProjectNamespace, type: :model do describe 'relationships' do it { is_expected.to have_one(:project).with_foreign_key(:project_namespace_id).inverse_of(:project_namespace) } + + specify do + project = create(:project) + namespace = project.project_namespace + namespace.reload_project + + expect(namespace.project).to eq project + end end describe 'validations' do diff --git a/spec/models/u2f_registration_spec.rb b/spec/models/u2f_registration_spec.rb index 027d26d9657..1fab3882c2a 100644 --- a/spec/models/u2f_registration_spec.rb +++ b/spec/models/u2f_registration_spec.rb @@ -6,21 +6,67 @@ RSpec.describe U2fRegistration do let_it_be(:user) { create(:user) } let(:u2f_registration_name) { 'u2f_device' } - let(:u2f_registration) do - device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5)) - create( - :u2f_registration, name: u2f_registration_name, - user: user, - certificate: Base64.strict_encode64(device.cert_raw), - key_handle: U2F.urlsafe_encode64(device.key_handle_raw), - public_key: Base64.strict_encode64(device.origin_public_key_raw) - ) + let(:app_id) { FFaker::BaconIpsum.characters(5) } + let(:device) { U2F::FakeU2F.new(app_id) } + + describe '.authenticate' do + context 'when registration is found' do + it 'returns true' do + create_u2f_registration + device_challenge = U2F.urlsafe_encode64(SecureRandom.random_bytes(32)) + sign_response_json = device.sign_response(device_challenge) + + response = U2fRegistration.authenticate( + user, + app_id, + sign_response_json, + device_challenge + ) + + expect(response).to eq true + end + end + + context 'when registration not found' do + it 'returns nil' do + device_challenge = U2F.urlsafe_encode64(SecureRandom.random_bytes(32)) + sign_response_json = device.sign_response(device_challenge) + + # data is valid but user does not have any u2f_registrations + response = U2fRegistration.authenticate( + user, + app_id, + sign_response_json, + device_challenge + ) + + expect(response).to eq nil + end + end + + context 'when args passed in are invalid' do + it 'returns false' do + some_app_id = 123 + invalid_json = 'invalid JSON' + challenges = 'whatever' + + response = U2fRegistration.authenticate( + user, + some_app_id, + invalid_json, + challenges + ) + + expect(response).to eq false + end + end end describe 'callbacks' do describe 'after create' do shared_examples_for 'creates webauthn registration' do it 'creates webauthn registration' do + u2f_registration = create_u2f_registration webauthn_registration = WebauthnRegistration.where(u2f_registration_id: u2f_registration.id) expect(webauthn_registration).to exist end @@ -51,13 +97,14 @@ RSpec.describe U2fRegistration do receive(:track_exception).with(kind_of(StandardError), u2f_registration_id: 123)) - u2f_registration + create_u2f_registration end end describe 'after update' do context 'when counter is updated' do it 'updates the webauthn registration counter to be the same value' do + u2f_registration = create_u2f_registration new_counter = u2f_registration.counter + 1 webauthn_registration = WebauthnRegistration.find_by(u2f_registration_id: u2f_registration.id) @@ -70,6 +117,7 @@ RSpec.describe U2fRegistration do context 'when sign count of registration is not updated' do it 'does not update the counter' do + u2f_registration = create_u2f_registration webauthn_registration = WebauthnRegistration.find_by(u2f_registration_id: u2f_registration.id) expect do @@ -79,4 +127,15 @@ RSpec.describe U2fRegistration do end end end + + def create_u2f_registration + create( + :u2f_registration, + name: u2f_registration_name, + user: user, + certificate: Base64.strict_encode64(device.cert_raw), + key_handle: U2F.urlsafe_encode64(device.key_handle_raw), + public_key: Base64.strict_encode64(device.origin_public_key_raw) + ) + end end diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index c513baea517..57923142648 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -1229,4 +1229,12 @@ RSpec.describe GroupPolicy do it { is_expected.to be_disallowed(:admin_crm_contact) } it { is_expected.to be_disallowed(:admin_crm_organization) } end + + it_behaves_like 'checks timelog categories permissions' do + let(:group) { create(:group) } + let(:namespace) { group } + let(:users_container) { group } + + subject { described_class.new(current_user, group) } + end end diff --git a/spec/policies/namespaces/project_namespace_policy_spec.rb b/spec/policies/namespaces/project_namespace_policy_spec.rb index 5ceea9dfb9d..4519f44a6ad 100644 --- a/spec/policies/namespaces/project_namespace_policy_spec.rb +++ b/spec/policies/namespaces/project_namespace_policy_spec.rb @@ -3,45 +3,11 @@ require 'spec_helper' RSpec.describe Namespaces::ProjectNamespacePolicy do - let_it_be(:parent) { create(:namespace) } - let_it_be(:project) { create(:project, namespace: parent) } - let_it_be(:namespace) { project.project_namespace } - - let(:permissions) do - [:owner_access, :create_projects, :admin_namespace, :read_namespace, - :read_statistics, :transfer_projects, :admin_package, - :create_jira_connect_subscription] - end - subject { described_class.new(current_user, namespace) } - context 'with no user' do - let_it_be(:current_user) { nil } - - it { is_expected.to be_disallowed(*permissions) } - end - - context 'regular user' do - let_it_be(:current_user) { create(:user) } - - it { is_expected.to be_disallowed(*permissions) } - end - - context 'parent owner' do - let_it_be(:current_user) { parent.first_owner } - - it { is_expected.to be_disallowed(*permissions) } - end - - context 'admin' do - let_it_be(:current_user) { create(:admin) } - - context 'when admin mode is enabled', :enable_admin_mode do - it { is_expected.to be_disallowed(*permissions) } - end - - context 'when admin mode is disabled' do - it { is_expected.to be_disallowed(*permissions) } - end + it_behaves_like 'checks timelog categories permissions' do + let(:project) { create(:project) } + let(:namespace) { project.project_namespace } + let(:users_container) { project } end end diff --git a/spec/requests/api/graphql/group_query_spec.rb b/spec/requests/api/graphql/group_query_spec.rb index fd0ee5d52b9..41750f44794 100644 --- a/spec/requests/api/graphql/group_query_spec.rb +++ b/spec/requests/api/graphql/group_query_spec.rb @@ -122,6 +122,75 @@ RSpec.describe 'getting group information' do end end + context 'with timelog categories' do + let_it_be(:group) { create(:group) } + let_it_be(:timelog_category) { create(:timelog_category, namespace: group, name: 'TimelogCategoryTest') } + + context 'when user is guest' do + it 'includes empty timelog categories array' do + post_graphql(group_query(group), current_user: user2) + + expect(graphql_data_at(:group, :timelogCategories, :nodes)).to match([]) + end + end + + context 'when user has reporter role' do + before do + group.add_reporter(user2) + end + + it 'returns the timelog category with all its fields' do + post_graphql(group_query(group), current_user: user2) + + expect(graphql_data_at(:group, :timelogCategories, :nodes)) + .to contain_exactly(a_graphql_entity_for(timelog_category)) + end + end + + context 'for N+1 queries' do + let!(:group1) { create(:group) } + let!(:group2) { create(:group) } + + before do + group1.add_reporter(user2) + group2.add_reporter(user2) + end + + it 'avoids N+1 database queries' do + pending('See: https://gitlab.com/gitlab-org/gitlab/-/issues/369396') + + ctx = { current_user: user2 } + + baseline_query = <<~GQL + query { + a: group(fullPath: "#{group1.full_path}") { ... g } + } + + fragment g on Group { + timelogCategories { nodes { name } } + } + GQL + + query = <<~GQL + query { + a: group(fullPath: "#{group1.full_path}") { ... g } + b: group(fullPath: "#{group2.full_path}") { ... g } + } + + fragment g on Group { + timelogCategories { nodes { name } } + } + GQL + + control = ActiveRecord::QueryRecorder.new do + run_with_clean_state(baseline_query, context: ctx) + end + + expect { run_with_clean_state(query, context: ctx) }.not_to exceed_query_limit(control) + end + end + end + context "when authenticated as admin" do it "returns any existing group" do post_graphql(group_query(private_group), current_user: admin) diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb index 310a8e9fa33..298462268fc 100644 --- a/spec/requests/api/graphql/project_query_spec.rb +++ b/spec/requests/api/graphql/project_query_spec.rb @@ -190,4 +190,88 @@ RSpec.describe 'getting project information' do end end end + + context 'with timelog categories' do + let_it_be(:timelog_category) do + create(:timelog_category, namespace: project.project_namespace, name: 'TimelogCategoryTest') + end + + let(:project_fields) do + <<~GQL + timelogCategories { + nodes { + #{all_graphql_fields_for('TimeTrackingTimelogCategory')} + } + } + GQL + end + + context 'when user is guest and the project is public' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + end + + it 'includes empty timelog categories array' do + post_graphql(query, current_user: current_user) + + expect(graphql_data_at(:project, :timelogCategories, :nodes)).to match([]) + end + end + + context 'when user has reporter role' do + before do + project.add_reporter(current_user) + end + + it 'returns the timelog category with all its fields' do + post_graphql(query, current_user: current_user) + + expect(graphql_data_at(:project, :timelogCategories, :nodes)) + .to contain_exactly(a_graphql_entity_for(timelog_category)) + end + end + + context 'for N+1 queries' do + let!(:project1) { create(:project) } + let!(:project2) { create(:project) } + + before do + project1.add_reporter(current_user) + project2.add_reporter(current_user) + end + + it 'avoids N+1 database queries' do + pending('See: https://gitlab.com/gitlab-org/gitlab/-/issues/369396') + + ctx = { current_user: current_user } + + baseline_query = <<~GQL + query { + a: project(fullPath: "#{project1.full_path}") { ... p } + } + + fragment p on Project { + timelogCategories { nodes { name } } + } + GQL + + query = <<~GQL + query { + a: project(fullPath: "#{project1.full_path}") { ... p } + b: project(fullPath: "#{project2.full_path}") { ... p } + } + + fragment p on Project { + timelogCategories { nodes { name } } + } + GQL + + control = ActiveRecord::QueryRecorder.new do + run_with_clean_state(baseline_query, context: ctx) + end + + expect { run_with_clean_state(query, context: ctx) }.not_to exceed_query_limit(control) + end + end + end end diff --git a/spec/services/webauthn/authenticate_service_spec.rb b/spec/services/webauthn/authenticate_service_spec.rb index 61f64f24f5e..b40f9465b63 100644 --- a/spec/services/webauthn/authenticate_service_spec.rb +++ b/spec/services/webauthn/authenticate_service_spec.rb @@ -30,19 +30,28 @@ RSpec.describe Webauthn::AuthenticateService do get_result['clientExtensionResults'] = {} service = Webauthn::AuthenticateService.new(user, get_result.to_json, challenge) - expect(service.execute).to be_truthy + expect(service.execute).to eq true end - it 'returns false if the response is valid but no matching stored credential is present' do - other_client = WebAuthn::FakeClient.new(origin) - other_client.create(challenge: challenge) # rubocop:disable Rails/SaveBang + context 'when response is valid but no matching stored credential is present' do + it 'returns false' do + other_client = WebAuthn::FakeClient.new(origin) + other_client.create(challenge: challenge) # rubocop:disable Rails/SaveBang - get_result = other_client.get(challenge: challenge) + get_result = other_client.get(challenge: challenge) - get_result['clientExtensionResults'] = {} - service = Webauthn::AuthenticateService.new(user, get_result.to_json, challenge) + get_result['clientExtensionResults'] = {} + service = Webauthn::AuthenticateService.new(user, get_result.to_json, challenge) - expect(service.execute).to be_falsey + expect(service.execute).to eq false + end + end + + context 'when device response includes invalid json' do + it 'returns false' do + service = Webauthn::AuthenticateService.new(user, 'invalid JSON', '') + expect(service.execute).to eq false + end end end end diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index d0a1941817a..9ff59d4b6f3 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -307,14 +307,14 @@ module GraphqlHelpers end def graphql_mutation(name, input, fields = nil, &block) - raise ArgumentError, 'Please pass either `fields` parameter or a block to `#graphql_mutation`, but not both.' if fields.present? && block_given? + raise ArgumentError, 'Please pass either `fields` parameter or a block to `#graphql_mutation`, but not both.' if fields.present? && block name = name.graphql_name if name.respond_to?(:graphql_name) mutation_name = GraphqlHelpers.fieldnamerize(name) input_variable_name = "$#{input_variable_name_for_mutation(name)}" mutation_field = GitlabSchema.mutation.fields[mutation_name] - fields = yield if block_given? + fields = yield if block fields ||= all_graphql_fields_for(mutation_field.type.to_type_signature) query = <<~MUTATION diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb index 01839a74e65..dd124ed9c7f 100644 --- a/spec/support/helpers/query_recorder.rb +++ b/spec/support/helpers/query_recorder.rb @@ -14,7 +14,7 @@ module ActiveRecord @skip_schema_queries = skip_schema_queries @query_recorder_debug = ENV['QUERY_RECORDER_DEBUG'] || query_recorder_debug @log_file = log_file - record(&block) if block_given? + record(&block) if block end def record(&block) diff --git a/spec/support/helpers/stub_method_calls.rb b/spec/support/helpers/stub_method_calls.rb index 45d704958ca..ccbede16563 100644 --- a/spec/support/helpers/stub_method_calls.rb +++ b/spec/support/helpers/stub_method_calls.rb @@ -44,7 +44,7 @@ module StubMethodCalls end def self.stub_method(object, method, &block) - raise ArgumentError, "Block is required" unless block_given? + raise ArgumentError, "Block is required" unless block backup_method(object, method) unless backed_up_method?(object, method) object.define_singleton_method(method, &block) diff --git a/spec/support/shared_examples/policies/group_project_namespace_policy_shared_examples.rb b/spec/support/shared_examples/policies/group_project_namespace_policy_shared_examples.rb new file mode 100644 index 00000000000..9a1f0e685be --- /dev/null +++ b/spec/support/shared_examples/policies/group_project_namespace_policy_shared_examples.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'checks timelog categories permissions' do + context 'with no user' do + let_it_be(:current_user) { nil } + + it { is_expected.to be_disallowed(:read_timelog_category) } + end + + context 'with a regular user' do + let_it_be(:current_user) { create(:user) } + + it { is_expected.to be_disallowed(:read_timelog_category) } + end + + context 'with a reporter user' do + let_it_be(:current_user) { create(:user) } + + before do + users_container.add_reporter(current_user) + end + + context 'when timelog_categories is enabled' do + it { is_expected.to be_allowed(:read_timelog_category) } + end + + context 'when timelog_categories is disabled' do + before do + stub_feature_flags(timelog_categories: false) + end + + it { is_expected.to be_disallowed(:read_timelog_category) } + end + end +end diff --git a/tooling/lib/tooling/helm3_client.rb b/tooling/lib/tooling/helm3_client.rb index 6e4a35e82f1..82ebe3f51dc 100644 --- a/tooling/lib/tooling/helm3_client.rb +++ b/tooling/lib/tooling/helm3_client.rb @@ -84,7 +84,7 @@ module Tooling # method - The Octokit method to use for getting the data. # args - Arguments to pass to the `helm list` command. def each_releases_page(args, &block) - return to_enum(__method__, args) unless block_given? + return to_enum(__method__, args) unless block page = 0 final_args = args.dup @@ -100,7 +100,7 @@ module Tooling # # args - Any arguments to pass to the `helm list` command. def each_release(args, &block) - return to_enum(__method__, args) unless block_given? + return to_enum(__method__, args) unless block each_releases_page(args) do |page| page.releases.each do |release| diff --git a/tooling/lib/tooling/test_map_packer.rb b/tooling/lib/tooling/test_map_packer.rb index d74edb9500f..151ce88111f 100644 --- a/tooling/lib/tooling/test_map_packer.rb +++ b/tooling/lib/tooling/test_map_packer.rb @@ -44,7 +44,7 @@ module Tooling end def traverse(tree, segments = [], &block) - return to_enum(__method__, tree, segments) unless block_given? + return to_enum(__method__, tree, segments) unless block if tree == MARKER return yield segments.join(SEPARATOR) diff --git a/yarn.lock b/yarn.lock index 834d04a4bcb..5cf599320d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4805,10 +4805,10 @@ domhandler@^4.0.0, domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" -dompurify@2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875" - integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg== +dompurify@2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.8.tgz#224fe9ae57d7ebd9a1ae1ac18c1c1ca3f532226f" + integrity sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw== dompurify@^2.3.10: version "2.3.10" @@ -8236,16 +8236,16 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -mermaid@^9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-9.1.1.tgz#5d3d330ca4adf7f3c8ca51095f8bb2f0fb1a93bb" - integrity sha512-2RVD+WkzZ4VDyO9gQvQAuQ/ux2gLigJtKDTlbwjYqOR/NwsVzTSfGm/kx648/qWJsg6Sv04tE9BWCO8s6a+pFA== +mermaid@^9.1.3: + version "9.1.3" + resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-9.1.3.tgz#15d08662c66250124ce31106a4620285061ac59c" + integrity sha512-jTIYiqKwsUXVCoxHUVkK8t0QN3zSKIdJlb9thT0J5jCnzXyc+gqTbZE2QmjRfavFTPPn5eRy5zaFp7V+6RhxYg== dependencies: "@braintree/sanitize-url" "^6.0.0" d3 "^7.0.0" dagre "^0.8.5" dagre-d3 "^0.6.4" - dompurify "2.3.6" + dompurify "2.3.8" graphlib "^2.1.8" khroma "^2.0.0" moment-mini "^2.24.0"