Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-08-19 18:10:32 +00:00
parent 155f106fd5
commit 21db5294d4
84 changed files with 1117 additions and 285 deletions

View File

@ -23,30 +23,6 @@ Graphql/Descriptions:
- 'ee/app/graphql/types/vulnerability_severity_enum.rb'
- 'ee/app/graphql/types/vulnerability_state_enum.rb'
- 'ee/app/graphql/types/vulnerability_confidence_enum.rb'
- 'app/graphql/resolvers/labels_resolver.rb'
- 'app/graphql/resolvers/merge_requests_resolver.rb'
- 'app/graphql/resolvers/milestones_resolver.rb'
- 'app/graphql/resolvers/package_details_resolver.rb'
- 'app/graphql/resolvers/paginated_tree_resolver.rb'
- 'app/graphql/resolvers/release_resolver.rb'
- 'app/graphql/resolvers/repository_branch_names_resolver.rb'
- 'app/graphql/resolvers/snippets_resolver.rb'
- 'app/graphql/resolvers/todo_resolver.rb'
- 'app/graphql/resolvers/tree_resolver.rb'
- 'app/graphql/resolvers/users/snippets_resolver.rb'
- 'app/graphql/types/admin/analytics/usage_trends/measurement_type.rb'
- 'app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb'
- 'app/graphql/types/alert_management/alert_type.rb'
- 'app/graphql/types/award_emojis/award_emoji_type.rb'
- 'app/graphql/types/ci/config/job_restriction_type.rb'
- 'app/graphql/types/ci/config/status_enum.rb'
- 'app/graphql/types/ci/pipeline_type.rb'
- 'app/graphql/types/ci_configuration/sast/ui_component_size_enum.rb'
- 'app/graphql/types/commit_action_type.rb'
- 'app/graphql/types/container_repository_cleanup_status_enum.rb'
- 'app/graphql/types/container_repository_tag_type.rb'
- 'app/graphql/types/container_repository_type.rb'
- 'app/graphql/types/custom_emoji_type.rb'
- 'app/graphql/types/design_management/design_at_version_type.rb'
- 'app/graphql/types/design_management/design_fields.rb'
- 'app/graphql/types/diff_paths_input_type.rb'

View File

@ -10,7 +10,7 @@ module Resolvers
argument :search_term, GraphQL::Types::String,
required: false,
description: 'A search term to find labels with.'
description: 'Search term to find labels with.'
argument :include_ancestor_groups, GraphQL::Types::Boolean,
required: false,

View File

@ -49,7 +49,7 @@ module Resolvers
argument :state, ::Types::MergeRequestStateEnum,
required: false,
description: 'A merge request state. If provided, all resolved merge requests will have this state.'
description: 'Merge request state. If provided, all resolved merge requests will have this state.'
argument :labels, [GraphQL::Types::String],
required: false,

View File

@ -15,15 +15,15 @@ module Resolvers
argument :title, GraphQL::Types::String,
required: false,
description: 'The title of the milestone.'
description: 'Title of the milestone.'
argument :search_title, GraphQL::Types::String,
required: false,
description: 'A search string for the title.'
description: 'Search string for the title.'
argument :containing_date, Types::TimeType,
required: false,
description: 'A date that the milestone contains.'
description: 'Date the milestone contains.'
argument :sort, Types::MilestoneSortEnum,
description: 'Sort milestones by this criteria.',

View File

@ -6,7 +6,7 @@ module Resolvers
argument :id, ::Types::GlobalIDType[::Packages::Package],
required: true,
description: 'The global ID of the package.'
description: 'Global ID of the package.'
def ready?(**args)
context[self.class] ||= { executions: 0 }

View File

@ -10,11 +10,11 @@ module Resolvers
argument :path, GraphQL::Types::String,
required: false,
default_value: '', # root of the repository
description: 'The path to get the tree for. Default value is the root of the repository.'
description: 'Path to get the tree for. Default value is the root of the repository.'
argument :ref, GraphQL::Types::String,
required: false,
default_value: :head,
description: 'The commit ref to get the tree for. Default value is HEAD.'
description: 'Commit ref to get the tree for. Default value is HEAD.'
argument :recursive, GraphQL::Types::Boolean,
required: false,
default_value: false,

View File

@ -6,7 +6,7 @@ module Resolvers
argument :tag_name, GraphQL::Types::String,
required: true,
description: 'The name of the tag associated to the release.'
description: 'Name of the tag associated to the release.'
alias_method :project, :object

View File

@ -8,15 +8,15 @@ module Resolvers
argument :search_pattern, GraphQL::Types::String,
required: true,
description: 'The pattern to search for branch names by.'
description: 'Pattern to search for branch names by.'
argument :offset, GraphQL::Types::Int,
required: true,
description: 'The number of branch names to skip.'
description: 'Number of branch names to skip.'
argument :limit, GraphQL::Types::Int,
required: true,
description: 'The number of branch names to return.'
description: 'Number of branch names to return.'
def resolve(search_pattern:, offset:, limit:)
Repositories::BranchNamesFinder.new(object, offset: offset, limit: limit, search: search_pattern).execute

View File

@ -12,15 +12,15 @@ module Resolvers
argument :author_id, ::Types::GlobalIDType[::User],
required: false,
description: 'The ID of an author.'
description: 'ID of an author.'
argument :project_id, ::Types::GlobalIDType[::Project],
required: false,
description: 'The ID of a project.'
description: 'ID of a project.'
argument :type, Types::Snippets::TypeEnum,
required: false,
description: 'The type of snippet.'
description: 'Type of snippet.'
argument :explore,
GraphQL::Types::Boolean,

View File

@ -8,27 +8,27 @@ module Resolvers
argument :action, [Types::TodoActionEnum],
required: false,
description: 'The action to be filtered.'
description: 'Action to be filtered.'
argument :author_id, [GraphQL::Types::ID],
required: false,
description: 'The ID of an author.'
description: 'ID of an author.'
argument :project_id, [GraphQL::Types::ID],
required: false,
description: 'The ID of a project.'
description: 'ID of a project.'
argument :group_id, [GraphQL::Types::ID],
required: false,
description: 'The ID of a group.'
description: 'ID of a group.'
argument :state, [Types::TodoStateEnum],
required: false,
description: 'The state of the todo.'
description: 'State of the todo.'
argument :type, [Types::TodoTargetEnum],
required: false,
description: 'The type of the todo.'
description: 'Type of the todo.'
def resolve(**args)
return Todo.none unless current_user.present? && target.present?

View File

@ -9,11 +9,11 @@ module Resolvers
argument :path, GraphQL::Types::String,
required: false,
default_value: '',
description: 'The path to get the tree for. Default value is the root of the repository.'
description: 'Path to get the tree for. Default value is the root of the repository.'
argument :ref, GraphQL::Types::String,
required: false,
default_value: :head,
description: 'The commit ref to get the tree for. Default value is HEAD.'
description: 'Commit ref to get the tree for. Default value is HEAD.'
argument :recursive, GraphQL::Types::Boolean,
required: false,
default_value: false,

View File

@ -11,7 +11,7 @@ module Resolvers
argument :type, Types::Snippets::TypeEnum,
required: false,
description: 'The type of snippet.'
description: 'Type of snippet.'
private

View File

@ -12,13 +12,13 @@ module Types
authorize :read_usage_trends_measurement
field :recorded_at, Types::TimeType, null: true,
description: 'The time the measurement was recorded.'
description: 'Time the measurement was recorded.'
field :count, GraphQL::Types::Int, null: false,
description: 'Object count.'
field :identifier, Types::Admin::Analytics::UsageTrends::MeasurementIdentifierEnum, null: false,
description: 'The type of objects being measured.'
description: 'Type of objects being measured.'
end
end
end

View File

@ -17,12 +17,12 @@ module Types
field :deleted_jobs,
GraphQL::Types::Int,
null: true,
description: 'The number of matching jobs deleted.'
description: 'Number of matching jobs deleted.'
field :queue_size,
GraphQL::Types::Int,
null: true,
description: 'The queue size after processing.'
description: 'Queue size after processing.'
end
end
end

View File

@ -122,12 +122,12 @@ module Types
field :details_url,
GraphQL::Types::String,
null: false,
description: 'The URL of the alert detail page.'
description: 'URL of the alert detail page.'
field :prometheus_alert,
Types::PrometheusAlertType,
null: true,
description: 'The alert condition for Prometheus.'
description: 'Alert condition for Prometheus.'
def notes
object.ordered_notes

View File

@ -13,32 +13,32 @@ module Types
field :name,
GraphQL::Types::String,
null: false,
description: 'The emoji name.'
description: 'Emoji name.'
field :description,
GraphQL::Types::String,
null: false,
description: 'The emoji description.'
description: 'Emoji description.'
field :unicode,
GraphQL::Types::String,
null: false,
description: 'The emoji in Unicode.'
description: 'Emoji in Unicode.'
field :emoji,
GraphQL::Types::String,
null: false,
description: 'The emoji as an icon.'
description: 'Emoji as an icon.'
field :unicode_version,
GraphQL::Types::String,
null: false,
description: 'The Unicode version for this emoji.'
description: 'Unicode version for this emoji.'
field :user,
Types::UserType,
null: false,
description: 'The user who awarded the emoji.'
description: 'User who awarded the emoji.'
def user
Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.user_id).find

View File

@ -8,7 +8,7 @@ module Types
graphql_name 'CiConfigJobRestriction'
field :refs, [GraphQL::Types::String], null: true,
description: 'The Git refs the job restriction applies to.'
description: 'Git refs the job restriction applies to.'
end
end
end

View File

@ -7,8 +7,8 @@ module Types
graphql_name 'CiConfigStatus'
description 'Values for YAML processor result'
value 'VALID', 'The configuration file is valid.', value: :valid
value 'INVALID', 'The configuration file is not valid.', value: :invalid
value 'VALID', 'Configuration file is valid.', value: :valid
value 'INVALID', 'Configuration file is not valid.', value: :invalid
end
end
end

View File

@ -97,7 +97,7 @@ module Types
type: ::Types::Ci::JobType,
null: true,
authorize: :read_commit_status,
description: 'A specific job in this pipeline, either by name or ID.' do
description: 'Specific job in this pipeline, either by name or ID.' do
argument :id,
type: ::Types::GlobalIDType[::CommitStatus],
required: false,

View File

@ -7,9 +7,9 @@ module Types
graphql_name 'SastUiComponentSize'
description 'Size of UI component in SAST configuration page'
value 'SMALL', description: "The size of UI component in SAST configuration page is small."
value 'MEDIUM', description: "The size of UI component in SAST configuration page is medium."
value 'LARGE', description: "The size of UI component in SAST configuration page is large."
value 'SMALL', description: "Size of UI component in SAST configuration page is small."
value 'MEDIUM', description: "Size of UI component in SAST configuration page is medium."
value 'LARGE', description: "Size of UI component in SAST configuration page is large."
end
end
end

View File

@ -3,7 +3,7 @@
module Types
class CommitActionType < BaseInputObject
argument :action, type: Types::CommitActionModeEnum, required: true,
description: 'The action to perform, create, delete, move, update, chmod.'
description: 'Action to perform: create, delete, move, update, or chmod.'
argument :file_path, type: GraphQL::Types::String, required: true,
description: 'Full path to the file.'
argument :content, type: GraphQL::Types::String, required: false,

View File

@ -5,9 +5,9 @@ module Types
graphql_name 'ContainerRepositoryCleanupStatus'
description 'Status of the tags cleanup of a container repository'
value 'UNSCHEDULED', value: 'cleanup_unscheduled', description: 'The tags cleanup is not scheduled. This is the default state.'
value 'SCHEDULED', value: 'cleanup_scheduled', description: 'The tags cleanup is scheduled and is going to be executed shortly.'
value 'UNFINISHED', value: 'cleanup_unfinished', description: 'The tags cleanup has been partially executed. There are still remaining tags to delete.'
value 'ONGOING', value: 'cleanup_ongoing', description: 'The tags cleanup is ongoing.'
value 'UNSCHEDULED', value: 'cleanup_unscheduled', description: 'Tags cleanup is not scheduled. This is the default state.'
value 'SCHEDULED', value: 'cleanup_scheduled', description: 'Tags cleanup is scheduled and is going to be executed shortly.'
value 'UNFINISHED', value: 'cleanup_unfinished', description: 'Tags cleanup has been partially executed. There are still remaining tags to delete.'
value 'ONGOING', value: 'cleanup_ongoing', description: 'Tags cleanup is ongoing.'
end
end

View File

@ -14,7 +14,7 @@ module Types
field :digest, GraphQL::Types::String, null: true, description: 'Digest of the tag.'
field :revision, GraphQL::Types::String, null: true, description: 'Revision of the tag.'
field :short_revision, GraphQL::Types::String, null: true, description: 'Short revision of the tag.'
field :total_size, GraphQL::Types::BigInt, null: true, description: 'The size of the tag.'
field :total_size, GraphQL::Types::BigInt, null: true, description: 'Size of the tag.'
field :created_at, Types::TimeType, null: true, description: 'Timestamp when the tag was created.'
field :can_delete, GraphQL::Types::Boolean, null: false, description: 'Can the current user delete this tag.'

View File

@ -15,7 +15,7 @@ module Types
field :created_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was created.'
field :updated_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was updated.'
field :expiration_policy_started_at, Types::TimeType, null: true, description: 'Timestamp when the cleanup done by the expiration policy was started on the container repository.'
field :expiration_policy_cleanup_status, Types::ContainerRepositoryCleanupStatusEnum, null: true, description: 'The tags cleanup status for the container repository.'
field :expiration_policy_cleanup_status, Types::ContainerRepositoryCleanupStatusEnum, null: true, description: 'Tags cleanup status for the container repository.'
field :status, Types::ContainerRepositoryStatusEnum, null: true, description: 'Status of the container repository.'
field :tags_count, GraphQL::Types::Int, null: false, description: 'Number of tags associated with this image.'
field :can_delete, GraphQL::Types::Boolean, null: false, description: 'Can the current user delete the container repository.'

View File

@ -9,16 +9,16 @@ module Types
field :id, ::Types::GlobalIDType[::CustomEmoji],
null: false,
description: 'The ID of the emoji.'
description: 'ID of the emoji.'
field :name, GraphQL::Types::String,
null: false,
description: 'The name of the emoji.'
description: 'Name of the emoji.'
field :url, GraphQL::Types::String,
null: false,
method: :file,
description: 'The link to file of the emoji.'
description: 'Link to file of the emoji.'
field :external, GraphQL::Types::Boolean,
null: false,

View File

@ -39,7 +39,8 @@ module SystemNoteHelper
'alert_issue_added' => 'issues',
'new_alert_added' => 'warning',
'severity' => 'information-o',
'cloned' => 'documents'
'cloned' => 'documents',
'issue_type' => 'pencil-square'
}.freeze
def system_note_icon_name(note)

View File

@ -584,9 +584,10 @@ class Issue < ApplicationRecord
confidential_changed?(from: true, to: false)
end
# Ensure that the metrics association is safely created and respecting the unique constraint on issue_id
override :ensure_metrics
def ensure_metrics
return Issue::Metrics.record!(self) if Feature.enabled?(:upsert_issue_metrics, default_enabled: :yaml)
if !association(:metrics).loaded? || metrics.blank?
metrics_record = Issue::Metrics.safe_find_or_create_by(issue: self)
self.metrics = metrics_record

View File

@ -9,6 +9,33 @@ class Issue::Metrics < ApplicationRecord
.or(where(arel_table['first_mentioned_in_commit_at'].gteq(timestamp)))
}
class << self
def record!(issue)
now = connection.quote(Time.current)
first_associated_with_milestone_at = issue.milestone_id.present? ? now : 'NULL'
first_added_to_board_at = issue_assigned_to_list_label?(issue) ? now : 'NULL'
sql = <<~SQL
INSERT INTO #{self.table_name} (issue_id, first_associated_with_milestone_at, first_added_to_board_at, created_at, updated_at)
VALUES (#{issue.id}, #{first_associated_with_milestone_at}, #{first_added_to_board_at}, NOW(), NOW())
ON CONFLICT (issue_id)
DO UPDATE SET
first_associated_with_milestone_at = LEAST(#{self.table_name}.first_associated_with_milestone_at, EXCLUDED.first_associated_with_milestone_at),
first_added_to_board_at = LEAST(#{self.table_name}.first_added_to_board_at, EXCLUDED.first_added_to_board_at),
updated_at = NOW()
RETURNING id
SQL
connection.execute(sql)
end
private
def issue_assigned_to_list_label?(issue)
issue.labels.joins(:lists).exists?
end
end
def record!
if issue.milestone_id.present? && self.first_associated_with_milestone_at.blank?
self.first_associated_with_milestone_at = Time.current
@ -24,10 +51,6 @@ class Issue::Metrics < ApplicationRecord
private
def issue_assigned_to_list_label?
# Avoid another DB lookup when issue.labels are empty by adding a guard clause here
# We can't use issue.labels.empty? because that will cause a `Label Exists?` DB lookup
return false if issue.labels.length == 0 # rubocop:disable Style/ZeroLengthPredicate
issue.labels.includes(:lists).any? { |label| label.lists.present? }
issue.labels.joins(:lists).exists?
end
end

View File

@ -77,6 +77,7 @@ module Issues
end
handle_severity_change(issue, old_severity)
handle_issue_type_change(issue)
end
def handle_assignee_changes(issue, old_assignees)
@ -218,6 +219,16 @@ module Issues
def remove_incident_label?(issue)
issue.issue_type != params[:issue_type] && issue.incident?
end
def handle_issue_type_change(issue)
return unless issue.previous_changes.include?('issue_type')
do_handle_issue_type_change(issue)
end
def do_handle_issue_type_change(issue)
SystemNoteService.change_issue_type(issue, current_user)
end
end
end

View File

@ -331,6 +331,10 @@ module SystemNoteService
::SystemNotes::AlertManagementService.new(noteable: alert, project: alert.project).log_resolving_alert(monitoring_tool)
end
def change_issue_type(issue, author)
::SystemNotes::IssuablesService.new(noteable: issue, project: issue.project, author: author).change_issue_type
end
private
def merge_requests_service(noteable, project, author)

View File

@ -380,6 +380,12 @@ module SystemNotes
create_resource_state_event(status: 'closed', close_auto_resolve_prometheus_alert: true)
end
def change_issue_type
body = "changed issue type to #{noteable.issue_type.humanize(capitalize: false)}"
create_note(NoteSummary.new(noteable, project, author, body, action: 'issue_type'))
end
private
def cross_reference_note_content(gfm_reference)

View File

@ -1,3 +1 @@
= render_if_exists "groups/ee/administration_nav"
= render 'shared/sidebar_toggle_button'

View File

@ -12,17 +12,10 @@ module Gitlab
include GithubImport::Queue
include StageMethods
# The importers to run in this stage. Issues can't be imported earlier
# on as we also use these to enrich pull requests with assigned labels.
IMPORTERS = [
Importer::IssuesImporter,
Importer::DiffNotesImporter
].freeze
# client - An instance of Gitlab::GithubImport::Client.
# project - An instance of Project.
def import(client, project)
waiters = IMPORTERS.each_with_object({}) do |klass, hash|
waiters = importers(project).each_with_object({}) do |klass, hash|
info(project.id, message: "starting importer", importer: klass.name)
waiter = klass.new(project, client).execute
hash[waiter.key] = waiter.jobs_remaining
@ -30,6 +23,25 @@ module Gitlab
AdvanceStageWorker.perform_async(project.id, waiters, :notes)
end
# The importers to run in this stage. Issues can't be imported earlier
# on as we also use these to enrich pull requests with assigned labels.
def importers(project)
[
Importer::IssuesImporter,
diff_notes_importer(project)
]
end
private
def diff_notes_importer(project)
if project.group.present? && Feature.enabled?(:github_importer_single_endpoint_notes_import, project.group, type: :ops, default_enabled: :yaml)
Importer::SingleEndpointDiffNotesImporter
else
Importer::DiffNotesImporter
end
end
end
end
end

View File

@ -15,17 +15,31 @@ module Gitlab
# client - An instance of Gitlab::GithubImport::Client.
# project - An instance of Project.
def import(client, project)
info(project.id, message: "starting importer", importer: 'Importer::NotesImporter')
waiter = Importer::NotesImporter
.new(project, client)
.execute
waiters = importers(project).each_with_object({}) do |klass, hash|
info(project.id, message: "starting importer", importer: klass.name)
waiter = klass.new(project, client).execute
hash[waiter.key] = waiter.jobs_remaining
end
AdvanceStageWorker.perform_async(
project.id,
{ waiter.key => waiter.jobs_remaining },
waiters,
:lfs_objects
)
end
def importers(project)
if project.group.present? && Feature.enabled?(:github_importer_single_endpoint_notes_import, project.group, type: :ops, default_enabled: :yaml)
[
Importer::SingleEndpointMergeRequestNotesImporter,
Importer::SingleEndpointIssueNotesImporter
]
else
[
Importer::NotesImporter
]
end
end
end
end
end

View File

@ -0,0 +1,8 @@
---
name: upsert_issue_metrics
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68509
rollout_issue_url:
milestone: '14.3'
type: development
group: group::project management
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: github_importer_lower_per_page_limit
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67150
rollout_issue_url:
milestone: '14.2'
type: ops
group: group::import
default_enabled: false

View File

@ -0,0 +1,8 @@
---
name: github_importer_single_endpoint_notes_import
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67150
rollout_issue_url:
milestone: '14.2'
type: ops
group: group::import
default_enabled: false

View File

@ -427,7 +427,7 @@ POST /projects/:id/boards/:board_id/lists
NOTE:
Label, assignee and milestone arguments are mutually exclusive,
that is, only one of them are accepted in a request.
Check the [Issue Board documentation](../user/project/issue_board.md)
Check the [issue board documentation](../user/project/issue_board.md)
for more information regarding the required license for each list type.
```shell

View File

@ -261,7 +261,7 @@ Returns [`PackageDetailsType`](#packagedetailstype).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="querypackageid"></a>`id` | [`PackagesPackageID!`](#packagespackageid) | The global ID of the package. |
| <a id="querypackageid"></a>`id` | [`PackagesPackageID!`](#packagespackageid) | Global ID of the package. |
### `Query.project`
@ -373,11 +373,11 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="querysnippetsauthorid"></a>`authorId` | [`UserID`](#userid) | The ID of an author. |
| <a id="querysnippetsauthorid"></a>`authorId` | [`UserID`](#userid) | ID of an author. |
| <a id="querysnippetsexplore"></a>`explore` | [`Boolean`](#boolean) | Explore personal snippets. |
| <a id="querysnippetsids"></a>`ids` | [`[SnippetID!]`](#snippetid) | Array of global snippet IDs. For example, `gid://gitlab/ProjectSnippet/1`. |
| <a id="querysnippetsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | The ID of a project. |
| <a id="querysnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | The type of snippet. |
| <a id="querysnippetsprojectid"></a>`projectId` | [`ProjectID`](#projectid) | ID of a project. |
| <a id="querysnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
| <a id="querysnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
### `Query.timelogs`
@ -654,7 +654,7 @@ Input type: `AwardEmojiAddInput`
| ---- | ---- | ----------- |
| <a id="mutationawardemojiaddawardableid"></a>`awardableId` | [`AwardableID!`](#awardableid) | Global ID of the awardable resource. |
| <a id="mutationawardemojiaddclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationawardemojiaddname"></a>`name` | [`String!`](#string) | The emoji name. |
| <a id="mutationawardemojiaddname"></a>`name` | [`String!`](#string) | Emoji name. |
#### Fields
@ -674,7 +674,7 @@ Input type: `AwardEmojiRemoveInput`
| ---- | ---- | ----------- |
| <a id="mutationawardemojiremoveawardableid"></a>`awardableId` | [`AwardableID!`](#awardableid) | Global ID of the awardable resource. |
| <a id="mutationawardemojiremoveclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationawardemojiremovename"></a>`name` | [`String!`](#string) | The emoji name. |
| <a id="mutationawardemojiremovename"></a>`name` | [`String!`](#string) | Emoji name. |
#### Fields
@ -694,7 +694,7 @@ Input type: `AwardEmojiToggleInput`
| ---- | ---- | ----------- |
| <a id="mutationawardemojitoggleawardableid"></a>`awardableId` | [`AwardableID!`](#awardableid) | Global ID of the awardable resource. |
| <a id="mutationawardemojitoggleclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationawardemojitogglename"></a>`name` | [`String!`](#string) | The emoji name. |
| <a id="mutationawardemojitogglename"></a>`name` | [`String!`](#string) | Emoji name. |
#### Fields
@ -7418,7 +7418,7 @@ Describes an alert from the project's Alert Management.
| <a id="alertmanagementalertcreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp the alert was created. |
| <a id="alertmanagementalertdescription"></a>`description` | [`String`](#string) | Description of the alert. |
| <a id="alertmanagementalertdetails"></a>`details` | [`JSON`](#json) | Alert details. |
| <a id="alertmanagementalertdetailsurl"></a>`detailsUrl` | [`String!`](#string) | The URL of the alert detail page. |
| <a id="alertmanagementalertdetailsurl"></a>`detailsUrl` | [`String!`](#string) | URL of the alert detail page. |
| <a id="alertmanagementalertdiscussions"></a>`discussions` | [`DiscussionConnection!`](#discussionconnection) | All discussions on this noteable. (see [Connections](#connections)) |
| <a id="alertmanagementalertendedat"></a>`endedAt` | [`Time`](#time) | Timestamp the alert ended. |
| <a id="alertmanagementalertenvironment"></a>`environment` | [`Environment`](#environment) | Environment for the alert. |
@ -7430,7 +7430,7 @@ Describes an alert from the project's Alert Management.
| <a id="alertmanagementalertmetricsdashboardurl"></a>`metricsDashboardUrl` | [`String`](#string) | URL for metrics embed for the alert. |
| <a id="alertmanagementalertmonitoringtool"></a>`monitoringTool` | [`String`](#string) | Monitoring tool the alert came from. |
| <a id="alertmanagementalertnotes"></a>`notes` | [`NoteConnection!`](#noteconnection) | All notes on this noteable. (see [Connections](#connections)) |
| <a id="alertmanagementalertprometheusalert"></a>`prometheusAlert` | [`PrometheusAlert`](#prometheusalert) | The alert condition for Prometheus. |
| <a id="alertmanagementalertprometheusalert"></a>`prometheusAlert` | [`PrometheusAlert`](#prometheusalert) | Alert condition for Prometheus. |
| <a id="alertmanagementalertrunbook"></a>`runbook` | [`String`](#string) | Runbook for the alert as defined in alert details. |
| <a id="alertmanagementalertservice"></a>`service` | [`String`](#string) | Service the alert came from. |
| <a id="alertmanagementalertseverity"></a>`severity` | [`AlertManagementSeverity`](#alertmanagementseverity) | Severity of the alert. |
@ -7455,12 +7455,12 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="alertmanagementalerttodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | The action to be filtered. |
| <a id="alertmanagementalerttodosauthorid"></a>`authorId` | [`[ID!]`](#id) | The ID of an author. |
| <a id="alertmanagementalerttodosgroupid"></a>`groupId` | [`[ID!]`](#id) | The ID of a group. |
| <a id="alertmanagementalerttodosprojectid"></a>`projectId` | [`[ID!]`](#id) | The ID of a project. |
| <a id="alertmanagementalerttodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | The state of the todo. |
| <a id="alertmanagementalerttodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | The type of the todo. |
| <a id="alertmanagementalerttodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | Action to be filtered. |
| <a id="alertmanagementalerttodosauthorid"></a>`authorId` | [`[ID!]`](#id) | ID of an author. |
| <a id="alertmanagementalerttodosgroupid"></a>`groupId` | [`[ID!]`](#id) | ID of a group. |
| <a id="alertmanagementalerttodosprojectid"></a>`projectId` | [`[ID!]`](#id) | ID of a project. |
| <a id="alertmanagementalerttodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | State of the todo. |
| <a id="alertmanagementalerttodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | Type of the todo. |
### `AlertManagementAlertStatusCountsType`
@ -7580,12 +7580,12 @@ An emoji awarded by a user.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="awardemojidescription"></a>`description` | [`String!`](#string) | The emoji description. |
| <a id="awardemojiemoji"></a>`emoji` | [`String!`](#string) | The emoji as an icon. |
| <a id="awardemojiname"></a>`name` | [`String!`](#string) | The emoji name. |
| <a id="awardemojiunicode"></a>`unicode` | [`String!`](#string) | The emoji in Unicode. |
| <a id="awardemojiunicodeversion"></a>`unicodeVersion` | [`String!`](#string) | The Unicode version for this emoji. |
| <a id="awardemojiuser"></a>`user` | [`UserCore!`](#usercore) | The user who awarded the emoji. |
| <a id="awardemojidescription"></a>`description` | [`String!`](#string) | Emoji description. |
| <a id="awardemojiemoji"></a>`emoji` | [`String!`](#string) | Emoji as an icon. |
| <a id="awardemojiname"></a>`name` | [`String!`](#string) | Emoji name. |
| <a id="awardemojiunicode"></a>`unicode` | [`String!`](#string) | Emoji in Unicode. |
| <a id="awardemojiunicodeversion"></a>`unicodeVersion` | [`String!`](#string) | Unicode version for this emoji. |
| <a id="awardemojiuser"></a>`user` | [`UserCore!`](#usercore) | User who awarded the emoji. |
### `BaseService`
@ -7975,7 +7975,7 @@ Represents the total number of issues and their weights for a particular day.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="ciconfigjobrestrictionrefs"></a>`refs` | [`[String!]`](#string) | The Git refs the job restriction applies to. |
| <a id="ciconfigjobrestrictionrefs"></a>`refs` | [`[String!]`](#string) | Git refs the job restriction applies to. |
### `CiConfigNeed`
@ -8326,7 +8326,7 @@ A container repository.
| ---- | ---- | ----------- |
| <a id="containerrepositorycandelete"></a>`canDelete` | [`Boolean!`](#boolean) | Can the current user delete the container repository. |
| <a id="containerrepositorycreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp when the container repository was created. |
| <a id="containerrepositoryexpirationpolicycleanupstatus"></a>`expirationPolicyCleanupStatus` | [`ContainerRepositoryCleanupStatus`](#containerrepositorycleanupstatus) | The tags cleanup status for the container repository. |
| <a id="containerrepositoryexpirationpolicycleanupstatus"></a>`expirationPolicyCleanupStatus` | [`ContainerRepositoryCleanupStatus`](#containerrepositorycleanupstatus) | Tags cleanup status for the container repository. |
| <a id="containerrepositoryexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
| <a id="containerrepositoryid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
| <a id="containerrepositorylocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
@ -8347,7 +8347,7 @@ Details of a container repository.
| ---- | ---- | ----------- |
| <a id="containerrepositorydetailscandelete"></a>`canDelete` | [`Boolean!`](#boolean) | Can the current user delete the container repository. |
| <a id="containerrepositorydetailscreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp when the container repository was created. |
| <a id="containerrepositorydetailsexpirationpolicycleanupstatus"></a>`expirationPolicyCleanupStatus` | [`ContainerRepositoryCleanupStatus`](#containerrepositorycleanupstatus) | The tags cleanup status for the container repository. |
| <a id="containerrepositorydetailsexpirationpolicycleanupstatus"></a>`expirationPolicyCleanupStatus` | [`ContainerRepositoryCleanupStatus`](#containerrepositorycleanupstatus) | Tags cleanup status for the container repository. |
| <a id="containerrepositorydetailsexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
| <a id="containerrepositorydetailsid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
| <a id="containerrepositorydetailslocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
@ -8375,7 +8375,7 @@ A tag from a container repository.
| <a id="containerrepositorytagpath"></a>`path` | [`String!`](#string) | Path of the tag. |
| <a id="containerrepositorytagrevision"></a>`revision` | [`String`](#string) | Revision of the tag. |
| <a id="containerrepositorytagshortrevision"></a>`shortRevision` | [`String`](#string) | Short revision of the tag. |
| <a id="containerrepositorytagtotalsize"></a>`totalSize` | [`BigInt`](#bigint) | The size of the tag. |
| <a id="containerrepositorytagtotalsize"></a>`totalSize` | [`BigInt`](#bigint) | Size of the tag. |
### `CurrentLicense`
@ -8410,9 +8410,9 @@ A custom emoji uploaded by user.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="customemojiexternal"></a>`external` | [`Boolean!`](#boolean) | Whether the emoji is an external link. |
| <a id="customemojiid"></a>`id` | [`CustomEmojiID!`](#customemojiid) | The ID of the emoji. |
| <a id="customemojiname"></a>`name` | [`String!`](#string) | The name of the emoji. |
| <a id="customemojiurl"></a>`url` | [`String!`](#string) | The link to file of the emoji. |
| <a id="customemojiid"></a>`id` | [`CustomEmojiID!`](#customemojiid) | ID of the emoji. |
| <a id="customemojiname"></a>`name` | [`String!`](#string) | Name of the emoji. |
| <a id="customemojiurl"></a>`url` | [`String!`](#string) | Link to file of the emoji. |
### `DastProfile`
@ -8526,8 +8526,8 @@ The response from the AdminSidekiqQueuesDeleteJobs mutation.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="deletejobsresponsecompleted"></a>`completed` | [`Boolean`](#boolean) | Whether or not the entire queue was processed in time; if not, retrying the same request is safe. |
| <a id="deletejobsresponsedeletedjobs"></a>`deletedJobs` | [`Int`](#int) | The number of matching jobs deleted. |
| <a id="deletejobsresponsequeuesize"></a>`queueSize` | [`Int`](#int) | The queue size after processing. |
| <a id="deletejobsresponsedeletedjobs"></a>`deletedJobs` | [`Int`](#int) | Number of matching jobs deleted. |
| <a id="deletejobsresponsequeuesize"></a>`queueSize` | [`Int`](#int) | Queue size after processing. |
### `Design`
@ -9897,7 +9897,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="grouplabelsincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Include labels from ancestor groups. |
| <a id="grouplabelsincludedescendantgroups"></a>`includeDescendantGroups` | [`Boolean`](#boolean) | Include labels from descendant groups. |
| <a id="grouplabelsonlygrouplabels"></a>`onlyGroupLabels` | [`Boolean`](#boolean) | Include only group level labels. |
| <a id="grouplabelssearchterm"></a>`searchTerm` | [`String`](#string) | A search term to find labels with. |
| <a id="grouplabelssearchterm"></a>`searchTerm` | [`String`](#string) | Search term to find labels with. |
##### `Group.mergeRequests`
@ -9924,7 +9924,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupmergerequestsnot"></a>`not` | [`MergeRequestsResolverNegatedParams`](#mergerequestsresolvernegatedparams) | List of negated arguments. Warning: this argument is experimental and a subject to change in future. |
| <a id="groupmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="groupmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="groupmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="groupmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="groupmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `Group.milestones`
@ -9941,17 +9941,17 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="groupmilestonescontainingdate"></a>`containingDate` | [`Time`](#time) | A date that the milestone contains. |
| <a id="groupmilestonescontainingdate"></a>`containingDate` | [`Time`](#time) | Date the milestone contains. |
| <a id="groupmilestonesenddate"></a>`endDate` **{warning-solid}** | [`Time`](#time) | **Deprecated** in 13.5. Use timeframe.end. |
| <a id="groupmilestonesids"></a>`ids` | [`[ID!]`](#id) | Array of global milestone IDs, e.g., `"gid://gitlab/Milestone/1"`. |
| <a id="groupmilestonesincludeancestors"></a>`includeAncestors` | [`Boolean`](#boolean) | Include milestones from all parent groups. |
| <a id="groupmilestonesincludedescendants"></a>`includeDescendants` | [`Boolean`](#boolean) | Include milestones from all subgroups and subprojects. |
| <a id="groupmilestonessearchtitle"></a>`searchTitle` | [`String`](#string) | A search string for the title. |
| <a id="groupmilestonessearchtitle"></a>`searchTitle` | [`String`](#string) | Search string for the title. |
| <a id="groupmilestonessort"></a>`sort` | [`MilestoneSort`](#milestonesort) | Sort milestones by this criteria. |
| <a id="groupmilestonesstartdate"></a>`startDate` **{warning-solid}** | [`Time`](#time) | **Deprecated** in 13.5. Use timeframe.start. |
| <a id="groupmilestonesstate"></a>`state` | [`MilestoneStateEnum`](#milestonestateenum) | Filter milestones by state. |
| <a id="groupmilestonestimeframe"></a>`timeframe` | [`Timeframe`](#timeframe) | List items overlapping the given timeframe. |
| <a id="groupmilestonestitle"></a>`title` | [`String`](#string) | The title of the milestone. |
| <a id="groupmilestonestitle"></a>`title` | [`String`](#string) | Title of the milestone. |
##### `Group.packages`
@ -10802,7 +10802,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestassigneeassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="mergerequestassigneeassignedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="mergerequestassigneeassignedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="mergerequestassigneeassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestassigneeassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestassigneeassignedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `MergeRequestAssignee.authoredMergeRequests`
@ -10831,7 +10831,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestassigneeauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="mergerequestassigneeauthoredmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="mergerequestassigneeauthoredmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="mergerequestassigneeauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestassigneeauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestassigneeauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `MergeRequestAssignee.reviewRequestedMergeRequests`
@ -10860,7 +10860,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestassigneereviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestassigneereviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="mergerequestassigneereviewrequestedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="mergerequestassigneereviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestassigneereviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestassigneereviewrequestedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `MergeRequestAssignee.snippets`
@ -10878,7 +10878,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestassigneesnippetsids"></a>`ids` | [`[SnippetID!]`](#snippetid) | Array of global snippet IDs. For example, `gid://gitlab/ProjectSnippet/1`. |
| <a id="mergerequestassigneesnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | The type of snippet. |
| <a id="mergerequestassigneesnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
| <a id="mergerequestassigneesnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
##### `MergeRequestAssignee.starredProjects`
@ -10933,12 +10933,12 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestassigneetodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | The action to be filtered. |
| <a id="mergerequestassigneetodosauthorid"></a>`authorId` | [`[ID!]`](#id) | The ID of an author. |
| <a id="mergerequestassigneetodosgroupid"></a>`groupId` | [`[ID!]`](#id) | The ID of a group. |
| <a id="mergerequestassigneetodosprojectid"></a>`projectId` | [`[ID!]`](#id) | The ID of a project. |
| <a id="mergerequestassigneetodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | The state of the todo. |
| <a id="mergerequestassigneetodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | The type of the todo. |
| <a id="mergerequestassigneetodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | Action to be filtered. |
| <a id="mergerequestassigneetodosauthorid"></a>`authorId` | [`[ID!]`](#id) | ID of an author. |
| <a id="mergerequestassigneetodosgroupid"></a>`groupId` | [`[ID!]`](#id) | ID of a group. |
| <a id="mergerequestassigneetodosprojectid"></a>`projectId` | [`[ID!]`](#id) | ID of a project. |
| <a id="mergerequestassigneetodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | State of the todo. |
| <a id="mergerequestassigneetodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | Type of the todo. |
### `MergeRequestDiffRegistry`
@ -11031,7 +11031,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestreviewerassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="mergerequestreviewerassignedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="mergerequestreviewerassignedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="mergerequestreviewerassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestreviewerassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestreviewerassignedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `MergeRequestReviewer.authoredMergeRequests`
@ -11060,7 +11060,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestreviewerauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="mergerequestreviewerauthoredmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="mergerequestreviewerauthoredmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="mergerequestreviewerauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestreviewerauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestreviewerauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `MergeRequestReviewer.reviewRequestedMergeRequests`
@ -11089,7 +11089,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="mergerequestreviewerreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="mergerequestreviewerreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="mergerequestreviewerreviewrequestedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestreviewerreviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="mergerequestreviewerreviewrequestedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `MergeRequestReviewer.snippets`
@ -11107,7 +11107,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestreviewersnippetsids"></a>`ids` | [`[SnippetID!]`](#snippetid) | Array of global snippet IDs. For example, `gid://gitlab/ProjectSnippet/1`. |
| <a id="mergerequestreviewersnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | The type of snippet. |
| <a id="mergerequestreviewersnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
| <a id="mergerequestreviewersnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
##### `MergeRequestReviewer.starredProjects`
@ -11162,12 +11162,12 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mergerequestreviewertodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | The action to be filtered. |
| <a id="mergerequestreviewertodosauthorid"></a>`authorId` | [`[ID!]`](#id) | The ID of an author. |
| <a id="mergerequestreviewertodosgroupid"></a>`groupId` | [`[ID!]`](#id) | The ID of a group. |
| <a id="mergerequestreviewertodosprojectid"></a>`projectId` | [`[ID!]`](#id) | The ID of a project. |
| <a id="mergerequestreviewertodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | The state of the todo. |
| <a id="mergerequestreviewertodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | The type of the todo. |
| <a id="mergerequestreviewertodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | Action to be filtered. |
| <a id="mergerequestreviewertodosauthorid"></a>`authorId` | [`[ID!]`](#id) | ID of an author. |
| <a id="mergerequestreviewertodosgroupid"></a>`groupId` | [`[ID!]`](#id) | ID of a group. |
| <a id="mergerequestreviewertodosprojectid"></a>`projectId` | [`[ID!]`](#id) | ID of a project. |
| <a id="mergerequestreviewertodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | State of the todo. |
| <a id="mergerequestreviewertodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | Type of the todo. |
### `Metadata`
@ -11654,7 +11654,7 @@ Represents a file or directory in the project repository that has been locked.
##### `Pipeline.job`
A specific job in this pipeline, either by name or ID.
Specific job in this pipeline, either by name or ID.
Returns [`CiJob`](#cijob).
@ -12322,7 +12322,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectlabelsincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Include labels from ancestor groups. |
| <a id="projectlabelssearchterm"></a>`searchTerm` | [`String`](#string) | A search term to find labels with. |
| <a id="projectlabelssearchterm"></a>`searchTerm` | [`String`](#string) | Search term to find labels with. |
##### `Project.mergeRequest`
@ -12361,7 +12361,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="projectmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="projectmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="projectmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="projectmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="projectmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `Project.milestones`
@ -12378,16 +12378,16 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectmilestonescontainingdate"></a>`containingDate` | [`Time`](#time) | A date that the milestone contains. |
| <a id="projectmilestonescontainingdate"></a>`containingDate` | [`Time`](#time) | Date the milestone contains. |
| <a id="projectmilestonesenddate"></a>`endDate` **{warning-solid}** | [`Time`](#time) | **Deprecated** in 13.5. Use timeframe.end. |
| <a id="projectmilestonesids"></a>`ids` | [`[ID!]`](#id) | Array of global milestone IDs, e.g., `"gid://gitlab/Milestone/1"`. |
| <a id="projectmilestonesincludeancestors"></a>`includeAncestors` | [`Boolean`](#boolean) | Also return milestones in the project's parent group and its ancestors. |
| <a id="projectmilestonessearchtitle"></a>`searchTitle` | [`String`](#string) | A search string for the title. |
| <a id="projectmilestonessearchtitle"></a>`searchTitle` | [`String`](#string) | Search string for the title. |
| <a id="projectmilestonessort"></a>`sort` | [`MilestoneSort`](#milestonesort) | Sort milestones by this criteria. |
| <a id="projectmilestonesstartdate"></a>`startDate` **{warning-solid}** | [`Time`](#time) | **Deprecated** in 13.5. Use timeframe.start. |
| <a id="projectmilestonesstate"></a>`state` | [`MilestoneStateEnum`](#milestonestateenum) | Filter milestones by state. |
| <a id="projectmilestonestimeframe"></a>`timeframe` | [`Timeframe`](#timeframe) | List items overlapping the given timeframe. |
| <a id="projectmilestonestitle"></a>`title` | [`String`](#string) | The title of the milestone. |
| <a id="projectmilestonestitle"></a>`title` | [`String`](#string) | Title of the milestone. |
##### `Project.networkPolicies`
@ -12483,7 +12483,7 @@ Returns [`Release`](#release).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectreleasetagname"></a>`tagName` | [`String!`](#string) | The name of the tag associated to the release. |
| <a id="projectreleasetagname"></a>`tagName` | [`String!`](#string) | Name of the tag associated to the release. |
##### `Project.releases`
@ -12958,9 +12958,9 @@ Returns [`[String!]`](#string).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="repositorybranchnameslimit"></a>`limit` | [`Int!`](#int) | The number of branch names to return. |
| <a id="repositorybranchnamesoffset"></a>`offset` | [`Int!`](#int) | The number of branch names to skip. |
| <a id="repositorybranchnamessearchpattern"></a>`searchPattern` | [`String!`](#string) | The pattern to search for branch names by. |
| <a id="repositorybranchnameslimit"></a>`limit` | [`Int!`](#int) | Number of branch names to return. |
| <a id="repositorybranchnamesoffset"></a>`offset` | [`Int!`](#int) | Number of branch names to skip. |
| <a id="repositorybranchnamessearchpattern"></a>`searchPattern` | [`String!`](#string) | Pattern to search for branch names by. |
##### `Repository.paginatedTree`
@ -12976,9 +12976,9 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="repositorypaginatedtreepath"></a>`path` | [`String`](#string) | The path to get the tree for. Default value is the root of the repository. |
| <a id="repositorypaginatedtreepath"></a>`path` | [`String`](#string) | Path to get the tree for. Default value is the root of the repository. |
| <a id="repositorypaginatedtreerecursive"></a>`recursive` | [`Boolean`](#boolean) | Used to get a recursive tree. Default is false. |
| <a id="repositorypaginatedtreeref"></a>`ref` | [`String`](#string) | The commit ref to get the tree for. Default value is HEAD. |
| <a id="repositorypaginatedtreeref"></a>`ref` | [`String`](#string) | Commit ref to get the tree for. Default value is HEAD. |
##### `Repository.tree`
@ -12990,9 +12990,9 @@ Returns [`Tree`](#tree).
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="repositorytreepath"></a>`path` | [`String`](#string) | The path to get the tree for. Default value is the root of the repository. |
| <a id="repositorytreepath"></a>`path` | [`String`](#string) | Path to get the tree for. Default value is the root of the repository. |
| <a id="repositorytreerecursive"></a>`recursive` | [`Boolean`](#boolean) | Used to get a recursive tree. Default is false. |
| <a id="repositorytreeref"></a>`ref` | [`String`](#string) | The commit ref to get the tree for. Default value is HEAD. |
| <a id="repositorytreeref"></a>`ref` | [`String`](#string) | Commit ref to get the tree for. Default value is HEAD. |
### `RepositoryBlob`
@ -13834,8 +13834,8 @@ Represents a recorded measurement (object count) for the Admins.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usagetrendsmeasurementcount"></a>`count` | [`Int!`](#int) | Object count. |
| <a id="usagetrendsmeasurementidentifier"></a>`identifier` | [`MeasurementIdentifier!`](#measurementidentifier) | The type of objects being measured. |
| <a id="usagetrendsmeasurementrecordedat"></a>`recordedAt` | [`Time`](#time) | The time the measurement was recorded. |
| <a id="usagetrendsmeasurementidentifier"></a>`identifier` | [`MeasurementIdentifier!`](#measurementidentifier) | Type of objects being measured. |
| <a id="usagetrendsmeasurementrecordedat"></a>`recordedAt` | [`Time`](#time) | Time the measurement was recorded. |
### `UserCallout`
@ -13901,7 +13901,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="usercoreassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="usercoreassignedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="usercoreassignedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="usercoreassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="usercoreassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="usercoreassignedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `UserCore.authoredMergeRequests`
@ -13930,7 +13930,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="usercoreauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="usercoreauthoredmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="usercoreauthoredmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="usercoreauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="usercoreauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="usercoreauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `UserCore.reviewRequestedMergeRequests`
@ -13959,7 +13959,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="usercorereviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="usercorereviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="usercorereviewrequestedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="usercorereviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="usercorereviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="usercorereviewrequestedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
##### `UserCore.snippets`
@ -13977,7 +13977,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usercoresnippetsids"></a>`ids` | [`[SnippetID!]`](#snippetid) | Array of global snippet IDs. For example, `gid://gitlab/ProjectSnippet/1`. |
| <a id="usercoresnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | The type of snippet. |
| <a id="usercoresnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
| <a id="usercoresnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
##### `UserCore.starredProjects`
@ -14032,12 +14032,12 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usercoretodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | The action to be filtered. |
| <a id="usercoretodosauthorid"></a>`authorId` | [`[ID!]`](#id) | The ID of an author. |
| <a id="usercoretodosgroupid"></a>`groupId` | [`[ID!]`](#id) | The ID of a group. |
| <a id="usercoretodosprojectid"></a>`projectId` | [`[ID!]`](#id) | The ID of a project. |
| <a id="usercoretodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | The state of the todo. |
| <a id="usercoretodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | The type of the todo. |
| <a id="usercoretodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | Action to be filtered. |
| <a id="usercoretodosauthorid"></a>`authorId` | [`[ID!]`](#id) | ID of an author. |
| <a id="usercoretodosgroupid"></a>`groupId` | [`[ID!]`](#id) | ID of a group. |
| <a id="usercoretodosprojectid"></a>`projectId` | [`[ID!]`](#id) | ID of a project. |
| <a id="usercoretodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | State of the todo. |
| <a id="usercoretodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | Type of the todo. |
### `UserMergeRequestInteraction`
@ -14699,8 +14699,8 @@ Values for YAML processor result.
| Value | Description |
| ----- | ----------- |
| <a id="ciconfigstatusinvalid"></a>`INVALID` | The configuration file is not valid. |
| <a id="ciconfigstatusvalid"></a>`VALID` | The configuration file is valid. |
| <a id="ciconfigstatusinvalid"></a>`INVALID` | Configuration file is not valid. |
| <a id="ciconfigstatusvalid"></a>`VALID` | Configuration file is valid. |
### `CiJobStatus`
@ -14828,10 +14828,10 @@ Status of the tags cleanup of a container repository.
| Value | Description |
| ----- | ----------- |
| <a id="containerrepositorycleanupstatusongoing"></a>`ONGOING` | The tags cleanup is ongoing. |
| <a id="containerrepositorycleanupstatusscheduled"></a>`SCHEDULED` | The tags cleanup is scheduled and is going to be executed shortly. |
| <a id="containerrepositorycleanupstatusunfinished"></a>`UNFINISHED` | The tags cleanup has been partially executed. There are still remaining tags to delete. |
| <a id="containerrepositorycleanupstatusunscheduled"></a>`UNSCHEDULED` | The tags cleanup is not scheduled. This is the default state. |
| <a id="containerrepositorycleanupstatusongoing"></a>`ONGOING` | Tags cleanup is ongoing. |
| <a id="containerrepositorycleanupstatusscheduled"></a>`SCHEDULED` | Tags cleanup is scheduled and is going to be executed shortly. |
| <a id="containerrepositorycleanupstatusunfinished"></a>`UNFINISHED` | Tags cleanup has been partially executed. There are still remaining tags to delete. |
| <a id="containerrepositorycleanupstatusunscheduled"></a>`UNSCHEDULED` | Tags cleanup is not scheduled. This is the default state. |
### `ContainerRepositorySort`
@ -15610,9 +15610,9 @@ Size of UI component in SAST configuration page.
| Value | Description |
| ----- | ----------- |
| <a id="sastuicomponentsizelarge"></a>`LARGE` | The size of UI component in SAST configuration page is large. |
| <a id="sastuicomponentsizemedium"></a>`MEDIUM` | The size of UI component in SAST configuration page is medium. |
| <a id="sastuicomponentsizesmall"></a>`SMALL` | The size of UI component in SAST configuration page is small. |
| <a id="sastuicomponentsizelarge"></a>`LARGE` | Size of UI component in SAST configuration page is large. |
| <a id="sastuicomponentsizemedium"></a>`MEDIUM` | Size of UI component in SAST configuration page is medium. |
| <a id="sastuicomponentsizesmall"></a>`SMALL` | Size of UI component in SAST configuration page is small. |
### `SecurityReportTypeEnum`
@ -16817,7 +16817,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="userassignedmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="userassignedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="userassignedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="userassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="userassignedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="userassignedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
###### `User.authoredMergeRequests`
@ -16846,7 +16846,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="userauthoredmergerequestsreviewerusername"></a>`reviewerUsername` | [`String`](#string) | Username of the reviewer. |
| <a id="userauthoredmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="userauthoredmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="userauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="userauthoredmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="userauthoredmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
###### `User.reviewRequestedMergeRequests`
@ -16875,7 +16875,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="userreviewrequestedmergerequestsprojectpath"></a>`projectPath` | [`String`](#string) | The full-path of the project the authored merge requests should be in. Incompatible with projectId. |
| <a id="userreviewrequestedmergerequestssort"></a>`sort` | [`MergeRequestSort`](#mergerequestsort) | Sort merge requests by this criteria. |
| <a id="userreviewrequestedmergerequestssourcebranches"></a>`sourceBranches` | [`[String!]`](#string) | Array of source branch names. All resolved merge requests will have one of these branches as their source. |
| <a id="userreviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | A merge request state. If provided, all resolved merge requests will have this state. |
| <a id="userreviewrequestedmergerequestsstate"></a>`state` | [`MergeRequestState`](#mergerequeststate) | Merge request state. If provided, all resolved merge requests will have this state. |
| <a id="userreviewrequestedmergerequeststargetbranches"></a>`targetBranches` | [`[String!]`](#string) | Array of target branch names. All resolved merge requests will have one of these branches as their target. |
###### `User.snippets`
@ -16893,7 +16893,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usersnippetsids"></a>`ids` | [`[SnippetID!]`](#snippetid) | Array of global snippet IDs. For example, `gid://gitlab/ProjectSnippet/1`. |
| <a id="usersnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | The type of snippet. |
| <a id="usersnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
| <a id="usersnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
###### `User.starredProjects`
@ -16948,12 +16948,12 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="usertodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | The action to be filtered. |
| <a id="usertodosauthorid"></a>`authorId` | [`[ID!]`](#id) | The ID of an author. |
| <a id="usertodosgroupid"></a>`groupId` | [`[ID!]`](#id) | The ID of a group. |
| <a id="usertodosprojectid"></a>`projectId` | [`[ID!]`](#id) | The ID of a project. |
| <a id="usertodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | The state of the todo. |
| <a id="usertodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | The type of the todo. |
| <a id="usertodosaction"></a>`action` | [`[TodoActionEnum!]`](#todoactionenum) | Action to be filtered. |
| <a id="usertodosauthorid"></a>`authorId` | [`[ID!]`](#id) | ID of an author. |
| <a id="usertodosgroupid"></a>`groupId` | [`[ID!]`](#id) | ID of a group. |
| <a id="usertodosprojectid"></a>`projectId` | [`[ID!]`](#id) | ID of a project. |
| <a id="usertodosstate"></a>`state` | [`[TodoStateEnum!]`](#todostateenum) | State of the todo. |
| <a id="usertodostype"></a>`type` | [`[TodoTargetEnum!]`](#todotargetenum) | Type of the todo. |
## Input types
@ -17007,7 +17007,7 @@ Field that are available while modifying the custom mapping attributes for an HT
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="commitactionaction"></a>`action` | [`CommitActionMode!`](#commitactionmode) | The action to perform, create, delete, move, update, chmod. |
| <a id="commitactionaction"></a>`action` | [`CommitActionMode!`](#commitactionmode) | Action to perform: create, delete, move, update, or chmod. |
| <a id="commitactioncontent"></a>`content` | [`String`](#string) | Content of the file. |
| <a id="commitactionencoding"></a>`encoding` | [`CommitEncoding`](#commitencoding) | Encoding of the file. Default is text. |
| <a id="commitactionexecutefilemode"></a>`executeFilemode` | [`Boolean`](#boolean) | Enables/disables the execute flag on the file. |

View File

@ -244,7 +244,7 @@ Example response:
## Create a group issue board **(PREMIUM)**
Creates a Group Issue Board.
Creates a group issue board.
```plaintext
POST /groups/:id/boards
@ -283,7 +283,7 @@ Example response:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/5954) in GitLab 11.1.
Updates a Group Issue Board.
Updates a group issue board.
```plaintext
PUT /groups/:id/boards/:board_id
@ -351,7 +351,7 @@ Example response:
## Delete a group issue board **(PREMIUM)**
Deletes a Group Issue Board.
Deletes a group issue board.
```plaintext
DELETE /groups/:id/boards/:board_id
@ -452,7 +452,7 @@ Example response:
## New group issue board list
Creates a new Issue Board list.
Creates an issue board list.
```plaintext
POST /groups/:id/boards/:board_id/lists
@ -493,7 +493,7 @@ Example response:
## Edit group issue board list
Updates an existing Issue Board list. This call is used to change list position.
Updates an existing issue board list. This call is used to change list position.
```plaintext
PUT /groups/:id/boards/:board_id/lists/:list_id

View File

@ -88,7 +88,7 @@ With the purpose of being [respectful of others' time](https://about.gitlab.com/
GitLab architecture.
1. Add a diagram to the issue and ask a frontend maintainer in the Slack channel `#frontend_maintainers` about it.
![Diagram of Issue Boards Architecture](img/boards_diagram.png)
![Diagram of issue boards architecture](img/boards_diagram.png)
1. Don't take more than one week between starting work on a feature and
sharing a Merge Request with a reviewer or a maintainer.

View File

@ -272,3 +272,11 @@ The last log entry reports the number of objects fetched and imported:
"import_stage": "Gitlab::GithubImport::Stage::FinishImportWorker"
}
```
## Errors when importing large projects
The GitHub importer may encounter errors when importing large projects. For help with this, see the
documentation for the following use cases:
- [Alternative way to import notes and diff notes](../user/project/import/github.md#alternative-way-to-import-notes-and-diff-notes)
- [Reduce GitHub API request objects per page](../user/project/import/github.md#reduce-github-api-request-objects-per-page)

View File

@ -483,7 +483,7 @@ https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#test-sn
### Performance
We use the [AsyncEmitter](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/ruby-tracker//emitters/#the-asyncemitter-class) when tracking events, which allows for instrumentation calls to be run in a background thread. This is still an active area of development.
We use the [AsyncEmitter](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/ruby-tracker/emitters/#the-asyncemitter-class) when tracking events, which allows for instrumentation calls to be run in a background thread. This is still an active area of development.
## Developing and testing Snowplow

View File

@ -826,4 +826,4 @@ A more extensive guide on understanding query plans can be found in
the [presentation](https://public.dalibo.com/exports/conferences/_archives/_2012/201211_explain/understanding_explain.pdf)
from [Dalibo.org](https://www.dalibo.com/en/).
Depesz's blog also has a good [section](https://www.depesz.com/tag/unexplainable) dedicated to query plans.
Depesz's blog also has a good [section](https://www.depesz.com/tag/unexplainable/) dedicated to query plans.

View File

@ -321,7 +321,7 @@ For the listed web browsers, GitLab supports:
NOTE:
We don't support running GitLab with JavaScript disabled in the browser and have no plans of supporting that
in the future because we have features such as Issue Boards which require JavaScript extensively.
in the future because we have features such as issue boards which require JavaScript extensively.
<!-- ## Troubleshooting

View File

@ -44,7 +44,7 @@ With the Gitpod integration enabled for your GitLab instance, to enable it for y
For GitLab self-managed instances, a GitLab administrator needs to:
1. Set up a Gitpod instance to integrate with GitLab. Refer to the [Gitpod documentation](https://www.gitpod.io/docs/self-hosted/latest/self-hosted/)
1. Set up a Gitpod instance to integrate with GitLab. Refer to the [Gitpod documentation](https://www.gitpod.io/docs/self-hosted/latest)
to get your instance up and running.
1. Enable it in GitLab:
1. On the top bar, select **Menu >** **{admin}** **Admin**.

View File

@ -101,7 +101,7 @@ If you do not have an existing SSH key pair, generate a new one.
You can also dedicate the SSH key pair to a [specific host](#configure-ssh-to-point-to-a-different-directory).
1. Specify a [passphrase](https://www.ssh.com/ssh/passphrase):
1. Specify a [passphrase](https://www.ssh.com/academy/ssh/passphrase):
```plaintext
Enter passphrase (empty for no passphrase):

View File

@ -32,7 +32,7 @@ the tiers are no longer mentioned in GitLab documentation:
- [Overriding user permissions](../user/group/index.md#override-user-permissions)
- [User contribution analytics](../user/group/contribution_analytics/index.md)
- [Kerberos integration](../integration/kerberos.md)
- Issue Boards:
- Issue boards:
- [Configurable issue boards](../user/project/issue_board.md#configurable-issue-boards)
- [Sum of issue weights](../user/project/issue_board.md#sum-of-issue-weights)
- [Work In Progress limits](../user/project/issue_board.md#work-in-progress-limits)

View File

@ -64,7 +64,7 @@ Items aren't included in the stage time calculation if they have not reached the
| Stage | Description |
|---------|---------------|
| Issue | Measures the median time between creating an issue and taking action to solve it, by either labeling it or adding it to a milestone, whichever comes first. The label is tracked only if it already includes an [Issue Board list](../project/issue_board.md) created for it. |
| Issue | Measures the median time between creating an issue and taking action to solve it, by either labeling it or adding it to a milestone, whichever comes first. The label is tracked only if it already includes an [issue board list](../project/issue_board.md) created for it. |
| Plan | Measures the median time between the action you took for the previous stage, and pushing the first commit to the branch. That first branch commit triggers the separation between **Plan** and **Code**, and at least one of the commits in the branch must include the related issue number (such as `#42`). If the issue number is *not* included in a commit, that data is not included in the measurement time of the stage. |
| Code | Measures the median time between pushing a first commit (previous stage) and creating a merge request (MR). The process is tracked with the [issue closing pattern](../project/issues/managing_issues.md#closing-issues-automatically) in the description of the merge request. For example, if the issue is closed with `Closes #xxx`, it's assumed that `xxx` is issue number for the merge request). If there is no closing pattern, the start time is set to the create time of the first commit. |
| Test | Essentially the start to finish time for all pipelines. Measures the median time to run the entire pipeline for that project. Related to the time required by GitLab CI/CD to run every job for the commits pushed to that merge request, as defined in the previous stage. |
@ -85,7 +85,7 @@ How this works:
In short, the Value Stream Analytics dashboard tracks data related to [GitLab flow](../../topics/gitlab_flow.md). It does not include data for:
- Merge requests that do not close an issue.
- Issues that do not include labels present in the Issue Board
- Issues that do not include labels present in the issue board.
- Issues without a milestone.
- Staging stages, in projects without a [production environment](#how-the-production-environment-is-identified).

View File

@ -4,7 +4,7 @@ group: Product Planning
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Epic Boards **(PREMIUM)**
# Epic boards **(PREMIUM)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5067) in GitLab 13.10.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/290039) in GitLab 14.1.
@ -54,7 +54,7 @@ Prerequisites:
To delete the active epic board:
1. Select the dropdown with the current board name in the upper left corner of the Epic Boards page.
1. Select the dropdown with the current board name in the upper left corner of the epic boards page.
1. Select **Delete board**.
1. Select **Delete**.

View File

@ -64,7 +64,7 @@ You can also consult the [group permissions table](../../permissions.md#group-me
## Related topics
- [Manage epics](manage_epics.md) and multi-level child epics.
- Create workflows with [Epic Boards](epic_boards.md).
- Create workflows with [epic boards](epic_boards.md).
- [Turn on notifications](../../profile/notifications.md) for about epic events.
- [Award an emoji](../../award_emojis.md) to an epic or its comments.
- Collaborate on an epic by posting comments in a [thread](../../discussions/index.md).

View File

@ -113,7 +113,7 @@ Each stage of Value Stream Analytics is further described in the table below.
| **Stage** | **Description** |
| --------- | --------------- |
| Issue | Measures the median time between creating an issue and taking action to solve it, by either labeling it or adding it to a milestone, whatever comes first. The label is tracked only if it already has an [Issue Board list](../../project/issue_board.md) created for it. |
| Issue | Measures the median time between creating an issue and taking action to solve it, by either labeling it or adding it to a milestone, whatever comes first. The label is tracked only if it already has an [issue board list](../../project/issue_board.md) created for it. |
| Plan | Measures the median time between the action you took for the previous stage, and pushing the first commit to the branch. The very first commit of the branch is the one that triggers the separation between **Plan** and **Code**, and at least one of the commits in the branch needs to contain the related issue number (for example, `#42`). If none of the commits in the branch mention the related issue number, it is not considered to the measurement time of the stage. |
| Code | Measures the median time between pushing a first commit (previous stage) and creating a merge request (MR) related to that commit. The key to keep the process tracked is to include the [issue closing pattern](../../project/issues/managing_issues.md#closing-issues-automatically) to the description of the merge request (for example, `Closes #xxx`, where `xxx` is the number of the issue related to this merge request). If the closing pattern is not present, then the calculation takes the creation time of the first commit in the merge request as the start time. |
| Test | Measures the median time to run the entire pipeline for that project. It's related to the time GitLab CI/CD takes to run every job for the commits pushed to that merge request defined in the previous stage. It is basically the start->finish time for all pipelines. |
@ -136,7 +136,7 @@ To sum up, anything that doesn't follow [GitLab flow](../../../topics/gitlab_flo
Value Stream Analytics dashboard does not present any data for:
- Merge requests that do not close an issue.
- Issues not labeled with a label present in the Issue Board or for issues not assigned a milestone.
- Issues not labeled with a label present in the issue board or for issues not assigned a milestone.
- Staging stage, if the project has no [production environment](#how-the-production-environment-is-identified).
## How the production environment is identified

View File

@ -43,7 +43,7 @@ GitLab is a Git-based platform that integrates a great number of essential tools
- Hosting code in repositories with version control.
- Tracking proposals for new implementations, bug reports, and feedback with a
fully featured [Issue tracker](project/issues/index.md).
- Organizing and prioritizing with [Issue Boards](project/issue_board.md).
- Organizing and prioritizing with [issue boards](project/issue_board.md).
- Reviewing code in [Merge Requests](project/merge_requests/index.md) with live-preview changes per
branch with [Review Apps](../ci/review_apps/index.md).
- Building, testing, and deploying with built-in [Continuous Integration](../ci/index.md).
@ -58,7 +58,7 @@ With GitLab Enterprise Edition, you can also:
- Improve collaboration with:
- [Merge Request Approvals](project/merge_requests/approvals/index.md).
- [Multiple Assignees for Issues](project/issues/multiple_assignees_for_issues.md).
- [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards).
- [Multiple issue boards](project/issue_board.md#multiple-issue-boards).
- Create formal relationships between issues with [linked issues](project/issues/related_issues.md).
- Use [Burndown Charts](project/milestones/burndown_and_burnup_charts.md) to track progress during a sprint or while working on a new version of their software.
- Leverage [Elasticsearch](../integration/elasticsearch.md) with [Advanced Search](search/advanced_search.md) for faster, more advanced code search across your entire GitLab instance.

View File

@ -242,10 +242,10 @@ to learn more.
Find the current permissions on the Value Stream Analytics dashboard, as described in
[related documentation](analytics/value_stream_analytics.md#permissions).
### Issue Board permissions
### Issue board permissions
Find the current permissions for interacting with the Issue Board feature in the
[Issue Boards permissions page](project/issue_board.md#permissions).
Find the current permissions for interacting with the issue board feature in the
[issue boards permissions page](project/issue_board.md#permissions).
### File Locking permissions **(PREMIUM)**

View File

@ -184,3 +184,51 @@ servers. For 4 servers with 8 cores this means you can import up to 32 objects (
Reducing the time spent in cloning a repository can be done by increasing network throughput, CPU capacity, and disk
performance (by using high performance SSDs, for example) of the disks that store the Git repositories (for your GitLab instance).
Increasing the number of Sidekiq workers will *not* reduce the time spent cloning repositories.
## Alternative way to import notes and diff notes
When GitHub Importer runs on extremely large projects not all notes & diff notes can be imported due to GitHub API `issues_comments` & `pull_requests_comments` endpoints limitation.
Not all pages can be fetched due to the following error coming from GitHub API: `In order to keep the API fast for everyone, pagination is limited for this resource. Check the rel=last link relation in the Link response header to see how far back you can traverse.`.
Because of that, alternative approach for importing notes & diff notes is available that is behind a feature flag.
Instead of using `issues_comments` & `pull_requests_comments`, use individual resources `issue_comments` & `pull_request_comments` instead in order to pull notes from 1 object at a time.
This allows us to carry over any missing comments, however it increases the number of network requests required to perform the import, which means its execution is going to be much longer.
In order to use alternative way of importing notes `github_importer_single_endpoint_notes_import` feature flag needs to be enabled on the group project is being imported into.
Start a [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session).
```ruby
group = Group.find_by_full_path('my/group/fullpath')
# Enable
Feature.enable(:github_importer_single_endpoint_notes_import, group)
# Disable
Feature.disable(:github_importer_single_endpoint_notes_import, group)
```
## Reduce GitHub API request objects per page
Some GitHub API endpoints may return a 500 or 502 error for project imports from large repositories.
To reduce the chance of such errors, you can enable the feature flag
`github_importer_lower_per_page_limit` in the group project importing the data. This reduces the
page size from 100 to 50.
To enable this feature flag, start a [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
and run the following `enable` command:
```ruby
group = Group.find_by_full_path('my/group/fullpath')
# Enable
Feature.enable(:github_importer_lower_per_page_limit, group)
```
To disable the feature, run this command:
```ruby
# Disable
Feature.disable(:github_importer_lower_per_page_limit, group)
```

View File

@ -76,7 +76,7 @@ a self-managed instance from an old server to a new server.
The backups produced don't depend on the operating system running GitLab. You can therefore use
the restore method to switch between different operating system distributions or versions, as long
as the same GitLab version [is available for installation](https://docs.gitlab.com/omnibus/package-information/deprecated_os.md).
as the same GitLab version [is available for installation](https://docs.gitlab.com/omnibus/package-information/deprecated_os.html).
To instead merge two self-managed GitLab instances together, use the instructions in
[Migrate from self-managed GitLab to GitLab.com](#migrate-from-self-managed-gitlab-to-gitlabcom).

View File

@ -22,8 +22,8 @@ Projects include the following [features](https://about.gitlab.com/features/):
**Repositories:**
- [Issue tracker](issues/index.md): Discuss implementations with your team.
- [Issue Boards](issue_board.md): Organize and prioritize your workflow.
- [Multiple Issue Boards](issue_board.md#multiple-issue-boards): Create team-specific workflows (Issue Boards) for a project.
- [Issue boards](issue_board.md): Organize and prioritize your workflow.
- [Multiple issue boards](issue_board.md#multiple-issue-boards): Create team-specific workflows (issue boards) for a project.
- [Repositories](repository/index.md): Host your code in a fully-integrated platform.
- [Branches](repository/branches/index.md): Use Git branching strategies to
collaborate on code.
@ -41,8 +41,8 @@ Projects include the following [features](https://about.gitlab.com/features/):
**Issues and merge requests:**
- [Issue tracker](issues/index.md): Discuss implementations with your team.
- [Issue Boards](issue_board.md): Organize and prioritize your workflow.
- [Multiple Issue Boards](issue_board.md#multiple-issue-boards): Create team-specific workflows (Issue Boards) for a project.
- [Issue boards](issue_board.md): Organize and prioritize your workflow.
- [Multiple issue boards](issue_board.md#multiple-issue-boards): Create team-specific workflows (issue boards) for a project.
- [Merge Requests](merge_requests/index.md): Apply a branching
strategy and get reviewed by your team.
- [Merge Request Approvals](merge_requests/approvals/index.md): Ask for approval before
@ -141,7 +141,7 @@ There are numerous [APIs](../../api/index.md) to use with your projects:
- [Threads](../../api/discussions.md)
- [General](../../api/projects.md)
- [Import/export](../../api/project_import_export.md)
- [Issue Board](../../api/boards.md)
- [Issue board](../../api/boards.md)
- [Labels](../../api/labels.md)
- [Markdown](../../api/markdown.md)
- [Merge Requests](../../api/merge_requests.md)

View File

@ -4,9 +4,9 @@ group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# Issue Boards **(FREE)**
# Issue boards **(FREE)**
The GitLab Issue Board is a software project management tool used to plan,
The issue board is a software project management tool used to plan,
organize, and visualize a workflow for a feature or product release.
It can be used as a [Kanban](https://en.wikipedia.org/wiki/Kanban_(development)) or a
[Scrum](https://en.wikipedia.org/wiki/Scrum_(software_development)) board.
@ -46,7 +46,7 @@ To learn more, visit [GitLab Enterprise features for issue boards](#gitlab-enter
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
Watch a [video presentation](https://youtu.be/vjccjHI7aGI) of
the Issue Board feature.
the issue board feature.
## Multiple issue boards
@ -70,7 +70,7 @@ GitLab automatically loads the last board you visited.
To create a new issue board:
1. Click the dropdown with the current board name in the upper left corner of the Issue Boards page.
1. Click the dropdown with the current board name in the upper left corner of the issue boards page.
1. Click **Create new board**.
1. Enter the new board's name and select its scope: milestone, labels, assignee, or weight.
@ -78,7 +78,7 @@ To create a new issue board:
To delete the currently active issue board:
1. Click the dropdown with the current board name in the upper left corner of the Issue Boards page.
1. Click the dropdown with the current board name in the upper left corner of the issue boards page.
1. Click **Delete board**.
1. Click **Delete** to confirm.
@ -195,7 +195,7 @@ card includes:
## Permissions
Users with the [Reporter and higher roles](../permissions.md) can use all the functionality of the
Issue Board feature to create or delete lists. They can also drag issues from one list to another.
issue board feature to create or delete lists. They can also drag issues from one list to another.
## How GitLab orders issues in a list
@ -271,7 +271,7 @@ clicking **View scope**.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
Watch a [video presentation](https://youtu.be/m5UTNCSqaDk) of
the Configurable Issue Board feature.
the configurable issue board feature.
### Focus mode

View File

@ -45,7 +45,7 @@ To learn how the GitLab Strategic Marketing department uses GitLab issues with [
- [Sort issue lists](sorting_issue_lists.md)
- [Search for issues](../../search/index.md#filtering-issue-and-merge-request-lists)
- [Epics](../../group/epics/index.md)
- [Issue Boards](../issue_board.md)
- [Issue boards](../issue_board.md)
- [Issues API](../../../api/issues.md)
- [Configure an external issue tracker](../../../integration/external-issue-tracker.md)
- [Parts of an issue](issue_data_and_actions.md)

View File

@ -129,7 +129,7 @@ element. Due dates can be changed as many times as needed.
### Labels
Categorize issues by giving them [labels](../labels.md). They help to organize workflows,
and they enable you to work with the [GitLab Issue Board](../issue_board.md).
and they enable you to work with the [issue board](../issue_board.md).
Group Labels, which allow you to use the same labels for all projects in the same
group, can also be given to issues. They work exactly the same, but are immediately

View File

@ -44,7 +44,7 @@ There are many ways to get to the New Issue form from a project's page:
![New issue from a project's dashboard](img/new_issue_from_projects_dashboard.png)
- From an **Issue Board**, create a new issue by clicking on the plus sign (**+**) at the top of a list.
- From an **issue board**, create a new issue by clicking on the plus sign (**+**) at the top of a list.
It opens a new issue for that project, pre-labeled with its respective list.
![From the issue board](img/new_issue_from_issue_board.png)
@ -237,10 +237,10 @@ using the close button:
![close issue - button](img/button_close_issue_v13_6.png)
You can also close an issue from the [Issue Boards](../issue_board.md) by dragging an issue card
You can also close an issue from the [issue boards](../issue_board.md) by dragging an issue card
from its list and dropping it into the **Closed** list.
![close issue from the Issue Board](img/close_issue_from_board.gif)
![close issue from the issue board](img/close_issue_from_board.gif)
### Closing issues automatically

View File

@ -213,7 +213,7 @@ Some features depend on others:
- If you disable the **Issues** option, GitLab also removes the following
features:
- **Issue Boards**
- **issue boards**
- [**Service Desk**](#service-desk)
NOTE:

View File

@ -217,12 +217,12 @@ filters them for you as you type.
You can also **Explore** all public and internal groups available in GitLab.com,
and sort them by **Last created**, **Oldest created**, **Last updated**, or **Oldest updated**.
## Issue Boards
## Issue boards
From an [Issue Board](../../user/project/issue_board.md), you can filter issues by **Author**, **Assignee**, **Milestone**, and **Labels**.
From an [issue board](../../user/project/issue_board.md), you can filter issues by **Author**, **Assignee**, **Milestone**, and **Labels**.
You can also filter them by name (issue title), from the field **Filter by name**, which is loaded as you type.
To search for issues to add to lists present in your Issue Board, click
To search for issues to add to lists present in your issue board, click
the button **Add issues** on the top-right of your screen, opening a modal window from which
you can, besides filtering them by **Name**, **Author**, **Assignee**, **Milestone**,
and **Labels**, select multiple issues to add to a list of your choice:

View File

@ -7,6 +7,8 @@ module Gitlab
# The default timeout of the cache keys.
TIMEOUT = 24.hours.to_i
LONGER_TIMEOUT = 72.hours.to_i
WRITE_IF_GREATER_SCRIPT = <<-EOF.strip_heredoc.freeze
local key, value, ttl = KEYS[1], tonumber(ARGV[1]), ARGV[2]
local existing = tonumber(redis.call("get", key))

View File

@ -11,6 +11,7 @@ module Gitlab
Client.new(
token_to_use,
host: host.presence || self.formatted_import_url(project),
per_page: self.per_page(project),
parallel: parallel
)
end
@ -33,5 +34,13 @@ module Gitlab
url.to_s
end
end
def self.per_page(project)
if project.group.present? && Feature.enabled?(:github_importer_lower_per_page_limit, project.group, type: :ops, default_enabled: :yaml)
Gitlab::GithubImport::Client::LOWER_PER_PAGE
else
Gitlab::GithubImport::Client::DEFAULT_PER_PAGE
end
end
end
end

View File

@ -19,6 +19,8 @@ module Gitlab
attr_reader :octokit
SEARCH_MAX_REQUESTS_PER_MINUTE = 30
DEFAULT_PER_PAGE = 100
LOWER_PER_PAGE = 50
# A single page of data and the corresponding page number.
Page = Struct.new(:objects, :number)
@ -44,7 +46,7 @@ module Gitlab
# this value to `true` for parallel importing is crucial as
# otherwise hitting the rate limit will result in a thread
# being blocked in a `sleep()` call for up to an hour.
def initialize(token, host: nil, per_page: 100, parallel: true)
def initialize(token, host: nil, per_page: DEFAULT_PER_PAGE, parallel: true)
@host = host
@octokit = ::Octokit::Client.new(
access_token: token,

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
# This importer is used when `github_importer_single_endpoint_notes_import`
# feature flag is on and replaces `DiffNotesImporter`.
#
# It fetches 1 PR's diff notes at a time using `pull_request_comments` endpoint, which is
# slower than `NotesImporter` but it makes sure all notes are imported,
# as it can sometimes not be the case for `NotesImporter`, because
# `issues_comments` endpoint it uses can be limited by GitHub API
# to not return all available pages.
module Gitlab
module GithubImport
module Importer
class SingleEndpointDiffNotesImporter
include ParallelScheduling
include SingleEndpointNotesImporting
def importer_class
DiffNoteImporter
end
def representation_class
Representation::DiffNote
end
def sidekiq_worker_class
ImportDiffNoteWorker
end
def object_type
:diff_note
end
def collection_method
:pull_request_comments
end
private
def noteables
project.merge_requests.where.not(iid: already_imported_noteables) # rubocop: disable CodeReuse/ActiveRecord
end
def page_counter_id(merge_request)
"merge_request/#{merge_request.id}/#{collection_method}"
end
def notes_imported_cache_key
"github-importer/merge_request/diff_notes/already-imported/#{project.id}"
end
end
end
end
end

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
# This importer is used when `github_importer_single_endpoint_notes_import`
# feature flag is on and replaces `IssuesImporter` issue notes import.
#
# It fetches 1 issue's comments at a time using `issue_comments` endpoint, which is
# slower than `NotesImporter` but it makes sure all notes are imported,
# as it can sometimes not be the case for `NotesImporter`, because
# `issues_comments` endpoint it uses can be limited by GitHub API
# to not return all available pages.
module Gitlab
module GithubImport
module Importer
class SingleEndpointIssueNotesImporter
include ParallelScheduling
include SingleEndpointNotesImporting
def importer_class
NoteImporter
end
def representation_class
Representation::Note
end
def sidekiq_worker_class
ImportNoteWorker
end
def object_type
:note
end
def collection_method
:issue_comments
end
private
def noteables
project.issues.where.not(iid: already_imported_noteables) # rubocop: disable CodeReuse/ActiveRecord
end
def page_counter_id(issue)
"issue/#{issue.id}/#{collection_method}"
end
def notes_imported_cache_key
"github-importer/issue/notes/already-imported/#{project.id}"
end
end
end
end
end

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
# This importer is used when `github_importer_single_endpoint_notes_import`
# feature flag is on and replaces `NotesImporter` MR notes import.
#
# It fetches 1 PR's comments at a time using `issue_comments` endpoint, which is
# slower than `NotesImporter` but it makes sure all notes are imported,
# as it can sometimes not be the case for `NotesImporter`, because
# `issues_comments` endpoint it uses can be limited by GitHub API
# to not return all available pages.
module Gitlab
module GithubImport
module Importer
class SingleEndpointMergeRequestNotesImporter
include ParallelScheduling
include SingleEndpointNotesImporting
def importer_class
NoteImporter
end
def representation_class
Representation::Note
end
def sidekiq_worker_class
ImportNoteWorker
end
def object_type
:note
end
def collection_method
:issue_comments
end
private
def noteables
project.merge_requests.where.not(iid: already_imported_noteables) # rubocop: disable CodeReuse/ActiveRecord
end
def page_counter_id(merge_request)
"merge_request/#{merge_request.id}/#{collection_method}"
end
def notes_imported_cache_key
"github-importer/merge_request/notes/already-imported/#{project.id}"
end
end
end
end
end

View File

@ -23,7 +23,7 @@ module Gitlab
#
# This method will return `nil` if no ID could be found.
def database_id
val = Gitlab::Cache::Import::Caching.read(cache_key)
val = Gitlab::Cache::Import::Caching.read(cache_key, timeout: timeout)
val.to_i if val.present?
end
@ -32,7 +32,7 @@ module Gitlab
#
# database_id - The ID of the corresponding database row.
def cache_database_id(database_id)
Gitlab::Cache::Import::Caching.write(cache_key, database_id)
Gitlab::Cache::Import::Caching.write(cache_key, database_id, timeout: timeout)
end
private
@ -76,6 +76,14 @@ module Gitlab
)
end
end
def timeout
if project.group.present? && ::Feature.enabled?(:github_importer_single_endpoint_notes_import, project.group, type: :ops, default_enabled: :yaml)
Gitlab::Cache::Import::Caching::LONGER_TIMEOUT
else
Gitlab::Cache::Import::Caching::TIMEOUT
end
end
end
end
end

View File

@ -0,0 +1,85 @@
# frozen_string_literal: true
# This module is used in:
# - SingleEndpointDiffNotesImporter
# - SingleEndpointIssueNotesImporter
# - SingleEndpointMergeRequestNotesImporter
#
# `github_importer_single_endpoint_notes_import`
# feature flag is on.
#
# It fetches 1 PR's associated objects at a time using `issue_comments` or
# `pull_request_comments` endpoint, which is slower than `NotesImporter`
# but it makes sure all notes are imported, as it can sometimes not be
# the case for `NotesImporter`, because `issues_comments` endpoint
# it uses can be limited by GitHub API to not return all available pages.
module Gitlab
module GithubImport
module SingleEndpointNotesImporting
BATCH_SIZE = 100
def each_object_to_import
each_notes_page do |page|
page.objects.each do |note|
next if already_imported?(note)
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
yield(note)
mark_as_imported(note)
end
end
end
def id_for_already_imported_cache(note)
note.id
end
private
def each_notes_page
noteables.each_batch(of: BATCH_SIZE, column: :iid) do |batch|
batch.each do |noteable|
# The page counter needs to be scoped by noteable to avoid skipping
# pages of notes from already imported noteables.
page_counter = PageCounter.new(project, page_counter_id(noteable))
repo = project.import_source
options = collection_options.merge(page: page_counter.current)
client.each_page(collection_method, repo, noteable.iid, options) do |page|
next unless page_counter.set(page.number)
yield page
end
mark_notes_imported(noteable)
end
end
end
def mark_notes_imported(noteable)
Gitlab::Cache::Import::Caching.set_add(
notes_imported_cache_key,
noteable.iid
)
end
def already_imported_noteables
Gitlab::Cache::Import::Caching.values_from_set(notes_imported_cache_key)
end
def noteables
NotImplementedError
end
def notes_imported_cache_key
NotImplementedError
end
def page_counter_id(noteable)
NotImplementedError
end
end
end
end

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointDiffNotesImporter do
let(:client) { double }
let(:project) { create(:project, import_source: 'github/repo') }
subject { described_class.new(project, client) }
it { is_expected.to include_module(Gitlab::GithubImport::ParallelScheduling) }
it { is_expected.to include_module(Gitlab::GithubImport::SingleEndpointNotesImporting) }
it { expect(subject.representation_class).to eq(Gitlab::GithubImport::Representation::DiffNote) }
it { expect(subject.importer_class).to eq(Gitlab::GithubImport::Importer::DiffNoteImporter) }
it { expect(subject.collection_method).to eq(:pull_request_comments) }
it { expect(subject.object_type).to eq(:diff_note) }
it { expect(subject.id_for_already_imported_cache(double(id: 1))).to eq(1) }
describe '#each_object_to_import', :clean_gitlab_redis_cache do
let(:merge_request) do
create(
:merged_merge_request,
iid: 999,
source_project: project,
target_project: project
)
end
let(:note) { double(id: 1) }
let(:page) { double(objects: [note], number: 1) }
it 'fetches data' do
expect(client)
.to receive(:each_page)
.exactly(:once) # ensure to be cached on the second call
.with(:pull_request_comments, 'github/repo', merge_request.iid, page: 1)
.and_yield(page)
expect { |b| subject.each_object_to_import(&b) }.to yield_with_args(note)
subject.each_object_to_import {}
expect(
Gitlab::Cache::Import::Caching.set_includes?(
"github-importer/merge_request/diff_notes/already-imported/#{project.id}",
merge_request.iid
)
).to eq(true)
end
it 'skips cached pages' do
Gitlab::GithubImport::PageCounter
.new(project, "merge_request/#{merge_request.id}/pull_request_comments")
.set(2)
expect(client)
.to receive(:each_page)
.exactly(:once) # ensure to be cached on the second call
.with(:pull_request_comments, 'github/repo', merge_request.iid, page: 2)
subject.each_object_to_import {}
end
it 'skips cached merge requests' do
Gitlab::Cache::Import::Caching.set_add(
"github-importer/merge_request/diff_notes/already-imported/#{project.id}",
merge_request.iid
)
expect(client).not_to receive(:each_page)
subject.each_object_to_import {}
end
end
end

View File

@ -0,0 +1,74 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointIssueNotesImporter do
let(:client) { double }
let(:project) { create(:project, import_source: 'github/repo') }
subject { described_class.new(project, client) }
it { is_expected.to include_module(Gitlab::GithubImport::ParallelScheduling) }
it { is_expected.to include_module(Gitlab::GithubImport::SingleEndpointNotesImporting) }
it { expect(subject.representation_class).to eq(Gitlab::GithubImport::Representation::Note) }
it { expect(subject.importer_class).to eq(Gitlab::GithubImport::Importer::NoteImporter) }
it { expect(subject.collection_method).to eq(:issue_comments) }
it { expect(subject.object_type).to eq(:note) }
it { expect(subject.id_for_already_imported_cache(double(id: 1))).to eq(1) }
describe '#each_object_to_import', :clean_gitlab_redis_cache do
let(:issue) do
create(
:issue,
iid: 999,
project: project
)
end
let(:note) { double(id: 1) }
let(:page) { double(objects: [note], number: 1) }
it 'fetches data' do
expect(client)
.to receive(:each_page)
.exactly(:once) # ensure to be cached on the second call
.with(:issue_comments, 'github/repo', issue.iid, page: 1)
.and_yield(page)
expect { |b| subject.each_object_to_import(&b) }.to yield_with_args(note)
subject.each_object_to_import {}
expect(
Gitlab::Cache::Import::Caching.set_includes?(
"github-importer/issue/notes/already-imported/#{project.id}",
issue.iid
)
).to eq(true)
end
it 'skips cached pages' do
Gitlab::GithubImport::PageCounter
.new(project, "issue/#{issue.id}/issue_comments")
.set(2)
expect(client)
.to receive(:each_page)
.exactly(:once) # ensure to be cached on the second call
.with(:issue_comments, 'github/repo', issue.iid, page: 2)
subject.each_object_to_import {}
end
it 'skips cached merge requests' do
Gitlab::Cache::Import::Caching.set_add(
"github-importer/issue/notes/already-imported/#{project.id}",
issue.iid
)
expect(client).not_to receive(:each_page)
subject.each_object_to_import {}
end
end
end

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::SingleEndpointMergeRequestNotesImporter do
let(:client) { double }
let(:project) { create(:project, import_source: 'github/repo') }
subject { described_class.new(project, client) }
it { is_expected.to include_module(Gitlab::GithubImport::ParallelScheduling) }
it { is_expected.to include_module(Gitlab::GithubImport::SingleEndpointNotesImporting) }
it { expect(subject.representation_class).to eq(Gitlab::GithubImport::Representation::Note) }
it { expect(subject.importer_class).to eq(Gitlab::GithubImport::Importer::NoteImporter) }
it { expect(subject.collection_method).to eq(:issue_comments) }
it { expect(subject.object_type).to eq(:note) }
it { expect(subject.id_for_already_imported_cache(double(id: 1))).to eq(1) }
describe '#each_object_to_import', :clean_gitlab_redis_cache do
let(:merge_request) do
create(
:merge_request,
iid: 999,
source_project: project,
target_project: project
)
end
let(:note) { double(id: 1) }
let(:page) { double(objects: [note], number: 1) }
it 'fetches data' do
expect(client)
.to receive(:each_page)
.exactly(:once) # ensure to be cached on the second call
.with(:issue_comments, 'github/repo', merge_request.iid, page: 1)
.and_yield(page)
expect { |b| subject.each_object_to_import(&b) }.to yield_with_args(note)
subject.each_object_to_import {}
expect(
Gitlab::Cache::Import::Caching.set_includes?(
"github-importer/merge_request/notes/already-imported/#{project.id}",
merge_request.iid
)
).to eq(true)
end
it 'skips cached pages' do
Gitlab::GithubImport::PageCounter
.new(project, "merge_request/#{merge_request.id}/issue_comments")
.set(2)
expect(client)
.to receive(:each_page)
.exactly(:once) # ensure to be cached on the second call
.with(:issue_comments, 'github/repo', merge_request.iid, page: 2)
subject.each_object_to_import {}
end
it 'skips cached merge requests' do
Gitlab::Cache::Import::Caching.set_add(
"github-importer/merge_request/notes/already-imported/#{project.id}",
merge_request.iid
)
expect(client).not_to receive(:each_page)
subject.each_object_to_import {}
end
end
end

View File

@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache do
let(:project) { double(:project, id: 4) }
let(:project) { double(:project, id: 4, group: nil) }
let(:issue) do
double(:issue, issuable_type: MergeRequest, iid: 1)
end
@ -26,15 +26,77 @@ RSpec.describe Gitlab::GithubImport::IssuableFinder, :clean_gitlab_redis_cache d
expect { finder.database_id }.to raise_error(TypeError)
end
context 'when group is present' do
context 'when github_importer_single_endpoint_notes_import feature flag is enabled' do
it 'reads cache value with longer timeout' do
project = create(:project, import_url: 'http://t0ken@github.com/user/repo.git')
group = create(:group, projects: [project])
stub_feature_flags(github_importer_single_endpoint_notes_import: group)
expect(Gitlab::Cache::Import::Caching)
.to receive(:read)
.with(anything, timeout: Gitlab::Cache::Import::Caching::LONGER_TIMEOUT)
described_class.new(project, issue).database_id
end
end
context 'when github_importer_single_endpoint_notes_import feature flag is disabled' do
it 'reads cache value with default timeout' do
project = double(:project, id: 4, group: create(:group))
stub_feature_flags(github_importer_single_endpoint_notes_import: false)
expect(Gitlab::Cache::Import::Caching)
.to receive(:read)
.with(anything, timeout: Gitlab::Cache::Import::Caching::TIMEOUT)
described_class.new(project, issue).database_id
end
end
end
end
describe '#cache_database_id' do
it 'caches the ID of a database row' do
expect(Gitlab::Cache::Import::Caching)
.to receive(:write)
.with('github-import/issuable-finder/4/MergeRequest/1', 10)
.with('github-import/issuable-finder/4/MergeRequest/1', 10, timeout: 86400)
finder.cache_database_id(10)
end
context 'when group is present' do
context 'when github_importer_single_endpoint_notes_import feature flag is enabled' do
it 'caches value with longer timeout' do
project = create(:project, import_url: 'http://t0ken@github.com/user/repo.git')
group = create(:group, projects: [project])
stub_feature_flags(github_importer_single_endpoint_notes_import: group)
expect(Gitlab::Cache::Import::Caching)
.to receive(:write)
.with(anything, anything, timeout: Gitlab::Cache::Import::Caching::LONGER_TIMEOUT)
described_class.new(project, issue).cache_database_id(10)
end
end
context 'when github_importer_single_endpoint_notes_import feature flag is disabled' do
it 'caches value with default timeout' do
project = double(:project, id: 4, group: create(:group))
stub_feature_flags(github_importer_single_endpoint_notes_import: false)
expect(Gitlab::Cache::Import::Caching)
.to receive(:write)
.with(anything, anything, timeout: Gitlab::Cache::Import::Caching::TIMEOUT)
described_class.new(project, issue).cache_database_id(10)
end
end
end
end
end

View File

@ -6,7 +6,7 @@ RSpec.describe Gitlab::GithubImport::SequentialImporter do
describe '#execute' do
it 'imports a project in sequence' do
repository = double(:repository)
project = double(:project, id: 1, repository: repository, import_url: 'http://t0ken@github.another-domain.com/repo-org/repo.git')
project = double(:project, id: 1, repository: repository, import_url: 'http://t0ken@github.another-domain.com/repo-org/repo.git', group: nil)
importer = described_class.new(project, token: 'foo')
expect_next_instance_of(Gitlab::GithubImport::Importer::RepositoryImporter) do |instance|

View File

@ -3,13 +3,17 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport do
before do
stub_feature_flags(github_importer_lower_per_page_limit: false)
end
context 'github.com' do
let(:project) { double(:project, import_url: 'http://t0ken@github.com/user/repo.git', id: 1) }
let(:project) { double(:project, import_url: 'http://t0ken@github.com/user/repo.git', id: 1, group: nil) }
it 'returns a new Client with a custom token' do
expect(described_class::Client)
.to receive(:new)
.with('123', host: nil, parallel: true)
.with('123', host: nil, parallel: true, per_page: 100)
described_class.new_client_for(project, token: '123')
end
@ -23,7 +27,7 @@ RSpec.describe Gitlab::GithubImport do
expect(described_class::Client)
.to receive(:new)
.with('123', host: nil, parallel: true)
.with('123', host: nil, parallel: true, per_page: 100)
described_class.new_client_for(project)
end
@ -45,12 +49,12 @@ RSpec.describe Gitlab::GithubImport do
end
context 'GitHub Enterprise' do
let(:project) { double(:project, import_url: 'http://t0ken@github.another-domain.com/repo-org/repo.git') }
let(:project) { double(:project, import_url: 'http://t0ken@github.another-domain.com/repo-org/repo.git', group: nil) }
it 'returns a new Client with a custom token' do
expect(described_class::Client)
.to receive(:new)
.with('123', host: 'http://github.another-domain.com/api/v3', parallel: true)
.with('123', host: 'http://github.another-domain.com/api/v3', parallel: true, per_page: 100)
described_class.new_client_for(project, token: '123')
end
@ -64,7 +68,7 @@ RSpec.describe Gitlab::GithubImport do
expect(described_class::Client)
.to receive(:new)
.with('123', host: 'http://github.another-domain.com/api/v3', parallel: true)
.with('123', host: 'http://github.another-domain.com/api/v3', parallel: true, per_page: 100)
described_class.new_client_for(project)
end
@ -88,4 +92,37 @@ RSpec.describe Gitlab::GithubImport do
expect(described_class.formatted_import_url(project)).to eq('http://github.another-domain.com/api/v3')
end
end
describe '.per_page' do
context 'when project group is present' do
context 'when github_importer_lower_per_page_limit is enabled' do
it 'returns lower per page value' do
project = create(:project, import_url: 'http://t0ken@github.com/user/repo.git')
group = create(:group, projects: [project])
stub_feature_flags(github_importer_lower_per_page_limit: group)
expect(described_class.per_page(project)).to eq(Gitlab::GithubImport::Client::LOWER_PER_PAGE)
end
end
context 'when github_importer_lower_per_page_limit is disabled' do
it 'returns default per page value' do
project = double(:project, import_url: 'http://t0ken@github.com/user/repo.git', id: 1, group: create(:group))
stub_feature_flags(github_importer_lower_per_page_limit: false)
expect(described_class.per_page(project)).to eq(Gitlab::GithubImport::Client::DEFAULT_PER_PAGE)
end
end
end
context 'when project group is missing' do
it 'returns default per page value' do
project = double(:project, import_url: 'http://t0ken@github.com/user/repo.git', id: 1, group: nil)
expect(described_class.per_page(project)).to eq(Gitlab::GithubImport::Client::DEFAULT_PER_PAGE)
end
end
end
end

View File

@ -34,7 +34,7 @@ RSpec.describe Issue::Metrics do
end
end
describe "when recording the default set of issue metrics on issue save" do
shared_examples "when recording the default set of issue metrics on issue save" do
context "milestones" do
it "records the first time an issue is associated with a milestone" do
time = Time.current
@ -80,20 +80,21 @@ RSpec.describe Issue::Metrics do
expect(metrics.first_added_to_board_at).to be_like_time(time)
end
end
end
describe "#record!" do
it "does not cause an N+1 query" do
label = create(:label)
subject.update!(label_ids: [label.id])
control_count = ActiveRecord::QueryRecorder.new { Issue::Metrics.find_by(issue: subject).record! }.count
additional_labels = create_list(:label, 4)
subject.update!(label_ids: additional_labels.map(&:id))
expect { Issue::Metrics.find_by(issue: subject).record! }.not_to exceed_query_limit(control_count)
end
context 'when upsert_issue_metrics is enabled' do
before do
stub_feature_flags(upsert_issue_metrics: true)
end
it_behaves_like 'when recording the default set of issue metrics on issue save'
end
context 'when upsert_issue_metrics is disabled' do
before do
stub_feature_flags(upsert_issue_metrics: false)
end
it_behaves_like 'when recording the default set of issue metrics on issue save'
end
end

View File

@ -102,7 +102,7 @@ RSpec.describe Issue do
end
it 'records current metrics' do
expect_any_instance_of(Issue::Metrics).to receive(:record!)
expect(Issue::Metrics).to receive(:record!)
create(:issue, project: reusable_project)
end
@ -111,7 +111,6 @@ RSpec.describe Issue do
before do
subject.metrics.delete
subject.reload
subject.metrics # make sure metrics association is cached (currently nil)
end
it 'creates the metrics record' do

View File

@ -189,6 +189,14 @@ RSpec.describe Issues::UpdateService, :mailer do
expect(issue.labels.pluck(:title)).to eq(['incident'])
end
it 'creates system note about issue type' do
update_issue(issue_type: 'incident')
note = find_note('changed issue type to incident')
expect(note).not_to eq(nil)
end
context 'for an issue with multiple labels' do
let(:issue) { create(:incident, project: project, labels: [label_1]) }

View File

@ -793,4 +793,16 @@ RSpec.describe SystemNoteService do
described_class.log_resolving_alert(alert, monitoring_tool)
end
end
describe '.change_issue_type' do
let(:incident) { build(:incident) }
it 'calls IssuableService' do
expect_next_instance_of(::SystemNotes::IssuablesService) do |service|
expect(service).to receive(:change_issue_type)
end
described_class.change_issue_type(incident, author)
end
end
end

View File

@ -773,4 +773,16 @@ RSpec.describe ::SystemNotes::IssuablesService do
expect(event.state).to eq('closed')
end
end
describe '#change_issue_type' do
let(:noteable) { create(:incident, project: project) }
subject { service.change_issue_type }
it_behaves_like 'a system note' do
let(:action) { 'issue_type' }
end
it { expect(subject.note).to eq "changed issue type to incident" }
end
end

View File

@ -10,7 +10,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportIssuesAndDiffNotesWorker do
it 'imports the issues and diff notes' do
client = double(:client)
described_class::IMPORTERS.each do |klass|
worker.importers(project).each do |klass|
importer = double(:importer)
waiter = Gitlab::JobWaiter.new(2, '123')
@ -31,4 +31,45 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportIssuesAndDiffNotesWorker do
worker.import(client, project)
end
end
describe '#importers' do
context 'when project group is present' do
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group, projects: [project]) }
context 'when feature flag github_importer_single_endpoint_notes_import is enabled' do
it 'includes single endpoint diff notes importer' do
project = create(:project)
group = create(:group, projects: [project])
stub_feature_flags(github_importer_single_endpoint_notes_import: group)
expect(worker.importers(project)).to contain_exactly(
Gitlab::GithubImport::Importer::IssuesImporter,
Gitlab::GithubImport::Importer::SingleEndpointDiffNotesImporter
)
end
end
context 'when feature flag github_importer_single_endpoint_notes_import is disabled' do
it 'includes default diff notes importer' do
stub_feature_flags(github_importer_single_endpoint_notes_import: false)
expect(worker.importers(project)).to contain_exactly(
Gitlab::GithubImport::Importer::IssuesImporter,
Gitlab::GithubImport::Importer::DiffNotesImporter
)
end
end
end
context 'when project group is missing' do
it 'includes default diff notes importer' do
expect(worker.importers(project)).to contain_exactly(
Gitlab::GithubImport::Importer::IssuesImporter,
Gitlab::GithubImport::Importer::DiffNotesImporter
)
end
end
end
end

View File

@ -8,18 +8,21 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportNotesWorker do
describe '#import' do
it 'imports all the notes' do
importer = double(:importer)
client = double(:client)
waiter = Gitlab::JobWaiter.new(2, '123')
expect(Gitlab::GithubImport::Importer::NotesImporter)
.to receive(:new)
.with(project, client)
.and_return(importer)
worker.importers(project).each do |klass|
importer = double(:importer)
waiter = Gitlab::JobWaiter.new(2, '123')
expect(importer)
.to receive(:execute)
.and_return(waiter)
expect(klass)
.to receive(:new)
.with(project, client)
.and_return(importer)
expect(importer)
.to receive(:execute)
.and_return(waiter)
end
expect(Gitlab::GithubImport::AdvanceStageWorker)
.to receive(:perform_async)
@ -28,4 +31,43 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportNotesWorker do
worker.import(client, project)
end
end
describe '#importers' do
context 'when project group is present' do
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group, projects: [project]) }
context 'when feature flag github_importer_single_endpoint_notes_import is enabled' do
it 'includes single endpoint mr and issue notes importers' do
project = create(:project)
group = create(:group, projects: [project])
stub_feature_flags(github_importer_single_endpoint_notes_import: group)
expect(worker.importers(project)).to contain_exactly(
Gitlab::GithubImport::Importer::SingleEndpointMergeRequestNotesImporter,
Gitlab::GithubImport::Importer::SingleEndpointIssueNotesImporter
)
end
end
context 'when feature flag github_importer_single_endpoint_notes_import is disabled' do
it 'includes default notes importer' do
stub_feature_flags(github_importer_single_endpoint_notes_import: false)
expect(worker.importers(project)).to contain_exactly(
Gitlab::GithubImport::Importer::NotesImporter
)
end
end
end
context 'when project group is missing' do
it 'includes default diff notes importer' do
expect(worker.importers(project)).to contain_exactly(
Gitlab::GithubImport::Importer::NotesImporter
)
end
end
end
end