+
{{ __('Create') }}
-
+
{{ __('Cancel') }}
diff --git a/app/assets/stylesheets/highlight/themes/dark.scss b/app/assets/stylesheets/highlight/themes/dark.scss
index 156f7ec3802..0b696f1be60 100644
--- a/app/assets/stylesheets/highlight/themes/dark.scss
+++ b/app/assets/stylesheets/highlight/themes/dark.scss
@@ -94,7 +94,8 @@ $dark-il: #de935f;
}
.line-numbers,
- .diff-line-num {
+ .diff-line-num,
+ .code-search-line {
background-color: $dark-main-bg;
}
@@ -168,7 +169,8 @@ $dark-il: #de935f;
}
.diff-grid-left:hover,
- .diff-grid-right:hover {
+ .diff-grid-right:hover,
+ &.code-search-line:hover {
.diff-line-num:not(.empty-cell) {
@include line-number-hover;
}
diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss
index 5e259b72442..ae72c0b6bf4 100644
--- a/app/assets/stylesheets/highlight/themes/monokai.scss
+++ b/app/assets/stylesheets/highlight/themes/monokai.scss
@@ -95,7 +95,8 @@ $monokai-gh: #75715e;
}
.line-numbers,
- .diff-line-num {
+ .diff-line-num,
+ .code-search-line {
background-color: $monokai-bg;
}
@@ -169,7 +170,8 @@ $monokai-gh: #75715e;
}
.diff-grid-left:hover,
- .diff-grid-right:hover {
+ .diff-grid-right:hover,
+ &.code-search-line:hover {
.diff-line-num:not(.empty-cell) {
@include line-number-hover;
}
diff --git a/app/assets/stylesheets/highlight/themes/none.scss b/app/assets/stylesheets/highlight/themes/none.scss
index 999719685b6..913b289d808 100644
--- a/app/assets/stylesheets/highlight/themes/none.scss
+++ b/app/assets/stylesheets/highlight/themes/none.scss
@@ -16,7 +16,8 @@
}
.line-numbers,
- .diff-line-num {
+ .diff-line-num,
+ .code-search-line {
background-color: $gray-light;
}
@@ -66,7 +67,8 @@
}
.diff-grid-left:hover,
- .diff-grid-right:hover {
+ .diff-grid-right:hover,
+ &.code-search-line:hover {
.diff-line-num:not(.empty-cell) {
@include line-number-hover;
}
diff --git a/app/assets/stylesheets/highlight/themes/solarized-dark.scss b/app/assets/stylesheets/highlight/themes/solarized-dark.scss
index 8a20b323332..eee699ca4c2 100644
--- a/app/assets/stylesheets/highlight/themes/solarized-dark.scss
+++ b/app/assets/stylesheets/highlight/themes/solarized-dark.scss
@@ -98,7 +98,8 @@ $solarized-dark-il: #2aa198;
}
.line-numbers,
- .diff-line-num {
+ .diff-line-num,
+ .code-search-line {
background-color: $solarized-dark-line-bg;
}
@@ -148,7 +149,8 @@ $solarized-dark-il: #2aa198;
}
.diff-grid-left:hover,
- .diff-grid-right:hover {
+ .diff-grid-right:hover,
+ &.code-search-line:hover {
.diff-line-num:not(.empty-cell) {
@include line-number-hover;
}
diff --git a/app/assets/stylesheets/highlight/themes/solarized-light.scss b/app/assets/stylesheets/highlight/themes/solarized-light.scss
index 1f1b13d0faa..8c5e1f7318b 100644
--- a/app/assets/stylesheets/highlight/themes/solarized-light.scss
+++ b/app/assets/stylesheets/highlight/themes/solarized-light.scss
@@ -105,7 +105,8 @@ $solarized-light-il: #2aa198;
}
.line-numbers,
- .diff-line-num {
+ .diff-line-num,
+ .code-search-line {
background-color: $solarized-light-line-bg;
}
@@ -168,7 +169,8 @@ $solarized-light-il: #2aa198;
}
.diff-grid-left:hover,
- .diff-grid-right:hover {
+ .diff-grid-right:hover,
+ &.code-search-line:hover {
.diff-line-num:not(.empty-cell) {
@include line-number-hover;
}
diff --git a/app/assets/stylesheets/highlight/white_base.scss b/app/assets/stylesheets/highlight/white_base.scss
index f13c8bb3891..c0f8475323a 100644
--- a/app/assets/stylesheets/highlight/white_base.scss
+++ b/app/assets/stylesheets/highlight/white_base.scss
@@ -82,7 +82,8 @@ $white-gc-bg: #eaf2f5;
}
.line-numbers,
-.diff-line-num {
+.diff-line-num,
+.code-search-line {
background-color: $gray-light;
&.conflict_marker,
@@ -128,7 +129,8 @@ pre.code,
}
.diff-grid-left:hover,
- .diff-grid-right:hover {
+ .diff-grid-right:hover,
+ &.code-search-line:hover {
.diff-line-num:not(.empty-cell):not(.conflict_marker_their):not(.conflict_marker_our) {
@include line-number-hover;
}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 2e6c6a021f8..4c31cc6e111 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -321,6 +321,51 @@ input[type='checkbox']:hover {
}
}
+// This overrides parts of the Project File View CSS
+// We leverage most of the styling but broke off
+// from how we were doing it in `shared/file_highlight`
+#search-blob-content {
+ .line_holder {
+ pre {
+ padding: 0; // This overrides the existing style that will add space between each line.
+ }
+
+ svg {
+ float: none; // We have more than one icon on this implementation and don't want to float them.
+ margin: 0; // We will manage the margin with GitLab UI utility classes
+ }
+
+ .line-numbers {
+ padding: 0; // This overrides the existing style that will add space between each line.
+ min-width: 6.5rem; // Ensure our numbers fit
+
+ .diff-line-num {
+ a {
+ transition: none; // There will be a hover transition from theme, blue, darkened
+ }
+ }
+ }
+
+ &:hover {
+ svg {
+ visibility: visible; // We want to show the icons when the any part of the line is hovered
+ }
+ }
+
+ // The icons only appear on hover
+ // So on mobile we can hide them and retake the space for the code blob
+ @include media-breakpoint-down(sm) {
+ svg {
+ display: none;
+ }
+
+ .line-numbers {
+ min-width: 4rem;
+ }
+ }
+ }
+}
+
// Disable webkit input icons, link to solution: https://stackoverflow.com/questions/9421551/how-do-i-remove-all-default-webkit-search-field-styling
/* stylelint-disable property-no-vendor-prefix */
input[type='search']::-webkit-search-decoration,
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 899fa614949..f48d03869a4 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -50,6 +50,8 @@ class GraphqlController < ApplicationController
end
rescue_from StandardError do |exception|
+ @exception_object = exception
+
log_exception(exception)
if Rails.env.test? || Rails.env.development?
@@ -197,7 +199,9 @@ class GraphqlController < ApplicationController
# Merging to :metadata will ensure these are logged as top level keys
payload[:metadata] ||= {}
- payload[:metadata].merge!(graphql: logs)
+ payload[:metadata][:graphql] = logs
+
+ payload[:exception_object] = @exception_object if @exception_object
end
def logs
diff --git a/app/graphql/resolvers/base_issues_resolver.rb b/app/graphql/resolvers/base_issues_resolver.rb
index 54ebb697cb2..dca93444907 100644
--- a/app/graphql/resolvers/base_issues_resolver.rb
+++ b/app/graphql/resolvers/base_issues_resolver.rb
@@ -4,13 +4,13 @@ module Resolvers
class BaseIssuesResolver < BaseResolver
prepend IssueResolverArguments
- argument :state, Types::IssuableStateEnum,
- required: false,
- description: 'Current state of this issue.'
argument :sort, Types::IssueSortEnum,
description: 'Sort issues by this criteria.',
required: false,
default_value: :created_desc
+ argument :state, Types::IssuableStateEnum,
+ required: false,
+ description: 'Current state of this issue.'
type Types::IssueType.connection_type, null: true
diff --git a/app/graphql/resolvers/design_management/designs_resolver.rb b/app/graphql/resolvers/design_management/designs_resolver.rb
index dec778fac80..a62ef6d76e5 100644
--- a/app/graphql/resolvers/design_management/designs_resolver.rb
+++ b/app/graphql/resolvers/design_management/designs_resolver.rb
@@ -8,16 +8,16 @@ module Resolvers
type ::Types::DesignManagement::DesignType.connection_type, null: true
- argument :ids, [DesignID],
- required: false,
- description: 'Filters designs by their ID.'
- argument :filenames, [GraphQL::Types::String],
- required: false,
- description: 'Filters designs by their filename.'
argument :at_version, VersionID,
required: false,
description: 'Filters designs to only those that existed at the version. ' \
'If argument is omitted or nil then all designs will reflect the latest version'
+ argument :filenames, [GraphQL::Types::String],
+ required: false,
+ description: 'Filters designs by their filename.'
+ argument :ids, [DesignID],
+ required: false,
+ description: 'Filters designs by their ID.'
def self.single
::Resolvers::DesignManagement::DesignResolver
diff --git a/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
index d879c1434dc..76e365c40b1 100644
--- a/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
+++ b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
@@ -16,16 +16,16 @@ module Resolvers
authorize :read_design
- argument :id, DesignAtVersionID,
- required: false,
- as: :design_at_version_id,
- description: 'ID of the DesignAtVersion.'
argument :design_id, DesignID,
required: false,
description: 'ID of a specific design.'
argument :filename, GraphQL::Types::String,
required: false,
description: 'Filename of a specific design.'
+ argument :id, DesignAtVersionID,
+ required: false,
+ as: :design_at_version_id,
+ description: 'ID of the DesignAtVersion.'
def self.single
self
diff --git a/app/helpers/x509_helper.rb b/app/helpers/x509_helper.rb
index 4afc5643af4..1a9dbefceef 100644
--- a/app/helpers/x509_helper.rb
+++ b/app/helpers/x509_helper.rb
@@ -18,6 +18,6 @@ module X509Helper
end
def x509_signature?(sig)
- sig.is_a?(X509CommitSignature) || sig.is_a?(Gitlab::X509::Signature)
+ sig.is_a?(CommitSignatures::X509CommitSignature) || sig.is_a?(Gitlab::X509::Signature)
end
end
diff --git a/app/models/commit_signatures/gpg_signature.rb b/app/models/commit_signatures/gpg_signature.rb
new file mode 100644
index 00000000000..1ce76b53da4
--- /dev/null
+++ b/app/models/commit_signatures/gpg_signature.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+module CommitSignatures
+ class GpgSignature < ApplicationRecord
+ include CommitSignature
+
+ sha_attribute :gpg_key_primary_keyid
+
+ belongs_to :gpg_key
+ belongs_to :gpg_key_subkey
+
+ validates :gpg_key_primary_keyid, presence: true
+
+ def self.with_key_and_subkeys(gpg_key)
+ subkey_ids = gpg_key.subkeys.pluck(:id)
+
+ where(
+ arel_table[:gpg_key_id].eq(gpg_key.id).or(
+ arel_table[:gpg_key_subkey_id].in(subkey_ids)
+ )
+ )
+ end
+
+ def gpg_key=(model)
+ case model
+ when GpgKey
+ super
+ when GpgKeySubkey
+ self.gpg_key_subkey = model
+ when NilClass
+ super
+ self.gpg_key_subkey = nil
+ end
+ end
+
+ def gpg_key
+ if gpg_key_id
+ super
+ elsif gpg_key_subkey_id
+ gpg_key_subkey
+ end
+ end
+
+ def gpg_key_primary_keyid
+ super&.upcase
+ end
+
+ def gpg_commit
+ return unless commit
+
+ Gitlab::Gpg::Commit.new(commit)
+ end
+ end
+end
diff --git a/app/models/commit_signatures/x509_commit_signature.rb b/app/models/commit_signatures/x509_commit_signature.rb
new file mode 100644
index 00000000000..2cbb331dd7e
--- /dev/null
+++ b/app/models/commit_signatures/x509_commit_signature.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+module CommitSignatures
+ class X509CommitSignature < ApplicationRecord
+ include CommitSignature
+
+ belongs_to :x509_certificate, class_name: 'X509Certificate', foreign_key: 'x509_certificate_id', optional: false
+
+ validates :x509_certificate_id, presence: true
+
+ def x509_commit
+ return unless commit
+
+ Gitlab::X509::Commit.new(commit)
+ end
+ end
+end
diff --git a/app/models/concerns/commit_signature.rb b/app/models/concerns/commit_signature.rb
new file mode 100644
index 00000000000..5bdfa9a2966
--- /dev/null
+++ b/app/models/concerns/commit_signature.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+module CommitSignature
+ extend ActiveSupport::Concern
+
+ included do
+ include ShaAttribute
+
+ sha_attribute :commit_sha
+
+ enum verification_status: {
+ unverified: 0,
+ verified: 1,
+ same_user_different_email: 2,
+ other_user: 3,
+ unverified_key: 4,
+ unknown_key: 5,
+ multiple_signatures: 6
+ }
+
+ belongs_to :project, class_name: 'Project', foreign_key: 'project_id', optional: false
+
+ validates :commit_sha, presence: true
+ validates :project_id, presence: true
+
+ scope :by_commit_sha, ->(shas) { where(commit_sha: shas) }
+ end
+
+ class_methods do
+ def safe_create!(attributes)
+ create_with(attributes)
+ .safe_find_or_create_by!(commit_sha: attributes[:commit_sha])
+ end
+
+ # Find commits that are lacking a signature in the database at present
+ def unsigned_commit_shas(commit_shas)
+ return [] if commit_shas.empty?
+
+ signed = by_commit_sha(commit_shas).pluck(:commit_sha)
+ commit_shas - signed
+ end
+ end
+
+ def commit
+ project.commit(commit_sha)
+ end
+
+ def user
+ commit.committer
+ end
+end
diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb
index 0cb3662368c..a56e28859c9 100644
--- a/app/models/gpg_key.rb
+++ b/app/models/gpg_key.rb
@@ -92,13 +92,13 @@ class GpgKey < ApplicationRecord
end
def revoke
- GpgSignature
+ CommitSignatures::GpgSignature
.with_key_and_subkeys(self)
- .where.not(verification_status: GpgSignature.verification_statuses[:unknown_key])
+ .where.not(verification_status: CommitSignatures::GpgSignature.verification_statuses[:unknown_key])
.update_all(
gpg_key_id: nil,
gpg_key_subkey_id: nil,
- verification_status: GpgSignature.verification_statuses[:unknown_key],
+ verification_status: CommitSignatures::GpgSignature.verification_statuses[:unknown_key],
updated_at: Time.zone.now
)
diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb
deleted file mode 100644
index 2775b520b2f..00000000000
--- a/app/models/gpg_signature.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# frozen_string_literal: true
-
-class GpgSignature < ApplicationRecord
- include ShaAttribute
-
- sha_attribute :commit_sha
- sha_attribute :gpg_key_primary_keyid
-
- enum verification_status: {
- unverified: 0,
- verified: 1,
- same_user_different_email: 2,
- other_user: 3,
- unverified_key: 4,
- unknown_key: 5,
- multiple_signatures: 6
- }
-
- belongs_to :project
- belongs_to :gpg_key
- belongs_to :gpg_key_subkey
-
- validates :commit_sha, presence: true
- validates :project_id, presence: true
- validates :gpg_key_primary_keyid, presence: true
-
- scope :by_commit_sha, ->(shas) { where(commit_sha: shas) }
-
- def self.with_key_and_subkeys(gpg_key)
- subkey_ids = gpg_key.subkeys.pluck(:id)
-
- where(
- arel_table[:gpg_key_id].eq(gpg_key.id).or(
- arel_table[:gpg_key_subkey_id].in(subkey_ids)
- )
- )
- end
-
- def self.safe_create!(attributes)
- create_with(attributes)
- .safe_find_or_create_by!(commit_sha: attributes[:commit_sha])
- end
-
- # Find commits that are lacking a signature in the database at present
- def self.unsigned_commit_shas(commit_shas)
- return [] if commit_shas.empty?
-
- signed = GpgSignature.where(commit_sha: commit_shas).pluck(:commit_sha)
-
- commit_shas - signed
- end
-
- def gpg_key=(model)
- case model
- when GpgKey
- super
- when GpgKeySubkey
- self.gpg_key_subkey = model
- when NilClass
- super
- self.gpg_key_subkey = nil
- end
- end
-
- def gpg_key
- if gpg_key_id
- super
- elsif gpg_key_subkey_id
- gpg_key_subkey
- end
- end
-
- def gpg_key_primary_keyid
- super&.upcase
- end
-
- def commit
- project.commit(commit_sha)
- end
-
- def gpg_commit
- return unless commit
-
- Gitlab::Gpg::Commit.new(commit)
- end
-end
diff --git a/app/models/packages/conan/metadatum.rb b/app/models/packages/conan/metadatum.rb
index ad4b499c1e5..58af34879af 100644
--- a/app/models/packages/conan/metadatum.rb
+++ b/app/models/packages/conan/metadatum.rb
@@ -10,17 +10,10 @@ class Packages::Conan::Metadatum < ApplicationRecord
validates :package_username,
:package_channel,
presence: true,
- format: { with: Gitlab::Regex.conan_recipe_component_regex },
- if: -> { Feature.disabled?(:packages_conan_allow_empty_username_channel) }
-
- validates :package_username,
- :package_channel,
- presence: true,
- format: { with: Gitlab::Regex.conan_recipe_user_channel_regex },
- if: -> { Feature.enabled?(:packages_conan_allow_empty_username_channel) }
+ format: { with: Gitlab::Regex.conan_recipe_user_channel_regex }
validate :conan_package_type
- validate :username_channel_none_values, if: -> { Feature.enabled?(:packages_conan_allow_empty_username_channel) }
+ validate :username_channel_none_values
def recipe
"#{package.name}/#{package.version}@#{package_username}/#{package_channel}"
diff --git a/app/models/x509_certificate.rb b/app/models/x509_certificate.rb
index 428fd336a32..2c1d0110b7c 100644
--- a/app/models/x509_certificate.rb
+++ b/app/models/x509_certificate.rb
@@ -13,7 +13,7 @@ class X509Certificate < ApplicationRecord
belongs_to :x509_issuer, class_name: 'X509Issuer', foreign_key: 'x509_issuer_id', optional: false
- has_many :x509_commit_signatures, inverse_of: 'x509_certificate'
+ has_many :x509_commit_signatures, class_name: 'CommitSignatures::X509CommitSignature', inverse_of: 'x509_certificate'
# rfc 5280 - 4.2.1.2 Subject Key Identifier
validates :subject_key_identifier, presence: true, format: { with: /\A(\h{2}:){19}\h{2}\z/ }
diff --git a/app/models/x509_commit_signature.rb b/app/models/x509_commit_signature.rb
deleted file mode 100644
index 57d809f7cfb..00000000000
--- a/app/models/x509_commit_signature.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-class X509CommitSignature < ApplicationRecord
- include ShaAttribute
-
- sha_attribute :commit_sha
-
- enum verification_status: {
- unverified: 0,
- verified: 1
- }
-
- belongs_to :project, class_name: 'Project', foreign_key: 'project_id', optional: false
- belongs_to :x509_certificate, class_name: 'X509Certificate', foreign_key: 'x509_certificate_id', optional: false
-
- validates :commit_sha, presence: true
- validates :project_id, presence: true
- validates :x509_certificate_id, presence: true
-
- scope :by_commit_sha, ->(shas) { where(commit_sha: shas) }
-
- def self.safe_create!(attributes)
- create_with(attributes)
- .safe_find_or_create_by!(commit_sha: attributes[:commit_sha])
- end
-
- # Find commits that are lacking a signature in the database at present
- def self.unsigned_commit_shas(commit_shas)
- return [] if commit_shas.empty?
-
- signed = by_commit_sha(commit_shas).pluck(:commit_sha)
- commit_shas - signed
- end
-
- def commit
- project.commit(commit_sha)
- end
-
- def x509_commit
- return unless commit
-
- Gitlab::X509::Commit.new(commit)
- end
-
- def user
- commit.committer
- end
-end
diff --git a/app/services/git/branch_hooks_service.rb b/app/services/git/branch_hooks_service.rb
index 9b113be5465..aa471d3a69f 100644
--- a/app/services/git/branch_hooks_service.rb
+++ b/app/services/git/branch_hooks_service.rb
@@ -157,11 +157,11 @@ module Git
end
def unsigned_x509_shas(commits)
- X509CommitSignature.unsigned_commit_shas(commits.map(&:sha))
+ CommitSignatures::X509CommitSignature.unsigned_commit_shas(commits.map(&:sha))
end
def unsigned_gpg_shas(commits)
- GpgSignature.unsigned_commit_shas(commits.map(&:sha))
+ CommitSignatures::GpgSignature.unsigned_commit_shas(commits.map(&:sha))
end
def enqueue_update_signatures
diff --git a/app/views/admin/projects/_archived.html.haml b/app/views/admin/projects/_archived.html.haml
index 8b4d5806c47..3d79cc7ca71 100644
--- a/app/views/admin/projects/_archived.html.haml
+++ b/app/views/admin/projects/_archived.html.haml
@@ -1,3 +1,2 @@
- if project.archived
- %span.badge.badge-warning
- = _('archived')
+ = gl_badge_tag _('archived'), variant: :warning
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 9dbf60b119c..d8461d85a89 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -18,8 +18,7 @@
= render 'delete_project_button', project: project
.stats
- %span.badge.badge-pill
- = storage_counter(project.statistics&.storage_size)
+ = gl_badge_tag storage_counter(project.statistics&.storage_size)
= render 'project_badges', project: project
.title
diff --git a/app/views/projects/protected_branches/shared/_matching_branch.html.haml b/app/views/projects/protected_branches/shared/_matching_branch.html.haml
index 9145be5d2f2..1a2ec38fae9 100644
--- a/app/views/projects/protected_branches/shared/_matching_branch.html.haml
+++ b/app/views/projects/protected_branches/shared/_matching_branch.html.haml
@@ -3,7 +3,7 @@
= link_to matching_branch.name, project_ref_path(@project, matching_branch.name), class: 'ref-name'
- if @project.root_ref?(matching_branch.name)
- %span.badge.badge-info.gl-ml-2 default
+ = gl_badge_tag s_('ProtectedBranch|default'), { variant: :info }, { class: 'gl-ml-2' }
%td
- commit = @project.commit(matching_branch.name)
= link_to(commit.short_id, project_commit_path(@project, commit.id), class: 'commit-sha')
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index aeb37022f99..3681f823ef5 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -1,5 +1,6 @@
- project = blob.project
- return unless project
- blob_link = project_blob_path(project, tree_join(repository_ref(project), blob.path))
+- blame_link = project_blame_path(project, tree_join(repository_ref(project), blob.path))
-= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, path: blob.path, blob_link: blob_link }
+= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, path: blob.path, blob_link: blob_link, blame_link: blame_link }
diff --git a/app/views/search/results/_blob_data.html.haml b/app/views/search/results/_blob_data.html.haml
index 88a2ab4bb42..c42367f45c5 100644
--- a/app/views/search/results/_blob_data.html.haml
+++ b/app/views/search/results/_blob_data.html.haml
@@ -9,7 +9,7 @@
- if blob.data
- if blob.data.size > 0
.file-content.code.term{ data: { qa_selector: 'file_text_content' } }
- = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, blob_link: blob_link, highlight_line: blob.highlight_line
+ = render 'search/results/blob_highlight', blob: blob, first_line_number: blob.startline, blob_link: blob_link, blame_link: blame_link, highlight_line: blob.highlight_line
- else
.file-content.code
.nothing-here-block
diff --git a/app/views/search/results/_blob_highlight.html.haml b/app/views/search/results/_blob_highlight.html.haml
new file mode 100644
index 00000000000..de1fa9a7fd5
--- /dev/null
+++ b/app/views/search/results/_blob_highlight.html.haml
@@ -0,0 +1,22 @@
+- offset = defined?(first_line_number) ? first_line_number : 1
+- highlight = defined?(highlight_line) && highlight_line ? highlight_line - offset : nil
+
+#search-blob-content.file-content.code.js-syntax-highlight{ class: 'gl-py-3!' }
+ - if blob.present?
+ .blob-content{ data: { blob_id: blob.id, path: blob.path, highlight_line: highlight, qa_selector: 'file_content' } }
+ - blob.present.highlight.lines.each_with_index do |line, index|
+ - i = index + offset
+ .line_holder.code-search-line
+ .line-numbers
+ .gl-display-flex
+ %span.diff-line-num.gl-pl-3
+ %a.has-tooltip{ href: "#{blame_link}#L#{i}", id: "blame-L#{i}", 'data-line-number' => i, title: _('View blame') }
+ = sprite_icon('git')
+ %span.diff-line-num.flex-grow-1.gl-pr-3
+ %a{ href: "#{blob_link}#L#{i}", id: "blob-L#{i}", 'data-line-number' => i, class: 'gl-display-flex! gl-align-items-center gl-justify-content-end' }
+ = sprite_icon('link', css_class: 'gl-ml-3! gl-mr-1!')
+ = i
+ %pre.code.highlight
+ %code
+ = line.html_safe
+
diff --git a/app/views/shared/members/_requests.html.haml b/app/views/shared/members/_requests.html.haml
index 8b0a85656dc..ec08dde37bf 100644
--- a/app/views/shared/members/_requests.html.haml
+++ b/app/views/shared/members/_requests.html.haml
@@ -9,7 +9,7 @@
.card-header
= _("Users requesting access to")
%strong= membership_source.name
- %span.badge.badge-pill= requesters.size
+ = gl_badge_tag requesters.size
= render 'shared/members/manage_access_button', path: membership_source.is_a?(Project) ? project_project_members_path(@project, tab: 'access_requests') : group_group_members_path(@group, tab: 'access_requests')
%ul.content-list.members-list
= render partial: 'shared/members/member',
diff --git a/app/views/shared/projects/_archived.html.haml b/app/views/shared/projects/_archived.html.haml
index f24fe3a8b89..018bf137cc6 100644
--- a/app/views/shared/projects/_archived.html.haml
+++ b/app/views/shared/projects/_archived.html.haml
@@ -1,3 +1,2 @@
- if project.archived
- %span.d-flex.badge-pill.gl-badge.badge-warning.gl-ml-3
- = _('archived')
+ = gl_badge_tag _('archived'), { variant: :warning }, { class: 'gl-display-flex gl-ml-3' }
diff --git a/config/feature_flags/development/packages_conan_allow_empty_username_channel.yml b/config/feature_flags/development/packages_conan_allow_empty_username_channel.yml
deleted file mode 100644
index 15a38dcf1b6..00000000000
--- a/config/feature_flags/development/packages_conan_allow_empty_username_channel.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: packages_conan_allow_empty_username_channel
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75106
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/346006
-milestone: '14.5'
-type: development
-group: group::package
-default_enabled: false
diff --git a/config/initializers/grape_validators.rb b/config/initializers/grape_validators.rb
index 402da1c9abe..1492894e1fa 100644
--- a/config/initializers/grape_validators.rb
+++ b/config/initializers/grape_validators.rb
@@ -11,6 +11,3 @@ Grape::Validations.register_validator(:untrusted_regexp, ::API::Validations::Val
Grape::Validations.register_validator(:email_or_email_list, ::API::Validations::Validators::EmailOrEmailList)
Grape::Validations.register_validator(:iteration_id, ::API::Validations::Validators::IntegerOrCustomValue)
Grape::Validations.register_validator(:project_portable, ::API::Validations::Validators::ProjectPortable)
-# TODO Delete this validator along with the packages_conan_allow_empty_username_channel feature flag
-# # https://gitlab.com/gitlab-org/gitlab/-/issues/346006
-Grape::Validations.register_validator('packages_conan_user_channel', ::API::Validations::Validators::PackagesConanUserChannel)
diff --git a/config/metrics/counts_28d/20210216175101_merge_requests_users.yml b/config/metrics/counts_28d/20210216175101_merge_requests_users.yml
index 2b43fbf8131..e5b5300dae3 100644
--- a/config/metrics/counts_28d/20210216175101_merge_requests_users.yml
+++ b/config/metrics/counts_28d/20210216175101_merge_requests_users.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.create.merge_requests_users
description: Distinct count of users performing merge request actions like closed, merged, created, commented
product_section: dev
diff --git a/config/metrics/counts_28d/20210216175542_ci_builds.yml b/config/metrics/counts_28d/20210216175542_ci_builds.yml
index 371da6c937b..0c1523797c0 100644
--- a/config/metrics/counts_28d/20210216175542_ci_builds.yml
+++ b/config/metrics/counts_28d/20210216175542_ci_builds.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.verify.ci_builds
description: Unique monthly builds in project
product_section: ops
diff --git a/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml b/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml
index 317548c8c24..4d9b6b2cd9c 100644
--- a/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml
+++ b/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.verify.ci_internal_pipelines
description: Total pipelines in GitLab repositories in a month
product_section: ops
diff --git a/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml b/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml
index cd9ed768ce1..976ffa0444a 100644
--- a/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml
+++ b/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.verify.ci_pipeline_config_repository
description: Total Monthly Pipelines from templates in repository
product_section: ops
diff --git a/config/metrics/counts_28d/20210216175554_ci_pipelines.yml b/config/metrics/counts_28d/20210216175554_ci_pipelines.yml
index fb3992a766d..ee32c2baed9 100644
--- a/config/metrics/counts_28d/20210216175554_ci_pipelines.yml
+++ b/config/metrics/counts_28d/20210216175554_ci_pipelines.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.verify.ci_pipelines
description: Distinct users triggering pipelines in a month
product_section: ops
diff --git a/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml b/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml
index 9c2820ce851..3c35bed2ceb 100644
--- a/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml
+++ b/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.create.action_monthly_active_users_design_management
description: Monthly active users for design management
product_section: dev
diff --git a/config/metrics/counts_28d/20210216181050_packages.yml b/config/metrics/counts_28d/20210216181050_packages.yml
index 45997bad6f2..966f3fa48a3 100644
--- a/config/metrics/counts_28d/20210216181050_packages.yml
+++ b/config/metrics/counts_28d/20210216181050_packages.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts_monthly.packages
description: A monthly count of packages published to the registry
product_section: ops
diff --git a/config/metrics/counts_28d/20210216181139_issues.yml b/config/metrics/counts_28d/20210216181139_issues.yml
index 84f7f6f4ba8..de5238e3e77 100644
--- a/config/metrics/counts_28d/20210216181139_issues.yml
+++ b/config/metrics/counts_28d/20210216181139_issues.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.plan.issues
description: Count of users creating Issues in last 28 days.
product_section: dev
diff --git a/config/metrics/counts_28d/20210216181158_epics.yml b/config/metrics/counts_28d/20210216181158_epics.yml
index 57dd292b17a..aa3658b03bd 100644
--- a/config/metrics/counts_28d/20210216181158_epics.yml
+++ b/config/metrics/counts_28d/20210216181158_epics.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.plan.epics
description: Count distinct author ids from epics
product_section: dev
diff --git a/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml b/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml
index 0a7d5dc82ee..5dc6c335f34 100644
--- a/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml
+++ b/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: redis_hll_counters.issues_edit.g_project_management_issue_milestone_changed_monthly
description: Count of MAU changing an issue's milestone
product_section: dev
diff --git a/config/metrics/counts_28d/20210216181935_deployments.yml b/config/metrics/counts_28d/20210216181935_deployments.yml
index 24a06991d91..a8c2928caeb 100644
--- a/config/metrics/counts_28d/20210216181935_deployments.yml
+++ b/config/metrics/counts_28d/20210216181935_deployments.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.release.deployments
description: Unique users triggering deployments
product_section: ops
diff --git a/config/metrics/counts_28d/20210216181939_releases.yml b/config/metrics/counts_28d/20210216181939_releases.yml
index 87c39db5271..ea59a5be99f 100644
--- a/config/metrics/counts_28d/20210216181939_releases.yml
+++ b/config/metrics/counts_28d/20210216181939_releases.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.release.releases
description: Unique users creating release tags
product_section: ops
diff --git a/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml b/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml
index 71b7af1eace..e8d8ad16a08 100644
--- a/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml
+++ b/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.create.action_monthly_active_users_project_repo
description: Count of monthly active users who have performed any Git operation (read/write/push)
product_section: dev
diff --git a/config/metrics/counts_28d/20210216183701_jira.yml b/config/metrics/counts_28d/20210216183701_jira.yml
index c8f45b9f926..b171deb35f0 100644
--- a/config/metrics/counts_28d/20210216183701_jira.yml
+++ b/config/metrics/counts_28d/20210216183701_jira.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage_monthly.manage.issue_imports.jira
description: Count of imports from Jira
product_section: dev
diff --git a/config/metrics/counts_28d/20210216184322_i_code_review_user_approve_mr_monthly.yml b/config/metrics/counts_28d/20210216184322_i_code_review_user_approve_mr_monthly.yml
index 87d78d83450..e3e7aa10c95 100644
--- a/config/metrics/counts_28d/20210216184322_i_code_review_user_approve_mr_monthly.yml
+++ b/config/metrics/counts_28d/20210216184322_i_code_review_user_approve_mr_monthly.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: redis_hll_counters.code_review.i_code_review_user_approve_mr_monthly
description: Count of unique users per month who approve a merge request
product_stage: create
diff --git a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
index 637b02b93ed..1e3d07ed1da 100644
--- a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: redis_hll_counters.ci_templates.ci_templates_total_unique_counts_monthly
description: Total count of pipelines runs
product_section: ops
diff --git a/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml b/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
index be0fa6eaff7..a0dd87cd7dc 100644
--- a/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
+++ b/config/metrics/counts_28d/20210427102618_code_review_category_monthly_active_users.yml
@@ -1,11 +1,11 @@
---
-data_category: optional
+data_category: operational
key_path: counts_monthly.aggregated_metrics.code_review_category_monthly_active_users
description: Unique users performing actions on code review events
product_section: dev
product_stage: devops::create
product_group: group::code review
-product_category:
+product_category:
value_type: number
status: active
milestone: "13.12"
diff --git a/config/metrics/counts_all/20210216175229_auto_devops_enabled.yml b/config/metrics/counts_all/20210216175229_auto_devops_enabled.yml
index 0a26577ae8d..85870f728bb 100644
--- a/config/metrics/counts_all/20210216175229_auto_devops_enabled.yml
+++ b/config/metrics/counts_all/20210216175229_auto_devops_enabled.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.auto_devops_enabled
description: Projects with Auto DevOps template enabled (excluding implicit Auto DevOps
enabled and Auto DevOps template includes)
diff --git a/config/metrics/counts_all/20210216175520_ci_runners.yml b/config/metrics/counts_all/20210216175520_ci_runners.yml
index e402391f9ba..b3fa3f2678b 100644
--- a/config/metrics/counts_all/20210216175520_ci_runners.yml
+++ b/config/metrics/counts_all/20210216175520_ci_runners.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.ci_runners
description: Total configured Runners of all types
product_section: ops
diff --git a/config/metrics/counts_all/20210216175537_ci_pipelines.yml b/config/metrics/counts_all/20210216175537_ci_pipelines.yml
index 0a5e5ff0269..70b1c4138be 100644
--- a/config/metrics/counts_all/20210216175537_ci_pipelines.yml
+++ b/config/metrics/counts_all/20210216175537_ci_pipelines.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: usage_activity_by_stage.verify.ci_pipelines
description: Distinct Users triggering Total pipelines
product_section: ops
diff --git a/config/metrics/counts_all/20210216181011_projects_with_packages.yml b/config/metrics/counts_all/20210216181011_projects_with_packages.yml
index e26cae87f95..554ed451d64 100644
--- a/config/metrics/counts_all/20210216181011_projects_with_packages.yml
+++ b/config/metrics/counts_all/20210216181011_projects_with_packages.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.projects_with_packages
description: Projects with package registry enabled
product_section: ops
diff --git a/config/metrics/counts_all/20210216182004_commit_comment.yml b/config/metrics/counts_all/20210216182004_commit_comment.yml
index 4e2d402e9e1..b2b19dfcf17 100644
--- a/config/metrics/counts_all/20210216182004_commit_comment.yml
+++ b/config/metrics/counts_all/20210216182004_commit_comment.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.commit_comment
description: Count of total unique commit comments. Does not include MR diff comments
product_section: dev
diff --git a/config/metrics/counts_all/20210216182006_source_code_pushes.yml b/config/metrics/counts_all/20210216182006_source_code_pushes.yml
index aa5c55ec3e7..9930105d8cf 100644
--- a/config/metrics/counts_all/20210216182006_source_code_pushes.yml
+++ b/config/metrics/counts_all/20210216182006_source_code_pushes.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.source_code_pushes
description: Count of total Git push operations
product_section: dev
diff --git a/config/metrics/license/20210204124936_pages_version.yml b/config/metrics/license/20210204124936_pages_version.yml
index 5e498ceb6c4..878134574e2 100644
--- a/config/metrics/license/20210204124936_pages_version.yml
+++ b/config/metrics/license/20210204124936_pages_version.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: gitlab_pages.version
description: The version number of GitLab Pages
product_section: ops
diff --git a/config/metrics/settings/20210204124856_instance_auto_devops_enabled.yml b/config/metrics/settings/20210204124856_instance_auto_devops_enabled.yml
index 5b886288fec..f0bcf95871a 100644
--- a/config/metrics/settings/20210204124856_instance_auto_devops_enabled.yml
+++ b/config/metrics/settings/20210204124856_instance_auto_devops_enabled.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: instance_auto_devops_enabled
description: Whether auto DevOps is enabled
product_section: ops
diff --git a/config/metrics/settings/20210204124858_container_registry_enabled.yml b/config/metrics/settings/20210204124858_container_registry_enabled.yml
index c65d1934c61..1fdee829b84 100644
--- a/config/metrics/settings/20210204124858_container_registry_enabled.yml
+++ b/config/metrics/settings/20210204124858_container_registry_enabled.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: container_registry_enabled
description: A count of projects where the container registry is enabled
product_section: ops
diff --git a/config/metrics/settings/20210204124902_gitlab_shared_runners_enabled.yml b/config/metrics/settings/20210204124902_gitlab_shared_runners_enabled.yml
index 6b5719d284d..c58b3a8c8d5 100644
--- a/config/metrics/settings/20210204124902_gitlab_shared_runners_enabled.yml
+++ b/config/metrics/settings/20210204124902_gitlab_shared_runners_enabled.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: gitlab_shared_runners_enabled
description: Whether shared runners is enabled
product_section: ops
diff --git a/config/metrics/settings/20210204124914_prometheus_metrics_enabled.yml b/config/metrics/settings/20210204124914_prometheus_metrics_enabled.yml
index 1d13b72fbff..5b1447a58e8 100644
--- a/config/metrics/settings/20210204124914_prometheus_metrics_enabled.yml
+++ b/config/metrics/settings/20210204124914_prometheus_metrics_enabled.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: prometheus_metrics_enabled
description: Whether Prometheus Metrics endpoint is enabled
product_section: growth
diff --git a/config/metrics/settings/20210204124934_pages_enabled.yml b/config/metrics/settings/20210204124934_pages_enabled.yml
index 28e12d85e41..e267bd7109b 100644
--- a/config/metrics/settings/20210204124934_pages_enabled.yml
+++ b/config/metrics/settings/20210204124934_pages_enabled.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: gitlab_pages.enabled
description: Whether GitLab Pages is enabled
product_section: ops
diff --git a/config/metrics/settings/20210216180913_enabled.yml b/config/metrics/settings/20210216180913_enabled.yml
index c1e8869d9a6..9411f1cacf8 100644
--- a/config/metrics/settings/20210216180913_enabled.yml
+++ b/config/metrics/settings/20210216180913_enabled.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: object_store.packages.enabled
description: Whether Object Storage is enabled for Uploads
product_section: enablement
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index 64cf2524bf0..731ba04a9f7 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -105,8 +105,7 @@ For more details about creating and managing Conan packages, see the
#### Package without a username and a channel
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345055) in GitLab 14.6 [with a flag](../../../administration/feature_flags.md) named `packages_conan_allow_empty_username_channel`. Disabled by default.
-> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/345055) in GitLab 14.6.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345055) in GitLab 14.6.
Even though they are [recommended](https://docs.conan.io/en/latest/reference/conanfile/attributes.html#user-channel)
to distinguish your package from a similarly named existing package,
diff --git a/doc/user/project/repository/x509_signed_commits/index.md b/doc/user/project/repository/x509_signed_commits/index.md
index 2db7ae308bd..f9d9af3e672 100644
--- a/doc/user/project/repository/x509_signed_commits/index.md
+++ b/doc/user/project/repository/x509_signed_commits/index.md
@@ -290,7 +290,7 @@ To investigate why a commit shows as `Unverified`:
1. The verification status is stored in the database. To display the database record:
```ruby
- pp X509CommitSignature.by_commit_sha(commit.sha);nil
+ pp CommitSignatures::X509CommitSignature.by_commit_sha(commit.sha);nil
```
If all the previous checks returned the correct values:
diff --git a/lib/api/concerns/packages/conan_endpoints.rb b/lib/api/concerns/packages/conan_endpoints.rb
index fbb9e5cff53..edf20b6aebe 100644
--- a/lib/api/concerns/packages/conan_endpoints.rb
+++ b/lib/api/concerns/packages/conan_endpoints.rb
@@ -27,6 +27,7 @@ module API
PACKAGE_COMPONENT_REGEX = Gitlab::Regex.conan_recipe_component_regex
CONAN_REVISION_REGEX = Gitlab::Regex.conan_revision_regex
+ CONAN_REVISION_USER_CHANNEL_REGEX = Gitlab::Regex.conan_recipe_user_channel_regex
CONAN_FILES = (Gitlab::Regex::Packages::CONAN_RECIPE_FILES + Gitlab::Regex::Packages::CONAN_PACKAGE_FILES).freeze
@@ -105,12 +106,12 @@ module API
params do
requires :package_name, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package name'
requires :package_version, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package version'
- requires :package_username, type: String, packages_conan_user_channel: true, desc: 'Package username'
- requires :package_channel, type: String, packages_conan_user_channel: true, desc: 'Package channel'
+ requires :package_username, type: String, regexp: CONAN_REVISION_USER_CHANNEL_REGEX, desc: 'Package username'
+ requires :package_channel, type: String, regexp: CONAN_REVISION_USER_CHANNEL_REGEX, desc: 'Package channel'
end
namespace 'conans/:package_name/:package_version/:package_username/:package_channel', requirements: PACKAGE_REQUIREMENTS do
after_validation do
- check_username_channel if Feature.enabled?(:packages_conan_allow_empty_username_channel)
+ check_username_channel
end
# Get the snapshot
@@ -268,8 +269,8 @@ module API
params do
requires :package_name, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package name'
requires :package_version, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package version'
- requires :package_username, type: String, packages_conan_user_channel: true, desc: 'Package username'
- requires :package_channel, type: String, packages_conan_user_channel: true, desc: 'Package channel'
+ requires :package_username, type: String, regexp: CONAN_REVISION_USER_CHANNEL_REGEX, desc: 'Package username'
+ requires :package_channel, type: String, regexp: CONAN_REVISION_USER_CHANNEL_REGEX, desc: 'Package channel'
requires :recipe_revision, type: String, regexp: CONAN_REVISION_REGEX, desc: 'Conan Recipe Revision'
end
namespace 'files/:package_name/:package_version/:package_username/:package_channel/:recipe_revision', requirements: PACKAGE_REQUIREMENTS do
@@ -278,7 +279,7 @@ module API
end
after_validation do
- check_username_channel if Feature.enabled?(:packages_conan_allow_empty_username_channel)
+ check_username_channel
end
params do
diff --git a/lib/api/entities/commit_signature.rb b/lib/api/entities/commit_signature.rb
index 505ce462edf..0d8e977a9f5 100644
--- a/lib/api/entities/commit_signature.rb
+++ b/lib/api/entities/commit_signature.rb
@@ -6,9 +6,9 @@ module API
expose :signature_type
expose :signature, merge: true do |commit, options|
- if commit.signature.is_a?(GpgSignature) || commit.raw_commit_from_rugged?
+ if commit.signature.is_a?(::CommitSignatures::GpgSignature) || commit.raw_commit_from_rugged?
::API::Entities::GpgCommitSignature.represent commit_signature(commit), options
- elsif commit.signature.is_a?(X509CommitSignature)
+ elsif commit.signature.is_a?(::CommitSignatures::X509CommitSignature)
::API::Entities::X509Signature.represent commit.signature, options
end
end
diff --git a/lib/api/validations/validators/packages_conan_user_channel.rb b/lib/api/validations/validators/packages_conan_user_channel.rb
deleted file mode 100644
index 14afda9657c..00000000000
--- a/lib/api/validations/validators/packages_conan_user_channel.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-module API
- module Validations
- module Validators
- # TODO Delete this validator along with the packages_conan_allow_empty_username_channel feature flag
- # Use a regexp validator in its place: regexp: Gitlab::Regex.conan_recipe_user_channel_regex
- # https://gitlab.com/gitlab-org/gitlab/-/issues/346006
- class PackagesConanUserChannel < Grape::Validations::Base
- def validate_param!(attr_name, params)
- value = params[attr_name]
-
- if Feature.enabled?(:packages_conan_allow_empty_username_channel)
- unless Gitlab::Regex.conan_recipe_user_channel_regex.match?(value)
- raise Grape::Exceptions::Validation.new(
- params: [@scope.full_name(attr_name)],
- message: 'is invalid'
- )
- end
- else
- unless Gitlab::Regex.conan_recipe_component_regex.match?(value)
- raise Grape::Exceptions::Validation.new(
- params: [@scope.full_name(attr_name)],
- message: 'is invalid'
- )
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb
index 9a6317e2b76..59882e8d4f8 100644
--- a/lib/gitlab/gpg/commit.rb
+++ b/lib/gitlab/gpg/commit.rb
@@ -25,7 +25,7 @@ module Gitlab
def lazy_signature
BatchLoader.for(@commit.sha).batch do |shas, loader|
- GpgSignature.by_commit_sha(shas).each do |signature|
+ CommitSignatures::GpgSignature.by_commit_sha(shas).each do |signature|
loader.call(signature.commit_sha, signature)
end
end
@@ -62,9 +62,9 @@ module Gitlab
def create_cached_signature!
using_keychain do |gpg_key|
attributes = attributes(gpg_key)
- break GpgSignature.new(attributes) if Gitlab::Database.read_only?
+ break CommitSignatures::GpgSignature.new(attributes) if Gitlab::Database.read_only?
- GpgSignature.safe_create!(attributes)
+ CommitSignatures::GpgSignature.safe_create!(attributes)
end
end
diff --git a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb
index d892d27a917..0eb105143ea 100644
--- a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb
+++ b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb
@@ -9,9 +9,9 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def run
- GpgSignature
+ CommitSignatures::GpgSignature
.select(:id, :commit_sha, :project_id)
- .where('gpg_key_id IS NULL OR verification_status <> ?', GpgSignature.verification_statuses[:verified])
+ .where('gpg_key_id IS NULL OR verification_status <> ?', CommitSignatures::GpgSignature.verification_statuses[:verified])
.where(gpg_key_primary_keyid: @gpg_key.keyids)
.find_each { |sig| sig.gpg_commit&.update_signature!(sig) }
end
diff --git a/lib/gitlab/x509/commit.rb b/lib/gitlab/x509/commit.rb
index 91951a3e505..c7f4b7cbdf5 100644
--- a/lib/gitlab/x509/commit.rb
+++ b/lib/gitlab/x509/commit.rb
@@ -25,7 +25,7 @@ module Gitlab
def lazy_signature
BatchLoader.for(@commit.sha).batch do |shas, loader|
- X509CommitSignature.by_commit_sha(shas).each do |signature|
+ CommitSignatures::X509CommitSignature.by_commit_sha(shas).each do |signature|
loader.call(signature.commit_sha, signature)
end
end
@@ -49,9 +49,9 @@ module Gitlab
def create_cached_signature!
return if attributes.nil?
- return X509CommitSignature.new(attributes) if Gitlab::Database.read_only?
+ return CommitSignatures::X509CommitSignature.new(attributes) if Gitlab::Database.read_only?
- X509CommitSignature.safe_create!(attributes)
+ CommitSignatures::X509CommitSignature.safe_create!(attributes)
end
end
end
diff --git a/lib/tasks/gitlab/x509/update.rake b/lib/tasks/gitlab/x509/update.rake
index d3c63fa8514..7b7d15479bf 100644
--- a/lib/tasks/gitlab/x509/update.rake
+++ b/lib/tasks/gitlab/x509/update.rake
@@ -12,14 +12,14 @@ namespace :gitlab do
def update_certificates
logger = Logger.new($stdout)
- unless X509CommitSignature.exists?
+ unless CommitSignatures::X509CommitSignature.exists?
logger.info("Unable to find any x509 commit signatures. Exiting.")
return
end
logger.info("Start to update x509 commit signatures")
- X509CommitSignature.find_each do |sig|
+ CommitSignatures::X509CommitSignature.find_each do |sig|
sig.x509_commit&.update_signature!(sig)
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a52bbc47fa8..26dbf747fc0 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -28415,6 +28415,9 @@ msgstr ""
msgid "ProtectedBranch|What are protected branches?"
msgstr ""
+msgid "ProtectedBranch|default"
+msgstr ""
+
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
msgstr ""
@@ -38618,6 +38621,9 @@ msgstr ""
msgid "View all issues"
msgstr ""
+msgid "View blame"
+msgstr ""
+
msgid "View blame prior to this change"
msgstr ""
diff --git a/qa/qa/page/project/settings/services/jira.rb b/qa/qa/page/project/settings/services/jira.rb
index 0a56aaa758e..827508e488c 100644
--- a/qa/qa/page/project/settings/services/jira.rb
+++ b/qa/qa/page/project/settings/services/jira.rb
@@ -23,6 +23,11 @@ module QA
element :save_changes_button
end
+ view 'app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue' do
+ element :service_jira_issues_enabled_checkbox
+ element :service_jira_project_key_field
+ end
+
def setup_service_with(url:)
QA::Runtime::Logger.info "Setting up JIRA"
@@ -34,12 +39,22 @@ module QA
use_custom_transitions
set_transition_ids('11,21,31,41')
+ yield self if block_given?
+
click_save_changes_button
wait_until(reload: false) do
has_element?(:save_changes_button, wait: 1) ? !find_element(:save_changes_button).disabled? : true
end
end
+ def enable_jira_issues
+ check_element(:service_jira_issues_enabled_checkbox, true)
+ end
+
+ def set_jira_project_key(key)
+ fill_element(:service_jira_project_key_field, key)
+ end
+
private
def set_jira_server_url(url)
diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb
index 1df93d1118b..48cdf9791f8 100644
--- a/qa/qa/page/project/sub_menus/issues.rb
+++ b/qa/qa/page/project/sub_menus/issues.rb
@@ -51,6 +51,14 @@ module QA
end
end
+ def go_to_jira_issues
+ hover_issues do
+ within_submenu do
+ click_element(:sidebar_menu_item_link, menu_item: 'Jira issues')
+ end
+ end
+ end
+
private
def hover_issues
diff --git a/qa/qa/vendor/jira/jira_api.rb b/qa/qa/vendor/jira/jira_api.rb
index 64af824418d..15039ac244e 100644
--- a/qa/qa/vendor/jira/jira_api.rb
+++ b/qa/qa/vendor/jira/jira_api.rb
@@ -7,6 +7,9 @@ module QA
include Scenario::Actable
include Support::API
+ DEFAULT_ISSUE_SUMMARY = 'REST ye merry gentlemen.'
+ DEFAULT_ISSUE_DESCRIPTION = 'Creating of an issue using project keys and issue type names using the REST API'
+
def base_url
host = QA::Runtime::Env.jira_hostname || 'localhost'
@@ -18,27 +21,58 @@ module QA
end
def fetch_issue(issue_key)
- response = get("#{api_url}/issue/#{issue_key}", user: Runtime::Env.jira_admin_username, password: Runtime::Env.jira_admin_password)
+ response = get("#{api_url}/issue/#{issue_key}",
+ user: Runtime::Env.jira_admin_username,
+ password: Runtime::Env.jira_admin_password)
parse_body(response)
end
- def create_issue(jira_project_key)
+ def create_project(project_key = "GL#{SecureRandom.hex(4)}".upcase)
+ payload = {
+ key: project_key,
+ name: "Project #{project_key}",
+ description: "New Project #{project_key}",
+ lead: Runtime::Env.jira_admin_username,
+ projectTypeKey: 'software'
+ }
+ response = post(
+ "#{api_url}/project",
+ payload.to_json,
+ headers: { 'Content-Type' => 'application/json' },
+ user: Runtime::Env.jira_admin_username,
+ password: Runtime::Env.jira_admin_password)
+
+ returned_project_key = parse_body(response)[:key]
+
+ QA::Runtime::Logger.debug("Created JIRA project with key: '#{project_key}'")
+
+ returned_project_key
+ end
+
+ def create_issue(
+ jira_project_key,
+ issue_type: 'Bug',
+ summary: DEFAULT_ISSUE_SUMMARY,
+ description: DEFAULT_ISSUE_DESCRIPTION
+ )
payload = {
fields: {
project: {
key: jira_project_key
},
- summary: 'REST ye merry gentlemen.',
- description: 'Creating of an issue using project keys and issue type names using the REST API',
+ summary: summary,
+ description: description,
issuetype: {
- name: 'Bug'
+ name: issue_type
}
}
}
- response = post("#{api_url}/issue",
- payload.to_json, headers: { 'Content-Type': 'application/json' },
+ response = post(
+ "#{api_url}/issue",
+ payload.to_json,
+ headers: { 'Content-Type': 'application/json' },
user: Runtime::Env.jira_admin_username,
password: Runtime::Env.jira_admin_password)
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
index f9b15c9a48e..578ce04721c 100644
--- a/spec/controllers/graphql_controller_spec.rb
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -262,5 +262,16 @@ RSpec.describe GraphqlController do
expect(controller).to have_received(:append_info_to_payload)
expect(log_payload.dig(:metadata, :graphql)).to match_array(expected_logs)
end
+
+ it 'appends the exception in case of errors' do
+ exception = StandardError.new('boom')
+
+ expect(controller).to receive(:execute).and_raise(exception)
+
+ post :execute, params: { _json: graphql_queries }
+
+ expect(controller).to have_received(:append_info_to_payload)
+ expect(log_payload.dig(:exception_object)).to eq(exception)
+ end
end
end
diff --git a/spec/factories/gpg_signature.rb b/spec/factories/commit_signature/gpg_signature.rb
similarity index 76%
rename from spec/factories/gpg_signature.rb
rename to spec/factories/commit_signature/gpg_signature.rb
index 2ab4d190276..50a25291cc7 100644
--- a/spec/factories/gpg_signature.rb
+++ b/spec/factories/commit_signature/gpg_signature.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :gpg_signature do
+ factory :gpg_signature, class: 'CommitSignatures::GpgSignature' do
commit_sha { Digest::SHA1.hexdigest(SecureRandom.hex) }
project
gpg_key
diff --git a/spec/factories/x509_commit_signature.rb b/spec/factories/commit_signature/x509_commit_signature.rb
similarity index 69%
rename from spec/factories/x509_commit_signature.rb
rename to spec/factories/commit_signature/x509_commit_signature.rb
index a342b240690..1de92f56b33 100644
--- a/spec/factories/x509_commit_signature.rb
+++ b/spec/factories/commit_signature/x509_commit_signature.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
FactoryBot.define do
- factory :x509_commit_signature do
+ factory :x509_commit_signature, class: 'CommitSignatures::X509CommitSignature' do
commit_sha { Digest::SHA1.hexdigest(SecureRandom.hex) }
project
x509_certificate
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index 76e9b999638..8938bab60d7 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe "Admin::Projects" do
expect(page).to have_content(project.name)
expect(page).to have_content(archived_project.name)
- expect(page).to have_xpath("//span[@class='badge badge-warning']", text: 'archived')
+ expect(page).to have_xpath("//span[@class='gl-badge badge badge-pill badge-warning md']", text: 'archived')
end
it 'renders only archived projects', :js do
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index ef7af0ba138..c04a4493a9b 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -40,14 +40,24 @@ RSpec.describe 'User searches for code' do
include_examples 'top right search form'
include_examples 'search timeouts', 'blobs'
- it 'finds code' do
+ it 'finds code and links to blob' do
fill_in('dashboard_search', with: 'rspec')
find('.btn-search').click
expect(page).to have_selector('.results', text: 'Update capybara, rspec-rails, poltergeist to recent versions')
- find("#L3").click
- expect(current_url).to match(%r{master/.gitignore#L3})
+ find("#blob-L3").click
+ expect(current_url).to match(%r{blob/master/.gitignore#L3})
+ end
+
+ it 'finds code and links to blame' do
+ fill_in('dashboard_search', with: 'rspec')
+ find('.btn-search').click
+
+ expect(page).to have_selector('.results', text: 'Update capybara, rspec-rails, poltergeist to recent versions')
+
+ find("#blame-L3").click
+ expect(current_url).to match(%r{blame/master/.gitignore#L3})
end
it 'search mutiple words with refs switching' do
@@ -65,7 +75,8 @@ RSpec.describe 'User searches for code' do
expect(page).to have_selector('.results', text: expected_result)
expect(find_field('dashboard_search').value).to eq(search)
- expect(find("#L1502")[:href]).to match(%r{v1.0.0/files/markdown/ruby-style-guide.md#L1502})
+ expect(find("#blob-L1502")[:href]).to match(%r{blob/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
+ expect(find("#blame-L1502")[:href]).to match(%r{blame/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
end
end
diff --git a/spec/fixtures/clusters/ca_certificate.pem b/spec/fixtures/clusters/ca_certificate.pem
deleted file mode 100644
index 9e6810ab70c..00000000000
--- a/spec/fixtures/clusters/ca_certificate.pem
+++ /dev/null
@@ -1,23 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
-+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
-PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
-xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
-Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
-hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
-EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
-FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
-eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
-hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
-Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
-+OkuE6N36B9K
------END CERTIFICATE-----
diff --git a/spec/fixtures/clusters/chain_certificates.pem b/spec/fixtures/clusters/chain_certificates.pem
index b8e64d58ee7..fe6affec17a 100644
--- a/spec/fixtures/clusters/chain_certificates.pem
+++ b/spec/fixtures/clusters/chain_certificates.pem
@@ -1,100 +1,86 @@
-----BEGIN CERTIFICATE-----
-MIIItjCCB56gAwIBAgIQCu5Ga1hR41iahM0SWhyeNjANBgkqhkiG9w0BAQsFADB1
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk
-IFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE5MTIwNDAwMDAwMFoXDTIxMTIwODEy
-MDAwMFowgb0xHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB
-BAGCNzwCAQMTAlVTMRUwEwYLKwYBBAGCNzwCAQITBFV0YWgxFTATBgNVBAUTDDUy
-OTk1MzctMDE0MjELMAkGA1UEBhMCVVMxDTALBgNVBAgTBFV0YWgxDTALBgNVBAcT
-BExlaGkxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMRUwEwYDVQQDEwxkaWdpY2Vy
-dC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAeRYb/RLbljGZ
-IB//DrEdyKYMQqqaJwBlrr3t2paAWNuDJizvVkTMIzdJesI1pA58Myenxp5Dp8GJ
-u/VhBf//v/HAZHUE4xwu104Fg6A1BwUEKgVKERf+7kTt17Lf9fcMIjMyL+FeyPXb
-DOFbH+ej/nYaneFLch2j2xWZg1+Thk0qBlGE8WWAK+fvbEuM0SOeH9RkYFCNGPRS
-KsLn0GvaCnnD4LfNDyMqYop0IpaqXoREEnkRv1MVSOw+hBj497wnnO+/GZegfzwU
-iS60h+PjlDfmdCP18qOS7tRd0qnfU3N3S+PYEd3R63LMcIfbgXNEEWBNKpiH9+8f
-eXq6bXKPAgMBAAGjggT3MIIE8zAfBgNVHSMEGDAWgBQ901Cl1qCt7vNKYApl0yHU
-+PjWDzAdBgNVHQ4EFgQUTx0XO7HqD5DOhwlm2p+70uYPBmgwggGjBgNVHREEggGa
-MIIBloIMZGlnaWNlcnQuY29tggl0aGF3dGUuZGWCC2ZyZWVzc2wuY29tggxyYXBp
-ZHNzbC5jb22CDGdlb3RydXN0LmNvbYIJdGhhd3RlLmZyggp0aGF3dGUuY29tghB3
-d3cucmFwaWRzc2wuY29tghB3d3cuZ2VvdHJ1c3QuY29tgg13d3cudGhhd3RlLmZy
-gg13d3cudGhhd3RlLmRlgg53d3cudGhhd3RlLmNvbYIQd3d3LmRpZ2ljZXJ0LmNv
-bYIYa2ItaW50ZXJuYWwuZGlnaWNlcnQuY29tghprbm93bGVkZ2ViYXNlLmRpZ2lj
-ZXJ0LmNvbYIWa25vd2xlZGdlLmRpZ2ljZXJ0LmNvbYIPa2guZGlnaWNlcnQuY29t
-ghlrbm93bGVkZ2VodWIuZGlnaWNlcnQuY29tghh3ZWJzZWN1cml0eS5kaWdpY2Vy
-dC5jb22CFGNvbnRlbnQuZGlnaWNlcnQuY29tgg93d3cuZnJlZXNzbC5jb22CHHd3
-dy53ZWJzZWN1cml0eS5kaWdpY2VydC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1Ud
-JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRw
-Oi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1ldi1zZXJ2ZXItZzIuY3JsMDSgMqAw
-hi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1ldi1zZXJ2ZXItZzIuY3Js
-MEsGA1UdIAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
-d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwgYgGCCsGAQUFBwEBBHwwejAk
-BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFIGCCsGAQUFBzAC
-hkZodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyRXh0ZW5k
-ZWRWYWxpZGF0aW9uU2VydmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwggF8BgorBgEE
-AdZ5AgQCBIIBbASCAWgBZgB1AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7I
-DdwQAAABbtLkOs4AAAQDAEYwRAIgQ7gh393PInhYfPOhg/lF9yZNRdvjBeufFoG8
-VnBuPNMCIBP8YGC83ig5ttw3ipSRjH0bKj4Ak5O4rynoql9Dy8x3AHYAVhQGmi/X
-wuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0AAAFu0uQ7VgAABAMARzBFAiEAhzE7
-1c48wn3s/30IB4WgxfpLburH0Ku8cchv8QeqcgACIBrWpUlDD18AOfkPCOcB2kWU
-vRXsdptVm3jPeU5TtDSoAHUAu9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e
-0YUAAAFu0uQ60gAABAMARjBEAiBBpH5m7ntGKFTOFgSLcFXRDg66xJqerMy0gOHj
-4TIBYAIgfFABPNy6P61hjiOWwjq73lvoEdAyh18GeFHIp0BgsWEwDQYJKoZIhvcN
-AQELBQADggEBAInaSEqteyQA1zUKiXVqgffhHKZsUq9UnMows6X+UoFPoby9xqm6
-IaY/77zaFZYwXJlP/SvrlbgTLHAdir3y38uhAlfPX4iRuwggOpFFF5hqDckzCm91
-ocGnoG6sUY5mOqKu2vIcZkUQDe+K5gOxI6ME/4YwzWCIcTmBPQ6NQmqiFLPoQty1
-gdbGCcLQNFCuNq4n5OK2NmBjcbtyT4gglat7C4+KV8RkEubZ+MkXzyDkpEXjjzsK
-7iuNB0hRgyyhGzHrlZ/l0OLoT0Cb4I5PzzRSseFEyPKCC1WSF7aE9rFfUqhpqSAT
-7NV7SEijYyFFtuZfz9RGglcqnRlAfgTy+tU=
+MIIGYzCCBUugAwIBAgIQAaQHyOeT/PBR4ioLKYneZDANBgkqhkiG9w0BAQsFADBY
+MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
+AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgSDIgMjAyMTAeFw0yMTEw
+MTgxODUwMDRaFw0yMjExMTkxODUwMDNaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
+Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWSo0eziN/0lq5
+dIcS7ZceJw2odzZeT0tRkcKEW8iagNul6JetrFlk6h5lxoLEu35+MK6/fWHNmt7u
+eQk7HS0uRipskAzeGrL1Hvk8EjIcHXXTxpRu7JqWOu7ZSXwNxW5cqn7L9/N2gYwt
+Jg/sfkv9AFQiNOdKrarKfbcBstxmra6rQbh5ggLG5UBT23N4ZrA3XnzvEx3+GjtO
+u/a5izbk7FQP3gyXKyfm/SQRpNsytYa9jJqu5Hmyzfap5KaueOJbtJEOk8dR/HWR
+i/gmAUevq62MNxorYbz8YU/P1468tS7iORkD31Tc2QWCMQSPya5qGaCGnz7dVgWy
+E1xTPbBXAgMBAAGjggNkMIIDYDAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
+MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
+HQYDVR0OBBYEFJFVruwpjWeUfGJXl3m5grAjhAwPMFcGA1UdIARQME4wCAYGZ4EM
+AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
+YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
+AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
+L2NhL2dzYXRsYXNyM2R2dGxzY2FoMjIwMjEwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
+ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2FoMjIw
+MjEuY3J0MB8GA1UdIwQYMBaAFCo0uar6vzyI8Ufy0hJ4vsXlqrBpMEgGA1UdHwRB
+MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
+ZHZ0bHNjYWgyMjAyMS5jcmwwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB3AG9T
+dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABfJS9R5YAAAQDAEgwRgIh
+AOOZmc41vB2ICwkwEB5Bmpm/X8UHfjbxwrCXEdeRmO+qAiEAg/JugZIrG2PeV4bA
+Gm6rry7HUfB954bQJ4p0PeQVmwsAdABGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiF
+q/L8cP5tRwAAAXyUvUeOAAAEAwBFMEMCHyRAiTz2fZ8DuQF6hrVP+IMTCPBtjB3D
+m4naI8tC/foCIDXFCRIYjRb00CFI6piLYGihRy+GYF5nMQhQ9uE6hltzAHcAUaOw
+9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAF8lL1ICgAABAMASDBGAiEA
+5d/bXb9TPZWhwSH8GGji/LDFL6OJnZtOV94sBaDiFgMCIQCtl00oCRMFFnqsvBo6
+SRtnDqJkEHYBS12I4LyC+D1onjANBgkqhkiG9w0BAQsFAAOCAQEAE5xcno79J+Ec
+DIPJKnJCugKiM7yKjCjCp/63osCbRC+jUwRyXBIe/oTdY3geKwDOQAvyEeJPSWP1
+LbNp0l3yHbYXfsYl/NMTrJpjrJrrRO5BxG/d3IPwXIlcZrrdDSoGfGYIF9N23iqB
+in15L7B+PodTl8/mSQZTjbLoecPvl+AOcLyStcWCKYQUlQb3x4UV3R4Z1ukwGbBC
+cDbTR2XOSJzA9ECJcxKnWjQRQUc54pdG3pt13Wu2dVapX5sWZpV05rga3bBDjCqw
+DcfKuYbOChm2i6CQ578lAntPTIS02EkGFHrmYxrIAvlhGksHpJNJtRoff1KkQKni
+r8emWp7D2Q==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW
-YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY
-uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/
-LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy
-/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh
-cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k
-8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB
-Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
-BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
-Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy
-dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2
-MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j
-b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW
-gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh
-hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg
-4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa
-2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs
-1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1
-oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn
-8TUoE6smftX3eg==
+MIIExTCCA62gAwIBAgIQeimFGrf0XWZ5UGZBtv/XHTANBgkqhkiG9w0BAQsFADBM
+MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
+YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMTA2MTYxMjAwMDBaFw0y
+NDA2MTYwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
+IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSBI
+MiAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTAQMj+QUYF
+3d9X5eOWFOphbB6GpHE3J0uvUXcQwxnd8Jz26aQCE1ZYxJFEc2WmsxuVeVXU+rZj
+7+MYD7Mg72bhuiwUdwRGRN4a2N122LfIQlTFlHu/fwcNqYX/fe3phvZt9upnH4oJ
+aLBbay+t+HPPC4em74x2WKaIl31ZXzgzllLomnlLISLOKiQe1rEHp4yy3/yE2a4G
+1l/lprA49dcyM/oylm9Bbkum2F4C+EOjHgTAoDVJrJpdWvPj0CU+HkmftujfFp4S
+55LECSr2TfJt7xjgR3eLUx12nlpoauWEzZ0/i6OIDPfbmqcksw4ani/YO07LbRM6
+cY9VZzkAvwIDAQABo4IBlTCCAZEwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
+CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
+BBQqNLmq+r88iPFH8tISeL7F5aqwaTAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
+move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
+Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
+cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
+K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwVwYD
+VR0gBFAwTjAIBgZngQwBAgEwQgYKKwYBBAGgMgoBAzA0MDIGCCsGAQUFBwIBFiZo
+dHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0B
+AQsFAAOCAQEAEsIwXEhdAfoUGaKAnYfVI7zsOY7Sx8bpC/obGxXa4Kyu8CVx+TtT
+g8WmKNF7+I7C51NZEmhvb8UDI1G9ny7iYIRDajQD5AeZowbfC69aHQSI9LiOeAZb
+YaRDJfWps9redPwoaC0iT5R4xLOnWwCtmIho1bv/YG3pMAvaQ+qn04kuUvWO7LEp
+u7FdHmx1DdgkefcqYgN/rAZ8E39S9VxWV+64PNUDey8vkAIH8FCTxbWiITty6dsH
+SulKQ9pSa93k9PHTf+di08mMQBq5WBWTiFeMYZEWyE/z7NHdU3eLMZjq6y/nKlF9
+nywrToh4AgdZK6JnbU+lqbNiexJbaBoA3w==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
-+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
-PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
-xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
-Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
-hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
-EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
-FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
-eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
-hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
-Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
-+OkuE6N36B9K
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
+MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
+RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
+gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
+KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
+QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
+XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
+LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
+RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
+jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
+6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
+mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
+Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
+WD9f
-----END CERTIFICATE-----
diff --git a/spec/fixtures/clusters/intermediate_certificate.pem b/spec/fixtures/clusters/intermediate_certificate.pem
index 8a81175b746..21bada73564 100644
--- a/spec/fixtures/clusters/intermediate_certificate.pem
+++ b/spec/fixtures/clusters/intermediate_certificate.pem
@@ -1,28 +1,28 @@
-----BEGIN CERTIFICATE-----
-MIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW
-YWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY
-uD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/
-LhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy
-/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh
-cJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k
-8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB
-Af8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
-BQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
-Z2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy
-dC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2
-MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j
-b20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW
-gBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh
-hgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg
-4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa
-2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs
-1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1
-oVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn
-8TUoE6smftX3eg==
+MIIExTCCA62gAwIBAgIQeimFGrf0XWZ5UGZBtv/XHTANBgkqhkiG9w0BAQsFADBM
+MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv
+YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMTA2MTYxMjAwMDBaFw0y
+NDA2MTYwMDAwMDBaMFgxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu
+IG52LXNhMS4wLAYDVQQDEyVHbG9iYWxTaWduIEF0bGFzIFIzIERWIFRMUyBDQSBI
+MiAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1JTAQMj+QUYF
+3d9X5eOWFOphbB6GpHE3J0uvUXcQwxnd8Jz26aQCE1ZYxJFEc2WmsxuVeVXU+rZj
+7+MYD7Mg72bhuiwUdwRGRN4a2N122LfIQlTFlHu/fwcNqYX/fe3phvZt9upnH4oJ
+aLBbay+t+HPPC4em74x2WKaIl31ZXzgzllLomnlLISLOKiQe1rEHp4yy3/yE2a4G
+1l/lprA49dcyM/oylm9Bbkum2F4C+EOjHgTAoDVJrJpdWvPj0CU+HkmftujfFp4S
+55LECSr2TfJt7xjgR3eLUx12nlpoauWEzZ0/i6OIDPfbmqcksw4ani/YO07LbRM6
+cY9VZzkAvwIDAQABo4IBlTCCAZEwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQG
+CCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQW
+BBQqNLmq+r88iPFH8tISeL7F5aqwaTAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpj
+move4t0bvDB7BggrBgEFBQcBAQRvMG0wLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3Nw
+Mi5nbG9iYWxzaWduLmNvbS9yb290cjMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9zZWN1
+cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L3Jvb3QtcjMuY3J0MDYGA1UdHwQvMC0w
+K6ApoCeGJWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vcm9vdC1yMy5jcmwwVwYD
+VR0gBFAwTjAIBgZngQwBAgEwQgYKKwYBBAGgMgoBAzA0MDIGCCsGAQUFBwIBFiZo
+dHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0B
+AQsFAAOCAQEAEsIwXEhdAfoUGaKAnYfVI7zsOY7Sx8bpC/obGxXa4Kyu8CVx+TtT
+g8WmKNF7+I7C51NZEmhvb8UDI1G9ny7iYIRDajQD5AeZowbfC69aHQSI9LiOeAZb
+YaRDJfWps9redPwoaC0iT5R4xLOnWwCtmIho1bv/YG3pMAvaQ+qn04kuUvWO7LEp
+u7FdHmx1DdgkefcqYgN/rAZ8E39S9VxWV+64PNUDey8vkAIH8FCTxbWiITty6dsH
+SulKQ9pSa93k9PHTf+di08mMQBq5WBWTiFeMYZEWyE/z7NHdU3eLMZjq6y/nKlF9
+nywrToh4AgdZK6JnbU+lqbNiexJbaBoA3w==
-----END CERTIFICATE-----
diff --git a/spec/fixtures/clusters/leaf_certificate.pem b/spec/fixtures/clusters/leaf_certificate.pem
new file mode 100644
index 00000000000..aecb3fc8d4b
--- /dev/null
+++ b/spec/fixtures/clusters/leaf_certificate.pem
@@ -0,0 +1,37 @@
+-----BEGIN CERTIFICATE-----
+MIIGYzCCBUugAwIBAgIQAaQHyOeT/PBR4ioLKYneZDANBgkqhkiG9w0BAQsFADBY
+MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEuMCwGA1UE
+AxMlR2xvYmFsU2lnbiBBdGxhcyBSMyBEViBUTFMgQ0EgSDIgMjAyMTAeFw0yMTEw
+MTgxODUwMDRaFw0yMjExMTkxODUwMDNaMBsxGTAXBgNVBAMMEGFib3V0LmdpdGxh
+Yi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWSo0eziN/0lq5
+dIcS7ZceJw2odzZeT0tRkcKEW8iagNul6JetrFlk6h5lxoLEu35+MK6/fWHNmt7u
+eQk7HS0uRipskAzeGrL1Hvk8EjIcHXXTxpRu7JqWOu7ZSXwNxW5cqn7L9/N2gYwt
+Jg/sfkv9AFQiNOdKrarKfbcBstxmra6rQbh5ggLG5UBT23N4ZrA3XnzvEx3+GjtO
+u/a5izbk7FQP3gyXKyfm/SQRpNsytYa9jJqu5Hmyzfap5KaueOJbtJEOk8dR/HWR
+i/gmAUevq62MNxorYbz8YU/P1468tS7iORkD31Tc2QWCMQSPya5qGaCGnz7dVgWy
+E1xTPbBXAgMBAAGjggNkMIIDYDAbBgNVHREEFDASghBhYm91dC5naXRsYWIuY29t
+MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
+HQYDVR0OBBYEFJFVruwpjWeUfGJXl3m5grAjhAwPMFcGA1UdIARQME4wCAYGZ4EM
+AQIBMEIGCisGAQQBoDIKAQMwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
+YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wDAYDVR0TAQH/BAIwADCBngYIKwYBBQUH
+AQEEgZEwgY4wQAYIKwYBBQUHMAGGNGh0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29t
+L2NhL2dzYXRsYXNyM2R2dGxzY2FoMjIwMjEwSgYIKwYBBQUHMAKGPmh0dHA6Ly9z
+ZWN1cmUuZ2xvYmFsc2lnbi5jb20vY2FjZXJ0L2dzYXRsYXNyM2R2dGxzY2FoMjIw
+MjEuY3J0MB8GA1UdIwQYMBaAFCo0uar6vzyI8Ufy0hJ4vsXlqrBpMEgGA1UdHwRB
+MD8wPaA7oDmGN2h0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vY2EvZ3NhdGxhc3Iz
+ZHZ0bHNjYWgyMjAyMS5jcmwwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB3AG9T
+dqwx8DEZ2JkApFEV/3cVHBHZAsEAKQaNsgiaN9kTAAABfJS9R5YAAAQDAEgwRgIh
+AOOZmc41vB2ICwkwEB5Bmpm/X8UHfjbxwrCXEdeRmO+qAiEAg/JugZIrG2PeV4bA
+Gm6rry7HUfB954bQJ4p0PeQVmwsAdABGpVXrdfqRIDC1oolp9PN9ESxBdL79SbiF
+q/L8cP5tRwAAAXyUvUeOAAAEAwBFMEMCHyRAiTz2fZ8DuQF6hrVP+IMTCPBtjB3D
+m4naI8tC/foCIDXFCRIYjRb00CFI6piLYGihRy+GYF5nMQhQ9uE6hltzAHcAUaOw
+9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeUAAAF8lL1ICgAABAMASDBGAiEA
+5d/bXb9TPZWhwSH8GGji/LDFL6OJnZtOV94sBaDiFgMCIQCtl00oCRMFFnqsvBo6
+SRtnDqJkEHYBS12I4LyC+D1onjANBgkqhkiG9w0BAQsFAAOCAQEAE5xcno79J+Ec
+DIPJKnJCugKiM7yKjCjCp/63osCbRC+jUwRyXBIe/oTdY3geKwDOQAvyEeJPSWP1
+LbNp0l3yHbYXfsYl/NMTrJpjrJrrRO5BxG/d3IPwXIlcZrrdDSoGfGYIF9N23iqB
+in15L7B+PodTl8/mSQZTjbLoecPvl+AOcLyStcWCKYQUlQb3x4UV3R4Z1ukwGbBC
+cDbTR2XOSJzA9ECJcxKnWjQRQUc54pdG3pt13Wu2dVapX5sWZpV05rga3bBDjCqw
+DcfKuYbOChm2i6CQ578lAntPTIS02EkGFHrmYxrIAvlhGksHpJNJtRoff1KkQKni
+r8emWp7D2Q==
+-----END CERTIFICATE-----
diff --git a/spec/fixtures/clusters/root_certificate.pem b/spec/fixtures/clusters/root_certificate.pem
index 40107bd837d..8afb219058f 100644
--- a/spec/fixtures/clusters/root_certificate.pem
+++ b/spec/fixtures/clusters/root_certificate.pem
@@ -1,49 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIItjCCB56gAwIBAgIQCu5Ga1hR41iahM0SWhyeNjANBgkqhkiG9w0BAQsFADB1
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk
-IFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE5MTIwNDAwMDAwMFoXDTIxMTIwODEy
-MDAwMFowgb0xHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB
-BAGCNzwCAQMTAlVTMRUwEwYLKwYBBAGCNzwCAQITBFV0YWgxFTATBgNVBAUTDDUy
-OTk1MzctMDE0MjELMAkGA1UEBhMCVVMxDTALBgNVBAgTBFV0YWgxDTALBgNVBAcT
-BExlaGkxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMRUwEwYDVQQDEwxkaWdpY2Vy
-dC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAeRYb/RLbljGZ
-IB//DrEdyKYMQqqaJwBlrr3t2paAWNuDJizvVkTMIzdJesI1pA58Myenxp5Dp8GJ
-u/VhBf//v/HAZHUE4xwu104Fg6A1BwUEKgVKERf+7kTt17Lf9fcMIjMyL+FeyPXb
-DOFbH+ej/nYaneFLch2j2xWZg1+Thk0qBlGE8WWAK+fvbEuM0SOeH9RkYFCNGPRS
-KsLn0GvaCnnD4LfNDyMqYop0IpaqXoREEnkRv1MVSOw+hBj497wnnO+/GZegfzwU
-iS60h+PjlDfmdCP18qOS7tRd0qnfU3N3S+PYEd3R63LMcIfbgXNEEWBNKpiH9+8f
-eXq6bXKPAgMBAAGjggT3MIIE8zAfBgNVHSMEGDAWgBQ901Cl1qCt7vNKYApl0yHU
-+PjWDzAdBgNVHQ4EFgQUTx0XO7HqD5DOhwlm2p+70uYPBmgwggGjBgNVHREEggGa
-MIIBloIMZGlnaWNlcnQuY29tggl0aGF3dGUuZGWCC2ZyZWVzc2wuY29tggxyYXBp
-ZHNzbC5jb22CDGdlb3RydXN0LmNvbYIJdGhhd3RlLmZyggp0aGF3dGUuY29tghB3
-d3cucmFwaWRzc2wuY29tghB3d3cuZ2VvdHJ1c3QuY29tgg13d3cudGhhd3RlLmZy
-gg13d3cudGhhd3RlLmRlgg53d3cudGhhd3RlLmNvbYIQd3d3LmRpZ2ljZXJ0LmNv
-bYIYa2ItaW50ZXJuYWwuZGlnaWNlcnQuY29tghprbm93bGVkZ2ViYXNlLmRpZ2lj
-ZXJ0LmNvbYIWa25vd2xlZGdlLmRpZ2ljZXJ0LmNvbYIPa2guZGlnaWNlcnQuY29t
-ghlrbm93bGVkZ2VodWIuZGlnaWNlcnQuY29tghh3ZWJzZWN1cml0eS5kaWdpY2Vy
-dC5jb22CFGNvbnRlbnQuZGlnaWNlcnQuY29tgg93d3cuZnJlZXNzbC5jb22CHHd3
-dy53ZWJzZWN1cml0eS5kaWdpY2VydC5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1Ud
-JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRw
-Oi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1ldi1zZXJ2ZXItZzIuY3JsMDSgMqAw
-hi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1ldi1zZXJ2ZXItZzIuY3Js
-MEsGA1UdIAREMEIwNwYJYIZIAYb9bAIBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
-d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwBwYFZ4EMAQEwgYgGCCsGAQUFBwEBBHwwejAk
-BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFIGCCsGAQUFBzAC
-hkZodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyRXh0ZW5k
-ZWRWYWxpZGF0aW9uU2VydmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwggF8BgorBgEE
-AdZ5AgQCBIIBbASCAWgBZgB1AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7I
-DdwQAAABbtLkOs4AAAQDAEYwRAIgQ7gh393PInhYfPOhg/lF9yZNRdvjBeufFoG8
-VnBuPNMCIBP8YGC83ig5ttw3ipSRjH0bKj4Ak5O4rynoql9Dy8x3AHYAVhQGmi/X
-wuzT9eG9RLI+x0Z2ubyZEVzA75SYVdaJ0N0AAAFu0uQ7VgAABAMARzBFAiEAhzE7
-1c48wn3s/30IB4WgxfpLburH0Ku8cchv8QeqcgACIBrWpUlDD18AOfkPCOcB2kWU
-vRXsdptVm3jPeU5TtDSoAHUAu9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e
-0YUAAAFu0uQ60gAABAMARjBEAiBBpH5m7ntGKFTOFgSLcFXRDg66xJqerMy0gOHj
-4TIBYAIgfFABPNy6P61hjiOWwjq73lvoEdAyh18GeFHIp0BgsWEwDQYJKoZIhvcN
-AQELBQADggEBAInaSEqteyQA1zUKiXVqgffhHKZsUq9UnMows6X+UoFPoby9xqm6
-IaY/77zaFZYwXJlP/SvrlbgTLHAdir3y38uhAlfPX4iRuwggOpFFF5hqDckzCm91
-ocGnoG6sUY5mOqKu2vIcZkUQDe+K5gOxI6ME/4YwzWCIcTmBPQ6NQmqiFLPoQty1
-gdbGCcLQNFCuNq4n5OK2NmBjcbtyT4gglat7C4+KV8RkEubZ+MkXzyDkpEXjjzsK
-7iuNB0hRgyyhGzHrlZ/l0OLoT0Cb4I5PzzRSseFEyPKCC1WSF7aE9rFfUqhpqSAT
-7NV7SEijYyFFtuZfz9RGglcqnRlAfgTy+tU=
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
+MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
+RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
+gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
+KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
+QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
+XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
+LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
+RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
+jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
+6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
+mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
+Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
+WD9f
-----END CERTIFICATE-----
diff --git a/spec/frontend/header_search/store/getters_spec.js b/spec/frontend/header_search/store/getters_spec.js
index e8cfb17d83d..35d1bf350d7 100644
--- a/spec/frontend/header_search/store/getters_spec.js
+++ b/spec/frontend/header_search/store/getters_spec.js
@@ -37,18 +37,20 @@ describe('Header Search Store Getters', () => {
});
describe.each`
- group | project | expectedPath
- ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=undefined&group_id=undefined&scope=issues`}
- ${MOCK_GROUP} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=undefined&group_id=${MOCK_GROUP.id}&scope=issues`}
- ${MOCK_GROUP} | ${MOCK_PROJECT} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues`}
- `('searchQuery', ({ group, project, expectedPath }) => {
- describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
+ group | project | scope | expectedPath
+ ${null} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues`}
+ `('searchQuery', ({ group, project, scope, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, and scope is ${scope}`, () => {
beforeEach(() => {
createState({
searchContext: {
group,
project,
- scope: 'issues',
+ scope,
},
});
state.search = MOCK_SEARCH;
@@ -62,8 +64,9 @@ describe('Header Search Store Getters', () => {
describe.each`
project | ref | expectedPath
- ${null} | ${null} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_id=undefined&project_ref=null`}
- ${MOCK_PROJECT} | ${null} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_id=${MOCK_PROJECT.id}&project_ref=null`}
+ ${null} | ${null} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}`}
+ ${MOCK_PROJECT} | ${null} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_id=${MOCK_PROJECT.id}`}
+ ${null} | ${MOCK_PROJECT.id} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_ref=${MOCK_PROJECT.id}`}
${MOCK_PROJECT} | ${MOCK_PROJECT.id} | ${`${MOCK_AUTOCOMPLETE_PATH}?term=${MOCK_SEARCH}&project_id=${MOCK_PROJECT.id}&project_ref=${MOCK_PROJECT.id}`}
`('autocompleteQuery', ({ project, ref, expectedPath }) => {
describe(`when project is ${project?.name} and project ref is ${ref}`, () => {
@@ -132,18 +135,20 @@ describe('Header Search Store Getters', () => {
});
describe.each`
- group | project | expectedPath
- ${null} | ${null} | ${null}
- ${MOCK_GROUP} | ${null} | ${null}
- ${MOCK_GROUP} | ${MOCK_PROJECT} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues`}
- `('projectUrl', ({ group, project, expectedPath }) => {
- describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
+ group | project | scope | expectedPath
+ ${null} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&project_id=${MOCK_PROJECT.id}&group_id=${MOCK_GROUP.id}&scope=issues`}
+ `('projectUrl', ({ group, project, scope, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, and scope is ${scope}`, () => {
beforeEach(() => {
createState({
searchContext: {
group,
project,
- scope: 'issues',
+ scope,
},
});
state.search = MOCK_SEARCH;
@@ -156,18 +161,20 @@ describe('Header Search Store Getters', () => {
});
describe.each`
- group | project | expectedPath
- ${null} | ${null} | ${null}
- ${MOCK_GROUP} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}&scope=issues`}
- ${MOCK_GROUP} | ${MOCK_PROJECT} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}&scope=issues`}
- `('groupUrl', ({ group, project, expectedPath }) => {
- describe(`when group is ${group?.name} and project is ${project?.name}`, () => {
+ group | project | scope | expectedPath
+ ${null} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&group_id=${MOCK_GROUP.id}&scope=issues`}
+ `('groupUrl', ({ group, project, scope, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, and scope is ${scope}`, () => {
beforeEach(() => {
createState({
searchContext: {
group,
project,
- scope: 'issues',
+ scope,
},
});
state.search = MOCK_SEARCH;
@@ -179,20 +186,29 @@ describe('Header Search Store Getters', () => {
});
});
- describe('allUrl', () => {
- const expectedPath = `${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&scope=issues`;
-
- beforeEach(() => {
- createState({
- searchContext: {
- scope: 'issues',
- },
+ describe.each`
+ group | project | scope | expectedPath
+ ${null} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${null} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${null} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${null} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar`}
+ ${MOCK_GROUP} | ${MOCK_PROJECT} | ${'issues'} | ${`${MOCK_SEARCH_PATH}?search=${MOCK_SEARCH}&nav_source=navbar&scope=issues`}
+ `('allUrl', ({ group, project, scope, expectedPath }) => {
+ describe(`when group is ${group?.name}, project is ${project?.name}, and scope is ${scope}`, () => {
+ beforeEach(() => {
+ createState({
+ searchContext: {
+ group,
+ project,
+ scope,
+ },
+ });
+ state.search = MOCK_SEARCH;
});
- state.search = MOCK_SEARCH;
- });
- it(`should return ${expectedPath}`, () => {
- expect(getters.allUrl(state)).toBe(expectedPath);
+ it(`should return ${expectedPath}`, () => {
+ expect(getters.allUrl(state)).toBe(expectedPath);
+ });
});
});
diff --git a/spec/frontend/issues/show/components/app_spec.js b/spec/frontend/issues/show/components/app_spec.js
index 0f36303c02a..27c4c27874c 100644
--- a/spec/frontend/issues/show/components/app_spec.js
+++ b/spec/frontend/issues/show/components/app_spec.js
@@ -4,11 +4,12 @@ import { nextTick } from 'vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import '~/behaviors/markdown/render_gfm';
+import { IssuableStatus, IssuableStatusText } from '~/issues/constants';
import IssuableApp from '~/issues/show/components/app.vue';
import DescriptionComponent from '~/issues/show/components/description.vue';
import IncidentTabs from '~/issues/show/components/incidents/incident_tabs.vue';
import PinnedLinks from '~/issues/show/components/pinned_links.vue';
-import { IssuableStatus, IssuableStatusText, POLLING_DELAY } from '~/issues/show/constants';
+import { POLLING_DELAY } from '~/issues/show/constants';
import eventHub from '~/issues/show/event_hub';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
diff --git a/spec/frontend/issues/show/components/header_actions_spec.js b/spec/frontend/issues/show/components/header_actions_spec.js
index 7d39f342f27..880981355dd 100644
--- a/spec/frontend/issues/show/components/header_actions_spec.js
+++ b/spec/frontend/issues/show/components/header_actions_spec.js
@@ -4,7 +4,8 @@ import Vuex from 'vuex';
import createFlash, { FLASH_TYPES } from '~/flash';
import { IssuableType } from '~/vue_shared/issuable/show/constants';
import HeaderActions from '~/issues/show/components/header_actions.vue';
-import { IssuableStatus, IssueStateEvent } from '~/issues/show/constants';
+import { IssuableStatus } from '~/issues/constants';
+import { IssueStateEvent } from '~/issues/show/constants';
import promoteToEpicMutation from '~/issues/show/queries/promote_to_epic.mutation.graphql';
import * as urlUtility from '~/lib/utils/url_utility';
import eventHub from '~/notes/event_hub';
diff --git a/spec/frontend/packages/shared/utils_spec.js b/spec/frontend/packages/shared/utils_spec.js
deleted file mode 100644
index 94c16606cf8..00000000000
--- a/spec/frontend/packages/shared/utils_spec.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import { PackageType, TrackingCategories } from '~/packages/shared/constants';
-import {
- packageTypeToTrackCategory,
- beautifyPath,
- getPackageTypeLabel,
- getCommitLink,
-} from '~/packages/shared/utils';
-import { packageList } from 'jest/packages_and_registries/infrastructure_registry/components/mock_data';
-
-describe('Packages shared utils', () => {
- describe('packageTypeToTrackCategory', () => {
- it('prepend UI to package category', () => {
- expect(packageTypeToTrackCategory()).toMatchInlineSnapshot(`"UI::undefined"`);
- });
-
- it.each(Object.keys(PackageType))('returns a correct category string for %s', (packageKey) => {
- const packageName = PackageType[packageKey];
- expect(packageTypeToTrackCategory(packageName)).toBe(
- `UI::${TrackingCategories[packageName]}`,
- );
- });
- });
-
- describe('beautifyPath', () => {
- it('returns a string with spaces around /', () => {
- expect(beautifyPath('foo/bar')).toBe('foo / bar');
- });
- it('does not fail for empty string', () => {
- expect(beautifyPath()).toBe('');
- });
- });
-
- describe('getPackageTypeLabel', () => {
- describe.each`
- packageType | expectedResult
- ${'conan'} | ${'Conan'}
- ${'maven'} | ${'Maven'}
- ${'npm'} | ${'npm'}
- ${'nuget'} | ${'NuGet'}
- ${'pypi'} | ${'PyPI'}
- ${'rubygems'} | ${'RubyGems'}
- ${'composer'} | ${'Composer'}
- ${'debian'} | ${'Debian'}
- ${'helm'} | ${'Helm'}
- ${'foo'} | ${null}
- `(`package type`, ({ packageType, expectedResult }) => {
- it(`${packageType} should show as ${expectedResult}`, () => {
- expect(getPackageTypeLabel(packageType)).toBe(expectedResult);
- });
- });
- });
-
- describe('getCommitLink', () => {
- it('returns a relative link when isGroup is false', () => {
- const link = getCommitLink(packageList[0], false);
-
- expect(link).toContain('../commit');
- });
-
- describe('when isGroup is true', () => {
- it('returns an absolute link matching project path', () => {
- const mavenPackage = packageList[0];
- const link = getCommitLink(mavenPackage, true);
-
- expect(link).toContain(`/${mavenPackage.project_path}/commit`);
- });
- });
- });
-});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js
index ee6a6315ff3..2868af84181 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/app_spec.js
@@ -10,9 +10,9 @@ import PackageFiles from '~/packages_and_registries/infrastructure_registry/deta
import PackageHistory from '~/packages_and_registries/infrastructure_registry/details/components/package_history.vue';
import * as getters from '~/packages_and_registries/infrastructure_registry/details/store/getters';
import PackageListRow from '~/packages_and_registries/infrastructure_registry/shared/package_list_row.vue';
-import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
-import { TrackingActions } from '~/packages/shared/constants';
-import * as SharedUtils from '~/packages/shared/utils';
+import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
+import { TRACKING_ACTIONS } from '~/packages_and_registries/shared/constants';
+import { TRACK_CATEGORY } from '~/packages_and_registries/infrastructure_registry/shared/constants';
import TerraformTitle from '~/packages_and_registries/infrastructure_registry/details/components/details_title.vue';
import TerraformInstallation from '~/packages_and_registries/infrastructure_registry/details/components/terraform_installation.vue';
import Tracking from '~/tracking';
@@ -232,87 +232,78 @@ describe('PackagesApp', () => {
describe('tracking', () => {
let eventSpy;
- let utilSpy;
- const category = 'foo';
beforeEach(() => {
eventSpy = jest.spyOn(Tracking, 'event');
- utilSpy = jest.spyOn(SharedUtils, 'packageTypeToTrackCategory').mockReturnValue(category);
});
- it('tracking category calls packageTypeToTrackCategory', () => {
- createComponent({ packageEntity: npmPackage });
- expect(wrapper.vm.tracking.category).toBe(category);
- expect(utilSpy).toHaveBeenCalledWith('npm');
- });
-
- it(`delete button on delete modal call event with ${TrackingActions.DELETE_PACKAGE}`, () => {
+ it(`delete button on delete modal call event with ${TRACKING_ACTIONS.DELETE_PACKAGE}`, () => {
createComponent({ packageEntity: npmPackage });
findDeleteModal().vm.$emit('primary');
expect(eventSpy).toHaveBeenCalledWith(
- category,
- TrackingActions.DELETE_PACKAGE,
+ TRACK_CATEGORY,
+ TRACKING_ACTIONS.DELETE_PACKAGE,
expect.any(Object),
);
});
- it(`canceling a package deletion tracks ${TrackingActions.CANCEL_DELETE_PACKAGE}`, () => {
+ it(`canceling a package deletion tracks ${TRACKING_ACTIONS.CANCEL_DELETE_PACKAGE}`, () => {
createComponent({ packageEntity: npmPackage });
findDeleteModal().vm.$emit('canceled');
expect(eventSpy).toHaveBeenCalledWith(
- category,
- TrackingActions.CANCEL_DELETE_PACKAGE,
+ TRACK_CATEGORY,
+ TRACKING_ACTIONS.CANCEL_DELETE_PACKAGE,
expect.any(Object),
);
});
- it(`request a file deletion tracks ${TrackingActions.REQUEST_DELETE_PACKAGE_FILE}`, () => {
+ it(`request a file deletion tracks ${TRACKING_ACTIONS.REQUEST_DELETE_PACKAGE_FILE}`, () => {
createComponent({ packageEntity: npmPackage });
findPackageFiles().vm.$emit('delete-file', mavenFiles[0]);
expect(eventSpy).toHaveBeenCalledWith(
- category,
- TrackingActions.REQUEST_DELETE_PACKAGE_FILE,
+ TRACK_CATEGORY,
+ TRACKING_ACTIONS.REQUEST_DELETE_PACKAGE_FILE,
expect.any(Object),
);
});
- it(`confirming a file deletion tracks ${TrackingActions.DELETE_PACKAGE_FILE}`, () => {
+ it(`confirming a file deletion tracks ${TRACKING_ACTIONS.DELETE_PACKAGE_FILE}`, () => {
createComponent({ packageEntity: npmPackage });
findPackageFiles().vm.$emit('delete-file', npmPackage);
findDeleteFileModal().vm.$emit('primary');
expect(eventSpy).toHaveBeenCalledWith(
- category,
- TrackingActions.REQUEST_DELETE_PACKAGE_FILE,
+ TRACK_CATEGORY,
+ TRACKING_ACTIONS.REQUEST_DELETE_PACKAGE_FILE,
expect.any(Object),
);
});
- it(`canceling a file deletion tracks ${TrackingActions.CANCEL_DELETE_PACKAGE_FILE}`, () => {
+ it(`canceling a file deletion tracks ${TRACKING_ACTIONS.CANCEL_DELETE_PACKAGE_FILE}`, () => {
createComponent({ packageEntity: npmPackage });
findPackageFiles().vm.$emit('delete-file', npmPackage);
findDeleteFileModal().vm.$emit('canceled');
expect(eventSpy).toHaveBeenCalledWith(
- category,
- TrackingActions.CANCEL_DELETE_PACKAGE_FILE,
+ TRACK_CATEGORY,
+ TRACKING_ACTIONS.CANCEL_DELETE_PACKAGE_FILE,
expect.any(Object),
);
});
- it(`file download link call event with ${TrackingActions.PULL_PACKAGE}`, () => {
+ it(`file download link call event with ${TRACKING_ACTIONS.PULL_PACKAGE}`, () => {
createComponent({ packageEntity: npmPackage });
findPackageFiles().vm.$emit('download-file');
expect(eventSpy).toHaveBeenCalledWith(
- category,
- TrackingActions.PULL_PACKAGE,
+ TRACK_CATEGORY,
+ TRACKING_ACTIONS.PULL_PACKAGE,
expect.any(Object),
);
});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
index e27e95186ca..b9383d6c38c 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/store/actions_spec.js
@@ -12,7 +12,7 @@ import {
DELETE_PACKAGE_ERROR_MESSAGE,
DELETE_PACKAGE_FILE_ERROR_MESSAGE,
DELETE_PACKAGE_FILE_SUCCESS_MESSAGE,
-} from '~/packages/shared/constants';
+} from '~/packages_and_registries/shared/constants';
import { npmPackage as packageEntity } from '../../mock_data';
jest.mock('~/flash.js');
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js
index cbdf001dea8..cad75d2a858 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js
@@ -6,8 +6,11 @@ import createFlash from '~/flash';
import * as commonUtils from '~/lib/utils/common_utils';
import PackageListApp from '~/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue';
import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '~/packages_and_registries/infrastructure_registry/list/constants';
-import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
-import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants';
+import {
+ SHOW_DELETE_SUCCESS_ALERT,
+ FILTERED_SEARCH_TERM,
+} from '~/packages_and_registries/shared/constants';
+
import * as packageUtils from '~/packages_and_registries/shared/utils';
import InfrastructureSearch from '~/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue';
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js
index d096fbc2a91..2fb76b98925 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js
@@ -5,9 +5,9 @@ import Vuex from 'vuex';
import stubChildren from 'helpers/stub_children';
import PackagesList from '~/packages_and_registries/infrastructure_registry/list/components/packages_list.vue';
import PackagesListRow from '~/packages_and_registries/infrastructure_registry/shared/package_list_row.vue';
-import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
-import { TrackingActions } from '~/packages/shared/constants';
-import * as SharedUtils from '~/packages/shared/utils';
+import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
+import { TRACKING_ACTIONS } from '~/packages_and_registries/shared/constants';
+import { TRACK_CATEGORY } from '~/packages_and_registries/infrastructure_registry/shared/constants';
import Tracking from '~/tracking';
import { packageList } from '../../mock_data';
@@ -190,26 +190,18 @@ describe('packages_list', () => {
describe('tracking', () => {
let eventSpy;
- let utilSpy;
- const category = 'foo';
beforeEach(() => {
mountComponent();
eventSpy = jest.spyOn(Tracking, 'event');
- utilSpy = jest.spyOn(SharedUtils, 'packageTypeToTrackCategory').mockReturnValue(category);
wrapper.setData({ itemToBeDeleted: { package_type: 'conan' } });
});
- it('tracking category calls packageTypeToTrackCategory', () => {
- expect(wrapper.vm.tracking.category).toBe(category);
- expect(utilSpy).toHaveBeenCalledWith('conan');
- });
-
it('deleteItemConfirmation calls event', () => {
wrapper.vm.deleteItemConfirmation();
expect(eventSpy).toHaveBeenCalledWith(
- category,
- TrackingActions.DELETE_PACKAGE,
+ TRACK_CATEGORY,
+ TRACKING_ACTIONS.DELETE_PACKAGE,
expect.any(Object),
);
});
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
index bcfde68160a..3fbfe1060dc 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/stores/actions_spec.js
@@ -6,7 +6,7 @@ import createFlash from '~/flash';
import { MISSING_DELETE_PATH_ERROR } from '~/packages_and_registries/infrastructure_registry/list/constants';
import * as actions from '~/packages_and_registries/infrastructure_registry/list/stores/actions';
import * as types from '~/packages_and_registries/infrastructure_registry/list/stores/mutation_types';
-import { DELETE_PACKAGE_ERROR_MESSAGE } from '~/packages/shared/constants';
+import { DELETE_PACKAGE_ERROR_MESSAGE } from '~/packages_and_registries/shared/constants';
jest.mock('~/flash.js');
jest.mock('~/api.js');
diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js
index fd6fde1c83e..1052fdd1dda 100644
--- a/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/shared/package_list_row_spec.js
@@ -3,9 +3,9 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import PackagesListRow from '~/packages_and_registries/infrastructure_registry/shared/package_list_row.vue';
-import PackagePath from '~/packages/shared/components/package_path.vue';
-import PackageTags from '~/packages/shared/components/package_tags.vue';
-import { PACKAGE_ERROR_STATUS } from '~/packages/shared/constants';
+import PackagePath from '~/packages_and_registries/shared/components/package_path.vue';
+import PackageTags from '~/packages_and_registries/shared/components/package_tags.vue';
+import { PACKAGE_ERROR_STATUS } from '~/packages_and_registries/shared/constants';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { packageList } from '../mock_data';
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js
index d59c3184e4e..6ad6007c9da 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_title_spec.js
@@ -2,7 +2,7 @@ import { GlIcon, GlSprintf } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import PackageTags from '~/packages/shared/components/package_tags.vue';
+import PackageTags from '~/packages_and_registries/shared/components/package_tags.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
import {
PACKAGE_TYPE_CONAN,
diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js b/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js
index f7613949fe4..faeca76d746 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/version_row_spec.js
@@ -1,8 +1,8 @@
import { GlLink, GlSprintf, GlTruncate } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import PackageTags from '~/packages/shared/components/package_tags.vue';
-import PublishMethod from '~/packages/shared/components/publish_method.vue';
+import PackageTags from '~/packages_and_registries/shared/components/package_tags.vue';
+import PublishMethod from '~/packages_and_registries/shared/components/publish_method.vue';
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js
index 4e172211d92..292667ec47c 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js
@@ -3,9 +3,9 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import PackagesListRow from '~/packages_and_registries/package_registry/components/list/package_list_row.vue';
-import PackagePath from '~/packages/shared/components/package_path.vue';
-import PackageTags from '~/packages/shared/components/package_tags.vue';
-import PackageIconAndName from '~/packages/shared/components/package_icon_and_name.vue';
+import PackagePath from '~/packages_and_registries/shared/components/package_path.vue';
+import PackageTags from '~/packages_and_registries/shared/components/package_tags.vue';
+import PackageIconAndName from '~/packages_and_registries/shared/components/package_icon_and_name.vue';
import PublishMethod from '~/packages_and_registries/package_registry/components/list/publish_method.vue';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { PACKAGE_ERROR_STATUS } from '~/packages_and_registries/package_registry/constants';
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
index 777c3b9ecc7..97978dee909 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js
@@ -2,7 +2,7 @@ import { GlKeysetPagination, GlModal, GlSprintf } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PackagesListRow from '~/packages_and_registries/package_registry/components/list/package_list_row.vue';
-import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
+import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
import {
DELETE_PACKAGE_TRACKING_ACTION,
REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
diff --git a/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap b/spec/frontend/packages_and_registries/shared/__snapshots__/publish_method_spec.js.snap
similarity index 100%
rename from spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap
rename to spec/frontend/packages_and_registries/shared/__snapshots__/publish_method_spec.js.snap
diff --git a/spec/frontend/packages/shared/components/package_icon_and_name_spec.js b/spec/frontend/packages_and_registries/shared/package_icon_and_name_spec.js
similarity index 85%
rename from spec/frontend/packages/shared/components/package_icon_and_name_spec.js
rename to spec/frontend/packages_and_registries/shared/package_icon_and_name_spec.js
index c96a570a29c..d6d1970cb12 100644
--- a/spec/frontend/packages/shared/components/package_icon_and_name_spec.js
+++ b/spec/frontend/packages_and_registries/shared/package_icon_and_name_spec.js
@@ -1,6 +1,6 @@
import { GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import PackageIconAndName from '~/packages/shared/components/package_icon_and_name.vue';
+import PackageIconAndName from '~/packages_and_registries/shared/components/package_icon_and_name.vue';
describe('PackageIconAndName', () => {
let wrapper;
diff --git a/spec/frontend/packages/shared/components/package_path_spec.js b/spec/frontend/packages_and_registries/shared/package_path_spec.js
similarity index 97%
rename from spec/frontend/packages/shared/components/package_path_spec.js
rename to spec/frontend/packages_and_registries/shared/package_path_spec.js
index edbdd55c1d7..93425d4f399 100644
--- a/spec/frontend/packages/shared/components/package_path_spec.js
+++ b/spec/frontend/packages_and_registries/shared/package_path_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import PackagePath from '~/packages/shared/components/package_path.vue';
+import PackagePath from '~/packages_and_registries/shared/components/package_path.vue';
describe('PackagePath', () => {
let wrapper;
diff --git a/spec/frontend/packages/shared/components/package_tags_spec.js b/spec/frontend/packages_and_registries/shared/package_tags_spec.js
similarity index 97%
rename from spec/frontend/packages/shared/components/package_tags_spec.js
rename to spec/frontend/packages_and_registries/shared/package_tags_spec.js
index 881b49cfb06..33e96c0775e 100644
--- a/spec/frontend/packages/shared/components/package_tags_spec.js
+++ b/spec/frontend/packages_and_registries/shared/package_tags_spec.js
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
-import PackageTags from '~/packages/shared/components/package_tags.vue';
+import PackageTags from '~/packages_and_registries/shared/components/package_tags.vue';
import { mockTags } from 'jest/packages_and_registries/infrastructure_registry/components/mock_data';
describe('PackageTags', () => {
diff --git a/spec/frontend/packages/shared/components/packages_list_loader_spec.js b/spec/frontend/packages_and_registries/shared/packages_list_loader_spec.js
similarity index 92%
rename from spec/frontend/packages/shared/components/packages_list_loader_spec.js
rename to spec/frontend/packages_and_registries/shared/packages_list_loader_spec.js
index 4ff01068f92..0005162e0bb 100644
--- a/spec/frontend/packages/shared/components/packages_list_loader_spec.js
+++ b/spec/frontend/packages_and_registries/shared/packages_list_loader_spec.js
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
-import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue';
+import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
describe('PackagesListLoader', () => {
let wrapper;
diff --git a/spec/frontend/packages/shared/components/publish_method_spec.js b/spec/frontend/packages_and_registries/shared/publish_method_spec.js
similarity index 94%
rename from spec/frontend/packages/shared/components/publish_method_spec.js
rename to spec/frontend/packages_and_registries/shared/publish_method_spec.js
index 784776fd3f0..fa8f8f7641a 100644
--- a/spec/frontend/packages/shared/components/publish_method_spec.js
+++ b/spec/frontend/packages_and_registries/shared/publish_method_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import PublishMethod from '~/packages/shared/components/publish_method.vue';
+import PublishMethod from '~/packages_and_registries/shared/components/publish_method.vue';
import { packageList } from 'jest/packages_and_registries/infrastructure_registry/components/mock_data';
describe('publish_method', () => {
diff --git a/spec/frontend/packages_and_registries/shared/utils_spec.js b/spec/frontend/packages_and_registries/shared/utils_spec.js
index bbc8791ca21..962cb2257ce 100644
--- a/spec/frontend/packages_and_registries/shared/utils_spec.js
+++ b/spec/frontend/packages_and_registries/shared/utils_spec.js
@@ -4,8 +4,12 @@ import {
keyValueToFilterToken,
searchArrayToFilterTokens,
extractFilterAndSorting,
+ beautifyPath,
+ getCommitLink,
} from '~/packages_and_registries/shared/utils';
+import { packageList } from 'jest/packages_and_registries/infrastructure_registry/components/mock_data';
+
describe('Packages And Registries shared utils', () => {
describe('getQueryParams', () => {
it('returns an object from a query string, with arrays', () => {
@@ -56,4 +60,30 @@ describe('Packages And Registries shared utils', () => {
},
);
});
+
+ describe('beautifyPath', () => {
+ it('returns a string with spaces around /', () => {
+ expect(beautifyPath('foo/bar')).toBe('foo / bar');
+ });
+ it('does not fail for empty string', () => {
+ expect(beautifyPath()).toBe('');
+ });
+ });
+
+ describe('getCommitLink', () => {
+ it('returns a relative link when isGroup is false', () => {
+ const link = getCommitLink(packageList[0], false);
+
+ expect(link).toContain('../commit');
+ });
+
+ describe('when isGroup is true', () => {
+ it('returns an absolute link matching project path', () => {
+ const mavenPackage = packageList[0];
+ const link = getCommitLink(mavenPackage, true);
+
+ expect(link).toContain(`/${mavenPackage.project_path}/commit`);
+ });
+ });
+ });
});
diff --git a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
index 9c57a3fcf8d..07da4acef8c 100644
--- a/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
+++ b/spec/frontend/sidebar/components/assignees/sidebar_assignees_widget_spec.js
@@ -5,7 +5,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
-import { IssuableType } from '~/issues/show/constants';
+import { IssuableType } from '~/issues/constants';
import SidebarAssigneesRealtime from '~/sidebar/components/assignees/assignees_realtime.vue';
import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
diff --git a/spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js b/spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js
index d2459faf83a..69e35cd1d05 100644
--- a/spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js
+++ b/spec/frontend/sidebar/components/reference/sidebar_reference_widget_spec.js
@@ -3,7 +3,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { IssuableType } from '~/issues/show/constants';
+import { IssuableType } from '~/issues/constants';
import SidebarReferenceWidget from '~/sidebar/components/reference/sidebar_reference_widget.vue';
import issueReferenceQuery from '~/sidebar/queries/issue_reference.query.graphql';
import mergeRequestReferenceQuery from '~/sidebar/queries/merge_request_reference.query.graphql';
diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
index bfd6fc22cf5..d7471d99477 100644
--- a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
+++ b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
@@ -17,7 +17,7 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { IssuableType } from '~/issues/show/constants';
+import { IssuableType } from '~/issues/constants';
import { timeFor } from '~/lib/utils/datetime_utility';
import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
diff --git a/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js b/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js
index 55a65cfc4b3..c8dab0204d3 100644
--- a/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js
+++ b/spec/frontend/vue_shared/components/notes/placeholder_note_spec.js
@@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import IssuePlaceholderNote from '~/vue_shared/components/notes/placeholder_note.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import { userDataMock } from '../../../notes/mock_data';
Vue.use(Vuex);
@@ -15,7 +16,7 @@ describe('Issue placeholder note component', () => {
const findNote = () => wrapper.find({ ref: 'note' });
- const createComponent = (isIndividual = false) => {
+ const createComponent = (isIndividual = false, propsData = {}) => {
wrapper = shallowMount(IssuePlaceholderNote, {
store: new Vuex.Store({
getters,
@@ -25,6 +26,7 @@ describe('Issue placeholder note component', () => {
body: 'Foo',
individual_note: isIndividual,
},
+ ...propsData,
},
});
};
@@ -51,4 +53,17 @@ describe('Issue placeholder note component', () => {
expect(findNote().classes()).toContain('discussion');
});
+
+ describe('avatar size', () => {
+ it.each`
+ size | line | isOverviewTab
+ ${40} | ${null} | ${false}
+ ${24} | ${{ line_code: '123' }} | ${false}
+ ${40} | ${{ line_code: '123' }} | ${true}
+ `('renders avatar $size for $line and $isOverviewTab', ({ size, line, isOverviewTab }) => {
+ createComponent(false, { line, isOverviewTab });
+
+ expect(wrapper.findComponent(UserAvatarLink).props('imgSize')).toBe(size);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
index 70d298ef206..139a1456554 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
-import { IssuableType } from '~/issues/show/constants';
+import { IssuableType } from '~/issues/constants';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import DropdownContents from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue';
import DropdownValue from '~/vue_shared/components/sidebar/labels_select_widget/dropdown_value.vue';
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index c8d46b51888..9741a193258 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -1,13 +1,13 @@
export const workItemQueryResponse = {
workItem: {
- __typename: 'WorkItem',
+ __typename: 'LocalWorkItem',
id: '1',
type: 'FEATURE',
widgets: {
- __typename: 'WorkItemWidgetConnection',
+ __typename: 'LocalWorkItemWidgetConnection',
nodes: [
{
- __typename: 'TitleWidget',
+ __typename: 'LocalTitleWidget',
type: 'TITLE',
contentText: 'Test',
},
@@ -17,15 +17,15 @@ export const workItemQueryResponse = {
};
export const updateWorkItemMutationResponse = {
- __typename: 'UpdateWorkItemPayload',
+ __typename: 'LocalUpdateWorkItemPayload',
workItem: {
- __typename: 'WorkItem',
+ __typename: 'LocalWorkItem',
id: '1',
widgets: {
- __typename: 'WorkItemWidgetConnection',
+ __typename: 'LocalWorkItemWidgetConnection',
nodes: [
{
- __typename: 'TitleWidget',
+ __typename: 'LocalTitleWidget',
type: 'TITLE',
enabled: true,
contentText: 'Updated title',
diff --git a/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb b/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb
index d1c2b4044c1..37c9d6b269c 100644
--- a/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb
+++ b/spec/graphql/types/admin/analytics/usage_trends/measurement_type_spec.rb
@@ -36,8 +36,14 @@ RSpec.describe GitlabSchema.types['UsageTrendsMeasurement'] do
end
context 'when the user is not admin' do
- it 'returns no data' do
- expect(subject.dig('data', 'usageTrendsMeasurements')).to be_nil
+ it 'returns an error' do
+ expected_err = "The resource that you are attempting to access does not exist or you don't have permission to perform this action"
+
+ expect(subject["errors"].first["message"]).to eq(expected_err)
+ end
+
+ it 'does not return usageTrendsMeasurements data' do
+ expect(subject["data"]["usageTrendsMeasurements"]).to be_nil
end
end
@@ -48,7 +54,7 @@ RSpec.describe GitlabSchema.types['UsageTrendsMeasurement'] do
stub_application_setting(admin_mode: false)
end
- it 'returns data' do
+ it 'returns usageTrendsMeasurements data' do
expect(subject.dig('data', 'usageTrendsMeasurements', 'nodes')).not_to be_empty
end
end
diff --git a/spec/graphql/types/ci/job_token_scope_type_spec.rb b/spec/graphql/types/ci/job_token_scope_type_spec.rb
index 19a8cc324f9..43225b2089b 100644
--- a/spec/graphql/types/ci/job_token_scope_type_spec.rb
+++ b/spec/graphql/types/ci/job_token_scope_type_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
end
describe 'query' do
- let_it_be(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
+ let(:project) { create(:project, ci_job_token_scope_enabled: true).tap(&:save!) }
let_it_be(:current_user) { create(:user) }
let(:query) do
@@ -65,8 +65,12 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeType'] do
project.ci_cd_settings.update!(job_token_scope_enabled: false)
end
+ it 'does not return an error' do
+ expect(subject['errors']).to be_nil
+ end
+
it 'returns nil' do
- expect(subject.dig('data', 'project', 'ciJobTokenScope')).to be_nil
+ expect(subject['data']['project']['ciJobTokenScope']).to be_nil
end
end
end
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb
index c0a0fdf3b0b..1b8bf007a73 100644
--- a/spec/graphql/types/issue_type_spec.rb
+++ b/spec/graphql/types/issue_type_spec.rb
@@ -66,10 +66,16 @@ RSpec.describe GitlabSchema.types['Issue'] do
end
context 'when user does not have the permission' do
- it 'returns no data' do
+ before do
allow(Ability).to receive(:allowed?).with(user, :read_project, project).and_return(false)
+ end
- expect(subject.dig(:data, :project)).to eq(nil)
+ it 'does not return an error' do
+ expect(subject['errors']).to be_nil
+ end
+
+ it 'returns no data' do
+ expect(subject['data']['project']).to be_nil
end
end
diff --git a/spec/lib/api/validations/validators/packages_conan_user_channel_spec.rb b/spec/lib/api/validations/validators/packages_conan_user_channel_spec.rb
deleted file mode 100644
index 86cb4c54a57..00000000000
--- a/spec/lib/api/validations/validators/packages_conan_user_channel_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe API::Validations::Validators::PackagesConanUserChannel do
- include ApiValidatorsHelpers
-
- describe '#validate_param!' do
- subject do
- described_class.new(['test'], {}, false, scope.new)
- end
-
- shared_examples 'accepting valid values for conan user channels' do
- let(:fifty_one_characters) { 'f_a' * 17}
-
- it { expect_no_validation_error('test' => 'foobar') }
- it { expect_no_validation_error('test' => 'foo_bar') }
- it { expect_no_validation_error('test' => 'foo+bar') }
- it { expect_no_validation_error('test' => '_foo+bar-baz+1.0') }
- it { expect_no_validation_error('test' => '1.0.0') }
- it { expect_validation_error('test' => '-foo_bar') }
- it { expect_validation_error('test' => '+foo_bar') }
- it { expect_validation_error('test' => '.foo_bar') }
- it { expect_validation_error('test' => 'foo@bar') }
- it { expect_validation_error('test' => 'foo/bar') }
- it { expect_validation_error('test' => '!!()()') }
- it { expect_validation_error('test' => fifty_one_characters) }
- end
-
- it_behaves_like 'accepting valid values for conan user channels'
- it { expect_no_validation_error('test' => '_') }
-
- context 'with packages_conan_allow_empty_username_channel disabled' do
- before do
- stub_feature_flags(packages_conan_allow_empty_username_channel: false)
- end
-
- it_behaves_like 'accepting valid values for conan user channels'
- it { expect_validation_error('test' => '_') }
- end
- end
-end
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index 07143b41a37..b298bf2c8bb 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -201,7 +201,7 @@ RSpec.describe Clusters::Platforms::Kubernetes do
it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::KubeClient) }
context 'ca_pem is a single certificate' do
- let(:ca_pem) { File.read(Rails.root.join('spec/fixtures/clusters/ca_certificate.pem')) }
+ let(:ca_pem) { File.read(Rails.root.join('spec/fixtures/clusters/root_certificate.pem')) }
let(:kubernetes) do
build(:cluster_platform_kubernetes,
:configured,
@@ -228,21 +228,22 @@ RSpec.describe Clusters::Platforms::Kubernetes do
ca_pem: cert_chain)
end
- it 'includes chain of certificates', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/347425' do
- cert1_file = File.read(Rails.root.join('spec/fixtures/clusters/root_certificate.pem'))
- cert1 = OpenSSL::X509::Certificate.new(cert1_file)
+ where(:fixture_path) do
+ %w[
+ spec/fixtures/clusters/root_certificate.pem
+ spec/fixtures/clusters/intermediate_certificate.pem
+ spec/fixtures/clusters/leaf_certificate.pem
+ ]
+ end
- cert2_file = File.read(Rails.root.join('spec/fixtures/clusters/intermediate_certificate.pem'))
- cert2 = OpenSSL::X509::Certificate.new(cert2_file)
+ with_them do
+ it 'includes chain of certificates' do
+ cert_store = kubernetes.kubeclient.kubeclient_options[:ssl_options][:cert_store]
+ cert_file = File.read(Rails.root.join(fixture_path))
+ certificate = OpenSSL::X509::Certificate.new(cert_file)
- cert3_file = File.read(Rails.root.join('spec/fixtures/clusters/ca_certificate.pem'))
- cert3 = OpenSSL::X509::Certificate.new(cert3_file)
-
- cert_store = kubernetes.kubeclient.kubeclient_options[:ssl_options][:cert_store]
-
- expect(cert_store.verify(cert1)).to be true
- expect(cert_store.verify(cert2)).to be true
- expect(cert_store.verify(cert3)).to be true
+ expect(cert_store.verify(certificate)).to be true
+ end
end
end
end
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/commit_signatures/gpg_signature_spec.rb
similarity index 97%
rename from spec/models/gpg_signature_spec.rb
rename to spec/models/commit_signatures/gpg_signature_spec.rb
index 7a1799c670e..9646e974f40 100644
--- a/spec/models/gpg_signature_spec.rb
+++ b/spec/models/commit_signatures/gpg_signature_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe GpgSignature do
+RSpec.describe CommitSignatures::GpgSignature do
let(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' }
let!(:project) { create(:project, :repository, path: 'sample-project') }
let!(:commit) { create(:commit, project: project, sha: commit_sha) }
@@ -13,7 +13,7 @@ RSpec.describe GpgSignature do
it_behaves_like 'having unique enum values'
describe 'associations' do
- it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:project).required }
it { is_expected.to belong_to(:gpg_key) }
it { is_expected.to belong_to(:gpg_key_subkey) }
end
diff --git a/spec/models/x509_commit_signature_spec.rb b/spec/models/commit_signatures/x509_commit_signature_spec.rb
similarity index 97%
rename from spec/models/x509_commit_signature_spec.rb
rename to spec/models/commit_signatures/x509_commit_signature_spec.rb
index 2efb77c96ad..076f209e1b7 100644
--- a/spec/models/x509_commit_signature_spec.rb
+++ b/spec/models/commit_signatures/x509_commit_signature_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe X509CommitSignature do
+RSpec.describe CommitSignatures::X509CommitSignature do
let(:commit_sha) { '189a6c924013fc3fe40d6f1ec1dc20214183bc97' }
let(:project) { create(:project, :public, :repository) }
let!(:commit) { create(:commit, project: project, sha: commit_sha) }
diff --git a/spec/models/packages/conan/metadatum_spec.rb b/spec/models/packages/conan/metadatum_spec.rb
index 1e0bcd7eede..d00723e8e43 100644
--- a/spec/models/packages/conan/metadatum_spec.rb
+++ b/spec/models/packages/conan/metadatum_spec.rb
@@ -54,23 +54,17 @@ RSpec.describe Packages::Conan::Metadatum, type: :model do
subject { metadatum.valid? }
- where(:username, :channel, :feature_flag, :valid) do
- 'username' | 'channel' | true | true
- 'username' | '_' | true | false
- '_' | 'channel' | true | false
- '_' | '_' | true | true
-
- 'username' | 'channel' | false | true
- 'username' | '_' | false | false
- '_' | 'channel' | false | false
- '_' | '_' | false | false
+ where(:username, :channel, :valid) do
+ 'username' | 'channel' | true
+ 'username' | '_' | false
+ '_' | 'channel' | false
+ '_' | '_' | true
end
with_them do
before do
metadatum.package_username = username
metadatum.package_channel = channel
- stub_feature_flags(packages_conan_allow_empty_username_channel: feature_flag)
end
it { is_expected.to eq(valid) }
diff --git a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
index e62314e624e..71f3a0235be 100644
--- a/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb
@@ -183,16 +183,11 @@ RSpec.shared_examples 'handling empty values for username and channel' do
let(:recipe_path) { "#{package.name}/#{package.version}/#{package_username}/#{channel}" }
- where(:username, :channel, :feature_flag, :status) do
- 'username' | 'channel' | true | :ok
- 'username' | '_' | true | :bad_request
- '_' | 'channel' | true | :bad_request_or_not_found
- '_' | '_' | true | :ok_or_not_found
-
- 'username' | 'channel' | false | :ok
- 'username' | '_' | false | :bad_request
- '_' | 'channel' | false | :bad_request
- '_' | '_' | false | :bad_request
+ where(:username, :channel, :status) do
+ 'username' | 'channel' | :ok
+ 'username' | '_' | :bad_request
+ '_' | 'channel' | :bad_request_or_not_found
+ '_' | '_' | :ok_or_not_found
end
with_them do
@@ -205,7 +200,6 @@ RSpec.shared_examples 'handling empty values for username and channel' do
end
before do
- stub_feature_flags(packages_conan_allow_empty_username_channel: feature_flag)
project.add_maintainer(user) # avoid any permission issue
end
diff --git a/spec/workers/create_commit_signature_worker_spec.rb b/spec/workers/create_commit_signature_worker_spec.rb
index d283ff5b732..0e31faf47af 100644
--- a/spec/workers/create_commit_signature_worker_spec.rb
+++ b/spec/workers/create_commit_signature_worker_spec.rb
@@ -143,7 +143,7 @@ RSpec.describe CreateCommitSignatureWorker do
let(:type) { :X509 }
it 'performs a single query for commit signatures' do
- expect(X509CommitSignature).to receive(:by_commit_sha).with(commit_shas).once.and_return([])
+ expect(CommitSignatures::X509CommitSignature).to receive(:by_commit_sha).with(commit_shas).once.and_return([])
subject
end
@@ -153,7 +153,7 @@ RSpec.describe CreateCommitSignatureWorker do
let(:type) { :PGP }
it 'performs a single query for commit signatures' do
- expect(GpgSignature).to receive(:by_commit_sha).with(commit_shas).once.and_return([])
+ expect(CommitSignatures::GpgSignature).to receive(:by_commit_sha).with(commit_shas).once.and_return([])
subject
end