summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-07 12:10:27 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-07 12:10:27 +0000
commit53f456b167f19877d663ee6ed510673cebee0f91 (patch)
treefcc0bb52b79c195bf0eda100cc5d7e7a16dc0c0b /lib
parente8a31d8dc2afd673ca50d74d26edab0a0fec83ca (diff)
downloadgitlab-ce-53f456b167f19877d663ee6ed510673cebee0f91.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/ci/build/cache.rb31
-rw-r--r--lib/gitlab/ci/config/entry/cache.rb110
-rw-r--r--lib/gitlab/ci/config/entry/caches.rb40
-rw-r--r--lib/gitlab/ci/config/entry/default.rb2
-rw-r--r--lib/gitlab/ci/config/entry/job.rb2
-rw-r--r--lib/gitlab/ci/config/entry/root.rb2
-rw-r--r--lib/gitlab/ci/features.rb4
-rw-r--r--lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml12
-rw-r--r--lib/gitlab/quick_actions/spend_time_and_date_separator.rb2
-rw-r--r--lib/gitlab/subscription_portal.rb5
-rw-r--r--lib/gitlab/usage/metric_definition.rb4
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/base_metric.rb19
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/database_metric.rb68
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/generic_metric.rb32
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/redis_hll_metric.rb45
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/uuid_metric.rb15
-rw-r--r--lib/gitlab/usage/metrics/key_path_processor.rb27
-rw-r--r--lib/gitlab/usage_data_metrics.rb28
-rw-r--r--lib/sidebars/projects/menus/settings_menu.rb145
-rw-r--r--lib/sidebars/projects/panel.rb1
-rw-r--r--lib/tasks/gitlab/usage_data.rake5
21 files changed, 484 insertions, 115 deletions
diff --git a/lib/gitlab/ci/build/cache.rb b/lib/gitlab/ci/build/cache.rb
index 4fcb5168847..375e6b4a96f 100644
--- a/lib/gitlab/ci/build/cache.rb
+++ b/lib/gitlab/ci/build/cache.rb
@@ -7,39 +7,22 @@ module Gitlab
include ::Gitlab::Utils::StrongMemoize
def initialize(cache, pipeline)
- if multiple_cache_per_job?
- cache = Array.wrap(cache)
- @cache = cache.map do |cache|
- Gitlab::Ci::Pipeline::Seed::Build::Cache
- .new(pipeline, cache)
- end
- else
- @cache = Gitlab::Ci::Pipeline::Seed::Build::Cache
- .new(pipeline, cache)
+ cache = Array.wrap(cache)
+ @cache = cache.map do |cache|
+ Gitlab::Ci::Pipeline::Seed::Build::Cache
+ .new(pipeline, cache)
end
end
def cache_attributes
strong_memoize(:cache_attributes) do
- if multiple_cache_per_job?
- if @cache.empty?
- {}
- else
- { options: { cache: @cache.map(&:attributes) } }
- end
+ if @cache.empty?
+ {}
else
- @cache.build_attributes
+ { options: { cache: @cache.map(&:attributes) } }
end
end
end
-
- private
-
- def multiple_cache_per_job?
- strong_memoize(:multiple_cache_per_job) do
- ::Gitlab::Ci::Features.multiple_cache_per_job?
- end
- end
end
end
end
diff --git a/lib/gitlab/ci/config/entry/cache.rb b/lib/gitlab/ci/config/entry/cache.rb
index f9688c500d2..ab79add688b 100644
--- a/lib/gitlab/ci/config/entry/cache.rb
+++ b/lib/gitlab/ci/config/entry/cache.rb
@@ -4,88 +4,52 @@ module Gitlab
module Ci
class Config
module Entry
- ##
- # Entry that represents a cache configuration
- #
- class Cache < ::Gitlab::Config::Entry::Simplifiable
- strategy :Caches, if: -> (config) { Feature.enabled?(:multiple_cache_per_job, default_enabled: :yaml) }
- strategy :Cache, if: -> (config) { Feature.disabled?(:multiple_cache_per_job, default_enabled: :yaml) }
-
- class Caches < ::Gitlab::Config::Entry::ComposableArray
- include ::Gitlab::Config::Entry::Validatable
-
- MULTIPLE_CACHE_LIMIT = 4
-
- validations do
- validate do
- unless config.is_a?(Hash) || config.is_a?(Array)
- errors.add(:config, 'can only be a Hash or an Array')
- end
-
- if config.is_a?(Array) && config.count > MULTIPLE_CACHE_LIMIT
- errors.add(:config, "no more than #{MULTIPLE_CACHE_LIMIT} caches can be created")
- end
- end
- end
-
- def initialize(*args)
- super
-
- @key = nil
- end
-
- def composable_class
- Entry::Cache::Cache
+ class Cache < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Configurable
+ include ::Gitlab::Config::Entry::Validatable
+ include ::Gitlab::Config::Entry::Attributable
+
+ ALLOWED_KEYS = %i[key untracked paths when policy].freeze
+ ALLOWED_POLICY = %w[pull-push push pull].freeze
+ DEFAULT_POLICY = 'pull-push'
+ ALLOWED_WHEN = %w[on_success on_failure always].freeze
+ DEFAULT_WHEN = 'on_success'
+
+ validations do
+ validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
+ validates :policy,
+ inclusion: { in: ALLOWED_POLICY, message: 'should be pull-push, push, or pull' },
+ allow_blank: true
+
+ with_options allow_nil: true do
+ validates :when,
+ inclusion: {
+ in: ALLOWED_WHEN,
+ message: 'should be on_success, on_failure or always'
+ }
end
end
- class Cache < ::Gitlab::Config::Entry::Node
- include ::Gitlab::Config::Entry::Configurable
- include ::Gitlab::Config::Entry::Validatable
- include ::Gitlab::Config::Entry::Attributable
-
- ALLOWED_KEYS = %i[key untracked paths when policy].freeze
- ALLOWED_POLICY = %w[pull-push push pull].freeze
- DEFAULT_POLICY = 'pull-push'
- ALLOWED_WHEN = %w[on_success on_failure always].freeze
- DEFAULT_WHEN = 'on_success'
+ entry :key, Entry::Key,
+ description: 'Cache key used to define a cache affinity.'
- validations do
- validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
- validates :policy,
- inclusion: { in: ALLOWED_POLICY, message: 'should be pull-push, push, or pull' },
- allow_blank: true
-
- with_options allow_nil: true do
- validates :when,
- inclusion: {
- in: ALLOWED_WHEN,
- message: 'should be on_success, on_failure or always'
- }
- end
- end
+ entry :untracked, ::Gitlab::Config::Entry::Boolean,
+ description: 'Cache all untracked files.'
- entry :key, Entry::Key,
- description: 'Cache key used to define a cache affinity.'
+ entry :paths, Entry::Paths,
+ description: 'Specify which paths should be cached across builds.'
- entry :untracked, ::Gitlab::Config::Entry::Boolean,
- description: 'Cache all untracked files.'
+ attributes :policy, :when
- entry :paths, Entry::Paths,
- description: 'Specify which paths should be cached across builds.'
+ def value
+ result = super
- attributes :policy, :when
+ result[:key] = key_value
+ result[:policy] = policy || DEFAULT_POLICY
+ # Use self.when to avoid conflict with reserved word
+ result[:when] = self.when || DEFAULT_WHEN
- def value
- result = super
-
- result[:key] = key_value
- result[:policy] = policy || DEFAULT_POLICY
- # Use self.when to avoid conflict with reserved word
- result[:when] = self.when || DEFAULT_WHEN
-
- result
- end
+ result
end
class UnknownStrategy < ::Gitlab::Config::Entry::Node
diff --git a/lib/gitlab/ci/config/entry/caches.rb b/lib/gitlab/ci/config/entry/caches.rb
new file mode 100644
index 00000000000..75240599c9c
--- /dev/null
+++ b/lib/gitlab/ci/config/entry/caches.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Config
+ module Entry
+ ##
+ # Entry that represents caches configuration
+ #
+ class Caches < ::Gitlab::Config::Entry::ComposableArray
+ include ::Gitlab::Config::Entry::Validatable
+
+ MULTIPLE_CACHE_LIMIT = 4
+
+ validations do
+ validate do
+ unless config.is_a?(Hash) || config.is_a?(Array)
+ errors.add(:config, 'can only be a Hash or an Array')
+ end
+
+ if config.is_a?(Array) && config.count > MULTIPLE_CACHE_LIMIT
+ errors.add(:config, "no more than #{MULTIPLE_CACHE_LIMIT} caches can be created")
+ end
+ end
+ end
+
+ def initialize(*args)
+ super
+
+ @key = nil
+ end
+
+ def composable_class
+ Entry::Cache
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config/entry/default.rb b/lib/gitlab/ci/config/entry/default.rb
index ab493ff7d78..eaaf9f69102 100644
--- a/lib/gitlab/ci/config/entry/default.rb
+++ b/lib/gitlab/ci/config/entry/default.rb
@@ -37,7 +37,7 @@ module Gitlab
description: 'Script that will be executed after each job.',
inherit: true
- entry :cache, Entry::Cache,
+ entry :cache, Entry::Caches,
description: 'Configure caching between build jobs.',
inherit: true
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index a20b802be58..d76cab5d7c0 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -64,7 +64,7 @@ module Gitlab
description: 'Commands that will be executed when finishing job.',
inherit: true
- entry :cache, Entry::Cache,
+ entry :cache, Entry::Caches,
description: 'Cache definition for this job.',
inherit: true
diff --git a/lib/gitlab/ci/config/entry/root.rb b/lib/gitlab/ci/config/entry/root.rb
index 54ef84b965a..e6290ef2479 100644
--- a/lib/gitlab/ci/config/entry/root.rb
+++ b/lib/gitlab/ci/config/entry/root.rb
@@ -61,7 +61,7 @@ module Gitlab
description: 'Deprecated: stages for this pipeline.',
reserved: true
- entry :cache, Entry::Cache,
+ entry :cache, Entry::Caches,
description: 'Configure caching between build jobs.',
reserved: true
diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb
index 64eaffa1e82..162dbc4bcc7 100644
--- a/lib/gitlab/ci/features.rb
+++ b/lib/gitlab/ci/features.rb
@@ -56,8 +56,8 @@ module Gitlab
::Feature.enabled?(:codequality_mr_diff, project, default_enabled: false)
end
- def self.multiple_cache_per_job?
- ::Feature.enabled?(:multiple_cache_per_job, default_enabled: :yaml)
+ def self.gldropdown_tags_enabled?
+ ::Feature.enabled?(:gldropdown_tags, default_enabled: :yaml)
end
end
end
diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
index b6f98d5034e..f768bcae6d3 100644
--- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
@@ -157,11 +157,6 @@ gosec-sast:
mobsf-android-sast:
extends: .sast-analyzer
- services:
- # this version must match with analyzer version mentioned in: https://gitlab.com/gitlab-org/security-products/analyzers/mobsf/-/blob/master/Dockerfile
- # Unfortunately, we need to keep track of mobsf version in 2 different places for now.
- - name: opensecurity/mobile-security-framework-mobsf:v3.4.0
- alias: mobsf
image:
name: "$SAST_ANALYZER_IMAGE"
variables:
@@ -169,7 +164,6 @@ mobsf-android-sast:
# override the analyzer image with a custom value. This may be subject to change or
# breakage across GitLab releases.
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG"
- MOBSF_API_KEY: key
rules:
- if: $SAST_DISABLED
when: never
@@ -183,11 +177,6 @@ mobsf-android-sast:
mobsf-ios-sast:
extends: .sast-analyzer
- services:
- # this version must match with analyzer version mentioned in: https://gitlab.com/gitlab-org/security-products/analyzers/mobsf/-/blob/master/Dockerfile
- # Unfortunately, we need to keep track of mobsf version in 2 different places for now.
- - name: opensecurity/mobile-security-framework-mobsf:v3.4.0
- alias: mobsf
image:
name: "$SAST_ANALYZER_IMAGE"
variables:
@@ -195,7 +184,6 @@ mobsf-ios-sast:
# override the analyzer image with a custom value. This may be subject to change or
# breakage across GitLab releases.
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG"
- MOBSF_API_KEY: key
rules:
- if: $SAST_DISABLED
when: never
diff --git a/lib/gitlab/quick_actions/spend_time_and_date_separator.rb b/lib/gitlab/quick_actions/spend_time_and_date_separator.rb
index 4a62e83e8e9..03b2a1086bb 100644
--- a/lib/gitlab/quick_actions/spend_time_and_date_separator.rb
+++ b/lib/gitlab/quick_actions/spend_time_and_date_separator.rb
@@ -19,7 +19,7 @@ module Gitlab
def execute
return if @spend_arg.blank?
- return [get_time, DateTime.now.to_date] unless date_present?
+ return [get_time, DateTime.current] unless date_present?
return unless valid_date?
[get_time, get_date]
diff --git a/lib/gitlab/subscription_portal.rb b/lib/gitlab/subscription_portal.rb
index 1ba1d70a13c..ab2e1404cd2 100644
--- a/lib/gitlab/subscription_portal.rb
+++ b/lib/gitlab/subscription_portal.rb
@@ -9,8 +9,13 @@ module Gitlab
def self.subscriptions_url
ENV.fetch('CUSTOMER_PORTAL_URL', default_subscriptions_url)
end
+
+ def self.payment_form_url
+ "#{self.subscriptions_url}/payment_forms/cc_validation"
+ end
end
end
Gitlab::SubscriptionPortal.prepend_mod
Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL = Gitlab::SubscriptionPortal.subscriptions_url.freeze
+Gitlab::SubscriptionPortal::PAYMENT_FORM_URL = Gitlab::SubscriptionPortal.payment_form_url.freeze
diff --git a/lib/gitlab/usage/metric_definition.rb b/lib/gitlab/usage/metric_definition.rb
index 9d047b8a255..c0cf4a4db4b 100644
--- a/lib/gitlab/usage/metric_definition.rb
+++ b/lib/gitlab/usage/metric_definition.rb
@@ -65,6 +65,10 @@ module Gitlab
@definitions ||= load_all!
end
+ def all
+ @all ||= definitions.map { |_key_path, definition| definition }
+ end
+
def schemer
@schemer ||= ::JSONSchemer.schema(Pathname.new(METRIC_SCHEMA_PATH))
end
diff --git a/lib/gitlab/usage/metrics/instrumentations/base_metric.rb b/lib/gitlab/usage/metrics/instrumentations/base_metric.rb
new file mode 100644
index 00000000000..29b44f2bd0a
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/base_metric.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class BaseMetric
+ include Gitlab::Utils::UsageData
+
+ attr_reader :time_frame
+
+ def initialize(time_frame:)
+ @time_frame = time_frame
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/database_metric.rb b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
new file mode 100644
index 00000000000..f83f90dea03
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class DatabaseMetric < BaseMetric
+ # Usage Example
+ #
+ # class CountUsersCreatingIssuesMetric < DatabaseMetric
+ # operation :distinct_count, column: :author_id
+ #
+ # relation do |database_time_constraints|
+ # ::Issue.where(database_time_constraints)
+ # end
+ # end
+ class << self
+ def start(&block)
+ @metric_start = block
+ end
+
+ def finish(&block)
+ @metric_finish = block
+ end
+
+ def relation(&block)
+ @metric_relation = block
+ end
+
+ def operation(symbol, column: nil)
+ @metric_operation = symbol
+ @column = column
+ end
+
+ attr_reader :metric_operation, :metric_relation, :metric_start, :metric_finish, :column
+ end
+
+ def value
+ method(self.class.metric_operation)
+ .call(relation,
+ self.class.column,
+ start: self.class.metric_start&.call,
+ finish: self.class.metric_finish&.call)
+ end
+
+ def relation
+ self.class.metric_relation.call.where(time_constraints)
+ end
+
+ private
+
+ def time_constraints
+ case time_frame
+ when '28d'
+ { created_at: 30.days.ago..2.days.ago }
+ when 'all'
+ {}
+ when 'none'
+ nil
+ else
+ raise "Unknown time frame: #{time_frame} for DatabaseMetric"
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/generic_metric.rb b/lib/gitlab/usage/metrics/instrumentations/generic_metric.rb
new file mode 100644
index 00000000000..7c97cc37d17
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/generic_metric.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class GenericMetric < BaseMetric
+ # Usage example
+ #
+ # class UuidMetric < GenericMetric
+ # value do
+ # Gitlab::CurrentSettings.uuid
+ # end
+ # end
+ class << self
+ def value(&block)
+ @metric_value = block
+ end
+
+ attr_reader :metric_value
+ end
+
+ def value
+ alt_usage_data do
+ self.class.metric_value.call
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric.rb b/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric.rb
new file mode 100644
index 00000000000..ed0ddb1cbbe
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/redis_hll_metric.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class RedisHLLMetric < BaseMetric
+ # Usage example
+ #
+ # class CountUsersVisitingAnalyticsValuestreamMetric < RedisHLLMetric
+ # event_names :g_analytics_valuestream
+ # end
+ class << self
+ def event_names(events = nil)
+ @mentric_events = events
+ end
+
+ attr_reader :metric_events
+ end
+
+ def value
+ redis_usage_data do
+ event_params = time_constraints.merge(event_names: self.class.metric_events)
+
+ Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(**event_params)
+ end
+ end
+
+ private
+
+ def time_constraints
+ case time_frame
+ when '28d'
+ { start_date: 4.weeks.ago.to_date, end_date: Date.current }
+ when '7d'
+ { start_date: 7.days.ago.to_date, end_date: Date.current }
+ else
+ raise "Unknown time frame: #{time_frame} for TimeConstraint"
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/uuid_metric.rb b/lib/gitlab/usage/metrics/instrumentations/uuid_metric.rb
new file mode 100644
index 00000000000..58547b5383a
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/uuid_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class UuidMetric < GenericMetric
+ value do
+ Gitlab::CurrentSettings.uuid
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/key_path_processor.rb b/lib/gitlab/usage/metrics/key_path_processor.rb
new file mode 100644
index 00000000000..dbe574d5838
--- /dev/null
+++ b/lib/gitlab/usage/metrics/key_path_processor.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ class KeyPathProcessor
+ class << self
+ def process(key_path, value)
+ unflatten(key_path.split('.'), value)
+ end
+
+ private
+
+ def unflatten(keys, value)
+ loop do
+ value = { keys.pop.to_sym => value }
+
+ break if keys.blank?
+ end
+
+ value
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data_metrics.rb b/lib/gitlab/usage_data_metrics.rb
new file mode 100644
index 00000000000..4f162c28f1c
--- /dev/null
+++ b/lib/gitlab/usage_data_metrics.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class UsageDataMetrics
+ class << self
+ # Build the Usage Ping JSON payload from metrics YAML definitions which have instrumentation class set
+ def uncached_data
+ ::Gitlab::Usage::MetricDefinition.all.map do |definition|
+ instrumentation_class = definition.attributes[:instrumentation_class]
+
+ if instrumentation_class.present?
+ metric_value = instrumentation_class.constantize.new(time_frame: definition.attributes[:time_frame]).value
+
+ metric_payload(definition.key_path, metric_value)
+ else
+ {}
+ end
+ end.reduce({}, :deep_merge)
+ end
+
+ private
+
+ def metric_payload(key_path, value)
+ ::Gitlab::Usage::Metrics::KeyPathProcessor.process(key_path, value)
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/settings_menu.rb b/lib/sidebars/projects/menus/settings_menu.rb
new file mode 100644
index 00000000000..8aec769d8d5
--- /dev/null
+++ b/lib/sidebars/projects/menus/settings_menu.rb
@@ -0,0 +1,145 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class SettingsMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ return false unless can?(context.current_user, :admin_project, context.project)
+
+ add_item(general_menu_item)
+ add_item(integrations_menu_item)
+ add_item(webhooks_menu_item)
+ add_item(access_tokens_menu_item)
+ add_item(repository_menu_item)
+ add_item(ci_cd_menu_item)
+ add_item(operations_menu_item)
+ add_item(pages_menu_item)
+ add_item(packages_and_registries_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ edit_project_path(context.project)
+ end
+
+ override :title
+ def title
+ _('Settings')
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-settings-link'
+ }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'settings'
+ end
+
+ private
+
+ def general_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('General'),
+ link: edit_project_path(context.project),
+ active_routes: { path: 'projects#edit' },
+ item_id: :general
+ )
+ end
+
+ def integrations_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Integrations'),
+ link: project_settings_integrations_path(context.project),
+ active_routes: { path: %w[integrations#show services#edit] },
+ item_id: :integrations
+ )
+ end
+
+ def webhooks_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Webhooks'),
+ link: project_hooks_path(context.project),
+ active_routes: { path: %w[hooks#index hooks#edit hook_logs#show] },
+ item_id: :webhooks
+ )
+ end
+
+ def access_tokens_menu_item
+ return unless can?(context.current_user, :read_resource_access_tokens, context.project)
+
+ ::Sidebars::MenuItem.new(
+ title: _('Access Tokens'),
+ link: project_settings_access_tokens_path(context.project),
+ active_routes: { path: 'access_tokens#index' },
+ item_id: :access_tokens
+ )
+ end
+
+ def repository_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Repository'),
+ link: project_settings_repository_path(context.project),
+ active_routes: { path: 'repository#show' },
+ item_id: :repository
+ )
+ end
+
+ def ci_cd_menu_item
+ return if context.project.archived?
+ return unless context.project.feature_available?(:builds, context.current_user)
+
+ ::Sidebars::MenuItem.new(
+ title: _('CI/CD'),
+ link: project_settings_ci_cd_path(context.project),
+ active_routes: { path: 'ci_cd#show' },
+ item_id: :ci_cd
+ )
+ end
+
+ def operations_menu_item
+ return if context.project.archived?
+ return unless can?(context.current_user, :admin_operations, context.project)
+
+ ::Sidebars::MenuItem.new(
+ title: _('Operations'),
+ link: project_settings_operations_path(context.project),
+ active_routes: { path: 'operations#show' },
+ item_id: :operations
+ )
+ end
+
+ def pages_menu_item
+ return unless context.project.pages_available?
+
+ ::Sidebars::MenuItem.new(
+ title: _('Pages'),
+ link: project_pages_path(context.project),
+ active_routes: { path: 'pages#show' },
+ item_id: :pages
+ )
+ end
+
+ def packages_and_registries_menu_item
+ return unless Gitlab.config.registry.enabled
+ return if Feature.disabled?(:sidebar_refactor, context.current_user)
+ return unless can?(context.current_user, :destroy_container_image, context.project)
+
+ ::Sidebars::MenuItem.new(
+ title: _('Packages & Registries'),
+ link: project_settings_packages_and_registries_path(context.project),
+ active_routes: { path: 'packages_and_registries#index' },
+ item_id: :packages_and_registries
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb
index bc37eb262b8..3be2a2b2b71 100644
--- a/lib/sidebars/projects/panel.rb
+++ b/lib/sidebars/projects/panel.rb
@@ -24,6 +24,7 @@ module Sidebars
add_menu(Sidebars::Projects::Menus::ExternalWikiMenu.new(context))
add_menu(Sidebars::Projects::Menus::SnippetsMenu.new(context))
add_menu(Sidebars::Projects::Menus::MembersMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::SettingsMenu.new(context))
end
override :render_raw_menus_partial
diff --git a/lib/tasks/gitlab/usage_data.rake b/lib/tasks/gitlab/usage_data.rake
index 95072444fcf..0ad50c0fa53 100644
--- a/lib/tasks/gitlab/usage_data.rake
+++ b/lib/tasks/gitlab/usage_data.rake
@@ -29,5 +29,10 @@ namespace :gitlab do
items = Gitlab::Usage::MetricDefinition.definitions
Gitlab::Usage::Docs::Renderer.new(items).write
end
+
+ desc 'GitLab | UsageDataMetrics | Generate usage ping from metrics definition YAML files in JSON'
+ task generate_from_yaml: :environment do
+ puts Gitlab::Json.pretty_generate(Gitlab::UsageDataMetrics.uncached_data)
+ end
end
end