Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
211635ad
Commit
211635ad
authored
Oct 06, 2020
by
Felipe Artur
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add IssueMove mutation
Allow to move issue between projects with GraphQL
parent
35032389
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
367 additions
and
1 deletion
+367
-1
app/graphql/mutations/issues/move.rb
app/graphql/mutations/issues/move.rb
+33
-0
app/graphql/types/mutation_type.rb
app/graphql/types/mutation_type.rb
+1
-0
changelogs/unreleased/issue-233479-Allow_move_issues_on_graphql.yml
.../unreleased/issue-233479-Allow_move_issues_on_graphql.yml
+5
-0
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+46
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+157
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+10
-0
rubocop/cop/graphql/id_type.rb
rubocop/cop/graphql/id_type.rb
+1
-1
spec/graphql/mutations/issues/move_spec.rb
spec/graphql/mutations/issues/move_spec.rb
+41
-0
spec/requests/api/graphql/mutations/issues/move_spec.rb
spec/requests/api/graphql/mutations/issues/move_spec.rb
+73
-0
No files found.
app/graphql/mutations/issues/move.rb
0 → 100644
View file @
211635ad
# frozen_string_literal: true
module
Mutations
module
Issues
class
Move
<
Base
graphql_name
'IssueMove'
argument
:target_project_path
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'The project to move the issue to.'
def
resolve
(
project_path
:,
iid
:,
target_project_path
:)
Gitlab
::
QueryLimiting
.
whitelist
(
'https://gitlab.com/gitlab-org/gitlab/-/issues/267762'
)
issue
=
authorized_find!
(
project_path:
project_path
,
iid:
iid
)
source_project
=
issue
.
project
target_project
=
resolve_project
(
full_path:
target_project_path
).
sync
begin
moved_issue
=
::
Issues
::
MoveService
.
new
(
source_project
,
current_user
).
execute
(
issue
,
target_project
)
rescue
::
Issues
::
MoveService
::
MoveError
=>
error
errors
=
error
.
message
end
{
issue:
moved_issue
,
errors:
Array
.
wrap
(
errors
)
}
end
end
end
end
app/graphql/types/mutation_type.rb
View file @
211635ad
...
...
@@ -31,6 +31,7 @@ module Types
mount_mutation
Mutations
::
Issues
::
SetSeverity
mount_mutation
Mutations
::
Issues
::
SetSubscription
mount_mutation
Mutations
::
Issues
::
Update
mount_mutation
Mutations
::
Issues
::
Move
mount_mutation
Mutations
::
MergeRequests
::
Create
mount_mutation
Mutations
::
MergeRequests
::
Update
mount_mutation
Mutations
::
MergeRequests
::
SetLabels
...
...
changelogs/unreleased/issue-233479-Allow_move_issues_on_graphql.yml
0 → 100644
View file @
211635ad
---
title
:
Allow to move issues between projects on GraphQL
merge_request
:
44491
author
:
type
:
added
doc/api/graphql/reference/gitlab_schema.graphql
View file @
211635ad
...
...
@@ -9187,6 +9187,31 @@ Identifier of Issue
"""
scalar
IssueID
"""
Autogenerated input type of IssueMove
"""
input
IssueMoveInput
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
The
IID
of
the
issue
to
mutate
"""
iid
:
String
!
"""
The
project
the
issue
to
mutate
is
in
"""
projectPath
:
ID
!
"""
The
project
to
move
the
issue
to
.
"""
targetProjectPath
:
ID
!
}
"""
Autogenerated input type of IssueMoveList
"""
...
...
@@ -9257,6 +9282,26 @@ type IssueMoveListPayload {
issue
:
Issue
}
"""
Autogenerated return type of IssueMove
"""
type
IssueMovePayload
{
"""
A
unique
identifier
for
the
client
performing
the
mutation
.
"""
clientMutationId
:
String
"""
Errors
encountered
during
execution
of
the
mutation
.
"""
errors
:
[
String
!]!
"""
The
issue
after
mutation
"""
issue
:
Issue
}
"""
Check permissions for the current user on a issue
"""
...
...
@@ -12109,6 +12154,7 @@ type Mutation {
epicAddIssue
(
input
:
EpicAddIssueInput
!):
EpicAddIssuePayload
epicSetSubscription
(
input
:
EpicSetSubscriptionInput
!):
EpicSetSubscriptionPayload
epicTreeReorder
(
input
:
EpicTreeReorderInput
!):
EpicTreeReorderPayload
issueMove
(
input
:
IssueMoveInput
!):
IssueMovePayload
issueMoveList
(
input
:
IssueMoveListInput
!):
IssueMoveListPayload
issueSetAssignees
(
input
:
IssueSetAssigneesInput
!):
IssueSetAssigneesPayload
issueSetConfidential
(
input
:
IssueSetConfidentialInput
!):
IssueSetConfidentialPayload
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
211635ad
...
...
@@ -25043,6 +25043,69 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "IssueMoveInput",
"description": "Autogenerated input type of IssueMove",
"fields": null,
"inputFields": [
{
"name": "projectPath",
"description": "The project the issue 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 issue to mutate",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "targetProjectPath",
"description": "The project to move the issue to.",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"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": "INPUT_OBJECT",
"name": "IssueMoveListInput",
...
...
@@ -25223,6 +25286,73 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "IssueMovePayload",
"description": "Autogenerated return type of IssueMove",
"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": "Errors encountered during execution of the mutation.",
"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": "issue",
"description": "The issue after mutation",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Issue",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "IssuePermissions",
...
...
@@ -34412,6 +34542,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "issueMove",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "IssueMoveInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "IssueMovePayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "issueMoveList",
"description": null,
doc/api/graphql/reference/index.md
View file @
211635ad
...
...
@@ -1296,6 +1296,16 @@ Autogenerated return type of IssueMoveList.
|
`errors`
| String! => Array | Errors encountered during execution of the mutation. |
|
`issue`
| Issue | The issue after mutation |
### IssueMovePayload
Autogenerated return type of IssueMove.
| Field | Type | Description |
| ----- | ---- | ----------- |
|
`clientMutationId`
| String | A unique identifier for the client performing the mutation. |
|
`errors`
| String! => Array | Errors encountered during execution of the mutation. |
|
`issue`
| Issue | The issue after mutation |
### IssuePermissions
Check permissions for the current user on a issue.
...
...
rubocop/cop/graphql/id_type.rb
View file @
211635ad
...
...
@@ -6,7 +6,7 @@ module RuboCop
class
IDType
<
RuboCop
::
Cop
::
Cop
MSG
=
'Do not use GraphQL::ID_TYPE, use a specific GlobalIDType instead'
WHITELISTED_ARGUMENTS
=
%i[iid full_path project_path group_path]
.
freeze
WHITELISTED_ARGUMENTS
=
%i[iid full_path project_path group_path
target_project_path
]
.
freeze
def_node_search
:graphql_id_type?
,
<<~
PATTERN
(send nil? :argument (_ #does_not_match?) (const (const nil? :GraphQL) :ID_TYPE) ...)
...
...
spec/graphql/mutations/issues/move_spec.rb
0 → 100644
View file @
211635ad
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Mutations
::
Issues
::
Move
do
let_it_be
(
:issue
)
{
create
(
:issue
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:target_project
)
{
create
(
:project
)
}
subject
(
:mutation
)
{
described_class
.
new
(
object:
nil
,
context:
{
current_user:
user
},
field:
nil
)
}
describe
'#resolve'
do
subject
(
:resolve
)
{
mutation
.
resolve
(
project_path:
issue
.
project
.
full_path
,
iid:
issue
.
iid
,
target_project_path:
target_project
.
full_path
)
}
it
'raises an error if the resource is not accessible to the user'
do
expect
{
resolve
}.
to
raise_error
(
Gitlab
::
Graphql
::
Errors
::
ResourceNotAvailable
)
end
context
'when user does not have permissions'
do
before
do
issue
.
project
.
add_developer
(
user
)
end
it
'returns error message'
do
expect
(
resolve
[
:issue
]).
to
eq
(
nil
)
expect
(
resolve
[
:errors
].
first
).
to
eq
(
'Cannot move issue due to insufficient permissions!'
)
end
end
context
'when user has sufficient permissions'
do
before
do
issue
.
project
.
add_developer
(
user
)
target_project
.
add_developer
(
user
)
end
it
'moves issue'
do
expect
(
resolve
[
:issue
].
project
).
to
eq
(
target_project
)
end
end
end
end
spec/requests/api/graphql/mutations/issues/move_spec.rb
0 → 100644
View file @
211635ad
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'Moving an issue'
do
include
GraphqlHelpers
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:issue
)
{
create
(
:issue
)
}
let_it_be
(
:target_project
)
{
create
(
:project
)
}
let
(
:mutation
)
do
variables
=
{
project_path:
issue
.
project
.
full_path
,
target_project_path:
target_project
.
full_path
,
iid:
issue
.
iid
.
to_s
}
graphql_mutation
(
:issue_move
,
variables
,
<<-
QL
.
strip_heredoc
clientMutationId
errors
issue {
title
}
QL
)
end
def
mutation_response
graphql_mutation_response
(
:issue_move
)
end
context
'when the user is not allowed to read source project'
do
it
'returns an error'
do
error
=
"The resource that you are attempting to access does not exist or you don't have permission to perform this action"
post_graphql_mutation
(
mutation
,
current_user:
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
expect
(
graphql_errors
).
to
include
(
a_hash_including
(
'message'
=>
error
))
end
end
context
'when the user is not allowed to move issue to target project'
do
before
do
issue
.
project
.
add_developer
(
user
)
end
it
'returns an error'
do
error
=
"Cannot move issue due to insufficient permissions!"
post_graphql_mutation
(
mutation
,
current_user:
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
expect
(
mutation_response
[
'errors'
][
0
]).
to
eq
(
error
)
end
end
context
'when the user is allowed to move issue'
do
before
do
issue
.
project
.
add_developer
(
user
)
target_project
.
add_developer
(
user
)
end
it
'moves the issue'
do
post_graphql_mutation
(
mutation
,
current_user:
user
)
expect
(
response
).
to
have_gitlab_http_status
(
:success
)
expect
(
mutation_response
.
dig
(
'issue'
,
'title'
)).
to
eq
(
issue
.
title
)
expect
(
issue
.
reload
.
state
).
to
eq
(
'closed'
)
expect
(
target_project
.
issues
.
find_by_title
(
issue
.
title
)).
to
be_present
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment