diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index d38ecff73c7..e1d67106649 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -340,7 +340,7 @@ }, { "ImportPath": "github.com/google/go-github/github", - "Rev": "930e6fdb8dc2b11458fdeb55b3cd68e5370a1a28" + "Rev": "800345634beceb9b499012319eb8bf97fd97a298" }, { "ImportPath": "github.com/google/go-querystring/query", diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go b/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go index 982f24d7170..fac4f41d2cf 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go @@ -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 diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/activity_star_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/activity_star_test.go index ae33b93cffa..eb2c4055e76 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/activity_star_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/activity_star_test.go @@ -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) } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/doc.go b/Godeps/_workspace/src/github.com/google/go-github/github/doc.go index 9e48242d219..b4ac8e640a8 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/doc.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/doc.go @@ -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) diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/gists.go b/Godeps/_workspace/src/github.com/google/go-github/github/gists.go index 14bf5dc50a1..a662d3548ee 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/gists.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/gists.go @@ -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) { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/github.go b/Godeps/_workspace/src/github.com/google/go-github/github/github.go index 034adac8117..737c17cc3b5 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/github.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/github.go @@ -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() diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues.go index 1d51a3df0cd..05f5477f95e 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues.go @@ -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. diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go index 0c720aa152d..79eb8d3dcd9 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go @@ -49,6 +49,9 @@ type IssueEvent struct { // // head_ref_restored // The pull request’s 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. diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go b/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go index d2a5a506691..fb2fb5af2cc 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go @@ -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) { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/licenses_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/licenses_test.go index 72f6633b2bb..dfecfebbb64 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/licenses_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/licenses_test.go @@ -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"), diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/misc.go b/Godeps/_workspace/src/github.com/google/go-github/github/misc.go index d501405b4e5..66e7f5239da 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/misc.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/misc.go @@ -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 diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/misc_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/misc_test.go index 438f28f34ef..8ca58d251b4 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/misc_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/misc_test.go @@ -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) { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go index 64dcfcc3d0a..554cb1d50d4 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go @@ -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 team’s 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) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members_test.go index 493488aa622..973e3aa8baa 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members_test.go @@ -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) + } +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go index dd01a7b22d0..858c5451024 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go @@ -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 team’s 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 { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams_test.go index 1b18b623f01..a258137ade5 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams_test.go @@ -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) } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go b/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go index bfbad9af2d1..35c7241b9a2 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go @@ -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) diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go index 3ad61622a49..61dc4ef2069 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go @@ -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) } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators_test.go index de26ba97055..ee6c4989e6b 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators_test.go @@ -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) } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go index 1400114418e..629b32131d2 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go @@ -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 } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases_test.go index 17c670235fb..21808b7e63b 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases_test.go @@ -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() diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_test.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_test.go index c489fcf4109..3a2c4133290 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_test.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_test.go @@ -45,7 +45,6 @@ func TestRepositoriesService_List_specifiedUser(t *testing.T) { "direction": "asc", "page": "2", }) - fmt.Fprint(w, `[{"id":1}]`) }) diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/users.go b/Godeps/_workspace/src/github.com/google/go-github/github/users.go index bd68ac20209..95cca6b700d 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/users.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/users.go @@ -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 {