| @ -0,0 +1,140 @@ | |||
| // Copyright 2014 The go-github AUTHORS. All rights reserved. | |||
| // | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package github | |||
| import ( | |||
| "fmt" | |||
| "time" | |||
| ) | |||
| // Milestone represents a Github repository milestone. | |||
| type Milestone struct { | |||
| URL *string `json:"url,omitempty"` | |||
| Number *int `json:"number,omitempty"` | |||
| State *string `json:"state,omitempty"` | |||
| Title *string `json:"title,omitempty"` | |||
| Description *string `json:"description,omitempty"` | |||
| Creator *User `json:"creator,omitempty"` | |||
| OpenIssues *int `json:"open_issues,omitempty"` | |||
| ClosedIssues *int `json:"closed_issues,omitempty"` | |||
| CreatedAt *time.Time `json:"created_at,omitempty"` | |||
| UpdatedAt *time.Time `json:"updated_at,omitempty"` | |||
| DueOn *time.Time `json:"due_on,omitempty"` | |||
| } | |||
| func (m Milestone) String() string { | |||
| return Stringify(m) | |||
| } | |||
| // MilestoneListOptions specifies the optional parameters to the | |||
| // IssuesService.ListMilestones method. | |||
| type MilestoneListOptions struct { | |||
| // State filters milestones based on their state. Possible values are: | |||
| // open, closed. Default is "open". | |||
| State string `url:"state,omitempty"` | |||
| // Sort specifies how to sort milestones. Possible values are: due_date, completeness. | |||
| // Default value is "due_date". | |||
| Sort string `url:"sort,omitempty"` | |||
| // Direction in which to sort milestones. Possible values are: asc, desc. | |||
| // Default is "asc". | |||
| Direction string `url:"direction,omitempty"` | |||
| } | |||
| // ListMilestones lists all milestones for a repository. | |||
| // | |||
| // GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository | |||
| func (s *IssuesService) ListMilestones(owner string, repo string, opt *MilestoneListOptions) ([]Milestone, *Response, error) { | |||
| u := fmt.Sprintf("/repos/%v/%v/milestones", owner, repo) | |||
| u, err := addOptions(u, opt) | |||
| if err != nil { | |||
| return nil, nil, err | |||
| } | |||
| req, err := s.client.NewRequest("GET", u, nil) | |||
| if err != nil { | |||
| return nil, nil, err | |||
| } | |||
| milestones := new([]Milestone) | |||
| resp, err := s.client.Do(req, milestones) | |||
| if err != nil { | |||
| return nil, resp, err | |||
| } | |||
| return *milestones, resp, err | |||
| } | |||
| // GetMilestone gets a single milestone. | |||
| // | |||
| // GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone | |||
| func (s *IssuesService) GetMilestone(owner string, repo string, number int) (*Milestone, *Response, error) { | |||
| u := fmt.Sprintf("/repos/%v/%v/milestones/%d", owner, repo, number) | |||
| req, err := s.client.NewRequest("GET", u, nil) | |||
| if err != nil { | |||
| return nil, nil, err | |||
| } | |||
| milestone := new(Milestone) | |||
| resp, err := s.client.Do(req, milestone) | |||
| if err != nil { | |||
| return nil, resp, err | |||
| } | |||
| return milestone, resp, err | |||
| } | |||
| // CreateMilestone creates a new milestone on the specified repository. | |||
| // | |||
| // GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone | |||
| func (s *IssuesService) CreateMilestone(owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) { | |||
| u := fmt.Sprintf("/repos/%v/%v/milestones", owner, repo) | |||
| req, err := s.client.NewRequest("POST", u, milestone) | |||
| if err != nil { | |||
| return nil, nil, err | |||
| } | |||
| m := new(Milestone) | |||
| resp, err := s.client.Do(req, m) | |||
| if err != nil { | |||
| return nil, resp, err | |||
| } | |||
| return m, resp, err | |||
| } | |||
| // EditMilestone edits a milestone. | |||
| // | |||
| // GitHub API docs: https://developer.github.com/v3/issues/milestones/#update-a-milestone | |||
| func (s *IssuesService) EditMilestone(owner string, repo string, number int, milestone *Milestone) (*Milestone, *Response, error) { | |||
| u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) | |||
| req, err := s.client.NewRequest("PATCH", u, milestone) | |||
| if err != nil { | |||
| return nil, nil, err | |||
| } | |||
| m := new(Milestone) | |||
| resp, err := s.client.Do(req, m) | |||
| if err != nil { | |||
| return nil, resp, err | |||
| } | |||
| return m, resp, err | |||
| } | |||
| // DeleteMilestone deletes a milestone. | |||
| // | |||
| // GitHub API docs: https://developer.github.com/v3/issues/milestones/#delete-a-milestone | |||
| func (s *IssuesService) DeleteMilestone(owner string, repo string, number int) (*Response, error) { | |||
| u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) | |||
| req, err := s.client.NewRequest("DELETE", u, nil) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return s.client.Do(req, nil) | |||
| } | |||
| @ -0,0 +1,157 @@ | |||
| // Copyright 2014 The go-github AUTHORS. All rights reserved. | |||
| // | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package github | |||
| import ( | |||
| "encoding/json" | |||
| "fmt" | |||
| "net/http" | |||
| "reflect" | |||
| "testing" | |||
| ) | |||
| func TestIssuesService_ListMilestones(t *testing.T) { | |||
| setup() | |||
| defer teardown() | |||
| mux.HandleFunc("/repos/o/r/milestones", func(w http.ResponseWriter, r *http.Request) { | |||
| testMethod(t, r, "GET") | |||
| testFormValues(t, r, values{ | |||
| "state": "closed", | |||
| "sort": "due_date", | |||
| "direction": "asc", | |||
| }) | |||
| fmt.Fprint(w, `[{"number":1}]`) | |||
| }) | |||
| opt := &MilestoneListOptions{"closed", "due_date", "asc"} | |||
| milestones, _, err := client.Issues.ListMilestones("o", "r", opt) | |||
| if err != nil { | |||
| t.Errorf("IssuesService.ListMilestones returned error: %v", err) | |||
| } | |||
| want := []Milestone{{Number: Int(1)}} | |||
| if !reflect.DeepEqual(milestones, want) { | |||
| t.Errorf("IssuesService.ListMilestones returned %+v, want %+v", milestones, want) | |||
| } | |||
| } | |||
| func TestIssuesService_ListMilestones_invalidOwner(t *testing.T) { | |||
| _, _, err := client.Issues.ListMilestones("%", "r", nil) | |||
| testURLParseError(t, err) | |||
| } | |||
| func TestIssuesService_GetMilestone(t *testing.T) { | |||
| setup() | |||
| defer teardown() | |||
| mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) { | |||
| testMethod(t, r, "GET") | |||
| fmt.Fprint(w, `{"number":1}`) | |||
| }) | |||
| milestone, _, err := client.Issues.GetMilestone("o", "r", 1) | |||
| if err != nil { | |||
| t.Errorf("IssuesService.GetMilestone returned error: %v", err) | |||
| } | |||
| want := &Milestone{Number: Int(1)} | |||
| if !reflect.DeepEqual(milestone, want) { | |||
| t.Errorf("IssuesService.GetMilestone returned %+v, want %+v", milestone, want) | |||
| } | |||
| } | |||
| func TestIssuesService_GetMilestone_invalidOwner(t *testing.T) { | |||
| _, _, err := client.Issues.GetMilestone("%", "r", 1) | |||
| testURLParseError(t, err) | |||
| } | |||
| func TestIssuesService_CreateMilestone(t *testing.T) { | |||
| setup() | |||
| defer teardown() | |||
| input := &Milestone{Title: String("t")} | |||
| mux.HandleFunc("/repos/o/r/milestones", func(w http.ResponseWriter, r *http.Request) { | |||
| v := new(Milestone) | |||
| json.NewDecoder(r.Body).Decode(v) | |||
| testMethod(t, r, "POST") | |||
| if !reflect.DeepEqual(v, input) { | |||
| t.Errorf("Request body = %+v, want %+v", v, input) | |||
| } | |||
| fmt.Fprint(w, `{"number":1}`) | |||
| }) | |||
| milestone, _, err := client.Issues.CreateMilestone("o", "r", input) | |||
| if err != nil { | |||
| t.Errorf("IssuesService.CreateMilestone returned error: %v", err) | |||
| } | |||
| want := &Milestone{Number: Int(1)} | |||
| if !reflect.DeepEqual(milestone, want) { | |||
| t.Errorf("IssuesService.CreateMilestone returned %+v, want %+v", milestone, want) | |||
| } | |||
| } | |||
| func TestIssuesService_CreateMilestone_invalidOwner(t *testing.T) { | |||
| _, _, err := client.Issues.CreateMilestone("%", "r", nil) | |||
| testURLParseError(t, err) | |||
| } | |||
| func TestIssuesService_EditMilestone(t *testing.T) { | |||
| setup() | |||
| defer teardown() | |||
| input := &Milestone{Title: String("t")} | |||
| mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) { | |||
| v := new(Milestone) | |||
| json.NewDecoder(r.Body).Decode(v) | |||
| testMethod(t, r, "PATCH") | |||
| if !reflect.DeepEqual(v, input) { | |||
| t.Errorf("Request body = %+v, want %+v", v, input) | |||
| } | |||
| fmt.Fprint(w, `{"number":1}`) | |||
| }) | |||
| milestone, _, err := client.Issues.EditMilestone("o", "r", 1, input) | |||
| if err != nil { | |||
| t.Errorf("IssuesService.EditMilestone returned error: %v", err) | |||
| } | |||
| want := &Milestone{Number: Int(1)} | |||
| if !reflect.DeepEqual(milestone, want) { | |||
| t.Errorf("IssuesService.EditMilestone returned %+v, want %+v", milestone, want) | |||
| } | |||
| } | |||
| func TestIssuesService_EditMilestone_invalidOwner(t *testing.T) { | |||
| _, _, err := client.Issues.EditMilestone("%", "r", 1, nil) | |||
| testURLParseError(t, err) | |||
| } | |||
| func TestIssuesService_DeleteMilestone(t *testing.T) { | |||
| setup() | |||
| defer teardown() | |||
| mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) { | |||
| testMethod(t, r, "DELETE") | |||
| }) | |||
| _, err := client.Issues.DeleteMilestone("o", "r", 1) | |||
| if err != nil { | |||
| t.Errorf("IssuesService.DeleteMilestone returned error: %v", err) | |||
| } | |||
| } | |||
| func TestIssuesService_DeleteMilestone_invalidOwner(t *testing.T) { | |||
| _, err := client.Issues.DeleteMilestone("%", "r", 1) | |||
| testURLParseError(t, err) | |||
| } | |||