Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop_manual_todo.yml24
-rw-r--r--app/graphql/resolvers/labels_resolver.rb2
-rw-r--r--app/graphql/resolvers/merge_requests_resolver.rb2
-rw-r--r--app/graphql/resolvers/milestones_resolver.rb6
-rw-r--r--app/graphql/resolvers/package_details_resolver.rb2
-rw-r--r--app/graphql/resolvers/paginated_tree_resolver.rb4
-rw-r--r--app/graphql/resolvers/release_resolver.rb2
-rw-r--r--app/graphql/resolvers/repository_branch_names_resolver.rb6
-rw-r--r--app/graphql/resolvers/snippets_resolver.rb6
-rw-r--r--app/graphql/resolvers/todo_resolver.rb12
-rw-r--r--app/graphql/resolvers/tree_resolver.rb4
-rw-r--r--app/graphql/resolvers/users/snippets_resolver.rb2
-rw-r--r--app/graphql/types/admin/analytics/usage_trends/measurement_type.rb4
-rw-r--r--app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb4
-rw-r--r--app/graphql/types/alert_management/alert_type.rb4
-rw-r--r--app/graphql/types/award_emojis/award_emoji_type.rb12
-rw-r--r--app/graphql/types/ci/config/job_restriction_type.rb2
-rw-r--r--app/graphql/types/ci/config/status_enum.rb4
-rw-r--r--app/graphql/types/ci/pipeline_type.rb2
-rw-r--r--app/graphql/types/ci_configuration/sast/ui_component_size_enum.rb6
-rw-r--r--app/graphql/types/commit_action_type.rb2
-rw-r--r--app/graphql/types/container_repository_cleanup_status_enum.rb8
-rw-r--r--app/graphql/types/container_repository_tag_type.rb2
-rw-r--r--app/graphql/types/container_repository_type.rb2
-rw-r--r--app/graphql/types/custom_emoji_type.rb6
-rw-r--r--app/helpers/system_note_helper.rb3
-rw-r--r--app/models/issue.rb3
-rw-r--r--app/models/issue/metrics.rb33
-rw-r--r--app/services/issues/update_service.rb11
-rw-r--r--app/services/system_note_service.rb4
-rw-r--r--app/services/system_notes/issuables_service.rb6
-rw-r--r--app/views/layouts/nav/sidebar/_group_menus.html.haml2
-rw-r--r--app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb28
-rw-r--r--app/workers/gitlab/github_import/stage/import_notes_worker.rb24
-rw-r--r--config/feature_flags/development/upsert_issue_metrics.yml8
-rw-r--r--config/feature_flags/ops/github_importer_lower_per_page_limit.yml8
-rw-r--r--config/feature_flags/ops/github_importer_single_endpoint_notes_import.yml8
-rw-r--r--doc/api/boards.md2
-rw-r--r--doc/api/graphql/reference/index.md202
-rw-r--r--doc/api/group_boards.md10
-rw-r--r--doc/development/fe_guide/development_process.md2
-rw-r--r--doc/development/github_importer.md8
-rw-r--r--doc/development/snowplow/index.md2
-rw-r--r--doc/development/understanding_explain_plans.md2
-rw-r--r--doc/install/requirements.md2
-rw-r--r--doc/integration/gitpod.md2
-rw-r--r--doc/ssh/index.md2
-rw-r--r--doc/subscriptions/bronze_starter.md2
-rw-r--r--doc/user/analytics/value_stream_analytics.md4
-rw-r--r--doc/user/group/epics/epic_boards.md4
-rw-r--r--doc/user/group/epics/index.md2
-rw-r--r--doc/user/group/value_stream_analytics/index.md4
-rw-r--r--doc/user/index.md4
-rw-r--r--doc/user/permissions.md6
-rw-r--r--doc/user/project/import/github.md48
-rw-r--r--doc/user/project/import/index.md2
-rw-r--r--doc/user/project/index.md10
-rw-r--r--doc/user/project/issue_board.md14
-rw-r--r--doc/user/project/issues/index.md2
-rw-r--r--doc/user/project/issues/issue_data_and_actions.md2
-rw-r--r--doc/user/project/issues/managing_issues.md6
-rw-r--r--doc/user/project/settings/index.md2
-rw-r--r--doc/user/search/index.md6
-rw-r--r--lib/gitlab/cache/import/caching.rb2
-rw-r--r--lib/gitlab/github_import.rb9
-rw-r--r--lib/gitlab/github_import/client.rb4
-rw-r--r--lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer.rb54
-rw-r--r--lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer.rb54
-rw-r--r--lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer.rb54
-rw-r--r--lib/gitlab/github_import/issuable_finder.rb12
-rw-r--r--lib/gitlab/github_import/single_endpoint_notes_importing.rb85
-rw-r--r--spec/lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer_spec.rb75
-rw-r--r--spec/lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer_spec.rb74
-rw-r--r--spec/lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer_spec.rb75
-rw-r--r--spec/lib/gitlab/github_import/issuable_finder_spec.rb66
-rw-r--r--spec/lib/gitlab/github_import/sequential_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import_spec.rb49
-rw-r--r--spec/models/issue/metrics_spec.rb25
-rw-r--r--spec/models/issue_spec.rb3
-rw-r--r--spec/services/issues/update_service_spec.rb8
-rw-r--r--spec/services/system_note_service_spec.rb12
-rw-r--r--spec/services/system_notes/issuables_service_spec.rb12
-rw-r--r--spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb43
-rw-r--r--spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb60
84 files changed, 1115 insertions, 283 deletions
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index 647d5e4c5ac..96571d48b1c 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -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'
diff --git a/app/graphql/resolvers/labels_resolver.rb b/app/graphql/resolvers/labels_resolver.rb
index 505d1dff8d2..f0e099e8fb2 100644
--- a/app/graphql/resolvers/labels_resolver.rb
+++ b/app/graphql/resolvers/labels_resolver.rb
@@ -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,
diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb
index 8f2c7847a2e..c0dd61078c6 100644
--- a/app/graphql/resolvers/merge_requests_resolver.rb
+++ b/app/graphql/resolvers/merge_requests_resolver.rb
@@ -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,
diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb
index 84f7d66ec19..dc6d781f584 100644
--- a/app/graphql/resolvers/milestones_resolver.rb
+++ b/app/graphql/resolvers/milestones_resolver.rb
@@ -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.',
diff --git a/app/graphql/resolvers/package_details_resolver.rb b/app/graphql/resolvers/package_details_resolver.rb
index 89d79747732..42cb23e701d 100644
--- a/app/graphql/resolvers/package_details_resolver.rb
+++ b/app/graphql/resolvers/package_details_resolver.rb
@@ -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 }
diff --git a/app/graphql/resolvers/paginated_tree_resolver.rb b/app/graphql/resolvers/paginated_tree_resolver.rb
index d1b4e75169c..6c0545d26de 100644
--- a/app/graphql/resolvers/paginated_tree_resolver.rb
+++ b/app/graphql/resolvers/paginated_tree_resolver.rb
@@ -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,
diff --git a/app/graphql/resolvers/release_resolver.rb b/app/graphql/resolvers/release_resolver.rb
index 0374a1103de..82b5647615e 100644
--- a/app/graphql/resolvers/release_resolver.rb
+++ b/app/graphql/resolvers/release_resolver.rb
@@ -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
diff --git a/app/graphql/resolvers/repository_branch_names_resolver.rb b/app/graphql/resolvers/repository_branch_names_resolver.rb
index e9aacda2652..96550bce32f 100644
--- a/app/graphql/resolvers/repository_branch_names_resolver.rb
+++ b/app/graphql/resolvers/repository_branch_names_resolver.rb
@@ -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
diff --git a/app/graphql/resolvers/snippets_resolver.rb b/app/graphql/resolvers/snippets_resolver.rb
index 7d18c9c6fea..149bd8fa1ce 100644
--- a/app/graphql/resolvers/snippets_resolver.rb
+++ b/app/graphql/resolvers/snippets_resolver.rb
@@ -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,
diff --git a/app/graphql/resolvers/todo_resolver.rb b/app/graphql/resolvers/todo_resolver.rb
index 263b190c74e..863d402b4d3 100644
--- a/app/graphql/resolvers/todo_resolver.rb
+++ b/app/graphql/resolvers/todo_resolver.rb
@@ -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?
diff --git a/app/graphql/resolvers/tree_resolver.rb b/app/graphql/resolvers/tree_resolver.rb
index 70b4d81845c..8d6ece0956e 100644
--- a/app/graphql/resolvers/tree_resolver.rb
+++ b/app/graphql/resolvers/tree_resolver.rb
@@ -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,
diff --git a/app/graphql/resolvers/users/snippets_resolver.rb b/app/graphql/resolvers/users/snippets_resolver.rb
index ee1727aadbe..75bba8debab 100644
--- a/app/graphql/resolvers/users/snippets_resolver.rb
+++ b/app/graphql/resolvers/users/snippets_resolver.rb
@@ -11,7 +11,7 @@ module Resolvers
argument :type, Types::Snippets::TypeEnum,
required: false,
- description: 'The type of snippet.'
+ description: 'Type of snippet.'
private
diff --git a/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb b/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb
index c54c938402d..8276549ddcc 100644
--- a/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb
+++ b/app/graphql/types/admin/analytics/usage_trends/measurement_type.rb
@@ -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
diff --git a/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb b/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb
index cc6e3db007b..4f31e2f783a 100644
--- a/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb
+++ b/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb
@@ -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
diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb
index bdfdd2c5886..4bdb476860a 100644
--- a/app/graphql/types/alert_management/alert_type.rb
+++ b/app/graphql/types/alert_management/alert_type.rb
@@ -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
diff --git a/app/graphql/types/award_emojis/award_emoji_type.rb b/app/graphql/types/award_emojis/award_emoji_type.rb
index 1f6f0badcac..76415afc6c1 100644
--- a/app/graphql/types/award_emojis/award_emoji_type.rb
+++ b/app/graphql/types/award_emojis/award_emoji_type.rb
@@ -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
diff --git a/app/graphql/types/ci/config/job_restriction_type.rb b/app/graphql/types/ci/config/job_restriction_type.rb
index 891ba18dacc..8cf0e210def 100644
--- a/app/graphql/types/ci/config/job_restriction_type.rb
+++ b/app/graphql/types/ci/config/job_restriction_type.rb
@@ -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
diff --git a/app/graphql/types/ci/config/status_enum.rb b/app/graphql/types/ci/config/status_enum.rb
index 1ba207531b8..dbb560c93c3 100644
--- a/app/graphql/types/ci/config/status_enum.rb
+++ b/app/graphql/types/ci/config/status_enum.rb
@@ -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
diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb
index 0375257eb7b..493ce188d9b 100644
--- a/app/graphql/types/ci/pipeline_type.rb
+++ b/app/graphql/types/ci/pipeline_type.rb
@@ -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,
diff --git a/app/graphql/types/ci_configuration/sast/ui_component_size_enum.rb b/app/graphql/types/ci_configuration/sast/ui_component_size_enum.rb
index 76d2a314c13..62bd3e9b2ca 100644
--- a/app/graphql/types/ci_configuration/sast/ui_component_size_enum.rb
+++ b/app/graphql/types/ci_configuration/sast/ui_component_size_enum.rb
@@ -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
diff --git a/app/graphql/types/commit_action_type.rb b/app/graphql/types/commit_action_type.rb
index b170134b388..6f6d6a418dc 100644
--- a/app/graphql/types/commit_action_type.rb
+++ b/app/graphql/types/commit_action_type.rb
@@ -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,
diff --git a/app/graphql/types/container_repository_cleanup_status_enum.rb b/app/graphql/types/container_repository_cleanup_status_enum.rb
index 6e654e65360..e9ccb8adec8 100644
--- a/app/graphql/types/container_repository_cleanup_status_enum.rb
+++ b/app/graphql/types/container_repository_cleanup_status_enum.rb
@@ -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
diff --git a/app/graphql/types/container_repository_tag_type.rb b/app/graphql/types/container_repository_tag_type.rb
index b6b65bce421..206d6a3426c 100644
--- a/app/graphql/types/container_repository_tag_type.rb
+++ b/app/graphql/types/container_repository_tag_type.rb
@@ -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.'
diff --git a/app/graphql/types/container_repository_type.rb b/app/graphql/types/container_repository_type.rb
index 91a65053131..67093f57862 100644
--- a/app/graphql/types/container_repository_type.rb
+++ b/app/graphql/types/container_repository_type.rb
@@ -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.'
diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb
index 64381b3ee1e..379a0c44d67 100644
--- a/app/graphql/types/custom_emoji_type.rb
+++ b/app/graphql/types/custom_emoji_type.rb
@@ -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,
diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb
index 521423fbb94..1d8b657025c 100644
--- a/app/helpers/system_note_helper.rb
+++ b/app/helpers/system_note_helper.rb
@@ -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)
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 48e3fdd51e9..fc5c0455df4 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -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
diff --git a/app/models/issue/metrics.rb b/app/models/issue/metrics.rb
index 86523bbd023..b6ef600450e 100644
--- a/app/models/issue/metrics.rb
+++ b/app/models/issue/metrics.rb
@@ -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
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 9ede5ef728b..4e52acfcdda 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -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
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 56a6244eebf..e5080718b69 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -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)
diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb
index ae4f65e785c..62aead352aa 100644
--- a/app/services/system_notes/issuables_service.rb
+++ b/app/services/system_notes/issuables_service.rb
@@ -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)
diff --git a/app/views/layouts/nav/sidebar/_group_menus.html.haml b/app/views/layouts/nav/sidebar/_group_menus.html.haml
index 25b6c264d92..4c0ed6a888d 100644
--- a/app/views/layouts/nav/sidebar/_group_menus.html.haml
+++ b/app/views/layouts/nav/sidebar/_group_menus.html.haml
@@ -1,3 +1 @@
-= render_if_exists "groups/ee/administration_nav"
-
= render 'shared/sidebar_toggle_button'
diff --git a/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb b/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb
index c33836e20d1..5188bda03e2 100644
--- a/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb
+++ b/app/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker.rb
@@ -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
diff --git a/app/workers/gitlab/github_import/stage/import_notes_worker.rb b/app/workers/gitlab/github_import/stage/import_notes_worker.rb
index 0160145ffe2..90a1337169f 100644
--- a/app/workers/gitlab/github_import/stage/import_notes_worker.rb
+++ b/app/workers/gitlab/github_import/stage/import_notes_worker.rb
@@ -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
diff --git a/config/feature_flags/development/upsert_issue_metrics.yml b/config/feature_flags/development/upsert_issue_metrics.yml
new file mode 100644
index 00000000000..c04beb75aa1
--- /dev/null
+++ b/config/feature_flags/development/upsert_issue_metrics.yml
@@ -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
diff --git a/config/feature_flags/ops/github_importer_lower_per_page_limit.yml b/config/feature_flags/ops/github_importer_lower_per_page_limit.yml
new file mode 100644
index 00000000000..d3a446dc125
--- /dev/null
+++ b/config/feature_flags/ops/github_importer_lower_per_page_limit.yml
@@ -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
diff --git a/config/feature_flags/ops/github_importer_single_endpoint_notes_import.yml b/config/feature_flags/ops/github_importer_single_endpoint_notes_import.yml
new file mode 100644
index 00000000000..7bbc6fba9e0
--- /dev/null
+++ b/config/feature_flags/ops/github_importer_single_endpoint_notes_import.yml
@@ -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
diff --git a/doc/api/boards.md b/doc/api/boards.md
index 3288aefb1cf..ab9bd4ea3f1 100644
--- a/doc/api/boards.md
+++ b/doc/api/boards.md
@@ -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
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 440267a1ff2..d00739420bb 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -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. |
diff --git a/doc/api/group_boards.md b/doc/api/group_boards.md
index eaa7b57e520..e92c8784664 100644
--- a/doc/api/group_boards.md
+++ b/doc/api/group_boards.md
@@ -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
diff --git a/doc/development/fe_guide/development_process.md b/doc/development/fe_guide/development_process.md
index b85ed4da442..4e50621add4 100644
--- a/doc/development/fe_guide/development_process.md
+++ b/doc/development/fe_guide/development_process.md
@@ -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.
diff --git a/doc/development/github_importer.md b/doc/development/github_importer.md
index 84c10e0c005..e2e843544ca 100644
--- a/doc/development/github_importer.md
+++ b/doc/development/github_importer.md
@@ -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)
diff --git a/doc/development/snowplow/index.md b/doc/development/snowplow/index.md
index 527b4292b23..4a61beaf626 100644
--- a/doc/development/snowplow/index.md
+++ b/doc/development/snowplow/index.md
@@ -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
diff --git a/doc/development/understanding_explain_plans.md b/doc/development/understanding_explain_plans.md
index c3fefd40171..c3dfeaa6b92 100644
--- a/doc/development/understanding_explain_plans.md
+++ b/doc/development/understanding_explain_plans.md
@@ -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.
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index ba515de417f..3957828ba30 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -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
diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md
index e3cd3075bc9..7d53af89ca5 100644
--- a/doc/integration/gitpod.md
+++ b/doc/integration/gitpod.md
@@ -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**.
diff --git a/doc/ssh/index.md b/doc/ssh/index.md
index c4e651a0072..402e1c225c3 100644
--- a/doc/ssh/index.md
+++ b/doc/ssh/index.md
@@ -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):
diff --git a/doc/subscriptions/bronze_starter.md b/doc/subscriptions/bronze_starter.md
index 410759aa506..961a6bf5ec4 100644
--- a/doc/subscriptions/bronze_starter.md
+++ b/doc/subscriptions/bronze_starter.md
@@ -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)
diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md
index 9a1aed9c39f..7057d069e95 100644
--- a/doc/user/analytics/value_stream_analytics.md
+++ b/doc/user/analytics/value_stream_analytics.md
@@ -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).
diff --git a/doc/user/group/epics/epic_boards.md b/doc/user/group/epics/epic_boards.md
index 34eebfb9e3b..d184030718a 100644
--- a/doc/user/group/epics/epic_boards.md
+++ b/doc/user/group/epics/epic_boards.md
@@ -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**.
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index 24c78d169c4..68df71d1c5d 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -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).
diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md
index 4d254279a3d..3a7167e0907 100644
--- a/doc/user/group/value_stream_analytics/index.md
+++ b/doc/user/group/value_stream_analytics/index.md
@@ -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
diff --git a/doc/user/index.md b/doc/user/index.md
index 8fc91ec95ea..104da206e5f 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -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.
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 726bea58ba5..6e95361c3f4 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -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)**
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 1ab343d75fb..126d893483f 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -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)
+```
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index dcc41c6c85e..549cea73f8e 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -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).
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 668a0dffd32..8c81af418a0 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -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)
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 0c624d7df01..8c212c99913 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -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
diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md
index 56c219eb8c3..cc0a1dccafd 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -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)
diff --git a/doc/user/project/issues/issue_data_and_actions.md b/doc/user/project/issues/issue_data_and_actions.md
index 78dc6805f2b..6bb60e5e31a 100644
--- a/doc/user/project/issues/issue_data_and_actions.md
+++ b/doc/user/project/issues/issue_data_and_actions.md
@@ -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
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index a2185c83f4d..bcf76ad53f6 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -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
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 66fdace81ba..ff8e56289b4 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -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:
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index 92d01e6a43e..9079394bcda 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -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:
diff --git a/lib/gitlab/cache/import/caching.rb b/lib/gitlab/cache/import/caching.rb
index 89c85cb50be..8cc4f213fc1 100644
--- a/lib/gitlab/cache/import/caching.rb
+++ b/lib/gitlab/cache/import/caching.rb
@@ -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))
diff --git a/lib/gitlab/github_import.rb b/lib/gitlab/github_import.rb
index c3cc15e10f7..7ac0d875512 100644
--- a/lib/gitlab/github_import.rb
+++ b/lib/gitlab/github_import.rb
@@ -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
diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb
index 138716b1b53..efa816c5eb0 100644
--- a/lib/gitlab/github_import/client.rb
+++ b/lib/gitlab/github_import/client.rb
@@ -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,
diff --git a/lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer.rb b/lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer.rb
new file mode 100644
index 00000000000..a2c3d1bd057
--- /dev/null
+++ b/lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer.rb
@@ -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
diff --git a/lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer.rb b/lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer.rb
new file mode 100644
index 00000000000..49569ed52d8
--- /dev/null
+++ b/lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer.rb
@@ -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
diff --git a/lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer.rb b/lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer.rb
new file mode 100644
index 00000000000..d837639c14d
--- /dev/null
+++ b/lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer.rb
@@ -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
diff --git a/lib/gitlab/github_import/issuable_finder.rb b/lib/gitlab/github_import/issuable_finder.rb
index 136531505ea..5298a3d81ea 100644
--- a/lib/gitlab/github_import/issuable_finder.rb
+++ b/lib/gitlab/github_import/issuable_finder.rb
@@ -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
diff --git a/lib/gitlab/github_import/single_endpoint_notes_importing.rb b/lib/gitlab/github_import/single_endpoint_notes_importing.rb
new file mode 100644
index 00000000000..43402ecd165
--- /dev/null
+++ b/lib/gitlab/github_import/single_endpoint_notes_importing.rb
@@ -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
diff --git a/spec/lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer_spec.rb
new file mode 100644
index 00000000000..8c71d7d0ed7
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/single_endpoint_diff_notes_importer_spec.rb
@@ -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
diff --git a/spec/lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer_spec.rb
new file mode 100644
index 00000000000..8d8f2730880
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/single_endpoint_issue_notes_importer_spec.rb
@@ -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
diff --git a/spec/lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer_spec.rb b/spec/lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer_spec.rb
new file mode 100644
index 00000000000..b8282212a90
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/single_endpoint_merge_request_notes_importer_spec.rb
@@ -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
diff --git a/spec/lib/gitlab/github_import/issuable_finder_spec.rb b/spec/lib/gitlab/github_import/issuable_finder_spec.rb
index f009b61ad89..3afd006109b 100644
--- a/spec/lib/gitlab/github_import/issuable_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/issuable_finder_spec.rb
@@ -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
diff --git a/spec/lib/gitlab/github_import/sequential_importer_spec.rb b/spec/lib/gitlab/github_import/sequential_importer_spec.rb
index a5e89049ed9..3c3f8ff59d0 100644
--- a/spec/lib/gitlab/github_import/sequential_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/sequential_importer_spec.rb
@@ -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|
diff --git a/spec/lib/gitlab/github_import_spec.rb b/spec/lib/gitlab/github_import_spec.rb
index 662757f66ad..1ea9f003098 100644
--- a/spec/lib/gitlab/github_import_spec.rb
+++ b/spec/lib/gitlab/github_import_spec.rb
@@ -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
diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb
index 49c891c20da..6e3ef69017b 100644
--- a/spec/models/issue/metrics_spec.rb
+++ b/spec/models/issue/metrics_spec.rb
@@ -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)
+ context 'when upsert_issue_metrics is enabled' do
+ before do
+ stub_feature_flags(upsert_issue_metrics: true)
+ end
- subject.update!(label_ids: additional_labels.map(&:id))
+ it_behaves_like 'when recording the default set of issue metrics on issue save'
+ end
- expect { Issue::Metrics.find_by(issue: subject).record! }.not_to exceed_query_limit(control_count)
- 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
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 116bda7a18b..3ec28a3f72f 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -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
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 29ac7df88eb..0c7f3f7e6e2 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -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]) }
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 5aff5149dcf..1a421999ffb 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -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
diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb
index 1ea3c241d27..71a28a89cd8 100644
--- a/spec/services/system_notes/issuables_service_spec.rb
+++ b/spec/services/system_notes/issuables_service_spec.rb
@@ -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
diff --git a/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
index f2a28ec40b8..c0dd4f488cc 100644
--- a/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_issues_and_diff_notes_worker_spec.rb
@@ -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
diff --git a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
index 73b19239f4a..f9f21e4dfa2 100644
--- a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
+++ b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb
@@ -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