diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-15 03:06:05 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-15 03:06:05 +0300 |
commit | 386e5740f68fc7f49bc7692a28e927d6ea5ab056 (patch) | |
tree | 36c74aefd8101dbf439e11ba9bf1c0cf45f0ff16 | |
parent | b1ffdbb7f92407ceef575e557af07a3e3d067edf (diff) |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | app/graphql/mutations/merge_requests/set_assignees.rb | 48 | ||||
-rw-r--r-- | app/graphql/types/mutation_operation_mode_enum.rb | 14 | ||||
-rw-r--r-- | app/graphql/types/mutation_type.rb | 1 | ||||
-rw-r--r-- | app/models/milestone.rb | 1 | ||||
-rw-r--r-- | changelogs/unreleased/12769-milestone-blank-name-causes-issues.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/31919-graphql-MR-assignee-mutation.yml | 5 | ||||
-rw-r--r-- | db/migrate/20191112232338_ensure_no_empty_milestone_titles.rb | 18 | ||||
-rw-r--r-- | db/schema.rb | 2 | ||||
-rw-r--r-- | doc/api/graphql/reference/gitlab_schema.graphql | 71 | ||||
-rw-r--r-- | doc/api/graphql/reference/gitlab_schema.json | 204 | ||||
-rw-r--r-- | doc/api/graphql/reference/index.md | 8 | ||||
-rw-r--r-- | doc/ci/img/junit_test_report_ui.png | bin | 0 -> 84300 bytes | |||
-rw-r--r-- | doc/ci/junit_test_reports.md | 24 | ||||
-rw-r--r-- | spec/graphql/mutations/merge_requests/set_assignees_spec.rb | 106 | ||||
-rw-r--r-- | spec/models/milestone_spec.rb | 11 | ||||
-rw-r--r-- | spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb | 134 |
16 files changed, 651 insertions, 1 deletions
diff --git a/app/graphql/mutations/merge_requests/set_assignees.rb b/app/graphql/mutations/merge_requests/set_assignees.rb new file mode 100644 index 00000000000..8f0025f0a58 --- /dev/null +++ b/app/graphql/mutations/merge_requests/set_assignees.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Mutations + module MergeRequests + class SetAssignees < Base + graphql_name 'MergeRequestSetAssignees' + + argument :assignee_usernames, + [GraphQL::STRING_TYPE], + required: true, + description: <<~DESC + The usernames to assign to the merge request. Replaces existing assignees by default. + DESC + + argument :operation_mode, + Types::MutationOperationModeEnum, + required: false, + description: <<~DESC + The operation to perform. Defaults to REPLACE. + DESC + + def resolve(project_path:, iid:, assignee_usernames:, operation_mode: Types::MutationOperationModeEnum.enum[:replace]) + Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/issues/36098') + + merge_request = authorized_find!(project_path: project_path, iid: iid) + project = merge_request.project + + assignee_ids = [] + assignee_ids += merge_request.assignees.map(&:id) if Types::MutationOperationModeEnum.enum.values_at(:remove, :append).include?(operation_mode) + user_ids = UsersFinder.new(current_user, username: assignee_usernames).execute.map(&:id) + + if operation_mode == Types::MutationOperationModeEnum.enum[:remove] + assignee_ids -= user_ids + else + assignee_ids |= user_ids + end + + ::MergeRequests::UpdateService.new(project, current_user, assignee_ids: assignee_ids) + .execute(merge_request) + + { + merge_request: merge_request, + errors: merge_request.errors.full_messages + } + end + end + end +end diff --git a/app/graphql/types/mutation_operation_mode_enum.rb b/app/graphql/types/mutation_operation_mode_enum.rb new file mode 100644 index 00000000000..90a29d2b0e5 --- /dev/null +++ b/app/graphql/types/mutation_operation_mode_enum.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + class MutationOperationModeEnum < BaseEnum + graphql_name 'MutationOperationMode' + description 'Different toggles for changing mutator behavior.' + + # Suggested param name for the enum: `operation_mode` + + value 'REPLACE', 'Performs a replace operation' + value 'APPEND', 'Performs an append operation' + value 'REMOVE', 'Performs a removal operation' + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 632e1fdc2df..56e724292d5 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -11,6 +11,7 @@ module Types mount_mutation Mutations::AwardEmojis::Toggle mount_mutation Mutations::MergeRequests::SetMilestone mount_mutation Mutations::MergeRequests::SetWip, calls_gitaly: true + mount_mutation Mutations::MergeRequests::SetAssignees mount_mutation Mutations::Notes::Create::Note, calls_gitaly: true mount_mutation Mutations::Notes::Create::DiffNote, calls_gitaly: true mount_mutation Mutations::Notes::Create::ImageDiffNote, calls_gitaly: true diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 3552efbdd7b..d0be54eed02 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -60,6 +60,7 @@ class Milestone < ApplicationRecord validates :group, presence: true, unless: :project validates :project, presence: true, unless: :group + validates :title, presence: true validate :uniqueness_of_title, if: :title_changed? validate :milestone_type_check diff --git a/changelogs/unreleased/12769-milestone-blank-name-causes-issues.yml b/changelogs/unreleased/12769-milestone-blank-name-causes-issues.yml new file mode 100644 index 00000000000..44ec08e611b --- /dev/null +++ b/changelogs/unreleased/12769-milestone-blank-name-causes-issues.yml @@ -0,0 +1,5 @@ +--- +title: Ensure milestone titles are never empty +merge_request: 19985 +author: +type: fixed diff --git a/changelogs/unreleased/31919-graphql-MR-assignee-mutation.yml b/changelogs/unreleased/31919-graphql-MR-assignee-mutation.yml new file mode 100644 index 00000000000..02c2e4421dc --- /dev/null +++ b/changelogs/unreleased/31919-graphql-MR-assignee-mutation.yml @@ -0,0 +1,5 @@ +--- +title: Add MergeRequestSetAssignees GraphQL mutation +merge_request: 19272 +author: +type: added diff --git a/db/migrate/20191112232338_ensure_no_empty_milestone_titles.rb b/db/migrate/20191112232338_ensure_no_empty_milestone_titles.rb new file mode 100644 index 00000000000..76cb511424e --- /dev/null +++ b/db/migrate/20191112232338_ensure_no_empty_milestone_titles.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class EnsureNoEmptyMilestoneTitles < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def up + loop do + rows_updated = exec_update <<~SQL + UPDATE milestones SET title = '%BLANK' WHERE id IN (SELECT id FROM milestones WHERE title = '' LIMIT 500) + SQL + break if rows_updated < 500 + end + end + + def down; end +end diff --git a/db/schema.rb b/db/schema.rb index 36883130b78..72d1d957d6b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_11_12_221821) do +ActiveRecord::Schema.define(version: 2019_11_12_232338) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index c75d9f236f9..2023f135550 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -3358,6 +3358,56 @@ type MergeRequestPermissions { } """ +Autogenerated input type of MergeRequestSetAssignees +""" +input MergeRequestSetAssigneesInput { + """ + The usernames to assign to the merge request. Replaces existing assignees by default. + """ + assigneeUsernames: [String!]! + + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + The iid of the merge request to mutate + """ + iid: String! + + """ + The operation to perform. Defaults to REPLACE. + """ + operationMode: MutationOperationMode + + """ + The project the merge request to mutate is in + """ + projectPath: ID! +} + +""" +Autogenerated return type of MergeRequestSetAssignees +""" +type MergeRequestSetAssigneesPayload { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + Reasons why the mutation failed. + """ + errors: [String!]! + + """ + The merge request after mutation + """ + mergeRequest: MergeRequest +} + +""" Autogenerated input type of MergeRequestSetMilestone """ input MergeRequestSetMilestoneInput { @@ -3537,6 +3587,7 @@ type Mutation { destroyNote(input: DestroyNoteInput!): DestroyNotePayload epicSetSubscription(input: EpicSetSubscriptionInput!): EpicSetSubscriptionPayload epicTreeReorder(input: EpicTreeReorderInput!): EpicTreeReorderPayload + mergeRequestSetAssignees(input: MergeRequestSetAssigneesInput!): MergeRequestSetAssigneesPayload mergeRequestSetMilestone(input: MergeRequestSetMilestoneInput!): MergeRequestSetMilestonePayload mergeRequestSetWip(input: MergeRequestSetWipInput!): MergeRequestSetWipPayload removeAwardEmoji(input: RemoveAwardEmojiInput!): RemoveAwardEmojiPayload @@ -3546,6 +3597,26 @@ type Mutation { updateNote(input: UpdateNoteInput!): UpdateNotePayload } +""" +Different toggles for changing mutator behavior. +""" +enum MutationOperationMode { + """ + Performs an append operation + """ + APPEND + + """ + Performs a removal operation + """ + REMOVE + + """ + Performs a replace operation + """ + REPLACE +} + type Namespace { """ Description of the namespace diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 629c18629cf..420b20919a7 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -14737,6 +14737,33 @@ "deprecationReason": null }, { + "name": "mergeRequestSetAssignees", + "description": null, + "args": [ + { + "name": "input", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "MergeRequestSetAssigneesInput", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "MergeRequestSetAssigneesPayload", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "mergeRequestSetMilestone", "description": null, "args": [ @@ -15678,6 +15705,183 @@ }, { "kind": "OBJECT", + "name": "MergeRequestSetAssigneesPayload", + "description": "Autogenerated return type of MergeRequestSetAssignees", + "fields": [ + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "errors", + "description": "Reasons why the mutation failed.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mergeRequest", + "description": "The merge request after mutation", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "MergeRequest", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", + "name": "MergeRequestSetAssigneesInput", + "description": "Autogenerated input type of MergeRequestSetAssignees", + "fields": null, + "inputFields": [ + { + "name": "projectPath", + "description": "The project the merge request to mutate is in", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "iid", + "description": "The iid of the merge request to mutate", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "assigneeUsernames", + "description": "The usernames to assign to the merge request. Replaces existing assignees by default.\n", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + "defaultValue": null + }, + { + "name": "operationMode", + "description": "The operation to perform. Defaults to REPLACE.\n", + "type": { + "kind": "ENUM", + "name": "MutationOperationMode", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "ENUM", + "name": "MutationOperationMode", + "description": "Different toggles for changing mutator behavior.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "REPLACE", + "description": "Performs a replace operation", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "APPEND", + "description": "Performs an append operation", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "REMOVE", + "description": "Performs a removal operation", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, + { + "kind": "OBJECT", "name": "CreateNotePayload", "description": "Autogenerated return type of CreateNote", "fields": [ diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 7ad698ee0b5..957ea489dac 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -483,6 +483,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph | `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 | +### MergeRequestSetAssigneesPayload + +| Name | Type | Description | +| --- | ---- | ---------- | +| `clientMutationId` | String | A unique identifier for the client performing the mutation. | +| `errors` | String! => Array | Reasons why the mutation failed. | +| `mergeRequest` | MergeRequest | The merge request after mutation | + ### MergeRequestSetMilestonePayload | Name | Type | Description | diff --git a/doc/ci/img/junit_test_report_ui.png b/doc/ci/img/junit_test_report_ui.png Binary files differnew file mode 100644 index 00000000000..380c6bbb89c --- /dev/null +++ b/doc/ci/img/junit_test_report_ui.png diff --git a/doc/ci/junit_test_reports.md b/doc/ci/junit_test_reports.md index bc30e007393..3a94e9725e7 100644 --- a/doc/ci/junit_test_reports.md +++ b/doc/ci/junit_test_reports.md @@ -178,3 +178,27 @@ Currently, the following tools might not work because their XML formats are unsu |Case|Tool|Issue| |---|---|---| |`<testcase>` does not have `classname` attribute|ESlint, sass-lint|<https://gitlab.com/gitlab-org/gitlab-foss/issues/50964>| + +## Viewing JUnit test reports on GitLab + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/24792) in GitLab 12.5. + +If JUnit XML files are generated and uploaded as part of a pipeline, these reports +can be viewed inside the pipelines details page. The **Tests** tab on this page will +display a list of test suites and cases reported from the XML file. + +![Test Reports Widget](img/junit_test_report_ui.png) + +You can view all the known test suites and click on each of these to see further +details, including the cases that makeup the suite. Cases are ordered by status, +with failed showing at the top, skipped next and successful cases last. + +### Enabling the feature + +This feature comes with the `:junit_pipeline_view` feature flag disabled by default. +To enable this feature, ask a GitLab administrator with Rails console access to run the +following command: + +```ruby +Feature.enable(:junit_pipeline_view) +``` diff --git a/spec/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb new file mode 100644 index 00000000000..e8da0e25b7d --- /dev/null +++ b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Mutations::MergeRequests::SetAssignees do + let(:merge_request) { create(:merge_request) } + let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } + + describe '#resolve' do + let(:assignee) { create(:user) } + let(:assignee2) { create(:user) } + let(:assignee_usernames) { [assignee.username] } + let(:mutated_merge_request) { subject[:merge_request] } + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: assignee_usernames) } + + before do + merge_request.project.add_developer(assignee) + merge_request.project.add_developer(assignee2) + end + + it 'raises an error if the resource is not accessible to the user' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + + context 'when the user can update the merge request' do + before do + merge_request.project.add_developer(user) + end + + it 'replaces the assignee' do + merge_request.assignees = [assignee2] + merge_request.save! + + expect(mutated_merge_request).to eq(merge_request) + expect(mutated_merge_request.assignees).to contain_exactly(assignee) + expect(subject[:errors]).to be_empty + end + + it 'returns errors merge request could not be updated' do + # Make the merge request invalid + merge_request.allow_broken = true + merge_request.update!(source_project: nil) + + expect(subject[:errors]).not_to be_empty + end + + context 'when passing an empty assignee list' do + let(:assignee_usernames) { [] } + + before do + merge_request.assignees = [assignee] + merge_request.save! + end + + it 'removes all assignees' do + expect(mutated_merge_request).to eq(merge_request) + expect(mutated_merge_request.assignees).to eq([]) + expect(subject[:errors]).to be_empty + end + end + + context 'when passing "append" as true' do + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: assignee_usernames, operation_mode: Types::MutationOperationModeEnum.enum[:append]) } + + before do + merge_request.assignees = [assignee2] + merge_request.save! + + # In CE, APPEND is a NOOP as you can't have multiple assignees + # We test multiple assignment in EE specs + stub_licensed_features(multiple_merge_request_assignees: false) + end + + it 'is a NO-OP in FOSS' do + expect(mutated_merge_request).to eq(merge_request) + expect(mutated_merge_request.assignees).to contain_exactly(assignee2) + expect(subject[:errors]).to be_empty + end + end + + context 'when passing "remove" as true' do + before do + merge_request.assignees = [assignee] + merge_request.save! + end + + it 'removes named assignee' do + mutated_merge_request = mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: assignee_usernames, operation_mode: Types::MutationOperationModeEnum.enum[:remove])[:merge_request] + + expect(mutated_merge_request).to eq(merge_request) + expect(mutated_merge_request.assignees).to eq([]) + expect(subject[:errors]).to be_empty + end + + it 'does not remove unnamed assignee' do + mutated_merge_request = mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: [assignee2.username], operation_mode: Types::MutationOperationModeEnum.enum[:remove])[:merge_request] + + expect(mutated_merge_request).to eq(merge_request) + expect(mutated_merge_request.assignees).to contain_exactly(assignee) + expect(subject[:errors]).to be_empty + end + end + end + end +end diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 120ba67f328..45cd2768708 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -55,6 +55,17 @@ describe Milestone do end end + describe 'title' do + it { is_expected.to validate_presence_of(:title) } + + it 'is invalid if title would be empty after sanitation' do + milestone = build(:milestone, project: project, title: '<img src=x onerror=prompt(1)>') + + expect(milestone).not_to be_valid + expect(milestone.errors[:title]).to include("can't be blank") + end + end + describe 'milestone_releases' do let(:milestone) { build(:milestone, project: project) } diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb new file mode 100644 index 00000000000..8f908b7bf88 --- /dev/null +++ b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb @@ -0,0 +1,134 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Setting assignees of a merge request' do + include GraphqlHelpers + + let(:current_user) { create(:user) } + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.project } + let(:assignee) { create(:user) } + let(:assignee2) { create(:user) } + let(:input) { { assignee_usernames: [assignee.username] } } + let(:expected_result) do + [{ 'username' => assignee.username }] + end + + let(:mutation) do + variables = { + project_path: project.full_path, + iid: merge_request.iid.to_s + } + graphql_mutation(:merge_request_set_assignees, variables.merge(input), + <<-QL.strip_heredoc + clientMutationId + errors + mergeRequest { + id + assignees { + nodes { + username + } + } + } + QL + ) + end + + def mutation_response + graphql_mutation_response(:merge_request_set_assignees) + end + + def mutation_assignee_nodes + mutation_response['mergeRequest']['assignees']['nodes'] + end + + before do + project.add_developer(current_user) + project.add_developer(assignee) + project.add_developer(assignee2) + end + + it 'returns an error if the user is not allowed to update the merge request' do + post_graphql_mutation(mutation, current_user: create(:user)) + + expect(graphql_errors).not_to be_empty + end + + it 'does not allow members without the right permission to add assignees' do + user = create(:user) + project.add_guest(user) + + post_graphql_mutation(mutation, current_user: user) + + expect(graphql_errors).not_to be_empty + end + + context 'with assignees already assigned' do + before do + merge_request.assignees = [assignee2] + merge_request.save! + end + + it 'replaces the assignee' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_assignee_nodes).to match_array(expected_result) + end + end + + context 'when passing an empty list of assignees' do + let(:input) { { assignee_usernames: [] } } + + before do + merge_request.assignees = [assignee2] + merge_request.save! + end + + it 'removes assignee' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_assignee_nodes).to eq([]) + end + end + + context 'when passing append as true' do + let(:input) { { assignee_usernames: [assignee2.username], operation_mode: Types::MutationOperationModeEnum.enum[:append] } } + + before do + # In CE, APPEND is a NOOP as you can't have multiple assignees + # We test multiple assignment in EE specs + stub_licensed_features(multiple_merge_request_assignees: false) + + merge_request.assignees = [assignee] + merge_request.save! + end + + it 'does not replace the assignee in CE' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_assignee_nodes).to match_array(expected_result) + end + end + + context 'when passing remove as true' do + let(:input) { { assignee_usernames: [assignee.username], operation_mode: Types::MutationOperationModeEnum.enum[:remove] } } + let(:expected_result) { [] } + + before do + merge_request.assignees = [assignee] + merge_request.save! + end + + it 'removes the users in the list, while adding none' do + post_graphql_mutation(mutation, current_user: current_user) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_assignee_nodes).to match_array(expected_result) + end + end +end |