Browse Source

add support for multiple issue assignees

Fixes #362.

Change-Id: I39d142b4ef54bf514140a56b5fcbbcfa784f0c7f
Glenn Lewis 10 years ago
parent
commit
0237c55854
5 changed files with 119 additions and 3 deletions
  1. +3
    -0
      github/github.go
  2. +8
    -0
      github/issues.go
  3. +44
    -2
      github/issues_assignees.go
  4. +62
    -1
      github/issues_assignees_test.go
  5. +2
    -0
      github/issues_test.go

+ 3
- 0
github/github.go View File

@ -75,6 +75,9 @@ const (
// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/
mediaTypeGitSigningPreview = "application/vnd.github.cryptographer-preview+json"
// https://developer.github.com/changes/2016-5-27-multiple-assignees/
mediaTypeMultipleAssigneesPreview = "application/vnd.github.cerberus-preview+json"
)
// A Client manages communication with the GitHub API.


+ 8
- 0
github/issues.go View File

@ -37,6 +37,7 @@ type Issue struct {
PullRequestLinks *PullRequestLinks `json:"pull_request,omitempty"`
Repository *Repository `json:"repository,omitempty"`
Reactions *Reactions `json:"reactions,omitempty"`
Assignees []*User `json:"assignees,omitempty"`
// TextMatches is only populated from search results that request text matches
// See: search.go and https://developer.github.com/v3/search/#text-match-metadata
@ -57,6 +58,7 @@ type IssueRequest struct {
Assignee *string `json:"assignee,omitempty"`
State *string `json:"state,omitempty"`
Milestone *int `json:"milestone,omitempty"`
Assignees *[]string `json:"assignees,omitempty"`
}
// IssueListOptions specifies the optional parameters to the IssuesService.List
@ -243,6 +245,9 @@ func (s *IssuesService) Create(owner string, repo string, issue *IssueRequest) (
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview)
i := new(Issue)
resp, err := s.client.Do(req, i)
if err != nil {
@ -262,6 +267,9 @@ func (s *IssuesService) Edit(owner string, repo string, number int, issue *Issue
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview)
i := new(Issue)
resp, err := s.client.Do(req, i)
if err != nil {


+ 44
- 2
github/issues_assignees.go View File

@ -11,7 +11,7 @@ import "fmt"
// which issues may be assigned.
//
// GitHub API docs: http://developer.github.com/v3/issues/assignees/#list-assignees
func (s *IssuesService) ListAssignees(owner string, repo string, opt *ListOptions) ([]User, *Response, error) {
func (s *IssuesService) ListAssignees(owner, repo string, opt *ListOptions) ([]User, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/assignees", owner, repo)
u, err := addOptions(u, opt)
if err != nil {
@ -34,7 +34,7 @@ func (s *IssuesService) ListAssignees(owner string, repo string, opt *ListOption
// IsAssignee checks if a user is an assignee for the specified repository.
//
// GitHub API docs: http://developer.github.com/v3/issues/assignees/#check-assignee
func (s *IssuesService) IsAssignee(owner string, repo string, user string) (bool, *Response, error) {
func (s *IssuesService) IsAssignee(owner, repo, user string) (bool, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/assignees/%v", owner, repo, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
@ -44,3 +44,45 @@ func (s *IssuesService) IsAssignee(owner string, repo string, user string) (bool
assignee, err := parseBoolResponse(err)
return assignee, resp, err
}
// AddAssignees adds the provided GitHub users as assignees to the issue.
//
// GitHub API docs: https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue
func (s *IssuesService) AddAssignees(owner, repo string, number int, assignees []string) (*Issue, *Response, error) {
users := &struct {
Assignees []string `json:"assignees,omitempty"`
}{Assignees: assignees}
u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number)
req, err := s.client.NewRequest("POST", u, users)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview)
issue := &Issue{}
resp, err := s.client.Do(req, issue)
return issue, resp, err
}
// RemoveAssignees removes the provided GitHub users as assignees from the issue.
//
// GitHub API docs: https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue
func (s *IssuesService) RemoveAssignees(owner, repo string, number int, assignees []string) (*Issue, *Response, error) {
users := &struct {
Assignees []string `json:"assignees,omitempty"`
}{Assignees: assignees}
u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number)
req, err := s.client.NewRequest("DELETE", u, users)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview)
issue := &Issue{}
resp, err := s.client.Do(req, issue)
return issue, resp, err
}

+ 62
- 1
github/issues_assignees_test.go View File

@ -6,6 +6,7 @@
package github
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
@ -25,7 +26,7 @@ func TestIssuesService_ListAssignees(t *testing.T) {
opt := &ListOptions{Page: 2}
assignees, _, err := client.Issues.ListAssignees("o", "r", opt)
if err != nil {
t.Errorf("Issues.List returned error: %v", err)
t.Errorf("Issues.ListAssignees returned error: %v", err)
}
want := []User{{ID: Int(1)}}
@ -96,3 +97,63 @@ func TestIssuesService_IsAssignee_invalidOwner(t *testing.T) {
_, _, err := client.Issues.IsAssignee("%", "r", "u")
testURLParseError(t, err)
}
func TestIssuesService_AddAssignees(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/assignees", func(w http.ResponseWriter, r *http.Request) {
var assignees struct {
Assignees []string `json:"assignees,omitempty"`
}
json.NewDecoder(r.Body).Decode(&assignees)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeMultipleAssigneesPreview)
want := []string{"user1", "user2"}
if !reflect.DeepEqual(assignees.Assignees, want) {
t.Errorf("assignees = %+v, want %+v", assignees, want)
}
fmt.Fprint(w, `{"number":1,"assignees":[{"login":"user1"},{"login":"user2"}]}`)
})
got, _, err := client.Issues.AddAssignees("o", "r", 1, []string{"user1", "user2"})
if err != nil {
t.Errorf("Issues.AddAssignees returned error: %v", err)
}
want := &Issue{Number: Int(1), Assignees: []*User{{Login: String("user1")}, {Login: String("user2")}}}
if !reflect.DeepEqual(got, want) {
t.Errorf("Issues.AddAssignees = %+v, want %+v", got, want)
}
}
func TestIssuesService_RemoveAssignees(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/assignees", func(w http.ResponseWriter, r *http.Request) {
var assignees struct {
Assignees []string `json:"assignees,omitempty"`
}
json.NewDecoder(r.Body).Decode(&assignees)
testMethod(t, r, "DELETE")
testHeader(t, r, "Accept", mediaTypeMultipleAssigneesPreview)
want := []string{"user1", "user2"}
if !reflect.DeepEqual(assignees.Assignees, want) {
t.Errorf("assignees = %+v, want %+v", assignees, want)
}
fmt.Fprint(w, `{"number":1,"assignees":[]}`)
})
got, _, err := client.Issues.RemoveAssignees("o", "r", 1, []string{"user1", "user2"})
if err != nil {
t.Errorf("Issues.RemoveAssignees returned error: %v", err)
}
want := &Issue{Number: Int(1), Assignees: []*User{}}
if !reflect.DeepEqual(got, want) {
t.Errorf("Issues.RemoveAssignees = %+v, want %+v", got, want)
}
}

+ 2
- 0
github/issues_test.go View File

@ -189,6 +189,7 @@ func TestIssuesService_Create(t *testing.T) {
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeMultipleAssigneesPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@ -223,6 +224,7 @@ func TestIssuesService_Edit(t *testing.T) {
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", mediaTypeMultipleAssigneesPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}


Loading…
Cancel
Save