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
0
Merge Requests
0
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
Léo-Paul Géneau
gitlab-ce
Commits
c5c9dce2
Commit
c5c9dce2
authored
Jul 12, 2017
by
Felipe Artur
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add group milestones API endpoint
parent
05329d4a
Changes
12
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
545 additions
and
101 deletions
+545
-101
app/finders/issuable_finder.rb
app/finders/issuable_finder.rb
+1
-1
doc/api/README.md
doc/api/README.md
+2
-1
doc/api/group_milestones.md
doc/api/group_milestones.md
+120
-0
lib/api/api.rb
lib/api/api.rb
+2
-1
lib/api/entities.rb
lib/api/entities.rb
+2
-2
lib/api/group_milestones.rb
lib/api/group_milestones.rb
+85
-0
lib/api/helpers.rb
lib/api/helpers.rb
+4
-0
lib/api/milestone_responses.rb
lib/api/milestone_responses.rb
+98
-0
lib/api/project_milestones.rb
lib/api/project_milestones.rb
+91
-0
spec/requests/api/group_milestones_spec.rb
spec/requests/api/group_milestones_spec.rb
+21
-0
spec/requests/api/project_milestones_spec.rb
spec/requests/api/project_milestones_spec.rb
+25
-0
spec/support/api/milestones_shared_examples.rb
spec/support/api/milestones_shared_examples.rb
+94
-96
No files found.
app/finders/issuable_finder.rb
View file @
c5c9dce2
doc/api/README.md
View file @
c5c9dce2
...
...
@@ -29,7 +29,8 @@ following locations:
-
[
Keys
](
keys.md
)
-
[
Labels
](
labels.md
)
-
[
Merge Requests
](
merge_requests.md
)
-
[
Milestones
](
milestones.md
)
-
[
Project milestones
](
milestones.md
)
-
[
Group milestones
](
group_milestones.md
)
-
[
Namespaces
](
namespaces.md
)
-
[
Notes
](
notes.md
)
(
comments
)
-
[
Notification settings
](
notification_settings.md
)
...
...
doc/api/group_milestones.md
0 → 100644
View file @
c5c9dce2
# Group milestones API
## List group milestones
Returns a list of group milestones.
```
GET /groups/:id/milestones
GET /groups/:id/milestones?iids=42
GET /groups/:id/milestones?iids[]=42&iids[]=43
GET /groups/:id/milestones?state=active
GET /groups/:id/milestones?state=closed
GET /groups/:id/milestones?search=version
```
Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the group
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`iids`
| Array[integer] | optional | Return only the milestones having the given
`iids`
|
|
`state`
| string | optional | Return only
`active`
or
`closed`
milestones
` |
| `
search
` | string | optional | Return only milestones with a title or description matching the provided string |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/milestones
```
Example Response:
```json
[
{
"id": 12,
"iid": 3,
"group_id": 16,
"title": "10.0",
"description": "Version",
"due_date": "2013-11-29",
"start_date": "2013-11-10",
"state": "active",
"updated_at": "2013-10-02T09:24:18Z",
"created_at": "2013-10-02T09:24:18Z"
}
]
```
## Get single milestone
Gets a single group milestone.
```
GET /groups/:id/milestones/:milestone_id
```
Parameters:
- `
id
` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
- `
milestone_id
` (required) - The ID of the group milestone
## Create new milestone
Creates a new group milestone.
```
POST /groups/:id/milestones
```
Parameters:
- `
id
` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
- `
title
` (required) - The title of an milestone
- `
description
` (optional) - The description of the milestone
- `
due_date
` (optional) - The due date of the milestone
- `
start_date
` (optional) - The start date of the milestone
## Edit milestone
Updates an existing group milestone.
```
PUT /groups/:id/milestones/:milestone_id
```
Parameters:
- `
id
` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
- `
milestone_id
` (required) - The ID of a group milestone
- `
title
` (optional) - The title of a milestone
- `
description
` (optional) - The description of a milestone
- `
due_date
` (optional) - The due date of the milestone
- `
start_date
` (optional) - The start date of the milestone
- `
state_event
` (optional) - The state event of the milestone (close|activate)
## Get all issues assigned to a single milestone
Gets all issues assigned to a single group milestone.
```
GET /groups/:id/milestones/:milestone_id/issues
```
Parameters:
- `
id
` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
- `
milestone_id
` (required) - The ID of a group milestone
## Get all merge requests assigned to a single milestone
Gets all merge requests assigned to a single group milestone.
```
GET /groups/:id/milestones/:milestone_id/merge_requests
```
Parameters:
- `
id
` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
- `
milestone_id
`
(required) - The ID of a group milestone
lib/api/api.rb
View file @
c5c9dce2
...
...
@@ -109,7 +109,8 @@ module API
mount
::
API
::
Members
mount
::
API
::
MergeRequestDiffs
mount
::
API
::
MergeRequests
mount
::
API
::
Milestones
mount
::
API
::
ProjectMilestones
mount
::
API
::
GroupMilestones
mount
::
API
::
Namespaces
mount
::
API
::
Notes
mount
::
API
::
NotificationSettings
...
...
lib/api/entities.rb
View file @
c5c9dce2
...
...
@@ -269,8 +269,8 @@ module API
class
Milestone
<
Grape
::
Entity
expose
:id
,
:iid
expose
(
:project_id
)
{
|
entity
|
entity
&
.
project_id
}
expose
(
:group_id
)
{
|
entity
|
entity
&
.
group_id
}
expose
:project_id
,
if:
->
(
entity
,
options
)
{
entity
&
.
project_id
}
expose
:group_id
,
if:
->
(
entity
,
options
)
{
entity
&
.
group_id
}
expose
:title
,
:description
expose
:state
,
:created_at
,
:updated_at
expose
:due_date
...
...
lib/api/group_milestones.rb
0 → 100644
View file @
c5c9dce2
module
API
class
GroupMilestones
<
Grape
::
API
include
MilestoneResponses
include
PaginationParams
before
do
authenticate!
end
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a group'
end
resource
:groups
,
requirements:
{
id:
%r{[^/]+}
}
do
desc
'Get a list of group milestones'
do
success
Entities
::
Milestone
end
params
do
use
:list_params
end
get
":id/milestones"
do
list_milestones_for
(
user_group
)
end
desc
'Get a single group milestone'
do
success
Entities
::
Milestone
end
params
do
requires
:milestone_id
,
type:
Integer
,
desc:
'The ID of a group milestone'
end
get
":id/milestones/:milestone_id"
do
authorize!
:read_group
,
user_group
get_milestone_for
(
user_group
)
end
desc
'Create a new group milestone'
do
success
Entities
::
Milestone
end
params
do
requires
:title
,
type:
String
,
desc:
'The title of the milestone'
use
:optional_params
end
post
":id/milestones"
do
authorize!
:admin_milestones
,
user_group
create_milestone_for
(
user_group
)
end
desc
'Update an existing group milestone'
do
success
Entities
::
Milestone
end
params
do
use
:update_params
end
put
":id/milestones/:milestone_id"
do
authorize!
:admin_milestones
,
user_group
update_milestone_for
(
user_group
)
end
desc
'Get all issues for a single group milestone'
do
success
Entities
::
IssueBasic
end
params
do
requires
:milestone_id
,
type:
Integer
,
desc:
'The ID of a group milestone'
use
:pagination
end
get
":id/milestones/:milestone_id/issues"
do
milestone_issuables_for
(
user_group
,
:issue
)
end
desc
'Get all merge requests for a single group milestone'
do
detail
'This feature was introduced in GitLab 9.'
success
Entities
::
MergeRequestBasic
end
params
do
requires
:milestone_id
,
type:
Integer
,
desc:
'The ID of a group milestone'
use
:pagination
end
get
':id/milestones/:milestone_id/merge_requests'
do
milestone_issuables_for
(
user_group
,
:merge_request
)
end
end
end
end
lib/api/helpers.rb
View file @
c5c9dce2
...
...
@@ -25,6 +25,10 @@ module API
initial_current_user
!=
current_user
end
def
user_group
@group
||=
find_group!
(
params
[
:id
])
end
def
user_project
@project
||=
find_project!
(
params
[
:id
])
end
...
...
lib/api/milestone_responses.rb
0 → 100644
View file @
c5c9dce2
module
API
module
MilestoneResponses
extend
ActiveSupport
::
Concern
included
do
helpers
do
params
:optional_params
do
optional
:description
,
type:
String
,
desc:
'The description of the milestone'
optional
:due_date
,
type:
String
,
desc:
'The due date of the milestone. The ISO 8601 date format (%Y-%m-%d)'
optional
:start_date
,
type:
String
,
desc:
'The start date of the milestone. The ISO 8601 date format (%Y-%m-%d)'
end
params
:list_params
do
optional
:state
,
type:
String
,
values:
%w[active closed all]
,
default:
'all'
,
desc:
'Return "active", "closed", or "all" milestones'
optional
:iids
,
type:
Array
[
Integer
],
desc:
'The IIDs of the milestones'
optional
:search
,
type:
String
,
desc:
'The search criteria for the title or description of the milestone'
use
:pagination
end
params
:update_params
do
requires
:milestone_id
,
type:
Integer
,
desc:
'The milestone ID number'
optional
:title
,
type:
String
,
desc:
'The title of the milestone'
optional
:state_event
,
type:
String
,
values:
%w[close activate]
,
desc:
'The state event of the milestone '
use
:optional_params
at_least_one_of
:title
,
:description
,
:due_date
,
:state_event
end
def
list_milestones_for
(
parent
)
milestones
=
parent
.
milestones
milestones
=
Milestone
.
filter_by_state
(
milestones
,
params
[
:state
])
milestones
=
filter_by_iid
(
milestones
,
params
[
:iids
])
if
params
[
:iids
].
present?
milestones
=
filter_by_search
(
milestones
,
params
[
:search
])
if
params
[
:search
]
present
paginate
(
milestones
),
with:
Entities
::
Milestone
end
def
get_milestone_for
(
parent
)
milestone
=
parent
.
milestones
.
find
(
params
[
:milestone_id
])
present
milestone
,
with:
Entities
::
Milestone
end
def
create_milestone_for
(
parent
)
milestone
=
::
Milestones
::
CreateService
.
new
(
parent
,
current_user
,
declared_params
).
execute
if
milestone
.
valid?
present
milestone
,
with:
Entities
::
Milestone
else
render_api_error!
(
"Failed to create milestone
#{
milestone
.
errors
.
messages
}
"
,
400
)
end
end
def
update_milestone_for
(
parent
)
milestone
=
parent
.
milestones
.
find
(
params
.
delete
(
:milestone_id
))
milestone_params
=
declared_params
(
include_missing:
false
)
milestone
=
::
Milestones
::
UpdateService
.
new
(
parent
,
current_user
,
milestone_params
).
execute
(
milestone
)
if
milestone
.
valid?
present
milestone
,
with:
Entities
::
Milestone
else
render_api_error!
(
"Failed to update milestone
#{
milestone
.
errors
.
messages
}
"
,
400
)
end
end
def
milestone_issuables_for
(
parent
,
type
)
milestone
=
parent
.
milestones
.
find
(
params
[
:milestone_id
])
finder_klass
,
entity
=
get_finder_and_entity
(
type
)
params
=
build_finder_params
(
milestone
,
parent
)
issuables
=
finder_klass
.
new
(
current_user
,
params
).
execute
present
paginate
(
issuables
),
with:
entity
,
current_user:
current_user
end
def
build_finder_params
(
milestone
,
parent
)
finder_params
=
{
milestone_title:
milestone
.
title
,
sort:
'label_priority'
}
if
parent
.
is_a?
(
Group
)
finder_params
.
merge
(
group_id:
parent
.
id
)
else
finder_params
.
merge
(
project_id:
parent
.
id
)
end
end
def
get_finder_and_entity
(
type
)
if
type
==
:issue
[
IssuesFinder
,
Entities
::
IssueBasic
]
else
[
MergeRequestsFinder
,
Entities
::
MergeRequestBasic
]
end
end
end
end
end
end
lib/api/milestones.rb
→
lib/api/
project_
milestones.rb
View file @
c5c9dce2
module
API
class
Milestones
<
Grape
::
API
class
Project
Milestones
<
Grape
::
API
include
PaginationParams
include
MilestoneResponses
before
{
authenticate!
}
helpers
do
def
filter_milestones_state
(
milestones
,
state
)
case
state
when
'active'
then
milestones
.
active
when
'closed'
then
milestones
.
closed
else
milestones
end
end
params
:optional_params
do
optional
:description
,
type:
String
,
desc:
'The description of the milestone'
optional
:due_date
,
type:
String
,
desc:
'The due date of the milestone. The ISO 8601 date format (%Y-%m-%d)'
optional
:start_date
,
type:
String
,
desc:
'The start date of the milestone. The ISO 8601 date format (%Y-%m-%d)'
end
before
do
authenticate!
end
params
do
...
...
@@ -28,21 +15,12 @@ module API
success
Entities
::
Milestone
end
params
do
optional
:state
,
type:
String
,
values:
%w[active closed all]
,
default:
'all'
,
desc:
'Return "active", "closed", or "all" milestones'
optional
:iids
,
type:
Array
[
Integer
],
desc:
'The IIDs of the milestones'
optional
:search
,
type:
String
,
desc:
'The search criteria for the title or description of the milestone'
use
:pagination
use
:list_params
end
get
":id/milestones"
do
authorize!
:read_milestone
,
user_project
milestones
=
user_project
.
milestones
milestones
=
filter_milestones_state
(
milestones
,
params
[
:state
])
milestones
=
filter_by_iid
(
milestones
,
params
[
:iids
])
if
params
[
:iids
].
present?
milestones
=
filter_by_search
(
milestones
,
params
[
:search
])
if
params
[
:search
]
present
paginate
(
milestones
),
with:
Entities
::
Milestone
list_milestones_for
(
user_project
)
end
desc
'Get a single project milestone'
do
...
...
@@ -54,8 +32,7 @@ module API
get
":id/milestones/:milestone_id"
do
authorize!
:read_milestone
,
user_project
milestone
=
user_project
.
milestones
.
find
(
params
[
:milestone_id
])
present
milestone
,
with:
Entities
::
Milestone
get_milestone_for
(
user_project
)
end
desc
'Create a new project milestone'
do
...
...
@@ -68,38 +45,19 @@ module API
post
":id/milestones"
do
authorize!
:admin_milestone
,
user_project
milestone
=
::
Milestones
::
CreateService
.
new
(
user_project
,
current_user
,
declared_params
).
execute
if
milestone
.
valid?
present
milestone
,
with:
Entities
::
Milestone
else
render_api_error!
(
"Failed to create milestone
#{
milestone
.
errors
.
messages
}
"
,
400
)
end
create_milestone_for
(
user_project
)
end
desc
'Update an existing project milestone'
do
success
Entities
::
Milestone
end
params
do
requires
:milestone_id
,
type:
Integer
,
desc:
'The ID of a project milestone'
optional
:title
,
type:
String
,
desc:
'The title of the milestone'
optional
:state_event
,
type:
String
,
values:
%w[close activate]
,
desc:
'The state event of the milestone '
use
:optional_params
at_least_one_of
:title
,
:description
,
:due_date
,
:state_event
use
:update_params
end
put
":id/milestones/:milestone_id"
do
authorize!
:admin_milestone
,
user_project
milestone
=
user_project
.
milestones
.
find
(
params
.
delete
(
:milestone_id
))
milestone_params
=
declared_params
(
include_missing:
false
)
milestone
=
::
Milestones
::
UpdateService
.
new
(
user_project
,
current_user
,
milestone_params
).
execute
(
milestone
)
if
milestone
.
valid?
present
milestone
,
with:
Entities
::
Milestone
else
render_api_error!
(
"Failed to update milestone
#{
milestone
.
errors
.
messages
}
"
,
400
)
end
update_milestone_for
(
user_project
)
end
desc
'Get all issues for a single project milestone'
do
...
...
@@ -112,16 +70,7 @@ module API
get
":id/milestones/:milestone_id/issues"
do
authorize!
:read_milestone
,
user_project
milestone
=
user_project
.
milestones
.
find
(
params
[
:milestone_id
])
finder_params
=
{
project_id:
user_project
.
id
,
milestone_title:
milestone
.
title
,
sort:
'label_priority'
}
issues
=
IssuesFinder
.
new
(
current_user
,
finder_params
).
execute
present
paginate
(
issues
),
with:
Entities
::
IssueBasic
,
current_user:
current_user
,
project:
user_project
milestone_issuables_for
(
user_project
,
:issue
)
end
desc
'Get all merge requests for a single project milestone'
do
...
...
@@ -135,19 +84,7 @@ module API
get
':id/milestones/:milestone_id/merge_requests'
do
authorize!
:read_milestone
,
user_project
milestone
=
user_project
.
milestones
.
find
(
params
[
:milestone_id
])
finder_params
=
{
project_id:
user_project
.
id
,
milestone_title:
milestone
.
title
,
sort:
'label_priority'
}
merge_requests
=
MergeRequestsFinder
.
new
(
current_user
,
finder_params
).
execute
present
paginate
(
merge_requests
),
with:
Entities
::
MergeRequestBasic
,
current_user:
current_user
,
project:
user_project
milestone_issuables_for
(
user_project
,
:merge_request
)
end
end
end
...
...
spec/requests/api/group_milestones_spec.rb
0 → 100644
View file @
c5c9dce2
require
'spec_helper'
describe
API
::
GroupMilestones
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:group
)
{
create
(
:group
,
:private
)
}
let
(
:project
)
{
create
(
:empty_project
,
namespace:
group
)
}
let!
(
:group_member
)
{
create
(
:group_member
,
group:
group
,
user:
user
)
}
let!
(
:closed_milestone
)
{
create
(
:closed_milestone
,
group:
group
,
title:
'version1'
,
description:
'closed milestone'
)
}
let!
(
:milestone
)
{
create
(
:milestone
,
group:
group
,
title:
'version2'
,
description:
'open milestone'
)
}
it_behaves_like
'group and project milestones'
,
"/groups/:id/milestones"
do
let
(
:route
)
{
"/groups/
#{
group
.
id
}
/milestones"
}
end
def
setup_for_group
context_group
.
update
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
)
context_group
.
add_developer
(
user
)
public_project
.
update
(
namespace:
context_group
)
context_group
.
reload
end
end
spec/requests/api/project_milestones_spec.rb
0 → 100644
View file @
c5c9dce2
require
'spec_helper'
describe
API
::
ProjectMilestones
do
let
(
:user
)
{
create
(
:user
)
}
let!
(
:project
)
{
create
(
:empty_project
,
namespace:
user
.
namespace
)
}
let!
(
:closed_milestone
)
{
create
(
:closed_milestone
,
project:
project
,
title:
'version1'
,
description:
'closed milestone'
)
}
let!
(
:milestone
)
{
create
(
:milestone
,
project:
project
,
title:
'version2'
,
description:
'open milestone'
)
}
before
do
project
.
team
<<
[
user
,
:developer
]
end
it_behaves_like
'group and project milestones'
,
"/projects/:id/milestones"
do
let
(
:route
)
{
"/projects/
#{
project
.
id
}
/milestones"
}
end
describe
'PUT /projects/:id/milestones/:milestone_id to test observer on close'
do
it
'creates an activity event when an milestone is closed'
do
expect
(
Event
).
to
receive
(
:create
)
put
api
(
"/projects/
#{
project
.
id
}
/milestones/
#{
milestone
.
id
}
"
,
user
),
state_event:
'close'
end
end
end
spec/
requests/api/milestones_spec
.rb
→
spec/
support/api/milestones_shared_examples
.rb
View file @
c5c9dce2
This diff is collapsed.
Click to expand it.
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