Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-28 09:10:15 +00:00
parent 5431dbfffc
commit 2578890510
74 changed files with 322 additions and 556 deletions

View File

@ -198,7 +198,7 @@ export default {
<gl-badge <gl-badge
v-if="isInternalNote" v-if="isInternalNote"
v-gl-tooltip:tooltipcontainer.bottom v-gl-tooltip:tooltipcontainer.bottom
data-testid="internalNoteIndicator" data-testid="internal-note-indicator"
variant="warning" variant="warning"
size="sm" size="sm"
class="gl-ml-2" class="gl-ml-2"

View File

@ -60,7 +60,6 @@ module IssuableCollectionsAction
def finder_options def finder_options
issue_types = Issue::TYPES_FOR_LIST issue_types = Issue::TYPES_FOR_LIST
issue_types = issue_types.excluding('task') unless Feature.enabled?(:work_items)
super.merge( super.merge(
non_archived: true, non_archived: true,

View File

@ -405,7 +405,6 @@ class Projects::IssuesController < Projects::ApplicationController
options = super options = super
options[:issue_types] = Issue::TYPES_FOR_LIST options[:issue_types] = Issue::TYPES_FOR_LIST
options[:issue_types] = options[:issue_types].excluding('task') unless project.work_items_feature_flag_enabled?
if service_desk? if service_desk?
options.reject! { |key| key == 'author_username' || key == 'author_id' } options.reject! { |key| key == 'author_username' || key == 'author_id' }
@ -432,7 +431,6 @@ class Projects::IssuesController < Projects::ApplicationController
def create_vulnerability_issue_feedback(issue); end def create_vulnerability_issue_feedback(issue); end
def redirect_if_task def redirect_if_task
return render_404 if issue.task? && !project.work_items_feature_flag_enabled?
return unless issue.task? return unless issue.task?
if Feature.enabled?(:use_iid_in_work_items_path, project.group) if Feature.enabled?(:use_iid_in_work_items_path, project.group)

View File

@ -9,8 +9,4 @@ class Projects::WorkItemsController < Projects::ApplicationController
feature_category :team_planning feature_category :team_planning
urgency :low urgency :low
def index
render_404 unless project&.work_items_feature_flag_enabled?
end
end end

View File

@ -9,7 +9,7 @@ module Mutations
include FindsProject include FindsProject
include Mutations::WorkItems::Widgetable include Mutations::WorkItems::Widgetable
description "Creates a work item. Available only when feature flag `work_items` is enabled." description "Creates a work item."
authorize :create_work_item authorize :create_work_item
@ -42,10 +42,6 @@ module Mutations
def resolve(project_path:, **attributes) def resolve(project_path:, **attributes)
project = authorized_find!(project_path) project = authorized_find!(project_path)
unless project.work_items_feature_flag_enabled?
return { errors: ['`work_items` feature flag disabled for this project'] }
end
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
params = global_id_compatibility_params(attributes).merge(author_id: current_user.id) params = global_id_compatibility_params(attributes).merge(author_id: current_user.id)
type = ::WorkItems::Type.find(attributes[:work_item_type_id]) type = ::WorkItems::Type.find(attributes[:work_item_type_id])

View File

@ -7,8 +7,7 @@ module Mutations
include Mutations::SpamProtection include Mutations::SpamProtection
description "Creates a work item from a task in another work item's description." \ description "Creates a work item from a task in another work item's description."
" Available only when feature flag `work_items` is enabled."
authorize :update_work_item authorize :update_work_item
@ -31,10 +30,6 @@ module Mutations
def resolve(id:, work_item_data:) def resolve(id:, work_item_data:)
work_item = authorized_find!(id: id) work_item = authorized_find!(id: id)
unless work_item.project.work_items_feature_flag_enabled?
return { errors: ['`work_items` feature flag disabled for this project'] }
end
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
result = ::WorkItems::CreateFromTaskService.new( result = ::WorkItems::CreateFromTaskService.new(

View File

@ -4,8 +4,7 @@ module Mutations
module WorkItems module WorkItems
class Delete < BaseMutation class Delete < BaseMutation
graphql_name 'WorkItemDelete' graphql_name 'WorkItemDelete'
description "Deletes a work item." \ description "Deletes a work item."
" Available only when feature flag `work_items` is enabled."
authorize :delete_work_item authorize :delete_work_item
@ -20,10 +19,6 @@ module Mutations
def resolve(id:) def resolve(id:)
work_item = authorized_find!(id: id) work_item = authorized_find!(id: id)
unless work_item.project.work_items_feature_flag_enabled?
return { errors: ['`work_items` feature flag disabled for this project'] }
end
result = ::WorkItems::DeleteService.new( result = ::WorkItems::DeleteService.new(
project: work_item.project, project: work_item.project,
current_user: current_user current_user: current_user

View File

@ -5,8 +5,7 @@ module Mutations
class DeleteTask < BaseMutation class DeleteTask < BaseMutation
graphql_name 'WorkItemDeleteTask' graphql_name 'WorkItemDeleteTask'
description "Deletes a task in a work item's description." \ description "Deletes a task in a work item's description."
' Available only when feature flag `work_items` is enabled.'
authorize :update_work_item authorize :update_work_item
@ -29,10 +28,6 @@ module Mutations
work_item = authorized_find!(id: id) work_item = authorized_find!(id: id)
task_data[:task] = authorized_find_task!(task_data[:id]) task_data[:task] = authorized_find_task!(task_data[:id])
unless work_item.project.work_items_feature_flag_enabled?
return { errors: ['`work_items` feature flag disabled for this project'] }
end
result = ::WorkItems::DeleteTaskService.new( result = ::WorkItems::DeleteTaskService.new(
work_item: work_item, work_item: work_item,
current_user: current_user, current_user: current_user,

View File

@ -4,8 +4,7 @@ module Mutations
module WorkItems module WorkItems
class Update < BaseMutation class Update < BaseMutation
graphql_name 'WorkItemUpdate' graphql_name 'WorkItemUpdate'
description "Updates a work item by Global ID." \ description "Updates a work item by Global ID."
" Available only when feature flag `work_items` is enabled."
include Mutations::SpamProtection include Mutations::SpamProtection
include Mutations::WorkItems::UpdateArguments include Mutations::WorkItems::UpdateArguments
@ -20,10 +19,6 @@ module Mutations
def resolve(id:, **attributes) def resolve(id:, **attributes)
work_item = authorized_find!(id: id) work_item = authorized_find!(id: id)
unless work_item.project.work_items_feature_flag_enabled?
return { errors: ['`work_items` feature flag disabled for this project'] }
end
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
widget_params = extract_widget_params!(work_item.work_item_type, attributes) widget_params = extract_widget_params!(work_item.work_item_type, attributes)

View File

@ -4,8 +4,7 @@ module Mutations
module WorkItems module WorkItems
class UpdateTask < BaseMutation class UpdateTask < BaseMutation
graphql_name 'WorkItemUpdateTask' graphql_name 'WorkItemUpdateTask'
description "Updates a work item's task by Global ID." \ description "Updates a work item's task by Global ID."
" Available only when feature flag `work_items` is enabled."
include Mutations::SpamProtection include Mutations::SpamProtection
@ -30,10 +29,6 @@ module Mutations
work_item = authorized_find!(id: id) work_item = authorized_find!(id: id)
task = authorized_find_task!(task_data_hash[:id]) task = authorized_find_task!(task_data_hash[:id])
unless work_item.project.work_items_feature_flag_enabled?
return { errors: ['`work_items` feature flag disabled for this project'] }
end
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
::WorkItems::UpdateService.new( ::WorkItems::UpdateService.new(

View File

@ -11,10 +11,7 @@ module Resolvers
argument :id, ::Types::GlobalIDType[::WorkItem], required: true, description: 'Global ID of the work item.' argument :id, ::Types::GlobalIDType[::WorkItem], required: true, description: 'Global ID of the work item.'
def resolve(id:) def resolve(id:)
work_item = authorized_find!(id: id) authorized_find!(id: id)
return unless work_item.project.work_items_feature_flag_enabled?
work_item
end end
private private

View File

@ -11,8 +11,6 @@ module Resolvers
' Argument is experimental and can be removed in the future without notice.' ' Argument is experimental and can be removed in the future without notice.'
def resolve(taskable: nil) def resolve(taskable: nil)
return unless feature_flag_enabled_for_parent?(object)
# This will require a finder in the future when groups/projects get their work item types # This will require a finder in the future when groups/projects get their work item types
# All groups/projects use the default types for now # All groups/projects use the default types for now
base_scope = ::WorkItems::Type.default base_scope = ::WorkItems::Type.default
@ -20,14 +18,6 @@ module Resolvers
base_scope.order_by_name_asc base_scope.order_by_name_asc
end end
private
def feature_flag_enabled_for_parent?(parent)
return false unless parent.is_a?(::Project) || parent.is_a?(::Group)
parent.work_items_feature_flag_enabled?
end
end end
end end
end end

View File

@ -26,7 +26,7 @@ module Resolvers
required: false required: false
def resolve_with_lookahead(**args) def resolve_with_lookahead(**args)
return WorkItem.none if resource_parent.nil? || !resource_parent.work_items_feature_flag_enabled? return WorkItem.none if resource_parent.nil?
finder = ::WorkItems::WorkItemsFinder.new(current_user, prepare_finder_params(args)) finder = ::WorkItems::WorkItemsFinder.new(current_user, prepare_finder_params(args))

View File

@ -231,9 +231,7 @@ module Types
field :work_item_types, Types::WorkItems::TypeType.connection_type, field :work_item_types, Types::WorkItems::TypeType.connection_type,
resolver: Resolvers::WorkItems::TypesResolver, resolver: Resolvers::WorkItems::TypesResolver,
description: 'Work item types available to the group.' \ description: 'Work item types available to the group.'
' Returns `null` if `work_items` feature flag is disabled.' \
' This flag is disabled by default, because the feature is experimental and is subject to change without notice.'
def label(title:) def label(title:)
BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args|

View File

@ -10,7 +10,7 @@ module Types
end end
value 'TASK', value: 'task', value 'TASK', value: 'task',
description: 'Task issue type. Available only when feature flag `work_items` is enabled.', description: 'Task issue type.',
alpha: { milestone: '15.2' } alpha: { milestone: '15.2' }
end end
end end

View File

@ -513,9 +513,7 @@ module Types
field :work_item_types, Types::WorkItems::TypeType.connection_type, field :work_item_types, Types::WorkItems::TypeType.connection_type,
resolver: Resolvers::WorkItems::TypesResolver, resolver: Resolvers::WorkItems::TypesResolver,
description: 'Work item types available to the project.' \ description: 'Work item types available to the project.'
' Returns `null` if `work_items` feature flag is disabled.' \
' This flag is disabled by default, because the feature is experimental and is subject to change without notice.'
field :timelog_categories, Types::TimeTracking::TimelogCategoryType.connection_type, field :timelog_categories, Types::TimeTracking::TimelogCategoryType.connection_type,
null: true, null: true,

View File

@ -92,7 +92,7 @@ module Types
null: true, null: true,
resolver: Resolvers::WorkItemResolver, resolver: Resolvers::WorkItemResolver,
alpha: { milestone: '15.1' }, alpha: { milestone: '15.1' },
description: 'Find a work item. Returns `null` if `work_items` feature flag is disabled.' description: 'Find a work item.'
field :merge_request, Types::MergeRequestType, field :merge_request, Types::MergeRequestType,
null: true, null: true,

View File

@ -96,7 +96,7 @@ module Routing
private private
def use_work_items_path?(issue) def use_work_items_path?(issue)
issue.issue_type == 'task' && issue.project.work_items_feature_flag_enabled? issue.issue_type == 'task'
end end
end end
end end

View File

@ -6,6 +6,16 @@ class Appearance < ApplicationRecord
include ObjectStorage::BackgroundMove include ObjectStorage::BackgroundMove
include WithUploads include WithUploads
attribute :title, default: ''
attribute :description, default: ''
attribute :new_project_guidelines, default: ''
attribute :profile_image_guidelines, default: ''
attribute :header_message, default: ''
attribute :footer_message, default: ''
attribute :message_background_color, default: '#E75E40'
attribute :message_font_color, default: '#FFFFFF'
attribute :email_header_and_footer_enabled, default: false
cache_markdown_field :description cache_markdown_field :description
cache_markdown_field :new_project_guidelines cache_markdown_field :new_project_guidelines
cache_markdown_field :profile_image_guidelines cache_markdown_field :profile_image_guidelines
@ -20,16 +30,6 @@ class Appearance < ApplicationRecord
validate :single_appearance_row, on: :create validate :single_appearance_row, on: :create
default_value_for :title, ''
default_value_for :description, ''
default_value_for :new_project_guidelines, ''
default_value_for :profile_image_guidelines, ''
default_value_for :header_message, ''
default_value_for :footer_message, ''
default_value_for :message_background_color, '#E75E40'
default_value_for :message_font_color, '#FFFFFF'
default_value_for :email_header_and_footer_enabled, false
mount_uploader :logo, AttachmentUploader mount_uploader :logo, AttachmentUploader
mount_uploader :header_logo, AttachmentUploader mount_uploader :header_logo, AttachmentUploader
mount_uploader :favicon, FaviconUploader mount_uploader :favicon, FaviconUploader

View File

@ -75,9 +75,9 @@ class ApplicationSetting < ApplicationRecord
cache_markdown_field :shared_runners_text, pipeline: :plain_markdown cache_markdown_field :shared_runners_text, pipeline: :plain_markdown
cache_markdown_field :after_sign_up_text cache_markdown_field :after_sign_up_text
default_value_for :id, 1 attribute :id, default: 1
default_value_for :repository_storages_weighted, {} attribute :repository_storages_weighted, default: -> { {} }
default_value_for :kroki_formats, {} attribute :kroki_formats, default: -> { {} }
chronic_duration_attr_writer :archive_builds_in_human_readable, :archive_builds_in_seconds chronic_duration_attr_writer :archive_builds_in_human_readable, :archive_builds_in_seconds

View File

@ -23,8 +23,8 @@ class BroadcastMessage < ApplicationRecord
validates :color, allow_blank: true, color: true validates :color, allow_blank: true, color: true
validates :font, allow_blank: true, color: true validates :font, allow_blank: true, color: true
default_value_for :color, '#E75E40' attribute :color, default: '#E75E40'
default_value_for :font, '#FFFFFF' attribute :font, default: '#FFFFFF'
CACHE_KEY = 'broadcast_message_current_json' CACHE_KEY = 'broadcast_message_current_json'
BANNER_CACHE_KEY = 'broadcast_message_current_banner_json' BANNER_CACHE_KEY = 'broadcast_message_current_banner_json'

View File

@ -4,8 +4,8 @@ module TtlExpirable
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
attribute :read_at, default: -> { Time.zone.now }
validates :status, presence: true validates :status, presence: true
default_value_for :read_at, Time.zone.now
enum status: { default: 0, pending_destruction: 1, processing: 2, error: 3 } enum status: { default: 0, pending_destruction: 1, processing: 2, error: 3 }

View File

@ -3,7 +3,7 @@
class DependencyProxy::GroupSetting < ApplicationRecord class DependencyProxy::GroupSetting < ApplicationRecord
belongs_to :group belongs_to :group
validates :group, presence: true attribute :enabled, default: true
default_value_for :enabled, true validates :group, presence: true
end end

View File

@ -3006,7 +3006,7 @@ class Project < ApplicationRecord
end end
def work_items_create_from_markdown_feature_flag_enabled? def work_items_create_from_markdown_feature_flag_enabled?
work_items_feature_flag_enabled? && (group&.work_items_create_from_markdown_feature_flag_enabled? || Feature.enabled?(:work_items_create_from_markdown)) group&.work_items_create_from_markdown_feature_flag_enabled? || Feature.enabled?(:work_items_create_from_markdown)
end end
def enqueue_record_project_target_platforms def enqueue_record_project_target_platforms

View File

@ -4,14 +4,10 @@ module WorkItems
module Widgets module Widgets
class Hierarchy < Base class Hierarchy < Base
def parent def parent
return unless work_item.project.work_items_feature_flag_enabled?
work_item.work_item_parent work_item.work_item_parent
end end
def children def children
return WorkItem.none unless work_item.project.work_items_feature_flag_enabled?
work_item.work_item_children work_item.work_item_children
end end
end end

View File

@ -195,8 +195,6 @@ class ProjectPolicy < BasePolicy
with_scope :subject with_scope :subject
condition(:packages_disabled) { !@subject.packages_enabled } condition(:packages_disabled) { !@subject.packages_enabled }
condition(:work_items_enabled, scope: :subject) { project&.work_items_feature_flag_enabled? }
features = %w[ features = %w[
merge_requests merge_requests
issues issues
@ -304,7 +302,7 @@ class ProjectPolicy < BasePolicy
rule { can?(:create_issue) }.enable :create_work_item rule { can?(:create_issue) }.enable :create_work_item
rule { can?(:create_issue) & work_items_enabled }.enable :create_task rule { can?(:create_issue) }.enable :create_task
# These abilities are not allowed to admins that are not members of the project, # These abilities are not allowed to admins that are not members of the project,
# that's why they are defined separately. # that's why they are defined separately.

View File

@ -10,7 +10,9 @@ value_type: number
status: active status: active
time_frame: all time_frame: all
data_source: database data_source: database
instrumentation_class: DistinctCountProjectsWithExpirationPolicyDisabledMetric instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
options:
enabled: false
distribution: distribution:
- ee - ee
- ce - ce

View File

@ -0,0 +1,9 @@
---
table_name: audit_events_streaming_event_type_filters
classes:
- AuditEvents::Streaming::EventTypeFilter
feature_categories:
- audit_events
description: Represents a event type filter for audit event streaming
introduced_by_url:
milestone: '15.6'

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class CreateAuditEventsStreamingEventTypeFilters < Gitlab::Database::Migration[2.0]
UNIQ_INDEX_NAME = 'unique_streaming_event_type_filters_destination_id'
def change
create_table :audit_events_streaming_event_type_filters do |t|
t.timestamps_with_timezone null: false
t.references :external_audit_event_destination,
null: false,
index: false,
foreign_key: { to_table: 'audit_events_external_audit_event_destinations', on_delete: :cascade }
t.text :audit_event_type, null: false, limit: 255
t.index [:external_audit_event_destination_id, :audit_event_type], unique: true, name: UNIQ_INDEX_NAME
end
end
end

View File

@ -0,0 +1 @@
84b89419404d26f7d2783a3adf1fa7b7d89417d6533b393ae6e0de40a31e299a

View File

@ -11858,6 +11858,24 @@ CREATE SEQUENCE audit_events_id_seq
ALTER SEQUENCE audit_events_id_seq OWNED BY audit_events.id; ALTER SEQUENCE audit_events_id_seq OWNED BY audit_events.id;
CREATE TABLE audit_events_streaming_event_type_filters (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
external_audit_event_destination_id bigint NOT NULL,
audit_event_type text NOT NULL,
CONSTRAINT check_d20c8e5a51 CHECK ((char_length(audit_event_type) <= 255))
);
CREATE SEQUENCE audit_events_streaming_event_type_filters_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE audit_events_streaming_event_type_filters_id_seq OWNED BY audit_events_streaming_event_type_filters.id;
CREATE TABLE audit_events_streaming_headers ( CREATE TABLE audit_events_streaming_headers (
id bigint NOT NULL, id bigint NOT NULL,
created_at timestamp with time zone NOT NULL, created_at timestamp with time zone NOT NULL,
@ -23397,6 +23415,8 @@ ALTER TABLE ONLY audit_events ALTER COLUMN id SET DEFAULT nextval('audit_events_
ALTER TABLE ONLY audit_events_external_audit_event_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_external_audit_event_destinations_id_seq'::regclass); ALTER TABLE ONLY audit_events_external_audit_event_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_external_audit_event_destinations_id_seq'::regclass);
ALTER TABLE ONLY audit_events_streaming_event_type_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_event_type_filters_id_seq'::regclass);
ALTER TABLE ONLY audit_events_streaming_headers ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_headers_id_seq'::regclass); ALTER TABLE ONLY audit_events_streaming_headers ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_headers_id_seq'::regclass);
ALTER TABLE ONLY authentication_events ALTER COLUMN id SET DEFAULT nextval('authentication_events_id_seq'::regclass); ALTER TABLE ONLY authentication_events ALTER COLUMN id SET DEFAULT nextval('authentication_events_id_seq'::regclass);
@ -25066,6 +25086,9 @@ ALTER TABLE ONLY audit_events_external_audit_event_destinations
ALTER TABLE ONLY audit_events ALTER TABLE ONLY audit_events
ADD CONSTRAINT audit_events_pkey PRIMARY KEY (id, created_at); ADD CONSTRAINT audit_events_pkey PRIMARY KEY (id, created_at);
ALTER TABLE ONLY audit_events_streaming_event_type_filters
ADD CONSTRAINT audit_events_streaming_event_type_filters_pkey PRIMARY KEY (id);
ALTER TABLE ONLY audit_events_streaming_headers ALTER TABLE ONLY audit_events_streaming_headers
ADD CONSTRAINT audit_events_streaming_headers_pkey PRIMARY KEY (id); ADD CONSTRAINT audit_events_streaming_headers_pkey PRIMARY KEY (id);
@ -31162,6 +31185,8 @@ CREATE UNIQUE INDEX unique_merge_request_metrics_by_merge_request_id ON merge_re
CREATE UNIQUE INDEX unique_projects_on_name_namespace_id ON projects USING btree (name, namespace_id); CREATE UNIQUE INDEX unique_projects_on_name_namespace_id ON projects USING btree (name, namespace_id);
CREATE UNIQUE INDEX unique_streaming_event_type_filters_destination_id ON audit_events_streaming_event_type_filters USING btree (external_audit_event_destination_id, audit_event_type);
CREATE UNIQUE INDEX unique_vuln_merge_request_link_vuln_id_and_mr_id ON vulnerability_merge_request_links USING btree (vulnerability_id, merge_request_id); CREATE UNIQUE INDEX unique_vuln_merge_request_link_vuln_id_and_mr_id ON vulnerability_merge_request_links USING btree (vulnerability_id, merge_request_id);
CREATE INDEX user_follow_users_followee_id_idx ON user_follow_users USING btree (followee_id); CREATE INDEX user_follow_users_followee_id_idx ON user_follow_users USING btree (followee_id);
@ -34949,6 +34974,9 @@ ALTER TABLE ONLY dast_site_tokens
ALTER TABLE ONLY group_deploy_keys_groups ALTER TABLE ONLY group_deploy_keys_groups
ADD CONSTRAINT fk_rails_e87145115d FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_e87145115d FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY audit_events_streaming_event_type_filters
ADD CONSTRAINT fk_rails_e8bd011129 FOREIGN KEY (external_audit_event_destination_id) REFERENCES audit_events_external_audit_event_destinations(id) ON DELETE CASCADE;
ALTER TABLE ONLY description_versions ALTER TABLE ONLY description_versions
ADD CONSTRAINT fk_rails_e8f4caf9c7 FOREIGN KEY (epic_id) REFERENCES epics(id) ON DELETE CASCADE; ADD CONSTRAINT fk_rails_e8f4caf9c7 FOREIGN KEY (epic_id) REFERENCES epics(id) ON DELETE CASCADE;

View File

@ -1,13 +0,0 @@
---
# Suggestion: gitlab.Admin
#
# Checks for "admin" and recommends using the full word instead. "Admin Area" is OK.
#
# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
message: 'Verify this use of the word "admin". Can it be updated to "administration", "administrator", "administer", or "Admin Area"?'
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
level: suggestion
ignorecase: false
swap:
'[Aa]dmin ?\w*': '(?:Admin( Area| Mode)?|[Aa]dminist(ration|rator|rators|er|rative|ering|ered))'

View File

@ -595,7 +595,7 @@ Returns [`Vulnerability`](#vulnerability).
### `Query.workItem` ### `Query.workItem`
Find a work item. Returns `null` if `work_items` feature flag is disabled. Find a work item.
WARNING: WARNING:
**Introduced** in 15.1. **Introduced** in 15.1.
@ -5777,7 +5777,7 @@ Input type: `VulnerabilityRevertToDetectedInput`
### `Mutation.workItemCreate` ### `Mutation.workItemCreate`
Creates a work item. Available only when feature flag `work_items` is enabled. Creates a work item.
WARNING: WARNING:
**Introduced** in 15.1. **Introduced** in 15.1.
@ -5808,7 +5808,7 @@ Input type: `WorkItemCreateInput`
### `Mutation.workItemCreateFromTask` ### `Mutation.workItemCreateFromTask`
Creates a work item from a task in another work item's description. Available only when feature flag `work_items` is enabled. Creates a work item from a task in another work item's description.
WARNING: WARNING:
**Introduced** in 15.1. **Introduced** in 15.1.
@ -5835,7 +5835,7 @@ Input type: `WorkItemCreateFromTaskInput`
### `Mutation.workItemDelete` ### `Mutation.workItemDelete`
Deletes a work item. Available only when feature flag `work_items` is enabled. Deletes a work item.
WARNING: WARNING:
**Introduced** in 15.1. **Introduced** in 15.1.
@ -5860,7 +5860,7 @@ Input type: `WorkItemDeleteInput`
### `Mutation.workItemDeleteTask` ### `Mutation.workItemDeleteTask`
Deletes a task in a work item's description. Available only when feature flag `work_items` is enabled. Deletes a task in a work item's description.
WARNING: WARNING:
**Introduced** in 15.1. **Introduced** in 15.1.
@ -5887,7 +5887,7 @@ Input type: `WorkItemDeleteTaskInput`
### `Mutation.workItemUpdate` ### `Mutation.workItemUpdate`
Updates a work item by Global ID. Available only when feature flag `work_items` is enabled. Updates a work item by Global ID.
WARNING: WARNING:
**Introduced** in 15.1. **Introduced** in 15.1.
@ -5924,7 +5924,7 @@ Input type: `WorkItemUpdateInput`
### `Mutation.workItemUpdateTask` ### `Mutation.workItemUpdateTask`
Updates a work item's task by Global ID. Available only when feature flag `work_items` is enabled. Updates a work item's task by Global ID.
WARNING: WARNING:
**Introduced** in 15.1. **Introduced** in 15.1.
@ -13585,7 +13585,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
##### `Group.workItemTypes` ##### `Group.workItemTypes`
Work item types available to the group. Returns `null` if `work_items` feature flag is disabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. Work item types available to the group.
Returns [`WorkItemTypeConnection`](#workitemtypeconnection). Returns [`WorkItemTypeConnection`](#workitemtypeconnection).
@ -17521,7 +17521,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
##### `Project.workItemTypes` ##### `Project.workItemTypes`
Work item types available to the project. Returns `null` if `work_items` feature flag is disabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice. Work item types available to the project.
Returns [`WorkItemTypeConnection`](#workitemtypeconnection). Returns [`WorkItemTypeConnection`](#workitemtypeconnection).
@ -21052,7 +21052,7 @@ Issue type.
| <a id="issuetypeincident"></a>`INCIDENT` | Incident issue type. | | <a id="issuetypeincident"></a>`INCIDENT` | Incident issue type. |
| <a id="issuetypeissue"></a>`ISSUE` | Issue issue type. | | <a id="issuetypeissue"></a>`ISSUE` | Issue issue type. |
| <a id="issuetyperequirement"></a>`REQUIREMENT` | Requirement issue type. | | <a id="issuetyperequirement"></a>`REQUIREMENT` | Requirement issue type. |
| <a id="issuetypetask"></a>`TASK` **{warning-solid}** | **Introduced** in 15.2. This feature is in Alpha. It can be changed or removed at any time. Task issue type. Available only when feature flag `work_items` is enabled. | | <a id="issuetypetask"></a>`TASK` **{warning-solid}** | **Introduced** in 15.2. This feature is in Alpha. It can be changed or removed at any time. Task issue type. |
| <a id="issuetypetest_case"></a>`TEST_CASE` | Test Case issue type. | | <a id="issuetypetest_case"></a>`TEST_CASE` | Test Case issue type. |
### `IterationSearchableField` ### `IterationSearchableField`

View File

@ -120,24 +120,25 @@ To do so:
### Simulate a SaaS instance ### Simulate a SaaS instance
If you're developing locally and need your instance to act like the SaaS version of the product, If you're developing locally and need your instance to simulate the SaaS (GitLab.com)
you can simulate SaaS by exporting an environment variable: version of the product:
```shell 1. Export this environment variable:
export GITLAB_SIMULATE_SAAS=1
```
There are many ways to pass an environment variable to your local GitLab instance. ```shell
For example, you can create a `env.runit` file in the root of your GDK with the above snippet. export GITLAB_SIMULATE_SAAS=1
```
#### Enable plans per namespace There are many ways to pass an environment variable to your local GitLab instance.
For example, you can create an `env.runit` file in the root of your GDK with the above snippet.
To enable plans per namespace turn on the `Allow use of licensed EE features` option from the settings page. 1. Enable **Allow use of licensed EE features** to make licensed EE features available to projects
This will make licensed EE features available to projects only if the project namespace's plan includes the feature only if the project namespace's plan includes the feature.
or if the project is public. To enable it:
1. If you are developing locally, follow the steps in [Simulate a SaaS instance](#simulate-a-saas-instance) to make the option available. 1. Visit **Admin > Settings > General**.
1. Visit Admin > Settings > General > "Account and limit" and enable "Allow use of licensed EE features". 1. Expand **Account and limit**.
1. Select the **Allow use of licensed EE features** checkbox.
1. Click **Save changes**.
### Run CI pipelines in a FOSS context ### Run CI pipelines in a FOSS context

View File

@ -41,7 +41,7 @@ We have built a domain-specific language (DSL) to define the metrics instrumenta
You can use database metrics to track data kept in the database, for example, a count of issues that exist on a given instance. You can use database metrics to track data kept in the database, for example, a count of issues that exist on a given instance.
- `operation`: Operations for the given `relation`, one of `count`, `distinct_count`, `sum`, and `average`. - `operation`: Operations for the given `relation`, one of `count`, `distinct_count`, `sum`, and `average`.
- `relation`: `ActiveRecord::Relation` for the objects we want to perform the `operation`. - `relation`: Assigns lambda that returns the `ActiveRecord::Relation` for the objects we want to perform the `operation`. The assigned lambda can accept up to one parameter. The parameter is hashed and stored under the `options` key in the metric definition.
- `start`: Specifies the start value of the batch counting, by default is `relation.minimum(:id)`. - `start`: Specifies the start value of the batch counting, by default is `relation.minimum(:id)`.
- `finish`: Specifies the end value of the batch counting, by default is `relation.maximum(:id)`. - `finish`: Specifies the end value of the batch counting, by default is `relation.maximum(:id)`.
- `cache_start_and_finish_as`: Specifies the cache key for `start` and `finish` values and sets up caching them. Use this call when `start` and `finish` are expensive queries that should be reused between different metric calculations. - `cache_start_and_finish_as`: Specifies the cache key for `start` and `finish` values and sets up caching them. Use this call when `start` and `finish` are expensive queries that should be reused between different metric calculations.
@ -55,10 +55,10 @@ module Gitlab
module Usage module Usage
module Metrics module Metrics
module Instrumentations module Instrumentations
class CountBoardsMetric < DatabaseMetric class CountIssuesMetric < DatabaseMetric
operation :count operation :count
relation { Board } relation ->(options) { Issue.where(confidential: options[:confidential]) }
end end
end end
end end

View File

@ -2,6 +2,9 @@
# https://docs.gitlab.com/ee/development/cicd/templates.html # https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at: # This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST-On-Demand-API-Scan.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST-On-Demand-API-Scan.gitlab-ci.yml
# NOTE: This template is intended for internal GitLab use only and likely will not work properly
# in any other project. Do not include it in your pipeline configuration.
# For information on how to set up and use DAST, visit https://docs.gitlab.com/ee/user/application_security/dast/
stages: stages:
- build - build

View File

@ -2,6 +2,9 @@
# https://docs.gitlab.com/ee/development/cicd/templates.html # https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at: # This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST-On-Demand-Scan.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST-On-Demand-Scan.gitlab-ci.yml
# NOTE: This template is intended for internal GitLab use only and likely will not work properly
# in any other project. Do not include it in your pipeline configuration.
# For information on how to set up and use DAST, visit https://docs.gitlab.com/ee/user/application_security/dast/
stages: stages:
- build - build

View File

@ -2,6 +2,9 @@
# https://docs.gitlab.com/ee/development/cicd/templates.html # https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at: # This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST-Runner-Validation.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST-Runner-Validation.gitlab-ci.yml
# NOTE: This template is intended for internal GitLab use only and likely will not work properly
# in any other project. Do not include it in your pipeline configuration.
# For information on how to set up and use DAST, visit https://docs.gitlab.com/ee/user/application_security/dast/
stages: stages:
- build - build

View File

@ -40,6 +40,7 @@ atlassian_identities: :gitlab_main
audit_events_external_audit_event_destinations: :gitlab_main audit_events_external_audit_event_destinations: :gitlab_main
audit_events: :gitlab_main audit_events: :gitlab_main
audit_events_streaming_headers: :gitlab_main audit_events_streaming_headers: :gitlab_main
audit_events_streaming_event_type_filters: :gitlab_main
authentication_events: :gitlab_main authentication_events: :gitlab_main
award_emoji: :gitlab_main award_emoji: :gitlab_main
aws_roles: :gitlab_main aws_roles: :gitlab_main

View File

@ -34,10 +34,10 @@ module Gitlab
@metric_finish = block @metric_finish = block
end end
def relation(&block) def relation(relation_proc = nil, &block)
return @metric_relation&.call unless block return unless relation_proc || block
@metric_relation = block @metric_relation = (relation_proc || block)
end end
def metric_options(&block) def metric_options(&block)
@ -106,7 +106,11 @@ module Gitlab
end end
def relation def relation
self.class.metric_relation.call.where(time_constraints) if self.class.metric_relation.arity == 1
self.class.metric_relation.call(options)
else
self.class.metric_relation.call
end.where(time_constraints)
end end
def time_constraints def time_constraints

View File

@ -4,7 +4,7 @@ module Gitlab
module Usage module Usage
module Metrics module Metrics
module Instrumentations module Instrumentations
class DistinctCountProjectsWithExpirationPolicyDisabledMetric < DatabaseMetric class DistinctCountProjectsWithExpirationPolicyMetric < DatabaseMetric
operation :distinct_count, column: :project_id operation :distinct_count, column: :project_id
start { Project.minimum(:id) } start { Project.minimum(:id) }
@ -12,7 +12,7 @@ module Gitlab
cache_start_and_finish_as :project_id cache_start_and_finish_as :project_id
relation { ::ContainerExpirationPolicy.where(enabled: false) } relation ->(options) { ::ContainerExpirationPolicy.where(enabled: options[:enabled]) }
end end
end end
end end

View File

@ -41,20 +41,6 @@ RSpec.describe DashboardController do
expect(assigns[:issues].map(&:id)).to include(task.id) expect(assigns[:issues].map(&:id)).to include(task.id)
end end
context 'when work_items is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does not include tasks in issue list' do
task = create(:work_item, :task, project: project, author: user)
get :issues, params: { author_id: user.id }
expect(assigns[:issues].map(&:id)).not_to include(task.id)
end
end
end end
describe 'GET merge requests' do describe 'GET merge requests' do

View File

@ -168,94 +168,56 @@ RSpec.describe Projects::IssuesController do
let_it_be(:task) { create(:issue, :task, project: project) } let_it_be(:task) { create(:issue, :task, project: project) }
context 'when work_items feature flag is enabled' do shared_examples 'redirects to show work item page' do
shared_examples 'redirects to show work item page' do context 'when use_iid_in_work_items_path feature flag is disabled' do
context 'when use_iid_in_work_items_path feature flag is disabled' do before do
before do stub_feature_flags(use_iid_in_work_items_path: false)
stub_feature_flags(use_iid_in_work_items_path: false)
end
it 'redirects to work item page' do
make_request
expect(response).to redirect_to(project_work_items_path(project, task.id, query))
end
end end
it 'redirects to work item page using iid' do it 'redirects to work item page' do
make_request make_request
expect(response).to redirect_to(project_work_items_path(project, task.iid, query.merge(iid_path: true))) expect(response).to redirect_to(project_work_items_path(project, task.id, query))
end end
end end
context 'show action' do it 'redirects to work item page using iid' do
let(:query) { { query: 'any' } } make_request
it_behaves_like 'redirects to show work item page' do expect(response).to redirect_to(project_work_items_path(project, task.iid, query.merge(iid_path: true)))
subject(:make_request) do
get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
end
end
end end
end
context 'edit action' do context 'show action' do
let(:query) { { query: 'any' } } let(:query) { { query: 'any' } }
it_behaves_like 'redirects to show work item page' do it_behaves_like 'redirects to show work item page' do
subject(:make_request) do subject(:make_request) do
get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query } get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
end
end
end
context 'update action' do
it_behaves_like 'redirects to show work item page' do
subject(:make_request) do
put :update, params: {
namespace_id: project.namespace,
project_id: project,
id: task.iid,
issue: { title: 'New title' }
}
end
end end
end end
end end
context 'when work_items feature flag is disabled' do context 'edit action' do
before do let(:query) { { query: 'any' } }
stub_feature_flags(work_items: false)
end
shared_examples 'renders 404' do it_behaves_like 'redirects to show work item page' do
it 'renders 404 for show action' do subject(:make_request) do
expect(response).to have_gitlab_http_status(:not_found) get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
end end
end end
end
context 'show action' do context 'update action' do
before do it_behaves_like 'redirects to show work item page' do
get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid } subject(:make_request) do
put :update, params: {
namespace_id: project.namespace,
project_id: project,
id: task.iid,
issue: { title: 'New title' }
}
end end
it_behaves_like 'renders 404'
end
context 'edit action' do
before do
get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid }
end
it_behaves_like 'renders 404'
end
context 'update action' do
before do
put :update, params: { namespace_id: project.namespace, project_id: project, id: task.iid, issue: { title: 'New title' } }
end
it_behaves_like 'renders 404'
end end
end end
end end
@ -1728,19 +1690,6 @@ RSpec.describe Projects::IssuesController do
expect(response).to redirect_to(project_issues_path(project)) expect(response).to redirect_to(project_issues_path(project))
expect(controller).to set_flash[:notice].to match(/\AYour CSV export has started/i) expect(controller).to set_flash[:notice].to match(/\AYour CSV export has started/i)
end end
context 'when work_items is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does not include tasks in CSV export' do
expect(IssuableExportCsvWorker).to receive(:perform_async)
.with(:issue, viewer.id, project.id, hash_including('issue_types' => Issue::TYPES_FOR_LIST.excluding('task')))
request_csv
end
end
end end
context 'when not logged in' do context 'when not logged in' do

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
require "spec_helper"
RSpec.describe "Confidential notes on issues", :js do
it_behaves_like 'confidential notes on issuables' do
let_it_be(:issuable_parent) { create(:project) }
let_it_be(:issuable) { create(:issue, project: issuable_parent) }
let_it_be(:user) { create(:user) }
let(:issuable_path) { project_issue_path(issuable_parent, issuable) }
end
end

View File

@ -5,9 +5,9 @@ require "spec_helper"
RSpec.describe "User comments on issue", :js do RSpec.describe "User comments on issue", :js do
include Spec::Support::Helpers::Features::NotesHelpers include Spec::Support::Helpers::Features::NotesHelpers
let(:project) { create(:project_empty_repo, :public) } let_it_be(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }
let(:user) { create(:user) } let_it_be(:user) { create(:user) }
before do before do
project.add_guest(user) project.add_guest(user)

View File

@ -18,7 +18,7 @@ describe('NoteHeader component', () => {
const findActionText = () => wrapper.findComponent({ ref: 'actionText' }); const findActionText = () => wrapper.findComponent({ ref: 'actionText' });
const findTimestampLink = () => wrapper.findComponent({ ref: 'noteTimestampLink' }); const findTimestampLink = () => wrapper.findComponent({ ref: 'noteTimestampLink' });
const findTimestamp = () => wrapper.findComponent({ ref: 'noteTimestamp' }); const findTimestamp = () => wrapper.findComponent({ ref: 'noteTimestamp' });
const findInternalNoteIndicator = () => wrapper.findByTestId('internalNoteIndicator'); const findInternalNoteIndicator = () => wrapper.findByTestId('internal-note-indicator');
const findSpinner = () => wrapper.findComponent({ ref: 'spinner' }); const findSpinner = () => wrapper.findComponent({ ref: 'spinner' });
const statusHtml = const statusHtml =

View File

@ -27,14 +27,6 @@ RSpec.describe Resolvers::WorkItemResolver do
end end
end end
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it { is_expected.to be_nil }
end
end end
private private

View File

@ -29,16 +29,6 @@ RSpec.describe Resolvers::WorkItems::TypesResolver do
expect(result.to_a).to contain_exactly(WorkItems::Type.default_by_type(:task)) expect(result.to_a).to contain_exactly(WorkItems::Type.default_by_type(:task))
end end
end end
context 'when work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'returns nil' do
expect(result).to be_nil
end
end
end end
describe '#resolve' do describe '#resolve' do
@ -53,15 +43,5 @@ RSpec.describe Resolvers::WorkItems::TypesResolver do
it_behaves_like 'a work item type resolver' it_behaves_like 'a work item type resolver'
end end
context 'when parent is not a group or project' do
let(:object) { 'not a project/group' }
it 'returns nil because of feature flag check' do
result = resolve(described_class, obj: object, args: {})
expect(result).to be_nil
end
end
end end
end end

View File

@ -72,18 +72,6 @@ RSpec.describe Gitlab::UrlBuilder do
end end
end end
context 'when work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'returns an issue path for an issue of type task' do
task = create(:issue, :task)
expect(subject.build(task, only_path: true)).to eq("/#{task.project.full_path}/-/issues/#{task.iid}")
end
end
context 'when passing a compare' do context 'when passing a compare' do
# NOTE: The Compare requires an actual repository, which isn't available # NOTE: The Compare requires an actual repository, which isn't available
# with the `build_stubbed` strategy used by the table tests above # with the `build_stubbed` strategy used by the table tests above

View File

@ -7,8 +7,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
described_class.tap do |metric_class| described_class.tap do |metric_class|
metric_class.relation { Issue } metric_class.relation { Issue }
metric_class.operation :count metric_class.operation :count
metric_class.start { metric_class.relation.minimum(:id) } metric_class.start { Issue.minimum(:id) }
metric_class.finish { metric_class.relation.maximum(:id) } metric_class.finish { Issue.maximum(:id) }
end.new(time_frame: 'all') end.new(time_frame: 'all')
end end
@ -41,8 +41,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
described_class.tap do |metric_class| described_class.tap do |metric_class|
metric_class.relation { Issue } metric_class.relation { Issue }
metric_class.operation :count metric_class.operation :count
metric_class.start { metric_class.relation.minimum(:id) } metric_class.start { Issue.minimum(:id) }
metric_class.finish { metric_class.relation.maximum(:id) } metric_class.finish { Issue.maximum(:id) }
metric_class.metric_options { { batch_size: 12345 } } metric_class.metric_options { { batch_size: 12345 } }
end.new(time_frame: 'all') end.new(time_frame: 'all')
end end
@ -103,8 +103,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
described_class.tap do |metric_class| described_class.tap do |metric_class|
metric_class.relation { Issue } metric_class.relation { Issue }
metric_class.operation :count metric_class.operation :count
metric_class.start { metric_class.relation.minimum(:id) } metric_class.start { Issue.minimum(:id) }
metric_class.finish { metric_class.relation.maximum(:id) } metric_class.finish { Issue.maximum(:id) }
metric_class.cache_start_and_finish_as :special_issue_count metric_class.cache_start_and_finish_as :special_issue_count
end.new(time_frame: 'all') end.new(time_frame: 'all')
end end
@ -126,8 +126,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
described_class.tap do |metric_class| described_class.tap do |metric_class|
metric_class.relation { Issue } metric_class.relation { Issue }
metric_class.operation(:estimate_batch_distinct_count) metric_class.operation(:estimate_batch_distinct_count)
metric_class.start { metric_class.relation.minimum(:id) } metric_class.start { Issue.minimum(:id) }
metric_class.finish { metric_class.relation.maximum(:id) } metric_class.finish { Issue.maximum(:id) }
end.new(time_frame: 'all') end.new(time_frame: 'all')
end end
@ -144,8 +144,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
metric_class.operation(:estimate_batch_distinct_count) do |result| metric_class.operation(:estimate_batch_distinct_count) do |result|
result.foo result.foo
end end
metric_class.start { metric_class.relation.minimum(:id) } metric_class.start { Issue.minimum(:id) }
metric_class.finish { metric_class.relation.maximum(:id) } metric_class.finish { Issue.maximum(:id) }
end.new(time_frame: 'all') end.new(time_frame: 'all')
end end
@ -192,6 +192,22 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
expect(subject.value).to eq(1) expect(subject.value).to eq(1)
end end
end end
context 'with additional parameters passed via options' do
subject do
described_class.tap do |metric_class|
metric_class.relation ->(options) { Issue.where(confidential: options[:confidential]) }
metric_class.operation :count
end.new(time_frame: '28d', options: { confidential: true })
end
it 'calculates a correct result' do
create(:issue, last_edited_at: 5.days.ago, confidential: true)
create(:issue, last_edited_at: 5.days.ago, confidential: false)
expect(subject.value).to eq(1)
end
end
end end
context 'with unimplemented operation method used' do context 'with unimplemented operation method used' do

View File

@ -2,18 +2,18 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DistinctCountProjectsWithExpirationPolicyDisabledMetric do RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DistinctCountProjectsWithExpirationPolicyMetric do
before_all do before_all do
create(:container_expiration_policy, enabled: false) create(:container_expiration_policy, enabled: false)
create(:container_expiration_policy, enabled: false, created_at: 29.days.ago) create(:container_expiration_policy, enabled: false, created_at: 29.days.ago)
create(:container_expiration_policy, enabled: true) create(:container_expiration_policy, enabled: true)
end end
it_behaves_like 'a correct instrumented metric value', { time_frame: '28d' } do it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', options: { enabled: false } } do
let(:expected_value) { 1 } let(:expected_value) { 1 }
end end
it_behaves_like 'a correct instrumented metric value', { time_frame: 'all' } do it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', options: { enabled: false } } do
let(:expected_value) { 2 } let(:expected_value) { 2 }
end end
end end

View File

@ -10,6 +10,20 @@ RSpec.describe Appearance do
it { is_expected.to have_many(:uploads) } it { is_expected.to have_many(:uploads) }
describe 'default values' do
subject(:appearance) { described_class.new }
it { expect(appearance.title).to eq('') }
it { expect(appearance.description).to eq('') }
it { expect(appearance.new_project_guidelines).to eq('') }
it { expect(appearance.profile_image_guidelines).to eq('') }
it { expect(appearance.header_message).to eq('') }
it { expect(appearance.footer_message).to eq('') }
it { expect(appearance.message_background_color).to eq('#E75E40') }
it { expect(appearance.message_font_color).to eq('#FFFFFF') }
it { expect(appearance.email_header_and_footer_enabled).to eq(false) }
end
describe '#single_appearance_row' do describe '#single_appearance_row' do
it 'adds an error when more than 1 row exists' do it 'adds an error when more than 1 row exists' do
create(:appearance) create(:appearance)

View File

@ -17,6 +17,14 @@ RSpec.describe ApplicationSetting do
it { expect(setting.uuid).to be_present } it { expect(setting.uuid).to be_present }
it { expect(setting).to have_db_column(:auto_devops_enabled) } it { expect(setting).to have_db_column(:auto_devops_enabled) }
describe 'default values' do
subject(:setting) { described_class.new }
it { expect(setting.id).to eq(1) }
it { expect(setting.repository_storages_weighted).to eq({}) }
it { expect(setting.kroki_formats).to eq({}) }
end
describe 'validations' do describe 'validations' do
let(:http) { 'http://example.com' } let(:http) { 'http://example.com' }
let(:https) { 'https://example.com' } let(:https) { 'https://example.com' }

View File

@ -27,6 +27,13 @@ RSpec.describe BroadcastMessage do
it { is_expected.to validate_inclusion_of(:target_access_levels).in_array(described_class::ALLOWED_TARGET_ACCESS_LEVELS) } it { is_expected.to validate_inclusion_of(:target_access_levels).in_array(described_class::ALLOWED_TARGET_ACCESS_LEVELS) }
end end
describe 'default values' do
subject(:message) { described_class.new }
it { expect(message.color).to eq('#E75E40') }
it { expect(message.font).to eq('#FFFFFF') }
end
shared_examples 'time constrainted' do |broadcast_type| shared_examples 'time constrainted' do |broadcast_type|
it 'returns message if time match' do it 'returns message if time match' do
message = create(:broadcast_message, broadcast_type: broadcast_type) message = create(:broadcast_message, broadcast_type: broadcast_type)

View File

@ -7,6 +7,11 @@ RSpec.describe DependencyProxy::GroupSetting, type: :model do
it { is_expected.to belong_to(:group) } it { is_expected.to belong_to(:group) }
end end
describe 'default values' do
it { is_expected.to be_enabled }
it { expect(described_class.new(enabled: false)).not_to be_enabled }
end
describe 'validations' do describe 'validations' do
it { is_expected.to validate_presence_of(:group) } it { is_expected.to validate_presence_of(:group) }
end end

View File

@ -26,22 +26,6 @@ RSpec.describe WorkItems::Widgets::Hierarchy do
subject { described_class.new(parent_link.work_item).parent } subject { described_class.new(parent_link.work_item).parent }
it { is_expected.to eq(parent_link.work_item_parent) } it { is_expected.to eq(parent_link.work_item_parent) }
context 'when work_items flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it { is_expected.to be_nil }
end
context 'when work_items flag is enabled for the parent group' do
before do
stub_feature_flags(work_items: group)
end
it { is_expected.to eq(parent_link.work_item_parent) }
end
end end
describe '#children' do describe '#children' do
@ -51,21 +35,5 @@ RSpec.describe WorkItems::Widgets::Hierarchy do
subject { described_class.new(work_item_parent).children } subject { described_class.new(work_item_parent).children }
it { is_expected.to contain_exactly(parent_link1.work_item, parent_link2.work_item) } it { is_expected.to contain_exactly(parent_link1.work_item, parent_link2.work_item) }
context 'when work_items flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it { is_expected.to be_empty }
end
context 'when work_items flag is enabled for the parent group' do
before do
stub_feature_flags(work_items: group)
end
it { is_expected.to contain_exactly(parent_link1.work_item, parent_link2.work_item) }
end
end end
end end

View File

@ -629,17 +629,7 @@ RSpec.describe ProjectPolicy do
context 'when user is member of the project' do context 'when user is member of the project' do
let(:current_user) { developer } let(:current_user) { developer }
context 'when work_items feature flag is enabled' do it { expect_allowed(:create_task) }
it { expect_allowed(:create_task) }
end
context 'when work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it { expect_disallowed(:create_task) }
end
end end
end end

View File

@ -26,32 +26,20 @@ RSpec.describe IssuePresenter do
context 'when issue type is task' do context 'when issue type is task' do
let(:presented_issue) { task } let(:presented_issue) { task }
context 'when work_items feature flag is enabled' do context 'when use_iid_in_work_items_path feature flag is disabled' do
context 'when use_iid_in_work_items_path feature flag is disabled' do before do
before do stub_feature_flags(use_iid_in_work_items_path: false)
stub_feature_flags(use_iid_in_work_items_path: false)
end
it 'returns a work item url for the task' do
expect(presenter.web_url).to eq(project_work_items_url(project, work_items_path: presented_issue.id))
end
end end
it 'returns a work item url using iid for the task' do it 'returns a work item url for the task' do
expect(presenter.web_url).to eq( expect(presenter.web_url).to eq(project_work_items_url(project, work_items_path: presented_issue.id))
project_work_items_url(project, work_items_path: presented_issue.iid, iid_path: true)
)
end end
end end
context 'when work_items feature flag is disabled' do it 'returns a work item url using iid for the task' do
before do expect(presenter.web_url).to eq(
stub_feature_flags(work_items: false) project_work_items_url(project, work_items_path: presented_issue.iid, iid_path: true)
end )
it 'returns an issue url for the task' do
expect(presenter.web_url).to eq("http://localhost/#{group.name}/#{project.name}/-/issues/#{presented_issue.iid}")
end
end end
end end
end end
@ -78,32 +66,20 @@ RSpec.describe IssuePresenter do
context 'when issue type is task' do context 'when issue type is task' do
let(:presented_issue) { task } let(:presented_issue) { task }
context 'when work_items feature flag is enabled' do context 'when use_iid_in_work_items_path feature flag is disabled' do
context 'when use_iid_in_work_items_path feature flag is disabled' do before do
before do stub_feature_flags(use_iid_in_work_items_path: false)
stub_feature_flags(use_iid_in_work_items_path: false)
end
it 'returns a work item path for the task' do
expect(presenter.issue_path).to eq(project_work_items_path(project, work_items_path: presented_issue.id))
end
end end
it 'returns a work item path using iid for the task' do it 'returns a work item path for the task' do
expect(presenter.issue_path).to eq( expect(presenter.issue_path).to eq(project_work_items_path(project, work_items_path: presented_issue.id))
project_work_items_path(project, work_items_path: presented_issue.iid, iid_path: true)
)
end end
end end
context 'when work_items feature flag is disabled' do it 'returns a work item path using iid for the task' do
before do expect(presenter.issue_path).to eq(
stub_feature_flags(work_items: false) project_work_items_path(project, work_items_path: presented_issue.iid, iid_path: true)
end )
it 'returns an issue path for the task' do
expect(presenter.issue_path).to eq("/#{group.name}/#{project.name}/-/issues/#{presented_issue.iid}")
end
end end
end end
end end

View File

@ -57,15 +57,4 @@ RSpec.describe 'getting a list of work item types for a group' do
expect(graphql_data).to eq('group' => nil) expect(graphql_data).to eq('group' => nil)
end end
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
post_graphql(query, current_user: current_user)
end
it 'returns null' do
expect(graphql_data.dig('group', 'workItemTypes')).to be_nil
end
end
end end

View File

@ -58,34 +58,15 @@ RSpec.describe 'Create an issue' do
input['type'] = 'TASK' input['type'] = 'TASK'
end end
context 'when work_items feature flag is disabled' do it 'creates an issue with TASK type' do
before do expect do
stub_feature_flags(work_items: false) post_graphql_mutation(mutation, current_user: current_user)
end end.to change(Issue, :count).by(1)
it 'creates an issue with the default ISSUE type' do created_issue = Issue.last
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to change(Issue, :count).by(1)
created_issue = Issue.last expect(created_issue.work_item_type.base_type).to eq('task')
expect(created_issue.issue_type).to eq('task')
expect(created_issue.work_item_type.base_type).to eq('issue')
expect(created_issue.issue_type).to eq('issue')
end
end
context 'when work_items feature flag is enabled' do
it 'creates an issue with TASK type' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to change(Issue, :count).by(1)
created_issue = Issue.last
expect(created_issue.work_item_type.base_type).to eq('task')
expect(created_issue.issue_type).to eq('task')
end
end end
end end

View File

@ -71,19 +71,5 @@ RSpec.describe "Create a work item from a task in a work item's description" do
it_behaves_like 'has spam protection' do it_behaves_like 'has spam protection' do
let(:mutation_class) { ::Mutations::WorkItems::CreateFromTask } let(:mutation_class) { ::Mutations::WorkItems::CreateFromTask }
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does nothing and returns and error' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to not_change(WorkItem, :count)
expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
end
end
end end
end end

View File

@ -215,19 +215,5 @@ RSpec.describe 'Create a work item' do
end end
end end
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does not create the work item and returns an error' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to not_change(WorkItem, :count)
expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
end
end
end end
end end

View File

@ -31,19 +31,5 @@ RSpec.describe 'Delete a work item' do
expect(response).to have_gitlab_http_status(:success) expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['project']).to include('id' => work_item.project.to_global_id.to_s) expect(mutation_response['project']).to include('id' => work_item.project.to_global_id.to_s)
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does not delete the work item' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to not_change(WorkItem, :count)
expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
end
end
end end
end end

View File

@ -75,19 +75,5 @@ RSpec.describe "Delete a task in a work item's description" do
expect(mutation_response['errors']).to contain_exactly('Stale work item. Check lock version') expect(mutation_response['errors']).to contain_exactly('Stale work item. Check lock version')
end end
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does nothing and returns and error' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to not_change(WorkItem, :count)
expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
end
end
end end
end end

View File

@ -644,20 +644,5 @@ RSpec.describe 'Update a work item' do
it_behaves_like 'a mutation that returns top-level errors', it_behaves_like 'a mutation that returns top-level errors',
errors: ["Following widget keys are not supported by some_test_case_name type: [:hierarchy_widget]"] errors: ["Following widget keys are not supported by some_test_case_name type: [:hierarchy_widget]"]
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does not update the work item and returns and error' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
work_item.reload
end.to not_change(work_item, :title)
expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
end
end
end end
end end

View File

@ -74,22 +74,6 @@ RSpec.describe 'Update a work item task' do
it_behaves_like 'has spam protection' do it_behaves_like 'has spam protection' do
let(:mutation_class) { ::Mutations::WorkItems::UpdateTask } let(:mutation_class) { ::Mutations::WorkItems::UpdateTask }
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'does not update the task item and returns and error' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
work_item.reload
task.reload
end.to not_change(task, :title)
expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
end
end
end end
context 'when user does not have permissions to update a work item' do context 'when user does not have permissions to update a work item' do

View File

@ -57,15 +57,4 @@ RSpec.describe 'getting a list of work item types for a project' do
expect(graphql_data).to eq('project' => nil) expect(graphql_data).to eq('project' => nil)
end end
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
post_graphql(query, current_user: current_user)
end
it 'returns null' do
expect(graphql_data.dig('project', 'workItemTypes')).to be_nil
end
end
end end

View File

@ -130,18 +130,6 @@ RSpec.describe 'getting a work item list for a project' do
end end
end end
context 'when work_items flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'returns an empty list' do
post_graphql(query)
expect(items_data).to eq([])
end
end
it 'returns only items visible to user' do it 'returns only items visible to user' do
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)

View File

@ -357,16 +357,4 @@ RSpec.describe 'Query.work_item(id)' do
) )
end end
end end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'returns nil' do
post_graphql(query)
expect(work_item_data).to be_nil
end
end
end end

View File

@ -15,24 +15,10 @@ RSpec.describe 'Work Items' do
sign_in(developer) sign_in(developer)
end end
context 'when the work_items feature flag is enabled' do it 'renders index' do
it 'renders index' do get project_work_items_url(work_item.project, work_items_path: work_item.id)
get project_work_items_url(work_item.project, work_items_path: work_item.id)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end
end
context 'when the work_items feature flag is disabled' do
before do
stub_feature_flags(work_items: false)
end
it 'returns 404' do
get project_work_items_url(work_item.project, work_items_path: work_item.id)
expect(response).to have_gitlab_http_status(:not_found)
end
end end
end end
end end

View File

@ -10,8 +10,8 @@ RSpec.shared_examples 'a correct instrumented metric value' do |params|
end end
before do before do
if described_class.respond_to?(:relation) && described_class.relation.respond_to?(:connection) if metric.respond_to?(:relation, true) && metric.send(:relation).respond_to?(:connection)
allow(described_class.relation.connection).to receive(:transaction_open?).and_return(false) allow(metric.send(:relation).connection).to receive(:transaction_open?).and_return(false)
end end
end end

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
require "spec_helper"
RSpec.shared_examples 'confidential notes on issuables' do
include Spec::Support::Helpers::Features::NotesHelpers
context 'when user does not have permissions' do
it 'does not show confidential note checkbox' do
issuable_parent.add_guest(user)
sign_in(user)
visit(issuable_path)
page.within('.new-note') do
expect(page).not_to have_selector('[data-testid="internal-note-checkbox"]')
end
end
end
context 'when user has permissions' do
it 'creates confidential note' do
issuable_parent.add_reporter(user)
sign_in(user)
visit(issuable_path)
find('[data-testid="internal-note-checkbox"]').click
add_note('Confidential note')
page.within('.note-header') do
expect(page).to have_selector('[data-testid="internal-note-indicator"]')
end
end
end
end

View File

@ -7,6 +7,11 @@ RSpec.shared_examples 'ttl_expirable' do
it_behaves_like 'having unique enum values' it_behaves_like 'having unique enum values'
describe 'default values', :freeze_time do
it { expect(described_class.new.read_at).to be_like_time(Time.zone.now) }
it { expect(described_class.new(read_at: 1.day.ago).read_at).to be_like_time(1.day.ago) }
end
describe 'validations' do describe 'validations' do
it { is_expected.to validate_presence_of(:status) } it { is_expected.to validate_presence_of(:status) }
end end
@ -38,7 +43,7 @@ RSpec.shared_examples 'ttl_expirable' do
end end
end end
describe '#read', :freeze_time do describe '#read!', :freeze_time do
let_it_be(:old_read_at) { 1.day.ago } let_it_be(:old_read_at) { 1.day.ago }
let_it_be(:item1) { create(class_symbol, read_at: old_read_at) } let_it_be(:item1) { create(class_symbol, read_at: old_read_at) }

View File

@ -226,7 +226,7 @@ func TestUploadHandlerSendingToExternalStorageAndSupportRequestTimeout(t *testin
RemoteObject: api.RemoteObject{ RemoteObject: api.RemoteObject{
StoreURL: storeServer.URL + "/url/put", StoreURL: storeServer.URL + "/url/put",
ID: "store-id", ID: "store-id",
Timeout: 0.001, Timeout: 0.1,
}, },
} }