diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-08 00:07:43 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-01-08 00:07:43 +0000 |
commit | 2b3bfe8fc59ed4cdc385955cdb38cbd481b45426 (patch) | |
tree | 6b570a8d134fb2beeacf11bbcc79ff22123156ec | |
parent | d203316c80aa27cf747aa29df9f7c2d374965b5f (diff) | |
download | gitlab-ce-2b3bfe8fc59ed4cdc385955cdb38cbd481b45426.tar.gz |
Add latest changes from gitlab-org/gitlab@master
48 files changed, 797 insertions, 407 deletions
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 5a65b0eb36b..dd392bd39a8 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -386,6 +386,7 @@ class ProjectsController < Projects::ApplicationController :template_project_id, :merge_method, :initialize_with_readme, + :autoclose_referenced_issues, project_feature_attributes: %i[ builds_access_level diff --git a/app/graphql/mutations/award_emojis/toggle.rb b/app/graphql/mutations/award_emojis/toggle.rb index d822048f3a6..22eab4812a1 100644 --- a/app/graphql/mutations/award_emojis/toggle.rb +++ b/app/graphql/mutations/award_emojis/toggle.rb @@ -5,10 +5,9 @@ module Mutations class Toggle < Base graphql_name 'ToggleAwardEmoji' - field :toggledOn, - GraphQL::BOOLEAN_TYPE, - null: false, - description: 'True when the emoji was awarded, false when it was removed' + field :toggledOn, GraphQL::BOOLEAN_TYPE, null: false, + description: 'Indicates the status of the emoji. ' \ + 'True if the toggle awarded the emoji, and false if the toggle removed the emoji.' def resolve(args) awardable = authorized_find!(id: args[:awardable_id]) diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 4cbb849da3a..11850e5865f 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -69,7 +69,7 @@ module Types field :participants, Types::UserType.connection_type, null: true, complexity: 5, description: 'List of participants in the issue' 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 issue' + description: 'Indicates the currently logged in user is subscribed to 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, diff --git a/app/graphql/types/permission_types/base_permission_type.rb b/app/graphql/types/permission_types/base_permission_type.rb index 73049ebed7b..deb8560bd79 100644 --- a/app/graphql/types/permission_types/base_permission_type.rb +++ b/app/graphql/types/permission_types/base_permission_type.rb @@ -25,7 +25,7 @@ module Types kword_args = kword_args.reverse_merge( name: name, type: GraphQL::BOOLEAN_TYPE, - description: "Whether or not a user can perform `#{name}` on this resource", + description: "Indicates the user can perform `#{name}` on this resource", null: false) field(**kword_args) # rubocop:disable Graphql/Descriptions diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index cd894f9775a..0bd2b0c81d9 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -46,7 +46,7 @@ module Types description: 'Timestamp of the project last activity' field :archived, GraphQL::BOOLEAN_TYPE, null: true, - description: 'Archived status of the project' + description: 'Indicates the archived status of the project' field :visibility, GraphQL::STRING_TYPE, null: true, description: 'Visibility of the project' @@ -102,6 +102,8 @@ module Types 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 :autoclose_referenced_issues, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if issues referenced by merge requests and commits within the default branch are closed automatically' field :namespace, Types::NamespaceType, null: true, description: 'Namespace of the project' diff --git a/app/models/diff_viewer/base.rb b/app/models/diff_viewer/base.rb index 22c8fe73563..37831683555 100644 --- a/app/models/diff_viewer/base.rb +++ b/app/models/diff_viewer/base.rb @@ -89,7 +89,7 @@ module DiffViewer { viewer: switcher_title, reason: render_error_reason, - options: render_error_options.to_sentence(two_words_connector: _(' or '), last_word_connector: _(', or ')) + options: Gitlab::Utils.to_exclusive_sentence(render_error_options) } end diff --git a/app/models/key.rb b/app/models/key.rb index e549c59b58f..71188f210bb 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -142,13 +142,9 @@ class Key < ApplicationRecord end def forbidden_key_type_message - allowed_types = - Gitlab::CurrentSettings - .allowed_key_types - .map(&:upcase) - .to_sentence(last_word_connector: ', or ', two_words_connector: ' or ') + allowed_types = Gitlab::CurrentSettings.allowed_key_types.map(&:upcase) - "type is forbidden. Must be #{allowed_types}" + "type is forbidden. Must be #{Gitlab::Utils.to_exclusive_sentence(allowed_types)}" end end diff --git a/app/models/project.rb b/app/models/project.rb index 057bcbabbeb..25819bc2b85 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -75,6 +75,7 @@ class Project < ApplicationRecord default_value_for :snippets_enabled, gitlab_config_features.snippets default_value_for :only_allow_merge_if_all_discussions_are_resolved, false default_value_for :remove_source_branch_after_merge, true + default_value_for :autoclose_referenced_issues, true default_value_for(:ci_config_path) { Gitlab::CurrentSettings.default_ci_config_path } add_authentication_token_field :runners_token, encrypted: -> { Feature.enabled?(:projects_tokens_optional_encryption, default_enabled: true) ? :optional : :required } @@ -679,6 +680,12 @@ class Project < ApplicationRecord end end + def autoclose_referenced_issues + return true if super.nil? + + super + end + def preload_protected_branches preloader = ActiveRecord::Associations::Preloader.new preloader.preload(self, protected_branches: [:push_access_levels, :merge_access_levels]) diff --git a/app/validators/key_restriction_validator.rb b/app/validators/key_restriction_validator.rb index 891d13b1596..9809047ae83 100644 --- a/app/validators/key_restriction_validator.rb +++ b/app/validators/key_restriction_validator.rb @@ -21,7 +21,8 @@ class KeyRestrictionValidator < ActiveModel::EachValidator def supported_sizes_message sizes = self.class.supported_sizes(options[:type]) - sizes.to_sentence(last_word_connector: ', or ', two_words_connector: ' or ') + + Gitlab::Utils.to_exclusive_sentence(sizes) end def valid_restriction?(value) diff --git a/app/views/projects/blob/_render_error.html.haml b/app/views/projects/blob/_render_error.html.haml index 9eef6cafd04..1ff68cd2d11 100644 --- a/app/views/projects/blob/_render_error.html.haml +++ b/app/views/projects/blob/_render_error.html.haml @@ -3,5 +3,5 @@ The #{viewer.switcher_title} could not be displayed because #{blob_render_error_reason(viewer)}. You can - = blob_render_error_options(viewer).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ').html_safe + = Gitlab::Utils.to_exclusive_sentence(blob_render_error_options(viewer)).html_safe instead. diff --git a/app/views/projects/blob/viewers/_contributing.html.haml b/app/views/projects/blob/viewers/_contributing.html.haml index c78f04c9c7c..546c064c06f 100644 --- a/app/views/projects/blob/viewers/_contributing.html.haml +++ b/app/views/projects/blob/viewers/_contributing.html.haml @@ -4,6 +4,6 @@ After you've reviewed these contribution guidelines, you'll be all set to - options = contribution_options(viewer.project) - if options.any? = succeed '.' do - = options.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ').html_safe + = Gitlab::Utils.to_exclusive_sentence(options).html_safe - else contribute to this project. diff --git a/app/views/projects/default_branch/_show.html.haml b/app/views/projects/default_branch/_show.html.haml index 59efcde5825..6a09004143e 100644 --- a/app/views/projects/default_branch/_show.html.haml +++ b/app/views/projects/default_branch/_show.html.haml @@ -9,13 +9,23 @@ = _('Select the branch you want to set as the default for this project. All merge requests and commits will automatically be made against this branch unless you specify a different one.') .settings-content - - if @project.empty_repo? - .text-secondary - = _('A default branch cannot be chosen for an empty project.') - - else - = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, anchor: 'default-branch-settings' }, authenticity_token: true do |f| - %fieldset + = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, anchor: 'default-branch-settings' }, authenticity_token: true do |f| + %fieldset + - if @project.empty_repo? + .text-secondary + = _('A default branch cannot be chosen for an empty project.') + - else .form-group = f.label :default_branch, "Default Branch", class: 'label-bold' = f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'}) - = f.submit 'Save changes', class: "btn btn-success" + + .form-group + .form-check + = f.check_box :autoclose_referenced_issues, class: 'form-check-input' + = f.label :autoclose_referenced_issues, class: 'form-check-label' do + %strong= _("Auto-close referenced issues on default branch") + .form-text.text-muted + = _("Issues referenced by merge requests and commits within the default branch will be closed automatically") + = link_to icon('question-circle'), help_page_path('user/project/issues/managing_issues.html', anchor: 'disabling-automatic-issue-closing'), target: '_blank' + + = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/shared/form_elements/_description.html.haml b/app/views/shared/form_elements/_description.html.haml index 9db6184ebca..2f2e6d83f9f 100644 --- a/app/views/shared/form_elements/_description.html.haml +++ b/app/views/shared/form_elements/_description.html.haml @@ -1,6 +1,8 @@ - project = local_assigns.fetch(:project) - model = local_assigns.fetch(:model) + + - form = local_assigns.fetch(:form) - placeholder = model.is_a?(MergeRequest) ? _('Describe the goal of the changes and what reviewers should be aware of.') : _('Write a comment or drag your files here…') - supports_quick_actions = model.new_record? @@ -14,6 +16,8 @@ = form.label :description, 'Description', class: 'col-form-label col-sm-2' .col-sm-10 + - if model.is_a?(Issuable) + = render 'shared/issuable/form/template_selector', issuable: model = render layout: 'projects/md_preview', locals: { url: preview_url, referenced_users: true } do = render 'projects/zen', f: form, attr: :description, classes: 'note-textarea qa-issuable-form-description rspec-issuable-form-description', diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 0fb23adc31f..a020a04e366 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -17,7 +17,6 @@ .form-group.row = form.label :title, class: 'col-form-label col-sm-2' - = render 'shared/issuable/form/template_selector', issuable: issuable = render 'shared/issuable/form/title', issuable: issuable, form: form, has_wip_commits: commits && commits.detect(&:work_in_progress?) #js-suggestions{ data: { project_path: @project.full_path } } diff --git a/app/views/shared/issuable/form/_template_selector.html.haml b/app/views/shared/issuable/form/_template_selector.html.haml index d613bd31d81..bf34ea4a1b2 100644 --- a/app/views/shared/issuable/form/_template_selector.html.haml +++ b/app/views/shared/issuable/form/_template_selector.html.haml @@ -2,7 +2,7 @@ - return unless issuable && issuable_templates(issuable).any? -.col-sm-3.col-lg-2 +.issuable-form-select-holder.selectbox.form-group .js-issuable-selector-wrap{ data: { issuable_type: issuable.to_ability_name } } = template_dropdown_tag(issuable) do %ul.dropdown-footer-list diff --git a/app/workers/chat_notification_worker.rb b/app/workers/chat_notification_worker.rb index 42a23cd472a..6162dcf9d38 100644 --- a/app/workers/chat_notification_worker.rb +++ b/app/workers/chat_notification_worker.rb @@ -3,6 +3,9 @@ class ChatNotificationWorker include ApplicationWorker + TimeoutExceeded = Class.new(StandardError) + + sidekiq_options retry: false feature_category :chatops latency_sensitive_worker! # TODO: break this into multiple jobs @@ -11,18 +14,21 @@ class ChatNotificationWorker # worker_has_external_dependencies! RESCHEDULE_INTERVAL = 2.seconds + RESCHEDULE_TIMEOUT = 5.minutes # rubocop: disable CodeReuse/ActiveRecord - def perform(build_id) + def perform(build_id, reschedule_count = 0) Ci::Build.find_by(id: build_id).try do |build| send_response(build) end rescue Gitlab::Chat::Output::MissingBuildSectionError + raise TimeoutExceeded if timeout_exceeded?(reschedule_count) + # The creation of traces and sections appears to be eventually consistent. # As a result it's possible for us to run the above code before the trace # sections are present. To better handle such cases we'll just reschedule # the job instead of producing an error. - self.class.perform_in(RESCHEDULE_INTERVAL, build_id) + self.class.perform_in(RESCHEDULE_INTERVAL, build_id, reschedule_count + 1) end # rubocop: enable CodeReuse/ActiveRecord @@ -37,4 +43,10 @@ class ChatNotificationWorker end end end + + private + + def timeout_exceeded?(reschedule_count) + (reschedule_count * RESCHEDULE_INTERVAL) >= RESCHEDULE_TIMEOUT + end end diff --git a/changelogs/unreleased/119198-chat_notification-sidekiq-job-latency-has-increased.yml b/changelogs/unreleased/119198-chat_notification-sidekiq-job-latency-has-increased.yml new file mode 100644 index 00000000000..158f062b3d6 --- /dev/null +++ b/changelogs/unreleased/119198-chat_notification-sidekiq-job-latency-has-increased.yml @@ -0,0 +1,5 @@ +--- +title: Limit the amount of time ChatNotificationWorker waits for the build trace +merge_request: 22132 +author: +type: fixed diff --git a/changelogs/unreleased/32273-fix-choose-template.yml b/changelogs/unreleased/32273-fix-choose-template.yml new file mode 100644 index 00000000000..384a46f4dae --- /dev/null +++ b/changelogs/unreleased/32273-fix-choose-template.yml @@ -0,0 +1,5 @@ +--- +title: Changes to template dropdown location +merge_request: 22049 +author: +type: changed diff --git a/changelogs/unreleased/feat-disable-issue-autoclose-feature.yml b/changelogs/unreleased/feat-disable-issue-autoclose-feature.yml new file mode 100644 index 00000000000..02b0f820bad --- /dev/null +++ b/changelogs/unreleased/feat-disable-issue-autoclose-feature.yml @@ -0,0 +1,5 @@ +--- +title: Add capability to disable issue auto-close feature per project +merge_request: 21704 +author: Fabio Huser +type: added diff --git a/db/migrate/20200103195205_add_autoclose_referenced_issues_to_projects.rb b/db/migrate/20200103195205_add_autoclose_referenced_issues_to_projects.rb new file mode 100644 index 00000000000..ac1aa2276fc --- /dev/null +++ b/db/migrate/20200103195205_add_autoclose_referenced_issues_to_projects.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddAutocloseReferencedIssuesToProjects < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def change + add_column :projects, :autoclose_referenced_issues, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 328948dea66..ca27c33d6f1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -3348,6 +3348,7 @@ ActiveRecord::Schema.define(version: 2020_01_06_085831) do t.boolean "remove_source_branch_after_merge" t.date "marked_for_deletion_at" t.integer "marked_for_deletion_by_user_id" + t.boolean "autoclose_referenced_issues" t.index "lower((name)::text)", name: "index_projects_on_lower_name" t.index ["created_at", "id"], name: "index_projects_on_created_at_and_id" t.index ["creator_id"], name: "index_projects_on_creator_id" diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md index 0a2602261d1..e60a70d57c9 100644 --- a/doc/administration/geo/replication/troubleshooting.md +++ b/doc/administration/geo/replication/troubleshooting.md @@ -318,6 +318,40 @@ Slots where `active` is `f` are not active. SELECT pg_drop_replication_slot('<name_of_extra_slot>'); ``` +### Message: "ERROR: canceling statement due to conflict with recovery" + +This error may rarely occur under normal usage, and the system is resilient +enough to recover. + +However, under certain conditions, some database queries on secondaries may run +excessively long, which increases the frequency of this error. At some point, +some of these queries will never be able to complete due to being canceled +every time. + +These long-running queries are +[planned to be removed in the future](https://gitlab.com/gitlab-org/gitlab/issues/34269), +but as a workaround, we recommend enabling +[hot_standby_feedback](https://www.postgresql.org/docs/10/hot-standby.html#HOT-STANDBY-CONFLICT). +This increases the likelihood of bloat on the **primary** node as it prevents +`VACUUM` from removing recently-dead rows. However, it has been used +successfully in production on GitLab.com. + +To enable `hot_standby_feedback`, add the following to `/etc/gitlab/gitlab.rb` +on the **secondary** node: + +```ruby +postgresql['hot_standby_feedback'] = 'on' +``` + +Then reconfigure GitLab: + +```sh +sudo gitlab-ctl reconfigure +``` + +To help us resolve this problem, consider commenting on +[the issue](https://gitlab.com/gitlab-org/gitlab/issues/4489). + ### Very large repositories never successfully synchronize on the **secondary** node GitLab places a timeout on all repository clones, including project imports diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 731d6dc05cd..5c6dd93a676 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -1668,7 +1668,7 @@ type Epic implements Noteable { state: EpicState! """ - Boolean flag for whether the currently logged in user is subscribed to this epic + Indicates the currently logged in user is subscribed to the epic """ subscribed: Boolean! @@ -1984,7 +1984,7 @@ type EpicIssue implements Noteable { state: IssueState! """ - Boolean flag for whether the currently logged in user is subscribed to this issue + Indicates the currently logged in user is subscribed to the issue """ subscribed: Boolean! @@ -2089,42 +2089,42 @@ Check permissions for the current user on an epic """ type EpicPermissions { """ - Whether or not a user can perform `admin_epic` on this resource + Indicates the user can perform `admin_epic` on this resource """ adminEpic: Boolean! """ - Whether or not a user can perform `award_emoji` on this resource + Indicates the user can perform `award_emoji` on this resource """ awardEmoji: Boolean! """ - Whether or not a user can perform `create_epic` on this resource + Indicates the user can perform `create_epic` on this resource """ createEpic: Boolean! """ - Whether or not a user can perform `create_note` on this resource + Indicates the user can perform `create_note` on this resource """ createNote: Boolean! """ - Whether or not a user can perform `destroy_epic` on this resource + Indicates the user can perform `destroy_epic` on this resource """ destroyEpic: Boolean! """ - Whether or not a user can perform `read_epic` on this resource + Indicates the user can perform `read_epic` on this resource """ readEpic: Boolean! """ - Whether or not a user can perform `read_epic_iid` on this resource + Indicates the user can perform `read_epic_iid` on this resource """ readEpicIid: Boolean! """ - Whether or not a user can perform `update_epic` on this resource + Indicates the user can perform `update_epic` on this resource """ updateEpic: Boolean! } @@ -2585,7 +2585,7 @@ type Group { type GroupPermissions { """ - Whether or not a user can perform `read_group` on this resource + Indicates the user can perform `read_group` on this resource """ readGroup: Boolean! } @@ -2816,7 +2816,7 @@ type Issue implements Noteable { state: IssueState! """ - Boolean flag for whether the currently logged in user is subscribed to this issue + Indicates the currently logged in user is subscribed to the issue """ subscribed: Boolean! @@ -2921,42 +2921,42 @@ Check permissions for the current user on a issue """ type IssuePermissions { """ - Whether or not a user can perform `admin_issue` on this resource + Indicates the user can perform `admin_issue` on this resource """ adminIssue: Boolean! """ - Whether or not a user can perform `create_design` on this resource + Indicates the user can perform `create_design` on this resource """ createDesign: Boolean! """ - Whether or not a user can perform `create_note` on this resource + Indicates the user can perform `create_note` on this resource """ createNote: Boolean! """ - Whether or not a user can perform `destroy_design` on this resource + Indicates the user can perform `destroy_design` on this resource """ destroyDesign: Boolean! """ - Whether or not a user can perform `read_design` on this resource + Indicates the user can perform `read_design` on this resource """ readDesign: Boolean! """ - Whether or not a user can perform `read_issue` on this resource + Indicates the user can perform `read_issue` on this resource """ readIssue: Boolean! """ - Whether or not a user can perform `reopen_issue` on this resource + Indicates the user can perform `reopen_issue` on this resource """ reopenIssue: Boolean! """ - Whether or not a user can perform `update_issue` on this resource + Indicates the user can perform `update_issue` on this resource """ updateIssue: Boolean! } @@ -3714,42 +3714,42 @@ Check permissions for the current user on a merge request """ type MergeRequestPermissions { """ - Whether or not a user can perform `admin_merge_request` on this resource + Indicates the user can perform `admin_merge_request` on this resource """ adminMergeRequest: Boolean! """ - Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource + Indicates the user can perform `cherry_pick_on_current_merge_request` on this resource """ cherryPickOnCurrentMergeRequest: Boolean! """ - Whether or not a user can perform `create_note` on this resource + Indicates the user can perform `create_note` on this resource """ createNote: Boolean! """ - Whether or not a user can perform `push_to_source_branch` on this resource + Indicates the user can perform `push_to_source_branch` on this resource """ pushToSourceBranch: Boolean! """ - Whether or not a user can perform `read_merge_request` on this resource + Indicates the user can perform `read_merge_request` on this resource """ readMergeRequest: Boolean! """ - Whether or not a user can perform `remove_source_branch` on this resource + Indicates the user can perform `remove_source_branch` on this resource """ removeSourceBranch: Boolean! """ - Whether or not a user can perform `revert_on_current_merge_request` on this resource + Indicates the user can perform `revert_on_current_merge_request` on this resource """ revertOnCurrentMergeRequest: Boolean! """ - Whether or not a user can perform `update_merge_request` on this resource + Indicates the user can perform `update_merge_request` on this resource """ updateMergeRequest: Boolean! } @@ -4362,27 +4362,27 @@ type NoteEdge { type NotePermissions { """ - Whether or not a user can perform `admin_note` on this resource + Indicates the user can perform `admin_note` on this resource """ adminNote: Boolean! """ - Whether or not a user can perform `award_emoji` on this resource + Indicates the user can perform `award_emoji` on this resource """ awardEmoji: Boolean! """ - Whether or not a user can perform `create_note` on this resource + Indicates the user can perform `create_note` on this resource """ createNote: Boolean! """ - Whether or not a user can perform `read_note` on this resource + Indicates the user can perform `read_note` on this resource """ readNote: Boolean! """ - Whether or not a user can perform `resolve_note` on this resource + Indicates the user can perform `resolve_note` on this resource """ resolveNote: Boolean! } @@ -4574,17 +4574,17 @@ type PipelineEdge { type PipelinePermissions { """ - Whether or not a user can perform `admin_pipeline` on this resource + Indicates the user can perform `admin_pipeline` on this resource """ adminPipeline: Boolean! """ - Whether or not a user can perform `destroy_pipeline` on this resource + Indicates the user can perform `destroy_pipeline` on this resource """ destroyPipeline: Boolean! """ - Whether or not a user can perform `update_pipeline` on this resource + Indicates the user can perform `update_pipeline` on this resource """ updatePipeline: Boolean! } @@ -4605,11 +4605,16 @@ enum PipelineStatusEnum { type Project { """ - Archived status of the project + Indicates the archived status of the project """ archived: Boolean """ + Indicates if issues referenced by merge requests and commits within the default branch are closed automatically + """ + autocloseReferencedIssues: Boolean + + """ URL to avatar image file of the project """ avatarUrl: String @@ -5145,207 +5150,207 @@ type ProjectEdge { type ProjectPermissions { """ - Whether or not a user can perform `admin_operations` on this resource + Indicates the user can perform `admin_operations` on this resource """ adminOperations: Boolean! """ - Whether or not a user can perform `admin_project` on this resource + Indicates the user can perform `admin_project` on this resource """ adminProject: Boolean! """ - Whether or not a user can perform `admin_remote_mirror` on this resource + Indicates the user can perform `admin_remote_mirror` on this resource """ adminRemoteMirror: Boolean! """ - Whether or not a user can perform `admin_wiki` on this resource + Indicates the user can perform `admin_wiki` on this resource """ adminWiki: Boolean! """ - Whether or not a user can perform `archive_project` on this resource + Indicates the user can perform `archive_project` on this resource """ archiveProject: Boolean! """ - Whether or not a user can perform `change_namespace` on this resource + Indicates the user can perform `change_namespace` on this resource """ changeNamespace: Boolean! """ - Whether or not a user can perform `change_visibility_level` on this resource + Indicates the user can perform `change_visibility_level` on this resource """ changeVisibilityLevel: Boolean! """ - Whether or not a user can perform `create_deployment` on this resource + Indicates the user can perform `create_deployment` on this resource """ createDeployment: Boolean! """ - Whether or not a user can perform `create_design` on this resource + Indicates the user can perform `create_design` on this resource """ createDesign: Boolean! """ - Whether or not a user can perform `create_issue` on this resource + Indicates the user can perform `create_issue` on this resource """ createIssue: Boolean! """ - Whether or not a user can perform `create_label` on this resource + Indicates the user can perform `create_label` on this resource """ createLabel: Boolean! """ - Whether or not a user can perform `create_merge_request_from` on this resource + Indicates the user can perform `create_merge_request_from` on this resource """ createMergeRequestFrom: Boolean! """ - Whether or not a user can perform `create_merge_request_in` on this resource + Indicates the user can perform `create_merge_request_in` on this resource """ createMergeRequestIn: Boolean! """ - Whether or not a user can perform `create_pages` on this resource + Indicates the user can perform `create_pages` on this resource """ createPages: Boolean! """ - Whether or not a user can perform `create_pipeline` on this resource + Indicates the user can perform `create_pipeline` on this resource """ createPipeline: Boolean! """ - Whether or not a user can perform `create_pipeline_schedule` on this resource + Indicates the user can perform `create_pipeline_schedule` on this resource """ createPipelineSchedule: Boolean! """ - Whether or not a user can perform `create_snippet` on this resource + Indicates the user can perform `create_snippet` on this resource """ createSnippet: Boolean! """ - Whether or not a user can perform `create_wiki` on this resource + Indicates the user can perform `create_wiki` on this resource """ createWiki: Boolean! """ - Whether or not a user can perform `destroy_design` on this resource + Indicates the user can perform `destroy_design` on this resource """ destroyDesign: Boolean! """ - Whether or not a user can perform `destroy_pages` on this resource + Indicates the user can perform `destroy_pages` on this resource """ destroyPages: Boolean! """ - Whether or not a user can perform `destroy_wiki` on this resource + Indicates the user can perform `destroy_wiki` on this resource """ destroyWiki: Boolean! """ - Whether or not a user can perform `download_code` on this resource + Indicates the user can perform `download_code` on this resource """ downloadCode: Boolean! """ - Whether or not a user can perform `download_wiki_code` on this resource + Indicates the user can perform `download_wiki_code` on this resource """ downloadWikiCode: Boolean! """ - Whether or not a user can perform `fork_project` on this resource + Indicates the user can perform `fork_project` on this resource """ forkProject: Boolean! """ - Whether or not a user can perform `push_code` on this resource + Indicates the user can perform `push_code` on this resource """ pushCode: Boolean! """ - Whether or not a user can perform `push_to_delete_protected_branch` on this resource + Indicates the user can perform `push_to_delete_protected_branch` on this resource """ pushToDeleteProtectedBranch: Boolean! """ - Whether or not a user can perform `read_commit_status` on this resource + Indicates the user can perform `read_commit_status` on this resource """ readCommitStatus: Boolean! """ - Whether or not a user can perform `read_cycle_analytics` on this resource + Indicates the user can perform `read_cycle_analytics` on this resource """ readCycleAnalytics: Boolean! """ - Whether or not a user can perform `read_design` on this resource + Indicates the user can perform `read_design` on this resource """ readDesign: Boolean! """ - Whether or not a user can perform `read_pages_content` on this resource + Indicates the user can perform `read_pages_content` on this resource """ readPagesContent: Boolean! """ - Whether or not a user can perform `read_project` on this resource + Indicates the user can perform `read_project` on this resource """ readProject: Boolean! """ - Whether or not a user can perform `read_project_member` on this resource + Indicates the user can perform `read_project_member` on this resource """ readProjectMember: Boolean! """ - Whether or not a user can perform `read_wiki` on this resource + Indicates the user can perform `read_wiki` on this resource """ readWiki: Boolean! """ - Whether or not a user can perform `remove_fork_project` on this resource + Indicates the user can perform `remove_fork_project` on this resource """ removeForkProject: Boolean! """ - Whether or not a user can perform `remove_pages` on this resource + Indicates the user can perform `remove_pages` on this resource """ removePages: Boolean! """ - Whether or not a user can perform `remove_project` on this resource + Indicates the user can perform `remove_project` on this resource """ removeProject: Boolean! """ - Whether or not a user can perform `rename_project` on this resource + Indicates the user can perform `rename_project` on this resource """ renameProject: Boolean! """ - Whether or not a user can perform `request_access` on this resource + Indicates the user can perform `request_access` on this resource """ requestAccess: Boolean! """ - Whether or not a user can perform `update_pages` on this resource + Indicates the user can perform `update_pages` on this resource """ updatePages: Boolean! """ - Whether or not a user can perform `update_wiki` on this resource + Indicates the user can perform `update_wiki` on this resource """ updateWiki: Boolean! """ - Whether or not a user can perform `upload_file` on this resource + Indicates the user can perform `upload_file` on this resource """ uploadFile: Boolean! } @@ -5909,32 +5914,32 @@ type SnippetEdge { type SnippetPermissions { """ - Whether or not a user can perform `admin_snippet` on this resource + Indicates the user can perform `admin_snippet` on this resource """ adminSnippet: Boolean! """ - Whether or not a user can perform `award_emoji` on this resource + Indicates the user can perform `award_emoji` on this resource """ awardEmoji: Boolean! """ - Whether or not a user can perform `create_note` on this resource + Indicates the user can perform `create_note` on this resource """ createNote: Boolean! """ - Whether or not a user can perform `read_snippet` on this resource + Indicates the user can perform `read_snippet` on this resource """ readSnippet: Boolean! """ - Whether or not a user can perform `report_snippet` on this resource + Indicates the user can perform `report_snippet` on this resource """ reportSnippet: Boolean! """ - Whether or not a user can perform `update_snippet` on this resource + Indicates the user can perform `update_snippet` on this resource """ updateSnippet: Boolean! } @@ -6360,7 +6365,7 @@ type ToggleAwardEmojiPayload { errors: [String!]! """ - True when the emoji was awarded, false when it was removed + Indicates the status of the emoji. True if the toggle awarded the emoji, and false if the toggle removed the emoji. """ toggledOn: Boolean! } @@ -6873,7 +6878,7 @@ type UserEdge { type UserPermissions { """ - Whether or not a user can perform `create_snippet` on this resource + Indicates the user can perform `create_snippet` on this resource """ createSnippet: Boolean! } diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index a68fe0e0e52..1357cab54fe 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -310,7 +310,21 @@ "fields": [ { "name": "archived", - "description": "Archived status of the project", + "description": "Indicates the archived status of the project", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "autocloseReferencedIssues", + "description": "Indicates if issues referenced by merge requests and commits within the default branch are closed automatically", "args": [ ], @@ -1600,7 +1614,7 @@ "fields": [ { "name": "adminOperations", - "description": "Whether or not a user can perform `admin_operations` on this resource", + "description": "Indicates the user can perform `admin_operations` on this resource", "args": [ ], @@ -1618,7 +1632,7 @@ }, { "name": "adminProject", - "description": "Whether or not a user can perform `admin_project` on this resource", + "description": "Indicates the user can perform `admin_project` on this resource", "args": [ ], @@ -1636,7 +1650,7 @@ }, { "name": "adminRemoteMirror", - "description": "Whether or not a user can perform `admin_remote_mirror` on this resource", + "description": "Indicates the user can perform `admin_remote_mirror` on this resource", "args": [ ], @@ -1654,7 +1668,7 @@ }, { "name": "adminWiki", - "description": "Whether or not a user can perform `admin_wiki` on this resource", + "description": "Indicates the user can perform `admin_wiki` on this resource", "args": [ ], @@ -1672,7 +1686,7 @@ }, { "name": "archiveProject", - "description": "Whether or not a user can perform `archive_project` on this resource", + "description": "Indicates the user can perform `archive_project` on this resource", "args": [ ], @@ -1690,7 +1704,7 @@ }, { "name": "changeNamespace", - "description": "Whether or not a user can perform `change_namespace` on this resource", + "description": "Indicates the user can perform `change_namespace` on this resource", "args": [ ], @@ -1708,7 +1722,7 @@ }, { "name": "changeVisibilityLevel", - "description": "Whether or not a user can perform `change_visibility_level` on this resource", + "description": "Indicates the user can perform `change_visibility_level` on this resource", "args": [ ], @@ -1726,7 +1740,7 @@ }, { "name": "createDeployment", - "description": "Whether or not a user can perform `create_deployment` on this resource", + "description": "Indicates the user can perform `create_deployment` on this resource", "args": [ ], @@ -1744,7 +1758,7 @@ }, { "name": "createDesign", - "description": "Whether or not a user can perform `create_design` on this resource", + "description": "Indicates the user can perform `create_design` on this resource", "args": [ ], @@ -1762,7 +1776,7 @@ }, { "name": "createIssue", - "description": "Whether or not a user can perform `create_issue` on this resource", + "description": "Indicates the user can perform `create_issue` on this resource", "args": [ ], @@ -1780,7 +1794,7 @@ }, { "name": "createLabel", - "description": "Whether or not a user can perform `create_label` on this resource", + "description": "Indicates the user can perform `create_label` on this resource", "args": [ ], @@ -1798,7 +1812,7 @@ }, { "name": "createMergeRequestFrom", - "description": "Whether or not a user can perform `create_merge_request_from` on this resource", + "description": "Indicates the user can perform `create_merge_request_from` on this resource", "args": [ ], @@ -1816,7 +1830,7 @@ }, { "name": "createMergeRequestIn", - "description": "Whether or not a user can perform `create_merge_request_in` on this resource", + "description": "Indicates the user can perform `create_merge_request_in` on this resource", "args": [ ], @@ -1834,7 +1848,7 @@ }, { "name": "createPages", - "description": "Whether or not a user can perform `create_pages` on this resource", + "description": "Indicates the user can perform `create_pages` on this resource", "args": [ ], @@ -1852,7 +1866,7 @@ }, { "name": "createPipeline", - "description": "Whether or not a user can perform `create_pipeline` on this resource", + "description": "Indicates the user can perform `create_pipeline` on this resource", "args": [ ], @@ -1870,7 +1884,7 @@ }, { "name": "createPipelineSchedule", - "description": "Whether or not a user can perform `create_pipeline_schedule` on this resource", + "description": "Indicates the user can perform `create_pipeline_schedule` on this resource", "args": [ ], @@ -1888,7 +1902,7 @@ }, { "name": "createSnippet", - "description": "Whether or not a user can perform `create_snippet` on this resource", + "description": "Indicates the user can perform `create_snippet` on this resource", "args": [ ], @@ -1906,7 +1920,7 @@ }, { "name": "createWiki", - "description": "Whether or not a user can perform `create_wiki` on this resource", + "description": "Indicates the user can perform `create_wiki` on this resource", "args": [ ], @@ -1924,7 +1938,7 @@ }, { "name": "destroyDesign", - "description": "Whether or not a user can perform `destroy_design` on this resource", + "description": "Indicates the user can perform `destroy_design` on this resource", "args": [ ], @@ -1942,7 +1956,7 @@ }, { "name": "destroyPages", - "description": "Whether or not a user can perform `destroy_pages` on this resource", + "description": "Indicates the user can perform `destroy_pages` on this resource", "args": [ ], @@ -1960,7 +1974,7 @@ }, { "name": "destroyWiki", - "description": "Whether or not a user can perform `destroy_wiki` on this resource", + "description": "Indicates the user can perform `destroy_wiki` on this resource", "args": [ ], @@ -1978,7 +1992,7 @@ }, { "name": "downloadCode", - "description": "Whether or not a user can perform `download_code` on this resource", + "description": "Indicates the user can perform `download_code` on this resource", "args": [ ], @@ -1996,7 +2010,7 @@ }, { "name": "downloadWikiCode", - "description": "Whether or not a user can perform `download_wiki_code` on this resource", + "description": "Indicates the user can perform `download_wiki_code` on this resource", "args": [ ], @@ -2014,7 +2028,7 @@ }, { "name": "forkProject", - "description": "Whether or not a user can perform `fork_project` on this resource", + "description": "Indicates the user can perform `fork_project` on this resource", "args": [ ], @@ -2032,7 +2046,7 @@ }, { "name": "pushCode", - "description": "Whether or not a user can perform `push_code` on this resource", + "description": "Indicates the user can perform `push_code` on this resource", "args": [ ], @@ -2050,7 +2064,7 @@ }, { "name": "pushToDeleteProtectedBranch", - "description": "Whether or not a user can perform `push_to_delete_protected_branch` on this resource", + "description": "Indicates the user can perform `push_to_delete_protected_branch` on this resource", "args": [ ], @@ -2068,7 +2082,7 @@ }, { "name": "readCommitStatus", - "description": "Whether or not a user can perform `read_commit_status` on this resource", + "description": "Indicates the user can perform `read_commit_status` on this resource", "args": [ ], @@ -2086,7 +2100,7 @@ }, { "name": "readCycleAnalytics", - "description": "Whether or not a user can perform `read_cycle_analytics` on this resource", + "description": "Indicates the user can perform `read_cycle_analytics` on this resource", "args": [ ], @@ -2104,7 +2118,7 @@ }, { "name": "readDesign", - "description": "Whether or not a user can perform `read_design` on this resource", + "description": "Indicates the user can perform `read_design` on this resource", "args": [ ], @@ -2122,7 +2136,7 @@ }, { "name": "readPagesContent", - "description": "Whether or not a user can perform `read_pages_content` on this resource", + "description": "Indicates the user can perform `read_pages_content` on this resource", "args": [ ], @@ -2140,7 +2154,7 @@ }, { "name": "readProject", - "description": "Whether or not a user can perform `read_project` on this resource", + "description": "Indicates the user can perform `read_project` on this resource", "args": [ ], @@ -2158,7 +2172,7 @@ }, { "name": "readProjectMember", - "description": "Whether or not a user can perform `read_project_member` on this resource", + "description": "Indicates the user can perform `read_project_member` on this resource", "args": [ ], @@ -2176,7 +2190,7 @@ }, { "name": "readWiki", - "description": "Whether or not a user can perform `read_wiki` on this resource", + "description": "Indicates the user can perform `read_wiki` on this resource", "args": [ ], @@ -2194,7 +2208,7 @@ }, { "name": "removeForkProject", - "description": "Whether or not a user can perform `remove_fork_project` on this resource", + "description": "Indicates the user can perform `remove_fork_project` on this resource", "args": [ ], @@ -2212,7 +2226,7 @@ }, { "name": "removePages", - "description": "Whether or not a user can perform `remove_pages` on this resource", + "description": "Indicates the user can perform `remove_pages` on this resource", "args": [ ], @@ -2230,7 +2244,7 @@ }, { "name": "removeProject", - "description": "Whether or not a user can perform `remove_project` on this resource", + "description": "Indicates the user can perform `remove_project` on this resource", "args": [ ], @@ -2248,7 +2262,7 @@ }, { "name": "renameProject", - "description": "Whether or not a user can perform `rename_project` on this resource", + "description": "Indicates the user can perform `rename_project` on this resource", "args": [ ], @@ -2266,7 +2280,7 @@ }, { "name": "requestAccess", - "description": "Whether or not a user can perform `request_access` on this resource", + "description": "Indicates the user can perform `request_access` on this resource", "args": [ ], @@ -2284,7 +2298,7 @@ }, { "name": "updatePages", - "description": "Whether or not a user can perform `update_pages` on this resource", + "description": "Indicates the user can perform `update_pages` on this resource", "args": [ ], @@ -2302,7 +2316,7 @@ }, { "name": "updateWiki", - "description": "Whether or not a user can perform `update_wiki` on this resource", + "description": "Indicates the user can perform `update_wiki` on this resource", "args": [ ], @@ -2320,7 +2334,7 @@ }, { "name": "uploadFile", - "description": "Whether or not a user can perform `upload_file` on this resource", + "description": "Indicates the user can perform `upload_file` on this resource", "args": [ ], @@ -3654,7 +3668,7 @@ "fields": [ { "name": "readGroup", - "description": "Whether or not a user can perform `read_group` on this resource", + "description": "Indicates the user can perform `read_group` on this resource", "args": [ ], @@ -4498,7 +4512,7 @@ }, { "name": "subscribed", - "description": "Boolean flag for whether the currently logged in user is subscribed to this epic", + "description": "Indicates the currently logged in user is subscribed to the epic", "args": [ ], @@ -5142,7 +5156,7 @@ "fields": [ { "name": "adminNote", - "description": "Whether or not a user can perform `admin_note` on this resource", + "description": "Indicates the user can perform `admin_note` on this resource", "args": [ ], @@ -5160,7 +5174,7 @@ }, { "name": "awardEmoji", - "description": "Whether or not a user can perform `award_emoji` on this resource", + "description": "Indicates the user can perform `award_emoji` on this resource", "args": [ ], @@ -5178,7 +5192,7 @@ }, { "name": "createNote", - "description": "Whether or not a user can perform `create_note` on this resource", + "description": "Indicates the user can perform `create_note` on this resource", "args": [ ], @@ -5196,7 +5210,7 @@ }, { "name": "readNote", - "description": "Whether or not a user can perform `read_note` on this resource", + "description": "Indicates the user can perform `read_note` on this resource", "args": [ ], @@ -5214,7 +5228,7 @@ }, { "name": "resolveNote", - "description": "Whether or not a user can perform `resolve_note` on this resource", + "description": "Indicates the user can perform `resolve_note` on this resource", "args": [ ], @@ -5604,7 +5618,7 @@ "fields": [ { "name": "createSnippet", - "description": "Whether or not a user can perform `create_snippet` on this resource", + "description": "Indicates the user can perform `create_snippet` on this resource", "args": [ ], @@ -6746,7 +6760,7 @@ "fields": [ { "name": "adminSnippet", - "description": "Whether or not a user can perform `admin_snippet` on this resource", + "description": "Indicates the user can perform `admin_snippet` on this resource", "args": [ ], @@ -6764,7 +6778,7 @@ }, { "name": "awardEmoji", - "description": "Whether or not a user can perform `award_emoji` on this resource", + "description": "Indicates the user can perform `award_emoji` on this resource", "args": [ ], @@ -6782,7 +6796,7 @@ }, { "name": "createNote", - "description": "Whether or not a user can perform `create_note` on this resource", + "description": "Indicates the user can perform `create_note` on this resource", "args": [ ], @@ -6800,7 +6814,7 @@ }, { "name": "readSnippet", - "description": "Whether or not a user can perform `read_snippet` on this resource", + "description": "Indicates the user can perform `read_snippet` on this resource", "args": [ ], @@ -6818,7 +6832,7 @@ }, { "name": "reportSnippet", - "description": "Whether or not a user can perform `report_snippet` on this resource", + "description": "Indicates the user can perform `report_snippet` on this resource", "args": [ ], @@ -6836,7 +6850,7 @@ }, { "name": "updateSnippet", - "description": "Whether or not a user can perform `update_snippet` on this resource", + "description": "Indicates the user can perform `update_snippet` on this resource", "args": [ ], @@ -7217,7 +7231,7 @@ "fields": [ { "name": "adminEpic", - "description": "Whether or not a user can perform `admin_epic` on this resource", + "description": "Indicates the user can perform `admin_epic` on this resource", "args": [ ], @@ -7235,7 +7249,7 @@ }, { "name": "awardEmoji", - "description": "Whether or not a user can perform `award_emoji` on this resource", + "description": "Indicates the user can perform `award_emoji` on this resource", "args": [ ], @@ -7253,7 +7267,7 @@ }, { "name": "createEpic", - "description": "Whether or not a user can perform `create_epic` on this resource", + "description": "Indicates the user can perform `create_epic` on this resource", "args": [ ], @@ -7271,7 +7285,7 @@ }, { "name": "createNote", - "description": "Whether or not a user can perform `create_note` on this resource", + "description": "Indicates the user can perform `create_note` on this resource", "args": [ ], @@ -7289,7 +7303,7 @@ }, { "name": "destroyEpic", - "description": "Whether or not a user can perform `destroy_epic` on this resource", + "description": "Indicates the user can perform `destroy_epic` on this resource", "args": [ ], @@ -7307,7 +7321,7 @@ }, { "name": "readEpic", - "description": "Whether or not a user can perform `read_epic` on this resource", + "description": "Indicates the user can perform `read_epic` on this resource", "args": [ ], @@ -7325,7 +7339,7 @@ }, { "name": "readEpicIid", - "description": "Whether or not a user can perform `read_epic_iid` on this resource", + "description": "Indicates the user can perform `read_epic_iid` on this resource", "args": [ ], @@ -7343,7 +7357,7 @@ }, { "name": "updateEpic", - "description": "Whether or not a user can perform `update_epic` on this resource", + "description": "Indicates the user can perform `update_epic` on this resource", "args": [ ], @@ -8597,7 +8611,7 @@ }, { "name": "subscribed", - "description": "Boolean flag for whether the currently logged in user is subscribed to this issue", + "description": "Indicates the currently logged in user is subscribed to the issue", "args": [ ], @@ -8840,7 +8854,7 @@ "fields": [ { "name": "adminIssue", - "description": "Whether or not a user can perform `admin_issue` on this resource", + "description": "Indicates the user can perform `admin_issue` on this resource", "args": [ ], @@ -8858,7 +8872,7 @@ }, { "name": "createDesign", - "description": "Whether or not a user can perform `create_design` on this resource", + "description": "Indicates the user can perform `create_design` on this resource", "args": [ ], @@ -8876,7 +8890,7 @@ }, { "name": "createNote", - "description": "Whether or not a user can perform `create_note` on this resource", + "description": "Indicates the user can perform `create_note` on this resource", "args": [ ], @@ -8894,7 +8908,7 @@ }, { "name": "destroyDesign", - "description": "Whether or not a user can perform `destroy_design` on this resource", + "description": "Indicates the user can perform `destroy_design` on this resource", "args": [ ], @@ -8912,7 +8926,7 @@ }, { "name": "readDesign", - "description": "Whether or not a user can perform `read_design` on this resource", + "description": "Indicates the user can perform `read_design` on this resource", "args": [ ], @@ -8930,7 +8944,7 @@ }, { "name": "readIssue", - "description": "Whether or not a user can perform `read_issue` on this resource", + "description": "Indicates the user can perform `read_issue` on this resource", "args": [ ], @@ -8948,7 +8962,7 @@ }, { "name": "reopenIssue", - "description": "Whether or not a user can perform `reopen_issue` on this resource", + "description": "Indicates the user can perform `reopen_issue` on this resource", "args": [ ], @@ -8966,7 +8980,7 @@ }, { "name": "updateIssue", - "description": "Whether or not a user can perform `update_issue` on this resource", + "description": "Indicates the user can perform `update_issue` on this resource", "args": [ ], @@ -9981,7 +9995,7 @@ }, { "name": "subscribed", - "description": "Boolean flag for whether the currently logged in user is subscribed to this issue", + "description": "Indicates the currently logged in user is subscribed to the issue", "args": [ ], @@ -12284,7 +12298,7 @@ "fields": [ { "name": "adminPipeline", - "description": "Whether or not a user can perform `admin_pipeline` on this resource", + "description": "Indicates the user can perform `admin_pipeline` on this resource", "args": [ ], @@ -12302,7 +12316,7 @@ }, { "name": "destroyPipeline", - "description": "Whether or not a user can perform `destroy_pipeline` on this resource", + "description": "Indicates the user can perform `destroy_pipeline` on this resource", "args": [ ], @@ -12320,7 +12334,7 @@ }, { "name": "updatePipeline", - "description": "Whether or not a user can perform `update_pipeline` on this resource", + "description": "Indicates the user can perform `update_pipeline` on this resource", "args": [ ], @@ -14828,7 +14842,7 @@ "fields": [ { "name": "adminMergeRequest", - "description": "Whether or not a user can perform `admin_merge_request` on this resource", + "description": "Indicates the user can perform `admin_merge_request` on this resource", "args": [ ], @@ -14846,7 +14860,7 @@ }, { "name": "cherryPickOnCurrentMergeRequest", - "description": "Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource", + "description": "Indicates the user can perform `cherry_pick_on_current_merge_request` on this resource", "args": [ ], @@ -14864,7 +14878,7 @@ }, { "name": "createNote", - "description": "Whether or not a user can perform `create_note` on this resource", + "description": "Indicates the user can perform `create_note` on this resource", "args": [ ], @@ -14882,7 +14896,7 @@ }, { "name": "pushToSourceBranch", - "description": "Whether or not a user can perform `push_to_source_branch` on this resource", + "description": "Indicates the user can perform `push_to_source_branch` on this resource", "args": [ ], @@ -14900,7 +14914,7 @@ }, { "name": "readMergeRequest", - "description": "Whether or not a user can perform `read_merge_request` on this resource", + "description": "Indicates the user can perform `read_merge_request` on this resource", "args": [ ], @@ -14918,7 +14932,7 @@ }, { "name": "removeSourceBranch", - "description": "Whether or not a user can perform `remove_source_branch` on this resource", + "description": "Indicates the user can perform `remove_source_branch` on this resource", "args": [ ], @@ -14936,7 +14950,7 @@ }, { "name": "revertOnCurrentMergeRequest", - "description": "Whether or not a user can perform `revert_on_current_merge_request` on this resource", + "description": "Indicates the user can perform `revert_on_current_merge_request` on this resource", "args": [ ], @@ -14954,7 +14968,7 @@ }, { "name": "updateMergeRequest", - "description": "Whether or not a user can perform `update_merge_request` on this resource", + "description": "Indicates the user can perform `update_merge_request` on this resource", "args": [ ], @@ -17089,7 +17103,7 @@ }, { "name": "toggledOn", - "description": "True when the emoji was awarded, false when it was removed", + "description": "Indicates the status of the emoji. True if the toggle awarded the emoji, and false if the toggle removed the emoji.", "args": [ ], diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index dbff0b1759b..8ca17d4107d 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -239,7 +239,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | `relativePosition` | Int | The relative position of the epic in the epic tree | | `relationPath` | String | | | `reference` | String! | | -| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this epic | +| `subscribed` | Boolean! | Indicates the currently logged in user is subscribed to the epic | | `descendantCounts` | EpicDescendantCount | Number of open and closed descendant epics and issues | ### EpicDescendantCount @@ -274,7 +274,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | `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) | -| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this issue | +| `subscribed` | Boolean! | Indicates the currently logged in user is subscribed to the issue | | `timeEstimate` | Int! | Time estimate of the issue | | `totalTimeSpent` | Int! | Total time reported as spent on the issue | | `closedAt` | Time | Timestamp of when the issue was closed | @@ -293,14 +293,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `readEpic` | Boolean! | Whether or not a user can perform `read_epic` on this resource | -| `readEpicIid` | Boolean! | Whether or not a user can perform `read_epic_iid` on this resource | -| `updateEpic` | Boolean! | Whether or not a user can perform `update_epic` on this resource | -| `destroyEpic` | Boolean! | Whether or not a user can perform `destroy_epic` on this resource | -| `adminEpic` | Boolean! | Whether or not a user can perform `admin_epic` on this resource | -| `createEpic` | Boolean! | Whether or not a user can perform `create_epic` on this resource | -| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource | -| `awardEmoji` | Boolean! | Whether or not a user can perform `award_emoji` on this resource | +| `readEpic` | Boolean! | Indicates the user can perform `read_epic` on this resource | +| `readEpicIid` | Boolean! | Indicates the user can perform `read_epic_iid` on this resource | +| `updateEpic` | Boolean! | Indicates the user can perform `update_epic` on this resource | +| `destroyEpic` | Boolean! | Indicates the user can perform `destroy_epic` on this resource | +| `adminEpic` | Boolean! | Indicates the user can perform `admin_epic` on this resource | +| `createEpic` | Boolean! | Indicates the user can perform `create_epic` on this resource | +| `createNote` | Boolean! | Indicates the user can perform `create_note` on this resource | +| `awardEmoji` | Boolean! | Indicates the user can perform `award_emoji` on this resource | ### EpicSetSubscriptionPayload @@ -355,7 +355,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `readGroup` | Boolean! | Whether or not a user can perform `read_group` on this resource | +| `readGroup` | Boolean! | Indicates the user can perform `read_group` on this resource | ### Issue @@ -380,7 +380,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | `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) | -| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this issue | +| `subscribed` | Boolean! | Indicates the currently logged in user is subscribed to the issue | | `timeEstimate` | Int! | Time estimate of the issue | | `totalTimeSpent` | Int! | Total time reported as spent on the issue | | `closedAt` | Time | Timestamp of when the issue was closed | @@ -396,14 +396,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `readIssue` | Boolean! | Whether or not a user can perform `read_issue` on this resource | -| `adminIssue` | Boolean! | Whether or not a user can perform `admin_issue` on this resource | -| `updateIssue` | Boolean! | Whether or not a user can perform `update_issue` on this resource | -| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource | -| `reopenIssue` | Boolean! | Whether or not a user can perform `reopen_issue` on this resource | -| `readDesign` | Boolean! | Whether or not a user can perform `read_design` on this resource | -| `createDesign` | Boolean! | Whether or not a user can perform `create_design` on this resource | -| `destroyDesign` | Boolean! | Whether or not a user can perform `destroy_design` on this resource | +| `readIssue` | Boolean! | Indicates the user can perform `read_issue` on this resource | +| `adminIssue` | Boolean! | Indicates the user can perform `admin_issue` on this resource | +| `updateIssue` | Boolean! | Indicates the user can perform `update_issue` on this resource | +| `createNote` | Boolean! | Indicates the user can perform `create_note` on this resource | +| `reopenIssue` | Boolean! | Indicates the user can perform `reopen_issue` on this resource | +| `readDesign` | Boolean! | Indicates the user can perform `read_design` on this resource | +| `createDesign` | Boolean! | Indicates the user can perform `create_design` on this resource | +| `destroyDesign` | Boolean! | Indicates the user can perform `destroy_design` on this resource | ### IssueSetConfidentialPayload @@ -506,14 +506,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `readMergeRequest` | Boolean! | Whether or not a user can perform `read_merge_request` on this resource | -| `adminMergeRequest` | Boolean! | Whether or not a user can perform `admin_merge_request` on this resource | -| `updateMergeRequest` | Boolean! | Whether or not a user can perform `update_merge_request` on this resource | -| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource | -| `pushToSourceBranch` | Boolean! | Whether or not a user can perform `push_to_source_branch` on this resource | -| `removeSourceBranch` | Boolean! | Whether or not a user can perform `remove_source_branch` on this resource | -| `cherryPickOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource | -| `revertOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `revert_on_current_merge_request` on this resource | +| `readMergeRequest` | Boolean! | Indicates the user can perform `read_merge_request` on this resource | +| `adminMergeRequest` | Boolean! | Indicates the user can perform `admin_merge_request` on this resource | +| `updateMergeRequest` | Boolean! | Indicates the user can perform `update_merge_request` on this resource | +| `createNote` | Boolean! | Indicates the user can perform `create_note` on this resource | +| `pushToSourceBranch` | Boolean! | Indicates the user can perform `push_to_source_branch` on this resource | +| `removeSourceBranch` | Boolean! | Indicates the user can perform `remove_source_branch` on this resource | +| `cherryPickOnCurrentMergeRequest` | Boolean! | Indicates the user can perform `cherry_pick_on_current_merge_request` on this resource | +| `revertOnCurrentMergeRequest` | Boolean! | Indicates the user can perform `revert_on_current_merge_request` on this resource | ### MergeRequestSetAssigneesPayload @@ -622,11 +622,11 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `readNote` | Boolean! | Whether or not a user can perform `read_note` on this resource | -| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource | -| `adminNote` | Boolean! | Whether or not a user can perform `admin_note` on this resource | -| `resolveNote` | Boolean! | Whether or not a user can perform `resolve_note` on this resource | -| `awardEmoji` | Boolean! | Whether or not a user can perform `award_emoji` on this resource | +| `readNote` | Boolean! | Indicates the user can perform `read_note` on this resource | +| `createNote` | Boolean! | Indicates the user can perform `create_note` on this resource | +| `adminNote` | Boolean! | Indicates the user can perform `admin_note` on this resource | +| `resolveNote` | Boolean! | Indicates the user can perform `resolve_note` on this resource | +| `awardEmoji` | Boolean! | Indicates the user can perform `award_emoji` on this resource | ### PageInfo @@ -660,9 +660,9 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `updatePipeline` | Boolean! | Whether or not a user can perform `update_pipeline` on this resource | -| `adminPipeline` | Boolean! | Whether or not a user can perform `admin_pipeline` on this resource | -| `destroyPipeline` | Boolean! | Whether or not a user can perform `destroy_pipeline` on this resource | +| `updatePipeline` | Boolean! | Indicates the user can perform `update_pipeline` on this resource | +| `adminPipeline` | Boolean! | Indicates the user can perform `admin_pipeline` on this resource | +| `destroyPipeline` | Boolean! | Indicates the user can perform `destroy_pipeline` on this resource | ### Project @@ -684,7 +684,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | `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 | +| `archived` | Boolean | Indicates the 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 | @@ -704,6 +704,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | `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 | +| `autocloseReferencedIssues` | Boolean | Indicates if issues referenced by merge requests and commits within the default branch are closed automatically | | `namespace` | Namespace | Namespace of the project | | `group` | Group | Group of the project | | `statistics` | ProjectStatistics | Statistics of the project | @@ -719,47 +720,47 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `changeNamespace` | Boolean! | Whether or not a user can perform `change_namespace` on this resource | -| `changeVisibilityLevel` | Boolean! | Whether or not a user can perform `change_visibility_level` on this resource | -| `renameProject` | Boolean! | Whether or not a user can perform `rename_project` on this resource | -| `removeProject` | Boolean! | Whether or not a user can perform `remove_project` on this resource | -| `archiveProject` | Boolean! | Whether or not a user can perform `archive_project` on this resource | -| `removeForkProject` | Boolean! | Whether or not a user can perform `remove_fork_project` on this resource | -| `removePages` | Boolean! | Whether or not a user can perform `remove_pages` on this resource | -| `readProject` | Boolean! | Whether or not a user can perform `read_project` on this resource | -| `createMergeRequestIn` | Boolean! | Whether or not a user can perform `create_merge_request_in` on this resource | -| `readWiki` | Boolean! | Whether or not a user can perform `read_wiki` on this resource | -| `readProjectMember` | Boolean! | Whether or not a user can perform `read_project_member` on this resource | -| `createIssue` | Boolean! | Whether or not a user can perform `create_issue` on this resource | -| `uploadFile` | Boolean! | Whether or not a user can perform `upload_file` on this resource | -| `readCycleAnalytics` | Boolean! | Whether or not a user can perform `read_cycle_analytics` on this resource | -| `downloadCode` | Boolean! | Whether or not a user can perform `download_code` on this resource | -| `downloadWikiCode` | Boolean! | Whether or not a user can perform `download_wiki_code` on this resource | -| `forkProject` | Boolean! | Whether or not a user can perform `fork_project` on this resource | -| `readCommitStatus` | Boolean! | Whether or not a user can perform `read_commit_status` on this resource | -| `requestAccess` | Boolean! | Whether or not a user can perform `request_access` on this resource | -| `createPipeline` | Boolean! | Whether or not a user can perform `create_pipeline` on this resource | -| `createPipelineSchedule` | Boolean! | Whether or not a user can perform `create_pipeline_schedule` on this resource | -| `createMergeRequestFrom` | Boolean! | Whether or not a user can perform `create_merge_request_from` on this resource | -| `createWiki` | Boolean! | Whether or not a user can perform `create_wiki` on this resource | -| `pushCode` | Boolean! | Whether or not a user can perform `push_code` on this resource | -| `createDeployment` | Boolean! | Whether or not a user can perform `create_deployment` on this resource | -| `pushToDeleteProtectedBranch` | Boolean! | Whether or not a user can perform `push_to_delete_protected_branch` on this resource | -| `adminWiki` | Boolean! | Whether or not a user can perform `admin_wiki` on this resource | -| `adminProject` | Boolean! | Whether or not a user can perform `admin_project` on this resource | -| `updatePages` | Boolean! | Whether or not a user can perform `update_pages` on this resource | -| `adminRemoteMirror` | Boolean! | Whether or not a user can perform `admin_remote_mirror` on this resource | -| `createLabel` | Boolean! | Whether or not a user can perform `create_label` on this resource | -| `updateWiki` | Boolean! | Whether or not a user can perform `update_wiki` on this resource | -| `destroyWiki` | Boolean! | Whether or not a user can perform `destroy_wiki` on this resource | -| `createPages` | Boolean! | Whether or not a user can perform `create_pages` on this resource | -| `destroyPages` | Boolean! | Whether or not a user can perform `destroy_pages` on this resource | -| `readPagesContent` | Boolean! | Whether or not a user can perform `read_pages_content` on this resource | -| `adminOperations` | Boolean! | Whether or not a user can perform `admin_operations` on this resource | -| `createSnippet` | Boolean! | Whether or not a user can perform `create_snippet` on this resource | -| `readDesign` | Boolean! | Whether or not a user can perform `read_design` on this resource | -| `createDesign` | Boolean! | Whether or not a user can perform `create_design` on this resource | -| `destroyDesign` | Boolean! | Whether or not a user can perform `destroy_design` on this resource | +| `changeNamespace` | Boolean! | Indicates the user can perform `change_namespace` on this resource | +| `changeVisibilityLevel` | Boolean! | Indicates the user can perform `change_visibility_level` on this resource | +| `renameProject` | Boolean! | Indicates the user can perform `rename_project` on this resource | +| `removeProject` | Boolean! | Indicates the user can perform `remove_project` on this resource | +| `archiveProject` | Boolean! | Indicates the user can perform `archive_project` on this resource | +| `removeForkProject` | Boolean! | Indicates the user can perform `remove_fork_project` on this resource | +| `removePages` | Boolean! | Indicates the user can perform `remove_pages` on this resource | +| `readProject` | Boolean! | Indicates the user can perform `read_project` on this resource | +| `createMergeRequestIn` | Boolean! | Indicates the user can perform `create_merge_request_in` on this resource | +| `readWiki` | Boolean! | Indicates the user can perform `read_wiki` on this resource | +| `readProjectMember` | Boolean! | Indicates the user can perform `read_project_member` on this resource | +| `createIssue` | Boolean! | Indicates the user can perform `create_issue` on this resource | +| `uploadFile` | Boolean! | Indicates the user can perform `upload_file` on this resource | +| `readCycleAnalytics` | Boolean! | Indicates the user can perform `read_cycle_analytics` on this resource | +| `downloadCode` | Boolean! | Indicates the user can perform `download_code` on this resource | +| `downloadWikiCode` | Boolean! | Indicates the user can perform `download_wiki_code` on this resource | +| `forkProject` | Boolean! | Indicates the user can perform `fork_project` on this resource | +| `readCommitStatus` | Boolean! | Indicates the user can perform `read_commit_status` on this resource | +| `requestAccess` | Boolean! | Indicates the user can perform `request_access` on this resource | +| `createPipeline` | Boolean! | Indicates the user can perform `create_pipeline` on this resource | +| `createPipelineSchedule` | Boolean! | Indicates the user can perform `create_pipeline_schedule` on this resource | +| `createMergeRequestFrom` | Boolean! | Indicates the user can perform `create_merge_request_from` on this resource | +| `createWiki` | Boolean! | Indicates the user can perform `create_wiki` on this resource | +| `pushCode` | Boolean! | Indicates the user can perform `push_code` on this resource | +| `createDeployment` | Boolean! | Indicates the user can perform `create_deployment` on this resource | +| `pushToDeleteProtectedBranch` | Boolean! | Indicates the user can perform `push_to_delete_protected_branch` on this resource | +| `adminWiki` | Boolean! | Indicates the user can perform `admin_wiki` on this resource | +| `adminProject` | Boolean! | Indicates the user can perform `admin_project` on this resource | +| `updatePages` | Boolean! | Indicates the user can perform `update_pages` on this resource | +| `adminRemoteMirror` | Boolean! | Indicates the user can perform `admin_remote_mirror` on this resource | +| `createLabel` | Boolean! | Indicates the user can perform `create_label` on this resource | +| `updateWiki` | Boolean! | Indicates the user can perform `update_wiki` on this resource | +| `destroyWiki` | Boolean! | Indicates the user can perform `destroy_wiki` on this resource | +| `createPages` | Boolean! | Indicates the user can perform `create_pages` on this resource | +| `destroyPages` | Boolean! | Indicates the user can perform `destroy_pages` on this resource | +| `readPagesContent` | Boolean! | Indicates the user can perform `read_pages_content` on this resource | +| `adminOperations` | Boolean! | Indicates the user can perform `admin_operations` on this resource | +| `createSnippet` | Boolean! | Indicates the user can perform `create_snippet` on this resource | +| `readDesign` | Boolean! | Indicates the user can perform `read_design` on this resource | +| `createDesign` | Boolean! | Indicates the user can perform `create_design` on this resource | +| `destroyDesign` | Boolean! | Indicates the user can perform `destroy_design` on this resource | ### ProjectStatistics @@ -857,12 +858,12 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource | -| `awardEmoji` | Boolean! | Whether or not a user can perform `award_emoji` on this resource | -| `readSnippet` | Boolean! | Whether or not a user can perform `read_snippet` on this resource | -| `updateSnippet` | Boolean! | Whether or not a user can perform `update_snippet` on this resource | -| `adminSnippet` | Boolean! | Whether or not a user can perform `admin_snippet` on this resource | -| `reportSnippet` | Boolean! | Whether or not a user can perform `report_snippet` on this resource | +| `createNote` | Boolean! | Indicates the user can perform `create_note` on this resource | +| `awardEmoji` | Boolean! | Indicates the user can perform `award_emoji` on this resource | +| `readSnippet` | Boolean! | Indicates the user can perform `read_snippet` on this resource | +| `updateSnippet` | Boolean! | Indicates the user can perform `update_snippet` on this resource | +| `adminSnippet` | Boolean! | Indicates the user can perform `admin_snippet` on this resource | +| `reportSnippet` | Boolean! | Indicates the user can perform `report_snippet` on this resource | ### Submodule @@ -938,7 +939,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | `clientMutationId` | String | A unique identifier for the client performing the mutation. | | `errors` | String! => Array | Reasons why the mutation failed. | | `awardEmoji` | AwardEmoji | The award emoji after mutation | -| `toggledOn` | Boolean! | True when the emoji was awarded, false when it was removed | +| `toggledOn` | Boolean! | Indicates the status of the emoji. True if the toggle awarded the emoji, and false if the toggle removed the emoji. | ### Tree @@ -996,4 +997,4 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | Name | Type | Description | | --- | ---- | ---------- | -| `createSnippet` | Boolean! | Whether or not a user can perform `create_snippet` on this resource | +| `createSnippet` | Boolean! | Indicates the user can perform `create_snippet` on this resource | diff --git a/doc/api/projects.md b/doc/api/projects.md index 209d41d62cd..33308ff8905 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -156,6 +156,7 @@ When the user is authenticated and `simple` is not set this returns something li "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "statistics": { "commit_count": 37, "storage_size": 1038090, @@ -254,6 +255,7 @@ When the user is authenticated and `simple` is not set this returns something li "packages_enabled": true, "service_desk_enabled": false, "service_desk_address": null, + "autoclose_referenced_issues": true, "statistics": { "commit_count": 12, "storage_size": 2066080, @@ -385,6 +387,7 @@ This endpoint supports [keyset pagination](README.md#keyset-based-pagination) fo "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "statistics": { "commit_count": 37, "storage_size": 1038090, @@ -483,6 +486,7 @@ This endpoint supports [keyset pagination](README.md#keyset-based-pagination) fo "packages_enabled": true, "service_desk_enabled": false, "service_desk_address": null, + "autoclose_referenced_issues": true, "statistics": { "commit_count": 12, "storage_size": 2066080, @@ -593,6 +597,7 @@ Example response: "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "statistics": { "commit_count": 37, "storage_size": 1038090, @@ -688,6 +693,7 @@ Example response: "packages_enabled": true, "service_desk_enabled": false, "service_desk_address": null, + "autoclose_referenced_issues": true, "statistics": { "commit_count": 12, "storage_size": 2066080, @@ -829,6 +835,7 @@ GET /projects/:id "packages_enabled": true, "service_desk_enabled": false, "service_desk_address": null, + "autoclose_referenced_issues": true, "statistics": { "commit_count": 37, "storage_size": 1038090, @@ -986,6 +993,7 @@ POST /projects | `only_allow_merge_if_pipeline_succeeds` | boolean | no | Set whether merge requests can only be merged with successful jobs | | `only_allow_merge_if_all_discussions_are_resolved` | boolean | no | Set whether merge requests can only be merged when all the discussions are resolved | | `merge_method` | string | no | Set the [merge method](#project-merge-method) used | +| `autoclose_referenced_issues` | boolean | no | Set whether auto-closing referenced issues on default branch | | `remove_source_branch_after_merge` | boolean | no | Enable `Delete source branch` option by default for all new merge requests | | `lfs_enabled` | boolean | no | Enable LFS | | `request_access_enabled` | boolean | no | Allow users to request member access | @@ -1050,6 +1058,7 @@ POST /projects/user/:user_id | `only_allow_merge_if_pipeline_succeeds` | boolean | no | Set whether merge requests can only be merged with successful jobs | | `only_allow_merge_if_all_discussions_are_resolved` | boolean | no | Set whether merge requests can only be merged when all the discussions are resolved | | `merge_method` | string | no | Set the [merge method](#project-merge-method) used | +| `autoclose_referenced_issues` | boolean | no | Set whether auto-closing referenced issues on default branch | | `remove_source_branch_after_merge` | boolean | no | Enable `Delete source branch` option by default for all new merge requests | | `lfs_enabled` | boolean | no | Enable LFS | | `request_access_enabled` | boolean | no | Allow users to request member access | @@ -1113,6 +1122,7 @@ PUT /projects/:id | `only_allow_merge_if_pipeline_succeeds` | boolean | no | Set whether merge requests can only be merged with successful jobs | | `only_allow_merge_if_all_discussions_are_resolved` | boolean | no | Set whether merge requests can only be merged when all the discussions are resolved | | `merge_method` | string | no | Set the [merge method](#project-merge-method) used | +| `autoclose_referenced_issues` | boolean | no | Set whether auto-closing referenced issues on default branch | | `remove_source_branch_after_merge` | boolean | no | Enable `Delete source branch` option by default for all new merge requests | | `lfs_enabled` | boolean | no | Enable LFS | | `request_access_enabled` | boolean | no | Allow users to request member access | @@ -1244,6 +1254,7 @@ Example responses: "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "_links": { "self": "http://example.com/api/v4/projects", "issues": "http://example.com/api/v4/projects/1/issues", @@ -1332,6 +1343,7 @@ Example response: "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "_links": { "self": "http://example.com/api/v4/projects", "issues": "http://example.com/api/v4/projects/1/issues", @@ -1419,6 +1431,7 @@ Example response: "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "_links": { "self": "http://example.com/api/v4/projects", "issues": "http://example.com/api/v4/projects/1/issues", @@ -1593,6 +1606,7 @@ Example response: "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "_links": { "self": "http://example.com/api/v4/projects", "issues": "http://example.com/api/v4/projects/1/issues", @@ -1699,6 +1713,7 @@ Example response: "remove_source_branch_after_merge": false, "request_access_enabled": false, "merge_method": "merge", + "autoclose_referenced_issues": true, "_links": { "self": "http://example.com/api/v4/projects", "issues": "http://example.com/api/v4/projects/1/issues", diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md index 1ef0b928820..053eb55420e 100644 --- a/doc/development/api_graphql_styleguide.md +++ b/doc/development/api_graphql_styleguide.md @@ -210,7 +210,7 @@ class MergeRequestPermissionsType < BasePermissionType abilities :admin_merge_request, :update_merge_request, :create_note ability_field :resolve_note, - description: 'Whether or not the user can resolve disussions on the merge request' + description: 'Indicates the user can resolve discussions on the merge request' permission_field :push_to_source_branch, method: :can_push_to_source_branch? end ``` diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md index 356e3f7a227..8dd5e2b1265 100644 --- a/doc/development/testing_guide/best_practices.md +++ b/doc/development/testing_guide/best_practices.md @@ -70,6 +70,7 @@ When using spring and guard together, use `SPRING=1 bundle exec guard` instead t use a Capyabara matcher beforehand (e.g. `find('.js-foo')`) to ensure the element actually exists. - Use `focus: true` to isolate parts of the specs you want to run. - Use [`:aggregate_failures`](https://relishapp.com/rspec/rspec-core/docs/expectation-framework-integration/aggregating-failures) when there is more than one expectation in a test. +- For [empty test description blocks](https://github.com/rubocop-hq/rspec-style-guide#it-and-specify), use `specify` rather than `it do` if the test is self-explanatory. ### System / Feature tests diff --git a/doc/user/project/issues/img/disable_issue_auto_close.png b/doc/user/project/issues/img/disable_issue_auto_close.png Binary files differnew file mode 100644 index 00000000000..2cf48a92331 --- /dev/null +++ b/doc/user/project/issues/img/disable_issue_auto_close.png diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md index 38649b05593..c660c920ecb 100644 --- a/doc/user/project/issues/managing_issues.md +++ b/doc/user/project/issues/managing_issues.md @@ -211,6 +211,19 @@ as well as `#22` and `#23` in group/otherproject. `#17` won't be closed as it do not match the pattern. It works with multi-line commit messages as well as one-liners when used from the command line with `git commit -m`. +#### Disabling automatic issue closing + +The automatic issue closing feature can be disabled on a per-project basis +within the [project's repository settings](../settings/index.md). Referenced +issues will still be displayed as such but won't be closed automatically. + +![disable issue auto close - settings](img/disable_issue_auto_close.png) + +This only applies to issues affected by new merge requests or commits. Already +closed issues remain as-is. Disabling automatic issue closing only affects merge +requests *within* the project and won't prevent other projects from closing it +via cross-project issues. + #### Customizing the issue closing pattern **(CORE ONLY)** In order to change the default issue closing pattern, GitLab administrators must edit the diff --git a/lib/api/entities.rb b/lib/api/entities.rb index b73eef9b7cb..c28d6797c56 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -331,6 +331,7 @@ module API expose :auto_devops_deploy_strategy do |project, options| project.auto_devops.nil? ? 'continuous' : project.auto_devops.deploy_strategy end + expose :autoclose_referenced_issues # rubocop: disable CodeReuse/ActiveRecord def self.preload_relation(projects_relation, options = {}) diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index 47b1f037eb8..0ca5b73e270 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -47,6 +47,7 @@ module API optional :ci_default_git_depth, type: Integer, desc: 'Default number of revisions for shallow cloning' optional :auto_devops_enabled, type: Boolean, desc: 'Flag indication if Auto DevOps is enabled' optional :auto_devops_deploy_strategy, type: String, values: %w(continuous manual timed_incremental), desc: 'Auto Deploy strategy' + optional :autoclose_referenced_issues, type: Boolean, desc: 'Flag indication if referenced issues auto-closing is enabled' end params :optional_project_params_ee do @@ -85,6 +86,7 @@ module API :container_registry_enabled, :default_branch, :description, + :autoclose_referenced_issues, :issues_access_level, :lfs_enabled, :merge_requests_access_level, diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb index 4ba921569ad..8e624215065 100644 --- a/lib/gitlab/closing_issue_extractor.rb +++ b/lib/gitlab/closing_issue_extractor.rb @@ -11,11 +11,13 @@ module Gitlab end def initialize(project, current_user = nil) + @project = project @extractor = Gitlab::ReferenceExtractor.new(project, current_user) end def closed_by_message(message) return [] if message.nil? + return [] unless @project.autoclose_referenced_issues closing_statements = [] message.scan(ISSUE_CLOSING_REGEX) do diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb index 7fbfc4c45c4..7eddfc471f6 100644 --- a/lib/gitlab/utils.rb +++ b/lib/gitlab/utils.rb @@ -50,6 +50,12 @@ module Gitlab .gsub(/(\A-+|-+\z)/, '') end + # Wraps ActiveSupport's Array#to_sentence to convert the given array to a + # comma-separated sentence joined with localized 'or' Strings instead of 'and'. + def to_exclusive_sentence(array) + array.to_sentence(two_words_connector: _(' or '), last_word_connector: _(', or ')) + end + # Converts newlines into HTML line break elements def nlbr(str) ActionView::Base.full_sanitizer.sanitize(+str, tags: []).gsub(/\r?\n/, '<br>').html_safe diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8967ce8b994..7cefd08d38c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2381,6 +2381,9 @@ msgstr "" msgid "Auto-cancel redundant, pending pipelines" msgstr "" +msgid "Auto-close referenced issues on default branch" +msgstr "" + msgid "AutoDevOps|Auto DevOps" msgstr "" @@ -10077,6 +10080,9 @@ msgstr "" msgid "Issues closed" msgstr "" +msgid "Issues referenced by merge requests and commits within the default branch will be closed automatically" +msgstr "" + msgid "Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities" msgstr "" @@ -21231,6 +21237,9 @@ msgstr "" msgid "already being used for another group or project milestone." msgstr "" +msgid "already has a \"created\" issue link" +msgstr "" + msgid "already shared with this group" msgstr "" @@ -21688,6 +21697,9 @@ msgstr "" msgid "group" msgstr "" +msgid "has already been linked to another vulnerability" +msgstr "" + msgid "has already been taken" msgstr "" diff --git a/spec/frontend/create_cluster/gke_cluster/components/gke_machine_type_dropdown_spec.js b/spec/frontend/create_cluster/gke_cluster/components/gke_machine_type_dropdown_spec.js new file mode 100644 index 00000000000..d6a752d761d --- /dev/null +++ b/spec/frontend/create_cluster/gke_cluster/components/gke_machine_type_dropdown_spec.js @@ -0,0 +1,136 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import { selectedMachineTypeMock, gapiMachineTypesResponseMock } from '../mock_data'; +import createState from '~/create_cluster/gke_cluster/store/state'; +import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; +import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; +import GkeMachineTypeDropdown from '~/create_cluster/gke_cluster/components/gke_machine_type_dropdown.vue'; + +const componentConfig = { + fieldId: 'cluster_provider_gcp_attributes_gcp_machine_type', + fieldName: 'cluster[provider_gcp_attributes][gcp_machine_type]', +}; +const setMachineType = jest.fn(); + +const LABELS = { + LOADING: 'Fetching machine types', + DISABLED_NO_PROJECT: 'Select project and zone to choose machine type', + DISABLED_NO_ZONE: 'Select zone to choose machine type', + DEFAULT: 'Select machine type', +}; + +const localVue = createLocalVue(); + +localVue.use(Vuex); + +const createComponent = (store, propsData = componentConfig) => + shallowMount(GkeMachineTypeDropdown, { + propsData, + store, + localVue, + sync: false, + }); + +const createStore = (initialState = {}, getters = {}) => + new Vuex.Store({ + state: { + ...createState(), + ...initialState, + }, + getters: { + hasZone: () => false, + ...getters, + }, + actions: { + setMachineType, + }, + }); + +describe('GkeMachineTypeDropdown', () => { + let wrapper; + let store; + + afterEach(() => { + wrapper.destroy(); + }); + + const dropdownButtonLabel = () => wrapper.find(DropdownButton).props('toggleText'); + const dropdownHiddenInputValue = () => wrapper.find(DropdownHiddenInput).props('value'); + + describe('shows various toggle text depending on state', () => { + it('returns disabled state toggle text when no project and zone are selected', () => { + store = createStore({ + projectHasBillingEnabled: false, + }); + wrapper = createComponent(store); + + expect(dropdownButtonLabel()).toBe(LABELS.DISABLED_NO_PROJECT); + }); + + it('returns disabled state toggle text when no zone is selected', () => { + store = createStore({ + projectHasBillingEnabled: true, + }); + wrapper = createComponent(store); + + expect(dropdownButtonLabel()).toBe(LABELS.DISABLED_NO_ZONE); + }); + + it('returns loading toggle text', () => { + store = createStore(); + wrapper = createComponent(store); + + wrapper.setData({ isLoading: true }); + + return wrapper.vm.$nextTick().then(() => { + expect(dropdownButtonLabel()).toBe(LABELS.LOADING); + }); + }); + + it('returns default toggle text', () => { + store = createStore( + { + projectHasBillingEnabled: true, + }, + { hasZone: () => true }, + ); + wrapper = createComponent(store); + + expect(dropdownButtonLabel()).toBe(LABELS.DEFAULT); + }); + + it('returns machine type name if machine type selected', () => { + store = createStore( + { + projectHasBillingEnabled: true, + selectedMachineType: selectedMachineTypeMock, + }, + { hasZone: () => true }, + ); + wrapper = createComponent(store); + + expect(dropdownButtonLabel()).toBe(selectedMachineTypeMock); + }); + }); + + describe('form input', () => { + it('reflects new value when dropdown item is clicked', () => { + store = createStore({ + machineTypes: gapiMachineTypesResponseMock.items, + }); + wrapper = createComponent(store); + + expect(dropdownHiddenInputValue()).toBe(''); + + wrapper.find('.dropdown-content button').trigger('click'); + + return wrapper.vm.$nextTick().then(() => { + expect(setMachineType).toHaveBeenCalledWith( + expect.anything(), + selectedMachineTypeMock, + undefined, + ); + }); + }); + }); +}); diff --git a/spec/frontend/create_cluster/gke_cluster/mock_data.js b/spec/frontend/create_cluster/gke_cluster/mock_data.js new file mode 100644 index 00000000000..d9f5dbc636f --- /dev/null +++ b/spec/frontend/create_cluster/gke_cluster/mock_data.js @@ -0,0 +1,75 @@ +export const emptyProjectMock = { + projectId: '', + name: '', +}; + +export const selectedProjectMock = { + projectId: 'gcp-project-123', + name: 'gcp-project', +}; + +export const selectedZoneMock = 'us-central1-a'; + +export const selectedMachineTypeMock = 'n1-standard-2'; + +export const gapiProjectsResponseMock = { + projects: [ + { + projectNumber: '1234', + projectId: 'gcp-project-123', + lifecycleState: 'ACTIVE', + name: 'gcp-project', + createTime: '2017-12-16T01:48:29.129Z', + parent: { + type: 'organization', + id: '12345', + }, + }, + ], +}; + +export const gapiZonesResponseMock = { + kind: 'compute#zoneList', + id: 'projects/gitlab-internal-153318/zones', + items: [ + { + kind: 'compute#zone', + id: '2000', + creationTimestamp: '1969-12-31T16:00:00.000-08:00', + name: 'us-central1-a', + description: 'us-central1-a', + status: 'UP', + region: + 'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/regions/us-central1', + selfLink: + 'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones/us-central1-a', + availableCpuPlatforms: ['Intel Skylake', 'Intel Broadwell', 'Intel Sandy Bridge'], + }, + ], + selfLink: 'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones', +}; + +export const gapiMachineTypesResponseMock = { + kind: 'compute#machineTypeList', + id: 'projects/gitlab-internal-153318/zones/us-central1-a/machineTypes', + items: [ + { + kind: 'compute#machineType', + id: '3002', + creationTimestamp: '1969-12-31T16:00:00.000-08:00', + name: 'n1-standard-2', + description: '2 vCPUs, 7.5 GB RAM', + guestCpus: 2, + memoryMb: 7680, + imageSpaceGb: 10, + maximumPersistentDisks: 64, + maximumPersistentDisksSizeGb: '65536', + zone: 'us-central1-a', + selfLink: + 'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones/us-central1-a/machineTypes/n1-standard-2', + isSharedCpu: false, + }, + ], + selfLink: + 'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones/us-central1-a/machineTypes', +}; diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index 3c16994495d..27fa98bbde4 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -23,7 +23,7 @@ describe GitlabSchema.types['Project'] do only_allow_merge_if_all_discussions_are_resolved printing_merge_request_link_enabled namespace group statistics repository merge_requests merge_request issues issue pipelines removeSourceBranchAfterMerge sentryDetailedError snippets - grafanaIntegration + grafanaIntegration autocloseReferencedIssues ] is_expected.to include_graphql_fields(*expected_fields) diff --git a/spec/javascripts/create_cluster/gke_cluster/components/gke_machine_type_dropdown_spec.js b/spec/javascripts/create_cluster/gke_cluster/components/gke_machine_type_dropdown_spec.js deleted file mode 100644 index e687040ddf9..00000000000 --- a/spec/javascripts/create_cluster/gke_cluster/components/gke_machine_type_dropdown_spec.js +++ /dev/null @@ -1,109 +0,0 @@ -import Vue from 'vue'; -import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; -import GkeMachineTypeDropdown from '~/create_cluster/gke_cluster/components/gke_machine_type_dropdown.vue'; -import { createStore } from '~/create_cluster/gke_cluster/store'; -import { - SET_PROJECT, - SET_PROJECT_BILLING_STATUS, - SET_ZONE, - SET_MACHINE_TYPES, -} from '~/create_cluster/gke_cluster/store/mutation_types'; -import { - selectedZoneMock, - selectedProjectMock, - selectedMachineTypeMock, - gapiMachineTypesResponseMock, -} from '../mock_data'; - -const componentConfig = { - fieldId: 'cluster_provider_gcp_attributes_gcp_machine_type', - fieldName: 'cluster[provider_gcp_attributes][gcp_machine_type]', -}; - -const LABELS = { - LOADING: 'Fetching machine types', - DISABLED_NO_PROJECT: 'Select project and zone to choose machine type', - DISABLED_NO_ZONE: 'Select zone to choose machine type', - DEFAULT: 'Select machine type', -}; - -const createComponent = (store, props = componentConfig) => { - const Component = Vue.extend(GkeMachineTypeDropdown); - - return mountComponentWithStore(Component, { - el: null, - props, - store, - }); -}; - -describe('GkeMachineTypeDropdown', () => { - let vm; - let store; - - beforeEach(() => { - store = createStore(); - vm = createComponent(store); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('shows various toggle text depending on state', () => { - it('returns disabled state toggle text when no project and zone are selected', () => { - expect(vm.toggleText).toBe(LABELS.DISABLED_NO_PROJECT); - }); - - it('returns disabled state toggle text when no zone is selected', () => { - vm.$store.commit(SET_PROJECT, selectedProjectMock); - vm.$store.commit(SET_PROJECT_BILLING_STATUS, true); - - expect(vm.toggleText).toBe(LABELS.DISABLED_NO_ZONE); - }); - - it('returns loading toggle text', () => { - vm.isLoading = true; - - expect(vm.toggleText).toBe(LABELS.LOADING); - }); - - it('returns default toggle text', () => { - expect(vm.toggleText).toBe(LABELS.DISABLED_NO_PROJECT); - - vm.$store.commit(SET_PROJECT, selectedProjectMock); - vm.$store.commit(SET_PROJECT_BILLING_STATUS, true); - vm.$store.commit(SET_ZONE, selectedZoneMock); - - expect(vm.toggleText).toBe(LABELS.DEFAULT); - }); - - it('returns machine type name if machine type selected', () => { - vm.setItem(selectedMachineTypeMock); - - expect(vm.toggleText).toBe(selectedMachineTypeMock); - }); - }); - - describe('form input', () => { - it('reflects new value when dropdown item is clicked', done => { - expect(vm.$el.querySelector('input').value).toBe(''); - vm.$store.commit(SET_MACHINE_TYPES, gapiMachineTypesResponseMock.items); - - return vm - .$nextTick() - .then(() => { - vm.$el.querySelector('.dropdown-content button').click(); - - return vm - .$nextTick() - .then(() => { - expect(vm.$el.querySelector('input').value).toBe(selectedMachineTypeMock); - done(); - }) - .catch(done.fail); - }) - .catch(done.fail); - }); - }); -}); diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index fdd01f58c9d..510876a5945 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -438,6 +438,17 @@ describe Gitlab::ClosingIssueExtractor do .to match_array([issue]) end end + + context "with autoclose referenced issues disabled" do + before do + project.update!(autoclose_referenced_issues: false) + end + + it do + message = "Awesome commit (Closes #{reference})" + expect(subject.closed_by_message(message)).to eq([]) + end + end end def urls diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index dc0851294b5..07439880beb 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -463,6 +463,7 @@ project: - import_failures - container_expiration_policy - resource_groups +- autoclose_referenced_issues award_emoji: - awardable - user diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 79442c35797..adb49c8c7e7 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -534,6 +534,7 @@ Project: - pages_https_only - merge_requests_disable_committers_approval - require_password_to_approve +- autoclose_referenced_issues ProjectTracingSetting: - external_url Author: diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb index 890918d4a7c..85a536ee6ad 100644 --- a/spec/lib/gitlab/utils_spec.rb +++ b/spec/lib/gitlab/utils_spec.rb @@ -3,8 +3,9 @@ require 'spec_helper' describe Gitlab::Utils do - delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, :ensure_array_from_string, - :bytes_to_megabytes, :append_path, :check_path_traversal!, to: :described_class + delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, + :ensure_array_from_string, :to_exclusive_sentence, :bytes_to_megabytes, + :append_path, :check_path_traversal!, to: :described_class describe '.check_path_traversal!' do it 'detects path traversal at the start of the string' do @@ -46,6 +47,36 @@ describe Gitlab::Utils do end end + describe '.to_exclusive_sentence' do + it 'calls #to_sentence on the array' do + array = double + + expect(array).to receive(:to_sentence) + + to_exclusive_sentence(array) + end + + it 'joins arrays with two elements correctly' do + array = %w(foo bar) + + expect(to_exclusive_sentence(array)).to eq('foo or bar') + end + + it 'joins arrays with more than two elements correctly' do + array = %w(foo bar baz) + + expect(to_exclusive_sentence(array)).to eq('foo, bar, or baz') + end + + it 'localizes the connector words' do + array = %w(foo bar baz) + + expect(described_class).to receive(:_).with(' or ').and_return(' <1> ') + expect(described_class).to receive(:_).with(', or ').and_return(', <2> ') + expect(to_exclusive_sentence(array)).to eq('foo, bar, <2> baz') + end + end + describe '.nlbr' do it 'replaces new lines with <br>' do expect(described_class.nlbr("<b>hello</b>\n<i>world</i>".freeze)).to eq("hello<br>world") diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 930ec889206..a9d79454dd5 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -390,6 +390,17 @@ eos expect(commit.closes_issues).to include(issue) expect(commit.closes_issues).to include(other_issue) end + + it 'ignores referenced issues when auto-close is disabled' do + project.update!(autoclose_referenced_issues: false) + + allow(commit).to receive_messages( + safe_message: "Fixes ##{issue.iid}", + committer_email: committer.email + ) + + expect(commit.closes_issues).to be_empty + end end it_behaves_like 'a mentionable' do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 0e151475128..7e28736954c 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -963,6 +963,15 @@ describe MergeRequest do expect(subject.closes_issues).to be_empty end + + it 'ignores referenced issues when auto-close is disabled' do + subject.project.update!(autoclose_referenced_issues: false) + + allow(subject.project).to receive(:default_branch) + .and_return(subject.target_branch) + + expect(subject.closes_issues).to be_empty + end end describe '#issues_mentioned_but_not_closing' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index c1c29ac9c29..e2fb7674d62 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -474,6 +474,32 @@ describe Project do end end + describe '#autoclose_referenced_issues' do + context 'when DB entry is nil' do + let(:project) { create(:project, autoclose_referenced_issues: nil) } + + it 'returns true' do + expect(project.autoclose_referenced_issues).to be_truthy + end + end + + context 'when DB entry is true' do + let(:project) { create(:project, autoclose_referenced_issues: true) } + + it 'returns true' do + expect(project.autoclose_referenced_issues).to be_truthy + end + end + + context 'when DB entry is false' do + let(:project) { create(:project, autoclose_referenced_issues: false) } + + it 'returns false' do + expect(project.autoclose_referenced_issues).to be_falsey + end + end + end + describe 'project token' do it 'sets an random token if none provided' do project = FactoryBot.create(:project, runners_token: '') diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 975e59346b8..03efbc6bce7 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -635,6 +635,7 @@ describe API::Projects do wiki_enabled: false, resolve_outdated_diff_discussions: false, remove_source_branch_after_merge: true, + autoclose_referenced_issues: true, only_allow_merge_if_pipeline_succeeds: false, request_access_enabled: true, only_allow_merge_if_all_discussions_are_resolved: false, @@ -807,6 +808,22 @@ describe API::Projects do expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_truthy end + it 'sets a project as enabling auto close referenced issues' do + project = attributes_for(:project, autoclose_referenced_issues: true) + + post api('/projects', user), params: project + + expect(json_response['autoclose_referenced_issues']).to be_truthy + end + + it 'sets a project as disabling auto close referenced issues' do + project = attributes_for(:project, autoclose_referenced_issues: false) + + post api('/projects', user), params: project + + expect(json_response['autoclose_referenced_issues']).to be_falsey + end + it 'sets the merge method of a project to rebase merge' do project = attributes_for(:project, merge_method: 'rebase_merge') diff --git a/spec/workers/chat_notification_worker_spec.rb b/spec/workers/chat_notification_worker_spec.rb index 91695674f5d..e4dccf2bf6b 100644 --- a/spec/workers/chat_notification_worker_spec.rb +++ b/spec/workers/chat_notification_worker_spec.rb @@ -8,6 +8,10 @@ describe ChatNotificationWorker do create(:ci_build, pipeline: create(:ci_pipeline, source: :chat)) end + it 'instructs sidekiq not to retry on failure' do + expect(described_class.get_sidekiq_options['retry']).to eq(false) + end + describe '#perform' do it 'does nothing when the build no longer exists' do expect(worker).not_to receive(:send_response) @@ -23,16 +27,31 @@ describe ChatNotificationWorker do worker.perform(chat_build.id) end - it 'reschedules the job if the trace sections could not be found' do - expect(worker) - .to receive(:send_response) - .and_raise(Gitlab::Chat::Output::MissingBuildSectionError) + context 'when the trace sections could not be found' do + it 'reschedules the job' do + expect(worker) + .to receive(:send_response) + .and_raise(Gitlab::Chat::Output::MissingBuildSectionError) - expect(described_class) - .to receive(:perform_in) - .with(described_class::RESCHEDULE_INTERVAL, chat_build.id) + expect(described_class) + .to receive(:perform_in) + .with(described_class::RESCHEDULE_INTERVAL, chat_build.id, 1) - worker.perform(chat_build.id) + worker.perform(chat_build.id) + end + + it "raises an error after #{described_class::RESCHEDULE_TIMEOUT} seconds of retrying" do + allow(described_class).to receive(:new).and_return(worker) + allow(worker).to receive(:send_response).and_raise(Gitlab::Chat::Output::MissingBuildSectionError) + + worker.perform(chat_build.id) + + expect { described_class.drain }.to raise_error(described_class::TimeoutExceeded) + + max_reschedules = described_class::RESCHEDULE_TIMEOUT / described_class::RESCHEDULE_INTERVAL + + expect(worker).to have_received(:send_response).exactly(max_reschedules + 1).times + end end end |