Update go-github dependency.

This commit is contained in:
Brendan Burns 2015-08-03 12:54:12 -07:00
parent 2e68002f31
commit 39735939e9
23 changed files with 429 additions and 85 deletions

2
Godeps/Godeps.json generated
View File

@ -340,7 +340,7 @@
},
{
"ImportPath": "github.com/google/go-github/github",
"Rev": "930e6fdb8dc2b11458fdeb55b3cd68e5370a1a28"
"Rev": "800345634beceb9b499012319eb8bf97fd97a298"
},
{
"ImportPath": "github.com/google/go-querystring/query",

View File

@ -7,6 +7,12 @@ package github
import "fmt"
// StarredRepository is returned by ListStarred.
type StarredRepository struct {
StarredAt *Timestamp `json:"starred_at,omitempty"`
Repository *Repository `json:"repo,omitempty"`
}
// ListStargazers lists people who have starred the specified repo.
//
// GitHub API Docs: https://developer.github.com/v3/activity/starring/#list-stargazers
@ -49,7 +55,7 @@ type ActivityListStarredOptions struct {
// will list the starred repositories for the authenticated user.
//
// GitHub API docs: http://developer.github.com/v3/activity/starring/#list-repositories-being-starred
func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptions) ([]Repository, *Response, error) {
func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptions) ([]StarredRepository, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("users/%v/starred", user)
@ -66,7 +72,10 @@ func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptio
return nil, nil, err
}
repos := new([]Repository)
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeStarringPreview)
repos := new([]StarredRepository)
resp, err := s.client.Do(req, repos)
if err != nil {
return nil, resp, err

View File

@ -10,6 +10,7 @@ import (
"net/http"
"reflect"
"testing"
"time"
)
func TestActivityService_ListStargazers(t *testing.T) {
@ -42,7 +43,8 @@ func TestActivityService_ListStarred_authenticatedUser(t *testing.T) {
mux.HandleFunc("/user/starred", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
testHeader(t, r, "Accept", mediaTypeStarringPreview)
fmt.Fprint(w, `[{"starred_at":"2002-02-10T15:30:00Z","repo":{"id":1}}]`)
})
repos, _, err := client.Activity.ListStarred("", nil)
@ -50,7 +52,7 @@ func TestActivityService_ListStarred_authenticatedUser(t *testing.T) {
t.Errorf("Activity.ListStarred returned error: %v", err)
}
want := []Repository{{ID: Int(1)}}
want := []StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int(1)}}}
if !reflect.DeepEqual(repos, want) {
t.Errorf("Activity.ListStarred returned %+v, want %+v", repos, want)
}
@ -62,12 +64,13 @@ func TestActivityService_ListStarred_specifiedUser(t *testing.T) {
mux.HandleFunc("/users/u/starred", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeStarringPreview)
testFormValues(t, r, values{
"sort": "created",
"direction": "asc",
"page": "2",
})
fmt.Fprint(w, `[{"id":2}]`)
fmt.Fprint(w, `[{"starred_at":"2002-02-10T15:30:00Z","repo":{"id":2}}]`)
})
opt := &ActivityListStarredOptions{"created", "asc", ListOptions{Page: 2}}
@ -76,7 +79,7 @@ func TestActivityService_ListStarred_specifiedUser(t *testing.T) {
t.Errorf("Activity.ListStarred returned error: %v", err)
}
want := []Repository{{ID: Int(2)}}
want := []StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int(2)}}}
if !reflect.DeepEqual(repos, want) {
t.Errorf("Activity.ListStarred returned %+v, want %+v", repos, want)
}

View File

@ -35,21 +35,10 @@ use it with the oauth2 library using:
import "golang.org/x/oauth2"
// tokenSource is an oauth2.TokenSource which returns a static access token
type tokenSource struct {
token *oauth2.Token
}
// Token implements the oauth2.TokenSource interface
func (t *tokenSource) Token() (*oauth2.Token, error){
return t.token, nil
}
func main() {
ts := &tokenSource{
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: "... your access token ..."},
}
)
tc := oauth2.NewClient(oauth2.NoContext, ts)
client := github.NewClient(tc)

View File

@ -157,7 +157,7 @@ func (s *GistsService) Get(id string) (*Gist, *Response, error) {
return gist, resp, err
}
// Get a specific revision of a gist.
// GetRevision gets a specific revision of a gist.
//
// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist
func (s *GistsService) GetRevision(id, sha string) (*Gist, *Response, error) {

View File

@ -39,6 +39,13 @@ const (
// https://developer.github.com/changes/2015-03-09-licenses-api/
mediaTypeLicensesPreview = "application/vnd.github.drax-preview+json"
// https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/
mediaTypeStarringPreview = "application/vnd.github.v3.star+json"
// https://developer.github.com/changes/2015-06-24-api-enhancements-for-working-with-organization-permissions/
mediaTypeOrgPermissionPreview = "application/vnd.github.ironman-preview+json"
mediaTypeOrgPermissionRepoPreview = "application/vnd.github.ironman-preview.repository+json"
)
// A Client manages communication with the GitHub API.
@ -218,7 +225,7 @@ type Response struct {
Rate
}
// newResponse creats a new Response for the provided http.Response.
// newResponse creates a new Response for the provided http.Response.
func newResponse(r *http.Response) *Response {
response := &Response{Response: r}
response.populatePageValues()

View File

@ -72,7 +72,7 @@ type IssueListOptions struct {
Labels []string `url:"labels,comma,omitempty"`
// Sort specifies how to sort issues. Possible values are: created, updated,
// and comments. Default value is "assigned".
// and comments. Default value is "created".
Sort string `url:"sort,omitempty"`
// Direction in which to sort issues. Possible values are: asc, desc.
@ -166,7 +166,7 @@ type IssueListByRepoOptions struct {
Labels []string `url:"labels,omitempty,comma"`
// Sort specifies how to sort issues. Possible values are: created, updated,
// and comments. Default value is "assigned".
// and comments. Default value is "created".
Sort string `url:"sort,omitempty"`
// Direction in which to sort issues. Possible values are: asc, desc.

View File

@ -49,6 +49,9 @@ type IssueEvent struct {
//
// head_ref_restored
// The pull requests branch was restored.
//
// labeled
// A label was added.
Event *string `json:"event,omitempty"`
// The SHA of the commit that referenced this commit, if applicable.
@ -56,6 +59,9 @@ type IssueEvent struct {
CreatedAt *time.Time `json:"created_at,omitempty"`
Issue *Issue `json:"issue,omitempty"`
// Only present on 'labeled' events
Label *Label `json:"label,omitempty"`
}
// ListIssueEvents lists events for the specified issue.

View File

@ -21,7 +21,7 @@ type License struct {
Name *string `json:"name,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url",omitempty`
HTMLURL *string `json:"html_url,omitempty"`
Featured *bool `json:"featured,omitempty"`
Description *string `json:"description,omitempty"`
Category *string `json:"category,omitempty"`
@ -57,7 +57,7 @@ func (s *LicensesService) List() ([]License, *Response, error) {
return *licenses, resp, err
}
// Fetch extended metadata for one license.
// Get extended metadata for one license.
//
// GitHub API docs: https://developer.github.com/v3/licenses/#get-an-individual-license
func (s *LicensesService) Get(licenseName string) (*License, *Response, error) {

View File

@ -27,7 +27,7 @@ func TestLicensesService_List(t *testing.T) {
t.Errorf("Licenses.List returned error: %v", err)
}
want := []License{License{
want := []License{{
Key: String("mit"),
Name: String("MIT"),
URL: String("https://api.github.com/licenses/mit"),

View File

@ -98,6 +98,10 @@ type APIMeta struct {
// username and password, sudo mode, and two-factor authentication are
// not supported on these servers.)
VerifiablePasswordAuthentication *bool `json:"verifiable_password_authentication,omitempty"`
// An array of IP addresses in CIDR format specifying the addresses
// which serve GitHub Pages websites.
Pages []string `json:"pages,omitempty"`
}
// APIMeta returns information about GitHub.com, the service. Or, if you access

View File

@ -72,7 +72,7 @@ func TestAPIMeta(t *testing.T) {
mux.HandleFunc("/meta", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"hooks":["h"], "git":["g"], "verifiable_password_authentication": true}`)
fmt.Fprint(w, `{"hooks":["h"], "git":["g"], "pages":["p"], "verifiable_password_authentication": true}`)
})
meta, _, err := client.APIMeta()
@ -83,6 +83,7 @@ func TestAPIMeta(t *testing.T) {
want := &APIMeta{
Hooks: []string{"h"},
Git: []string{"g"},
Pages: []string{"p"},
VerifiablePasswordAuthentication: Bool(true),
}
if !reflect.DeepEqual(want, meta) {

View File

@ -15,7 +15,16 @@ type Membership struct {
// Possible values are: "active", "pending"
State *string `json:"state,omitempty"`
// TODO(willnorris): add docs
// Role identifies the user's role within the organization or team.
// Possible values for organization membership:
// member - non-owner organization member
// admin - organization owner
//
// Possible values for team membership are:
// member - a normal member of the team
// maintainer - a team maintainer. Able to add/remove other team
// members, promote other team members to team
// maintainer, and edit the teams name and description
Role *string `json:"role,omitempty"`
// For organization membership, the API URL of the organization.
@ -43,6 +52,15 @@ type ListMembersOptions struct {
// 2fa_disabled, all. Default is "all".
Filter string `url:"filter,omitempty"`
// Role filters memebers returned by their role in the organization.
// Possible values are:
// all - all members of the organization, regardless of role
// admin - organization owners
// member - non-organization members
//
// Default is "all".
Role string `url:"role,omitempty"`
ListOptions
}
@ -68,6 +86,10 @@ func (s *OrganizationsService) ListMembers(org string, opt *ListMembersOptions)
return nil, nil, err
}
if opt != nil && opt.Role != "" {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
members := new([]User)
resp, err := s.client.Do(req, members)
if err != nil {
@ -120,7 +142,8 @@ func (s *OrganizationsService) RemoveMember(org, user string) (*Response, error)
return s.client.Do(req, nil)
}
// PublicizeMembership publicizes a user's membership in an organization.
// PublicizeMembership publicizes a user's membership in an organization. (A
// user cannot publicize the membership for another user.)
//
// GitHub API docs: http://developer.github.com/v3/orgs/members/#publicize-a-users-membership
func (s *OrganizationsService) PublicizeMembership(org, user string) (*Response, error) {
@ -180,12 +203,20 @@ func (s *OrganizationsService) ListOrgMemberships(opt *ListOrgMembershipsOptions
return memberships, resp, err
}
// GetOrgMembership gets the membership for the authenticated user for the
// specified organization.
// GetOrgMembership gets the membership for a user in a specified organization.
// Passing an empty string for user will get the membership for the
// authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-organization-membership
// GitHub API docs: https://developer.github.com/v3/orgs/members/#get-your-organization-membership
func (s *OrganizationsService) GetOrgMembership(org string) (*Membership, *Response, error) {
u := fmt.Sprintf("user/memberships/orgs/%v", org)
func (s *OrganizationsService) GetOrgMembership(user, org string) (*Membership, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user)
} else {
u = fmt.Sprintf("user/memberships/orgs/%v", org)
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
@ -200,12 +231,20 @@ func (s *OrganizationsService) GetOrgMembership(org string) (*Membership, *Respo
return membership, resp, err
}
// EditOrgMembership edits the membership for the authenticated user for the
// specified organization.
// EditOrgMembership edits the membership for user in specified organization.
// Passing an empty string for user will edit the membership for the
// authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership
// GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership
func (s *OrganizationsService) EditOrgMembership(org string, membership *Membership) (*Membership, *Response, error) {
u := fmt.Sprintf("user/memberships/orgs/%v", org)
func (s *OrganizationsService) EditOrgMembership(user, org string, membership *Membership) (*Membership, *Response, error) {
var u string
if user != "" {
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user)
} else {
u = fmt.Sprintf("user/memberships/orgs/%v", org)
}
req, err := s.client.NewRequest("PATCH", u, membership)
if err != nil {
return nil, nil, err
@ -219,3 +258,17 @@ func (s *OrganizationsService) EditOrgMembership(org string, membership *Members
return m, resp, err
}
// RemoveOrgMembership removes user from the specified organization. If the
// user has been invited to the organization, this will cancel their invitation.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-organization-membership
func (s *OrganizationsService) RemoveOrgMembership(user, org string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/memberships/%v", org, user)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}

View File

@ -19,8 +19,10 @@ func TestOrganizationsService_ListMembers(t *testing.T) {
mux.HandleFunc("/orgs/o/members", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
testFormValues(t, r, values{
"filter": "2fa_disabled",
"role": "admin",
"page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
@ -29,6 +31,7 @@ func TestOrganizationsService_ListMembers(t *testing.T) {
opt := &ListMembersOptions{
PublicOnly: false,
Filter: "2fa_disabled",
Role: "admin",
ListOptions: ListOptions{Page: 2},
}
members, _, err := client.Organizations.ListMembers("o", opt)
@ -239,7 +242,7 @@ func TestOrganizationsService_ListOrgMemberships(t *testing.T) {
}
}
func TestOrganizationsService_GetOrgMembership(t *testing.T) {
func TestOrganizationsService_GetOrgMembership_AuthenticatedUser(t *testing.T) {
setup()
defer teardown()
@ -248,7 +251,7 @@ func TestOrganizationsService_GetOrgMembership(t *testing.T) {
fmt.Fprint(w, `{"url":"u"}`)
})
membership, _, err := client.Organizations.GetOrgMembership("o")
membership, _, err := client.Organizations.GetOrgMembership("", "o")
if err != nil {
t.Errorf("Organizations.GetOrgMembership returned error: %v", err)
}
@ -259,7 +262,27 @@ func TestOrganizationsService_GetOrgMembership(t *testing.T) {
}
}
func TestOrganizationsService_EditOrgMembership(t *testing.T) {
func TestOrganizationsService_GetOrgMembership_SpecifiedUser(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"url":"u"}`)
})
membership, _, err := client.Organizations.GetOrgMembership("u", "o")
if err != nil {
t.Errorf("Organizations.GetOrgMembership returned error: %v", err)
}
want := &Membership{URL: String("u")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.GetOrgMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_EditOrgMembership_AuthenticatedUser(t *testing.T) {
setup()
defer teardown()
@ -277,7 +300,7 @@ func TestOrganizationsService_EditOrgMembership(t *testing.T) {
fmt.Fprint(w, `{"url":"u"}`)
})
membership, _, err := client.Organizations.EditOrgMembership("o", input)
membership, _, err := client.Organizations.EditOrgMembership("", "o", input)
if err != nil {
t.Errorf("Organizations.EditOrgMembership returned error: %v", err)
}
@ -287,3 +310,47 @@ func TestOrganizationsService_EditOrgMembership(t *testing.T) {
t.Errorf("Organizations.EditOrgMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_EditOrgMembership_SpecifiedUser(t *testing.T) {
setup()
defer teardown()
input := &Membership{State: String("active")}
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
v := new(Membership)
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, `{"url":"u"}`)
})
membership, _, err := client.Organizations.EditOrgMembership("u", "o", input)
if err != nil {
t.Errorf("Organizations.EditOrgMembership returned error: %v", err)
}
want := &Membership{URL: String("u")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.EditOrgMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_RemoveOrgMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.RemoveOrgMembership("u", "o")
if err != nil {
t.Errorf("Organizations.RemoveOrgMembership returned error: %v", err)
}
}

View File

@ -10,11 +10,25 @@ import "fmt"
// Team represents a team within a GitHub organization. Teams are used to
// manage access to an organization's repositories.
type Team struct {
ID *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
URL *string `json:"url,omitempty"`
Slug *string `json:"slug,omitempty"`
Permission *string `json:"permission,omitempty"`
ID *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
URL *string `json:"url,omitempty"`
Slug *string `json:"slug,omitempty"`
// Permission is deprecated when creating or editing a team in an org
// using the new GitHub permission model. It no longer identifies the
// permission a team has on its repos, but only specifies the default
// permission a repo is initially added with. Avoid confusion by
// specifying a permission value when calling AddTeamRepo.
Permission *string `json:"permission,omitempty"`
// Privacy identifies the level of privacy this team should have.
// Possible values are:
// secret - only visible to organization owners and members of this team
// closed - visible to all members of this organization
// Default is "secret".
Privacy *string `json:"privacy,omitempty"`
MembersCount *int `json:"members_count,omitempty"`
ReposCount *int `json:"repos_count,omitempty"`
Organization *Organization `json:"organization,omitempty"`
@ -77,6 +91,10 @@ func (s *OrganizationsService) CreateTeam(org string, team *Team) (*Team, *Respo
return nil, nil, err
}
if team.Privacy != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
t := new(Team)
resp, err := s.client.Do(req, t)
if err != nil {
@ -96,6 +114,10 @@ func (s *OrganizationsService) EditTeam(id int, team *Team) (*Team, *Response, e
return nil, nil, err
}
if team.Privacy != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
t := new(Team)
resp, err := s.client.Do(req, t)
if err != nil {
@ -118,11 +140,21 @@ func (s *OrganizationsService) DeleteTeam(team int) (*Response, error) {
return s.client.Do(req, nil)
}
// OrganizationListTeamMembersOptions specifies the optional parameters to the
// OrganizationsService.ListTeamMembers method.
type OrganizationListTeamMembersOptions struct {
// Role filters members returned by their role in the team. Possible
// values are "all", "member", "maintainer". Default is "all".
Role string `url:"role,omitempty"`
ListOptions
}
// ListTeamMembers lists all of the users who are members of the specified
// team.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-team-members
func (s *OrganizationsService) ListTeamMembers(team int, opt *ListOptions) ([]User, *Response, error) {
func (s *OrganizationsService) ListTeamMembers(team int, opt *OrganizationListTeamMembersOptions) ([]User, *Response, error) {
u := fmt.Sprintf("teams/%v/members", team)
u, err := addOptions(u, opt)
if err != nil {
@ -134,6 +166,10 @@ func (s *OrganizationsService) ListTeamMembers(team int, opt *ListOptions) ([]Us
return nil, nil, err
}
if opt != nil && opt.Role != "" {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
members := new([]User)
resp, err := s.client.Do(req, members)
if err != nil {
@ -182,19 +218,40 @@ func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]Repo
return *repos, resp, err
}
// IsTeamRepo checks if a team manages the specified repository.
// IsTeamRepo checks if a team manages the specified repository. If the
// repository is managed by team, a Repository is returned which includes the
// permissions team has for that repo.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#get-team-repo
func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) (bool, *Response, error) {
func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) (*Repository, *Response, error) {
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
return nil, nil, err
}
resp, err := s.client.Do(req, nil)
manages, err := parseBoolResponse(err)
return manages, resp, err
req.Header.Set("Accept", mediaTypeOrgPermissionRepoPreview)
repository := new(Repository)
resp, err := s.client.Do(req, repository)
if err != nil {
return nil, resp, err
}
return repository, resp, err
}
// OrganizationAddTeamRepoOptions specifies the optional parameters to the
// OrganizationsService.AddTeamRepo method.
type OrganizationAddTeamRepoOptions struct {
// Permission specifies the permission to grant the team on this repository.
// Possible values are:
// pull - team members can pull, but not push to or administer this repository
// push - team members can pull and push, but not administer this repository
// admin - team members can pull, push and administer this repository
//
// If not specified, the team's permission attribute will be used.
Permission string `json:"permission,omitempty"`
}
// AddTeamRepo adds a repository to be managed by the specified team. The
@ -202,13 +259,17 @@ func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) (
// belongs, or a direct fork of a repository owned by the organization.
//
// GitHub API docs: http://developer.github.com/v3/orgs/teams/#add-team-repo
func (s *OrganizationsService) AddTeamRepo(team int, owner string, repo string) (*Response, error) {
func (s *OrganizationsService) AddTeamRepo(team int, owner string, repo string, opt *OrganizationAddTeamRepoOptions) (*Response, error) {
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo)
req, err := s.client.NewRequest("PUT", u, nil)
req, err := s.client.NewRequest("PUT", u, opt)
if err != nil {
return nil, err
}
if opt != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
return s.client.Do(req, nil)
}
@ -269,6 +330,20 @@ func (s *OrganizationsService) GetTeamMembership(team int, user string) (*Member
return t, resp, err
}
// OrganizationAddTeamMembershipOptions does stuff specifies the optional
// parameters to the OrganizationsService.AddTeamMembership method.
type OrganizationAddTeamMembershipOptions struct {
// Role specifies the role the user should have in the team. Possible
// values are:
// member - a normal member of the team
// maintainer - a team maintainer. Able to add/remove other team
// members, promote other team members to team
// maintainer, and edit the teams name and description
//
// Default value is "member".
Role string `json:"role,omitempty"`
}
// AddTeamMembership adds or invites a user to a team.
//
// In order to add a membership between a user and a team, the authenticated
@ -287,13 +362,17 @@ func (s *OrganizationsService) GetTeamMembership(team int, user string) (*Member
// added as a member of the team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-membership
func (s *OrganizationsService) AddTeamMembership(team int, user string) (*Membership, *Response, error) {
func (s *OrganizationsService) AddTeamMembership(team int, user string, opt *OrganizationAddTeamMembershipOptions) (*Membership, *Response, error) {
u := fmt.Sprintf("teams/%v/memberships/%v", team, user)
req, err := s.client.NewRequest("PUT", u, nil)
req, err := s.client.NewRequest("PUT", u, opt)
if err != nil {
return nil, nil, err
}
if opt != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
t := new(Membership)
resp, err := s.client.Do(req, t)
if err != nil {

View File

@ -64,13 +64,14 @@ func TestOrganizationsService_CreateTeam(t *testing.T) {
setup()
defer teardown()
input := &Team{Name: String("n")}
input := &Team{Name: String("n"), Privacy: String("closed")}
mux.HandleFunc("/orgs/o/teams", func(w http.ResponseWriter, r *http.Request) {
v := new(Team)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@ -98,13 +99,14 @@ func TestOrganizationsService_EditTeam(t *testing.T) {
setup()
defer teardown()
input := &Team{Name: String("n")}
input := &Team{Name: String("n"), Privacy: String("closed")}
mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
v := new(Team)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@ -143,11 +145,12 @@ func TestOrganizationsService_ListTeamMembers(t *testing.T) {
mux.HandleFunc("/teams/1/members", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
testFormValues(t, r, values{"role": "member", "page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 2}
opt := &OrganizationListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}}
members, _, err := client.Organizations.ListTeamMembers(1, opt)
if err != nil {
t.Errorf("Organizations.ListTeamMembers returned error: %v", err)
@ -288,15 +291,18 @@ func TestOrganizationsService_IsTeamRepo_true(t *testing.T) {
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNoContent)
testHeader(t, r, "Accept", mediaTypeOrgPermissionRepoPreview)
fmt.Fprint(w, `{"id":1}`)
})
managed, _, err := client.Organizations.IsTeamRepo(1, "o", "r")
repo, _, err := client.Organizations.IsTeamRepo(1, "o", "r")
if err != nil {
t.Errorf("Organizations.IsTeamRepo returned error: %v", err)
}
if want := true; managed != want {
t.Errorf("Organizations.IsTeamRepo returned %+v, want %+v", managed, want)
want := &Repository{ID: Int(1)}
if !reflect.DeepEqual(repo, want) {
t.Errorf("Organizations.IsTeamRepo returned %+v, want %+v", repo, want)
}
}
@ -309,12 +315,15 @@ func TestOrganizationsService_IsTeamRepo_false(t *testing.T) {
w.WriteHeader(http.StatusNotFound)
})
managed, _, err := client.Organizations.IsTeamRepo(1, "o", "r")
if err != nil {
t.Errorf("Organizations.IsTeamRepo returned error: %v", err)
repo, resp, err := client.Organizations.IsTeamRepo(1, "o", "r")
if err == nil {
t.Errorf("Expected HTTP 404 response")
}
if want := false; managed != want {
t.Errorf("Organizations.IsTeamRepo returned %+v, want %+v", managed, want)
if got, want := resp.Response.StatusCode, http.StatusNotFound; got != want {
t.Errorf("Organizations.IsTeamRepo returned status %d, want %d", got, want)
}
if repo != nil {
t.Errorf("Organizations.IsTeamRepo returned %+v, want nil", repo)
}
}
@ -327,12 +336,15 @@ func TestOrganizationsService_IsTeamRepo_error(t *testing.T) {
http.Error(w, "BadRequest", http.StatusBadRequest)
})
managed, _, err := client.Organizations.IsTeamRepo(1, "o", "r")
repo, resp, err := client.Organizations.IsTeamRepo(1, "o", "r")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
if want := false; managed != want {
t.Errorf("Organizations.IsTeamRepo returned %+v, want %+v", managed, want)
if got, want := resp.Response.StatusCode, http.StatusBadRequest; got != want {
t.Errorf("Organizations.IsTeamRepo returned status %d, want %d", got, want)
}
if repo != nil {
t.Errorf("Organizations.IsTeamRepo returned %+v, want nil", repo)
}
}
@ -345,12 +357,22 @@ func TestOrganizationsService_AddTeamRepo(t *testing.T) {
setup()
defer teardown()
opt := &OrganizationAddTeamRepoOptions{Permission: "admin"}
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
v := new(OrganizationAddTeamRepoOptions)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, opt) {
t.Errorf("Request body = %+v, want %+v", v, opt)
}
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.AddTeamRepo(1, "o", "r")
_, err := client.Organizations.AddTeamRepo(1, "o", "r", opt)
if err != nil {
t.Errorf("Organizations.AddTeamRepo returned error: %v", err)
}
@ -365,14 +387,14 @@ func TestOrganizationsService_AddTeamRepo_noAccess(t *testing.T) {
w.WriteHeader(422)
})
_, err := client.Organizations.AddTeamRepo(1, "o", "r")
_, err := client.Organizations.AddTeamRepo(1, "o", "r", nil)
if err == nil {
t.Errorf("Expcted error to be returned")
}
}
func TestOrganizationsService_AddTeamRepo_invalidOwner(t *testing.T) {
_, err := client.Organizations.AddTeamRepo(1, "%", "r")
_, err := client.Organizations.AddTeamRepo(1, "%", "r", nil)
testURLParseError(t, err)
}
@ -420,12 +442,22 @@ func TestOrganizationsService_AddTeamMembership(t *testing.T) {
setup()
defer teardown()
opt := &OrganizationAddTeamMembershipOptions{Role: "maintainer"}
mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) {
v := new(OrganizationAddTeamMembershipOptions)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, opt) {
t.Errorf("Request body = %+v, want %+v", v, opt)
}
fmt.Fprint(w, `{"url":"u", "state":"pending"}`)
})
membership, _, err := client.Organizations.AddTeamMembership(1, "u")
membership, _, err := client.Organizations.AddTeamMembership(1, "u", opt)
if err != nil {
t.Errorf("Organizations.AddTeamMembership returned error: %v", err)
}

View File

@ -93,7 +93,7 @@ func (s *PullRequestsService) GetComment(owner string, repo string, number int)
// CreateComment creates a new comment on the specified pull request.
//
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#create-a-comment
func (s *PullRequestsService) CreateComment(owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number)
req, err := s.client.NewRequest("POST", u, comment)

View File

@ -22,6 +22,8 @@ func (s *RepositoriesService) ListCollaborators(owner, repo string, opt *ListOpt
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
users := new([]User)
resp, err := s.client.Do(req, users)
if err != nil {
@ -49,15 +51,33 @@ func (s *RepositoriesService) IsCollaborator(owner, repo, user string) (bool, *R
return isCollab, resp, err
}
// RepositoryAddCollaboratorOptions specifies the optional parameters to the
// RepositoriesService.AddCollaborator method.
type RepositoryAddCollaboratorOptions struct {
// Permission specifies the permission to grant the user on this repository.
// Possible values are:
// pull - team members can pull, but not push to or administer this repository
// push - team members can pull and push, but not administer this repository
// admin - team members can pull, push and administer this repository
//
// Default value is "pull". This option is only valid for organization-owned repositories.
Permission string `json:"permission,omitempty"`
}
// AddCollaborator adds the specified Github user as collaborator to the given repo.
//
// GitHub API docs: http://developer.github.com/v3/repos/collaborators/#add-collaborator
func (s *RepositoriesService) AddCollaborator(owner, repo, user string) (*Response, error) {
func (s *RepositoriesService) AddCollaborator(owner, repo, user string, opt *RepositoryAddCollaboratorOptions) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user)
req, err := s.client.NewRequest("PUT", u, nil)
req, err := s.client.NewRequest("PUT", u, opt)
if err != nil {
return nil, err
}
if opt != nil {
req.Header.Set("Accept", mediaTypeOrgPermissionPreview)
}
return s.client.Do(req, nil)
}

View File

@ -6,6 +6,7 @@
package github
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
@ -18,6 +19,7 @@ func TestRepositoriesService_ListCollaborators(t *testing.T) {
mux.HandleFunc("/repos/o/r/collaborators", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
testFormValues(t, r, values{"page": "2"})
fmt.Fprintf(w, `[{"id":1}, {"id":2}]`)
})
@ -86,19 +88,29 @@ func TestRepositoriesService_AddCollaborator(t *testing.T) {
setup()
defer teardown()
opt := &RepositoryAddCollaboratorOptions{Permission: "admin"}
mux.HandleFunc("/repos/o/r/collaborators/u", func(w http.ResponseWriter, r *http.Request) {
v := new(RepositoryAddCollaboratorOptions)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PUT")
testHeader(t, r, "Accept", mediaTypeOrgPermissionPreview)
if !reflect.DeepEqual(v, opt) {
t.Errorf("Request body = %+v, want %+v", v, opt)
}
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Repositories.AddCollaborator("o", "r", "u")
_, err := client.Repositories.AddCollaborator("o", "r", "u", opt)
if err != nil {
t.Errorf("Repositories.AddCollaborator returned error: %v", err)
}
}
func TestRepositoriesService_AddCollaborator_invalidUser(t *testing.T) {
_, err := client.Repositories.AddCollaborator("%", "%", "%")
_, err := client.Repositories.AddCollaborator("%", "%", "%", nil)
testURLParseError(t, err)
}

View File

@ -85,8 +85,27 @@ func (s *RepositoriesService) ListReleases(owner, repo string, opt *ListOptions)
// GitHub API docs: http://developer.github.com/v3/repos/releases/#get-a-single-release
func (s *RepositoriesService) GetRelease(owner, repo string, id int) (*RepositoryRelease, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id)
return s.getSingleRelease(u)
}
req, err := s.client.NewRequest("GET", u, nil)
// GetLatestRelease fetches the latest published release for the repository.
//
// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-the-latest-release
func (s *RepositoriesService) GetLatestRelease(owner, repo string) (*RepositoryRelease, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/releases/latest", owner, repo)
return s.getSingleRelease(u)
}
// GetReleaseByTag fetches a release with the specified tag.
//
// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name
func (s *RepositoriesService) GetReleaseByTag(owner, repo, tag string) (*RepositoryRelease, *Response, error) {
u := fmt.Sprintf("repos/%s/%s/releases/tags/%s", owner, repo, tag)
return s.getSingleRelease(u)
}
func (s *RepositoriesService) getSingleRelease(url string) (*RepositoryRelease, *Response, error) {
req, err := s.client.NewRequest("GET", url, nil)
if err != nil {
return nil, nil, err
}

View File

@ -55,6 +55,46 @@ func TestRepositoriesService_GetRelease(t *testing.T) {
}
}
func TestRepositoriesService_GetLatestRelease(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/releases/latest", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":3}`)
})
release, resp, err := client.Repositories.GetLatestRelease("o", "r")
if err != nil {
t.Errorf("Repositories.GetLatestRelease returned error: %v\n%v", err, resp.Body)
}
want := &RepositoryRelease{ID: Int(3)}
if !reflect.DeepEqual(release, want) {
t.Errorf("Repositories.GetLatestRelease returned %+v, want %+v", release, want)
}
}
func TestRepositoriesService_GetReleaseByTag(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/repos/o/r/releases/tags/foo", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":13}`)
})
release, resp, err := client.Repositories.GetReleaseByTag("o", "r", "foo")
if err != nil {
t.Errorf("Repositories.GetReleaseByTag returned error: %v\n%v", err, resp.Body)
}
want := &RepositoryRelease{ID: Int(13)}
if !reflect.DeepEqual(release, want) {
t.Errorf("Repositories.GetReleaseByTag returned %+v, want %+v", release, want)
}
}
func TestRepositoriesService_CreateRelease(t *testing.T) {
setup()
defer teardown()

View File

@ -45,7 +45,6 @@ func TestRepositoriesService_List_specifiedUser(t *testing.T) {
"direction": "asc",
"page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})

View File

@ -59,6 +59,10 @@ type User struct {
// TextMatches is only populated from search results that request text matches
// See: search.go and https://developer.github.com/v3/search/#text-match-metadata
TextMatches []TextMatch `json:"text_matches,omitempty"`
// Permissions identifies the permissions that a user has on a given
// repository. This is only populated when calling Repositories.ListCollaborators.
Permissions *map[string]bool `json:"permissions,omitempty"`
}
func (u User) String() string {