Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e91ff9d11f
commit
b4d5fdae42
|
|
@ -131,7 +131,7 @@ workflow:
|
|||
|
||||
variables:
|
||||
PG_VERSION: "12"
|
||||
DEFAULT_CI_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}.patched-golang-${GO_VERSION}-rust-${RUST_VERSION}-node-16.14-postgresql-${PG_VERSION}:rubygems-3.2-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-yarn-1.22-graphicsmagick-1.3.36"
|
||||
DEFAULT_CI_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}.patched-golang-${GO_VERSION}-rust-${RUST_VERSION}-node-16.14-postgresql-${PG_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-yarn-1.22-graphicsmagick-1.3.36"
|
||||
# We set $GITLAB_DEPENDENCY_PROXY to another variable (since it's set at the group level and has higher precedence than .gitlab-ci.yml)
|
||||
# so that we can override $GITLAB_DEPENDENCY_PROXY_ADDRESS in workflow rules.
|
||||
GITLAB_DEPENDENCY_PROXY_ADDRESS: "${GITLAB_DEPENDENCY_PROXY}"
|
||||
|
|
@ -151,6 +151,7 @@ variables:
|
|||
CHROME_VERSION: "109"
|
||||
DOCKER_VERSION: "23.0.1"
|
||||
RUBY_VERSION: "2.7"
|
||||
RUBYGEMS_VERSION: "3.4"
|
||||
GO_VERSION: "1.18"
|
||||
RUST_VERSION: "1.65"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
- .default-retry
|
||||
- .default-before_script
|
||||
- .assets-compile-cache
|
||||
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-16.14:rubygems-3.2-git-2.33-lfs-2.9-yarn-1.22-graphicsmagick-1.3.36
|
||||
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-16.14:rubygems-${RUBYGEMS_VERSION}-git-2.33-lfs-2.9-yarn-1.22-graphicsmagick-1.3.36
|
||||
variables:
|
||||
SETUP_DB: "false"
|
||||
WEBPACK_VENDOR_DLL: "true"
|
||||
|
|
|
|||
|
|
@ -440,6 +440,12 @@ BackgroundMigration/FeatureCategory:
|
|||
Include:
|
||||
- 'lib/gitlab/background_migration/*.rb'
|
||||
|
||||
BackgroundMigration/MissingDictionaryFile:
|
||||
Enabled: true
|
||||
EnforcedSince: 20230307160251
|
||||
Include:
|
||||
- 'db/post_migrate/*.rb'
|
||||
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/373194
|
||||
Gitlab/RSpec/AvoidSetup:
|
||||
Enabled: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
# Grace period will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/395354
|
||||
BackgroundMigration/MissingDictionaryFile:
|
||||
Details: grace period
|
||||
|
|
@ -1135,7 +1135,6 @@ RSpec/MissingFeatureCategory:
|
|||
- 'ee/spec/lib/omni_auth/strategies/kerberos_spec.rb'
|
||||
- 'ee/spec/lib/peek/views/elasticsearch_spec.rb'
|
||||
- 'ee/spec/lib/quality/seeders/vulnerabilities_spec.rb'
|
||||
- 'ee/spec/lib/sidebars/groups/menus/administration_menu_spec.rb'
|
||||
- 'ee/spec/lib/sidebars/groups/menus/analytics_menu_spec.rb'
|
||||
- 'ee/spec/lib/sidebars/groups/menus/security_compliance_menu_spec.rb'
|
||||
- 'ee/spec/lib/slack/api_spec.rb'
|
||||
|
|
|
|||
|
|
@ -642,7 +642,6 @@ Style/IfUnlessModifier:
|
|||
- 'ee/lib/gitlab/usage/metrics/instrumentations/count_users_creating_ci_builds_metric.rb'
|
||||
- 'ee/lib/gitlab/usage/metrics/instrumentations/license_metric.rb'
|
||||
- 'ee/lib/omni_auth/strategies/group_saml.rb'
|
||||
- 'ee/lib/sidebars/groups/menus/administration_menu.rb'
|
||||
- 'ee/lib/sidebars/groups/menus/analytics_menu.rb'
|
||||
- 'ee/lib/sidebars/groups/menus/security_compliance_menu.rb'
|
||||
- 'ee/lib/tasks/geo.rake'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
60b05a6155531cdfd5e51b2ed3c6e888f105048b
|
||||
d1ce57834e67383564e6d7faf7827be3a7dd8afe
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ export default {
|
|||
CollapseToggle: GlCollapseToggleDirective,
|
||||
},
|
||||
props: {
|
||||
/*
|
||||
* Contains metadata about the current view, e.g. `id`, `title` and `avatar`
|
||||
*/
|
||||
context: {
|
||||
type: Object,
|
||||
required: true,
|
||||
|
|
@ -24,6 +27,9 @@ export default {
|
|||
collapseIcon() {
|
||||
return this.expanded ? 'chevron-up' : 'chevron-down';
|
||||
},
|
||||
avatarShape() {
|
||||
return this.context.avatar_shape || 'rect';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -43,7 +49,7 @@ export default {
|
|||
<gl-avatar
|
||||
v-else
|
||||
:size="24"
|
||||
shape="rect"
|
||||
:shape="avatarShape"
|
||||
:entity-name="context.title"
|
||||
:entity-id="context.id"
|
||||
:src="context.avatar"
|
||||
|
|
|
|||
|
|
@ -143,11 +143,24 @@
|
|||
.dropdown-menu-toggle.dropdown-menu-toggle {
|
||||
justify-content: flex-start;
|
||||
overflow: hidden;
|
||||
padding-top: #{$gl-padding-8 - 1};
|
||||
padding-bottom: #{$gl-padding-8 - 1};
|
||||
padding-right: 25px;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
line-height: $gl-line-height;
|
||||
width: 160px;
|
||||
|
||||
&:hover {
|
||||
@include gl-inset-border-1-gray-400;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: $gray-50;
|
||||
border-color: $gray-400;
|
||||
}
|
||||
|
||||
.gl-spinner {
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
|
|
@ -157,7 +170,7 @@
|
|||
.dropdown-menu-toggle-icon {
|
||||
position: absolute;
|
||||
right: $gl-padding-8;
|
||||
color: $gray-darkest;
|
||||
color: $gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -661,9 +661,12 @@ html {
|
|||
.dropdown-menu-toggle.dropdown-menu-toggle {
|
||||
justify-content: flex-start;
|
||||
overflow: hidden;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
padding-right: 25px;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 16px;
|
||||
width: 160px;
|
||||
}
|
||||
.dropdown-menu {
|
||||
|
|
|
|||
|
|
@ -661,9 +661,12 @@ html {
|
|||
.dropdown-menu-toggle.dropdown-menu-toggle {
|
||||
justify-content: flex-start;
|
||||
overflow: hidden;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
padding-right: 25px;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 16px;
|
||||
width: 160px;
|
||||
}
|
||||
.dropdown-menu {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ module DropdownsHelper
|
|||
default_label = data_attr[:default_label]
|
||||
content_tag(:button, disabled: options[:disabled], class: "dropdown-menu-toggle #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do
|
||||
output = content_tag(:span, toggle_text, class: "dropdown-toggle-text #{'is-default' if toggle_text == default_label}")
|
||||
output << sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
|
||||
output << sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon")
|
||||
output.html_safe
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ module NavHelper
|
|||
def super_sidebar_supported?
|
||||
return true if @nav.nil?
|
||||
|
||||
%w(your_work project group profile).include?(@nav)
|
||||
%w(your_work project group profile user_profile).include?(@nav)
|
||||
end
|
||||
|
||||
def get_header_links
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@ module SidebarsHelper
|
|||
}
|
||||
end
|
||||
|
||||
def super_sidebar_nav_panel(nav: nil, project: nil, user: nil, group: nil, current_ref: nil, ref_type: nil)
|
||||
def super_sidebar_nav_panel(
|
||||
nav: nil, project: nil, user: nil, group: nil, current_ref: nil, ref_type: nil,
|
||||
viewed_user: nil)
|
||||
context_adds = { route_is_active: method(:active_nav_link?), is_super_sidebar: true }
|
||||
case nav
|
||||
when 'project'
|
||||
|
|
@ -102,6 +104,9 @@ module SidebarsHelper
|
|||
when 'profile'
|
||||
context = Sidebars::Context.new(current_user: user, container: user, **context_adds)
|
||||
Sidebars::UserSettings::Panel.new(context)
|
||||
when 'user_profile'
|
||||
context = Sidebars::Context.new(current_user: user, container: viewed_user, **context_adds)
|
||||
Sidebars::UserProfile::Panel.new(context)
|
||||
else
|
||||
context = your_work_sidebar_context(user, **context_adds)
|
||||
Sidebars::YourWork::Panel.new(context)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ContainerRegistry
|
||||
class DataRepairDetail < ApplicationRecord
|
||||
self.table_name = 'container_registry_data_repair_details'
|
||||
self.primary_key = :project_id
|
||||
|
||||
belongs_to :project, optional: false
|
||||
end
|
||||
end
|
||||
|
|
@ -13,7 +13,7 @@ module Packages
|
|||
|
||||
enum status: { default: 0, pending_destruction: 1, processing: 2, error: 3 }
|
||||
|
||||
belongs_to :project, inverse_of: :repository_files
|
||||
belongs_to :project, inverse_of: :rpm_repository_files
|
||||
|
||||
validates :project, presence: true
|
||||
validates :file, presence: true
|
||||
|
|
|
|||
|
|
@ -243,14 +243,22 @@ class Project < ApplicationRecord
|
|||
has_many :fork_network_projects, through: :fork_network, source: :projects
|
||||
|
||||
# Packages
|
||||
has_many :packages, class_name: 'Packages::Package'
|
||||
has_many :package_files, through: :packages, class_name: 'Packages::PackageFile'
|
||||
has_many :packages,
|
||||
class_name: 'Packages::Package'
|
||||
has_many :package_files,
|
||||
through: :packages, class_name: 'Packages::PackageFile'
|
||||
# repository_files must be destroyed by ruby code in order to properly remove carrierwave uploads
|
||||
has_many :repository_files, inverse_of: :project, class_name: 'Packages::Rpm::RepositoryFile',
|
||||
dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_many :rpm_repository_files,
|
||||
inverse_of: :project,
|
||||
class_name: 'Packages::Rpm::RepositoryFile',
|
||||
dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
# debian_distributions and associated component_files must be destroyed by ruby code in order to properly remove carrierwave uploads
|
||||
has_many :debian_distributions, class_name: 'Packages::Debian::ProjectDistribution', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_one :packages_cleanup_policy, class_name: 'Packages::Cleanup::Policy', inverse_of: :project
|
||||
has_many :debian_distributions,
|
||||
class_name: 'Packages::Debian::ProjectDistribution',
|
||||
dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_one :packages_cleanup_policy,
|
||||
class_name: 'Packages::Cleanup::Policy',
|
||||
inverse_of: :project
|
||||
|
||||
has_one :import_state, autosave: true, class_name: 'ProjectImportState', inverse_of: :project
|
||||
has_one :import_export_upload, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ class ProjectPolicy < BasePolicy
|
|||
enable :reporter_access
|
||||
enable :developer_access
|
||||
enable :maintainer_access
|
||||
enable :add_catalog_resource
|
||||
|
||||
enable :change_namespace
|
||||
enable :change_visibility_level
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
module Catalog
|
||||
class AddResourceService
|
||||
include Gitlab::Allowable
|
||||
|
||||
attr_reader :project, :current_user
|
||||
|
||||
def initialize(project, user)
|
||||
@current_user = user
|
||||
@project = project
|
||||
end
|
||||
|
||||
def execute
|
||||
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :add_catalog_resource, project)
|
||||
|
||||
validation_response = Ci::Catalog::ValidateResourceService.new(project, project.default_branch).execute
|
||||
|
||||
if validation_response.success?
|
||||
create_catalog_resource
|
||||
else
|
||||
ServiceResponse.error(message: validation_response.message)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_catalog_resource
|
||||
catalog_resource = Ci::Catalog::Resource.new(project: project)
|
||||
|
||||
if catalog_resource.valid?
|
||||
catalog_resource.save!
|
||||
ServiceResponse.success(payload: catalog_resource)
|
||||
else
|
||||
ServiceResponse.error(message: catalog_resource.errors.full_messages.join(', '))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
module Catalog
|
||||
class ValidateResourceService
|
||||
attr_reader :project
|
||||
|
||||
def initialize(project, ref)
|
||||
@project = project
|
||||
@ref = ref
|
||||
@errors = []
|
||||
end
|
||||
|
||||
def execute
|
||||
check_project_readme
|
||||
check_project_description
|
||||
|
||||
if errors.empty?
|
||||
ServiceResponse.success
|
||||
else
|
||||
ServiceResponse.error(message: errors.join(' , '))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :ref, :errors
|
||||
|
||||
def check_project_description
|
||||
return if project.description.present?
|
||||
|
||||
errors << 'Project must have a description'
|
||||
end
|
||||
|
||||
def check_project_readme
|
||||
return if project_has_readme?
|
||||
|
||||
errors << 'Project must have a README'
|
||||
end
|
||||
|
||||
def project_has_readme?
|
||||
project.repository.blob_data_at(ref, 'README.md')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -9,7 +9,7 @@ module Import
|
|||
|
||||
if project.import_in_progress?
|
||||
project.import_state.cancel
|
||||
metrics.track_import_state
|
||||
metrics.track_canceled_import
|
||||
|
||||
success(project: project)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
= sort_options_hash[@sort]
|
||||
- else
|
||||
= sort_title_recently_created
|
||||
= sprite_icon('chevron-down', css_class: 'dropdown-menu-toggle-icon gl-top-3')
|
||||
= sprite_icon('chevron-down', css_class: 'dropdown-menu-toggle-icon')
|
||||
%ul.dropdown-menu.dropdown-menu-sort.dropdown-menu-right
|
||||
%li
|
||||
= link_to todos_filter_path(sort: sort_value_label_priority) do
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
-# Render the parent group sidebar while creating a new subgroup/project, see GroupsController#new.
|
||||
- group = @parent_group || @group
|
||||
|
||||
- sidebar_panel = super_sidebar_nav_panel(nav: nav, user: current_user, group: group, project: @project, current_ref: current_ref, ref_type: @ref_type)
|
||||
- sidebar_panel = super_sidebar_nav_panel(nav: nav, user: current_user, group: group, project: @project, current_ref: current_ref, ref_type: @ref_type, viewed_user: @user)
|
||||
- sidebar_data = super_sidebar_context(current_user, group: group, project: @project, panel: sidebar_panel).to_json
|
||||
%aside.js-super-sidebar.super-sidebar.super-sidebar-loading{ data: { root_path: root_path, sidebar: sidebar_data, toggle_new_nav_endpoint: profile_preferences_url } }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
= render partial: 'shared/nav/sidebar', object: Sidebars::UserProfile::Panel.new(Sidebars::Context.new(current_user: current_user, container: @user))
|
||||
|
|
@ -5,7 +5,8 @@
|
|||
.gl-p-5.gl-display-flex
|
||||
.gl-md-display-flex.gl-text-left.gl-align-items-center.gl-flex-grow-1.gl-white-space-nowrap.gl-max-w-full
|
||||
- unless @search_service_presenter.without_count?
|
||||
= search_entries_info(@search_objects, @scope, @search_term)
|
||||
.gl-text-truncate
|
||||
= search_entries_info(@search_objects, @scope, @search_term)
|
||||
- unless @search_service_presenter.show_snippets?
|
||||
- if @project
|
||||
- link_to_project = link_to(@project.full_name, @project, class: 'ml-md-1 gl-text-truncate search-wrap-f-md-down')
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
- apply_is_default_styles = (selected.nil? || selected.empty?) && !no_default_styles
|
||||
%span.dropdown-toggle-text{ class: ("is-default" if apply_is_default_styles) }
|
||||
= multi_label_name(selected, label_name)
|
||||
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
|
||||
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon")
|
||||
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable.dropdown-extended-height
|
||||
= render partial: "shared/issuable/label_page_default", locals: { title: dropdown_title, show_footer: show_footer, show_create: show_create }
|
||||
- if show_create && project && can?(current_user, :admin_label, project)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
|
||||
%span.dropdown-toggle-text.is-default
|
||||
= issuable.issue_type.capitalize || _("Select type")
|
||||
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
|
||||
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon")
|
||||
.dropdown-menu.dropdown-menu-selectable.dropdown-select
|
||||
.dropdown-title.gl-display-flex
|
||||
%span.gl-ml-auto
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
- page_itemtype 'http://schema.org/Person'
|
||||
- add_page_specific_style 'page_bundles/profile'
|
||||
- link_classes = "flex-grow-1 mx-1 "
|
||||
- if show_super_sidebar?
|
||||
- @left_sidebar = true
|
||||
- nav "user_profile"
|
||||
|
||||
= content_for :meta_tags do
|
||||
= auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity")
|
||||
|
|
@ -120,7 +123,7 @@
|
|||
= @user.bio
|
||||
|
||||
- if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user)
|
||||
.scrolling-tabs-container
|
||||
.scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] }
|
||||
.fade-left= sprite_icon('chevron-lg-left', size: 12)
|
||||
.fade-right= sprite_icon('chevron-lg-right', size: 12)
|
||||
%ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: disable_update_max_seats_worker
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114127
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725
|
||||
milestone: '15.10'
|
||||
type: development
|
||||
group: group::utilization
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.importer.github_import_project_cancelled_monthly
|
||||
description: The number of github projects that were cancelled monthly
|
||||
product_section: dev
|
||||
product_stage: manage
|
||||
product_group: import
|
||||
product_category: importers
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.10"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
|
||||
time_frame: 28d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
options:
|
||||
events:
|
||||
- github_import_project_cancelled
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.importer.github_import_project_partially_completed_monthly
|
||||
description: The number of github projects that were partially completed monthly
|
||||
product_section: dev
|
||||
product_stage: manage
|
||||
product_group: import
|
||||
product_category: importers
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.10"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
|
||||
time_frame: 28d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
options:
|
||||
events:
|
||||
- github_import_project_partially_completed
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.importer.github_import_project_cancelled_weekly
|
||||
description: The number of github projects that were cancelled weekly
|
||||
product_section: dev
|
||||
product_stage: manage
|
||||
product_group: import
|
||||
product_category: importers
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.10"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
|
||||
time_frame: 7d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
options:
|
||||
events:
|
||||
- github_import_project_cancelled
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
key_path: redis_hll_counters.importer.github_import_project_partially_completed_weekly
|
||||
description: The number of github projects that were partially completed weekly
|
||||
product_section: dev
|
||||
product_stage: manage
|
||||
product_group: import
|
||||
product_category: importers
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: "15.10"
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113724
|
||||
time_frame: 7d
|
||||
data_source: redis_hll
|
||||
data_category: optional
|
||||
instrumentation_class: RedisHLLMetric
|
||||
options:
|
||||
events:
|
||||
- github_import_project_partially_completed
|
||||
performance_indicator_type: []
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
- title: "Error Tracking UI in GitLab Rails is deprecated"
|
||||
announcement_milestone: "15.9"
|
||||
removal_milestone: "16.0"
|
||||
removal_milestone: "16.6"
|
||||
breaking_change: true
|
||||
reporter: kbychu
|
||||
stage: monitor
|
||||
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389991
|
||||
body: |
|
||||
The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.0. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
|
||||
The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.6 (milestone might change) once GitLab Observability UI is made available. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
|
||||
|
||||
During the transition to the GitLab Observability UI, we will migrate the [GitLab Observability Backend](https://gitlab.com/gitlab-org/opstrace/opstrace) from a per-cluster deployment model to a per-tenant deployment model. Because [Integrated Error Tracking](https://docs.gitlab.com/ee/operations/error_tracking.html#integrated-error-tracking) is in Open Beta, we will not migrate any existing user data. For more details about the migration, see the direction pages for:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
table_name: container_registry_data_repair_details
|
||||
classes:
|
||||
- ContainerRegistry::DataRepairDetail
|
||||
feature_categories:
|
||||
- container_registry
|
||||
description: Contains details for the container registry data repair
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113029
|
||||
milestone: '15.10'
|
||||
gitlab_schema: gitlab_main
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateContainerRegistryDataRepairDetails < Gitlab::Database::Migration[2.1]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
create_table :container_registry_data_repair_details, id: false do |t|
|
||||
t.integer :missing_count, default: 0
|
||||
t.references :project,
|
||||
primary_key: true,
|
||||
default: nil,
|
||||
index: false,
|
||||
foreign_key: { to_table: :projects, on_delete: :cascade }
|
||||
t.timestamps_with_timezone null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
f9132e8d1d39307fc4f9ef17c6e044bab636d17ae7a7e5207f26ab3e38441638
|
||||
|
|
@ -14523,6 +14523,13 @@ CREATE TABLE container_expiration_policies (
|
|||
CONSTRAINT container_expiration_policies_name_regex_keep CHECK ((char_length(name_regex_keep) <= 255))
|
||||
);
|
||||
|
||||
CREATE TABLE container_registry_data_repair_details (
|
||||
missing_count integer DEFAULT 0,
|
||||
project_id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE container_repositories (
|
||||
id integer NOT NULL,
|
||||
project_id integer NOT NULL,
|
||||
|
|
@ -26505,6 +26512,9 @@ ALTER TABLE ONLY compliance_management_frameworks
|
|||
ALTER TABLE ONLY container_expiration_policies
|
||||
ADD CONSTRAINT container_expiration_policies_pkey PRIMARY KEY (project_id);
|
||||
|
||||
ALTER TABLE ONLY container_registry_data_repair_details
|
||||
ADD CONSTRAINT container_registry_data_repair_details_pkey PRIMARY KEY (project_id);
|
||||
|
||||
ALTER TABLE ONLY container_repositories
|
||||
ADD CONSTRAINT container_repositories_pkey PRIMARY KEY (id);
|
||||
|
||||
|
|
@ -36229,6 +36239,9 @@ ALTER TABLE ONLY packages_debian_project_component_files
|
|||
ALTER TABLE ONLY namespace_aggregation_schedules
|
||||
ADD CONSTRAINT fk_rails_b565c8d16c FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY container_registry_data_repair_details
|
||||
ADD CONSTRAINT fk_rails_b70d8111d9 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE batched_background_migration_job_transition_logs
|
||||
ADD CONSTRAINT fk_rails_b7523a175b FOREIGN KEY (batched_background_migration_job_id) REFERENCES batched_background_migration_jobs(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -210,17 +210,17 @@ Users on self-managed instances should update their pipelines to ensure they do
|
|||
|
||||
</div>
|
||||
|
||||
<div class="deprecation removal-160 breaking-change">
|
||||
<div class="deprecation removal-166 breaking-change">
|
||||
|
||||
### Error Tracking UI in GitLab Rails is deprecated
|
||||
|
||||
Planned removal: GitLab <span class="removal-milestone">16.0</span> <span class="removal-date"></span>
|
||||
Planned removal: GitLab <span class="removal-milestone">16.6</span> <span class="removal-date"></span>
|
||||
|
||||
WARNING:
|
||||
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
|
||||
Review the details carefully before upgrading.
|
||||
|
||||
The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.0. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
|
||||
The [Error Tracking UI](https://docs.gitlab.com/ee/operations/error_tracking.html) is deprecated in 15.9 and will be removed in 16.6 (milestone might change) once GitLab Observability UI is made available. In future versions, you should use the [GitLab Observability UI](https://gitlab.com/gitlab-org/opstrace/opstrace-ui/), which will gradually be made available on GitLab.com over the next few releases.
|
||||
|
||||
During the transition to the GitLab Observability UI, we will migrate the [GitLab Observability Backend](https://gitlab.com/gitlab-org/opstrace/opstrace) from a per-cluster deployment model to a per-tenant deployment model. Because [Integrated Error Tracking](https://docs.gitlab.com/ee/operations/error_tracking.html#integrated-error-tracking) is in Open Beta, we will not migrate any existing user data. For more details about the migration, see the direction pages for:
|
||||
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
|
|||
- **Upgrade to patch release 15.9.3 or later**. This provides fixes for two database migration bugs:
|
||||
- Patch releases 15.9.0, 15.9.1, 15.9.2 have [a bug that can cause data loss](#user-profile-data-loss-bug-in-159x) from the user profile fields.
|
||||
- The second [bug fix](https://gitlab.com/gitlab-org/gitlab/-/issues/394760) ensures it is possible to upgrade directly from 15.4.x.
|
||||
- As part of the [CI Partitioning effort](../architecture/blueprints/ci_data_decay/pipeline_partitioning.md), a [new Foreign Key](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107547) was added to `ci_builds_needs`. On GitLab instances with large CI tables, adding this constraint can take longer than usual. Make sure that this migration is finished before upgrading to 15.9.
|
||||
- As part of the [CI Partitioning effort](../architecture/blueprints/ci_data_decay/pipeline_partitioning.md), a [new Foreign Key](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107547) was added to `ci_builds_needs`. On GitLab instances with large CI tables, adding this constraint can take longer than usual.
|
||||
- Praefect's metadata verifier's [invalid metadata deletion behavior](../administration/gitaly/praefect.md#enable-deletions) is now enabled by default.
|
||||
|
||||
The metadata verifier processes replica records in the Praefect database and verifies the replicas actually exist on the Gitaly nodes. If the replica doesn't exist, its
|
||||
|
|
@ -1461,7 +1461,7 @@ If your organization uses these fields either wait for the bug fix to be release
|
|||
|
||||
Organizations that are already running earlier patch levels of GitLab 15.6, 15.7, or 15.8 can proceed with steps 2 and 3.
|
||||
|
||||
If you have already upgraded to GitLab 15.9 following these instructions, your instance will not be affected by this bug, and you don't need to apply the 15.9.x patch when it is released.
|
||||
If you have already upgraded to GitLab 15.9 following these instructions, your instance will not be affected by this bug, and you don't need to apply the 15.9.x patch when it is released.
|
||||
|
||||
See [issue 393216](https://gitlab.com/gitlab-org/gitlab/-/issues/393216) for more information.
|
||||
|
||||
|
|
|
|||
|
|
@ -325,10 +325,7 @@ After you have configured your identity provider, you can:
|
|||
|
||||
To change the identity provider:
|
||||
|
||||
- If the `NameID` is not identical in the existing and new identity providers,
|
||||
tell users to:
|
||||
1. [Unlink the current SAML identity](#unlinking-accounts).
|
||||
1. [Link their identity](#user-access-and-management) to the new identity provider.
|
||||
- If the `NameID` is not identical in the existing and new identity providers, [change the NameID for users](#change-nameid-for-one-or-more-users).
|
||||
- If the `NameID` is identical, users do not have to make any changes.
|
||||
|
||||
### Migrate to a different identity provider
|
||||
|
|
@ -340,19 +337,17 @@ users cannot access any of the SAML groups. To mitigate this, you can disable
|
|||
To migrate identity providers:
|
||||
|
||||
1. [Configure](#configure-your-identity-provider) the group with the new identity provider.
|
||||
1. Tell users to:
|
||||
1. [Unlink their account from the group](#unlinking-accounts).
|
||||
1. [Link their account to the new SAML app](#linking-saml-to-your-existing-gitlabcom-account).
|
||||
1. [Change the NameID for users](#change-nameid-for-one-or-more-users).
|
||||
|
||||
### Change email domains
|
||||
|
||||
To migrate users to a new email domain, tell users to:
|
||||
|
||||
1. Add their new email as the primary email to their accounts and verify it.
|
||||
1. [Unlink their account from the group](#unlinking-accounts).
|
||||
1. [Link their account to the group](#linking-saml-to-your-existing-gitlabcom-account).
|
||||
1. Optional. Remove their old email from the account.
|
||||
|
||||
If the NameID is configured with the email address, [change the NameID for users](#change-nameid-for-one-or-more-users).
|
||||
|
||||
## User access and management
|
||||
|
||||
> - SAML user provisioning [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/268142) in GitLab 13.7.
|
||||
|
|
@ -395,7 +390,8 @@ On subsequent visits, you should be able to go [sign in to GitLab.com with SAML]
|
|||
|
||||
> Update of SAML identities using the SAML API [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227841) in GitLab 15.5.
|
||||
|
||||
Group owners can update the SAML identities for their group members using the [SAML API](../../../api/saml.md).
|
||||
Group owners can update the SAML identities for their group members using the [SAML API](../../../api/saml.md#update-extern_uid-field-for-a-saml-identity).
|
||||
If [SCIM](scim_setup.md) is configured, group owners can update the SCIM identities using the [SCIM API](../../../api/scim.md#update-extern_uid-field-for-a-scim-identity).
|
||||
|
||||
Alternatively, ask the users to reconnect their SAML account.
|
||||
|
||||
|
|
|
|||
|
|
@ -64,5 +64,10 @@ module BatchedBackgroundMigration
|
|||
def feature_category
|
||||
options[:feature_category]
|
||||
end
|
||||
|
||||
def current_milestone
|
||||
version = Gem::Version.new(File.read('VERSION'))
|
||||
version.release.segments.first(2).join('.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ migration_job_name: <%= class_name %>
|
|||
description: # Please capture what <%= class_name %> does
|
||||
feature_category: <%= feature_category %>
|
||||
introduced_by_url: # URL of the MR (or issue/commit) that introduced the migration
|
||||
milestone:
|
||||
milestone: <%= current_milestone %>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ module Gitlab
|
|||
payload['exception.backtrace'] = Rails.backtrace_cleaner.clean(exception.backtrace)
|
||||
end
|
||||
|
||||
if exception.cause
|
||||
payload['exception.cause_class'] = exception.cause.class.name
|
||||
end
|
||||
|
||||
if sql = find_sql(exception)
|
||||
payload['exception.sql'] = sql
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,28 +44,28 @@ module Gitlab
|
|||
TRANSLATION_LEVELS = {
|
||||
'bg' => 0,
|
||||
'cs_CZ' => 0,
|
||||
'da_DK' => 34,
|
||||
'de' => 16,
|
||||
'da_DK' => 33,
|
||||
'de' => 15,
|
||||
'en' => 100,
|
||||
'eo' => 0,
|
||||
'es' => 33,
|
||||
'es' => 32,
|
||||
'fil_PH' => 0,
|
||||
'fr' => 99,
|
||||
'gl_ES' => 0,
|
||||
'id_ID' => 0,
|
||||
'it' => 1,
|
||||
'ja' => 31,
|
||||
'ko' => 20,
|
||||
'nb_NO' => 23,
|
||||
'ko' => 19,
|
||||
'nb_NO' => 22,
|
||||
'nl_NL' => 0,
|
||||
'pl_PL' => 3,
|
||||
'pt_BR' => 57,
|
||||
'ro_RO' => 91,
|
||||
'ru' => 26,
|
||||
'si_LK' => 11,
|
||||
'pt_BR' => 56,
|
||||
'ro_RO' => 89,
|
||||
'ru' => 25,
|
||||
'si_LK' => 10,
|
||||
'tr_TR' => 10,
|
||||
'uk' => 55,
|
||||
'zh_CN' => 98,
|
||||
'uk' => 53,
|
||||
'zh_CN' => 96,
|
||||
'zh_HK' => 1,
|
||||
'zh_TW' => 98
|
||||
}.freeze
|
||||
|
|
|
|||
|
|
@ -89,13 +89,8 @@ module Gitlab
|
|||
)
|
||||
end
|
||||
|
||||
def import_metrics
|
||||
@import_metrics ||= Gitlab::Import::Metrics.new("#{project.import_type}_importer", project)
|
||||
end
|
||||
|
||||
def track_metrics
|
||||
import_metrics.track_failed_import
|
||||
import_metrics.track_import_state
|
||||
Gitlab::Import::Metrics.new("#{project.import_type}_importer", project).track_failed_import
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,25 +26,20 @@ module Gitlab
|
|||
observe_histogram
|
||||
projects_counter.increment
|
||||
track_finish_metric
|
||||
track_import_state
|
||||
end
|
||||
|
||||
def track_failed_import
|
||||
return unless project.github_import?
|
||||
|
||||
track_usage_event(:github_import_project_failure, project.id)
|
||||
track_import_state('github')
|
||||
end
|
||||
|
||||
def track_import_state
|
||||
def track_canceled_import
|
||||
return unless project.github_import?
|
||||
|
||||
Gitlab::Tracking.event(
|
||||
importer,
|
||||
'create',
|
||||
label: 'github_import_project_state',
|
||||
project: project,
|
||||
extra: { import_type: 'github', state: project.beautified_import_status_name }
|
||||
)
|
||||
track_usage_event(:github_import_project_cancelled, project.id)
|
||||
track_import_state('github')
|
||||
end
|
||||
|
||||
def issues_counter
|
||||
|
|
@ -88,7 +83,24 @@ module Gitlab
|
|||
def track_finish_metric
|
||||
return unless project.github_import?
|
||||
|
||||
track_usage_event(:github_import_project_success, project.id)
|
||||
track_import_state('github')
|
||||
|
||||
case project.beautified_import_status_name
|
||||
when 'partially completed'
|
||||
track_usage_event(:github_import_project_partially_completed, project.id)
|
||||
when 'completed'
|
||||
track_usage_event(:github_import_project_success, project.id)
|
||||
end
|
||||
end
|
||||
|
||||
def track_import_state(type)
|
||||
Gitlab::Tracking.event(
|
||||
importer,
|
||||
'create',
|
||||
label: "#{type}_import_project_state",
|
||||
project: project,
|
||||
extra: { import_type: type, state: project.beautified_import_status_name }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,3 +9,9 @@
|
|||
- name: github_import_project_failure
|
||||
redis_slot: import
|
||||
aggregation: weekly
|
||||
- name: github_import_project_cancelled
|
||||
redis_slot: import
|
||||
aggregation: weekly
|
||||
- name: github_import_project_partially_completed
|
||||
redis_slot: import
|
||||
aggregation: weekly
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
class BaseMenu < ::Sidebars::Menu
|
||||
override :render?
|
||||
def render?
|
||||
can?(context.current_user, :read_user_profile, context.container)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class ActivityMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
override :link
|
||||
def link
|
||||
user_activity_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Activity')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#activity' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class ContributedProjectsMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
override :link
|
||||
def link
|
||||
user_contributed_projects_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Contributed projects')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#contributed' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class FollowersMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
override :link
|
||||
def link
|
||||
user_followers_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Followers')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#followers' }
|
||||
end
|
||||
|
||||
override :has_pill?
|
||||
def has_pill?
|
||||
context.container.followers.any?
|
||||
end
|
||||
strong_memoize_attr :has_pill?
|
||||
|
||||
override :pill_count
|
||||
def pill_count
|
||||
context.container.followers.count
|
||||
end
|
||||
strong_memoize_attr :pill_count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class FollowingMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
override :link
|
||||
def link
|
||||
user_following_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Following')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#following' }
|
||||
end
|
||||
|
||||
override :has_pill?
|
||||
def has_pill?
|
||||
context.container.followees.any?
|
||||
end
|
||||
strong_memoize_attr :has_pill?
|
||||
|
||||
override :pill_count
|
||||
def pill_count
|
||||
context.container.followees.count
|
||||
end
|
||||
strong_memoize_attr :pill_count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class GroupsMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
override :link
|
||||
def link
|
||||
user_groups_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Groups')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#groups' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class OverviewMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
override :link
|
||||
def link
|
||||
user_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Overview')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#show' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class PersonalProjectsMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
override :link
|
||||
def link
|
||||
user_projects_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Personal projects')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#projects' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class SnippetsMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
override :link
|
||||
def link
|
||||
user_snippets_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Snippets')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#snippets' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
module Menus
|
||||
class StarredProjectsMenu < ::Sidebars::UserProfile::BaseMenu
|
||||
override :link
|
||||
def link
|
||||
user_starred_projects_path(context.container)
|
||||
end
|
||||
|
||||
override :title
|
||||
def title
|
||||
s_('UserProfile|Starred projects')
|
||||
end
|
||||
|
||||
override :active_routes
|
||||
def active_routes
|
||||
{ path: 'users#starred' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sidebars
|
||||
module UserProfile
|
||||
class Panel < ::Sidebars::Panel
|
||||
include UsersHelper
|
||||
|
||||
override :configure_menus
|
||||
def configure_menus
|
||||
add_menus
|
||||
end
|
||||
|
||||
override :aria_label
|
||||
def aria_label
|
||||
s_('UserProfile|User profile navigation')
|
||||
end
|
||||
|
||||
override :super_sidebar_context_header
|
||||
def super_sidebar_context_header
|
||||
@super_sidebar_context_header ||= {
|
||||
title: user_name,
|
||||
avatar: context.container.avatar_url,
|
||||
avatar_shape: 'circle'
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user
|
||||
context.container
|
||||
end
|
||||
|
||||
def user_name
|
||||
return user_display_name(user) if user.blocked? || !user.confirmed?
|
||||
|
||||
user.name
|
||||
end
|
||||
|
||||
def add_menus
|
||||
add_menu(Sidebars::UserProfile::Menus::OverviewMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::ActivityMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::GroupsMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::ContributedProjectsMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::PersonalProjectsMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::StarredProjectsMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::SnippetsMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::FollowersMenu.new(context))
|
||||
add_menu(Sidebars::UserProfile::Menus::FollowingMenu.new(context))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -458,7 +458,7 @@ namespace :gitlab do
|
|||
Rails.application.eager_load!
|
||||
|
||||
version = Gem::Version.new(File.read('VERSION'))
|
||||
milestone = version.release.segments[0..1].join('.')
|
||||
milestone = version.release.segments.first(2).join('.')
|
||||
|
||||
classes = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -3627,9 +3627,6 @@ msgstr ""
|
|||
msgid "AdminUsers|user cap"
|
||||
msgstr ""
|
||||
|
||||
msgid "Administration"
|
||||
msgstr ""
|
||||
|
||||
msgid "Administrators"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -47224,6 +47221,9 @@ msgstr ""
|
|||
msgid "UserProfile|User ID: %{id}"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserProfile|User profile navigation"
|
||||
msgstr ""
|
||||
|
||||
msgid "UserProfile|View all"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@
|
|||
"cheerio": "^1.0.0-rc.9",
|
||||
"commander": "^2.20.3",
|
||||
"custom-jquery-matchers": "^2.1.0",
|
||||
"eslint": "8.34.0",
|
||||
"eslint": "8.35.0",
|
||||
"eslint-import-resolver-jest": "3.0.2",
|
||||
"eslint-import-resolver-webpack": "0.13.2",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ module QA
|
|||
end
|
||||
|
||||
def enable_saml_sso(group, saml_idp_service, enforce_sso: false, default_membership_role: 'Guest')
|
||||
Runtime::Feature.enable(:group_administration_nav_item)
|
||||
|
||||
page.visit Runtime::Scenario.gitlab_address
|
||||
|
||||
Page::Main::Login.perform(&:sign_in_using_credentials) unless Page::Main::Menu.perform(&:signed_in?)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../migration_helpers'
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module BackgroundMigration
|
||||
# Checks the batched background migration has the corresponding dictionary file
|
||||
class MissingDictionaryFile < RuboCop::Cop::Base
|
||||
include MigrationHelpers
|
||||
|
||||
MSG = "Missing %{file_name}. " \
|
||||
"Use the generator 'batched_background_migration' to create dictionary files automatically. " \
|
||||
"For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator"
|
||||
|
||||
DICTIONARY_DIR = "db/docs/batched_background_migrations"
|
||||
|
||||
def_node_matcher :batched_background_migration_name_node, <<~PATTERN
|
||||
`(send nil? :queue_batched_background_migration $_ ...)
|
||||
PATTERN
|
||||
|
||||
def_node_matcher :migration_constant_value, <<~PATTERN
|
||||
`(casgn nil? %const_name ({sym|str} $_))
|
||||
PATTERN
|
||||
|
||||
def on_class(node)
|
||||
return unless time_enforced?(node) && in_post_deployment_migration?(node)
|
||||
|
||||
migration_name_node = batched_background_migration_name_node(node)
|
||||
return unless migration_name_node
|
||||
|
||||
migration_name = if migration_name_node.const_name.present?
|
||||
migration_constant_value(node, const_name: migration_name_node.const_name.to_sym)
|
||||
else
|
||||
migration_name_node.value
|
||||
end
|
||||
|
||||
return if dictionary_file?(migration_name)
|
||||
|
||||
add_offense(node, message: format(MSG, file_name: dictionary_file_path(migration_name)))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def dictionary_file?(migration_class_name)
|
||||
File.exist?(dictionary_file_path(migration_class_name))
|
||||
end
|
||||
|
||||
def dictionary_file_path(migration_class_name)
|
||||
File.join(rails_root, DICTIONARY_DIR, "#{migration_class_name.underscore}.yml")
|
||||
end
|
||||
|
||||
def rails_root
|
||||
@rails_root ||= File.expand_path('../../..', __dir__)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import { GlAvatar } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import ContextSwitcherToggle from '~/super_sidebar/components/context_switcher_toggle.vue';
|
||||
|
||||
describe('ContextSwitcherToggle component', () => {
|
||||
let wrapper;
|
||||
|
||||
const context = {
|
||||
id: 1,
|
||||
title: 'Title',
|
||||
avatar: '/path/to/avatar.png',
|
||||
};
|
||||
|
||||
const findGlAvatar = () => wrapper.getComponent(GlAvatar);
|
||||
|
||||
const createWrapper = (props = {}) => {
|
||||
wrapper = shallowMountExtended(ContextSwitcherToggle, {
|
||||
propsData: {
|
||||
context,
|
||||
expanded: false,
|
||||
...props,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
describe('with an avatar', () => {
|
||||
it('passes the correct props to GlAvatar', () => {
|
||||
createWrapper();
|
||||
const avatar = findGlAvatar();
|
||||
|
||||
expect(avatar.props('shape')).toBe('rect');
|
||||
expect(avatar.props('entityName')).toBe(context.title);
|
||||
expect(avatar.props('entityId')).toBe(context.id);
|
||||
expect(avatar.props('src')).toBe(context.avatar);
|
||||
});
|
||||
|
||||
it('renders the avatar with a custom shape', () => {
|
||||
const customShape = 'circle';
|
||||
createWrapper({
|
||||
context: {
|
||||
...context,
|
||||
avatar_shape: customShape,
|
||||
},
|
||||
});
|
||||
const avatar = findGlAvatar();
|
||||
|
||||
expect(avatar.props('shape')).toBe(customShape);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -218,6 +218,10 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
|
|||
expect(helper.super_sidebar_nav_panel(nav: 'profile')).to be_a(Sidebars::UserSettings::Panel)
|
||||
end
|
||||
|
||||
it 'returns User profile Panel for user profile nav' do
|
||||
expect(helper.super_sidebar_nav_panel(nav: 'user_profile')).to be_a(Sidebars::UserProfile::Panel)
|
||||
end
|
||||
|
||||
it 'returns "Your Work" Panel for your_work nav', :use_clean_rails_memory_store_caching do
|
||||
expect(helper.super_sidebar_nav_panel(nav: 'your_work', user: user)).to be_a(Sidebars::YourWork::Panel)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ RSpec.describe BatchedBackgroundMigration::BatchedBackgroundMigrationGenerator,
|
|||
let(:expected_migration_spec_file) { load_expected_file('queue_my_batched_migration_spec.txt') }
|
||||
let(:expected_migration_job_file) { load_expected_file('my_batched_migration.txt') }
|
||||
let(:expected_migration_job_spec_file) { load_expected_file('my_batched_migration_spec_matcher.txt') }
|
||||
let(:expected_migration_dictionary) { load_expected_file('my_batched_migration_dictionary.txt') }
|
||||
let(:expected_migration_dictionary) { load_expected_file('my_batched_migration_dictionary_matcher.txt') }
|
||||
|
||||
it 'generates expected files' do
|
||||
run_generator %w[my_batched_migration --table_name=projects --column_name=id --feature_category=database]
|
||||
|
|
@ -48,7 +48,8 @@ RSpec.describe BatchedBackgroundMigration::BatchedBackgroundMigrationGenerator,
|
|||
end
|
||||
|
||||
assert_file('db/docs/batched_background_migrations/my_batched_migration.yml') do |migration_dictionary|
|
||||
expect(migration_dictionary).to eq(expected_migration_dictionary)
|
||||
# Regex is used to match the dynamically generated 'milestone' in the dictionary
|
||||
expect(migration_dictionary).to match(/#{expected_migration_dictionary}/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@
|
|||
migration_job_name: MyBatchedMigration
|
||||
description: # Please capture what MyBatchedMigration does
|
||||
feature_category: database
|
||||
introduced_by_url: # URL of the MR (or issue/commit) that introduced the migration
|
||||
milestone:
|
||||
introduced_by_url: # URL of the MR \(or issue/commit\) that introduced the migration
|
||||
milestone: [0-9\.]+
|
||||
|
|
@ -45,6 +45,12 @@ RSpec.describe Gitlab::ExceptionLogFormatter do
|
|||
allow(exception).to receive(:cause).and_return(ActiveRecord::StatementInvalid.new(sql: 'SELECT "users".* FROM "users" WHERE "users"."id" = 1 AND "users"."foo" = $1'))
|
||||
end
|
||||
|
||||
it 'adds the cause_class to payload' do
|
||||
described_class.format!(exception, payload)
|
||||
|
||||
expect(payload['exception.cause_class']).to eq('ActiveRecord::StatementInvalid')
|
||||
end
|
||||
|
||||
it 'adds the normalized SQL query to payload' do
|
||||
described_class.format!(exception, payload)
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,6 @@ RSpec.describe Gitlab::Import::ImportFailureService, :aggregate_failures do
|
|||
.with("#{project.import_type}_importer", project)
|
||||
.and_return(metrics_double)
|
||||
expect(metrics_double).to receive(:track_failed_import)
|
||||
expect(metrics_double).to receive(:track_import_state)
|
||||
|
||||
service.execute
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
|
|||
subject { described_class.new(importer, project) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Metrics).to receive(:counter) { counter }
|
||||
allow(counter).to receive(:increment)
|
||||
allow(histogram).to receive(:observe)
|
||||
end
|
||||
|
|
@ -42,29 +41,6 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
|
|||
context 'when project is not a github import' do
|
||||
it 'does not emit importer metrics' do
|
||||
expect(subject).not_to receive(:track_usage_event)
|
||||
|
||||
subject.track_failed_import
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is a github import' do
|
||||
before do
|
||||
project.import_type = 'github'
|
||||
end
|
||||
|
||||
it 'emits importer metrics' do
|
||||
expect(subject).to receive(:track_usage_event).with(:github_import_project_failure, project.id)
|
||||
|
||||
subject.track_failed_import
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#track_import_state' do
|
||||
context 'when project is not a github import' do
|
||||
it 'does not emit importer metrics' do
|
||||
subject.track_import_state
|
||||
|
||||
expect_no_snowplow_event(
|
||||
category: :test_importer,
|
||||
action: 'create',
|
||||
|
|
@ -72,6 +48,8 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
|
|||
project: project,
|
||||
extra: { import_type: 'github', state: 'failed' }
|
||||
)
|
||||
|
||||
subject.track_failed_import
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -82,7 +60,9 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
|
|||
end
|
||||
|
||||
it 'emits importer metrics' do
|
||||
subject.track_import_state
|
||||
expect(subject).to receive(:track_usage_event).with(:github_import_project_failure, project.id)
|
||||
|
||||
subject.track_failed_import
|
||||
|
||||
expect_snowplow_event(
|
||||
category: :test_importer,
|
||||
|
|
@ -96,28 +76,61 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
|
|||
end
|
||||
|
||||
describe '#track_finished_import' do
|
||||
before do
|
||||
allow(Gitlab::Metrics).to receive(:histogram) { histogram }
|
||||
end
|
||||
context 'when project is a github import' do
|
||||
before do
|
||||
project.import_type = 'github'
|
||||
allow(Gitlab::Metrics).to receive(:counter) { counter }
|
||||
allow(Gitlab::Metrics).to receive(:histogram) { histogram }
|
||||
allow(project).to receive(:beautified_import_status_name).and_return('completed')
|
||||
end
|
||||
|
||||
it 'emits importer metrics' do
|
||||
expect(Gitlab::Metrics).to receive(:counter).with(
|
||||
:test_importer_imported_projects_total,
|
||||
'The number of imported projects'
|
||||
)
|
||||
it 'emits importer metrics' do
|
||||
expect(Gitlab::Metrics).to receive(:counter).with(
|
||||
:test_importer_imported_projects_total,
|
||||
'The number of imported projects'
|
||||
)
|
||||
|
||||
expect(Gitlab::Metrics).to receive(:histogram).with(
|
||||
:test_importer_total_duration_seconds,
|
||||
'Total time spent importing projects, in seconds',
|
||||
{},
|
||||
described_class::IMPORT_DURATION_BUCKETS
|
||||
)
|
||||
expect(Gitlab::Metrics).to receive(:histogram).with(
|
||||
:test_importer_total_duration_seconds,
|
||||
'Total time spent importing projects, in seconds',
|
||||
{},
|
||||
described_class::IMPORT_DURATION_BUCKETS
|
||||
)
|
||||
|
||||
expect(counter).to receive(:increment)
|
||||
expect(counter).to receive(:increment)
|
||||
|
||||
subject.track_finished_import
|
||||
subject.track_finished_import
|
||||
|
||||
expect(subject.duration).not_to be_nil
|
||||
expect_snowplow_event(
|
||||
category: :test_importer,
|
||||
action: 'create',
|
||||
label: 'github_import_project_state',
|
||||
project: project,
|
||||
extra: { import_type: 'github', state: 'completed' }
|
||||
)
|
||||
|
||||
expect(subject.duration).not_to be_nil
|
||||
end
|
||||
|
||||
context 'when import is partially completed' do
|
||||
before do
|
||||
allow(project).to receive(:beautified_import_status_name).and_return('partially completed')
|
||||
end
|
||||
|
||||
it 'emits snowplow metrics' do
|
||||
expect(subject).to receive(:track_usage_event).with(:github_import_project_partially_completed, project.id)
|
||||
|
||||
subject.track_finished_import
|
||||
|
||||
expect_snowplow_event(
|
||||
category: :test_importer,
|
||||
action: 'create',
|
||||
label: 'github_import_project_state',
|
||||
project: project,
|
||||
extra: { import_type: 'github', state: 'partially completed' }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is not a github import' do
|
||||
|
|
@ -126,7 +139,6 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
|
|||
|
||||
subject.track_finished_import
|
||||
|
||||
expect(histogram).to have_received(:observe).with({ importer: :test_importer }, anything)
|
||||
expect_no_snowplow_event(
|
||||
category: :test_importer,
|
||||
action: 'create',
|
||||
|
|
@ -136,23 +148,41 @@ RSpec.describe Gitlab::Import::Metrics, :aggregate_failures do
|
|||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#track_cancelled_import' do
|
||||
context 'when project is not a github import' do
|
||||
it 'does not emit importer metrics' do
|
||||
expect(subject).not_to receive(:track_usage_event)
|
||||
expect_no_snowplow_event(
|
||||
category: :test_importer,
|
||||
action: 'create',
|
||||
label: 'github_import_project_state',
|
||||
project: project,
|
||||
extra: { import_type: 'github', state: 'canceled' }
|
||||
)
|
||||
|
||||
subject.track_canceled_import
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project is a github import' do
|
||||
before do
|
||||
project.import_type = 'github'
|
||||
allow(project).to receive(:import_status).and_return('finished')
|
||||
allow(project).to receive(:import_finished?).and_return(true)
|
||||
allow(project).to receive(:import_status).and_return('canceled')
|
||||
end
|
||||
|
||||
it 'emits snowplow metrics' do
|
||||
subject.track_finished_import
|
||||
it 'emits importer metrics' do
|
||||
expect(subject).to receive(:track_usage_event).with(:github_import_project_cancelled, project.id)
|
||||
|
||||
subject.track_canceled_import
|
||||
|
||||
expect_snowplow_event(
|
||||
category: :test_importer,
|
||||
action: 'create',
|
||||
label: 'github_import_project_state',
|
||||
project: project,
|
||||
extra: { import_type: 'github', state: 'completed' }
|
||||
extra: { import_type: 'github', state: 'canceled' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -704,7 +704,7 @@ project:
|
|||
- project_registry
|
||||
- packages
|
||||
- package_files
|
||||
- repository_files
|
||||
- rpm_repository_files
|
||||
- packages_cleanup_policy
|
||||
- alerting_setting
|
||||
- project_setting
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::ActivityMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Activity'),
|
||||
active_route: 'users#activity' do
|
||||
let(:link) { "/users/#{user.username}/activity" }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::ContributedProjectsMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Contributed projects'),
|
||||
active_route: 'users#contributed' do
|
||||
let(:link) { "/users/#{user.username}/contributed" }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::FollowersMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Followers'),
|
||||
active_route: 'users#followers' do
|
||||
let(:link) { "/users/#{user.username}/followers" }
|
||||
end
|
||||
|
||||
it_behaves_like 'Followers/followees counts', :followers
|
||||
end
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::FollowingMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Following'),
|
||||
active_route: 'users#following' do
|
||||
let(:link) { "/users/#{user.username}/following" }
|
||||
end
|
||||
|
||||
it_behaves_like 'Followers/followees counts', :followees
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::GroupsMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Groups'),
|
||||
active_route: 'users#groups' do
|
||||
let(:link) { "/users/#{user.username}/groups" }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::OverviewMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Overview'),
|
||||
active_route: 'users#show' do
|
||||
let(:link) { "/#{user.username}" }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::PersonalProjectsMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Personal projects'),
|
||||
active_route: 'users#projects' do
|
||||
let(:link) { "/users/#{user.username}/projects" }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::SnippetsMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Snippets'),
|
||||
active_route: 'users#snippets' do
|
||||
let(:link) { "/users/#{user.username}/snippets" }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Menus::StarredProjectsMenu, feature_category: :navigation do
|
||||
it_behaves_like 'User profile menu',
|
||||
title: s_('UserProfile|Starred projects'),
|
||||
active_route: 'users#starred' do
|
||||
let(:link) { "/users/#{user.username}/starred" }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Sidebars::UserProfile::Panel, feature_category: :navigation do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
|
||||
|
||||
subject { described_class.new(context) }
|
||||
|
||||
it 'implements #aria_label' do
|
||||
expect(subject.aria_label).to eq(s_('UserProfile|User profile navigation'))
|
||||
end
|
||||
|
||||
it 'implements #super_sidebar_context_header' do
|
||||
expect(subject.super_sidebar_context_header).to eq({
|
||||
title: user.name,
|
||||
avatar: user.avatar_url,
|
||||
avatar_shape: 'circle'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ContainerRegistry::DataRepairDetail, type: :model, feature_category: :container_registry do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
subject { described_class.new(project: project) }
|
||||
|
||||
it { is_expected.to belong_to(:project).required }
|
||||
end
|
||||
|
|
@ -137,6 +137,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
|
|||
it { is_expected.to have_many(:reviews).inverse_of(:project) }
|
||||
it { is_expected.to have_many(:packages).class_name('Packages::Package') }
|
||||
it { is_expected.to have_many(:package_files).class_name('Packages::PackageFile') }
|
||||
it { is_expected.to have_many(:rpm_repository_files).class_name('Packages::Rpm::RepositoryFile').inverse_of(:project).dependent(:destroy) }
|
||||
it { is_expected.to have_many(:debian_distributions).class_name('Packages::Debian::ProjectDistribution').dependent(:destroy) }
|
||||
it { is_expected.to have_one(:packages_cleanup_policy).class_name('Packages::Cleanup::Policy').inverse_of(:project) }
|
||||
it { is_expected.to have_many(:pipeline_artifacts).dependent(:restrict_with_error) }
|
||||
|
|
|
|||
|
|
@ -3042,6 +3042,26 @@ RSpec.describe ProjectPolicy, feature_category: :system_access do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'add_catalog_resource' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let(:current_user) { public_send(role) }
|
||||
|
||||
where(:role, :allowed) do
|
||||
:owner | true
|
||||
:maintainer | false
|
||||
:developer | false
|
||||
:reporter | false
|
||||
:guest | false
|
||||
end
|
||||
|
||||
with_them do
|
||||
it do
|
||||
expect(subject.can?(:add_catalog_resource)).to be(allowed)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'read_code' do
|
||||
let(:current_user) { create(:user) }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rubocop_spec_helper'
|
||||
require_relative '../../../../rubocop/cop/background_migration/missing_dictionary_file'
|
||||
|
||||
RSpec.describe RuboCop::Cop::BackgroundMigration::MissingDictionaryFile, feature_category: :database do
|
||||
let(:config) do
|
||||
RuboCop::Config.new(
|
||||
'BackgroundMigration/MissingDictionaryFile' => {
|
||||
'EnforcedSince' => 20230307160251
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
context 'for non post migrations' do
|
||||
before do
|
||||
allow(cop).to receive(:in_post_deployment_migration?).and_return(false)
|
||||
end
|
||||
|
||||
it 'does not throw any offense' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class QueueMyMigration < Gitlab::Database::Migration[2.1]
|
||||
MIGRATION = 'MyMigration'
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:users,
|
||||
:id
|
||||
)
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
context 'for post migrations' do
|
||||
before do
|
||||
allow(cop).to receive(:in_post_deployment_migration?).and_return(true)
|
||||
end
|
||||
|
||||
context 'without enqueuing batched migrations' do
|
||||
it 'does not throw any offense' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class CreateTestTable < Gitlab::Database::Migration[2.1]
|
||||
def change
|
||||
create_table(:tests)
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
context 'with enqueuing batched migration' do
|
||||
let(:rails_root) { File.expand_path('../../../..', __dir__) }
|
||||
let(:dictionary_file_path) { File.join(rails_root, 'db/docs/batched_background_migrations/my_migration.yml') }
|
||||
|
||||
context 'for migrations before enforced time' do
|
||||
before do
|
||||
allow(cop).to receive(:version).and_return(20230307160250)
|
||||
end
|
||||
|
||||
it 'does not throw any offenses' do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class QueueMyMigration < Gitlab::Database::Migration[2.1]
|
||||
MIGRATION = 'MyMigration'
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:users,
|
||||
:id
|
||||
)
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
|
||||
context 'for migrations after enforced time' do
|
||||
before do
|
||||
allow(cop).to receive(:version).and_return(20230307160252)
|
||||
end
|
||||
|
||||
it 'throws offense on not having the appropriate dictionary file with migration name as a constant' do
|
||||
expect_offense(<<~RUBY)
|
||||
class QueueMyMigration < Gitlab::Database::Migration[2.1]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format("Missing %{file_name}. Use the generator 'batched_background_migration' to create dictionary files automatically. For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator", file_name: dictionary_file_path)}
|
||||
MIGRATION = 'MyMigration'
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:users,
|
||||
:id
|
||||
)
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'throws offense on not having the appropriate dictionary file with migration name as a variable' do
|
||||
expect_offense(<<~RUBY)
|
||||
class QueueMyMigration < Gitlab::Database::Migration[2.1]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{format("Missing %{file_name}. Use the generator 'batched_background_migration' to create dictionary files automatically. For more details refer: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#generator", file_name: dictionary_file_path)}
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
'MyMigration',
|
||||
:users,
|
||||
:id
|
||||
)
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it 'does not throw offense with appropriate dictionary file' do
|
||||
expect(File).to receive(:exist?).with(dictionary_file_path).and_return(true)
|
||||
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class QueueMyMigration < Gitlab::Database::Migration[2.1]
|
||||
MIGRATION = 'MyMigration'
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:users,
|
||||
:id
|
||||
)
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::Catalog::AddResourceService, feature_category: :pipeline_composition do
|
||||
let_it_be(:project) { create(:project, :repository, description: 'Our components') }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let(:service) { described_class.new(project, user) }
|
||||
|
||||
describe '#execute' do
|
||||
context 'with an unauthorized user' do
|
||||
it 'raises an AccessDeniedError' do
|
||||
expect { service.execute }.to raise_error(Gitlab::Access::AccessDeniedError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an authorized user' do
|
||||
before do
|
||||
project.add_owner(user)
|
||||
end
|
||||
|
||||
context 'and a valid project' do
|
||||
it 'creates a catalog resource' do
|
||||
response = service.execute
|
||||
|
||||
expect(response.payload.project).to eq(project)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an invalid project' do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
it 'does not create a catalog resource' do
|
||||
response = service.execute
|
||||
|
||||
expect(response.message).to eq('Project must have a description')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an invalid catalog resource' do
|
||||
it 'does not save the catalog resource' do
|
||||
catalog_resource = instance_double(::Ci::Catalog::Resource,
|
||||
valid?: false,
|
||||
errors: instance_double(ActiveModel::Errors, full_messages: ['not valid']))
|
||||
allow(::Ci::Catalog::Resource).to receive(:new).and_return(catalog_resource)
|
||||
|
||||
response = service.execute
|
||||
|
||||
expect(response.message).to eq('not valid')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::Catalog::ValidateResourceService, feature_category: :pipeline_composition do
|
||||
describe '#execute' do
|
||||
context 'with a project that has a README and a description' do
|
||||
it 'is valid' do
|
||||
project = create(:project, :repository, description: 'Component project')
|
||||
response = described_class.new(project, project.default_branch).execute
|
||||
|
||||
expect(response).to be_success
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a project that has neither a description nor a README' do
|
||||
it 'is not valid' do
|
||||
project = create(:project, :empty_repo)
|
||||
project.repository.create_file(
|
||||
project.creator,
|
||||
'ruby.rb',
|
||||
'I like this',
|
||||
message: 'Ruby like this',
|
||||
branch_name: 'master'
|
||||
)
|
||||
response = described_class.new(project, project.default_branch).execute
|
||||
|
||||
expect(response.message).to eq('Project must have a README , Project must have a description')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a project that has a description but not a README' do
|
||||
it 'is not valid' do
|
||||
project = create(:project, :empty_repo, description: 'project with no README')
|
||||
project.repository.create_file(
|
||||
project.creator,
|
||||
'text.txt',
|
||||
'I do not like this',
|
||||
message: 'only text like text',
|
||||
branch_name: 'master'
|
||||
)
|
||||
response = described_class.new(project, project.default_branch).execute
|
||||
|
||||
expect(response.message).to eq('Project must have a README')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a project that has a README and not a description' do
|
||||
it 'is not valid' do
|
||||
project = create(:project, :repository)
|
||||
response = described_class.new(project, project.default_branch).execute
|
||||
|
||||
expect(response.message).to eq('Project must have a description')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -22,7 +22,7 @@ RSpec.describe Import::Github::CancelProjectImportService, feature_category: :im
|
|||
.to receive(:new)
|
||||
.with(:github_importer, project)
|
||||
.and_return(metrics_double)
|
||||
expect(metrics_double).to receive(:track_import_state)
|
||||
expect(metrics_double).to receive(:track_canceled_import)
|
||||
|
||||
import_cancel.execute
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1575,7 +1575,6 @@
|
|||
- './ee/spec/lib/omni_auth/strategies/group_saml_spec.rb'
|
||||
- './ee/spec/lib/omni_auth/strategies/kerberos_spec.rb'
|
||||
- './ee/spec/lib/peek/views/elasticsearch_spec.rb'
|
||||
- './ee/spec/lib/sidebars/groups/menus/administration_menu_spec.rb'
|
||||
- './ee/spec/lib/sidebars/groups/menus/analytics_menu_spec.rb'
|
||||
- './ee/spec/lib/sidebars/groups/menus/epics_menu_spec.rb'
|
||||
- './ee/spec/lib/sidebars/groups/menus/security_compliance_menu_spec.rb'
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ RSpec.shared_context 'group navbar structure' do
|
|||
_('CI/CD'),
|
||||
_('Applications'),
|
||||
_('Packages and registries'),
|
||||
s_('UsageQuota|Usage Quotas'),
|
||||
_('Domain Verification')
|
||||
]
|
||||
}
|
||||
|
|
@ -154,15 +155,6 @@ RSpec.shared_context 'group navbar structure' do
|
|||
}
|
||||
end
|
||||
|
||||
let(:administration_nav_item) do
|
||||
{
|
||||
nav_item: _('Administration'),
|
||||
nav_sub_items: [
|
||||
s_('UsageQuota|Usage Quotas')
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
let(:security_and_compliance_nav_item) do
|
||||
{
|
||||
nav_item: _('Security and Compliance'),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'User profile menu' do |title:, active_route:|
|
||||
let_it_be(:current_user) { build(:user) }
|
||||
let_it_be(:user) { build(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
|
||||
|
||||
subject { described_class.new(context) }
|
||||
|
||||
it 'does not contain any sub menu' do
|
||||
expect(subject.has_items?).to be false
|
||||
end
|
||||
|
||||
it 'renders the correct link' do
|
||||
expect(subject.link).to match link
|
||||
end
|
||||
|
||||
it 'renders the correct title' do
|
||||
expect(subject.title).to eq title
|
||||
end
|
||||
|
||||
it 'defines correct active route' do
|
||||
expect(subject.active_routes[:path]).to be active_route
|
||||
end
|
||||
|
||||
it 'renders if user is logged in' do
|
||||
expect(subject.render?).to be true
|
||||
end
|
||||
|
||||
[:blocked, :banned].each do |trait|
|
||||
context "when viewed user is #{trait}" do
|
||||
let_it_be(:viewed_user) { build(:user, trait) }
|
||||
let(:context) { Sidebars::Context.new(current_user: user, container: viewed_user) }
|
||||
|
||||
context 'when user is not logged in' do
|
||||
it 'is not allowed to view the menu item' do
|
||||
expect(described_class.new(Sidebars::Context.new(current_user: nil,
|
||||
container: viewed_user)).render?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user has permission' do
|
||||
before do
|
||||
allow(Ability).to receive(:allowed?).with(user, :read_user_profile, viewed_user).and_return(true)
|
||||
end
|
||||
|
||||
it 'is allowed to view the menu item' do
|
||||
expect(described_class.new(context).render?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user does not have permission' do
|
||||
it 'is not allowed to view the menu item' do
|
||||
expect(described_class.new(context).render?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'Followers/followees counts' do |symbol|
|
||||
let_it_be(:current_user) { build(:user) }
|
||||
let_it_be(:user) { build(:user) }
|
||||
|
||||
let(:context) { Sidebars::Context.new(current_user: current_user, container: user) }
|
||||
|
||||
subject { described_class.new(context) }
|
||||
|
||||
context 'when there are items' do
|
||||
before do
|
||||
allow(user).to receive(symbol).and_return([1, 2])
|
||||
end
|
||||
|
||||
it 'renders the pill' do
|
||||
expect(subject.has_pill?).to be(true)
|
||||
end
|
||||
|
||||
it 'returns the count' do
|
||||
expect(subject.pill_count).to be(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are no items' do
|
||||
it 'does not render the pill' do
|
||||
expect(subject.has_pill?).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
33
yarn.lock
33
yarn.lock
|
|
@ -1157,10 +1157,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.11.tgz#9be796d93ae27b636da32d960899a4912bca27a1"
|
||||
integrity sha512-N9vXqLP3eRL8BqSy8yn4Y98cZI2pZ8fyuHx6lKjiG2WABpT2l01TXdzq5Ma2ZUBzfB7tx5dXVhge8X9u0S70ZQ==
|
||||
|
||||
"@eslint/eslintrc@^1.4.1":
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e"
|
||||
integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==
|
||||
"@eslint/eslintrc@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.0.tgz#943309d8697c52fc82c076e90c1c74fbbe69dbff"
|
||||
integrity sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.3.2"
|
||||
|
|
@ -1172,6 +1172,11 @@
|
|||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@8.35.0":
|
||||
version "8.35.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7"
|
||||
integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==
|
||||
|
||||
"@gitlab/at.js@1.5.7":
|
||||
version "1.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e"
|
||||
|
|
@ -5664,12 +5669,13 @@ eslint-visitor-keys@^3.3.0:
|
|||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
|
||||
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
|
||||
|
||||
eslint@8.34.0:
|
||||
version "8.34.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6"
|
||||
integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==
|
||||
eslint@8.35.0:
|
||||
version "8.35.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.35.0.tgz#fffad7c7e326bae606f0e8f436a6158566d42323"
|
||||
integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==
|
||||
dependencies:
|
||||
"@eslint/eslintrc" "^1.4.1"
|
||||
"@eslint/eslintrc" "^2.0.0"
|
||||
"@eslint/js" "8.35.0"
|
||||
"@humanwhocodes/config-array" "^0.11.8"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@nodelib/fs.walk" "^1.2.8"
|
||||
|
|
@ -5683,7 +5689,7 @@ eslint@8.34.0:
|
|||
eslint-utils "^3.0.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
espree "^9.4.0"
|
||||
esquery "^1.4.0"
|
||||
esquery "^1.4.2"
|
||||
esutils "^2.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
file-entry-cache "^6.0.1"
|
||||
|
|
@ -5730,6 +5736,13 @@ esquery@^1.4.0:
|
|||
dependencies:
|
||||
estraverse "^5.1.0"
|
||||
|
||||
esquery@^1.4.2:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
|
||||
integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
|
||||
dependencies:
|
||||
estraverse "^5.1.0"
|
||||
|
||||
esrecurse@^4.1.0, esrecurse@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
|
||||
|
|
|
|||
Loading…
Reference in New Issue