summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-31 12:06:26 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-31 12:06:26 +0000
commit0be510a49f6e4f8e27b19b707fd1dac61571f78f (patch)
tree97ca0053d4fad66e900d25fdba61b2adb611efb0
parent6026bddcd51eca573c530240c421392045172b89 (diff)
downloadgitlab-ce-0be510a49f6e4f8e27b19b707fd1dac61571f78f.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/CODEOWNERS1
-rw-r--r--app/assets/stylesheets/framework/variables.scss21
-rw-r--r--app/assets/stylesheets/pages/projects.scss3
-rw-r--r--app/assets/stylesheets/utilities.scss6
-rw-r--r--app/controllers/notification_settings_controller.rb18
-rw-r--r--app/graphql/types/commit_type.rb30
-rw-r--r--app/graphql/types/group_type.rb15
-rw-r--r--app/graphql/types/issue_type.rb92
-rw-r--r--app/graphql/types/label_type.rb12
-rw-r--r--app/graphql/types/merge_request_type.rb156
-rw-r--r--app/graphql/types/metadata_type.rb6
-rw-r--r--app/graphql/types/milestone_type.rb21
-rw-r--r--app/graphql/types/namespace_type.rb34
-rw-r--r--app/graphql/types/project_statistics_type.rb21
-rw-r--r--app/graphql/types/project_type.rb166
-rw-r--r--app/graphql/types/repository_type.rb12
-rw-r--r--app/graphql/types/task_completion_status.rb6
-rw-r--r--app/graphql/types/user_type.rb14
-rw-r--r--app/views/projects/merge_requests/creations/_new_submit.html.haml10
-rw-r--r--app/views/projects/merge_requests/edit.html.haml1
-rw-r--r--app/views/shared/issuable/_form.html.haml5
-rw-r--r--app/views/shared/issuable/form/_branch_chooser.html.haml30
-rw-r--r--app/views/shared/issuable/form/_merge_params.html.haml14
-rw-r--r--app/views/shared/notifications/_button.html.haml6
-rw-r--r--app/views/shared/notifications/_custom_notifications.html.haml3
-rw-r--r--app/views/shared/notifications/_new_button.html.haml2
-rw-r--r--changelogs/unreleased/maintenance-move-branch-selector-to-top.yml6
-rw-r--r--doc/api/graphql/reference/index.md422
-rw-r--r--lib/gitlab/danger/helper.rb16
-rw-r--r--lib/gitlab/danger/teammate.rb5
-rw-r--r--locale/gitlab.pot12
-rw-r--r--spec/features/dashboard/projects_spec.rb3
-rw-r--r--spec/features/merge_request/user_edits_merge_request_spec.rb2
-rw-r--r--spec/features/projects/commit/cherry_pick_spec.rb6
-rw-r--r--spec/frontend/pipelines/graph/action_component_spec.js75
-rw-r--r--spec/frontend/pipelines/pipeline_triggerer_spec.js (renamed from spec/javascripts/pipelines/pipeline_triggerer_spec.js)5
-rw-r--r--spec/frontend/pipelines/pipelines_table_row_spec.js (renamed from spec/javascripts/pipelines/pipelines_table_row_spec.js)138
-rw-r--r--spec/javascripts/pipelines/graph/action_component_spec.js81
-rw-r--r--spec/lib/gitlab/danger/helper_spec.rb13
-rw-r--r--spec/lib/gitlab/danger/teammate_spec.rb18
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb2
41 files changed, 877 insertions, 632 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 61653d798a9..9ad0e604d61 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -8,6 +8,7 @@
# Frontend maintainers should see everything in `app/assets/`
app/assets/ @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter @wortschi @ntepluhina @iamphill
*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter @wortschi @ntepluhina @iamphill
+/scripts/frontend/ @ClemMakesApps @fatihacet @filipa @mikegreiling @timzallmann @kushalpandya @pslaughter @wortschi @ntepluhina @iamphill
# Database maintainers should review changes in `db/`
db/ @gitlab-org/maintainers/database
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index dfc39d8e03b..a7d94281008 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -21,6 +21,27 @@ $spacing-scale: (
);
/*
+ * Why another sizing scale???
+ * Great question, friend!
+ * This size scale is a "backport" of the equivalent set of "named" sizes
+ * (e.g. `xl` versus `70`) that came from the following design document as of 2019-10-23:
+ *
+ * https://gitlab-org.gitlab.io/gitlab-design/hosted/design-gitlab-specs/forms-spec-previews/
+ *
+ * (See `input-` items at the bottom)
+ *
+ * The presumption here is that these sizes will be standardized in GitLab UI and thus will be
+ * broadly useful here in the GitLab product when not using the GitLab UI components.
+ */
+$size-scale: (
+ 'xs': #{10 * $grid-size},
+ 's': #{20 * $grid-size},
+ 'm': #{30 * $grid-size},
+ 'l': #{40 * $grid-size},
+ 'xl': #{70 * $grid-size}
+);
+
+/*
* Color schema
*/
$darken-normal-factor: 7%;
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index b2c1d0b6dc5..3f8bdc82eff 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -252,6 +252,7 @@
.fa-caret-down {
margin-left: 3px;
+ line-height: 0;
&.dropdown-btn-icon {
margin-left: 0;
@@ -269,7 +270,7 @@
}
.count-badge,
- .btn-xs {
+ .btn {
height: 24px;
}
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index d2906ce0780..4a0b6ac1ddd 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -16,6 +16,12 @@
}
}
+@each $index, $size in $size-scale {
+ #{'.mw-#{$index}'} {
+ max-width: $size;
+ }
+}
+
.border-width-1px { border-width: 1px; }
.border-style-dashed { border-style: dashed; }
.border-style-solid { border-style: solid; }
diff --git a/app/controllers/notification_settings_controller.rb b/app/controllers/notification_settings_controller.rb
index c97fec0a6ee..e5d4a4bb073 100644
--- a/app/controllers/notification_settings_controller.rb
+++ b/app/controllers/notification_settings_controller.rb
@@ -16,12 +16,7 @@ class NotificationSettingsController < ApplicationController
@notification_setting = current_user.notification_settings.find(params[:id])
@saved = @notification_setting.update(notification_setting_params_for(@notification_setting.source))
- if params[:hide_label].present?
- btn_class = params[:project_id].present? ? 'btn-xs' : ''
- render_response("shared/notifications/_new_button", btn_class)
- else
- render_response
- end
+ render_response
end
private
@@ -42,7 +37,16 @@ class NotificationSettingsController < ApplicationController
can?(current_user, ability_name, resource)
end
- def render_response(response_template = "shared/notifications/_button", btn_class = nil)
+ def render_response
+ btn_class = nil
+
+ if params[:hide_label].present?
+ btn_class = 'btn-xs' if params[:project_id].present?
+ response_template = 'shared/notifications/_new_button'
+ else
+ response_template = 'shared/notifications/_button'
+ end
+
render json: {
html: view_to_html_string(response_template, notification_setting: @notification_setting, btn_class: btn_class),
saved: @saved
diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb
index fe71791f413..d5600881728 100644
--- a/app/graphql/types/commit_type.rb
+++ b/app/graphql/types/commit_type.rb
@@ -8,23 +8,31 @@ module Types
present_using CommitPresenter
- field :id, type: GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :sha, type: GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :title, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :description, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :message, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :authored_date, type: Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
- field :web_url, type: GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :signature_html, type: GraphQL::STRING_TYPE,
- null: true, calls_gitaly: true, description: 'Rendered html for the commit signature'
+ field :id, type: GraphQL::ID_TYPE, null: false,
+ description: 'ID (global ID) of the commit'
+ field :sha, type: GraphQL::STRING_TYPE, null: false,
+ description: 'SHA1 ID of the commit'
+ field :title, type: GraphQL::STRING_TYPE, null: true,
+ description: 'Title of the commit message'
+ field :description, type: GraphQL::STRING_TYPE, null: true,
+ description: 'Description of the commit message'
+ field :message, type: GraphQL::STRING_TYPE, null: true,
+ description: 'Raw commit message'
+ field :authored_date, type: Types::TimeType, null: true,
+ description: 'Timestamp of when the commit was authored'
+ field :web_url, type: GraphQL::STRING_TYPE, null: false,
+ description: 'Web URL of the commit'
+ field :signature_html, type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true,
+ description: 'Rendered HTML of the commit signature'
# models/commit lazy loads the author by email
- field :author, type: Types::UserType, null: true # rubocop:disable Graphql/Descriptions
+ field :author, type: Types::UserType, null: true,
+ description: 'Author of the commit'
field :latest_pipeline,
type: Types::Ci::PipelineType,
null: true,
- description: "Latest pipeline for this commit",
+ description: "Latest pipeline of the commit",
resolve: -> (obj, ctx, args) do
Gitlab::Graphql::Loaders::PipelineForShaLoader.new(obj.project, obj.sha).find_last
end
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 1e52c0cb147..386ae6ed4a3 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -8,14 +8,17 @@ module Types
expose_permissions Types::PermissionTypes::Group
- field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :web_url, GraphQL::STRING_TYPE, null: false,
+ description: 'Web URL of the group'
- field :avatar_url, GraphQL::STRING_TYPE, null: true, resolve: -> (group, args, ctx) do # rubocop:disable Graphql/Descriptions
- group.avatar_url(only_path: false)
- end
+ field :avatar_url, GraphQL::STRING_TYPE, null: true,
+ description: 'Avatar URL of the group',
+ resolve: -> (group, args, ctx) do
+ group.avatar_url(only_path: false)
+ end
- field :parent, GroupType, # rubocop:disable Graphql/Descriptions
- null: true,
+ field :parent, GroupType, null: true,
+ description: 'Parent group',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find }
end
end
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index 4965601fe65..bf055bd9eef 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -12,53 +12,77 @@ module Types
present_using IssuePresenter
- field :iid, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :iid, GraphQL::ID_TYPE, null: false,
+ description: "Internal ID of the issue"
+ field :title, GraphQL::STRING_TYPE, null: false,
+ description: 'Title of the issue'
markdown_field :title_html, null: true
- field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
+ field :description, GraphQL::STRING_TYPE, null: true,
+ description: 'Description of the issue'
markdown_field :description_html, null: true
- field :state, IssueStateEnum, null: false # rubocop:disable Graphql/Descriptions
-
- field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference do # rubocop:disable Graphql/Descriptions
- argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false # rubocop:disable Graphql/Descriptions
+ field :state, IssueStateEnum, null: false,
+ description: 'State of the issue'
+
+ field :reference, GraphQL::STRING_TYPE, null: false,
+ description: 'Internal reference of the issue. Returned in shortened format by default',
+ method: :to_reference do
+ argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false,
+ description: 'Boolean option specifying whether the reference should be returned in full'
end
- field :author, Types::UserType, # rubocop:disable Graphql/Descriptions
- null: false,
+ field :author, Types::UserType, null: false,
+ description: 'User that created the issue',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find }
# Remove complexity when BatchLoader is used
- field :assignees, Types::UserType.connection_type, null: true, complexity: 5 # rubocop:disable Graphql/Descriptions
+ field :assignees, Types::UserType.connection_type, null: true, complexity: 5,
+ description: 'Assignees of the issue'
# Remove complexity when BatchLoader is used
- field :labels, Types::LabelType.connection_type, null: true, complexity: 5 # rubocop:disable Graphql/Descriptions
- field :milestone, Types::MilestoneType, # rubocop:disable Graphql/Descriptions
- null: true,
+ field :labels, Types::LabelType.connection_type, null: true, complexity: 5,
+ description: 'Labels of the issue'
+ field :milestone, Types::MilestoneType, null: true,
+ description: 'Milestone of the issue',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find }
- field :due_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
- field :confidential, GraphQL::BOOLEAN_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :discussion_locked, GraphQL::BOOLEAN_TYPE, # rubocop:disable Graphql/Descriptions
- null: false,
+ field :due_date, Types::TimeType, null: true,
+ description: 'Due date of the issue'
+ field :confidential, GraphQL::BOOLEAN_TYPE, null: false,
+ description: 'Indicates the issue is confidential'
+ field :discussion_locked, GraphQL::BOOLEAN_TYPE, null: false,
+ description: 'Indicates discussion is locked on the issue',
resolve: -> (obj, _args, _ctx) { !!obj.discussion_locked }
- field :upvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :downvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :user_notes_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path # rubocop:disable Graphql/Descriptions
- field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :relative_position, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
-
- field :participants, Types::UserType.connection_type, null: true, complexity: 5, description: 'List of participants for the issue'
- field :time_estimate, GraphQL::INT_TYPE, null: false, description: 'The time estimate on the issue'
- field :total_time_spent, GraphQL::INT_TYPE, null: false, description: 'Total time reported as spent on the issue'
-
- field :closed_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
-
- field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
- field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
-
- field :task_completion_status, Types::TaskCompletionStatus, null: false # rubocop:disable Graphql/Descriptions
+ field :upvotes, GraphQL::INT_TYPE, null: false,
+ description: 'Number of upvotes the issue has received'
+ field :downvotes, GraphQL::INT_TYPE, null: false,
+ description: 'Number of downvotes the issue has received'
+ field :user_notes_count, GraphQL::INT_TYPE, null: false,
+ description: 'Number of user notes of the issue'
+ field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path,
+ description: 'Web path of the issue'
+ field :web_url, GraphQL::STRING_TYPE, null: false,
+ description: 'Web URL of the issue'
+ field :relative_position, GraphQL::INT_TYPE, null: true,
+ description: 'Relative position of the issue (used for positioning in epic tree and issue boards)'
+
+ field :participants, Types::UserType.connection_type, null: true, complexity: 5,
+ description: 'List of participants in the issue'
+ field :time_estimate, GraphQL::INT_TYPE, null: false,
+ description: 'Time estimate of the issue'
+ field :total_time_spent, GraphQL::INT_TYPE, null: false,
+ description: 'Total time reported as spent on the issue'
+
+ field :closed_at, Types::TimeType, null: true,
+ description: 'Timestamp of when the issue was closed'
+
+ field :created_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the issue was created'
+ field :updated_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the issue was last updated'
+
+ field :task_completion_status, Types::TaskCompletionStatus, null: false,
+ description: 'Task completion status of the issue'
end
end
diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb
index 384a27df563..b21503540f8 100644
--- a/app/graphql/types/label_type.rb
+++ b/app/graphql/types/label_type.rb
@@ -6,10 +6,14 @@ module Types
authorize :read_label
- field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
+ field :description, GraphQL::STRING_TYPE, null: true,
+ description: 'Description of the label (markdown rendered as HTML for caching)'
markdown_field :description_html, null: true
- field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :color, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :text_color, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :title, GraphQL::STRING_TYPE, null: false,
+ description: 'Content of the label'
+ field :color, GraphQL::STRING_TYPE, null: false,
+ description: 'Background color of the label'
+ field :text_color, GraphQL::STRING_TYPE, null: false,
+ description: 'Text color of the label'
end
end
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 71a65dc6713..278a95fe3ca 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -12,70 +12,116 @@ module Types
present_using MergeRequestPresenter
- field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :iid, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the merge request'
+ field :iid, GraphQL::STRING_TYPE, null: false,
+ description: 'Internal ID of the merge request'
+ field :title, GraphQL::STRING_TYPE, null: false,
+ description: 'Title of the merge request'
markdown_field :title_html, null: true
- field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
+ field :description, GraphQL::STRING_TYPE, null: true,
+ description: 'Description of the merge request (markdown rendered as HTML for caching)'
markdown_field :description_html, null: true
- field :state, MergeRequestStateEnum, null: false # rubocop:disable Graphql/Descriptions
- field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
- field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
- field :source_project, Types::ProjectType, null: true # rubocop:disable Graphql/Descriptions
- field :target_project, Types::ProjectType, null: false # rubocop:disable Graphql/Descriptions
- field :diff_refs, Types::DiffRefsType, null: true # rubocop:disable Graphql/Descriptions
- # Alias for target_project
- field :project, Types::ProjectType, null: false # rubocop:disable Graphql/Descriptions
- field :project_id, GraphQL::INT_TYPE, null: false, method: :target_project_id # rubocop:disable Graphql/Descriptions
- field :source_project_id, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :target_project_id, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :source_branch, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :target_branch, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :work_in_progress, GraphQL::BOOLEAN_TYPE, method: :work_in_progress?, null: false # rubocop:disable Graphql/Descriptions
- field :merge_when_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :diff_head_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :merge_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :user_notes_count, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true # rubocop:disable Graphql/Descriptions
- field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true # rubocop:disable Graphql/Descriptions
- field :merge_status, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :merge_error, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false # rubocop:disable Graphql/Descriptions
- field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true # rubocop:disable Graphql/Descriptions
- # rubocop:disable Graphql/Descriptions
- field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, deprecation_reason: "Renamed to defaultMergeCommitMessage"
- # rubocop:enable Graphql/Descriptions
- field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false # rubocop:disable Graphql/Descriptions
- field :source_branch_exists, GraphQL::BOOLEAN_TYPE, method: :source_branch_exists?, null: false # rubocop:disable Graphql/Descriptions
- field :mergeable_discussions_state, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :upvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :downvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :state, MergeRequestStateEnum, null: false,
+ description: 'State of the merge request'
+ field :created_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the merge request was created'
+ field :updated_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the merge request was last updated'
+ field :source_project, Types::ProjectType, null: true,
+ description: 'Source project of the merge request'
+ field :target_project, Types::ProjectType, null: false,
+ description: 'Target project of the merge request'
+ field :diff_refs, Types::DiffRefsType, null: true,
+ description: 'References of the base SHA, the head SHA, and the start SHA for this merge request'
+ field :project, Types::ProjectType, null: false,
+ description: 'Alias for target_project'
+ field :project_id, GraphQL::INT_TYPE, null: false, method: :target_project_id,
+ description: 'ID of the merge request project'
+ field :source_project_id, GraphQL::INT_TYPE, null: true,
+ description: 'ID of the merge request source project'
+ field :target_project_id, GraphQL::INT_TYPE, null: false,
+ description: 'ID of the merge request target project'
+ field :source_branch, GraphQL::STRING_TYPE, null: false,
+ description: 'Source branch of the merge request'
+ field :target_branch, GraphQL::STRING_TYPE, null: false,
+ description: 'Target branch of the merge request'
+ field :work_in_progress, GraphQL::BOOLEAN_TYPE, method: :work_in_progress?, null: false,
+ description: 'Indicates if the merge request is a work in progress (WIP)'
+ field :merge_when_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS)'
+ field :diff_head_sha, GraphQL::STRING_TYPE, null: true,
+ description: 'Diff head SHA of the merge request'
+ field :merge_commit_sha, GraphQL::STRING_TYPE, null: true,
+ description: 'SHA of the merge request commit (set once merged)'
+ field :user_notes_count, GraphQL::INT_TYPE, null: true,
+ description: 'User notes count of the merge request'
+ field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true,
+ description: 'Indicates if the source branch of the merge request will be deleted after merge'
+ field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true,
+ description: 'Indicates if the project settings will lead to source branch deletion after merge'
+ field :merge_status, GraphQL::STRING_TYPE, null: true,
+ description: 'Status of the merge request'
+ field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true,
+ description: 'Commit SHA of the merge request if merge is in progress'
+ field :merge_error, GraphQL::STRING_TYPE, null: true,
+ description: 'Error message due to a merge error'
+ field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if members of the target project can push to the fork'
+ field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false,
+ description: 'Indicates if the merge request will be rebased'
+ field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true,
+ description: 'Rebase commit SHA of the merge request'
+ field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true,
+ description: 'Indicates if there is a rebase currently in progress for the merge request'
+ field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, deprecation_reason: "Renamed to defaultMergeCommitMessage",
+ description: 'Deprecated - renamed to defaultMergeCommitMessage'
+ field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true,
+ description: 'Default merge commit message of the merge request'
+ field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false,
+ description: 'Indicates if a merge is currently occurring'
+ field :source_branch_exists, GraphQL::BOOLEAN_TYPE, method: :source_branch_exists?, null: false,
+ description: 'Indicates if the source branch of the merge request exists'
+ field :mergeable_discussions_state, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged'
+ field :web_url, GraphQL::STRING_TYPE, null: true,
+ description: 'Web URL of the merge request'
+ field :upvotes, GraphQL::INT_TYPE, null: false,
+ description: 'Number of upvotes for the merge request'
+ field :downvotes, GraphQL::INT_TYPE, null: false,
+ description: 'Number of downvotes for the merge request'
- field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline # rubocop:disable Graphql/Descriptions
- field :pipelines, Types::Ci::PipelineType.connection_type, # rubocop:disable Graphql/Descriptions
+ field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline,
+ description: 'The pipeline running on the branch HEAD of the merge request'
+ field :pipelines, Types::Ci::PipelineType.connection_type,
+ description: 'Pipelines for the merge request',
resolver: Resolvers::MergeRequestPipelinesResolver
- field :milestone, Types::MilestoneType, description: 'The milestone this merge request is linked to',
- null: true,
+ field :milestone, Types::MilestoneType, null: true,
+ description: 'The milestone of the merge request',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find }
- field :assignees, Types::UserType.connection_type, null: true, complexity: 5, description: 'The list of assignees for the merge request'
- field :participants, Types::UserType.connection_type, null: true, complexity: 5, description: 'The list of participants on the merge request'
+ field :assignees, Types::UserType.connection_type, null: true, complexity: 5,
+ description: 'Assignees of the merge request'
+ field :participants, Types::UserType.connection_type, null: true, complexity: 5,
+ description: 'Participants in the merge request'
field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false, complexity: 5,
- description: 'Boolean flag for whether the currently logged in user is subscribed to this MR'
- field :labels, Types::LabelType.connection_type, null: true, complexity: 5, description: 'The list of labels on the merge request'
- field :discussion_locked, GraphQL::BOOLEAN_TYPE, description: 'Boolean flag determining if comments on the merge request are locked to members only',
+ description: 'Indicates if the currently logged in user is subscribed to this merge request'
+ field :labels, Types::LabelType.connection_type, null: true, complexity: 5,
+ description: 'Labels of the merge request'
+ field :discussion_locked, GraphQL::BOOLEAN_TYPE,
+ description: 'Indicates if comments on the merge request are locked to members only',
null: false,
resolve: -> (obj, _args, _ctx) { !!obj.discussion_locked }
- field :time_estimate, GraphQL::INT_TYPE, null: false, description: 'The time estimate for the merge request'
- field :total_time_spent, GraphQL::INT_TYPE, null: false, description: 'Total time reported as spent on the merge request'
- field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference, description: 'Internal merge request reference. Returned in shortened format by default' do
- argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false, description: 'Boolean option specifying whether the reference should be returned in full'
+ field :time_estimate, GraphQL::INT_TYPE, null: false,
+ description: 'Time estimate of the merge request'
+ field :total_time_spent, GraphQL::INT_TYPE, null: false,
+ description: 'Total time reported as spent on the merge request'
+ field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference,
+ description: 'Internal reference of the merge request. Returned in shortened format by default' do
+ argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false,
+ description: 'Boolean option specifying whether the reference should be returned in full'
end
- field :task_completion_status, Types::TaskCompletionStatus, null: false # rubocop:disable Graphql/Descriptions
+ field :task_completion_status, Types::TaskCompletionStatus, null: false,
+ description: Types::TaskCompletionStatus.description
end
end
diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb
index bfcb929f5ac..1998b036a53 100644
--- a/app/graphql/types/metadata_type.rb
+++ b/app/graphql/types/metadata_type.rb
@@ -6,7 +6,9 @@ module Types
authorize :read_instance_metadata
- field :version, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :revision, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :version, GraphQL::STRING_TYPE, null: false,
+ description: 'Version'
+ field :revision, GraphQL::STRING_TYPE, null: false,
+ description: 'Revision'
end
end
diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb
index 78d0a8220ec..1d3a1231bca 100644
--- a/app/graphql/types/milestone_type.rb
+++ b/app/graphql/types/milestone_type.rb
@@ -6,14 +6,21 @@ module Types
authorize :read_milestone
- field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :state, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :description, GraphQL::STRING_TYPE, null: true,
+ description: 'Description of the milestone'
+ field :title, GraphQL::STRING_TYPE, null: false,
+ description: 'Title of the milestone'
+ field :state, GraphQL::STRING_TYPE, null: false,
+ description: 'State of the milestone'
- field :due_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
- field :start_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
+ field :due_date, Types::TimeType, null: true,
+ description: 'Timestamp of the milestone due date'
+ field :start_date, Types::TimeType, null: true,
+ description: 'Timestamp of the milestone start date'
- field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
- field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions
+ field :created_at, Types::TimeType, null: false,
+ description: 'Timestamp of milestone creation'
+ field :updated_at, Types::TimeType, null: false,
+ description: 'Timestamp of last milestone update'
end
end
diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb
index cc1d06b19e1..1714284a5cf 100644
--- a/app/graphql/types/namespace_type.rb
+++ b/app/graphql/types/namespace_type.rb
@@ -6,27 +6,35 @@ module Types
authorize :read_namespace
- field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the namespace'
- field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :full_name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :full_path, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :name, GraphQL::STRING_TYPE, null: false,
+ description: 'Name of the namespace'
+ field :path, GraphQL::STRING_TYPE, null: false,
+ description: 'Path of the namespace'
+ field :full_name, GraphQL::STRING_TYPE, null: false,
+ description: 'Full name of the namespace'
+ field :full_path, GraphQL::ID_TYPE, null: false,
+ description: 'Full path of the namespace'
- field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
+ field :description, GraphQL::STRING_TYPE, null: true,
+ description: 'Description of the namespace'
markdown_field :description_html, null: true
- field :visibility, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled? # rubocop:disable Graphql/Descriptions
- field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
+ field :visibility, GraphQL::STRING_TYPE, null: true,
+ description: 'Visibility of the namespace'
+ field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled?,
+ description: 'Indicates if Large File Storage (LFS) is enabled for namespace'
+ field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if users can request access to namespace'
field :root_storage_statistics, Types::RootStorageStatisticsType,
null: true,
- description: 'The aggregated storage statistics. Only available for root namespaces',
+ description: 'Aggregated storage statistics of the namespace. Only available for root namespaces',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader.new(obj.id).find }
- field :projects, # rubocop:disable Graphql/Descriptions
- Types::ProjectType.connection_type,
- null: false,
+ field :projects, Types::ProjectType.connection_type, null: false,
+ description: 'Projects within this namespace',
resolver: ::Resolvers::NamespaceProjectsResolver
end
end
diff --git a/app/graphql/types/project_statistics_type.rb b/app/graphql/types/project_statistics_type.rb
index 5045471a75b..c46410df6c0 100644
--- a/app/graphql/types/project_statistics_type.rb
+++ b/app/graphql/types/project_statistics_type.rb
@@ -6,13 +6,20 @@ module Types
authorize :read_statistics
- field :commit_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :commit_count, GraphQL::INT_TYPE, null: false,
+ description: 'Commit count of the project'
- field :storage_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :repository_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :lfs_objects_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :build_artifacts_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :packages_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :wiki_size, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions
+ field :storage_size, GraphQL::INT_TYPE, null: false,
+ description: 'Storage size of the project'
+ field :repository_size, GraphQL::INT_TYPE, null: false,
+ description: 'Repository size of the project'
+ field :lfs_objects_size, GraphQL::INT_TYPE, null: false,
+ description: 'Large File Storage (LFS) object size of the project'
+ field :build_artifacts_size, GraphQL::INT_TYPE, null: false,
+ description: 'Build artifacts size of the project'
+ field :packages_size, GraphQL::INT_TYPE, null: false,
+ description: 'Packages size of the project'
+ field :wiki_size, GraphQL::INT_TYPE, null: true,
+ description: 'Wiki size of the project'
end
end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 3f05610cf1f..f1e735508cc 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -8,98 +8,142 @@ module Types
expose_permissions Types::PermissionTypes::Project
- field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the project'
- field :full_path, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :full_path, GraphQL::ID_TYPE, null: false,
+ description: 'Full path of the project'
+ field :path, GraphQL::STRING_TYPE, null: false,
+ description: 'Path of the project'
- field :name_with_namespace, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :name_with_namespace, GraphQL::STRING_TYPE, null: false,
+ description: 'Full name of the project with its namespace'
+ field :name, GraphQL::STRING_TYPE, null: false,
+ description: 'Name of the project (without namespace)'
- field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
+ field :description, GraphQL::STRING_TYPE, null: true,
+ description: 'Short description of the project'
markdown_field :description_html, null: true
- field :tag_list, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
-
- field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :http_url_to_repo, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
-
- field :star_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true # 4 times # rubocop:disable Graphql/Descriptions
-
- field :created_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
- field :last_activity_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions
-
- field :archived, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
-
- field :visibility, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
-
- field :container_registry_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
-
- field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
- project.avatar_url(only_path: false)
- end
+ field :tag_list, GraphQL::STRING_TYPE, null: true,
+ description: 'List of project tags'
+
+ field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true,
+ description: 'URL to connect to the project via SSH'
+ field :http_url_to_repo, GraphQL::STRING_TYPE, null: true,
+ description: 'URL to connect to the project via HTTPS'
+ field :web_url, GraphQL::STRING_TYPE, null: true,
+ description: 'Web URL of the project'
+
+ field :star_count, GraphQL::INT_TYPE, null: false,
+ description: 'Number of times the project has been starred'
+ field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true, # 4 times
+ description: 'Number of times the project has been forked'
+
+ field :created_at, Types::TimeType, null: true,
+ description: 'Timestamp of the project creation'
+ field :last_activity_at, Types::TimeType, null: true,
+ description: 'Timestamp of the project last activity'
+
+ field :archived, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Archived status of the project'
+
+ field :visibility, GraphQL::STRING_TYPE, null: true,
+ description: 'Visibility of the project'
+
+ field :container_registry_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if the project stores Docker container images in a container registry'
+ field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if shared runners are enabled on the project'
+ field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if the project has Large File Storage (LFS) enabled'
+ field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.'
+
+ field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true,
+ description: 'URL to avatar image file of the project',
+ resolve: -> (project, args, ctx) do
+ project.avatar_url(only_path: false)
+ end
%i[issues merge_requests wiki snippets].each do |feature|
- field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
- project.feature_available?(feature, ctx[:current_user])
- end
+ field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true,
+ description: "(deprecated) Does this project have #{feature} enabled?. Use `#{feature}_access_level` instead",
+ resolve: -> (project, args, ctx) do
+ project.feature_available?(feature, ctx[:current_user])
+ end
end
- field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
- project.feature_available?(:builds, ctx[:current_user])
- end
-
- field :public_jobs, GraphQL::BOOLEAN_TYPE, method: :public_builds, null: true # rubocop:disable Graphql/Descriptions
-
- field :open_issues_count, GraphQL::INT_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions
- project.open_issues_count if project.feature_available?(:issues, ctx[:current_user])
- end
-
- field :import_status, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions
-
- field :only_allow_merge_if_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions
- field :remove_source_branch_after_merge, GraphQL::BOOLEAN_TYPE, null: true, description: 'Remove the source branch by default after merge'
-
- field :namespace, Types::NamespaceType, null: true # rubocop:disable Graphql/Descriptions
- field :group, Types::GroupType, null: true # rubocop:disable Graphql/Descriptions
-
- field :statistics, Types::ProjectStatisticsType, # rubocop:disable Graphql/Descriptions
+ field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: '(deprecated) Enable jobs for this project. Use `builds_access_level` instead',
+ resolve: -> (project, args, ctx) do
+ project.feature_available?(:builds, ctx[:current_user])
+ end
+
+ field :public_jobs, GraphQL::BOOLEAN_TYPE, method: :public_builds, null: true,
+ description: 'Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts'
+
+ field :open_issues_count, GraphQL::INT_TYPE, null: true,
+ description: 'Number of open issues for the project',
+ resolve: -> (project, args, ctx) do
+ project.open_issues_count if project.feature_available?(:issues, ctx[:current_user])
+ end
+
+ field :import_status, GraphQL::STRING_TYPE, null: true,
+ description: 'Status of project import background job of the project'
+
+ field :only_allow_merge_if_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if merge requests of the project can only be merged with successful jobs'
+ field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if users can request member access to the project'
+ field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if merge requests of the project can only be merged when all the discussions are resolved'
+ field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line'
+ field :remove_source_branch_after_merge, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project'
+
+ field :namespace, Types::NamespaceType, null: true,
+ description: 'Namespace of the project'
+ field :group, Types::GroupType, null: true,
+ description: 'Group of the project'
+
+ field :statistics, Types::ProjectStatisticsType,
null: true,
+ description: 'Statistics of the project',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find }
- field :repository, Types::RepositoryType, null: true # rubocop:disable Graphql/Descriptions
+ field :repository, Types::RepositoryType, null: true,
+ description: 'Git repository of the project'
- field :merge_requests, # rubocop:disable Graphql/Descriptions
+ field :merge_requests,
Types::MergeRequestType.connection_type,
null: true,
+ description: 'Merge requests of the project',
resolver: Resolvers::MergeRequestsResolver
- field :merge_request, # rubocop:disable Graphql/Descriptions
+ field :merge_request,
Types::MergeRequestType,
null: true,
+ description: 'A single merge request of the project',
resolver: Resolvers::MergeRequestsResolver.single
- field :issues, # rubocop:disable Graphql/Descriptions
+ field :issues,
Types::IssueType.connection_type,
null: true,
+ description: 'Issues of the project',
resolver: Resolvers::IssuesResolver
- field :issue, # rubocop:disable Graphql/Descriptions
+ field :issue,
Types::ExtendedIssueType,
null: true,
+ description: 'A single issue of the project',
resolver: Resolvers::IssuesResolver.single
- field :pipelines, # rubocop:disable Graphql/Descriptions
+ field :pipelines,
Types::Ci::PipelineType.connection_type,
null: true,
+ description: 'Build pipelines of the project',
resolver: Resolvers::ProjectPipelinesResolver
end
end
diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb
index 9ecd336b41d..f0c25e13a26 100644
--- a/app/graphql/types/repository_type.rb
+++ b/app/graphql/types/repository_type.rb
@@ -6,9 +6,13 @@ module Types
authorize :download_code
- field :root_ref, GraphQL::STRING_TYPE, null: true, calls_gitaly: true # rubocop:disable Graphql/Descriptions
- field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?, calls_gitaly: true # rubocop:disable Graphql/Descriptions
- field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists? # rubocop:disable Graphql/Descriptions
- field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true # rubocop:disable Graphql/Descriptions
+ field :root_ref, GraphQL::STRING_TYPE, null: true, calls_gitaly: true,
+ description: 'Default branch of the repository'
+ field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?, calls_gitaly: true,
+ description: 'Indicates repository has no visible content'
+ field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists?,
+ description: 'Indicates a corresponding Git repository exists on disk'
+ field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true,
+ description: 'Tree of the repository'
end
end
diff --git a/app/graphql/types/task_completion_status.rb b/app/graphql/types/task_completion_status.rb
index 0aa8fc60a7c..73a8b4f3020 100644
--- a/app/graphql/types/task_completion_status.rb
+++ b/app/graphql/types/task_completion_status.rb
@@ -8,8 +8,10 @@ module Types
graphql_name 'TaskCompletionStatus'
description 'Completion status of tasks'
- field :count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :completed_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :count, GraphQL::INT_TYPE, null: false,
+ description: 'Number of total tasks'
+ field :completed_count, GraphQL::INT_TYPE, null: false,
+ description: 'Number of completed tasks'
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb
index 1ba37927b40..b45c7893e75 100644
--- a/app/graphql/types/user_type.rb
+++ b/app/graphql/types/user_type.rb
@@ -8,12 +8,16 @@ module Types
present_using UserPresenter
- field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :username, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :avatar_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
- field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions
+ field :name, GraphQL::STRING_TYPE, null: false,
+ description: 'Human-readable name of the user'
+ field :username, GraphQL::STRING_TYPE, null: false,
+ description: 'Username of the user. Unique within this instance of GitLab'
+ field :avatar_url, GraphQL::STRING_TYPE, null: false,
+ description: "URL of the user's avatar"
+ field :web_url, GraphQL::STRING_TYPE, null: false,
+ description: 'Web URL of the user'
field :todos, Types::TodoType.connection_type, null: false,
resolver: Resolvers::TodoResolver,
- description: 'Todos of this user'
+ description: 'Todos of the user'
end
end
diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml
index 543441b9479..15c83f92474 100644
--- a/app/views/projects/merge_requests/creations/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml
@@ -1,15 +1,5 @@
%h3.page-title
New Merge Request
-%p.slead
- - source_title, target_title = format_mr_branch_names(@merge_request)
- From
- %strong.ref-name= source_title
- %span into
- %strong.ref-name= target_title
-
- %span.float-right
- = link_to 'Change branches', mr_change_branches_path(@merge_request)
-%hr
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form common-note-form js-requires-input js-quick-submit' } do |f|
= render 'shared/issuable/form', f: f, issuable: @merge_request, commits: @commits, presenter: @mr_presenter
= f.hidden_field :source_project_id
diff --git a/app/views/projects/merge_requests/edit.html.haml b/app/views/projects/merge_requests/edit.html.haml
index 03159f123f3..318c9d809c1 100644
--- a/app/views/projects/merge_requests/edit.html.haml
+++ b/app/views/projects/merge_requests/edit.html.haml
@@ -2,5 +2,4 @@
%h3.page-title
Edit Merge Request #{@merge_request.to_reference}
-%hr
= render 'form'
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 5e2b5f95ee3..a8aae03aad7 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -12,6 +12,9 @@
= link_to "the #{issuable.class.model_name.human.downcase}", polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), target: "_blank", rel: 'noopener noreferrer'
and make sure your changes will not unintentionally remove theirs
+= render 'shared/issuable/form/branch_chooser', issuable: issuable, form: form
+
+%hr
.form-group.row
= form.label :title, class: 'col-form-label col-sm-2'
@@ -34,8 +37,6 @@
= render_if_exists 'shared/issuable/approvals', issuable: issuable, presenter: presenter, form: form
-= render 'shared/issuable/form/branch_chooser', issuable: issuable, form: form
-
= render 'shared/issuable/form/merge_params', issuable: issuable
= render 'shared/issuable/form/contribution', issuable: issuable, form: form
diff --git a/app/views/shared/issuable/form/_branch_chooser.html.haml b/app/views/shared/issuable/form/_branch_chooser.html.haml
index fbc96baa0f7..03eebe7c987 100644
--- a/app/views/shared/issuable/form/_branch_chooser.html.haml
+++ b/app/views/shared/issuable/form/_branch_chooser.html.haml
@@ -4,21 +4,19 @@
- return unless issuable.is_a?(MergeRequest)
- return if issuable.closed_without_fork?
-%hr
-- if issuable.new_record?
- .form-group.row
- = form.label :source_branch, class: 'col-form-label col-sm-2'
- .col-sm-10
- .issuable-form-select-holder
- = form.select(:source_branch, [issuable.source_branch], {}, { class: 'source_branch select2 ref-name', disabled: true })
-.form-group.row
- = form.label :target_branch, class: 'col-form-label col-sm-2'
- .col-sm-10.target-branch-select-dropdown-container
- .issuable-form-select-holder
- = form.hidden_field(:target_branch,
- { class: 'target_branch js-target-branch-select ref-name',
- disabled: issuable.new_record?,
- data: { placeholder: "Select branch", endpoint: refs_project_path(@project, sort: 'updated_desc', find: 'branches') }})
+- source_title, target_title = format_mr_branch_names(@merge_request)
+
+.form-group.row.d-flex.gl-pl-3.gl-pr-3.branch-selector
+ .align-self-center
+ %span= s_('From %{source_title} into').html_safe % { source_title: "<code>#{source_title}</code>".html_safe }
- if issuable.new_record?
+ %code= target_title
&nbsp;
- = link_to 'Change branches', mr_change_branches_path(issuable)
+ = link_to _('Change branches'), mr_change_branches_path(issuable)
+ - elsif issuable.for_fork?
+ %code= issuable.target_project_path + ":"
+ - unless issuable.new_record?
+ %span.dropdown.prepend-left-5.d-inline-block
+ = form.hidden_field(:target_branch,
+ { class: 'target_branch js-target-branch-select ref-name mw-xl',
+ data: { placeholder: _('Select branch'), endpoint: refs_project_path(@project, sort: 'updated_desc', find: 'branches') }})
diff --git a/app/views/shared/issuable/form/_merge_params.html.haml b/app/views/shared/issuable/form/_merge_params.html.haml
index f0c4acdd07f..1b557214e02 100644
--- a/app/views/shared/issuable/form/_merge_params.html.haml
+++ b/app/views/shared/issuable/form/_merge_params.html.haml
@@ -3,17 +3,17 @@
- return unless issuable.is_a?(MergeRequest)
- return if issuable.closed_without_fork?
-- if issuable.can_remove_source_branch?(current_user)
- .form-group.row
- .col-sm-10.offset-sm-2
- .form-check
+.form-group.row
+ .col-sm-2.col-form-label.pt-sm-0
+ %label
+ = _('Merge options')
+ .col-sm-10
+ - if issuable.can_remove_source_branch?(current_user)
+ .form-check.append-bottom-default
= hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil
= check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch?, class: 'form-check-input'
= label_tag 'merge_request[force_remove_source_branch]', class: 'form-check-label' do
Delete source branch when merge request is accepted.
-
-.form-group.row
- .col-sm-10.offset-sm-2
.form-check
= hidden_field_tag 'merge_request[squash]', '0', id: nil
= check_box_tag 'merge_request[squash]', '1', issuable.squash, class: 'form-check-input'
diff --git a/app/views/shared/notifications/_button.html.haml b/app/views/shared/notifications/_button.html.haml
index 441abd57334..2b3e986a841 100644
--- a/app/views/shared/notifications/_button.html.haml
+++ b/app/views/shared/notifications/_button.html.haml
@@ -17,14 +17,14 @@
.js-notification-toggle-btns
%div{ class: ("btn-group" if notification_setting.custom?) }
- if notification_setting.custom?
- %button.dropdown-new.btn.btn-default.btn-xs.has-tooltip.notifications-btn.text-left#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
+ %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn.text-left#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
= icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level)
- %button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
+ %button.btn.dropdown-toggle.d-flex{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
= icon('caret-down')
.sr-only Toggle dropdown
- else
- %button.dropdown-new.btn.btn-default.btn-xs.has-tooltip.notifications-btn#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
+ %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
.float-left
= icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level)
diff --git a/app/views/shared/notifications/_custom_notifications.html.haml b/app/views/shared/notifications/_custom_notifications.html.haml
index 43a87fd8397..1fef43c0c37 100644
--- a/app/views/shared/notifications/_custom_notifications.html.haml
+++ b/app/views/shared/notifications/_custom_notifications.html.haml
@@ -1,3 +1,5 @@
+- hide_label = local_assigns.fetch(:hide_label, false)
+
.modal.fade{ tabindex: "-1", role: "dialog", id: notifications_menu_identifier("modal", notification_setting), "aria-labelledby": "custom-notifications-title" }
.modal-dialog
.modal-content
@@ -11,6 +13,7 @@
.container-fluid
= form_for notification_setting, html: { class: "custom-notifications-form" } do |f|
= hidden_setting_source_input(notification_setting)
+ = hidden_field_tag("hide_label", true) if hide_label
.row
.col-lg-4
%h4.prepend-top-0= _('Notification events')
diff --git a/app/views/shared/notifications/_new_button.html.haml b/app/views/shared/notifications/_new_button.html.haml
index 3c8cc023848..363053b5e35 100644
--- a/app/views/shared/notifications/_new_button.html.haml
+++ b/app/views/shared/notifications/_new_button.html.haml
@@ -31,4 +31,4 @@
= render "shared/notifications/notification_dropdown", notification_setting: notification_setting
= content_for :scripts_body do
- = render "shared/notifications/custom_notifications", notification_setting: notification_setting
+ = render "shared/notifications/custom_notifications", notification_setting: notification_setting, hide_label: true
diff --git a/changelogs/unreleased/maintenance-move-branch-selector-to-top.yml b/changelogs/unreleased/maintenance-move-branch-selector-to-top.yml
new file mode 100644
index 00000000000..78455c49116
--- /dev/null
+++ b/changelogs/unreleased/maintenance-move-branch-selector-to-top.yml
@@ -0,0 +1,6 @@
+---
+title: Reduce new MR page redundancy by moving the source/target branch selector to
+ the top
+merge_request: 17559
+author:
+type: changed
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 3f05b80ab63..a8c4e966099 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -47,16 +47,16 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `id` | ID! | |
-| `sha` | String! | |
-| `title` | String | |
-| `description` | String | |
-| `message` | String | |
-| `authoredDate` | Time | |
-| `webUrl` | String! | |
-| `signatureHtml` | String | Rendered html for the commit signature |
-| `author` | User | |
-| `latestPipeline` | Pipeline | Latest pipeline for this commit |
+| `id` | ID! | ID (global ID) of the commit |
+| `sha` | String! | SHA1 ID of the commit |
+| `title` | String | Title of the commit message |
+| `description` | String | Description of the commit message |
+| `message` | String | Raw commit message |
+| `authoredDate` | Time | Timestamp of when the commit was authored |
+| `webUrl` | String! | Web URL of the commit |
+| `signatureHtml` | String | Rendered HTML of the commit signature |
+| `author` | User | Author of the commit |
+| `latestPipeline` | Pipeline | Latest pipeline of the commit |
### CreateDiffNotePayload
@@ -226,30 +226,30 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
-| `iid` | ID! | |
-| `title` | String! | |
+| `iid` | ID! | Internal ID of the issue |
+| `title` | String! | Title of the issue |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
+| `description` | String | Description of the issue |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | IssueState! | |
-| `reference` | String! | |
-| `author` | User! | |
-| `milestone` | Milestone | |
-| `dueDate` | Time | |
-| `confidential` | Boolean! | |
-| `discussionLocked` | Boolean! | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `userNotesCount` | Int! | |
-| `webPath` | String! | |
-| `webUrl` | String! | |
-| `relativePosition` | Int | |
-| `timeEstimate` | Int! | The time estimate on the issue |
+| `state` | IssueState! | State of the issue |
+| `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
+| `author` | User! | User that created the issue |
+| `milestone` | Milestone | Milestone of the issue |
+| `dueDate` | Time | Due date of the issue |
+| `confidential` | Boolean! | Indicates the issue is confidential |
+| `discussionLocked` | Boolean! | Indicates discussion is locked on the issue |
+| `upvotes` | Int! | Number of upvotes the issue has received |
+| `downvotes` | Int! | Number of downvotes the issue has received |
+| `userNotesCount` | Int! | Number of user notes of the issue |
+| `webPath` | String! | Web path of the issue |
+| `webUrl` | String! | Web URL of the issue |
+| `relativePosition` | Int | Relative position of the issue (used for positioning in epic tree and issue boards) |
+| `timeEstimate` | Int! | Time estimate of the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
-| `closedAt` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
+| `closedAt` | Time | Timestamp of when the issue was closed |
+| `createdAt` | Time! | Timestamp of when the issue was created |
+| `updatedAt` | Time! | Timestamp of when the issue was last updated |
+| `taskCompletionStatus` | TaskCompletionStatus! | Task completion status of the issue |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
@@ -283,30 +283,30 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
-| `iid` | ID! | |
-| `title` | String! | |
+| `iid` | ID! | Internal ID of the issue |
+| `title` | String! | Title of the issue |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
+| `description` | String | Description of the issue |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | IssueState! | |
-| `reference` | String! | |
-| `author` | User! | |
-| `milestone` | Milestone | |
-| `dueDate` | Time | |
-| `confidential` | Boolean! | |
-| `discussionLocked` | Boolean! | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `userNotesCount` | Int! | |
-| `webPath` | String! | |
-| `webUrl` | String! | |
-| `relativePosition` | Int | |
-| `timeEstimate` | Int! | The time estimate on the issue |
+| `state` | IssueState! | State of the issue |
+| `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
+| `author` | User! | User that created the issue |
+| `milestone` | Milestone | Milestone of the issue |
+| `dueDate` | Time | Due date of the issue |
+| `confidential` | Boolean! | Indicates the issue is confidential |
+| `discussionLocked` | Boolean! | Indicates discussion is locked on the issue |
+| `upvotes` | Int! | Number of upvotes the issue has received |
+| `downvotes` | Int! | Number of downvotes the issue has received |
+| `userNotesCount` | Int! | Number of user notes of the issue |
+| `webPath` | String! | Web path of the issue |
+| `webUrl` | String! | Web URL of the issue |
+| `relativePosition` | Int | Relative position of the issue (used for positioning in epic tree and issue boards) |
+| `timeEstimate` | Int! | Time estimate of the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
-| `closedAt` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
+| `closedAt` | Time | Timestamp of when the issue was closed |
+| `createdAt` | Time! | Timestamp of when the issue was created |
+| `updatedAt` | Time! | Timestamp of when the issue was last updated |
+| `taskCompletionStatus` | TaskCompletionStatus! | Task completion status of the issue |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
@@ -317,21 +317,21 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `id` | ID! | |
-| `name` | String! | |
-| `path` | String! | |
-| `fullName` | String! | |
-| `fullPath` | ID! | |
-| `description` | String | |
+| `id` | ID! | ID of the namespace |
+| `name` | String! | Name of the namespace |
+| `path` | String! | Path of the namespace |
+| `fullName` | String! | Full name of the namespace |
+| `fullPath` | ID! | Full path of the namespace |
+| `description` | String | Description of the namespace |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `visibility` | String | |
-| `lfsEnabled` | Boolean | |
-| `requestAccessEnabled` | Boolean | |
-| `rootStorageStatistics` | RootStorageStatistics | The aggregated storage statistics. Only available for root namespaces |
+| `visibility` | String | Visibility of the namespace |
+| `lfsEnabled` | Boolean | Indicates if Large File Storage (LFS) is enabled for namespace |
+| `requestAccessEnabled` | Boolean | Indicates if users can request access to namespace |
+| `rootStorageStatistics` | RootStorageStatistics | Aggregated storage statistics of the namespace. Only available for root namespaces |
| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
-| `webUrl` | String! | |
-| `avatarUrl` | String | |
-| `parent` | Group | |
+| `webUrl` | String! | Web URL of the group |
+| `avatarUrl` | String | Avatar URL of the group |
+| `parent` | Group | Parent group |
| `epicsEnabled` | Boolean | |
| `epic` | Epic | |
@@ -346,30 +346,30 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
-| `iid` | ID! | |
-| `title` | String! | |
+| `iid` | ID! | Internal ID of the issue |
+| `title` | String! | Title of the issue |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
+| `description` | String | Description of the issue |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | IssueState! | |
-| `reference` | String! | |
-| `author` | User! | |
-| `milestone` | Milestone | |
-| `dueDate` | Time | |
-| `confidential` | Boolean! | |
-| `discussionLocked` | Boolean! | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `userNotesCount` | Int! | |
-| `webPath` | String! | |
-| `webUrl` | String! | |
-| `relativePosition` | Int | |
-| `timeEstimate` | Int! | The time estimate on the issue |
+| `state` | IssueState! | State of the issue |
+| `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
+| `author` | User! | User that created the issue |
+| `milestone` | Milestone | Milestone of the issue |
+| `dueDate` | Time | Due date of the issue |
+| `confidential` | Boolean! | Indicates the issue is confidential |
+| `discussionLocked` | Boolean! | Indicates discussion is locked on the issue |
+| `upvotes` | Int! | Number of upvotes the issue has received |
+| `downvotes` | Int! | Number of downvotes the issue has received |
+| `userNotesCount` | Int! | Number of user notes of the issue |
+| `webPath` | String! | Web path of the issue |
+| `webUrl` | String! | Web URL of the issue |
+| `relativePosition` | Int | Relative position of the issue (used for positioning in epic tree and issue boards) |
+| `timeEstimate` | Int! | Time estimate of the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
-| `closedAt` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
+| `closedAt` | Time | Timestamp of when the issue was closed |
+| `createdAt` | Time! | Timestamp of when the issue was created |
+| `updatedAt` | Time! | Timestamp of when the issue was last updated |
+| `taskCompletionStatus` | TaskCompletionStatus! | Task completion status of the issue |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
@@ -392,65 +392,65 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `description` | String | |
+| `description` | String | Description of the label (markdown rendered as HTML for caching) |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `title` | String! | |
-| `color` | String! | |
-| `textColor` | String! | |
+| `title` | String! | Content of the label |
+| `color` | String! | Background color of the label |
+| `textColor` | String! | Text color of the label |
### MergeRequest
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | MergeRequestPermissions! | Permissions for the current user on the resource |
-| `id` | ID! | |
-| `iid` | String! | |
-| `title` | String! | |
+| `id` | ID! | ID of the merge request |
+| `iid` | String! | Internal ID of the merge request |
+| `title` | String! | Title of the merge request |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
+| `description` | String | Description of the merge request (markdown rendered as HTML for caching) |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | MergeRequestState! | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `sourceProject` | Project | |
-| `targetProject` | Project! | |
-| `diffRefs` | DiffRefs | |
-| `project` | Project! | |
-| `projectId` | Int! | |
-| `sourceProjectId` | Int | |
-| `targetProjectId` | Int! | |
-| `sourceBranch` | String! | |
-| `targetBranch` | String! | |
-| `workInProgress` | Boolean! | |
-| `mergeWhenPipelineSucceeds` | Boolean | |
-| `diffHeadSha` | String | |
-| `mergeCommitSha` | String | |
-| `userNotesCount` | Int | |
-| `shouldRemoveSourceBranch` | Boolean | |
-| `forceRemoveSourceBranch` | Boolean | |
-| `mergeStatus` | String | |
-| `inProgressMergeCommitSha` | String | |
-| `mergeError` | String | |
-| `allowCollaboration` | Boolean | |
-| `shouldBeRebased` | Boolean! | |
-| `rebaseCommitSha` | String | |
-| `rebaseInProgress` | Boolean! | |
-| `mergeCommitMessage` | String | |
-| `defaultMergeCommitMessage` | String | |
-| `mergeOngoing` | Boolean! | |
-| `sourceBranchExists` | Boolean! | |
-| `mergeableDiscussionsState` | Boolean | |
-| `webUrl` | String | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `headPipeline` | Pipeline | |
-| `milestone` | Milestone | The milestone this merge request is linked to |
-| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this MR |
-| `discussionLocked` | Boolean! | Boolean flag determining if comments on the merge request are locked to members only |
-| `timeEstimate` | Int! | The time estimate for the merge request |
+| `state` | MergeRequestState! | State of the merge request |
+| `createdAt` | Time! | Timestamp of when the merge request was created |
+| `updatedAt` | Time! | Timestamp of when the merge request was last updated |
+| `sourceProject` | Project | Source project of the merge request |
+| `targetProject` | Project! | Target project of the merge request |
+| `diffRefs` | DiffRefs | References of the base SHA, the head SHA, and the start SHA for this merge request |
+| `project` | Project! | Alias for target_project |
+| `projectId` | Int! | ID of the merge request project |
+| `sourceProjectId` | Int | ID of the merge request source project |
+| `targetProjectId` | Int! | ID of the merge request target project |
+| `sourceBranch` | String! | Source branch of the merge request |
+| `targetBranch` | String! | Target branch of the merge request |
+| `workInProgress` | Boolean! | Indicates if the merge request is a work in progress (WIP) |
+| `mergeWhenPipelineSucceeds` | Boolean | Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS) |
+| `diffHeadSha` | String | Diff head SHA of the merge request |
+| `mergeCommitSha` | String | SHA of the merge request commit (set once merged) |
+| `userNotesCount` | Int | User notes count of the merge request |
+| `shouldRemoveSourceBranch` | Boolean | Indicates if the source branch of the merge request will be deleted after merge |
+| `forceRemoveSourceBranch` | Boolean | Indicates if the project settings will lead to source branch deletion after merge |
+| `mergeStatus` | String | Status of the merge request |
+| `inProgressMergeCommitSha` | String | Commit SHA of the merge request if merge is in progress |
+| `mergeError` | String | Error message due to a merge error |
+| `allowCollaboration` | Boolean | Indicates if members of the target project can push to the fork |
+| `shouldBeRebased` | Boolean! | Indicates if the merge request will be rebased |
+| `rebaseCommitSha` | String | Rebase commit SHA of the merge request |
+| `rebaseInProgress` | Boolean! | Indicates if there is a rebase currently in progress for the merge request |
+| `mergeCommitMessage` | String | Deprecated - renamed to defaultMergeCommitMessage |
+| `defaultMergeCommitMessage` | String | Default merge commit message of the merge request |
+| `mergeOngoing` | Boolean! | Indicates if a merge is currently occurring |
+| `sourceBranchExists` | Boolean! | Indicates if the source branch of the merge request exists |
+| `mergeableDiscussionsState` | Boolean | Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged |
+| `webUrl` | String | Web URL of the merge request |
+| `upvotes` | Int! | Number of upvotes for the merge request |
+| `downvotes` | Int! | Number of downvotes for the merge request |
+| `headPipeline` | Pipeline | The pipeline running on the branch HEAD of the merge request |
+| `milestone` | Milestone | The milestone of the merge request |
+| `subscribed` | Boolean! | Indicates if the currently logged in user is subscribed to this merge request |
+| `discussionLocked` | Boolean! | Indicates if comments on the merge request are locked to members only |
+| `timeEstimate` | Int! | Time estimate of the merge request |
| `totalTimeSpent` | Int! | Total time reported as spent on the merge request |
-| `reference` | String! | Internal merge request reference. Returned in shortened format by default |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
+| `reference` | String! | Internal reference of the merge request. Returned in shortened format by default |
+| `taskCompletionStatus` | TaskCompletionStatus! | Completion status of tasks |
### MergeRequestPermissions
@@ -477,36 +477,36 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `version` | String! | |
-| `revision` | String! | |
+| `version` | String! | Version |
+| `revision` | String! | Revision |
### Milestone
| Name | Type | Description |
| --- | ---- | ---------- |
-| `description` | String | |
-| `title` | String! | |
-| `state` | String! | |
-| `dueDate` | Time | |
-| `startDate` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
+| `description` | String | Description of the milestone |
+| `title` | String! | Title of the milestone |
+| `state` | String! | State of the milestone |
+| `dueDate` | Time | Timestamp of the milestone due date |
+| `startDate` | Time | Timestamp of the milestone start date |
+| `createdAt` | Time! | Timestamp of milestone creation |
+| `updatedAt` | Time! | Timestamp of last milestone update |
### Namespace
| Name | Type | Description |
| --- | ---- | ---------- |
-| `id` | ID! | |
-| `name` | String! | |
-| `path` | String! | |
-| `fullName` | String! | |
-| `fullPath` | ID! | |
-| `description` | String | |
+| `id` | ID! | ID of the namespace |
+| `name` | String! | Name of the namespace |
+| `path` | String! | Path of the namespace |
+| `fullName` | String! | Full name of the namespace |
+| `fullPath` | ID! | Full path of the namespace |
+| `description` | String | Description of the namespace |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `visibility` | String | |
-| `lfsEnabled` | Boolean | |
-| `requestAccessEnabled` | Boolean | |
-| `rootStorageStatistics` | RootStorageStatistics | The aggregated storage statistics. Only available for root namespaces |
+| `visibility` | String | Visibility of the namespace |
+| `lfsEnabled` | Boolean | Indicates if Large File Storage (LFS) is enabled for namespace |
+| `requestAccessEnabled` | Boolean | Indicates if users can request access to namespace |
+| `rootStorageStatistics` | RootStorageStatistics | Aggregated storage statistics of the namespace. Only available for root namespaces |
### Note
@@ -578,47 +578,47 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | ProjectPermissions! | Permissions for the current user on the resource |
-| `id` | ID! | |
-| `fullPath` | ID! | |
-| `path` | String! | |
-| `nameWithNamespace` | String! | |
-| `name` | String! | |
-| `description` | String | |
+| `id` | ID! | ID of the project |
+| `fullPath` | ID! | Full path of the project |
+| `path` | String! | Path of the project |
+| `nameWithNamespace` | String! | Full name of the project with its namespace |
+| `name` | String! | Name of the project (without namespace) |
+| `description` | String | Short description of the project |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `tagList` | String | |
-| `sshUrlToRepo` | String | |
-| `httpUrlToRepo` | String | |
-| `webUrl` | String | |
-| `starCount` | Int! | |
-| `forksCount` | Int! | |
-| `createdAt` | Time | |
-| `lastActivityAt` | Time | |
-| `archived` | Boolean | |
-| `visibility` | String | |
-| `containerRegistryEnabled` | Boolean | |
-| `sharedRunnersEnabled` | Boolean | |
-| `lfsEnabled` | Boolean | |
-| `mergeRequestsFfOnlyEnabled` | Boolean | |
-| `avatarUrl` | String | |
-| `issuesEnabled` | Boolean | |
-| `mergeRequestsEnabled` | Boolean | |
-| `wikiEnabled` | Boolean | |
-| `snippetsEnabled` | Boolean | |
-| `jobsEnabled` | Boolean | |
-| `publicJobs` | Boolean | |
-| `openIssuesCount` | Int | |
-| `importStatus` | String | |
-| `onlyAllowMergeIfPipelineSucceeds` | Boolean | |
-| `requestAccessEnabled` | Boolean | |
-| `onlyAllowMergeIfAllDiscussionsAreResolved` | Boolean | |
-| `printingMergeRequestLinkEnabled` | Boolean | |
-| `removeSourceBranchAfterMerge` | Boolean | Remove the source branch by default after merge |
-| `namespace` | Namespace | |
-| `group` | Group | |
-| `statistics` | ProjectStatistics | |
-| `repository` | Repository | |
-| `mergeRequest` | MergeRequest | |
-| `issue` | ExtendedIssue | |
+| `tagList` | String | List of project tags |
+| `sshUrlToRepo` | String | URL to connect to the project via SSH |
+| `httpUrlToRepo` | String | URL to connect to the project via HTTPS |
+| `webUrl` | String | Web URL of the project |
+| `starCount` | Int! | Number of times the project has been starred |
+| `forksCount` | Int! | Number of times the project has been forked |
+| `createdAt` | Time | Timestamp of the project creation |
+| `lastActivityAt` | Time | Timestamp of the project last activity |
+| `archived` | Boolean | Archived status of the project |
+| `visibility` | String | Visibility of the project |
+| `containerRegistryEnabled` | Boolean | Indicates if the project stores Docker container images in a container registry |
+| `sharedRunnersEnabled` | Boolean | Indicates if shared runners are enabled on the project |
+| `lfsEnabled` | Boolean | Indicates if the project has Large File Storage (LFS) enabled |
+| `mergeRequestsFfOnlyEnabled` | Boolean | Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. |
+| `avatarUrl` | String | URL to avatar image file of the project |
+| `issuesEnabled` | Boolean | (deprecated) Does this project have issues enabled?. Use `issues_access_level` instead |
+| `mergeRequestsEnabled` | Boolean | (deprecated) Does this project have merge_requests enabled?. Use `merge_requests_access_level` instead |
+| `wikiEnabled` | Boolean | (deprecated) Does this project have wiki enabled?. Use `wiki_access_level` instead |
+| `snippetsEnabled` | Boolean | (deprecated) Does this project have snippets enabled?. Use `snippets_access_level` instead |
+| `jobsEnabled` | Boolean | (deprecated) Enable jobs for this project. Use `builds_access_level` instead |
+| `publicJobs` | Boolean | Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts |
+| `openIssuesCount` | Int | Number of open issues for the project |
+| `importStatus` | String | Status of project import background job of the project |
+| `onlyAllowMergeIfPipelineSucceeds` | Boolean | Indicates if merge requests of the project can only be merged with successful jobs |
+| `requestAccessEnabled` | Boolean | Indicates if users can request member access to the project |
+| `onlyAllowMergeIfAllDiscussionsAreResolved` | Boolean | Indicates if merge requests of the project can only be merged when all the discussions are resolved |
+| `printingMergeRequestLinkEnabled` | Boolean | Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line |
+| `removeSourceBranchAfterMerge` | Boolean | Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project |
+| `namespace` | Namespace | Namespace of the project |
+| `group` | Group | Group of the project |
+| `statistics` | ProjectStatistics | Statistics of the project |
+| `repository` | Repository | Git repository of the project |
+| `mergeRequest` | MergeRequest | A single merge request of the project |
+| `issue` | ExtendedIssue | A single issue of the project |
### ProjectPermissions
@@ -670,13 +670,13 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `commitCount` | Int! | |
-| `storageSize` | Int! | |
-| `repositorySize` | Int! | |
-| `lfsObjectsSize` | Int! | |
-| `buildArtifactsSize` | Int! | |
-| `packagesSize` | Int! | |
-| `wikiSize` | Int | |
+| `commitCount` | Int! | Commit count of the project |
+| `storageSize` | Int! | Storage size of the project |
+| `repositorySize` | Int! | Repository size of the project |
+| `lfsObjectsSize` | Int! | Large File Storage (LFS) object size of the project |
+| `buildArtifactsSize` | Int! | Build artifacts size of the project |
+| `packagesSize` | Int! | Packages size of the project |
+| `wikiSize` | Int | Wiki size of the project |
### RemoveAwardEmojiPayload
@@ -690,10 +690,10 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `rootRef` | String | |
-| `empty` | Boolean! | |
-| `exists` | Boolean! | |
-| `tree` | Tree | |
+| `rootRef` | String | Default branch of the repository |
+| `empty` | Boolean! | Indicates repository has no visible content |
+| `exists` | Boolean! | Indicates a corresponding Git repository exists on disk |
+| `tree` | Tree | Tree of the repository |
### RootStorageStatistics
@@ -722,8 +722,8 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `count` | Int! | |
-| `completedCount` | Int! | |
+| `count` | Int! | Number of total tasks |
+| `completedCount` | Int! | Number of completed tasks |
### Todo
@@ -785,7 +785,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `name` | String! | |
-| `username` | String! | |
-| `avatarUrl` | String! | |
-| `webUrl` | String! | |
+| `name` | String! | Human-readable name of the user |
+| `username` | String! | Username of the user. Unique within this instance of GitLab |
+| `avatarUrl` | String! | URL of the user's avatar |
+| `webUrl` | String! | Web URL of the user |
diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb
index f22fc41a6d8..0e7e0c40a8a 100644
--- a/lib/gitlab/danger/helper.rb
+++ b/lib/gitlab/danger/helper.rb
@@ -93,8 +93,8 @@ module Gitlab
docs: "~documentation", # Docs are reviewed along DevOps stages, so don't need roulette for now.
none: "",
qa: "~QA",
- test: "~test for `spec/features/*`",
- engineering_productivity: "Engineering Productivity for CI config review"
+ test: "~test ~Quality for `spec/features/*`",
+ engineering_productivity: '~"Engineering Productivity" for CI, Danger'
}.freeze
CATEGORIES = {
%r{\Adoc/} => :none, # To reinstate roulette for documentation, set to `:docs`.
@@ -104,7 +104,7 @@ module Gitlab
%r{\A(ee/)?public/} => :frontend,
%r{\A(ee/)?spec/(javascripts|frontend)/} => :frontend,
%r{\A(ee/)?vendor/assets/} => :frontend,
- %r{\Ascripts/frontend/} => :frontend,
+ %r{\A(ee/)?scripts/frontend/} => :frontend,
%r{(\A|/)(
\.babelrc |
\.eslintignore |
@@ -130,14 +130,18 @@ module Gitlab
%r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => :database,
%r{\Arubocop/cop/migration(/|\.rb)} => :database,
+ %r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :engineering_productivity,
+ %r{Dangerfile\z} => :engineering_productivity,
+ %r{\A(ee/)?(danger/|lib/gitlab/danger/)} => :engineering_productivity,
+ %r{\A(ee/)?scripts/} => :engineering_productivity,
+
%r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend,
- %r{\A(ee/)?(bin|config|danger|generator_templates|lib|rubocop|scripts)/} => :backend,
+ %r{\A(ee/)?(bin|config|generator_templates|lib|rubocop)/} => :backend,
%r{\A(ee/)?spec/features/} => :test,
%r{\A(ee/)?spec/(?!javascripts|frontend)[^/]+} => :backend,
%r{\A(ee/)?vendor/(?!assets)[^/]+} => :backend,
%r{\A(ee/)?vendor/(languages\.yml|licenses\.csv)\z} => :backend,
- %r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :engineering_productivity,
- %r{\A(Dangerfile|Gemfile|Gemfile.lock|Procfile|Rakefile)\z} => :backend,
+ %r{\A(Gemfile|Gemfile.lock|Procfile|Rakefile)\z} => :backend,
%r{\A[A-Z_]+_VERSION\z} => :backend,
%r{\A\.rubocop(_todo)?\.yml\z} => :backend,
diff --git a/lib/gitlab/danger/teammate.rb b/lib/gitlab/danger/teammate.rb
index 5c2324836d7..e96f5177195 100644
--- a/lib/gitlab/danger/teammate.rb
+++ b/lib/gitlab/danger/teammate.rb
@@ -67,7 +67,10 @@ module Gitlab
area && labels.any?("devops::#{area.downcase}") if kind == :reviewer
when :engineering_productivity
- role[/Engineering Productivity/] if kind == :reviewer
+ return false unless role[/Engineering Productivity/]
+ return true if kind == :reviewer
+
+ capabilities(project).include?("#{kind} backend")
else
capabilities(project).include?("#{kind} #{category}")
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8bd33a223ee..76bfa60867d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2898,6 +2898,9 @@ msgstr ""
msgid "Change assignee(s)."
msgstr ""
+msgid "Change branches"
+msgstr ""
+
msgid "Change label"
msgstr ""
@@ -7397,6 +7400,9 @@ msgstr ""
msgid "From %{providerTitle}"
msgstr ""
+msgid "From %{source_title} into"
+msgstr ""
+
msgid "From Bitbucket"
msgstr ""
@@ -10287,6 +10293,9 @@ msgstr ""
msgid "Merge in progress"
msgstr ""
+msgid "Merge options"
+msgstr ""
+
msgid "Merge request"
msgstr ""
@@ -14871,6 +14880,9 @@ msgstr ""
msgid "Select an existing Kubernetes cluster or create a new one"
msgstr ""
+msgid "Select branch"
+msgstr ""
+
msgid "Select branch/tag"
msgstr ""
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 973d5a2dcfc..f10cdf6da1e 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -216,8 +216,7 @@ describe 'Dashboard Projects' do
expect(page).to have_selector('.merge-request-form')
expect(current_path).to eq project_new_merge_request_path(project)
expect(find('#merge_request_target_project_id', visible: false).value).to eq project.id.to_s
- expect(find('input#merge_request_source_branch', visible: false).value).to eq 'feature'
- expect(find('input#merge_request_target_branch', visible: false).value).to eq 'master'
+ expect(page).to have_content "From feature into master"
end
end
diff --git a/spec/features/merge_request/user_edits_merge_request_spec.rb b/spec/features/merge_request/user_edits_merge_request_spec.rb
index 81c56855961..821db8a1d5b 100644
--- a/spec/features/merge_request/user_edits_merge_request_spec.rb
+++ b/spec/features/merge_request/user_edits_merge_request_spec.rb
@@ -17,7 +17,7 @@ describe 'User edits a merge request', :js do
end
it 'changes the target branch' do
- expect(page).to have_content('Target branch')
+ expect(page).to have_content('From master into feature')
select2('merge-test', from: '#merge_request_target_branch')
click_button('Save changes')
diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb
index 46a6f62ba14..34b15aeaa25 100644
--- a/spec/features/projects/commit/cherry_pick_spec.rb
+++ b/spec/features/projects/commit/cherry_pick_spec.rb
@@ -55,12 +55,16 @@ describe 'Cherry-pick Commits' do
end
end
- context "I cherry-pick a commit in a new merge request" do
+ context "I cherry-pick a commit in a new merge request", :js do
it do
+ find('.header-action-buttons a.dropdown-toggle').click
find("a[href='#modal-cherry-pick-commit']").click
page.within('#modal-cherry-pick-commit') do
click_button 'Cherry-pick'
end
+
+ wait_for_requests
+
expect(page).to have_content("The commit has been successfully cherry-picked into cherry-pick-#{master_pickable_commit.short_id}. You can now submit a merge request to get this change into the original branch.")
expect(page).to have_content("From cherry-pick-#{master_pickable_commit.short_id} into master")
end
diff --git a/spec/frontend/pipelines/graph/action_component_spec.js b/spec/frontend/pipelines/graph/action_component_spec.js
new file mode 100644
index 00000000000..38ffe98c79b
--- /dev/null
+++ b/spec/frontend/pipelines/graph/action_component_spec.js
@@ -0,0 +1,75 @@
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import axios from '~/lib/utils/axios_utils';
+import ActionComponent from '~/pipelines/components/graph/action_component.vue';
+
+describe('pipeline graph action component', () => {
+ let wrapper;
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ mock.onPost('foo.json').reply(200);
+
+ wrapper = mount(ActionComponent, {
+ propsData: {
+ tooltipText: 'bar',
+ link: 'foo',
+ actionIcon: 'cancel',
+ },
+ sync: false,
+ });
+ });
+
+ afterEach(() => {
+ mock.restore();
+ wrapper.destroy();
+ });
+
+ it('should render the provided title as a bootstrap tooltip', () => {
+ expect(wrapper.attributes('data-original-title')).toBe('bar');
+ });
+
+ it('should update bootstrap tooltip when title changes', done => {
+ wrapper.setProps({ tooltipText: 'changed' });
+
+ wrapper.vm
+ .$nextTick()
+ .then(() => {
+ expect(wrapper.attributes('data-original-title')).toBe('changed');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('should render an svg', () => {
+ expect(wrapper.find('.ci-action-icon-wrapper')).toBeDefined();
+ expect(wrapper.find('svg')).toBeDefined();
+ });
+
+ describe('on click', () => {
+ it('emits `pipelineActionRequestComplete` after a successful request', done => {
+ jest.spyOn(wrapper.vm, '$emit');
+
+ wrapper.find('button').trigger('click');
+
+ waitForPromises()
+ .then(() => {
+ expect(wrapper.vm.$emit).toHaveBeenCalledWith('pipelineActionRequestComplete');
+ done();
+ })
+ .catch(done.fail);
+ });
+
+ it('renders a loading icon while waiting for request', done => {
+ wrapper.find('button').trigger('click');
+
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.find('.js-action-icon-loading').exists()).toBe(true);
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/pipelines/pipeline_triggerer_spec.js b/spec/frontend/pipelines/pipeline_triggerer_spec.js
index 8cf290f2663..45ac278dd38 100644
--- a/spec/javascripts/pipelines/pipeline_triggerer_spec.js
+++ b/spec/frontend/pipelines/pipeline_triggerer_spec.js
@@ -17,6 +17,7 @@ describe('Pipelines Triggerer', () => {
const createComponent = () => {
wrapper = mount(pipelineTriggerer, {
propsData: mockData,
+ sync: false,
});
};
@@ -49,6 +50,8 @@ describe('Pipelines Triggerer', () => {
},
});
- expect(wrapper.find('.js-pipeline-url-api').text()).toEqual('API');
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.find('.js-pipeline-url-api').text()).toEqual('API');
+ });
});
});
diff --git a/spec/javascripts/pipelines/pipelines_table_row_spec.js b/spec/frontend/pipelines/pipelines_table_row_spec.js
index d47504d2f54..1c785ec6ffe 100644
--- a/spec/javascripts/pipelines/pipelines_table_row_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_row_spec.js
@@ -1,22 +1,21 @@
-import Vue from 'vue';
-import tableRowComp from '~/pipelines/components/pipelines_table_row.vue';
+import { mount } from '@vue/test-utils';
+import PipelinesTableRowComponent from '~/pipelines/components/pipelines_table_row.vue';
import eventHub from '~/pipelines/event_hub';
describe('Pipelines Table Row', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
- const buildComponent = pipeline => {
- const PipelinesTableRowComponent = Vue.extend(tableRowComp);
- return new PipelinesTableRowComponent({
- el: document.querySelector('.test-dom-element'),
+
+ const createWrapper = pipeline =>
+ mount(PipelinesTableRowComponent, {
propsData: {
pipeline,
autoDevopsHelpPath: 'foo',
viewType: 'root',
},
- }).$mount();
- };
+ sync: false,
+ });
- let component;
+ let wrapper;
let pipeline;
let pipelineWithoutAuthor;
let pipelineWithoutCommit;
@@ -32,28 +31,29 @@ describe('Pipelines Table Row', () => {
});
afterEach(() => {
- component.$destroy();
+ wrapper.destroy();
+ wrapper = null;
});
it('should render a table row', () => {
- component = buildComponent(pipeline);
+ wrapper = createWrapper(pipeline);
- expect(component.$el.getAttribute('class')).toContain('gl-responsive-table-row');
+ expect(wrapper.attributes('class')).toContain('gl-responsive-table-row');
});
describe('status column', () => {
beforeEach(() => {
- component = buildComponent(pipeline);
+ wrapper = createWrapper(pipeline);
});
it('should render a pipeline link', () => {
- expect(
- component.$el.querySelector('.table-section.commit-link a').getAttribute('href'),
- ).toEqual(pipeline.path);
+ expect(wrapper.find('.table-section.commit-link a').attributes('href')).toEqual(
+ pipeline.path,
+ );
});
it('should render status text', () => {
- expect(component.$el.querySelector('.table-section.commit-link a').textContent).toContain(
+ expect(wrapper.find('.table-section.commit-link a').text()).toContain(
pipeline.details.status.text,
);
});
@@ -61,33 +61,32 @@ describe('Pipelines Table Row', () => {
describe('information column', () => {
beforeEach(() => {
- component = buildComponent(pipeline);
+ wrapper = createWrapper(pipeline);
});
it('should render a pipeline link', () => {
- expect(
- component.$el.querySelector('.table-section:nth-child(2) a').getAttribute('href'),
- ).toEqual(pipeline.path);
+ expect(wrapper.find('.table-section:nth-child(2) a').attributes('href')).toEqual(
+ pipeline.path,
+ );
});
it('should render pipeline ID', () => {
- expect(
- component.$el.querySelector('.table-section:nth-child(2) a > span').textContent,
- ).toEqual(`#${pipeline.id}`);
+ expect(wrapper.find('.table-section:nth-child(2) a > span').text()).toEqual(
+ `#${pipeline.id}`,
+ );
});
describe('when a user is provided', () => {
it('should render user information', () => {
expect(
- component.$el
- .querySelector('.table-section:nth-child(3) .js-pipeline-url-user')
- .getAttribute('href'),
+ wrapper.find('.table-section:nth-child(3) .js-pipeline-url-user').attributes('href'),
).toEqual(pipeline.user.path);
expect(
- component.$el
- .querySelector('.table-section:nth-child(3) .js-user-avatar-image-toolip')
- .textContent.trim(),
+ wrapper
+ .find('.table-section:nth-child(3) .js-user-avatar-image-toolip')
+ .text()
+ .trim(),
).toEqual(pipeline.user.name);
});
});
@@ -95,40 +94,47 @@ describe('Pipelines Table Row', () => {
describe('commit column', () => {
it('should render link to commit', () => {
- component = buildComponent(pipeline);
+ wrapper = createWrapper(pipeline);
- const commitLink = component.$el.querySelector('.branch-commit .commit-sha');
+ const commitLink = wrapper.find('.branch-commit .commit-sha');
- expect(commitLink.getAttribute('href')).toEqual(pipeline.commit.commit_path);
+ expect(commitLink.attributes('href')).toEqual(pipeline.commit.commit_path);
});
const findElements = () => {
- const commitTitleElement = component.$el.querySelector('.branch-commit .commit-title');
- const commitAuthorElement = commitTitleElement.querySelector('a.avatar-image-container');
+ const commitTitleElement = wrapper.find('.branch-commit .commit-title');
+ const commitAuthorElement = commitTitleElement.find('a.avatar-image-container');
- if (!commitAuthorElement) {
- return { commitAuthorElement };
+ if (!commitAuthorElement.exists()) {
+ return {
+ commitAuthorElement,
+ };
}
- const commitAuthorLink = commitAuthorElement.getAttribute('href');
+ const commitAuthorLink = commitAuthorElement.attributes('href');
const commitAuthorName = commitAuthorElement
- .querySelector('.js-user-avatar-image-toolip')
- .textContent.trim();
-
- return { commitAuthorElement, commitAuthorLink, commitAuthorName };
+ .find('.js-user-avatar-image-toolip')
+ .text()
+ .trim();
+
+ return {
+ commitAuthorElement,
+ commitAuthorLink,
+ commitAuthorName,
+ };
};
it('renders nothing without commit', () => {
expect(pipelineWithoutCommit.commit).toBe(null);
- component = buildComponent(pipelineWithoutCommit);
+ wrapper = createWrapper(pipelineWithoutCommit);
const { commitAuthorElement } = findElements();
- expect(commitAuthorElement).toBe(null);
+ expect(commitAuthorElement.exists()).toBe(false);
});
it('renders commit author', () => {
- component = buildComponent(pipeline);
+ wrapper = createWrapper(pipeline);
const { commitAuthorLink, commitAuthorName } = findElements();
expect(commitAuthorLink).toEqual(pipeline.commit.author.path);
@@ -137,8 +143,8 @@ describe('Pipelines Table Row', () => {
it('renders commit with unregistered author', () => {
expect(pipelineWithoutAuthor.commit.author).toBe(null);
- component = buildComponent(pipelineWithoutAuthor);
+ wrapper = createWrapper(pipelineWithoutAuthor);
const { commitAuthorLink, commitAuthorName } = findElements();
expect(commitAuthorLink).toEqual(`mailto:${pipelineWithoutAuthor.commit.author_email}`);
@@ -148,13 +154,12 @@ describe('Pipelines Table Row', () => {
describe('stages column', () => {
beforeEach(() => {
- component = buildComponent(pipeline);
+ wrapper = createWrapper(pipeline);
});
it('should render an icon for each stage', () => {
expect(
- component.$el.querySelectorAll('.table-section:nth-child(4) .js-builds-dropdown-button')
- .length,
+ wrapper.findAll('.table-section:nth-child(4) .js-builds-dropdown-button').length,
).toEqual(pipeline.details.stages.length);
});
});
@@ -172,44 +177,49 @@ describe('Pipelines Table Row', () => {
withActions.cancel_path = '/cancel';
withActions.retry_path = '/retry';
- component = buildComponent(withActions);
+ wrapper = createWrapper(withActions);
});
it('should render the provided actions', () => {
- expect(component.$el.querySelector('.js-pipelines-retry-button')).not.toBeNull();
- expect(component.$el.querySelector('.js-pipelines-cancel-button')).not.toBeNull();
- const dropdownMenu = component.$el.querySelectorAll('.dropdown-menu');
+ expect(wrapper.find('.js-pipelines-retry-button').exists()).toBe(true);
+ expect(wrapper.find('.js-pipelines-cancel-button').exists()).toBe(true);
+ const dropdownMenu = wrapper.find('.dropdown-menu');
- expect(dropdownMenu).toContainText(scheduledJobAction.name);
+ expect(dropdownMenu.text()).toContain(scheduledJobAction.name);
});
it('emits `retryPipeline` event when retry button is clicked and toggles loading', () => {
eventHub.$on('retryPipeline', endpoint => {
- expect(endpoint).toEqual('/retry');
+ expect(endpoint).toBe('/retry');
});
- component.$el.querySelector('.js-pipelines-retry-button').click();
-
- expect(component.isRetrying).toEqual(true);
+ wrapper.find('.js-pipelines-retry-button').trigger('click');
+ expect(wrapper.vm.isRetrying).toBe(true);
});
it('emits `openConfirmationModal` event when cancel button is clicked and toggles loading', () => {
eventHub.$once('openConfirmationModal', data => {
const { id, ref, commit } = pipeline;
- expect(data.endpoint).toEqual('/cancel');
- expect(data.pipeline).toEqual(jasmine.objectContaining({ id, ref, commit }));
+ expect(data.endpoint).toBe('/cancel');
+ expect(data.pipeline).toEqual(
+ expect.objectContaining({
+ id,
+ ref,
+ commit,
+ }),
+ );
});
- component.$el.querySelector('.js-pipelines-cancel-button').click();
+ wrapper.find('.js-pipelines-cancel-button').trigger('click');
});
it('renders a loading icon when `cancelingPipeline` matches pipeline id', done => {
- component.cancelingPipeline = pipeline.id;
- component
+ wrapper.setProps({ cancelingPipeline: pipeline.id });
+ wrapper.vm
.$nextTick()
.then(() => {
- expect(component.isCancelling).toEqual(true);
+ expect(wrapper.vm.isCancelling).toBe(true);
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/pipelines/graph/action_component_spec.js b/spec/javascripts/pipelines/graph/action_component_spec.js
deleted file mode 100644
index 321497b35b5..00000000000
--- a/spec/javascripts/pipelines/graph/action_component_spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import Vue from 'vue';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import actionComponent from '~/pipelines/components/graph/action_component.vue';
-import mountComponent from '../../helpers/vue_mount_component_helper';
-
-describe('pipeline graph action component', () => {
- let component;
- let mock;
-
- beforeEach(done => {
- const ActionComponent = Vue.extend(actionComponent);
- mock = new MockAdapter(axios);
-
- mock.onPost('foo.json').reply(200);
-
- component = mountComponent(ActionComponent, {
- tooltipText: 'bar',
- link: 'foo',
- actionIcon: 'cancel',
- });
-
- Vue.nextTick(done);
- });
-
- afterEach(() => {
- mock.restore();
- component.$destroy();
- });
-
- it('should render the provided title as a bootstrap tooltip', () => {
- expect(component.$el.getAttribute('data-original-title')).toEqual('bar');
- });
-
- it('should update bootstrap tooltip when title changes', done => {
- component.tooltipText = 'changed';
-
- component
- .$nextTick()
- .then(() => {
- expect(component.$el.getAttribute('data-original-title')).toBe('changed');
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('should render an svg', () => {
- expect(component.$el.querySelector('.ci-action-icon-wrapper')).toBeDefined();
- expect(component.$el.querySelector('svg')).toBeDefined();
- });
-
- describe('on click', () => {
- it('emits `pipelineActionRequestComplete` after a successful request', done => {
- spyOn(component, '$emit');
-
- component.$el.click();
-
- setTimeout(() => {
- component
- .$nextTick()
- .then(() => {
- expect(component.$emit).toHaveBeenCalledWith('pipelineActionRequestComplete');
- })
- .catch(done.fail);
-
- done();
- }, 0);
- });
-
- it('renders a loading icon while waiting for request', done => {
- component.$el.click();
-
- component.$nextTick(() => {
- expect(component.$el.querySelector('.js-action-icon-loading')).not.toBeNull();
- setTimeout(() => {
- done();
- });
- });
- });
- });
-});
diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb
index 1696d3566ad..8056418e697 100644
--- a/spec/lib/gitlab/danger/helper_spec.rb
+++ b/spec/lib/gitlab/danger/helper_spec.rb
@@ -178,6 +178,7 @@ describe Gitlab::Danger::Helper do
'app/assets/foo' | :frontend
'app/views/foo' | :frontend
'public/foo' | :frontend
+ 'scripts/frontend/foo' | :frontend
'spec/javascripts/foo' | :frontend
'spec/frontend/bar' | :frontend
'vendor/assets/foo' | :frontend
@@ -193,10 +194,8 @@ describe Gitlab::Danger::Helper do
'app/models/foo' | :backend
'bin/foo' | :backend
'config/foo' | :backend
- 'danger/foo' | :backend
'lib/foo' | :backend
'rubocop/foo' | :backend
- 'scripts/foo' | :backend
'spec/foo' | :backend
'spec/foo/bar' | :backend
@@ -209,16 +208,24 @@ describe Gitlab::Danger::Helper do
'vendor/languages.yml' | :backend
'vendor/licenses.csv' | :backend
- 'Dangerfile' | :backend
'Gemfile' | :backend
'Gemfile.lock' | :backend
'Procfile' | :backend
'Rakefile' | :backend
'FOO_VERSION' | :backend
+ 'Dangerfile' | :engineering_productivity
+ 'danger/commit_messages/Dangerfile' | :engineering_productivity
+ 'ee/danger/commit_messages/Dangerfile' | :engineering_productivity
+ 'danger/commit_messages/' | :engineering_productivity
+ 'ee/danger/commit_messages/' | :engineering_productivity
'.gitlab-ci.yml' | :engineering_productivity
'.gitlab/ci/cng.gitlab-ci.yml' | :engineering_productivity
'.gitlab/ci/ee-specific-checks.gitlab-ci.yml' | :engineering_productivity
+ 'scripts/foo' | :engineering_productivity
+ 'lib/gitlab/danger/foo' | :engineering_productivity
+ 'ee/lib/gitlab/danger/foo' | :engineering_productivity
+
'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | :backend
'ee/FOO_VERSION' | :unknown
diff --git a/spec/lib/gitlab/danger/teammate_spec.rb b/spec/lib/gitlab/danger/teammate_spec.rb
index bd1c2b10dc8..35edfa08a63 100644
--- a/spec/lib/gitlab/danger/teammate_spec.rb
+++ b/spec/lib/gitlab/danger/teammate_spec.rb
@@ -30,7 +30,7 @@ describe Gitlab::Danger::Teammate do
expect(subject.maintainer?(project, :frontend, labels)).to be_truthy
end
- context 'when labels contain Create and the category is test' do
+ context 'when labels contain devops::create and the category is test' do
let(:labels) { ['devops::create'] }
context 'when role is Test Automation Engineer, Create' do
@@ -79,6 +79,22 @@ describe Gitlab::Danger::Teammate do
it '#maintainer? returns false' do
expect(subject.maintainer?(project, :engineering_productivity, labels)).to be_falsey
end
+
+ context 'when capabilities include maintainer backend' do
+ let(:capabilities) { ['maintainer backend'] }
+
+ it '#maintainer? returns true' do
+ expect(subject.maintainer?(project, :engineering_productivity, labels)).to be_truthy
+ end
+ end
+
+ context 'when capabilities include trainee_maintainer backend' do
+ let(:capabilities) { ['trainee_maintainer backend'] }
+
+ it '#traintainer? returns true' do
+ expect(subject.traintainer?(project, :engineering_productivity, labels)).to be_truthy
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 1269fac7f48..b60c5cc59be 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -262,7 +262,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
it 'has the correct number of pipelines and statuses' do
expect(@project.ci_pipelines.size).to eq(6)
- @project.ci_pipelines.zip([0, 2, 2, 2, 2, 2])
+ @project.ci_pipelines.order(:id).zip([2, 2, 2, 2, 2, 0])
.each do |(pipeline, expected_status_size)|
expect(pipeline.statuses.size).to eq(expected_status_size)
end