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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-01 09:07:32 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-01 09:07:32 +0300
commit916bb1bb577b64ec769b4c081c4f861a2f47322f (patch)
tree5184da3dd62647179130811c75de9631c925300d
parenta3e0d4c59ff43ee406d2fee12a29339b95a0787d (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/gitlab/avoid_gitlab_instance_checks.yml1
-rw-r--r--.rubocop_todo/rspec/named_subject.yml1
-rw-r--r--.rubocop_todo/rspec/verified_doubles.yml1
-rw-r--r--.rubocop_todo/style/inline_disable_annotation.yml4
-rw-r--r--app/assets/javascripts/emoji/queries/custom_emoji.query.graphql2
-rw-r--r--app/assets/javascripts/vue_shared/components/awards_list.vue4
-rw-r--r--app/experiments/application_experiment.rb14
-rw-r--r--app/finders/groups/custom_emoji_finder.rb26
-rw-r--r--app/graphql/resolvers/custom_emoji_resolver.rb23
-rw-r--r--app/graphql/types/group_type.rb7
-rw-r--r--app/models/award_emoji.rb3
-rw-r--r--app/models/custom_emoji.rb31
-rw-r--r--app/serializers/award_emoji_entity.rb1
-rw-r--r--app/validators/gitlab/emoji_name_validator.rb6
-rw-r--r--config/initializers/gitlab_experiment.rb2
-rw-r--r--doc/administration/auth/crowd.md2
-rw-r--r--doc/api/graphql/reference/index.md21
-rw-r--r--doc/user/group/insights/index.md10
-rw-r--r--lib/banzai/filter/custom_emoji_filter.rb12
-rw-r--r--lib/gitlab/experiment/rollout/feature.rb8
-rw-r--r--locale/gitlab.pot6
-rw-r--r--spec/experiments/application_experiment_spec.rb35
-rw-r--r--spec/finders/groups/custom_emoji_finder_spec.rb65
-rw-r--r--spec/graphql/types/group_type_spec.rb33
-rw-r--r--spec/lib/banzai/filter/custom_emoji_filter_spec.rb8
-rw-r--r--spec/lib/gitlab/experiment/rollout/feature_spec.rb65
-rw-r--r--spec/models/award_emoji_spec.rb11
-rw-r--r--spec/models/custom_emoji_spec.rb41
-rw-r--r--spec/requests/api/graphql/custom_emoji_query_spec.rb4
-rw-r--r--spec/serializers/discussion_entity_spec.rb7
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/helpers/stub_saas_features.rb23
-rw-r--r--spec/support_specs/helpers/stub_saas_features_spec.rb65
33 files changed, 101 insertions, 442 deletions
diff --git a/.rubocop_todo/gitlab/avoid_gitlab_instance_checks.yml b/.rubocop_todo/gitlab/avoid_gitlab_instance_checks.yml
index cf0f863f7db..77a880115da 100644
--- a/.rubocop_todo/gitlab/avoid_gitlab_instance_checks.yml
+++ b/.rubocop_todo/gitlab/avoid_gitlab_instance_checks.yml
@@ -132,7 +132,6 @@ Gitlab/AvoidGitlabInstanceChecks:
- 'lib/gitlab/database/migration_helpers/convert_to_bigint.rb'
- 'lib/gitlab/database/migration_helpers/wraparound_autovacuum.rb'
- 'lib/gitlab/database/migration_helpers/wraparound_vacuum_helpers.rb'
- - 'lib/gitlab/experiment/rollout/feature.rb'
- 'lib/gitlab/gon_helper.rb'
- 'lib/gitlab/monitor/demo_projects.rb'
- 'lib/gitlab/qa.rb'
diff --git a/.rubocop_todo/rspec/named_subject.yml b/.rubocop_todo/rspec/named_subject.yml
index 38c55d261f0..9ee86882271 100644
--- a/.rubocop_todo/rspec/named_subject.yml
+++ b/.rubocop_todo/rspec/named_subject.yml
@@ -2171,7 +2171,6 @@ RSpec/NamedSubject:
- 'spec/lib/gitlab/event_store/store_spec.rb'
- 'spec/lib/gitlab/exclusive_lease_helpers/sleeping_lock_spec.rb'
- 'spec/lib/gitlab/exclusive_lease_helpers_spec.rb'
- - 'spec/lib/gitlab/experiment/rollout/feature_spec.rb'
- 'spec/lib/gitlab/faraday/error_callback_spec.rb'
- 'spec/lib/gitlab/favicon_spec.rb'
- 'spec/lib/gitlab/feature_categories_spec.rb'
diff --git a/.rubocop_todo/rspec/verified_doubles.yml b/.rubocop_todo/rspec/verified_doubles.yml
index d907b372477..8feedc2c4f9 100644
--- a/.rubocop_todo/rspec/verified_doubles.yml
+++ b/.rubocop_todo/rspec/verified_doubles.yml
@@ -497,7 +497,6 @@ RSpec/VerifiedDoubles:
- 'spec/lib/gitlab/etag_caching/router/rails_spec.rb'
- 'spec/lib/gitlab/etag_caching/router_spec.rb'
- 'spec/lib/gitlab/event_store/store_spec.rb'
- - 'spec/lib/gitlab/experiment/rollout/feature_spec.rb'
- 'spec/lib/gitlab/external_authorization/access_spec.rb'
- 'spec/lib/gitlab/external_authorization/logger_spec.rb'
- 'spec/lib/gitlab/faraday/error_callback_spec.rb'
diff --git a/.rubocop_todo/style/inline_disable_annotation.yml b/.rubocop_todo/style/inline_disable_annotation.yml
index f5a43785756..6140c5227a6 100644
--- a/.rubocop_todo/style/inline_disable_annotation.yml
+++ b/.rubocop_todo/style/inline_disable_annotation.yml
@@ -1903,7 +1903,6 @@ Style/InlineDisableAnnotation:
- 'ee/lib/ee/gitlab/import_export/project/object_builder.rb'
- 'ee/lib/ee/gitlab/object_hierarchy.rb'
- 'ee/lib/ee/gitlab/quick_actions/users_extractor.rb'
- - 'ee/lib/ee/gitlab/saas.rb'
- 'ee/lib/ee/gitlab/tracking.rb'
- 'ee/lib/ee/gitlab/usage_data.rb'
- 'ee/lib/ee/users/internal.rb'
@@ -2526,7 +2525,6 @@ Style/InlineDisableAnnotation:
- 'lib/gitlab/error_tracking/processor/sanitizer_processor.rb'
- 'lib/gitlab/etag_caching/store.rb'
- 'lib/gitlab/exclusive_lease.rb'
- - 'lib/gitlab/experiment/rollout/feature.rb'
- 'lib/gitlab/external_authorization/cache.rb'
- 'lib/gitlab/faraday/error_callback.rb'
- 'lib/gitlab/file_hook.rb'
@@ -2864,7 +2862,6 @@ Style/InlineDisableAnnotation:
- 'spec/controllers/projects/runners_controller_spec.rb'
- 'spec/db/docs_spec.rb'
- 'spec/deprecation_warnings.rb'
- - 'spec/experiments/application_experiment_spec.rb'
- 'spec/factories/design_management/designs.rb'
- 'spec/factories/events.rb'
- 'spec/factories/go_module_commits.rb'
@@ -2990,7 +2987,6 @@ Style/InlineDisableAnnotation:
- 'spec/lib/gitlab/doorkeeper_secret_storing/secret/pbkdf2_sha512_spec.rb'
- 'spec/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512_spec.rb'
- 'spec/lib/gitlab/encoding_helper_spec.rb'
- - 'spec/lib/gitlab/experiment/rollout/feature_spec.rb'
- 'spec/lib/gitlab/gfm/uploads_rewriter_spec.rb'
- 'spec/lib/gitlab/git/object_pool_spec.rb'
- 'spec/lib/gitlab/git/remote_mirror_spec.rb'
diff --git a/app/assets/javascripts/emoji/queries/custom_emoji.query.graphql b/app/assets/javascripts/emoji/queries/custom_emoji.query.graphql
index ba3911ab091..951027ec274 100644
--- a/app/assets/javascripts/emoji/queries/custom_emoji.query.graphql
+++ b/app/assets/javascripts/emoji/queries/custom_emoji.query.graphql
@@ -1,7 +1,7 @@
query getCustomEmoji($groupPath: ID!) {
group(fullPath: $groupPath) {
id
- customEmoji(includeAncestorGroups: true) {
+ customEmoji {
nodes {
id
name
diff --git a/app/assets/javascripts/vue_shared/components/awards_list.vue b/app/assets/javascripts/vue_shared/components/awards_list.vue
index 3c19df9c196..59f03b41144 100644
--- a/app/assets/javascripts/vue_shared/components/awards_list.vue
+++ b/app/assets/javascripts/vue_shared/components/awards_list.vue
@@ -94,12 +94,14 @@ export default {
return awardList.some((award) => award.user.id === this.currentUserId);
},
createAwardList(name, list) {
+ const url = list.length ? list[0].url : null;
+
return {
name,
list,
title: this.getAwardListTitle(list, name),
classes: this.getAwardClassBindings(list),
- html: glEmojiTag(name),
+ html: glEmojiTag(name, { url }),
};
},
getAwardListTitle(awardsList, name) {
diff --git a/app/experiments/application_experiment.rb b/app/experiments/application_experiment.rb
index 60bf47c2f12..cfbd4eb6b75 100644
--- a/app/experiments/application_experiment.rb
+++ b/app/experiments/application_experiment.rb
@@ -3,6 +3,18 @@
class ApplicationExperiment < Gitlab::Experiment
control { nil } # provide a default control for anonymous experiments
+ # We have experiments in ce/foss code even though they will never be available
+ # for ce/foss instances.
+ # We do that since we currently only experiment on the ee with SaaS instance.
+ # However, if the experiment is successful, we may commit the final code to ce/foss
+ # if the feature we are experimenting on is not a licensed or SaaS feature.
+ #
+ # This follows the https://docs.gitlab.com/ee/development/ee_features.html
+ # guidelines and therefore we have hardcoded `false` here.
+ def self.available?
+ false
+ end
+
def control_behavior
# define a default nil control behavior so we can omit it when not needed
end
@@ -44,3 +56,5 @@ class ApplicationExperiment < Gitlab::Experiment
actor.respond_to?(:id) ? actor : context.try(:user)
end
end
+
+ApplicationExperiment.prepend_mod
diff --git a/app/finders/groups/custom_emoji_finder.rb b/app/finders/groups/custom_emoji_finder.rb
deleted file mode 100644
index 80a4e948f8b..00000000000
--- a/app/finders/groups/custom_emoji_finder.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-module Groups
- class CustomEmojiFinder < Base
- include FinderWithGroupHierarchy
- include Gitlab::Utils::StrongMemoize
-
- def initialize(group, params = {})
- @group = group
- @params = params
- @skip_authorization = true
- end
-
- def execute
- return CustomEmoji.none if Feature.disabled?(:custom_emoji, group)
-
- return CustomEmoji.for_resource(group) unless params[:include_ancestor_groups]
-
- CustomEmoji.for_namespaces(group_ids_for(group))
- end
-
- private
-
- attr_reader :group, :params, :skip_authorization
- end
-end
diff --git a/app/graphql/resolvers/custom_emoji_resolver.rb b/app/graphql/resolvers/custom_emoji_resolver.rb
deleted file mode 100644
index 1e39fafe486..00000000000
--- a/app/graphql/resolvers/custom_emoji_resolver.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
- class CustomEmojiResolver < BaseResolver
- include Gitlab::Graphql::Authorize::AuthorizeResource
-
- authorizes_object!
-
- authorize :read_custom_emoji
-
- argument :include_ancestor_groups,
- GraphQL::Types::Boolean,
- required: false,
- default_value: false,
- description: 'Includes custom emoji from parent groups.'
-
- type Types::CustomEmojiType, null: true
-
- def resolve(**args)
- Groups::CustomEmojiFinder.new(object, args).execute
- end
- end
-end
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index a4eba3c63ae..74e7f256b44 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -21,8 +21,7 @@ module Types
field :custom_emoji,
type: Types::CustomEmojiType.connection_type,
null: true,
- resolver: Resolvers::CustomEmojiResolver,
- description: 'Custom emoji in this namespace.',
+ description: 'Custom emoji within this namespace.',
alpha: { milestone: '13.6' }
field :share_with_group_lock,
@@ -331,6 +330,10 @@ module Types
group.dependency_proxy_setting || group.create_dependency_proxy_setting
end
+ def custom_emoji
+ object.custom_emoji if Feature.enabled?(:custom_emoji)
+ end
+
private
def group
diff --git a/app/models/award_emoji.rb b/app/models/award_emoji.rb
index 9c1005e19c7..4dc26a2d197 100644
--- a/app/models/award_emoji.rb
+++ b/app/models/award_emoji.rb
@@ -66,8 +66,7 @@ class AwardEmoji < ApplicationRecord
def url
return if TanukiEmoji.find_by_alpha_code(name)
- Groups::CustomEmojiFinder.new(resource_parent, { include_ancestor_groups: true }).execute
- .by_name(name)&.select(:url)&.first&.url
+ CustomEmoji.for_resource(resource_parent).by_name(name).select(:url).first&.url
end
def expire_cache
diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb
index a3318cd0bd8..c704795130b 100644
--- a/app/models/custom_emoji.rb
+++ b/app/models/custom_emoji.rb
@@ -25,33 +25,20 @@ class CustomEmoji < ApplicationRecord
format: { with: /\A#{NAME_REGEXP}\z/o }
scope :by_name, -> (names) { where(name: names) }
- scope :for_namespaces, -> (namespace_ids) do
- order = Gitlab::Pagination::Keyset::Order.build([
- Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
- attribute_name: 'name',
- order_expression: CustomEmoji.arel_table[:name].asc,
- nullable: :not_nullable,
- distinct: true
- ),
- Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
- attribute_name: 'current_namespace',
- order_expression: Arel.sql("CASE WHEN namespace_id = #{namespace_ids.first} THEN 0 ELSE 1 END").asc,
- nullable: :not_nullable,
- add_to_projections: true
- )
- ])
- where(namespace_id: namespace_ids)
- .select("DISTINCT ON (name) *")
- .order(order)
- end
alias_attribute :url, :file # this might need a change in https://gitlab.com/gitlab-org/gitlab/-/issues/230467
+ # Find custom emoji for the given resource.
+ # A resource can be either a Project or a Group, or anything responding to #root_ancestor.
+ # Usually it's the return value of #resource_parent on any model.
scope :for_resource, -> (resource) do
- return none if resource.nil? || Feature.disabled?(:custom_emoji, resource)
- return none unless resource.is_a?(Group)
+ return none if resource.nil?
+
+ namespace = resource.root_ancestor
+
+ return none if namespace.nil? || Feature.disabled?(:custom_emoji, namespace)
- resource.custom_emoji
+ namespace.custom_emoji
end
private
diff --git a/app/serializers/award_emoji_entity.rb b/app/serializers/award_emoji_entity.rb
index 212931a2fa9..6ca782d8203 100644
--- a/app/serializers/award_emoji_entity.rb
+++ b/app/serializers/award_emoji_entity.rb
@@ -3,4 +3,5 @@
class AwardEmojiEntity < Grape::Entity
expose :name
expose :user, using: API::Entities::UserSafe
+ expose :url
end
diff --git a/app/validators/gitlab/emoji_name_validator.rb b/app/validators/gitlab/emoji_name_validator.rb
index 68743530d83..c034a79214b 100644
--- a/app/validators/gitlab/emoji_name_validator.rb
+++ b/app/validators/gitlab/emoji_name_validator.rb
@@ -25,12 +25,8 @@ module Gitlab
def valid_custom_emoji?(record, value)
resource = record.try(:resource_parent)
- namespace = resource.try(:namespace)
- return unless resource.is_a?(Group) || namespace.is_a?(Group)
-
- Groups::CustomEmojiFinder.new(resource, { include_ancestor_groups: true }).execute
- .by_name(value.to_s).any?
+ CustomEmoji.for_resource(resource).by_name(value.to_s).any?
end
end
end
diff --git a/config/initializers/gitlab_experiment.rb b/config/initializers/gitlab_experiment.rb
index a54a741ed65..10ae1fa8ff0 100644
--- a/config/initializers/gitlab_experiment.rb
+++ b/config/initializers/gitlab_experiment.rb
@@ -49,7 +49,7 @@ Gitlab::Experiment.configure do |config|
#
valid_domains = %w[about.gitlab.com docs.gitlab.com gitlab.com gdk.test localhost]
config.redirect_url_validator = lambda do |url|
- Gitlab.com? && (url = URI.parse(url)) && valid_domains.include?(url.host)
+ ApplicationExperiment.available? && (url = URI.parse(url)) && valid_domains.include?(url.host)
rescue URI::InvalidURIError
false
end
diff --git a/doc/administration/auth/crowd.md b/doc/administration/auth/crowd.md
index 574b8967b02..0034f244809 100644
--- a/doc/administration/auth/crowd.md
+++ b/doc/administration/auth/crowd.md
@@ -5,7 +5,7 @@ group: Authentication
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Use Atlassian Crowd as an OAuth 2.0 authentication provider (deprecated) **(FREE SELF)**
+# Use Atlassian Crowd as an authentication provider (deprecated) **(FREE SELF)**
WARNING:
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/369117) in GitLab 15.3 and is planned for
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index fc1c9c41f7f..bf25ee8182b 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -18894,6 +18894,7 @@ GPG signature for a signed commit.
| <a id="groupcontainerrepositoriescount"></a>`containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the group. |
| <a id="groupcontainslockedprojects"></a>`containsLockedProjects` | [`Boolean!`](#boolean) | Includes at least one project where the repository size exceeds the limit. This only applies to namespaces under Project limit enforcement. |
| <a id="groupcrossprojectpipelineavailable"></a>`crossProjectPipelineAvailable` | [`Boolean!`](#boolean) | Indicates if the cross_project_pipeline feature is available for the namespace. |
+| <a id="groupcustomemoji"></a>`customEmoji` **{warning-solid}** | [`CustomEmojiConnection`](#customemojiconnection) | **Introduced** in 13.6. This feature is an Experiment. It can be changed or removed at any time. Custom emoji within this namespace. |
| <a id="groupdependencyproxyblobcount"></a>`dependencyProxyBlobCount` | [`Int!`](#int) | Number of dependency proxy blobs cached in the group. |
| <a id="groupdependencyproxyblobs"></a>`dependencyProxyBlobs` | [`DependencyProxyBlobConnection`](#dependencyproxyblobconnection) | Dependency Proxy blobs. (see [Connections](#connections)) |
| <a id="groupdependencyproxyimagecount"></a>`dependencyProxyImageCount` | [`Int!`](#int) | Number of dependency proxy images cached in the group. |
@@ -19185,26 +19186,6 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupcontributionsfrom"></a>`from` | [`ISO8601Date!`](#iso8601date) | Start date of the reporting time range. |
| <a id="groupcontributionsto"></a>`to` | [`ISO8601Date!`](#iso8601date) | End date of the reporting time range. The end date must be within 93 days after the start date. |
-##### `Group.customEmoji`
-
-Custom emoji in this namespace.
-
-WARNING:
-**Introduced** in 13.6.
-This feature is an Experiment. It can be changed or removed at any time.
-
-Returns [`CustomEmojiConnection`](#customemojiconnection).
-
-This field returns a [connection](#connections). It accepts the
-four standard [pagination arguments](#connection-pagination-arguments):
-`before: String`, `after: String`, `first: Int`, `last: Int`.
-
-###### Arguments
-
-| Name | Type | Description |
-| ---- | ---- | ----------- |
-| <a id="groupcustomemojiincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Includes custom emoji from parent groups. |
-
##### `Group.customizableDashboardVisualizations`
Visualizations of the group or associated configuration project.
diff --git a/doc/user/group/insights/index.md b/doc/user/group/insights/index.md
index 2ded1b08de2..251965904a1 100644
--- a/doc/user/group/insights/index.md
+++ b/doc/user/group/insights/index.md
@@ -56,6 +56,16 @@ By default, insights display all available dimensions on the chart.
To exclude a dimension, from the legend below the chart, select the name of the dimension.
+### Drill down on charts
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/372215/) in GitLab 16.7.
+
+You can drill down into the data of the **Bugs created per month by priority** and **Bugs created per month by severity** charts from the [default configuration file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/fixtures/insights/default.yml).
+
+To view a drill-down report of the data for a specific priority or severity in a month:
+
+- On the chart, select the bar stack you want to drill down on.
+
## Configure group insights
GitLab reads insights from the
diff --git a/lib/banzai/filter/custom_emoji_filter.rb b/lib/banzai/filter/custom_emoji_filter.rb
index 4dd6bada306..dddaaebc9de 100644
--- a/lib/banzai/filter/custom_emoji_filter.rb
+++ b/lib/banzai/filter/custom_emoji_filter.rb
@@ -48,9 +48,10 @@ module Banzai
private
def has_custom_emoji?
- all_custom_emoji&.any?
+ strong_memoize(:has_custom_emoji) do
+ CustomEmoji.for_resource(resource_parent).any?
+ end
end
- strong_memoize_attr :has_custom_emoji?
def resource_parent
context[:project] || context[:group]
@@ -61,12 +62,9 @@ module Banzai
end
def all_custom_emoji
- Groups::CustomEmojiFinder.new(resource_parent, { include_ancestor_groups: true })
- .execute
- .by_name(custom_emoji_candidates)
- .index_by(&:name)
+ @all_custom_emoji ||=
+ CustomEmoji.for_resource(resource_parent).by_name(custom_emoji_candidates).index_by(&:name)
end
- strong_memoize_attr :all_custom_emoji
end
end
end
diff --git a/lib/gitlab/experiment/rollout/feature.rb b/lib/gitlab/experiment/rollout/feature.rb
index 4ff61aa3551..0f2a1b9fb1d 100644
--- a/lib/gitlab/experiment/rollout/feature.rb
+++ b/lib/gitlab/experiment/rollout/feature.rb
@@ -13,7 +13,7 @@ module Gitlab
# no inclusions, etc.)
def enabled?
return false unless feature_flag_defined?
- return false unless Gitlab.com?
+ return false unless available?
return false unless ::Feature.enabled?(:gitlab_experiment, type: :ops)
feature_flag_instance.state != :off
@@ -57,8 +57,12 @@ module Gitlab
private
+ def available?
+ ApplicationExperiment.available?
+ end
+
def feature_flag_instance
- ::Feature.get(feature_flag_name) # rubocop:disable Gitlab/AvoidFeatureGet
+ ::Feature.get(feature_flag_name) # rubocop:disable Gitlab/AvoidFeatureGet -- We are using at a lower layer here in experiment framework
end
def feature_flag_defined?
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 095ebbead51..b2f358fa500 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8975,6 +8975,12 @@ msgstr ""
msgid "Browse templates"
msgstr ""
+msgid "Bugs created per month by Priority"
+msgstr ""
+
+msgid "Bugs created per month by Severity"
+msgstr ""
+
msgid "Build cannot be erased"
msgstr ""
diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb
index 00370a5b7e3..24e08241fe7 100644
--- a/spec/experiments/application_experiment_spec.rb
+++ b/spec/experiments/application_experiment_spec.rb
@@ -24,6 +24,12 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :acquisitio
expect { experiment(:example) {} }.not_to raise_error
end
+ describe ".available?" do
+ it 'is false for foss' do
+ expect(described_class).not_to be_available
+ end
+ end
+
describe "#publish" do
it "tracks the assignment", :snowplow do
expect(application_experiment).to receive(:track).with(:assignment)
@@ -169,33 +175,6 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :acquisitio
end
describe "#process_redirect_url" do
- using RSpec::Parameterized::TableSyntax
-
- where(:url, :processed_url) do
- 'https://about.gitlab.com/' | 'https://about.gitlab.com/'
- 'https://gitlab.com/' | 'https://gitlab.com/'
- 'http://docs.gitlab.com' | 'http://docs.gitlab.com'
- 'https://docs.gitlab.com/some/path?foo=bar' | 'https://docs.gitlab.com/some/path?foo=bar'
- 'http://badgitlab.com' | nil
- 'https://gitlab.com.nefarious.net' | nil
- 'https://unknown.gitlab.com' | nil
- "https://badplace.com\nhttps://gitlab.com" | nil
- 'https://gitlabbcom' | nil
- 'https://gitlabbcom/' | nil
- 'http://gdk.test/foo/bar' | 'http://gdk.test/foo/bar'
- 'http://localhost:3000/foo/bar' | 'http://localhost:3000/foo/bar'
- end
-
- with_them do
- it "returns the url or nil if invalid on SaaS", :saas do
- expect(application_experiment.process_redirect_url(url)).to eq(processed_url)
- end
-
- it "considers all urls invalid when not on SaaS" do
- expect(application_experiment.process_redirect_url(url)).to be_nil
- end
- end
-
it "generates the correct urls based on where the engine was mounted" do
url = Rails.application.routes.url_helpers.experiment_redirect_url(application_experiment, url: 'https://docs.gitlab.com')
expect(url).to include("/-/experiment/namespaced%2Fstub:#{application_experiment.context.key}?https://docs.gitlab.com")
@@ -227,7 +206,7 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :acquisitio
it "tracks an event", :snowplow do
experiment(:top) { |e| e.control { experiment(:nested) {} } }
- expect(Gitlab::Tracking).to have_received(:event).with( # rubocop:disable RSpec/ExpectGitlabTracking
+ expect(Gitlab::Tracking).to have_received(:event).with( # rubocop:disable RSpec/ExpectGitlabTracking -- Testing nested functionality
'top',
:nested,
hash_including(label: 'nested')
diff --git a/spec/finders/groups/custom_emoji_finder_spec.rb b/spec/finders/groups/custom_emoji_finder_spec.rb
deleted file mode 100644
index f1044997d4f..00000000000
--- a/spec/finders/groups/custom_emoji_finder_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Groups::CustomEmojiFinder, feature_category: :code_review_workflow do
- describe '#execute' do
- let(:params) { {} }
-
- subject(:execute) { described_class.new(group, params).execute }
-
- context 'when inside a group' do
- let_it_be(:group) { create(:group) }
- let_it_be(:custom_emoji) { create(:custom_emoji, group: group) }
-
- it 'returns custom emoji from group' do
- expect(execute).to contain_exactly(custom_emoji)
- end
- end
-
- context 'when group is nil' do
- let_it_be(:group) { nil }
-
- it 'returns nil' do
- expect(execute).to be_empty
- end
- end
-
- context 'when group is a subgroup' do
- let_it_be(:parent) { create(:group) }
- let_it_be(:group) { create(:group, parent: parent) }
- let_it_be(:custom_emoji) { create(:custom_emoji, group: group) }
-
- it 'returns custom emoji' do
- expect(described_class.new(group, params).execute).to contain_exactly(custom_emoji)
- end
- end
-
- describe 'when custom emoji is in parent group' do
- let_it_be(:parent) { create(:group) }
- let_it_be(:group) { create(:group, parent: parent) }
- let_it_be(:custom_emoji) { create(:custom_emoji, group: parent) }
- let(:params) { { include_ancestor_groups: true } }
-
- it 'returns custom emoji' do
- expect(execute).to contain_exactly(custom_emoji)
- end
-
- context 'when params is empty' do
- let(:params) { {} }
-
- it 'returns empty record' do
- expect(execute).to eq([])
- end
- end
-
- context 'when include_ancestor_groups is false' do
- let(:params) { { include_ancestor_groups: false } }
-
- it 'returns empty record' do
- expect(execute).to eq([])
- end
- end
- end
- end
-end
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index d3f9053faf3..6622551f063 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -125,37 +125,4 @@ RSpec.describe GitlabSchema.types['Group'] do
expect { clean_state_query }.not_to exceed_all_query_limit(control)
end
end
-
- describe 'custom emoji' do
- let_it_be(:user) { create(:user) }
- let_it_be(:group) { create(:group) }
- let_it_be(:subgroup) { create(:group, parent: group) }
- let_it_be(:custom_emoji) { create(:custom_emoji, group: group) }
- let_it_be(:custom_emoji_subgroup) { create(:custom_emoji, group: subgroup) }
- let(:query) do
- %(
- query {
- group(fullPath: "#{subgroup.full_path}") {
- customEmoji(includeAncestorGroups: true) {
- nodes {
- id
- }
- }
- }
- }
- )
- end
-
- before_all do
- group.add_reporter(user)
- end
-
- describe 'when includeAncestorGroups is true' do
- it 'returns emoji from ancestor groups' do
- result = GitlabSchema.execute(query, context: { current_user: user }).as_json
-
- expect(result.dig('data', 'group', 'customEmoji', 'nodes').count).to eq(2)
- end
- end
- end
end
diff --git a/spec/lib/banzai/filter/custom_emoji_filter_spec.rb b/spec/lib/banzai/filter/custom_emoji_filter_spec.rb
index 4fc9d9dd4f6..7fd25eac81b 100644
--- a/spec/lib/banzai/filter/custom_emoji_filter_spec.rb
+++ b/spec/lib/banzai/filter/custom_emoji_filter_spec.rb
@@ -55,12 +55,4 @@ RSpec.describe Banzai::Filter::CustomEmojiFilter, feature_category: :team_planni
filter('<p>:tanuki:</p> <p>:party-parrot:</p>')
end.not_to exceed_all_query_limit(control_count.count)
end
-
- it 'uses custom emoji from ancestor group' do
- subgroup = create(:group, parent: group)
-
- doc = filter('<p>:tanuki:</p>', group: subgroup)
-
- expect(doc.css('gl-emoji').size).to eq 1
- end
end
diff --git a/spec/lib/gitlab/experiment/rollout/feature_spec.rb b/spec/lib/gitlab/experiment/rollout/feature_spec.rb
index 6d01b7a175f..9d602083ad6 100644
--- a/spec/lib/gitlab/experiment/rollout/feature_spec.rb
+++ b/spec/lib/gitlab/experiment/rollout/feature_spec.rb
@@ -3,50 +3,25 @@
require 'spec_helper'
RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment, feature_category: :acquisition do
- subject { described_class.new(subject_experiment) }
+ subject(:experiment_instance) { described_class.new(subject_experiment) }
let(:subject_experiment) { experiment('namespaced/stub') }
- describe "#enabled?", :saas do
+ describe "#enabled?" do
before do
stub_feature_flags(gitlab_experiment: true)
- allow(subject).to receive(:feature_flag_defined?).and_return(true)
- allow(subject).to receive(:feature_flag_instance).and_return(double(state: :on))
+ allow(experiment_instance).to receive(:feature_flag_defined?).and_return(true)
+ allow(experiment_instance)
+ .to receive(:feature_flag_instance).and_return(instance_double('Flipper::Feature', state: :on))
end
- it "is enabled when all criteria are met" do
- expect(subject).to be_enabled
- end
-
- it "isn't enabled if the feature definition doesn't exist" do
- expect(subject).to receive(:feature_flag_defined?).and_return(false)
-
- expect(subject).not_to be_enabled
- end
-
- it "isn't enabled if we're not in dev or dotcom environments" do
- expect(Gitlab).to receive(:com?).and_return(false)
-
- expect(subject).not_to be_enabled
- end
-
- it "isn't enabled if the feature flag state is :off" do
- expect(subject).to receive(:feature_flag_instance).and_return(double(state: :off))
-
- expect(subject).not_to be_enabled
- end
-
- it "isn't enabled if the gitlab_experiment feature flag is false" do
- stub_feature_flags(gitlab_experiment: false)
-
- expect(subject).not_to be_enabled
- end
+ it { is_expected.not_to be_enabled }
end
describe "#execute_assignment" do
let(:variants) do
->(e) do
- # rubocop:disable Lint/EmptyBlock
+ # rubocop:disable Lint/EmptyBlock -- Specific for test
e.control {}
e.variant(:red) {}
e.variant(:blue) {}
@@ -63,26 +38,26 @@ RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment, feature_catego
it "uses the default value as specified in the yaml" do
expect(Feature).to receive(:enabled?).with(
'namespaced_stub',
- subject,
+ experiment_instance,
type: :experiment
).and_return(false)
- expect(subject.execute_assignment).to be_nil
+ expect(experiment_instance.execute_assignment).to be_nil
end
it "returns an assigned name" do
- expect(subject.execute_assignment).to eq(:blue)
+ expect(experiment_instance.execute_assignment).to eq(:blue)
end
context "when there are no behaviors" do
- let(:variants) { ->(e) { e.control {} } } # rubocop:disable Lint/EmptyBlock
+ let(:variants) { ->(e) { e.control {} } } # rubocop:disable Lint/EmptyBlock -- Specific for test
it "does not raise an error" do
- expect { subject.execute_assignment }.not_to raise_error
+ expect { experiment_instance.execute_assignment }.not_to raise_error
end
end
- context "for even rollout to non-control", :saas do
+ context "for even rollout to non-control" do
let(:counts) { Hash.new(0) }
let(:subject_experiment) { experiment('namespaced/stub') }
@@ -91,8 +66,8 @@ RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment, feature_catego
allow(instance).to receive(:enabled?).and_return(true)
end
- subject_experiment.variant(:variant1) {} # rubocop:disable Lint/EmptyBlock
- subject_experiment.variant(:variant2) {} # rubocop:disable Lint/EmptyBlock
+ subject_experiment.variant(:variant1) {} # rubocop:disable Lint/EmptyBlock -- Specific for test
+ subject_experiment.variant(:variant2) {} # rubocop:disable Lint/EmptyBlock -- Specific for test
end
it "rolls out relatively evenly to 2 behaviors" do
@@ -102,7 +77,7 @@ RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment, feature_catego
end
it "rolls out relatively evenly to 3 behaviors" do
- subject_experiment.variant(:variant3) {} # rubocop:disable Lint/EmptyBlock
+ subject_experiment.variant(:variant3) {} # rubocop:disable Lint/EmptyBlock -- Specific for test
100.times { |i| run_cycle(subject_experiment, value: i) }
@@ -115,7 +90,7 @@ RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment, feature_catego
end
it "rolls out with the expected distribution" do
- subject_experiment.variant(:variant3) {} # rubocop:disable Lint/EmptyBlock
+ subject_experiment.variant(:variant3) {} # rubocop:disable Lint/EmptyBlock -- Specific for test
100.times { |i| run_cycle(subject_experiment, value: i) }
@@ -152,14 +127,14 @@ RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment, feature_catego
describe "#flipper_id" do
it "returns the expected flipper id if the experiment doesn't provide one" do
- subject.instance_variable_set(:@experiment, double(id: '__id__'))
- expect(subject.flipper_id).to eq('Experiment;__id__')
+ experiment_instance.instance_variable_set(:@experiment, instance_double('Gitlab::Experiment', id: '__id__'))
+ expect(experiment_instance.flipper_id).to eq('Experiment;__id__')
end
it "lets the experiment provide a flipper id so it can override the default" do
allow(subject_experiment).to receive(:flipper_id).and_return('_my_overridden_id_')
- expect(subject.flipper_id).to eq('_my_overridden_id_')
+ expect(experiment_instance.flipper_id).to eq('_my_overridden_id_')
end
end
end
diff --git a/spec/models/award_emoji_spec.rb b/spec/models/award_emoji_spec.rb
index a901453ba9f..87abd8a676d 100644
--- a/spec/models/award_emoji_spec.rb
+++ b/spec/models/award_emoji_spec.rb
@@ -319,17 +319,6 @@ RSpec.describe AwardEmoji, feature_category: :team_planning do
expect(new_award.url).to eq(custom_emoji.url)
end
- describe 'when inside subgroup' do
- let_it_be(:subgroup) { create(:group, parent: custom_emoji.group) }
- let_it_be(:project) { create(:project, namespace: subgroup) }
-
- it 'is set for custom emoji' do
- new_award = build_award(custom_emoji.name)
-
- expect(new_award.url).to eq(custom_emoji.url)
- end
- end
-
context 'feature flag disabled' do
before do
stub_feature_flags(custom_emoji: false)
diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb
index cbdf05cf28f..15655d08556 100644
--- a/spec/models/custom_emoji_spec.rb
+++ b/spec/models/custom_emoji_spec.rb
@@ -48,45 +48,4 @@ RSpec.describe CustomEmoji do
expect(emoji.errors.messages).to eq(file: ["is blocked: Only allowed schemes are http, https"])
end
end
-
- describe '#for_resource' do
- let_it_be(:group) { create(:group) }
- let_it_be(:custom_emoji) { create(:custom_emoji, namespace: group) }
-
- context 'when custom_emoji feature flag is disabled' do
- before do
- stub_feature_flags(custom_emoji: false)
- end
-
- it { expect(described_class.for_resource(group)).to eq([]) }
- end
-
- context 'when group is nil' do
- let_it_be(:group) { nil }
-
- it { expect(described_class.for_resource(group)).to eq([]) }
- end
-
- context 'when resource is a project' do
- let_it_be(:project) { create(:project) }
-
- it { expect(described_class.for_resource(project)).to eq([]) }
- end
-
- it { expect(described_class.for_resource(group)).to eq([custom_emoji]) }
- end
-
- describe '#for_namespaces' do
- let_it_be(:group) { create(:group) }
- let_it_be(:custom_emoji) { create(:custom_emoji, namespace: group, name: 'parrot') }
-
- it { expect(described_class.for_namespaces([group.id])).to eq([custom_emoji]) }
-
- context 'with subgroup' do
- let_it_be(:subgroup) { create(:group, parent: group) }
- let_it_be(:subgroup_emoji) { create(:custom_emoji, namespace: subgroup, name: 'parrot') }
-
- it { expect(described_class.for_namespaces([subgroup.id, group.id])).to eq([subgroup_emoji]) }
- end
- end
end
diff --git a/spec/requests/api/graphql/custom_emoji_query_spec.rb b/spec/requests/api/graphql/custom_emoji_query_spec.rb
index c89ad0002b4..1858ea831dd 100644
--- a/spec/requests/api/graphql/custom_emoji_query_spec.rb
+++ b/spec/requests/api/graphql/custom_emoji_query_spec.rb
@@ -35,14 +35,14 @@ RSpec.describe 'getting custom emoji within namespace', feature_category: :share
expect(graphql_data['group']['customEmoji']['nodes'].first['name']).to eq(custom_emoji.name)
end
- it 'returns empty array when the custom_emoji feature flag is disabled' do
+ it 'returns nil custom emoji when the custom_emoji feature flag is disabled' do
stub_feature_flags(custom_emoji: false)
post_graphql(custom_emoji_query(group), current_user: current_user)
expect(response).to have_gitlab_http_status(:ok)
expect(graphql_data['group']).to be_present
- expect(graphql_data['group']['customEmoji']['nodes']).to eq([])
+ expect(graphql_data['group']['customEmoji']).to be_nil
end
it 'returns nil group when unauthorised' do
diff --git a/spec/serializers/discussion_entity_spec.rb b/spec/serializers/discussion_entity_spec.rb
index 4b818ce35e6..0fe10ed2c6d 100644
--- a/spec/serializers/discussion_entity_spec.rb
+++ b/spec/serializers/discussion_entity_spec.rb
@@ -53,6 +53,13 @@ RSpec.describe DiscussionEntity do
.to match_schema('entities/note_user_entity')
end
+ it 'exposes the url for custom award emoji' do
+ custom_emoji = create(:custom_emoji, group: group)
+ create(:award_emoji, awardable: note, name: custom_emoji.name)
+
+ expect(subject[:notes].last[:award_emoji].first.keys).to include(:url)
+ end
+
context 'when is LegacyDiffDiscussion' do
let(:discussion) { create(:legacy_diff_note_on_merge_request, noteable: note.noteable, project: project).to_discussion }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 4876acfce8a..e57e110926b 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -212,7 +212,6 @@ RSpec.configure do |config|
config.include_context 'when rendered has no HTML escapes', type: :view
include StubFeatureFlags
- include StubSaasFeatures
include StubSnowplow
include StubMember
diff --git a/spec/support/helpers/stub_saas_features.rb b/spec/support/helpers/stub_saas_features.rb
deleted file mode 100644
index 82ad6e59cb4..00000000000
--- a/spec/support/helpers/stub_saas_features.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module StubSaasFeatures
- # Stub SaaS feature with `feature_name: true/false`
- #
- # @param [Hash] features where key is feature name and value is boolean whether enabled or not.
- #
- # Examples
- # - `stub_saas_features(onboarding: false)` ... Disable `onboarding`
- # SaaS feature globally.
- # - `stub_saas_features(onboarding: true)` ... Enable `onboarding`
- # SaaS feature globally.
- def stub_saas_features(features)
- all_features = ::Gitlab::Saas::FEATURES.index_with { false }
- all_features.merge!(features)
-
- all_features.each do |feature_name, value|
- raise ArgumentError, 'value must be boolean' unless value.in? [true, false]
-
- allow(::Gitlab::Saas).to receive(:feature_available?).with(feature_name).and_return(value)
- end
- end
-end
diff --git a/spec/support_specs/helpers/stub_saas_features_spec.rb b/spec/support_specs/helpers/stub_saas_features_spec.rb
deleted file mode 100644
index db608c774c0..00000000000
--- a/spec/support_specs/helpers/stub_saas_features_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe StubSaasFeatures, feature_category: :shared do
- describe '#stub_saas_features' do
- using RSpec::Parameterized::TableSyntax
-
- let(:feature_name) { :feature_one }
- let(:all_features) { [feature_name, :feature_two, :feature_three] }
-
- before do
- stub_const("Gitlab::Saas::FEATURES", all_features)
- end
-
- context 'when checking global state' do
- where(:feature_value) do
- [true, false]
- end
-
- with_them do
- before do
- stub_saas_features(feature_name => feature_value)
- end
-
- it { expect(::Gitlab::Saas.feature_available?(feature_name)).to eq(feature_value) }
- end
- end
-
- context 'when value is not boolean' do
- it 'raises an error' do
- expect do
- stub_saas_features(feature_name => '_not_boolean_')
- end.to raise_error(ArgumentError, /value must be boolean/)
- end
- end
-
- it 'subsequent run changes state' do
- # enable FF on all
- stub_saas_features({ feature_name => true })
- expect(::Gitlab::Saas.feature_available?(feature_name)).to eq(true)
-
- # disable FF on all
- stub_saas_features({ feature_name => false })
- expect(::Gitlab::Saas.feature_available?(feature_name)).to eq(false)
- end
-
- it 'handles multiple features' do
- stub_saas_features(feature_name => false, some_new_feature: true)
-
- expect(::Gitlab::Saas.feature_available?(feature_name)).to eq(false)
- expect(::Gitlab::Saas.feature_available?(:some_new_feature)).to eq(true)
- end
-
- context 'when checking multiple features' do
- it 'stubs defaults false value for other known features' do
- stub_saas_features(feature_one: true)
-
- expect(::Gitlab::Saas.feature_available?(:feature_one)).to eq(true)
- expect(::Gitlab::Saas.feature_available?(:feature_two)).to eq(false)
- expect(::Gitlab::Saas.feature_available?(:feature_three)).to eq(false)
- end
- end
- end
-end