Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
804348d39b
commit
c69e4aa48c
|
|
@ -317,7 +317,6 @@ Layout/LineLength:
|
|||
- 'app/models/concerns/packages/debian/distribution.rb'
|
||||
- 'app/models/concerns/packages/debian/distribution_key.rb'
|
||||
- 'app/models/concerns/partitioned_table.rb'
|
||||
- 'app/models/concerns/protected_ref.rb'
|
||||
- 'app/models/concerns/redis_cacheable.rb'
|
||||
- 'app/models/concerns/restricted_signup.rb'
|
||||
- 'app/models/concerns/shardable.rb'
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -184,7 +184,7 @@ gem 'elasticsearch-rails', '~> 7.2', require: 'elasticsearch/rails/instrumentati
|
|||
gem 'elasticsearch-api', '7.13.3'
|
||||
gem 'aws-sdk-core', '~> 3.178.0'
|
||||
gem 'aws-sdk-cloudformation', '~> 1'
|
||||
gem 'aws-sdk-s3', '~> 1.129.0'
|
||||
gem 'aws-sdk-s3', '~> 1.130.0'
|
||||
gem 'faraday_middleware-aws-sigv4', '~>0.3.0'
|
||||
gem 'typhoeus', '~> 1.4.0' # Used with Elasticsearch to support http keep-alive connections
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
{"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"},
|
||||
{"name":"aws-sdk-core","version":"3.178.0","platform":"ruby","checksum":"192485a032536ff8c8eb037f1204b432129a612f4de13e36c0d2cf0dec8165cb"},
|
||||
{"name":"aws-sdk-kms","version":"1.64.0","platform":"ruby","checksum":"40de596c95047bfc6e1aacea24f3df6241aa716b6f7ce08ac4c5f7e3120395ad"},
|
||||
{"name":"aws-sdk-s3","version":"1.129.0","platform":"ruby","checksum":"82b8eab53d22754e5855dbec3e7a9a53c348de2bbf202774b4483f9b06cb0f1a"},
|
||||
{"name":"aws-sdk-s3","version":"1.130.0","platform":"ruby","checksum":"80ac391ede15dcc62f1ada2fec12719a22148cf64ef76e5ec929558bb936c72a"},
|
||||
{"name":"aws-sigv4","version":"1.6.0","platform":"ruby","checksum":"ca9e6a15cd424f1f32b524b9760995331459bc22e67d3daad4fcf0c0084b087d"},
|
||||
{"name":"axe-core-api","version":"4.6.0","platform":"ruby","checksum":"1b0ddec3353f108dc10363baf2282f43a5ff7f13d4e25f99071294e78f8a6c62"},
|
||||
{"name":"axe-core-rspec","version":"4.6.0","platform":"ruby","checksum":"11c25bc9dd388c137ba4e5e63d64d20092bf22c884d8ffc829a22acfbacd747f"},
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ GEM
|
|||
aws-sdk-kms (1.64.0)
|
||||
aws-sdk-core (~> 3, >= 3.165.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.129.0)
|
||||
aws-sdk-s3 (1.130.0)
|
||||
aws-sdk-core (~> 3, >= 3.177.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.6)
|
||||
|
|
@ -1740,7 +1740,7 @@ DEPENDENCIES
|
|||
awesome_print
|
||||
aws-sdk-cloudformation (~> 1)
|
||||
aws-sdk-core (~> 3.178.0)
|
||||
aws-sdk-s3 (~> 1.129.0)
|
||||
aws-sdk-s3 (~> 1.130.0)
|
||||
axe-core-rspec
|
||||
babosa (~> 2.0)
|
||||
base32 (~> 0.3.0)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ $search-input-field-x-min-width: 200px;
|
|||
min-height: $header-height;
|
||||
border: 0;
|
||||
position: fixed;
|
||||
top: $calc-application-bars-height;
|
||||
top: $calc-system-headers-height;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-radius: 0;
|
||||
|
|
@ -322,7 +322,7 @@ $search-input-field-x-min-width: 200px;
|
|||
left: var(--application-bar-left);
|
||||
position: fixed;
|
||||
right: var(--application-bar-right);
|
||||
top: $calc-application-bars-height;
|
||||
top: $calc-system-headers-height;
|
||||
width: auto;
|
||||
z-index: $top-bar-z-index;
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ body {
|
|||
}
|
||||
|
||||
.layout-page {
|
||||
padding-top: calc(#{$header-height} + #{$calc-application-bars-height});
|
||||
padding-top: $calc-application-bars-height;
|
||||
padding-bottom: $calc-application-footer-height;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@
|
|||
.right-sidebar {
|
||||
&:not(.right-sidebar-merge-requests) {
|
||||
@include right-sidebar;
|
||||
top: calc(#{$header-height} + #{$calc-application-bars-height});
|
||||
top: $calc-application-bars-height;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
z-index: 251;
|
||||
|
|
@ -327,7 +327,7 @@
|
|||
&.right-sidebar-merge-requests {
|
||||
@include media-breakpoint-down(md) {
|
||||
@include right-sidebar;
|
||||
top: calc(#{$header-height} + #{$calc-application-bars-height});
|
||||
top: $calc-application-bars-height;
|
||||
z-index: 251;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
|
|||
}
|
||||
|
||||
.super-sidebar-skip-to {
|
||||
top: calc(#{$header-height} + #{$calc-application-bars-height});
|
||||
top: $calc-application-bars-height;
|
||||
width: calc(#{$super-sidebar-width} - #{$gl-spacing-scale-5});
|
||||
z-index: $super-sidebar-skip-to-z-index;
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ $super-sidebar-transition-hint-duration: $super-sidebar-transition-duration / 4;
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
top: calc(#{$header-height} + #{$calc-application-bars-height});
|
||||
top: $calc-application-bars-height;
|
||||
bottom: $calc-application-footer-height;
|
||||
left: 0;
|
||||
background-color: var(--gray-10, $gray-10);
|
||||
|
|
|
|||
|
|
@ -502,8 +502,9 @@ $pages-group-name-color: #4c4e54;
|
|||
/*
|
||||
* Calculated heights
|
||||
*/
|
||||
$calc-application-bars-height: calc(var(--system-header-height) + var(--performance-bar-height));
|
||||
$calc-application-header-height: calc(#{$header-height} + #{$calc-application-bars-height} + var(--top-bar-height));
|
||||
$calc-system-headers-height: calc(var(--system-header-height) + var(--performance-bar-height));
|
||||
$calc-application-bars-height: calc(#{$header-height} + #{$calc-system-headers-height});
|
||||
$calc-application-header-height: calc(#{$calc-application-bars-height} + var(--top-bar-height));
|
||||
$calc-application-footer-height: var(--system-footer-height);
|
||||
$calc-application-viewport-height: calc(100vh - #{$calc-application-header-height} - #{$calc-application-footer-height});
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
// Override Bootstrap class with offset for system-header and
|
||||
// performance bar when present
|
||||
.fixed-top {
|
||||
top: $calc-application-bars-height;
|
||||
top: $calc-system-headers-height;
|
||||
}
|
||||
|
||||
.gl-children-ml-sm-3 > * {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ class EventsFinder
|
|||
def by_current_user_access(events)
|
||||
events.merge(Project.public_or_visible_to_user(current_user))
|
||||
.joins(:project)
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417462")
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ module Issuables
|
|||
def filter(issuables)
|
||||
filtered = by_assignee(issuables)
|
||||
filtered = by_assignee_union(filtered)
|
||||
# Cross Joins Fails tests in bin/rspec spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
|
||||
filtered = filtered.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417462")
|
||||
by_negated_assignee(filtered)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -90,8 +90,10 @@ class MembersFinder
|
|||
|
||||
# enumerate the columns here since we are enumerating them in the union and want to be immune to
|
||||
# column caching issues when adding/removing columns
|
||||
Member.select(*Member.column_names)
|
||||
members = Member.select(*Member.column_names)
|
||||
.includes(:user).from([Arel.sql("(#{sql}) AS #{Member.table_name}")]) # rubocop: disable CodeReuse/ActiveRecord
|
||||
# The left join with the table users in the method distinct_on needs to be resolved
|
||||
members.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
|
||||
end
|
||||
|
||||
def distinct_on(union)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ class MergeRequestsFinder < IssuableFinder
|
|||
items = by_deployments(items)
|
||||
items = by_reviewer(items)
|
||||
items = by_source_project_id(items)
|
||||
items = items.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417462")
|
||||
|
||||
by_approved(items)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module IssueAvailableFeatures
|
|||
end
|
||||
|
||||
included do
|
||||
scope :with_feature, ->(feature) { where(issue_type: available_features_for_issue_types[feature]) }
|
||||
scope :with_feature, ->(feature) { with_issue_type(available_features_for_issue_types[feature]) }
|
||||
end
|
||||
|
||||
def issue_type_supports?(feature)
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# TODO: Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/402699
|
||||
module Issues
|
||||
module ForbidIssueTypeColumnUsage
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
ForbiddenColumnUsed = Class.new(StandardError)
|
||||
|
||||
included do
|
||||
WorkItems::Type.base_types.each do |base_type, _value|
|
||||
define_method "#{base_type}?".to_sym do
|
||||
error_message = <<~ERROR
|
||||
`#{model_name.element}.#{base_type}?` uses the `issue_type` column underneath. As we want to remove the column,
|
||||
its usage is forbidden. You should use the `work_item_types` table instead.
|
||||
|
||||
# Before
|
||||
|
||||
#{model_name.element}.#{base_type}? => true
|
||||
|
||||
# After
|
||||
|
||||
#{model_name.element}.work_item_type.#{base_type}? => true
|
||||
|
||||
More details in https://gitlab.com/groups/gitlab-org/-/epics/10529
|
||||
ERROR
|
||||
|
||||
raise ForbiddenColumnUsed, error_message
|
||||
end
|
||||
|
||||
define_singleton_method base_type.to_sym do
|
||||
error = ForbiddenColumnUsed.new(
|
||||
<<~ERROR
|
||||
`#{name}.#{base_type}` uses the `issue_type` column underneath. As we want to remove the column,
|
||||
its usage is forbidden. You should use the `work_item_types` table instead.
|
||||
|
||||
# Before
|
||||
|
||||
#{name}.#{base_type}
|
||||
|
||||
# After
|
||||
|
||||
#{name}.with_issue_type(:#{base_type})
|
||||
|
||||
More details in https://gitlab.com/groups/gitlab-org/-/epics/10529
|
||||
ERROR
|
||||
)
|
||||
|
||||
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
|
||||
error,
|
||||
method_name: "#{name}.#{base_type}"
|
||||
)
|
||||
|
||||
with_issue_type(base_type.to_sym)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -51,6 +51,7 @@ module Milestoneish
|
|||
def issue_participants_visible_by_user(user)
|
||||
User.joins(:issue_assignees)
|
||||
.where('issue_assignees.issue_id' => issues_visible_to_user(user).select(:id))
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417457")
|
||||
.distinct
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,12 @@ module ProtectedRef
|
|||
# to fail.
|
||||
has_many :"#{type}_access_levels", inverse_of: self.model_name.singular
|
||||
|
||||
validates :"#{type}_access_levels", length: { is: 1, message: "are restricted to a single instance per #{self.model_name.human}." }, unless: -> { allow_multiple?(type) }
|
||||
validates :"#{type}_access_levels",
|
||||
length: {
|
||||
is: 1,
|
||||
message: "are restricted to a single instance per #{self.model_name.human}."
|
||||
},
|
||||
unless: -> { allow_multiple?(type) }
|
||||
|
||||
accepts_nested_attributes_for :"#{type}_access_levels", allow_destroy: true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -38,7 +38,14 @@ module ProtectedRefAccess
|
|||
included do
|
||||
scope :maintainer, -> { where(access_level: Gitlab::Access::MAINTAINER) }
|
||||
scope :developer, -> { where(access_level: Gitlab::Access::DEVELOPER) }
|
||||
scope :for_role, -> { non_role_types.present? ? where.missing(*non_role_types) : all }
|
||||
scope :for_role, -> {
|
||||
if non_role_types.present?
|
||||
where.missing(*non_role_types)
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417457")
|
||||
else
|
||||
all
|
||||
end
|
||||
}
|
||||
|
||||
protected_ref_fk = "#{module_parent.model_name.singular}_id"
|
||||
validates :access_level,
|
||||
|
|
|
|||
|
|
@ -510,7 +510,9 @@ class Group < Namespace
|
|||
members_with_parents(only_active_users: false)
|
||||
end
|
||||
|
||||
members_from_hiearchy.all_owners.left_outer_joins(:user).merge(User.without_project_bot)
|
||||
members_from_hiearchy.all_owners.left_outer_joins(:user)
|
||||
.merge(User.without_project_bot)
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455")
|
||||
end
|
||||
|
||||
def ldap_synced?
|
||||
|
|
@ -694,7 +696,7 @@ class Group < Namespace
|
|||
.where(id: direct_and_indirect_members_with_inactive.select(:user_id))
|
||||
.reorder(nil),
|
||||
project_users_with_descendants
|
||||
])
|
||||
]).allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455") # failed in spec/tasks/gitlab/user_management_rake_spec.rb
|
||||
end
|
||||
|
||||
def users_count
|
||||
|
|
@ -707,6 +709,7 @@ class Group < Namespace
|
|||
User
|
||||
.joins(projects: :group)
|
||||
.where(namespaces: { id: self_and_descendants.select(:id) })
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455")
|
||||
end
|
||||
|
||||
# Return the highest access level for a user
|
||||
|
|
@ -973,12 +976,14 @@ class Group < Namespace
|
|||
end
|
||||
|
||||
def max_member_access(user_ids)
|
||||
Gitlab::SafeRequestLoader.execute(
|
||||
resource_key: max_member_access_for_resource_key(User),
|
||||
resource_ids: user_ids,
|
||||
default_value: Gitlab::Access::NO_ACCESS
|
||||
) do |user_ids|
|
||||
members_with_parents.where(user_id: user_ids).group(:user_id).maximum(:access_level)
|
||||
::Gitlab::Database.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455") do
|
||||
Gitlab::SafeRequestLoader.execute(
|
||||
resource_key: max_member_access_for_resource_key(User),
|
||||
resource_ids: user_ids,
|
||||
default_value: Gitlab::Access::NO_ACCESS
|
||||
) do |user_ids|
|
||||
members_with_parents.where(user_id: user_ids).group(:user_id).maximum(:access_level)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ class Issue < ApplicationRecord
|
|||
# This default came from the enum `issue_type` column. Defined as default in the DB
|
||||
DEFAULT_ISSUE_TYPE = :issue
|
||||
|
||||
ignore_column :issue_type, remove_with: '16.4', remove_after: '2023-08-22'
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :namespace, inverse_of: :issues
|
||||
|
||||
|
|
@ -133,12 +135,6 @@ class Issue < ApplicationRecord
|
|||
validate :allowed_work_item_type_change, on: :update, if: :work_item_type_id_changed?
|
||||
validate :due_date_after_start_date
|
||||
validate :parent_link_confidentiality
|
||||
# using a custom validation since we are overwriting the `issue_type` method to use the work_item_types table
|
||||
validate :issue_type_attribute_present
|
||||
|
||||
enum issue_type: WorkItems::Type.base_types
|
||||
# TODO: Remove with https://gitlab.com/gitlab-org/gitlab/-/issues/402699
|
||||
include ::Issues::ForbidIssueTypeColumnUsage
|
||||
|
||||
alias_method :issuing_parent, :project
|
||||
alias_attribute :issuing_parent_id, :project_id
|
||||
|
|
@ -254,7 +250,6 @@ class Issue < ApplicationRecord
|
|||
scope :with_projects_matching_search_data, -> { where('issue_search_data.project_id = issues.project_id') }
|
||||
|
||||
before_validation :ensure_namespace_id, :ensure_work_item_type
|
||||
before_save :check_issue_type_in_sync!
|
||||
|
||||
after_save :ensure_metrics!, unless: :importing?
|
||||
after_commit :expire_etag_cache, unless: :importing?
|
||||
|
|
@ -760,40 +755,6 @@ class Issue < ApplicationRecord
|
|||
|
||||
private
|
||||
|
||||
def check_issue_type_in_sync!
|
||||
# We might have existing records out of sync, so we need to skip this check unless the value is changed
|
||||
# so those records can still be updated until we fix them and remove the issue_type column
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/work_items/403158
|
||||
return unless (changes.keys & %w[issue_type work_item_type_id]).any?
|
||||
|
||||
# Do not replace the use of attributes with `issue_type` here
|
||||
if attributes['issue_type'] != work_item_type.base_type
|
||||
error = IssueTypeOutOfSyncError.new(
|
||||
<<~ERROR
|
||||
Issue `issue_type` out of sync with `work_item_type_id` column.
|
||||
`issue_type` must be equal to `work_item.base_type`.
|
||||
You can assign the correct work_item_type like this for example:
|
||||
|
||||
Issue.new(issue_type: :incident, work_item_type: WorkItems::Type.default_by_type(:incident))
|
||||
|
||||
More details in https://gitlab.com/gitlab-org/gitlab/-/issues/338005
|
||||
ERROR
|
||||
)
|
||||
|
||||
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
|
||||
error,
|
||||
issue_type: attributes['issue_type'],
|
||||
work_item_type_id: work_item_type_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def issue_type_attribute_present
|
||||
return if attributes['issue_type'].present?
|
||||
|
||||
errors.add(:issue_type, 'Must be present')
|
||||
end
|
||||
|
||||
def due_date_after_start_date
|
||||
return unless start_date.present? && due_date.present?
|
||||
|
||||
|
|
@ -854,9 +815,7 @@ class Issue < ApplicationRecord
|
|||
def ensure_work_item_type
|
||||
return if work_item_type_id.present? || work_item_type_id_change&.last.present?
|
||||
|
||||
# TODO: We should switch to DEFAULT_ISSUE_TYPE here when the issue_type column is dropped
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/work_items/402700
|
||||
self.work_item_type = WorkItems::Type.default_by_type(attributes['issue_type'])
|
||||
self.work_item_type = WorkItems::Type.default_by_type(DEFAULT_ISSUE_TYPE)
|
||||
end
|
||||
|
||||
def allowed_work_item_type_change
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class Member < ApplicationRecord
|
|||
scope :with_invited_user_state, -> do
|
||||
joins('LEFT JOIN users as invited_user ON invited_user.email = members.invite_email')
|
||||
.select('members.*', 'invited_user.state as invited_user_state')
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
|
||||
end
|
||||
|
||||
scope :in_hierarchy, ->(source) do
|
||||
|
|
@ -174,7 +175,10 @@ class Member < ApplicationRecord
|
|||
scope :by_access_level, -> (access_level) { active.where(access_level: access_level) }
|
||||
scope :all_by_access_level, -> (access_level) { where(access_level: access_level) }
|
||||
|
||||
scope :preload_user_and_notification_settings, -> { preload(user: :notification_settings) }
|
||||
scope :preload_user_and_notification_settings, -> do
|
||||
preload(user: :notification_settings)
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
|
||||
end
|
||||
|
||||
scope :with_source_id, ->(source_id) { where(source_id: source_id) }
|
||||
scope :including_source, -> { includes(:source) }
|
||||
|
|
@ -288,7 +292,9 @@ class Member < ApplicationRecord
|
|||
|
||||
class << self
|
||||
def search(query)
|
||||
scope = joins(:user).merge(User.search(query, use_minimum_char_limit: false))
|
||||
scope = joins(:user)
|
||||
.merge(User.search(query, use_minimum_char_limit: false))
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
|
||||
|
||||
return scope unless Gitlab::Pagination::Keyset::Order.keyset_aware?(scope)
|
||||
|
||||
|
|
@ -347,6 +353,7 @@ class Member < ApplicationRecord
|
|||
|
||||
def left_join_users
|
||||
left_outer_joins(:user)
|
||||
.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
|
||||
end
|
||||
|
||||
def access_for_user_ids(user_ids)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
|
|||
[
|
||||
commits_anchor_data,
|
||||
branches_anchor_data,
|
||||
terraform_states_anchor_data,
|
||||
tags_anchor_data,
|
||||
storage_anchor_data,
|
||||
releases_anchor_data,
|
||||
|
|
@ -236,6 +237,21 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
|
|||
)
|
||||
end
|
||||
|
||||
def terraform_states_anchor_data
|
||||
if project.terraform_states.exists? && can_read_terraform_state?
|
||||
AnchorData.new(
|
||||
true,
|
||||
statistic_icon('terraform') +
|
||||
n_('%{strong_start}%{terraform_states_count}%{strong_end} Terraform State', '%{strong_start}%{terraform_states_count}%{strong_end} Terraform States', project.terraform_states.count).html_safe % {
|
||||
terraform_states_count: number_with_delimiter(project.terraform_states.count),
|
||||
strong_start: '<strong class="project-stat-value">'.html_safe,
|
||||
strong_end: '</strong>'.html_safe
|
||||
},
|
||||
project_terraform_index_path(project)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def tags_anchor_data
|
||||
AnchorData.new(
|
||||
true,
|
||||
|
|
@ -488,6 +504,10 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
|
|||
end
|
||||
end
|
||||
|
||||
def can_read_terraform_state?
|
||||
current_user && can?(current_user, :read_terraform_state, project)
|
||||
end
|
||||
|
||||
# Avoid including ActionView::Helpers::UrlHelper
|
||||
def content_tag(...)
|
||||
ActionController::Base.helpers.content_tag(...)
|
||||
|
|
|
|||
|
|
@ -13,14 +13,17 @@ module Boards
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def metadata(required_fields = [:issue_count, :total_issue_weight])
|
||||
fields = metadata_fields(required_fields)
|
||||
keys = fields.keys
|
||||
# TODO: eliminate need for SQL literal fragment
|
||||
columns = Arel.sql(fields.values_at(*keys).join(', '))
|
||||
results = item_model.where(id: collection_ids)
|
||||
results = results.select(columns)
|
||||
# Failing tests in spec/requests/api/graphql/boards/board_lists_query_spec.rb
|
||||
::Gitlab::Database.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417465") do
|
||||
fields = metadata_fields(required_fields)
|
||||
keys = fields.keys
|
||||
# TODO: eliminate need for SQL literal fragment
|
||||
columns = Arel.sql(fields.values_at(*keys).join(', '))
|
||||
results = item_model.where(id: collection_ids)
|
||||
results = results.select(columns)
|
||||
|
||||
Hash[keys.zip(results.pluck(columns).flatten)]
|
||||
Hash[keys.zip(results.pluck(columns).flatten)]
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
|||
|
|
@ -83,18 +83,17 @@ module Issues
|
|||
params.delete(:work_item_type)
|
||||
end
|
||||
|
||||
base_type = work_item_type&.base_type
|
||||
# We need to support the legacy input params[:issue_type] even if we don't have the issue_type column anymore.
|
||||
# In the future only params[:work_item_type] should be provided
|
||||
base_type = work_item_type&.base_type || params[:issue_type]
|
||||
|
||||
if create_issue_type_allowed?(container, base_type)
|
||||
issue.work_item_type = work_item_type
|
||||
# Up to this point issue_type might be set to the default, so we need to sync if a work item type is provided
|
||||
issue.issue_type = base_type
|
||||
else
|
||||
# If no work item type was provided or not allowed, we need to set it to issue_type,
|
||||
# and that includes the column default
|
||||
issue_type = issue_params[:issue_type] || ::Issue::DEFAULT_ISSUE_TYPE
|
||||
issue.work_item_type = WorkItems::Type.default_by_type(issue_type)
|
||||
end
|
||||
issue.work_item_type = if create_issue_type_allowed?(container, base_type)
|
||||
work_item_type || WorkItems::Type.default_by_type(base_type)
|
||||
else
|
||||
# If no work item type was provided or not allowed, we need to set it to
|
||||
# the default issue_type
|
||||
WorkItems::Type.default_by_type(::Issue::DEFAULT_ISSUE_TYPE)
|
||||
end
|
||||
end
|
||||
|
||||
def model_klass
|
||||
|
|
@ -109,8 +108,6 @@ module Issues
|
|||
:confidential
|
||||
]
|
||||
|
||||
public_issue_params << :issue_type if create_issue_type_allowed?(container, params[:issue_type])
|
||||
|
||||
params.slice(*public_issue_params)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -32,10 +32,9 @@ module Issues
|
|||
end
|
||||
|
||||
def change_work_item_type(issue)
|
||||
return unless issue.changed_attributes['issue_type']
|
||||
return unless params[:issue_type].present?
|
||||
|
||||
issue_type = params[:issue_type] || ::Issue::DEFAULT_ISSUE_TYPE
|
||||
type_id = find_work_item_type_id(issue_type)
|
||||
type_id = find_work_item_type_id(params[:issue_type])
|
||||
|
||||
issue.work_item_type_id = type_id
|
||||
end
|
||||
|
|
@ -180,16 +179,22 @@ module Issues
|
|||
end
|
||||
|
||||
def handle_issue_type_change(issue)
|
||||
return unless issue.previous_changes.include?('issue_type')
|
||||
return unless issue.previous_changes.include?('work_item_type_id')
|
||||
|
||||
do_handle_issue_type_change(issue)
|
||||
end
|
||||
|
||||
def do_handle_issue_type_change(issue)
|
||||
SystemNoteService.change_issue_type(issue, current_user, issue.issue_type_before_last_save)
|
||||
old_work_item_type = ::WorkItems::Type.find(issue.work_item_type_id_before_last_save).base_type
|
||||
SystemNoteService.change_issue_type(issue, current_user, old_work_item_type)
|
||||
|
||||
::IncidentManagement::IssuableEscalationStatuses::CreateService.new(issue).execute if issue.supports_escalation?
|
||||
end
|
||||
|
||||
override :allowed_update_params
|
||||
def allowed_update_params(params)
|
||||
super.except(:issue_type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
.bs-callout.clearfix
|
||||
%p
|
||||
= s_("Cohorts|User cohorts are shown for the last %{months_included} months. Only users with activity are counted in the 'New users' column; inactive users are counted separately.") % { months_included: @cohorts[:months_included] }
|
||||
= link_to sprite_icon('question-o'), help_page_path('user/admin_area/user_cohorts', anchor: 'cohorts'), title: 'About this feature', target: '_blank', rel: 'noopener noreferrer'
|
||||
= link_to sprite_icon('question-o'), help_page_path('administration/user_cohorts', anchor: 'cohorts'), title: 'About this feature', target: '_blank', rel: 'noopener noreferrer'
|
||||
|
||||
.table-holder.d-xl-table
|
||||
%table.table
|
||||
|
|
|
|||
|
|
@ -3,9 +3,6 @@ description: Schema for all Cell-local tables, ex. namespaces, projects, etc.
|
|||
allow_cross_joins:
|
||||
- gitlab_shared
|
||||
- gitlab_main
|
||||
# Temporarily allow cross-joins between clusterwide and cell schemas
|
||||
# This is to be removed once we annotate all cross-joins between those
|
||||
- gitlab_main_clusterwide
|
||||
allow_cross_transactions:
|
||||
- gitlab_internal
|
||||
- gitlab_shared
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
stage: Anti-Abuse
|
||||
group: Anti-Abuse
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
type: reference, howto
|
||||
---
|
||||
|
||||
# Review abuse reports **(FREE SELF)**
|
||||
|
||||
View and resolve abuse reports from GitLab users.
|
||||
|
||||
GitLab administrators can view and [resolve](#resolving-abuse-reports) abuse
|
||||
reports in the Admin Area.
|
||||
|
||||
## Receive notification of abuse reports by email
|
||||
|
||||
To receive notifications of new abuse reports by email:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
1. Select **Admin Area**.
|
||||
1. Select **Settings > Reporting**.
|
||||
1. Expand the **Abuse reports** section.
|
||||
1. Provide an email address and select **Save changes**.
|
||||
|
||||
The notification email address can also be set and retrieved
|
||||
[using the API](../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
|
||||
|
||||
## Reporting abuse
|
||||
|
||||
To find out more about reporting abuse, see
|
||||
[abuse reports user documentation](../user/report_abuse.md).
|
||||
|
||||
## Resolving abuse reports
|
||||
|
||||
To access abuse reports:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
1. Select **Admin Area**.
|
||||
1. Select **Abuse Reports**.
|
||||
|
||||
There are 3 ways to resolve an abuse report, with a button for each method:
|
||||
|
||||
- Remove user & report. This:
|
||||
- [Deletes the reported user](../user/profile/account/delete_account.md) from the
|
||||
instance.
|
||||
- Removes the abuse report from the list.
|
||||
- [Block user](#blocking-users).
|
||||
- Remove report. This:
|
||||
- Removes the abuse report from the list.
|
||||
- Removes access restrictions for the reported user.
|
||||
|
||||
The following is an example of the **Abuse Reports** page:
|
||||
|
||||

|
||||
|
||||
### Blocking users
|
||||
|
||||
A blocked user cannot sign in or access any repositories, but all of their data
|
||||
remains.
|
||||
|
||||
Blocking a user:
|
||||
|
||||
- Leaves them in the abuse report list.
|
||||
- Changes the **Block user** button to a disabled **Already blocked** button.
|
||||
|
||||
The user is notified with the following message:
|
||||
|
||||
```plaintext
|
||||
Your account has been blocked. If you believe this is in error, contact a staff member.
|
||||
```
|
||||
|
||||
After blocking, you can still either:
|
||||
|
||||
- Remove the user and report if necessary.
|
||||
- Remove the report.
|
||||
|
||||
The following is an example of a blocked user listed on the **Abuse Reports**
|
||||
page:
|
||||
|
||||

|
||||
|
||||
NOTE:
|
||||
Users can be [blocked](../api/users.md#block-user) and
|
||||
[unblocked](../api/users.md#unblock-user) using the GitLab API.
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
||||
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
||||
important to describe those, too. Think of things that may go wrong and include them here.
|
||||
This is important to minimize requests for support, and to avoid doc comments with
|
||||
questions that you know someone might ask.
|
||||
|
||||
Each scenario can be a third-level heading, for example `### Getting error message X`.
|
||||
If you have none to add when creating a doc, leave this section in place
|
||||
but commented out to help encourage others to add to it in the future. -->
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
stage: none
|
||||
group: unassigned
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Cohorts **(FREE SELF)**
|
||||
|
||||
You can analyze your users' GitLab activities over time.
|
||||
|
||||
How do you interpret the user cohorts table? Let's review an example with the
|
||||
following user cohorts:
|
||||
|
||||

|
||||
|
||||
For the cohort of March 2020, three users were added to this server and have
|
||||
been active since this month. One month later (April 2020), two users are still
|
||||
active. Five months later (August 2020), one user from this cohort is still
|
||||
active, or 33% of the original cohort of three that joined in March.
|
||||
|
||||
The **Inactive users** column shows the number of users who were added during
|
||||
the month, but who never had any activity in the instance.
|
||||
|
||||
How do we measure the activity of users? GitLab considers a user active if:
|
||||
|
||||
- The user signs in.
|
||||
- The user has Git activity (whether push or pull).
|
||||
- The user visits pages related to dashboards, projects, issues, or merge
|
||||
requests ([introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/54947) in GitLab 11.8).
|
||||
- The user uses the API.
|
||||
- The user uses the GraphQL API.
|
||||
|
||||
## View user cohorts
|
||||
|
||||
To view user cohorts:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
1. Select **Admin Area**.
|
||||
1. Select **Overview > Users**.
|
||||
1. Select the **Cohorts** tab.
|
||||
|
|
@ -291,8 +291,8 @@ listed in the descriptions of the relevant settings.
|
|||
| Attribute | Type | Required | Description |
|
||||
|------------------------------------------|------------------|:------------------------------------:|-------------|
|
||||
| `admin_mode` | boolean | no | Require administrators to enable Admin Mode by re-authenticating for administrative tasks. |
|
||||
| `admin_notification_email` | string | no | Deprecated: Use `abuse_notification_email` instead. If set, [abuse reports](../user/admin_area/review_abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
|
||||
| `abuse_notification_email` | string | no | If set, [abuse reports](../user/admin_area/review_abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
|
||||
| `admin_notification_email` | string | no | Deprecated: Use `abuse_notification_email` instead. If set, [abuse reports](../administration/review_abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
|
||||
| `abuse_notification_email` | string | no | If set, [abuse reports](../administration/review_abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
|
||||
| `after_sign_out_path` | string | no | Where to redirect users after logout. |
|
||||
| `after_sign_up_text` | string | no | Text shown to the user after signing up. |
|
||||
| `akismet_api_key` | string | required by: `akismet_enabled` | API key for Akismet spam protection. |
|
||||
|
|
|
|||
|
|
@ -281,24 +281,24 @@ changes to prepare the codebase for data split.
|
|||
|
||||
One iteration describes one quarter's worth of work.
|
||||
|
||||
1. Iteration 1 - FY24Q1
|
||||
1. [Iteration 1](https://gitlab.com/groups/gitlab-org/-/epics/9667) - FY24Q1
|
||||
|
||||
- Data access layer: Initial Admin Area settings are shared across cluster.
|
||||
- Essential workflows: Allow to share cluster-wide data with database-level data access layer
|
||||
|
||||
1. Iteration 2 - FY24Q2
|
||||
1. [Iteration 2](https://gitlab.com/groups/gitlab-org/-/epics/9813) - FY24Q2
|
||||
|
||||
- Essential workflows: User accounts are shared across cluster.
|
||||
- Essential workflows: User can create group.
|
||||
|
||||
1. Iteration 3 - FY24Q3
|
||||
1. [Iteration 3](https://gitlab.com/groups/gitlab-org/-/epics/10997) - FY24Q3
|
||||
|
||||
- Essential workflows: User can create project.
|
||||
- Essential workflows: User can push to Git repository.
|
||||
- Cell deployment: Extend GitLab Dedicated to support GCP
|
||||
- Routing: Technology.
|
||||
|
||||
1. Iteration 4 - FY24Q4
|
||||
1. [Iteration 4](https://gitlab.com/groups/gitlab-org/-/epics/10998) - FY24Q4
|
||||
|
||||
- Essential workflows: User can run CI pipeline.
|
||||
- Essential workflows: User can create issue, merge request, and merge it after it is green.
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ GitLab administrators can block and unblock users.
|
|||
To completely prevent access of a user to the GitLab instance,
|
||||
administrators can choose to block the user.
|
||||
|
||||
Users can be blocked [via an abuse report](review_abuse_reports.md#blocking-users),
|
||||
Users can be blocked [via an abuse report](../../administration/review_abuse_reports.md#blocking-users),
|
||||
by removing them in LDAP, or directly from the Admin Area. To do this:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
|
|
|
|||
|
|
@ -1,96 +1,11 @@
|
|||
---
|
||||
stage: Anti-Abuse
|
||||
group: Anti-Abuse
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
type: reference, howto
|
||||
redirect_to: '../../administration/review_abuse_reports.md'
|
||||
remove_date: '2023-10-11'
|
||||
---
|
||||
|
||||
# Review abuse reports **(FREE SELF)**
|
||||
This document was moved to [another location](../../administration/review_abuse_reports.md).
|
||||
|
||||
View and resolve abuse reports from GitLab users.
|
||||
|
||||
GitLab administrators can view and [resolve](#resolving-abuse-reports) abuse
|
||||
reports in the Admin Area.
|
||||
|
||||
## Receive notification of abuse reports by email
|
||||
|
||||
To receive notifications of new abuse reports by email:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
1. Select **Admin Area**.
|
||||
1. Select **Settings > Reporting**.
|
||||
1. Expand the **Abuse reports** section.
|
||||
1. Provide an email address and select **Save changes**.
|
||||
|
||||
The notification email address can also be set and retrieved
|
||||
[using the API](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
|
||||
|
||||
## Reporting abuse
|
||||
|
||||
To find out more about reporting abuse, see
|
||||
[abuse reports user documentation](../report_abuse.md).
|
||||
|
||||
## Resolving abuse reports
|
||||
|
||||
To access abuse reports:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
1. Select **Admin Area**.
|
||||
1. Select **Abuse Reports**.
|
||||
|
||||
There are 3 ways to resolve an abuse report, with a button for each method:
|
||||
|
||||
- Remove user & report. This:
|
||||
- [Deletes the reported user](../profile/account/delete_account.md) from the
|
||||
instance.
|
||||
- Removes the abuse report from the list.
|
||||
- [Block user](#blocking-users).
|
||||
- Remove report. This:
|
||||
- Removes the abuse report from the list.
|
||||
- Removes access restrictions for the reported user.
|
||||
|
||||
The following is an example of the **Abuse Reports** page:
|
||||
|
||||

|
||||
|
||||
### Blocking users
|
||||
|
||||
A blocked user cannot sign in or access any repositories, but all of their data
|
||||
remains.
|
||||
|
||||
Blocking a user:
|
||||
|
||||
- Leaves them in the abuse report list.
|
||||
- Changes the **Block user** button to a disabled **Already blocked** button.
|
||||
|
||||
The user is notified with the following message:
|
||||
|
||||
```plaintext
|
||||
Your account has been blocked. If you believe this is in error, contact a staff member.
|
||||
```
|
||||
|
||||
After blocking, you can still either:
|
||||
|
||||
- Remove the user and report if necessary.
|
||||
- Remove the report.
|
||||
|
||||
The following is an example of a blocked user listed on the **Abuse Reports**
|
||||
page:
|
||||
|
||||

|
||||
|
||||
NOTE:
|
||||
Users can be [blocked](../../api/users.md#block-user) and
|
||||
[unblocked](../../api/users.md#unblock-user) using the GitLab API.
|
||||
|
||||
<!-- ## Troubleshooting
|
||||
|
||||
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
|
||||
one might have when setting this up, or when something is changed, or on upgrading, it's
|
||||
important to describe those, too. Think of things that may go wrong and include them here.
|
||||
This is important to minimize requests for support, and to avoid doc comments with
|
||||
questions that you know someone might ask.
|
||||
|
||||
Each scenario can be a third-level heading, for example `### Getting error message X`.
|
||||
If you have none to add when creating a doc, leave this section in place
|
||||
but commented out to help encourage others to add to it in the future. -->
|
||||
<!-- This redirect file can be deleted after <2023-10-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -1,40 +1,11 @@
|
|||
---
|
||||
stage: none
|
||||
group: unassigned
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
redirect_to: '../../administration/user_cohorts.md'
|
||||
remove_date: '2023-10-11'
|
||||
---
|
||||
|
||||
# Cohorts **(FREE SELF)**
|
||||
This document was moved to [another location](../../administration/user_cohorts.md).
|
||||
|
||||
You can analyze your users' GitLab activities over time.
|
||||
|
||||
How do you interpret the user cohorts table? Let's review an example with the
|
||||
following user cohorts:
|
||||
|
||||

|
||||
|
||||
For the cohort of March 2020, three users were added to this server and have
|
||||
been active since this month. One month later (April 2020), two users are still
|
||||
active. Five months later (August 2020), one user from this cohort is still
|
||||
active, or 33% of the original cohort of three that joined in March.
|
||||
|
||||
The **Inactive users** column shows the number of users who were added during
|
||||
the month, but who never had any activity in the instance.
|
||||
|
||||
How do we measure the activity of users? GitLab considers a user active if:
|
||||
|
||||
- The user signs in.
|
||||
- The user has Git activity (whether push or pull).
|
||||
- The user visits pages related to dashboards, projects, issues, or merge
|
||||
requests ([introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/54947) in GitLab 11.8).
|
||||
- The user uses the API.
|
||||
- The user uses the GraphQL API.
|
||||
|
||||
## View user cohorts
|
||||
|
||||
To view user cohorts:
|
||||
|
||||
1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
|
||||
1. Select **Admin Area**.
|
||||
1. Select **Overview > Users**.
|
||||
1. Select the **Cohorts** tab.
|
||||
<!-- This redirect file can be deleted after <2023-10-11>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ For example, the parameter `query=gitlab-org/gitlab-ui,gitlab-org/plan-stage` di
|
|||
|
||||
### Using YAML configuration
|
||||
|
||||
To change the default content of the page, you need to create a YAML configuration file in a project of your choice. Query parameters can still be used to override the YAML configuration.
|
||||
To customize the default content of the page, you need to create a YAML configuration file in a project of your choice. In this file you can define various settings and parameters, such as title, description, and number of panels and labels filters. The file is schema-driven and managed with version control systems like Git. This enables tracking and maintaining a history of configuration changes, reverting to previous versions if necessary, and collaborating effectively with team members.
|
||||
Query parameters can still be used to override the YAML configuration.
|
||||
|
||||
First, you need to set up the project.
|
||||
|
||||
|
|
@ -107,12 +108,25 @@ description: 'Custom description'
|
|||
# title - Change the title of the panel. [optional]
|
||||
# data.namespace - The Group or Project path to use for the chart panel.
|
||||
# data.exclude_metrics - Hide rows by metric ID from the chart panel.
|
||||
# data.filter_labels -
|
||||
# Only show results for data that matches the queried label(s). If multiple labels are provided,
|
||||
# only a single label needs to match for the data to be included in the results.
|
||||
# Compatible metrics (other metrics will be automatically excluded):
|
||||
# * lead_time
|
||||
# * cycle_time
|
||||
# * issues
|
||||
# * issues_completed
|
||||
# * merge_request_throughput
|
||||
# (This option is dependant on the `vsd_graphql_dora_and_flow_metrics` feature.)
|
||||
panels:
|
||||
- title: 'My Custom Project'
|
||||
data:
|
||||
namespace: group/my-custom-project
|
||||
- data:
|
||||
namespace: group/another-project
|
||||
filter_labels:
|
||||
- in_development
|
||||
- in_review
|
||||
- title: 'My Custom Group'
|
||||
data:
|
||||
namespace: group/my-custom-group
|
||||
|
|
@ -131,6 +145,9 @@ panels:
|
|||
namespace: my-group
|
||||
```
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an overview of editing label filters in the configuration file, see [GitLab Value Streams Dashboard - Label filters demo](https://www.youtube.com/watch?v=4qDAHCxCfik).
|
||||
|
||||
## Dashboard metrics and drill-down reports
|
||||
|
||||
| Metric | Description | Drill-down report | Documentation page | ID |
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ When deleting users, you can either:
|
|||
|
||||
An alternative to deleting is [blocking a user](../../admin_area/moderate_users.md#block-a-user).
|
||||
|
||||
When a user is deleted from an [abuse report](../../admin_area/review_abuse_reports.md) or spam log, these associated
|
||||
When a user is deleted from an [abuse report](../../../administration/review_abuse_reports.md) or spam log, these associated
|
||||
records are always removed.
|
||||
|
||||
The deleting associated records option can be requested in the [API](../../../api/users.md#user-deletion) as well as
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
You can report abuse from other GitLab users to GitLab administrators.
|
||||
|
||||
A GitLab administrator [can then choose](admin_area/review_abuse_reports.md) to:
|
||||
A GitLab administrator [can then choose](../administration/review_abuse_reports.md) to:
|
||||
|
||||
- Remove the user, which deletes them from the instance.
|
||||
- Block the user, which denies them access to the instance.
|
||||
|
|
@ -66,4 +66,4 @@ A URL to the reported user's comment is pre-filled in the abuse report's
|
|||
|
||||
## Related topics
|
||||
|
||||
- [Abuse reports administration documentation](admin_area/review_abuse_reports.md)
|
||||
- [Abuse reports administration documentation](../administration/review_abuse_reports.md)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ module API
|
|||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def retrieve_members(source, params:, deep: false)
|
||||
members = deep ? find_all_members(source) : source_members(source).connected_to_user
|
||||
members = members.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417456")
|
||||
members = members.includes(:user)
|
||||
members = members.references(:user).merge(User.search(params[:query], use_minimum_char_limit: false)) if params[:query].present?
|
||||
members = members.where(user_id: params[:user_ids]) if params[:user_ids].present?
|
||||
|
|
|
|||
|
|
@ -58,8 +58,11 @@ module Backup
|
|||
end
|
||||
|
||||
def enqueue_consecutive_projects
|
||||
project_relation.find_each(batch_size: 1000) do |project|
|
||||
enqueue_project(project)
|
||||
cross_join_issue = "https://gitlab.com/gitlab-org/gitlab/-/issues/417467"
|
||||
::Gitlab::Database.allow_cross_joins_across_databases(url: cross_join_issue) do
|
||||
project_relation.find_each(batch_size: 1000) do |project|
|
||||
enqueue_project(project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -65,10 +65,13 @@ module Banzai
|
|||
# The keys of this Hash are the namespace paths, the values the
|
||||
# corresponding Namespace objects.
|
||||
def namespaces
|
||||
@namespaces ||= Namespace.eager_load(:owner, :route)
|
||||
.where_full_path_in(usernames)
|
||||
.index_by(&:full_path)
|
||||
.transform_keys(&:downcase)
|
||||
cross_join_issue = "https://gitlab.com/gitlab-org/gitlab/-/issues/417466"
|
||||
Gitlab::Database.allow_cross_joins_across_databases(url: cross_join_issue) do
|
||||
@namespaces ||= Namespace.eager_load(:owner, :route)
|
||||
.where_full_path_in(usernames)
|
||||
.index_by(&:full_path)
|
||||
.transform_keys(&:downcase)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns all usernames referenced in the current document.
|
||||
|
|
|
|||
|
|
@ -97,9 +97,12 @@ module Banzai
|
|||
def find_users_for_groups(ids)
|
||||
return [] if ids.empty?
|
||||
|
||||
User.joins(:group_members).where(members: {
|
||||
source_id: Namespace.where(id: ids).where('mentions_disabled IS NOT TRUE').select(:id)
|
||||
}).to_a
|
||||
cross_join_issue = "https://gitlab.com/gitlab-org/gitlab/-/issues/417466"
|
||||
::Gitlab::Database.allow_cross_joins_across_databases(url: cross_join_issue) do
|
||||
User.joins(:group_members).where(members: {
|
||||
source_id: Namespace.where(id: ids).where('mentions_disabled IS NOT TRUE').select(:id)
|
||||
}).to_a
|
||||
end
|
||||
end
|
||||
|
||||
def find_users_for_projects(ids)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ module Gitlab
|
|||
# rubocop:disable CodeReuse/ActiveRecord
|
||||
def users
|
||||
groups = group.self_and_hierarchy_intersecting_with_user_groups(current_user)
|
||||
groups = groups.allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/417455")
|
||||
members = GroupMember.where(group: groups).non_invite
|
||||
|
||||
users = super
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ module Gitlab
|
|||
when :notes, :Note then setup_note
|
||||
when :'Ci::Pipeline' then setup_pipeline
|
||||
when *BUILD_MODELS then setup_build
|
||||
when :issues then setup_issue
|
||||
when :issues then setup_work_item
|
||||
when :'Ci::PipelineSchedule' then setup_pipeline_schedule
|
||||
when :'ProtectedBranch::MergeAccessLevel' then setup_protected_branch_access_level
|
||||
when :'ProtectedBranch::PushAccessLevel' then setup_protected_branch_access_level
|
||||
|
|
@ -169,13 +169,11 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def setup_issue
|
||||
def setup_work_item
|
||||
@relation_hash['relative_position'] = compute_relative_position
|
||||
|
||||
issue_type = @relation_hash['issue_type']
|
||||
issue_type = @relation_hash.delete('issue_type')
|
||||
@relation_hash['work_item_type'] ||= ::WorkItems::Type.default_by_type(issue_type) if issue_type
|
||||
# Make sure issue_type is in sync with work_item_type if either was provided in the export file
|
||||
@relation_hash['issue_type'] = @relation_hash['work_item_type'].base_type if @relation_hash['work_item_type']
|
||||
end
|
||||
|
||||
def setup_release
|
||||
|
|
|
|||
|
|
@ -259,7 +259,6 @@ module Gitlab
|
|||
current_user.can?(:"set_#{quick_action_target.issue_type}_metadata", quick_action_target)
|
||||
end
|
||||
command :promote_to_incident do
|
||||
@updates[:issue_type] = :incident
|
||||
@updates[:work_item_type] = ::WorkItems::Type.default_by_type(:incident)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1204,6 +1204,11 @@ msgid_plural "%{strong_start}%{tag_count}%{strong_end} Tags"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%{strong_start}%{terraform_states_count}%{strong_end} Terraform State"
|
||||
msgid_plural "%{strong_start}%{terraform_states_count}%{strong_end} Terraform States"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%{tabname} changed"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14023,6 +14028,9 @@ msgstr ""
|
|||
msgid "DORA4Metrics|Failed to load comparison chart for Namespace: %{fullPath}"
|
||||
msgstr ""
|
||||
|
||||
msgid "DORA4Metrics|Failed to load labels matching the filter: %{labels}"
|
||||
msgstr ""
|
||||
|
||||
msgid "DORA4Metrics|Filtered by"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14684,6 +14692,9 @@ msgstr ""
|
|||
msgid "Date range must be shorter than %{max_range} days."
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range too large"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date to enact enforcement on newly created namespaces"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -24816,6 +24827,9 @@ msgstr ""
|
|||
msgid "Invalid date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid dates set"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid feature"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
"@gitlab/favicon-overlay": "2.0.0",
|
||||
"@gitlab/fonts": "^1.3.0",
|
||||
"@gitlab/svgs": "3.55.0",
|
||||
"@gitlab/ui": "64.20.0",
|
||||
"@gitlab/ui": "64.20.1",
|
||||
"@gitlab/visual-review-tools": "1.7.3",
|
||||
"@gitlab/web-ide": "0.0.1-dev-20230713160749",
|
||||
"@mattiasbuelens/web-streams-adapter": "^0.1.0",
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ FactoryBot.define do
|
|||
end
|
||||
|
||||
trait :for_issue do
|
||||
target { association(:issue, issue_type: :issue) }
|
||||
target { association(:issue) }
|
||||
target_type { 'Issue' }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ FactoryBot.define do
|
|||
author { project.creator }
|
||||
updated_by { author }
|
||||
relative_position { RelativePositioning::START_POSITION }
|
||||
issue_type { :issue }
|
||||
association :work_item_type, :default
|
||||
|
||||
trait :confidential do
|
||||
|
|
@ -66,38 +65,35 @@ FactoryBot.define do
|
|||
end
|
||||
end
|
||||
|
||||
trait :issue do
|
||||
association :work_item_type, :default, :issue
|
||||
end
|
||||
|
||||
trait :requirement do
|
||||
issue_type { :requirement }
|
||||
association :work_item_type, :default, :requirement
|
||||
end
|
||||
|
||||
trait :task do
|
||||
issue_type { :task }
|
||||
association :work_item_type, :default, :task
|
||||
end
|
||||
|
||||
trait :objective do
|
||||
issue_type { :objective }
|
||||
association :work_item_type, :default, :objective
|
||||
end
|
||||
|
||||
trait :key_result do
|
||||
issue_type { :key_result }
|
||||
association :work_item_type, :default, :key_result
|
||||
end
|
||||
|
||||
trait :incident do
|
||||
issue_type { :incident }
|
||||
association :work_item_type, :default, :incident
|
||||
end
|
||||
|
||||
trait :test_case do
|
||||
issue_type { :test_case }
|
||||
association :work_item_type, :default, :test_case
|
||||
end
|
||||
|
||||
factory :incident do
|
||||
issue_type { :incident }
|
||||
association :work_item_type, :default, :incident
|
||||
|
||||
# An escalation status record is created for all incidents
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ FactoryBot.define do
|
|||
author { project.creator }
|
||||
updated_by { author }
|
||||
relative_position { RelativePositioning::START_POSITION }
|
||||
issue_type { :issue }
|
||||
association :work_item_type, :default
|
||||
|
||||
trait :confidential do
|
||||
|
|
@ -27,23 +26,23 @@ FactoryBot.define do
|
|||
closed_at { Time.now }
|
||||
end
|
||||
|
||||
trait :issue do
|
||||
association :work_item_type, :default, :issue
|
||||
end
|
||||
|
||||
trait :task do
|
||||
issue_type { :task }
|
||||
association :work_item_type, :default, :task
|
||||
end
|
||||
|
||||
trait :incident do
|
||||
issue_type { :incident }
|
||||
association :work_item_type, :default, :incident
|
||||
end
|
||||
|
||||
trait :requirement do
|
||||
issue_type { :requirement }
|
||||
association :work_item_type, :default, :requirement
|
||||
end
|
||||
|
||||
trait :test_case do
|
||||
issue_type { :test_case }
|
||||
association :work_item_type, :default, :test_case
|
||||
end
|
||||
|
||||
|
|
@ -52,12 +51,10 @@ FactoryBot.define do
|
|||
end
|
||||
|
||||
trait :objective do
|
||||
issue_type { :objective }
|
||||
association :work_item_type, :default, :objective
|
||||
end
|
||||
|
||||
trait :key_result do
|
||||
issue_type { :key_result }
|
||||
association :work_item_type, :default, :key_result
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ FactoryBot.define do
|
|||
namespace { nil }
|
||||
end
|
||||
|
||||
trait :issue do
|
||||
base_type { WorkItems::Type.base_types[:issue] }
|
||||
icon_name { 'issue-type-issue' }
|
||||
end
|
||||
|
||||
trait :incident do
|
||||
base_type { WorkItems::Type.base_types[:incident] }
|
||||
icon_name { 'issue-type-incident' }
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ RSpec.describe GraphQL::Query, type: :request do
|
|||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:issue_type) { 'issue' }
|
||||
|
||||
before_all do
|
||||
project.add_reporter(user)
|
||||
|
|
@ -128,8 +127,7 @@ RSpec.describe GraphQL::Query, type: :request do
|
|||
title: '15.2',
|
||||
start_date: Date.new(2020, 7, 1),
|
||||
due_date: Date.new(2020, 7, 30)
|
||||
),
|
||||
issue_type: issue_type
|
||||
)
|
||||
)
|
||||
|
||||
post_graphql(query, current_user: user, variables: { projectPath: project.full_path, iid: issue.iid.to_s })
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ RSpec.describe Mutations::Issues::Create do
|
|||
description: 'new description',
|
||||
confidential: true,
|
||||
due_date: Date.tomorrow,
|
||||
discussion_locked: true,
|
||||
issue_type: 'issue'
|
||||
discussion_locked: true
|
||||
}
|
||||
end
|
||||
|
||||
|
|
@ -29,7 +28,8 @@ RSpec.describe Mutations::Issues::Create do
|
|||
project_path: project.full_path,
|
||||
milestone_id: milestone.to_global_id,
|
||||
labels: [project_label1.title, project_label2.title, new_label1, new_label2],
|
||||
assignee_ids: [assignee1.to_global_id, assignee2.to_global_id]
|
||||
assignee_ids: [assignee1.to_global_id, assignee2.to_global_id],
|
||||
issue_type: 'issue'
|
||||
}.merge(expected_attributes)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -266,7 +266,6 @@ RSpec.describe GitlabSchema.types['Issue'] do
|
|||
context 'for an incident' do
|
||||
before do
|
||||
issue.update!(
|
||||
issue_type: WorkItems::Type.base_types[:incident],
|
||||
work_item_type: WorkItems::Type.default_by_type(:incident)
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ RSpec.describe IntegrationsHelper, feature_category: :integrations do
|
|||
|
||||
with_them do
|
||||
before do
|
||||
issue.assign_attributes(issue_type: issue_type, work_item_type: WorkItems::Type.default_by_type(issue_type))
|
||||
issue.assign_attributes(work_item_type: WorkItems::Type.default_by_type(issue_type))
|
||||
issue.save!(validate: false)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy, '#next_batch' do
|
||||
RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy,
|
||||
'#next_batch', feature_category: :database do
|
||||
let(:batching_strategy) { described_class.new(connection: ActiveRecord::Base.connection) }
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi
|
|||
context 'when scope has a join which makes the column name ambiguous' do
|
||||
let(:job_class) do
|
||||
Class.new(Gitlab::BackgroundMigration::BatchedMigrationJob) do
|
||||
scope_to ->(r) { r.joins('LEFT JOIN users ON users.id = namespaces.owner_id') }
|
||||
scope_to ->(r) { r.joins('LEFT JOIN namespaces as parents ON parents.id = namespaces.parent_id') }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -127,22 +127,6 @@ RSpec.describe Issue, feature_category: :team_planning do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'issue_type' do
|
||||
let(:issue) { build(:issue, issue_type: issue_type) }
|
||||
|
||||
context 'when a valid type' do
|
||||
let(:issue_type) { :issue }
|
||||
|
||||
it { is_expected.to eq(true) }
|
||||
end
|
||||
|
||||
context 'empty type' do
|
||||
let(:issue_type) { nil }
|
||||
|
||||
it { is_expected.to eq(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#allowed_work_item_type_change' do
|
||||
where(:old_type, :new_type, :is_valid) do
|
||||
:issue | :incident | true
|
||||
|
|
@ -161,7 +145,7 @@ RSpec.describe Issue, feature_category: :team_planning do
|
|||
it 'is possible to change type only between selected types' do
|
||||
issue = create(:issue, old_type, project: reusable_project)
|
||||
|
||||
issue.assign_attributes(work_item_type: WorkItems::Type.default_by_type(new_type), issue_type: new_type)
|
||||
issue.assign_attributes(work_item_type: WorkItems::Type.default_by_type(new_type))
|
||||
|
||||
expect(issue.valid?).to eq(is_valid)
|
||||
end
|
||||
|
|
@ -272,7 +256,7 @@ RSpec.describe Issue, feature_category: :team_planning do
|
|||
expect(issue.work_item_type_id).to eq(issue_type.id)
|
||||
expect(WorkItems::Type).not_to receive(:default_by_type)
|
||||
|
||||
issue.update!(work_item_type: incident_type, issue_type: :incident)
|
||||
issue.update!(work_item_type: incident_type)
|
||||
|
||||
expect(issue.work_item_type_id).to eq(incident_type.id)
|
||||
end
|
||||
|
|
@ -301,36 +285,13 @@ RSpec.describe Issue, feature_category: :team_planning do
|
|||
expect(issue.work_item_type_id).to be_nil
|
||||
expect(WorkItems::Type).not_to receive(:default_by_type)
|
||||
|
||||
issue.update!(work_item_type: incident_type, issue_type: :incident)
|
||||
issue.update!(work_item_type: incident_type)
|
||||
|
||||
expect(issue.work_item_type_id).to eq(incident_type.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#check_issue_type_in_sync' do
|
||||
it 'raises an error if issue_type is out of sync' do
|
||||
issue = build(:issue, issue_type: :issue, work_item_type: WorkItems::Type.default_by_type(:task))
|
||||
|
||||
expect do
|
||||
issue.save!
|
||||
end.to raise_error(Issue::IssueTypeOutOfSyncError)
|
||||
end
|
||||
|
||||
it 'uses attributes to compare both issue_type values' do
|
||||
issue_type = WorkItems::Type.default_by_type(:issue)
|
||||
issue = build(:issue, issue_type: :issue, work_item_type: issue_type)
|
||||
|
||||
attributes = double(:attributes)
|
||||
allow(issue).to receive(:attributes).and_return(attributes)
|
||||
|
||||
expect(attributes).to receive(:[]).with('issue_type').twice.and_return('issue')
|
||||
expect(issue_type).to receive(:base_type).and_call_original
|
||||
|
||||
issue.save!
|
||||
end
|
||||
end
|
||||
|
||||
describe '#record_create_action' do
|
||||
it 'records the creation action after saving' do
|
||||
expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_created_action)
|
||||
|
|
@ -1906,7 +1867,7 @@ RSpec.describe Issue, feature_category: :team_planning do
|
|||
|
||||
with_them do
|
||||
before do
|
||||
issue.update!(issue_type: issue_type, work_item_type: WorkItems::Type.default_by_type(issue_type))
|
||||
issue.update!(work_item_type: WorkItems::Type.default_by_type(issue_type))
|
||||
end
|
||||
|
||||
specify do
|
||||
|
|
@ -1926,7 +1887,7 @@ RSpec.describe Issue, feature_category: :team_planning do
|
|||
|
||||
with_them do
|
||||
before do
|
||||
issue.update!(issue_type: issue_type, work_item_type: WorkItems::Type.default_by_type(issue_type))
|
||||
issue.update!(work_item_type: WorkItems::Type.default_by_type(issue_type))
|
||||
end
|
||||
|
||||
specify do
|
||||
|
|
@ -2070,51 +2031,4 @@ RSpec.describe Issue, feature_category: :team_planning do
|
|||
expect { issue1.unsubscribe_email_participant(email) }.not_to change { issue2.issue_email_participants.count }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'issue_type enum generated methods' do
|
||||
describe '#<issue_type>?' do
|
||||
let_it_be(:issue) { create(:issue, project: reusable_project) }
|
||||
|
||||
where(issue_type: WorkItems::Type.base_types.keys)
|
||||
|
||||
with_them do
|
||||
it 'raises an error if called' do
|
||||
expect { issue.public_send("#{issue_type}?".to_sym) }.to raise_error(
|
||||
Issue::ForbiddenColumnUsed,
|
||||
a_string_matching(/`issue\.#{issue_type}\?` uses the `issue_type` column underneath/)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.<issue_type> scopes' do
|
||||
where(issue_type: WorkItems::Type.base_types.keys)
|
||||
|
||||
with_them do
|
||||
it 'raises an error if called' do
|
||||
expect { Issue.public_send(issue_type.to_sym) }.to raise_error(
|
||||
Issue::ForbiddenColumnUsed,
|
||||
a_string_matching(/`Issue\.#{issue_type}` uses the `issue_type` column underneath/)
|
||||
)
|
||||
end
|
||||
|
||||
context 'when called in a production environment' do
|
||||
before do
|
||||
stub_rails_env('production')
|
||||
end
|
||||
|
||||
it 'returns issues scoped by type instead of raising an error' do
|
||||
issue = create(
|
||||
:issue,
|
||||
issue_type: issue_type,
|
||||
work_item_type: WorkItems::Type.default_by_type(issue_type),
|
||||
project: reusable_project
|
||||
)
|
||||
|
||||
expect(Issue.public_send(issue_type.to_sym)).to contain_exactly(issue)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -304,22 +304,6 @@ RSpec.describe WorkItem, feature_category: :portfolio_management do
|
|||
describe 'validations' do
|
||||
subject { work_item.valid? }
|
||||
|
||||
describe 'issue_type' do
|
||||
let(:work_item) { build(:work_item, issue_type: issue_type) }
|
||||
|
||||
context 'when a valid type' do
|
||||
let(:issue_type) { :issue }
|
||||
|
||||
it { is_expected.to eq(true) }
|
||||
end
|
||||
|
||||
context 'empty type' do
|
||||
let(:issue_type) { nil }
|
||||
|
||||
it { is_expected.to eq(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'confidentiality' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ RSpec.describe WorkItems::ParentLink, feature_category: :portfolio_management do
|
|||
it 'validates if child can be added to the parent' do
|
||||
parent_type = WorkItems::Type.default_by_type(parent_type_sym)
|
||||
child_type = WorkItems::Type.default_by_type(child_type_sym)
|
||||
parent = build(:work_item, issue_type: parent_type_sym, work_item_type: parent_type, project: project)
|
||||
child = build(:work_item, issue_type: child_type_sym, work_item_type: child_type, project: project)
|
||||
parent = build(:work_item, work_item_type: parent_type, project: project)
|
||||
child = build(:work_item, work_item_type: child_type, project: project)
|
||||
link = build(:parent_link, work_item: child, work_item_parent: parent)
|
||||
|
||||
expect(link.valid?).to eq(is_valid)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe WorkItems::Widgets::Milestone do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:milestone) { create(:milestone, project: project) }
|
||||
let_it_be(:work_item) { create(:work_item, :issue, project: project, milestone: milestone) }
|
||||
let_it_be(:work_item) { create(:work_item, project: project, milestone: milestone) }
|
||||
|
||||
describe '.type' do
|
||||
subject { described_class.type }
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ RSpec.describe NotePolicy, feature_category: :team_planning do
|
|||
end
|
||||
|
||||
context 'when noteable is issue' do
|
||||
let(:noteable) { create(:work_item, :issue, project: project) }
|
||||
let(:noteable) { create(:work_item, project: project) }
|
||||
let(:note) { create(:note, system: true, noteable: noteable, author: user, project: project) }
|
||||
|
||||
it_behaves_like 'user can read the note'
|
||||
|
|
|
|||
|
|
@ -388,6 +388,35 @@ RSpec.describe ProjectPresenter do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#terraform_states_anchor_data' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let(:anchor_goto_terraform) do
|
||||
have_attributes(
|
||||
is_link: true,
|
||||
label: a_string_including(project.terraform_states.size.to_s),
|
||||
link: presenter.project_terraform_index_path(project)
|
||||
)
|
||||
end
|
||||
|
||||
where(:terraform_states_exists, :can_read_terraform_state, :expected_result) do
|
||||
true | true | ref(:anchor_goto_terraform)
|
||||
true | false | nil
|
||||
false | true | nil
|
||||
false | false | nil
|
||||
end
|
||||
|
||||
with_them do
|
||||
before do
|
||||
allow(project.terraform_states).to receive(:exists?).and_return(terraform_states_exists)
|
||||
allow(presenter).to receive(:can?).with(user, :read_terraform_state,
|
||||
project).and_return(can_read_terraform_state)
|
||||
end
|
||||
|
||||
it { expect(presenter.terraform_states_anchor_data).to match(expected_result) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#tags_anchor_data' do
|
||||
it 'returns tags data' do
|
||||
expect(presenter.tags_anchor_data).to have_attributes(
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ RSpec.describe API::Discussions, feature_category: :team_planning do
|
|||
end
|
||||
|
||||
context 'when noteable is a WorkItem' do
|
||||
let!(:work_item) { create(:work_item, :issue, project: project, author: user) }
|
||||
let!(:work_item) { create(:work_item, project: project, author: user) }
|
||||
let!(:work_item_note) { create(:discussion_note_on_issue, noteable: work_item, project: project, author: user) }
|
||||
|
||||
let(:parent) { project }
|
||||
|
|
|
|||
|
|
@ -51,9 +51,7 @@ RSpec.describe 'Update of an existing issue', feature_category: :team_planning d
|
|||
expect do
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
issue.reload
|
||||
end.to change { issue.work_item_type.base_type }.from('issue').to('incident').and(
|
||||
change(issue, :issue_type).from('issue').to('incident')
|
||||
)
|
||||
end.to change { issue.work_item_type.base_type }.from('issue').to('incident')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ RSpec.describe 'Adding a Note', feature_category: :team_planning do
|
|||
|
||||
context 'as work item' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:noteable) { create(:work_item, :issue, project: project) }
|
||||
let_it_be(:noteable) { create(:work_item, project: project) }
|
||||
|
||||
context 'when using internal param' do
|
||||
let(:variables_extra) { { internal: true } }
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe 'Destroying a Note', feature_category: :team_planning do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:noteable) { create(:work_item, :issue) }
|
||||
let(:noteable) { create(:work_item) }
|
||||
let!(:note) { create(:note, noteable: noteable, project: noteable.project) }
|
||||
let(:global_note_id) { GitlabSchema.id_from_object(note).to_s }
|
||||
let(:variables) { { id: global_note_id } }
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ RSpec.describe 'Updating a Note', feature_category: :team_planning do
|
|||
it_behaves_like 'a Note mutation update only with quick actions'
|
||||
|
||||
context 'for work item' do
|
||||
let(:noteable) { create(:work_item, :issue) }
|
||||
let(:noteable) { create(:work_item) }
|
||||
let(:note) { create(:note, noteable: noteable, project: noteable.project, note: original_body) }
|
||||
|
||||
it_behaves_like 'a Note mutation updates a note successfully'
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ RSpec.describe IssueSidebarBasicEntity do
|
|||
context 'for an incident issue' do
|
||||
before do
|
||||
issue.update!(
|
||||
issue_type: WorkItems::Type.base_types[:incident],
|
||||
work_item_type: WorkItems::Type.default_by_type(:incident)
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ RSpec.describe Issuable::DiscussionsListService, feature_category: :team_plannin
|
|||
it_behaves_like 'listing issuable discussions', :guest, 1, 7
|
||||
|
||||
context 'without notes widget' do
|
||||
let_it_be(:issuable) { create(:work_item, :issue, project: project) }
|
||||
let_it_be(:issuable) { create(:work_item, project: project) }
|
||||
|
||||
before do
|
||||
WorkItems::Type.default_by_type(:issue).widget_definitions.find_by_widget_type(:notes).update!(disabled: true)
|
||||
|
|
|
|||
|
|
@ -205,7 +205,6 @@ RSpec.describe Issues::BuildService, feature_category: :team_planning do
|
|||
issue = build_issue(**issue_params)
|
||||
|
||||
expect(issue.work_item_type_id).to eq(work_item_type_id)
|
||||
expect(issue.attributes['issue_type']).to eq(resulting_issue_type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ RSpec.describe Notes::QuickActionsService, feature_category: :team_planning do
|
|||
|
||||
context 'on an incident' do
|
||||
before do
|
||||
issue.update!(issue_type: :incident, work_item_type: WorkItems::Type.default_by_type(:incident))
|
||||
issue.update!(work_item_type: WorkItems::Type.default_by_type(:incident))
|
||||
end
|
||||
|
||||
it 'leaves the note empty' do
|
||||
|
|
@ -224,7 +224,7 @@ RSpec.describe Notes::QuickActionsService, feature_category: :team_planning do
|
|||
|
||||
context 'on an incident' do
|
||||
before do
|
||||
issue.update!(issue_type: :incident, work_item_type: WorkItems::Type.default_by_type(:incident))
|
||||
issue.update!(work_item_type: WorkItems::Type.default_by_type(:incident))
|
||||
end
|
||||
|
||||
it 'leaves the note empty' do
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ RSpec.describe WorkItems::UpdateService, feature_category: :team_planning do
|
|||
context 'when work item type is not the default Issue' do
|
||||
before do
|
||||
task_type = WorkItems::Type.default_by_type(:task)
|
||||
work_item.update_columns(issue_type: task_type.base_type, work_item_type_id: task_type.id)
|
||||
work_item.update_columns(work_item_type_id: task_type.id)
|
||||
end
|
||||
|
||||
it 'does not apply the quick action' do
|
||||
|
|
@ -55,7 +55,7 @@ RSpec.describe WorkItems::UpdateService, feature_category: :team_planning do
|
|||
end
|
||||
|
||||
context 'when work item type is the default Issue' do
|
||||
let(:issue) { create(:work_item, :issue, description: '') }
|
||||
let(:issue) { create(:work_item, description: '') }
|
||||
|
||||
it 'applies the quick action' do
|
||||
expect do
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# This module tries to discover and prevent cross-joins across tables
|
||||
# This will forbid usage of tables between CI and main database
|
||||
# This will forbid usage of tables of different gitlab_schemas
|
||||
# on a same query unless explicitly allowed by. This will change execution
|
||||
# from a given point to allow cross-joins. The state will be cleared
|
||||
# on a next test run.
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ RSpec.shared_examples 'work item supports type change via quick actions' do
|
|||
let(:body) { "Updating type.\n/type Issue" }
|
||||
|
||||
before do
|
||||
noteable.update!(work_item_type: task_type, issue_type: task_type.base_type)
|
||||
noteable.update!(work_item_type: task_type)
|
||||
end
|
||||
|
||||
it 'updates type' do
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ RSpec.shared_examples 'graphql issue list request spec' do
|
|||
end
|
||||
|
||||
before do
|
||||
issue_a.update_columns(issue_type: WorkItems::Type.base_types[:incident], work_item_type_id: incident_type.id)
|
||||
issue_a.update_columns(work_item_type_id: incident_type.id)
|
||||
end
|
||||
|
||||
it 'returns the escalation status values' do
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ RSpec.describe IncidentManagement::CloseIncidentWorker, feature_category: :incid
|
|||
|
||||
context 'when issue type is not incident' do
|
||||
before do
|
||||
issue.update!(issue_type: :issue, work_item_type: WorkItems::Type.default_by_type(:issue))
|
||||
issue.update!(work_item_type: WorkItems::Type.default_by_type(:issue))
|
||||
end
|
||||
|
||||
it_behaves_like 'does not call the close issue service'
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ func TestSetProperContentTypeAndDisposition(t *testing.T) {
|
|||
contentDisposition: "attachment",
|
||||
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 330 82\"><title>SVG logo combined with the W3C logo, set horizontally</title><desc>The logo combines three entities displayed horizontall</desc><metadata>",
|
||||
},
|
||||
{
|
||||
desc: "Incomplete SVG start tag",
|
||||
contentType: "image/svg+xml",
|
||||
contentDisposition: "attachment",
|
||||
body: "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"",
|
||||
},
|
||||
{
|
||||
desc: "Application type",
|
||||
contentType: "application/octet-stream",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
var (
|
||||
htmlCommentRegex = regexp.MustCompile(`(?i)<!--([\s\S]*?)-->`)
|
||||
svgRegex = regexp.MustCompile(`(?i)^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*>\s*)?<svg[^>]*>`)
|
||||
svgRegex = regexp.MustCompile(`(?i)^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*>\s*)?<svg[^>]*`)
|
||||
)
|
||||
|
||||
// isBinary checks if the given buffer is a binary file.
|
||||
|
|
|
|||
|
|
@ -1132,10 +1132,10 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.55.0.tgz#c67c5dddf54c400485762aff6a693e1f5a643739"
|
||||
integrity sha512-1wuXRGhrWKfWXSM9ZI1aRHlZ0wv4X7tJjDil+AQVjPBANB6oBXAPAiga+qkzkBHss7TzyOjY7OytG/9L5weDLg==
|
||||
|
||||
"@gitlab/ui@64.20.0":
|
||||
version "64.20.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-64.20.0.tgz#ee7e0bdee185cfb18c6b540d79d2a88839a76f61"
|
||||
integrity sha512-lQJP6twO6BhAsLj5FO6vCrGCjgSoNCvrZGxJCAx0FZrI8Dn/+DGiML2mqmmI7WG53+s5rV/xgMniUwBN2TQa0Q==
|
||||
"@gitlab/ui@64.20.1":
|
||||
version "64.20.1"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-64.20.1.tgz#4ca5ca7a854be5c15afcc464d16498b9b833ad6e"
|
||||
integrity sha512-yB4gRRzQCIQxxHnD50j3uOAcg5mhSBw9+tRi9kDqn+CxozDUNC/SNfTy+v7cTLJBn2mdxHfw++cuJcH3gRajxQ==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "1.2.9"
|
||||
bootstrap-vue "2.23.1"
|
||||
|
|
|
|||
Loading…
Reference in New Issue