Update go-github library

This commit is contained in:
Luke Kysow
2018-12-12 09:55:17 -06:00
parent e001353ae9
commit 139f05ab49
170 changed files with 14305 additions and 3086 deletions

View File

@@ -7,116 +7,9 @@ package github
import (
"context"
"encoding/json"
"fmt"
"time"
)
// Event represents a GitHub event.
type Event struct {
Type *string `json:"type,omitempty"`
Public *bool `json:"public"`
RawPayload *json.RawMessage `json:"payload,omitempty"`
Repo *Repository `json:"repo,omitempty"`
Actor *User `json:"actor,omitempty"`
Org *Organization `json:"org,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
ID *string `json:"id,omitempty"`
}
func (e Event) String() string {
return Stringify(e)
}
// ParsePayload parses the event payload. For recognized event types,
// a value of the corresponding struct type will be returned.
func (e *Event) ParsePayload() (payload interface{}, err error) {
switch *e.Type {
case "CommitCommentEvent":
payload = &CommitCommentEvent{}
case "CreateEvent":
payload = &CreateEvent{}
case "DeleteEvent":
payload = &DeleteEvent{}
case "DeploymentEvent":
payload = &DeploymentEvent{}
case "DeploymentStatusEvent":
payload = &DeploymentStatusEvent{}
case "ForkEvent":
payload = &ForkEvent{}
case "GollumEvent":
payload = &GollumEvent{}
case "InstallationEvent":
payload = &InstallationEvent{}
case "InstallationRepositoriesEvent":
payload = &InstallationRepositoriesEvent{}
case "IssueCommentEvent":
payload = &IssueCommentEvent{}
case "IssuesEvent":
payload = &IssuesEvent{}
case "LabelEvent":
payload = &LabelEvent{}
case "MemberEvent":
payload = &MemberEvent{}
case "MembershipEvent":
payload = &MembershipEvent{}
case "MilestoneEvent":
payload = &MilestoneEvent{}
case "OrganizationEvent":
payload = &OrganizationEvent{}
case "OrgBlockEvent":
payload = &OrgBlockEvent{}
case "PageBuildEvent":
payload = &PageBuildEvent{}
case "PingEvent":
payload = &PingEvent{}
case "ProjectEvent":
payload = &ProjectEvent{}
case "ProjectCardEvent":
payload = &ProjectCardEvent{}
case "ProjectColumnEvent":
payload = &ProjectColumnEvent{}
case "PublicEvent":
payload = &PublicEvent{}
case "PullRequestEvent":
payload = &PullRequestEvent{}
case "PullRequestReviewEvent":
payload = &PullRequestReviewEvent{}
case "PullRequestReviewCommentEvent":
payload = &PullRequestReviewCommentEvent{}
case "PushEvent":
payload = &PushEvent{}
case "ReleaseEvent":
payload = &ReleaseEvent{}
case "RepositoryEvent":
payload = &RepositoryEvent{}
case "StatusEvent":
payload = &StatusEvent{}
case "TeamEvent":
payload = &TeamEvent{}
case "TeamAddEvent":
payload = &TeamAddEvent{}
case "WatchEvent":
payload = &WatchEvent{}
}
err = json.Unmarshal(*e.RawPayload, &payload)
return payload, err
}
// Payload returns the parsed event payload. For recognized event types,
// a value of the corresponding struct type will be returned.
//
// Deprecated: Use ParsePayload instead, which returns an error
// rather than panics if JSON unmarshaling raw payload fails.
func (e *Event) Payload() (payload interface{}) {
var err error
payload, err = e.ParsePayload()
if err != nil {
panic(err)
}
return payload
}
// ListEvents drinks from the firehose of all public events across GitHub.
//
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events

View File

@@ -15,7 +15,7 @@ import (
)
func TestActivityService_ListEvents(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
@@ -39,7 +39,7 @@ func TestActivityService_ListEvents(t *testing.T) {
}
func TestActivityService_ListRepositoryEvents(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/events", func(w http.ResponseWriter, r *http.Request) {
@@ -63,12 +63,15 @@ func TestActivityService_ListRepositoryEvents(t *testing.T) {
}
func TestActivityService_ListRepositoryEvents_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.ListRepositoryEvents(context.Background(), "%", "%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListIssueEventsForRepository(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/events", func(w http.ResponseWriter, r *http.Request) {
@@ -85,19 +88,22 @@ func TestActivityService_ListIssueEventsForRepository(t *testing.T) {
t.Errorf("Activities.ListIssueEventsForRepository returned error: %v", err)
}
want := []*IssueEvent{{ID: Int(1)}, {ID: Int(2)}}
want := []*IssueEvent{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Activities.ListIssueEventsForRepository returned %+v, want %+v", events, want)
}
}
func TestActivityService_ListIssueEventsForRepository_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.ListIssueEventsForRepository(context.Background(), "%", "%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsForRepoNetwork(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/networks/o/r/events", func(w http.ResponseWriter, r *http.Request) {
@@ -121,12 +127,15 @@ func TestActivityService_ListEventsForRepoNetwork(t *testing.T) {
}
func TestActivityService_ListEventsForRepoNetwork_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.ListEventsForRepoNetwork(context.Background(), "%", "%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsForOrganization(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/events", func(w http.ResponseWriter, r *http.Request) {
@@ -150,12 +159,15 @@ func TestActivityService_ListEventsForOrganization(t *testing.T) {
}
func TestActivityService_ListEventsForOrganization_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.ListEventsForOrganization(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsPerformedByUser_all(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/events", func(w http.ResponseWriter, r *http.Request) {
@@ -179,7 +191,7 @@ func TestActivityService_ListEventsPerformedByUser_all(t *testing.T) {
}
func TestActivityService_ListEventsPerformedByUser_publicOnly(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/events/public", func(w http.ResponseWriter, r *http.Request) {
@@ -199,12 +211,15 @@ func TestActivityService_ListEventsPerformedByUser_publicOnly(t *testing.T) {
}
func TestActivityService_ListEventsPerformedByUser_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.ListEventsPerformedByUser(context.Background(), "%", false, nil)
testURLParseError(t, err)
}
func TestActivityService_ListEventsReceivedByUser_all(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/received_events", func(w http.ResponseWriter, r *http.Request) {
@@ -228,7 +243,7 @@ func TestActivityService_ListEventsReceivedByUser_all(t *testing.T) {
}
func TestActivityService_ListEventsReceivedByUser_publicOnly(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/received_events/public", func(w http.ResponseWriter, r *http.Request) {
@@ -248,12 +263,15 @@ func TestActivityService_ListEventsReceivedByUser_publicOnly(t *testing.T) {
}
func TestActivityService_ListEventsReceivedByUser_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.ListEventsReceivedByUser(context.Background(), "%", false, nil)
testURLParseError(t, err)
}
func TestActivityService_ListUserEventsForOrganization(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/events/orgs/o", func(w http.ResponseWriter, r *http.Request) {
@@ -283,7 +301,7 @@ func TestActivityService_EventParsePayload_typed(t *testing.T) {
t.Fatalf("Unmarshal Event returned error: %v", err)
}
want := &PushEvent{PushID: Int(1)}
want := &PushEvent{PushID: Int64(1)}
got, err := event.ParsePayload()
if err != nil {
t.Fatalf("ParsePayload returned unexpected error: %v", err)
@@ -320,7 +338,7 @@ func TestActivityService_EventParsePayload_installation(t *testing.T) {
t.Fatalf("Unmarshal Event returned error: %v", err)
}
want := &PullRequestEvent{Installation: &Installation{ID: Int(1)}}
want := &PullRequestEvent{Installation: &Installation{ID: Int64(1)}}
got, err := event.ParsePayload()
if err != nil {
t.Fatalf("ParsePayload returned unexpected error: %v", err)

View File

@@ -16,7 +16,7 @@ import (
)
func TestActivityService_ListNotification(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) {
@@ -34,8 +34,8 @@ func TestActivityService_ListNotification(t *testing.T) {
opt := &NotificationListOptions{
All: true,
Participating: true,
Since: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC),
Before: time.Date(2007, 03, 04, 15, 04, 05, 0, time.UTC),
Since: time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC),
Before: time.Date(2007, time.March, 04, 15, 04, 05, 0, time.UTC),
}
notifications, _, err := client.Activity.ListNotifications(context.Background(), opt)
if err != nil {
@@ -49,7 +49,7 @@ func TestActivityService_ListNotification(t *testing.T) {
}
func TestActivityService_ListRepositoryNotification(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/notifications", func(w http.ResponseWriter, r *http.Request) {
@@ -69,7 +69,7 @@ func TestActivityService_ListRepositoryNotification(t *testing.T) {
}
func TestActivityService_MarkNotificationsRead(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/notifications", func(w http.ResponseWriter, r *http.Request) {
@@ -80,14 +80,14 @@ func TestActivityService_MarkNotificationsRead(t *testing.T) {
w.WriteHeader(http.StatusResetContent)
})
_, err := client.Activity.MarkNotificationsRead(context.Background(), time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))
_, err := client.Activity.MarkNotificationsRead(context.Background(), time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC))
if err != nil {
t.Errorf("Activity.MarkNotificationsRead returned error: %v", err)
}
}
func TestActivityService_MarkRepositoryNotificationsRead(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/notifications", func(w http.ResponseWriter, r *http.Request) {
@@ -98,14 +98,14 @@ func TestActivityService_MarkRepositoryNotificationsRead(t *testing.T) {
w.WriteHeader(http.StatusResetContent)
})
_, err := client.Activity.MarkRepositoryNotificationsRead(context.Background(), "o", "r", time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))
_, err := client.Activity.MarkRepositoryNotificationsRead(context.Background(), "o", "r", time.Date(2006, time.January, 02, 15, 04, 05, 0, time.UTC))
if err != nil {
t.Errorf("Activity.MarkRepositoryNotificationsRead returned error: %v", err)
}
}
func TestActivityService_GetThread(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1", func(w http.ResponseWriter, r *http.Request) {
@@ -125,7 +125,7 @@ func TestActivityService_GetThread(t *testing.T) {
}
func TestActivityService_MarkThreadRead(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1", func(w http.ResponseWriter, r *http.Request) {
@@ -140,7 +140,7 @@ func TestActivityService_MarkThreadRead(t *testing.T) {
}
func TestActivityService_GetThreadSubscription(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1/subscription", func(w http.ResponseWriter, r *http.Request) {
@@ -160,7 +160,7 @@ func TestActivityService_GetThreadSubscription(t *testing.T) {
}
func TestActivityService_SetThreadSubscription(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Subscription{Subscribed: Bool(true)}
@@ -189,7 +189,7 @@ func TestActivityService_SetThreadSubscription(t *testing.T) {
}
func TestActivityService_DeleteThreadSubscription(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/notifications/threads/1/subscription", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -8,6 +8,7 @@ package github
import (
"context"
"fmt"
"strings"
)
// StarredRepository is returned by ListStarred.
@@ -84,8 +85,9 @@ func (s *ActivityService) ListStarred(ctx context.Context, user string, opt *Act
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeStarringPreview)
// TODO: remove custom Accept header when APIs fully launch
acceptHeaders := []string{mediaTypeStarringPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var repos []*StarredRepository
resp, err := s.client.Do(ctx, req, &repos)

View File

@@ -10,12 +10,13 @@ import (
"fmt"
"net/http"
"reflect"
"strings"
"testing"
"time"
)
func TestActivityService_ListStargazers(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/stargazers", func(w http.ResponseWriter, r *http.Request) {
@@ -33,19 +34,19 @@ func TestActivityService_ListStargazers(t *testing.T) {
t.Errorf("Activity.ListStargazers returned error: %v", err)
}
want := []*Stargazer{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, User: &User{ID: Int(1)}}}
want := []*Stargazer{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, User: &User{ID: Int64(1)}}}
if !reflect.DeepEqual(stargazers, want) {
t.Errorf("Activity.ListStargazers returned %+v, want %+v", stargazers, want)
}
}
func TestActivityService_ListStarred_authenticatedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/starred", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeStarringPreview)
testHeader(t, r, "Accept", strings.Join([]string{mediaTypeStarringPreview, mediaTypeTopicsPreview}, ", "))
fmt.Fprint(w, `[{"starred_at":"2002-02-10T15:30:00Z","repo":{"id":1}}]`)
})
@@ -54,19 +55,19 @@ func TestActivityService_ListStarred_authenticatedUser(t *testing.T) {
t.Errorf("Activity.ListStarred returned error: %v", err)
}
want := []*StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int(1)}}}
want := []*StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int64(1)}}}
if !reflect.DeepEqual(repos, want) {
t.Errorf("Activity.ListStarred returned %+v, want %+v", repos, want)
}
}
func TestActivityService_ListStarred_specifiedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/starred", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeStarringPreview)
testHeader(t, r, "Accept", strings.Join([]string{mediaTypeStarringPreview, mediaTypeTopicsPreview}, ", "))
testFormValues(t, r, values{
"sort": "created",
"direction": "asc",
@@ -81,19 +82,22 @@ func TestActivityService_ListStarred_specifiedUser(t *testing.T) {
t.Errorf("Activity.ListStarred returned error: %v", err)
}
want := []*StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int(2)}}}
want := []*StarredRepository{{StarredAt: &Timestamp{time.Date(2002, time.February, 10, 15, 30, 0, 0, time.UTC)}, Repository: &Repository{ID: Int64(2)}}}
if !reflect.DeepEqual(repos, want) {
t.Errorf("Activity.ListStarred returned %+v, want %+v", repos, want)
}
}
func TestActivityService_ListStarred_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.ListStarred(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestActivityService_IsStarred_hasStar(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
@@ -111,7 +115,7 @@ func TestActivityService_IsStarred_hasStar(t *testing.T) {
}
func TestActivityService_IsStarred_noStar(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
@@ -129,12 +133,15 @@ func TestActivityService_IsStarred_noStar(t *testing.T) {
}
func TestActivityService_IsStarred_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Activity.IsStarred(context.Background(), "%", "%")
testURLParseError(t, err)
}
func TestActivityService_Star(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
@@ -148,12 +155,15 @@ func TestActivityService_Star(t *testing.T) {
}
func TestActivityService_Star_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Activity.Star(context.Background(), "%", "%")
testURLParseError(t, err)
}
func TestActivityService_Unstar(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/starred/o/r", func(w http.ResponseWriter, r *http.Request) {
@@ -167,6 +177,9 @@ func TestActivityService_Unstar(t *testing.T) {
}
func TestActivityService_Unstar_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Activity.Unstar(context.Background(), "%", "%")
testURLParseError(t, err)
}

View File

@@ -13,7 +13,7 @@ import (
)
func TestActivityService_List(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/feeds", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -15,7 +15,7 @@ import (
)
func TestActivityService_ListWatchers(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscribers", func(w http.ResponseWriter, r *http.Request) {
@@ -32,14 +32,14 @@ func TestActivityService_ListWatchers(t *testing.T) {
t.Errorf("Activity.ListWatchers returned error: %v", err)
}
want := []*User{{ID: Int(1)}}
want := []*User{{ID: Int64(1)}}
if !reflect.DeepEqual(watchers, want) {
t.Errorf("Activity.ListWatchers returned %+v, want %+v", watchers, want)
}
}
func TestActivityService_ListWatched_authenticatedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/subscriptions", func(w http.ResponseWriter, r *http.Request) {
@@ -55,14 +55,14 @@ func TestActivityService_ListWatched_authenticatedUser(t *testing.T) {
t.Errorf("Activity.ListWatched returned error: %v", err)
}
want := []*Repository{{ID: Int(1)}}
want := []*Repository{{ID: Int64(1)}}
if !reflect.DeepEqual(watched, want) {
t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
}
}
func TestActivityService_ListWatched_specifiedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/subscriptions", func(w http.ResponseWriter, r *http.Request) {
@@ -78,14 +78,14 @@ func TestActivityService_ListWatched_specifiedUser(t *testing.T) {
t.Errorf("Activity.ListWatched returned error: %v", err)
}
want := []*Repository{{ID: Int(1)}}
want := []*Repository{{ID: Int64(1)}}
if !reflect.DeepEqual(watched, want) {
t.Errorf("Activity.ListWatched returned %+v, want %+v", watched, want)
}
}
func TestActivityService_GetRepositorySubscription_true(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
@@ -105,7 +105,7 @@ func TestActivityService_GetRepositorySubscription_true(t *testing.T) {
}
func TestActivityService_GetRepositorySubscription_false(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
@@ -125,7 +125,7 @@ func TestActivityService_GetRepositorySubscription_false(t *testing.T) {
}
func TestActivityService_GetRepositorySubscription_error(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {
@@ -140,7 +140,7 @@ func TestActivityService_GetRepositorySubscription_error(t *testing.T) {
}
func TestActivityService_SetRepositorySubscription(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Subscription{Subscribed: Bool(true)}
@@ -169,7 +169,7 @@ func TestActivityService_SetRepositorySubscription(t *testing.T) {
}
func TestActivityService_DeleteRepositorySubscription(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/subscription", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -19,7 +19,7 @@ type AdminService service
// TeamLDAPMapping represents the mapping between a GitHub team and an LDAP group.
type TeamLDAPMapping struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
LDAPDN *string `json:"ldap_dn,omitempty"`
URL *string `json:"url,omitempty"`
Name *string `json:"name,omitempty"`
@@ -38,7 +38,7 @@ func (m TeamLDAPMapping) String() string {
// UserLDAPMapping represents the mapping between a GitHub user and an LDAP user.
type UserLDAPMapping struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
LDAPDN *string `json:"ldap_dn,omitempty"`
Login *string `json:"login,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
@@ -84,7 +84,7 @@ func (s *AdminService) UpdateUserLDAPMapping(ctx context.Context, user string, m
// UpdateTeamLDAPMapping updates the mapping between a GitHub team and an LDAP group.
//
// GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-team
func (s *AdminService) UpdateTeamLDAPMapping(ctx context.Context, team int, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) {
func (s *AdminService) UpdateTeamLDAPMapping(ctx context.Context, team int64, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) {
u := fmt.Sprintf("admin/ldap/teams/%v/mapping", team)
req, err := s.client.NewRequest("PATCH", u, mapping)
if err != nil {

View File

@@ -0,0 +1,171 @@
// Copyright 2017 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"fmt"
)
// AdminStats represents a variety of stats of a Github Enterprise
// installation.
type AdminStats struct {
Issues *IssueStats `json:"issues,omitempty"`
Hooks *HookStats `json:"hooks,omitempty"`
Milestones *MilestoneStats `json:"milestones,omitempty"`
Orgs *OrgStats `json:"orgs,omitempty"`
Comments *CommentStats `json:"comments,omitempty"`
Pages *PageStats `json:"pages,omitempty"`
Users *UserStats `json:"users,omitempty"`
Gists *GistStats `json:"gists,omitempty"`
Pulls *PullStats `json:"pulls,omitempty"`
Repos *RepoStats `json:"repos,omitempty"`
}
func (s AdminStats) String() string {
return Stringify(s)
}
// IssueStats represents the number of total, open and closed issues.
type IssueStats struct {
TotalIssues *int `json:"total_issues,omitempty"`
OpenIssues *int `json:"open_issues,omitempty"`
ClosedIssues *int `json:"closed_issues,omitempty"`
}
func (s IssueStats) String() string {
return Stringify(s)
}
// HookStats represents the number of total, active and inactive hooks.
type HookStats struct {
TotalHooks *int `json:"total_hooks,omitempty"`
ActiveHooks *int `json:"active_hooks,omitempty"`
InactiveHooks *int `json:"inactive_hooks,omitempty"`
}
func (s HookStats) String() string {
return Stringify(s)
}
// MilestoneStats represents the number of total, open and close milestones.
type MilestoneStats struct {
TotalMilestones *int `json:"total_milestones,omitempty"`
OpenMilestones *int `json:"open_milestones,omitempty"`
ClosedMilestones *int `json:"closed_milestones,omitempty"`
}
func (s MilestoneStats) String() string {
return Stringify(s)
}
// OrgStats represents the number of total, disabled organizations and the team
// and team member count.
type OrgStats struct {
TotalOrgs *int `json:"total_orgs,omitempty"`
DisabledOrgs *int `json:"disabled_orgs,omitempty"`
TotalTeams *int `json:"total_teams,omitempty"`
TotalTeamMembers *int `json:"total_team_members,omitempty"`
}
func (s OrgStats) String() string {
return Stringify(s)
}
// CommentStats represents the number of total comments on commits, gists, issues
// and pull requests.
type CommentStats struct {
TotalCommitComments *int `json:"total_commit_comments,omitempty"`
TotalGistComments *int `json:"total_gist_comments,omitempty"`
TotalIssueComments *int `json:"total_issue_comments,omitempty"`
TotalPullRequestComments *int `json:"total_pull_request_comments,omitempty"`
}
func (s CommentStats) String() string {
return Stringify(s)
}
// PageStats represents the total number of github pages.
type PageStats struct {
TotalPages *int `json:"total_pages,omitempty"`
}
func (s PageStats) String() string {
return Stringify(s)
}
// UserStats represents the number of total, admin and suspended users.
type UserStats struct {
TotalUsers *int `json:"total_users,omitempty"`
AdminUsers *int `json:"admin_users,omitempty"`
SuspendedUsers *int `json:"suspended_users,omitempty"`
}
func (s UserStats) String() string {
return Stringify(s)
}
// GistStats represents the number of total, private and public gists.
type GistStats struct {
TotalGists *int `json:"total_gists,omitempty"`
PrivateGists *int `json:"private_gists,omitempty"`
PublicGists *int `json:"public_gists,omitempty"`
}
func (s GistStats) String() string {
return Stringify(s)
}
// PullStats represents the number of total, merged, mergable and unmergeable
// pull-requests.
type PullStats struct {
TotalPulls *int `json:"total_pulls,omitempty"`
MergedPulls *int `json:"merged_pulls,omitempty"`
MergablePulls *int `json:"mergeable_pulls,omitempty"`
UnmergablePulls *int `json:"unmergeable_pulls,omitempty"`
}
func (s PullStats) String() string {
return Stringify(s)
}
// RepoStats represents the number of total, root, fork, organization repositories
// together with the total number of pushes and wikis.
type RepoStats struct {
TotalRepos *int `json:"total_repos,omitempty"`
RootRepos *int `json:"root_repos,omitempty"`
ForkRepos *int `json:"fork_repos,omitempty"`
OrgRepos *int `json:"org_repos,omitempty"`
TotalPushes *int `json:"total_pushes,omitempty"`
TotalWikis *int `json:"total_wikis,omitempty"`
}
func (s RepoStats) String() string {
return Stringify(s)
}
// GetAdminStats returns a variety of metrics about a Github Enterprise
// installation.
//
// Please note that this is only available to site administrators,
// otherwise it will error with a 404 not found (instead of 401 or 403).
//
// GitHub API docs: https://developer.github.com/v3/enterprise-admin/admin_stats/
func (s *AdminService) GetAdminStats(ctx context.Context) (*AdminStats, *Response, error) {
u := fmt.Sprintf("enterprise/stats/all")
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
m := new(AdminStats)
resp, err := s.client.Do(ctx, req, m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}

View File

@@ -0,0 +1,142 @@
package github
import (
"context"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestAdminService_GetAdminStats(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/enterprise/stats/all", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `
{
"repos": {
"total_repos": 212,
"root_repos": 194,
"fork_repos": 18,
"org_repos": 51,
"total_pushes": 3082,
"total_wikis": 15
},
"hooks": {
"total_hooks": 27,
"active_hooks": 23,
"inactive_hooks": 4
},
"pages": {
"total_pages": 36
},
"orgs": {
"total_orgs": 33,
"disabled_orgs": 0,
"total_teams": 60,
"total_team_members": 314
},
"users": {
"total_users": 254,
"admin_users": 45,
"suspended_users": 21
},
"pulls": {
"total_pulls": 86,
"merged_pulls": 60,
"mergeable_pulls": 21,
"unmergeable_pulls": 3
},
"issues": {
"total_issues": 179,
"open_issues": 83,
"closed_issues": 96
},
"milestones": {
"total_milestones": 7,
"open_milestones": 6,
"closed_milestones": 1
},
"gists": {
"total_gists": 178,
"private_gists": 151,
"public_gists": 25
},
"comments": {
"total_commit_comments": 6,
"total_gist_comments": 28,
"total_issue_comments": 366,
"total_pull_request_comments": 30
}
}
`)
})
stats, _, err := client.Admin.GetAdminStats(context.Background())
if err != nil {
t.Errorf("AdminService.GetAdminStats returned error: %v", err)
}
want := &AdminStats{
Repos: &RepoStats{
TotalRepos: Int(212),
RootRepos: Int(194),
ForkRepos: Int(18),
OrgRepos: Int(51),
TotalPushes: Int(3082),
TotalWikis: Int(15),
},
Hooks: &HookStats{
TotalHooks: Int(27),
ActiveHooks: Int(23),
InactiveHooks: Int(4),
},
Pages: &PageStats{
TotalPages: Int(36),
},
Orgs: &OrgStats{
TotalOrgs: Int(33),
DisabledOrgs: Int(0),
TotalTeams: Int(60),
TotalTeamMembers: Int(314),
},
Users: &UserStats{
TotalUsers: Int(254),
AdminUsers: Int(45),
SuspendedUsers: Int(21),
},
Pulls: &PullStats{
TotalPulls: Int(86),
MergedPulls: Int(60),
MergablePulls: Int(21),
UnmergablePulls: Int(3),
},
Issues: &IssueStats{
TotalIssues: Int(179),
OpenIssues: Int(83),
ClosedIssues: Int(96),
},
Milestones: &MilestoneStats{
TotalMilestones: Int(7),
OpenMilestones: Int(6),
ClosedMilestones: Int(1),
},
Gists: &GistStats{
TotalGists: Int(178),
PrivateGists: Int(151),
PublicGists: Int(25),
},
Comments: &CommentStats{
TotalCommitComments: Int(6),
TotalGistComments: Int(28),
TotalIssueComments: Int(366),
TotalPullRequestComments: Int(30),
},
}
if !reflect.DeepEqual(stats, want) {
t.Errorf("AdminService.GetAdminStats returned %+v, want %+v", stats, want)
}
}

View File

@@ -15,7 +15,7 @@ import (
)
func TestAdminService_UpdateUserLDAPMapping(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &UserLDAPMapping{
@@ -39,7 +39,7 @@ func TestAdminService_UpdateUserLDAPMapping(t *testing.T) {
}
want := &UserLDAPMapping{
ID: Int(1),
ID: Int64(1),
LDAPDN: String("uid=asdf,ou=users,dc=github,dc=com"),
}
if !reflect.DeepEqual(mapping, want) {
@@ -48,7 +48,7 @@ func TestAdminService_UpdateUserLDAPMapping(t *testing.T) {
}
func TestAdminService_UpdateTeamLDAPMapping(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &TeamLDAPMapping{
@@ -72,7 +72,7 @@ func TestAdminService_UpdateTeamLDAPMapping(t *testing.T) {
}
want := &TeamLDAPMapping{
ID: Int(1),
ID: Int64(1),
LDAPDN: String("cn=Enterprise Ops,ou=teams,dc=github,dc=com"),
}
if !reflect.DeepEqual(mapping, want) {

View File

@@ -5,7 +5,11 @@
package github
import "context"
import (
"context"
"fmt"
"time"
)
// AppsService provides access to the installation related functions
// in the GitHub API.
@@ -13,6 +17,88 @@ import "context"
// GitHub API docs: https://developer.github.com/v3/apps/
type AppsService service
// App represents a GitHub App.
type App struct {
ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Owner *User `json:"owner,omitempty"`
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
ExternalURL *string `json:"external_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
// InstallationToken represents an installation token.
type InstallationToken struct {
Token *string `json:"token,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
}
// InstallationPermissions lists the permissions for metadata, contents, issues and single file for an installation.
type InstallationPermissions struct {
Metadata *string `json:"metadata,omitempty"`
Contents *string `json:"contents,omitempty"`
Issues *string `json:"issues,omitempty"`
SingleFile *string `json:"single_file,omitempty"`
}
// Installation represents a GitHub Apps installation.
type Installation struct {
ID *int64 `json:"id,omitempty"`
AppID *int64 `json:"app_id,omitempty"`
TargetID *int64 `json:"target_id,omitempty"`
Account *User `json:"account,omitempty"`
AccessTokensURL *string `json:"access_tokens_url,omitempty"`
RepositoriesURL *string `json:"repositories_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
TargetType *string `json:"target_type,omitempty"`
SingleFileName *string `json:"single_file_name,omitempty"`
RepositorySelection *string `json:"repository_selection,omitempty"`
Events []string `json:"events,omitempty"`
Permissions *InstallationPermissions `json:"permissions,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
}
func (i Installation) String() string {
return Stringify(i)
}
// Get a single GitHub App. Passing the empty string will get
// the authenticated GitHub App.
//
// Note: appSlug is just the URL-friendly name of your GitHub App.
// You can find this on the settings page for your GitHub App
// (e.g., https://github.com/settings/apps/:app_slug).
//
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app
func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) {
var u string
if appSlug != "" {
u = fmt.Sprintf("apps/%v", appSlug)
} else {
u = "app"
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeIntegrationPreview)
app := new(App)
resp, err := s.client.Do(ctx, req, app)
if err != nil {
return nil, resp, err
}
return app, resp, nil
}
// ListInstallations lists the installations that the current GitHub App has.
//
// GitHub API docs: https://developer.github.com/v3/apps/#find-installations
@@ -38,3 +124,107 @@ func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) (
return i, resp, nil
}
// GetInstallation returns the specified installation.
//
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation
func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("app/installations/%v", id))
}
// ListUserInstallations lists installations that are accessible to the authenticated user.
//
// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user
func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) {
u, err := addOptions("user/installations", opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeIntegrationPreview)
var i struct {
Installations []*Installation `json:"installations"`
}
resp, err := s.client.Do(ctx, req, &i)
if err != nil {
return nil, resp, err
}
return i.Installations, resp, nil
}
// CreateInstallationToken creates a new installation token.
//
// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*InstallationToken, *Response, error) {
u := fmt.Sprintf("app/installations/%v/access_tokens", id)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeIntegrationPreview)
t := new(InstallationToken)
resp, err := s.client.Do(ctx, req, t)
if err != nil {
return nil, resp, err
}
return t, resp, nil
}
// FindOrganizationInstallation finds the organization's installation information.
//
// GitHub API docs: https://developer.github.com/v3/apps/#find-organization-installation
func (s *AppsService) FindOrganizationInstallation(ctx context.Context, org string) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("orgs/%v/installation", org))
}
// FindRepositoryInstallation finds the repository's installation information.
//
// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation
func (s *AppsService) FindRepositoryInstallation(ctx context.Context, owner, repo string) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("repos/%v/%v/installation", owner, repo))
}
// FindRepositoryInstallationByID finds the repository's installation information.
//
// Note: FindRepositoryInstallationByID uses the undocumented GitHub API endpoint /repositories/:id/installation.
func (s *AppsService) FindRepositoryInstallationByID(ctx context.Context, id int64) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("repositories/%d/installation", id))
}
// FindUserInstallation finds the user's installation information.
//
// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation
func (s *AppsService) FindUserInstallation(ctx context.Context, user string) (*Installation, *Response, error) {
return s.getInstallation(ctx, fmt.Sprintf("users/%v/installation", user))
}
func (s *AppsService) getInstallation(ctx context.Context, url string) (*Installation, *Response, error) {
req, err := s.client.NewRequest("GET", url, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeIntegrationPreview)
i := new(Installation)
resp, err := s.client.Do(ctx, req, i)
if err != nil {
return nil, resp, err
}
return i, resp, nil
}

View File

@@ -5,20 +5,10 @@
package github
import "context"
// Installation represents a GitHub Apps installation.
type Installation struct {
ID *int `json:"id,omitempty"`
Account *User `json:"account,omitempty"`
AccessTokensURL *string `json:"access_tokens_url,omitempty"`
RepositoriesURL *string `json:"repositories_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
}
func (i Installation) String() string {
return Stringify(i)
}
import (
"context"
"fmt"
)
// ListRepos lists the repositories that are accessible to the authenticated installation.
//
@@ -47,3 +37,65 @@ func (s *AppsService) ListRepos(ctx context.Context, opt *ListOptions) ([]*Repos
return r.Repositories, resp, nil
}
// ListUserRepos lists repositories that are accessible
// to the authenticated user for an installation.
//
// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-for-an-installation
func (s *AppsService) ListUserRepos(ctx context.Context, id int64, opt *ListOptions) ([]*Repository, *Response, error) {
u := fmt.Sprintf("user/installations/%v/repositories", id)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeIntegrationPreview)
var r struct {
Repositories []*Repository `json:"repositories"`
}
resp, err := s.client.Do(ctx, req, &r)
if err != nil {
return nil, resp, err
}
return r.Repositories, resp, nil
}
// AddRepository adds a single repository to an installation.
//
// GitHub API docs: https://developer.github.com/v3/apps/installations/#add-repository-to-installation
func (s *AppsService) AddRepository(ctx context.Context, instID, repoID int64) (*Repository, *Response, error) {
u := fmt.Sprintf("apps/installations/%v/repositories/%v", instID, repoID)
req, err := s.client.NewRequest("PUT", u, nil)
if err != nil {
return nil, nil, err
}
r := new(Repository)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}
return r, resp, nil
}
// RemoveRepository removes a single repository from an installation.
//
// GitHub docs: https://developer.github.com/v3/apps/installations/#remove-repository-from-installation
func (s *AppsService) RemoveRepository(ctx context.Context, instID, repoID int64) (*Response, error) {
u := fmt.Sprintf("apps/installations/%v/repositories/%v", instID, repoID)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}

View File

@@ -14,7 +14,7 @@ import (
)
func TestAppsService_ListRepos(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/installation/repositories", func(w http.ResponseWriter, r *http.Request) {
@@ -33,8 +33,69 @@ func TestAppsService_ListRepos(t *testing.T) {
t.Errorf("Apps.ListRepos returned error: %v", err)
}
want := []*Repository{{ID: Int(1)}}
want := []*Repository{{ID: Int64(1)}}
if !reflect.DeepEqual(repositories, want) {
t.Errorf("Apps.ListRepos returned %+v, want %+v", repositories, want)
}
}
func TestAppsService_ListUserRepos(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/installations/1/repositories", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
testFormValues(t, r, values{
"page": "1",
"per_page": "2",
})
fmt.Fprint(w, `{"repositories": [{"id":1}]}`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
repositories, _, err := client.Apps.ListUserRepos(context.Background(), 1, opt)
if err != nil {
t.Errorf("Apps.ListUserRepos returned error: %v", err)
}
want := []*Repository{{ID: Int64(1)}}
if !reflect.DeepEqual(repositories, want) {
t.Errorf("Apps.ListUserRepos returned %+v, want %+v", repositories, want)
}
}
func TestAppsService_AddRepository(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/apps/installations/1/repositories/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
fmt.Fprint(w, `{"id":1,"name":"n","description":"d","owner":{"login":"l"},"license":{"key":"mit"}}`)
})
repo, _, err := client.Apps.AddRepository(context.Background(), 1, 1)
if err != nil {
t.Errorf("Apps.AddRepository returned error: %v", err)
}
want := &Repository{ID: Int64(1), Name: String("n"), Description: String("d"), Owner: &User{Login: String("l")}, License: &License{Key: String("mit")}}
if !reflect.DeepEqual(repo, want) {
t.Errorf("AddRepository returned %+v, want %+v", repo, want)
}
}
func TestAppsService_RemoveRepository(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/apps/installations/1/repositories/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Apps.RemoveRepository(context.Background(), 1, 1)
if err != nil {
t.Errorf("Apps.RemoveRepository returned error: %v", err)
}
}

View File

@@ -0,0 +1,183 @@
// Copyright 2017 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"fmt"
)
// MarketplaceService handles communication with the marketplace related
// methods of the GitHub API.
//
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
type MarketplaceService struct {
client *Client
// Stubbed controls whether endpoints that return stubbed data are used
// instead of production endpoints. Stubbed data is fake data that's useful
// for testing your GitHub Apps. Stubbed data is hard-coded and will not
// change based on actual subscriptions.
//
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
Stubbed bool
}
// MarketplacePlan represents a GitHub Apps Marketplace Listing Plan.
type MarketplacePlan struct {
URL *string `json:"url,omitempty"`
AccountsURL *string `json:"accounts_url,omitempty"`
ID *int64 `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
MonthlyPriceInCents *int `json:"monthly_price_in_cents,omitempty"`
YearlyPriceInCents *int `json:"yearly_price_in_cents,omitempty"`
// The pricing model for this listing. Can be one of "flat-rate", "per-unit", or "free".
PriceModel *string `json:"price_model,omitempty"`
UnitName *string `json:"unit_name,omitempty"`
Bullets *[]string `json:"bullets,omitempty"`
// State can be one of the values "draft" or "published".
State *string `json:"state,omitempty"`
HasFreeTrial *bool `json:"has_free_trial,omitempty"`
}
// MarketplacePurchase represents a GitHub Apps Marketplace Purchase.
type MarketplacePurchase struct {
// BillingCycle can be one of the values "yearly", "monthly" or nil.
BillingCycle *string `json:"billing_cycle,omitempty"`
NextBillingDate *Timestamp `json:"next_billing_date,omitempty"`
UnitCount *int `json:"unit_count,omitempty"`
Plan *MarketplacePlan `json:"plan,omitempty"`
Account *MarketplacePlanAccount `json:"account,omitempty"`
OnFreeTrial *bool `json:"on_free_trial,omitempty"`
FreeTrialEndsOn *Timestamp `json:"free_trial_ends_on,omitempty"`
}
// MarketplacePendingChange represents a pending change to a GitHub Apps Marketplace Plan.
type MarketplacePendingChange struct {
EffectiveDate *Timestamp `json:"effective_date,omitempty"`
UnitCount *int `json:"unit_count,omitempty"`
ID *int64 `json:"id,omitempty"`
Plan *MarketplacePlan `json:"plan,omitempty"`
}
// MarketplacePlanAccount represents a GitHub Account (user or organization) on a specific plan.
type MarketplacePlanAccount struct {
URL *string `json:"url,omitempty"`
Type *string `json:"type,omitempty"`
ID *int64 `json:"id,omitempty"`
Login *string `json:"login,omitempty"`
Email *string `json:"email,omitempty"`
OrganizationBillingEmail *string `json:"organization_billing_email,omitempty"`
MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"`
MarketplacePendingChange *MarketplacePendingChange `json:"marketplace_pending_change,omitempty"`
}
// ListPlans lists all plans for your Marketplace listing.
//
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-plans-for-your-marketplace-listing
func (s *MarketplaceService) ListPlans(ctx context.Context, opt *ListOptions) ([]*MarketplacePlan, *Response, error) {
uri := s.marketplaceURI("plans")
u, err := addOptions(uri, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var plans []*MarketplacePlan
resp, err := s.client.Do(ctx, req, &plans)
if err != nil {
return nil, resp, err
}
return plans, resp, nil
}
// ListPlanAccountsForPlan lists all GitHub accounts (user or organization) on a specific plan.
//
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-github-accounts-user-or-organization-on-a-specific-plan
func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) {
uri := s.marketplaceURI(fmt.Sprintf("plans/%v/accounts", planID))
u, err := addOptions(uri, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var accounts []*MarketplacePlanAccount
resp, err := s.client.Do(ctx, req, &accounts)
if err != nil {
return nil, resp, err
}
return accounts, resp, nil
}
// ListPlanAccountsForAccount lists all GitHub accounts (user or organization) associated with an account.
//
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#check-if-a-github-account-is-associated-with-any-marketplace-listing
func (s *MarketplaceService) ListPlanAccountsForAccount(ctx context.Context, accountID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) {
uri := s.marketplaceURI(fmt.Sprintf("accounts/%v", accountID))
u, err := addOptions(uri, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var accounts []*MarketplacePlanAccount
resp, err := s.client.Do(ctx, req, &accounts)
if err != nil {
return nil, resp, err
}
return accounts, resp, nil
}
// ListMarketplacePurchasesForUser lists all GitHub marketplace purchases made by a user.
//
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#get-a-users-marketplace-purchases
func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context, opt *ListOptions) ([]*MarketplacePurchase, *Response, error) {
uri := "user/marketplace_purchases"
if s.Stubbed {
uri = "user/marketplace_purchases/stubbed"
}
u, err := addOptions(uri, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var purchases []*MarketplacePurchase
resp, err := s.client.Do(ctx, req, &purchases)
if err != nil {
return nil, resp, err
}
return purchases, resp, nil
}
func (s *MarketplaceService) marketplaceURI(endpoint string) string {
url := "marketplace_listing"
if s.Stubbed {
url = "marketplace_listing/stubbed"
}
return url + "/" + endpoint
}

View File

@@ -0,0 +1,194 @@
// Copyright 2017 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestMarketplaceService_ListPlans(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/marketplace_listing/plans", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{
"page": "1",
"per_page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = false
plans, _, err := client.Marketplace.ListPlans(context.Background(), opt)
if err != nil {
t.Errorf("Marketplace.ListPlans returned error: %v", err)
}
want := []*MarketplacePlan{{ID: Int64(1)}}
if !reflect.DeepEqual(plans, want) {
t.Errorf("Marketplace.ListPlans returned %+v, want %+v", plans, want)
}
}
func TestMarketplaceService_Stubbed_ListPlans(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/marketplace_listing/stubbed/plans", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = true
plans, _, err := client.Marketplace.ListPlans(context.Background(), opt)
if err != nil {
t.Errorf("Marketplace.ListPlans (Stubbed) returned error: %v", err)
}
want := []*MarketplacePlan{{ID: Int64(1)}}
if !reflect.DeepEqual(plans, want) {
t.Errorf("Marketplace.ListPlans (Stubbed) returned %+v, want %+v", plans, want)
}
}
func TestMarketplaceService_ListPlanAccountsForPlan(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/marketplace_listing/plans/1/accounts", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = false
accounts, _, err := client.Marketplace.ListPlanAccountsForPlan(context.Background(), 1, opt)
if err != nil {
t.Errorf("Marketplace.ListPlanAccountsForPlan returned error: %v", err)
}
want := []*MarketplacePlanAccount{{ID: Int64(1)}}
if !reflect.DeepEqual(accounts, want) {
t.Errorf("Marketplace.ListPlanAccountsForPlan returned %+v, want %+v", accounts, want)
}
}
func TestMarketplaceService_Stubbed_ListPlanAccountsForPlan(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/marketplace_listing/stubbed/plans/1/accounts", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = true
accounts, _, err := client.Marketplace.ListPlanAccountsForPlan(context.Background(), 1, opt)
if err != nil {
t.Errorf("Marketplace.ListPlanAccountsForPlan (Stubbed) returned error: %v", err)
}
want := []*MarketplacePlanAccount{{ID: Int64(1)}}
if !reflect.DeepEqual(accounts, want) {
t.Errorf("Marketplace.ListPlanAccountsForPlan (Stubbed) returned %+v, want %+v", accounts, want)
}
}
func TestMarketplaceService_ListPlanAccountsForAccount(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/marketplace_listing/accounts/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1, "marketplace_pending_change": {"id": 77}}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = false
accounts, _, err := client.Marketplace.ListPlanAccountsForAccount(context.Background(), 1, opt)
if err != nil {
t.Errorf("Marketplace.ListPlanAccountsForAccount returned error: %v", err)
}
want := []*MarketplacePlanAccount{{ID: Int64(1), MarketplacePendingChange: &MarketplacePendingChange{ID: Int64(77)}}}
if !reflect.DeepEqual(accounts, want) {
t.Errorf("Marketplace.ListPlanAccountsForAccount returned %+v, want %+v", accounts, want)
}
}
func TestMarketplaceService_Stubbed_ListPlanAccountsForAccount(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/marketplace_listing/stubbed/accounts/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = true
accounts, _, err := client.Marketplace.ListPlanAccountsForAccount(context.Background(), 1, opt)
if err != nil {
t.Errorf("Marketplace.ListPlanAccountsForAccount (Stubbed) returned error: %v", err)
}
want := []*MarketplacePlanAccount{{ID: Int64(1)}}
if !reflect.DeepEqual(accounts, want) {
t.Errorf("Marketplace.ListPlanAccountsForAccount (Stubbed) returned %+v, want %+v", accounts, want)
}
}
func TestMarketplaceService_ListMarketplacePurchasesForUser(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/marketplace_purchases", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"billing_cycle":"monthly"}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = false
purchases, _, err := client.Marketplace.ListMarketplacePurchasesForUser(context.Background(), opt)
if err != nil {
t.Errorf("Marketplace.ListMarketplacePurchasesForUser returned error: %v", err)
}
want := []*MarketplacePurchase{{BillingCycle: String("monthly")}}
if !reflect.DeepEqual(purchases, want) {
t.Errorf("Marketplace.ListMarketplacePurchasesForUser returned %+v, want %+v", purchases, want)
}
}
func TestMarketplaceService_Stubbed_ListMarketplacePurchasesForUser(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/marketplace_purchases/stubbed", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"billing_cycle":"monthly"}]`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
client.Marketplace.Stubbed = true
purchases, _, err := client.Marketplace.ListMarketplacePurchasesForUser(context.Background(), opt)
if err != nil {
t.Errorf("Marketplace.ListMarketplacePurchasesForUser returned error: %v", err)
}
want := []*MarketplacePurchase{{BillingCycle: String("monthly")}}
if !reflect.DeepEqual(purchases, want) {
t.Errorf("Marketplace.ListMarketplacePurchasesForUser returned %+v, want %+v", purchases, want)
}
}

View File

@@ -11,10 +11,53 @@ import (
"net/http"
"reflect"
"testing"
"time"
)
func TestAppsService_Get_authenticatedApp(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"id":1}`)
})
app, _, err := client.Apps.Get(context.Background(), "")
if err != nil {
t.Errorf("Apps.Get returned error: %v", err)
}
want := &App{ID: Int64(1)}
if !reflect.DeepEqual(app, want) {
t.Errorf("Apps.Get returned %+v, want %+v", app, want)
}
}
func TestAppsService_Get_specifiedApp(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/apps/a", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"html_url":"https://github.com/apps/a"}`)
})
app, _, err := client.Apps.Get(context.Background(), "a")
if err != nil {
t.Errorf("Apps.Get returned error: %v", err)
}
want := &App{HTMLURL: String("https://github.com/apps/a")}
if !reflect.DeepEqual(app, want) {
t.Errorf("Apps.Get returned %+v, want %+v", *app.HTMLURL, *want.HTMLURL)
}
}
func TestAppsService_ListInstallations(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/app/installations", func(w http.ResponseWriter, r *http.Request) {
@@ -24,7 +67,26 @@ func TestAppsService_ListInstallations(t *testing.T) {
"page": "1",
"per_page": "2",
})
fmt.Fprint(w, `[{"id":1}]`)
fmt.Fprint(w, `[{
"id":1,
"app_id":1,
"target_id":1,
"target_type": "Organization",
"permissions": {
"metadata": "read",
"contents": "read",
"issues": "write",
"single_file": "write"
},
"events": [
"push",
"pull_request"
],
"single_file_name": "config.yml",
"repository_selection": "selected",
"created_at": "2018-01-01T00:00:00Z",
"updated_at": "2018-01-01T00:00:00Z"}]`,
)
})
opt := &ListOptions{Page: 1, PerPage: 2}
@@ -33,8 +95,176 @@ func TestAppsService_ListInstallations(t *testing.T) {
t.Errorf("Apps.ListInstallations returned error: %v", err)
}
want := []*Installation{{ID: Int(1)}}
date := Timestamp{Time: time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC)}
want := []*Installation{{
ID: Int64(1),
AppID: Int64(1),
TargetID: Int64(1),
TargetType: String("Organization"),
SingleFileName: String("config.yml"),
RepositorySelection: String("selected"),
Permissions: &InstallationPermissions{
Metadata: String("read"),
Contents: String("read"),
Issues: String("write"),
SingleFile: String("write")},
Events: []string{"push", "pull_request"},
CreatedAt: &date,
UpdatedAt: &date,
}}
if !reflect.DeepEqual(installations, want) {
t.Errorf("Apps.ListInstallations returned %+v, want %+v", installations, want)
}
}
func TestAppsService_GetInstallation(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/app/installations/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
})
installation, _, err := client.Apps.GetInstallation(context.Background(), 1)
if err != nil {
t.Errorf("Apps.GetInstallation returned error: %v", err)
}
want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
if !reflect.DeepEqual(installation, want) {
t.Errorf("Apps.GetInstallation returned %+v, want %+v", installation, want)
}
}
func TestAppsService_ListUserInstallations(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/installations", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
testFormValues(t, r, values{
"page": "1",
"per_page": "2",
})
fmt.Fprint(w, `{"installations":[{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}]}`)
})
opt := &ListOptions{Page: 1, PerPage: 2}
installations, _, err := client.Apps.ListUserInstallations(context.Background(), opt)
if err != nil {
t.Errorf("Apps.ListUserInstallations returned error: %v", err)
}
want := []*Installation{{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}}
if !reflect.DeepEqual(installations, want) {
t.Errorf("Apps.ListUserInstallations returned %+v, want %+v", installations, want)
}
}
func TestAppsService_CreateInstallationToken(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/app/installations/1/access_tokens", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"token":"t"}`)
})
token, _, err := client.Apps.CreateInstallationToken(context.Background(), 1)
if err != nil {
t.Errorf("Apps.CreateInstallationToken returned error: %v", err)
}
want := &InstallationToken{Token: String("t")}
if !reflect.DeepEqual(token, want) {
t.Errorf("Apps.CreateInstallationToken returned %+v, want %+v", token, want)
}
}
func TestAppsService_FindOrganizationInstallation(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/installation", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
})
installation, _, err := client.Apps.FindOrganizationInstallation(context.Background(), "o")
if err != nil {
t.Errorf("Apps.FindOrganizationInstallation returned error: %v", err)
}
want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
if !reflect.DeepEqual(installation, want) {
t.Errorf("Apps.FindOrganizationInstallation returned %+v, want %+v", installation, want)
}
}
func TestAppsService_FindRepositoryInstallation(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/installation", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
})
installation, _, err := client.Apps.FindRepositoryInstallation(context.Background(), "o", "r")
if err != nil {
t.Errorf("Apps.FindRepositoryInstallation returned error: %v", err)
}
want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
if !reflect.DeepEqual(installation, want) {
t.Errorf("Apps.FindRepositoryInstallation returned %+v, want %+v", installation, want)
}
}
func TestAppsService_FindRepositoryInstallationByID(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repositories/1/installation", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "Organization"}`)
})
installation, _, err := client.Apps.FindRepositoryInstallationByID(context.Background(), 1)
if err != nil {
t.Errorf("Apps.FindRepositoryInstallationByID returned error: %v", err)
}
want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("Organization")}
if !reflect.DeepEqual(installation, want) {
t.Errorf("Apps.FindRepositoryInstallationByID returned %+v, want %+v", installation, want)
}
}
func TestAppsService_FindUserInstallation(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/installation", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeIntegrationPreview)
fmt.Fprint(w, `{"id":1, "app_id":1, "target_id":1, "target_type": "User"}`)
})
installation, _, err := client.Apps.FindUserInstallation(context.Background(), "u")
if err != nil {
t.Errorf("Apps.FindUserInstallation returned error: %v", err)
}
want := &Installation{ID: Int64(1), AppID: Int64(1), TargetID: Int64(1), TargetType: String("User")}
if !reflect.DeepEqual(installation, want) {
t.Errorf("Apps.FindUserInstallation returned %+v, want %+v", installation, want)
}
}

View File

@@ -54,7 +54,7 @@ type AuthorizationsService service
// Authorization represents an individual GitHub authorization.
type Authorization struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
Scopes []Scope `json:"scopes,omitempty"`
Token *string `json:"token,omitempty"`
@@ -88,7 +88,7 @@ func (a AuthorizationApp) String() string {
// Grant represents an OAuth application that has been granted access to an account.
type Grant struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
App *AuthorizationApp `json:"app,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
@@ -160,7 +160,7 @@ func (s *AuthorizationsService) List(ctx context.Context, opt *ListOptions) ([]*
// Get a single authorization.
//
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization
func (s *AuthorizationsService) Get(ctx context.Context, id int) (*Authorization, *Response, error) {
func (s *AuthorizationsService) Get(ctx context.Context, id int64) (*Authorization, *Response, error) {
u := fmt.Sprintf("authorizations/%d", id)
req, err := s.client.NewRequest("GET", u, nil)
@@ -234,7 +234,7 @@ func (s *AuthorizationsService) GetOrCreateForApp(ctx context.Context, clientID
// Edit a single authorization.
//
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization
func (s *AuthorizationsService) Edit(ctx context.Context, id int, auth *AuthorizationUpdateRequest) (*Authorization, *Response, error) {
func (s *AuthorizationsService) Edit(ctx context.Context, id int64, auth *AuthorizationUpdateRequest) (*Authorization, *Response, error) {
u := fmt.Sprintf("authorizations/%d", id)
req, err := s.client.NewRequest("PATCH", u, auth)
@@ -254,7 +254,7 @@ func (s *AuthorizationsService) Edit(ctx context.Context, id int, auth *Authoriz
// Delete a single authorization.
//
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization
func (s *AuthorizationsService) Delete(ctx context.Context, id int) (*Response, error) {
func (s *AuthorizationsService) Delete(ctx context.Context, id int64) (*Response, error) {
u := fmt.Sprintf("authorizations/%d", id)
req, err := s.client.NewRequest("DELETE", u, nil)
@@ -366,7 +366,7 @@ func (s *AuthorizationsService) ListGrants(ctx context.Context, opt *ListOptions
// GetGrant gets a single OAuth application grant.
//
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-grant
func (s *AuthorizationsService) GetGrant(ctx context.Context, id int) (*Grant, *Response, error) {
func (s *AuthorizationsService) GetGrant(ctx context.Context, id int64) (*Grant, *Response, error) {
u := fmt.Sprintf("applications/grants/%d", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
@@ -387,7 +387,7 @@ func (s *AuthorizationsService) GetGrant(ctx context.Context, id int) (*Grant, *
// the user.
//
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-a-grant
func (s *AuthorizationsService) DeleteGrant(ctx context.Context, id int) (*Response, error) {
func (s *AuthorizationsService) DeleteGrant(ctx context.Context, id int64) (*Response, error) {
u := fmt.Sprintf("applications/grants/%d", id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {

View File

@@ -15,7 +15,7 @@ import (
)
func TestAuthorizationsService_List(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/authorizations", func(w http.ResponseWriter, r *http.Request) {
@@ -30,14 +30,14 @@ func TestAuthorizationsService_List(t *testing.T) {
t.Errorf("Authorizations.List returned error: %v", err)
}
want := []*Authorization{{ID: Int(1)}}
want := []*Authorization{{ID: Int64(1)}}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorizations.List returned %+v, want %+v", *got[0].ID, *want[0].ID)
}
}
func TestAuthorizationsService_Get(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/authorizations/1", func(w http.ResponseWriter, r *http.Request) {
@@ -50,14 +50,14 @@ func TestAuthorizationsService_Get(t *testing.T) {
t.Errorf("Authorizations.Get returned error: %v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorizations.Get returned auth %+v, want %+v", got, want)
}
}
func TestAuthorizationsService_Create(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &AuthorizationRequest{
@@ -81,14 +81,14 @@ func TestAuthorizationsService_Create(t *testing.T) {
t.Errorf("Authorizations.Create returned error: %v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorization.Create returned %+v, want %+v", got, want)
}
}
func TestAuthorizationsService_GetOrCreateForApp(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &AuthorizationRequest{
@@ -112,14 +112,14 @@ func TestAuthorizationsService_GetOrCreateForApp(t *testing.T) {
t.Errorf("Authorizations.GetOrCreateForApp returned error: %v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorization.GetOrCreateForApp returned %+v, want %+v", got, want)
}
}
func TestAuthorizationsService_GetOrCreateForApp_Fingerprint(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &AuthorizationRequest{
@@ -144,14 +144,14 @@ func TestAuthorizationsService_GetOrCreateForApp_Fingerprint(t *testing.T) {
t.Errorf("Authorizations.GetOrCreateForApp returned error: %v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorization.GetOrCreateForApp returned %+v, want %+v", got, want)
}
}
func TestAuthorizationsService_Edit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &AuthorizationUpdateRequest{
@@ -175,14 +175,14 @@ func TestAuthorizationsService_Edit(t *testing.T) {
t.Errorf("Authorizations.Edit returned error: %v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorization.Update returned %+v, want %+v", got, want)
}
}
func TestAuthorizationsService_Delete(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/authorizations/1", func(w http.ResponseWriter, r *http.Request) {
@@ -197,7 +197,7 @@ func TestAuthorizationsService_Delete(t *testing.T) {
}
func TestAuthorizationsService_Check(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/applications/id/tokens/t", func(w http.ResponseWriter, r *http.Request) {
@@ -210,14 +210,14 @@ func TestAuthorizationsService_Check(t *testing.T) {
t.Errorf("Authorizations.Check returned error: %v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorizations.Check returned auth %+v, want %+v", got, want)
}
}
func TestAuthorizationsService_Reset(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/applications/id/tokens/t", func(w http.ResponseWriter, r *http.Request) {
@@ -230,14 +230,14 @@ func TestAuthorizationsService_Reset(t *testing.T) {
t.Errorf("Authorizations.Reset returned error: %v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorizations.Reset returned auth %+v, want %+v", got, want)
}
}
func TestAuthorizationsService_Revoke(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/applications/id/tokens/t", func(w http.ResponseWriter, r *http.Request) {
@@ -252,7 +252,7 @@ func TestAuthorizationsService_Revoke(t *testing.T) {
}
func TestListGrants(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/applications/grants", func(w http.ResponseWriter, r *http.Request) {
@@ -265,14 +265,14 @@ func TestListGrants(t *testing.T) {
t.Errorf("OAuthAuthorizations.ListGrants returned error: %v", err)
}
want := []*Grant{{ID: Int(1)}}
want := []*Grant{{ID: Int64(1)}}
if !reflect.DeepEqual(got, want) {
t.Errorf("OAuthAuthorizations.ListGrants = %+v, want %+v", got, want)
}
}
func TestListGrants_withOptions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/applications/grants", func(w http.ResponseWriter, r *http.Request) {
@@ -290,7 +290,7 @@ func TestListGrants_withOptions(t *testing.T) {
}
func TestGetGrant(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/applications/grants/1", func(w http.ResponseWriter, r *http.Request) {
@@ -303,14 +303,14 @@ func TestGetGrant(t *testing.T) {
t.Errorf("OAuthAuthorizations.GetGrant returned error: %v", err)
}
want := &Grant{ID: Int(1)}
want := &Grant{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("OAuthAuthorizations.GetGrant = %+v, want %+v", got, want)
}
}
func TestDeleteGrant(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/applications/grants/1", func(w http.ResponseWriter, r *http.Request) {
@@ -324,7 +324,7 @@ func TestDeleteGrant(t *testing.T) {
}
func TestAuthorizationsService_CreateImpersonation(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/admin/users/u/authorizations", func(w http.ResponseWriter, r *http.Request) {
@@ -338,14 +338,14 @@ func TestAuthorizationsService_CreateImpersonation(t *testing.T) {
t.Errorf("Authorizations.CreateImpersonation returned error: %+v", err)
}
want := &Authorization{ID: Int(1)}
want := &Authorization{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("Authorizations.CreateImpersonation returned %+v, want %+v", *got.ID, *want.ID)
}
}
func TestAuthorizationsService_DeleteImpersonation(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/admin/users/u/authorizations", func(w http.ResponseWriter, r *http.Request) {

431
vendor/github.com/google/go-github/github/checks.go generated vendored Normal file
View File

@@ -0,0 +1,431 @@
// Copyright 2018 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"fmt"
)
// ChecksService provides access to the Checks API in the
// GitHub API.
//
// GitHub API docs: https://developer.github.com/v3/checks/
type ChecksService service
// CheckRun represents a GitHub check run on a repository associated with a GitHub app.
type CheckRun struct {
ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
HeadSHA *string `json:"head_sha,omitempty"`
ExternalID *string `json:"external_id,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
DetailsURL *string `json:"details_url,omitempty"`
Status *string `json:"status,omitempty"`
Conclusion *string `json:"conclusion,omitempty"`
StartedAt *Timestamp `json:"started_at,omitempty"`
CompletedAt *Timestamp `json:"completed_at,omitempty"`
Output *CheckRunOutput `json:"output,omitempty"`
Name *string `json:"name,omitempty"`
CheckSuite *CheckSuite `json:"check_suite,omitempty"`
App *App `json:"app,omitempty"`
PullRequests []*PullRequest `json:"pull_requests,omitempty"`
}
// CheckRunOutput represents the output of a CheckRun.
type CheckRunOutput struct {
Title *string `json:"title,omitempty"`
Summary *string `json:"summary,omitempty"`
Text *string `json:"text,omitempty"`
AnnotationsCount *int `json:"annotations_count,omitempty"`
AnnotationsURL *string `json:"annotations_url,omitempty"`
Annotations []*CheckRunAnnotation `json:"annotations,omitempty"`
Images []*CheckRunImage `json:"images,omitempty"`
}
// CheckRunAnnotation represents an annotation object for a CheckRun output.
type CheckRunAnnotation struct {
Path *string `json:"path,omitempty"`
BlobHRef *string `json:"blob_href,omitempty"`
StartLine *int `json:"start_line,omitempty"`
EndLine *int `json:"end_line,omitempty"`
AnnotationLevel *string `json:"annotation_level,omitempty"`
Message *string `json:"message,omitempty"`
Title *string `json:"title,omitempty"`
RawDetails *string `json:"raw_details,omitempty"`
}
// CheckRunImage represents an image object for a CheckRun output.
type CheckRunImage struct {
Alt *string `json:"alt,omitempty"`
ImageURL *string `json:"image_url,omitempty"`
Caption *string `json:"caption,omitempty"`
}
// CheckSuite represents a suite of check runs.
type CheckSuite struct {
ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
HeadBranch *string `json:"head_branch,omitempty"`
HeadSHA *string `json:"head_sha,omitempty"`
URL *string `json:"url,omitempty"`
BeforeSHA *string `json:"before,omitempty"`
AfterSHA *string `json:"after,omitempty"`
Status *string `json:"status,omitempty"`
Conclusion *string `json:"conclusion,omitempty"`
App *App `json:"app,omitempty"`
Repository *Repository `json:"repository,omitempty"`
PullRequests []*PullRequest `json:"pull_requests,omitempty"`
}
func (c CheckRun) String() string {
return Stringify(c)
}
func (c CheckSuite) String() string {
return Stringify(c)
}
// GetCheckRun gets a check-run for a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#get-a-single-check-run
func (s *ChecksService) GetCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*CheckRun, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkRun := new(CheckRun)
resp, err := s.client.Do(ctx, req, checkRun)
if err != nil {
return nil, resp, err
}
return checkRun, resp, nil
}
// GetCheckSuite gets a single check suite.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#get-a-single-check-suite
func (s *ChecksService) GetCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*CheckSuite, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites/%v", owner, repo, checkSuiteID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkSuite := new(CheckSuite)
resp, err := s.client.Do(ctx, req, checkSuite)
if err != nil {
return nil, resp, err
}
return checkSuite, resp, nil
}
// CreateCheckRunOptions sets up parameters needed to create a CheckRun.
type CreateCheckRunOptions struct {
Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.)
HeadBranch string `json:"head_branch"` // The name of the branch to perform a check against. (Required.)
HeadSHA string `json:"head_sha"` // The SHA of the commit. (Required.)
DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.)
ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.)
Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.)
Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".)
StartedAt *Timestamp `json:"started_at,omitempty"` // The time that the check run began. (Optional.)
CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.)
Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional)
Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.)
}
// CheckRunAction exposes further actions the integrator can perform, which a user may trigger.
type CheckRunAction struct {
Label string `json:"label"` // The text to be displayed on a button in the web UI. The maximum size is 20 characters. (Required.)
Description string `json:"description"` // A short explanation of what this action would do. The maximum size is 40 characters. (Required.)
Identifier string `json:"identifier"` // A reference for the action on the integrator's system. The maximum size is 20 characters. (Required.)
}
// CreateCheckRun creates a check run for repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#create-a-check-run
func (s *ChecksService) CreateCheckRun(ctx context.Context, owner, repo string, opt CreateCheckRunOptions) (*CheckRun, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs", owner, repo)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkRun := new(CheckRun)
resp, err := s.client.Do(ctx, req, checkRun)
if err != nil {
return nil, resp, err
}
return checkRun, resp, nil
}
// UpdateCheckRunOptions sets up parameters needed to update a CheckRun.
type UpdateCheckRunOptions struct {
Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.)
HeadBranch *string `json:"head_branch,omitempty"` // The name of the branch to perform a check against. (Optional.)
HeadSHA *string `json:"head_sha,omitempty"` // The SHA of the commit. (Optional.)
DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.)
ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.)
Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.)
Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".)
CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.)
Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional)
Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.)
}
// UpdateCheckRun updates a check run for a specific commit in a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#update-a-check-run
func (s *ChecksService) UpdateCheckRun(ctx context.Context, owner, repo string, checkRunID int64, opt UpdateCheckRunOptions) (*CheckRun, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID)
req, err := s.client.NewRequest("PATCH", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkRun := new(CheckRun)
resp, err := s.client.Do(ctx, req, checkRun)
if err != nil {
return nil, resp, err
}
return checkRun, resp, nil
}
// ListCheckRunAnnotations lists the annotations for a check run.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-annotations-for-a-check-run
func (s *ChecksService) ListCheckRunAnnotations(ctx context.Context, owner, repo string, checkRunID int64, opt *ListOptions) ([]*CheckRunAnnotation, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-runs/%v/annotations", owner, repo, checkRunID)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkRunAnnotations []*CheckRunAnnotation
resp, err := s.client.Do(ctx, req, &checkRunAnnotations)
if err != nil {
return nil, resp, err
}
return checkRunAnnotations, resp, nil
}
// ListCheckRunsOptions represents parameters to list check runs.
type ListCheckRunsOptions struct {
CheckName *string `url:"check_name,omitempty"` // Returns check runs with the specified name.
Status *string `url:"status,omitempty"` // Returns check runs with the specified status. Can be one of "queued", "in_progress", or "completed".
Filter *string `url:"filter,omitempty"` // Filters check runs by their completed_at timestamp. Can be one of "latest" (returning the most recent check runs) or "all". Default: "latest"
ListOptions
}
// ListCheckRunsResults represents the result of a check run list.
type ListCheckRunsResults struct {
Total *int `json:"total_count,omitempty"`
CheckRuns []*CheckRun `json:"check_runs,omitempty"`
}
// ListCheckRunsForRef lists check runs for a specific ref.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref
func (s *ChecksService) ListCheckRunsForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-runs", owner, repo, ref)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkRunResults *ListCheckRunsResults
resp, err := s.client.Do(ctx, req, &checkRunResults)
if err != nil {
return nil, resp, err
}
return checkRunResults, resp, nil
}
// ListCheckRunsCheckSuite lists check runs for a check suite.
//
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-in-a-check-suite
func (s *ChecksService) ListCheckRunsCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/check-runs", owner, repo, checkSuiteID)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkRunResults *ListCheckRunsResults
resp, err := s.client.Do(ctx, req, &checkRunResults)
if err != nil {
return nil, resp, err
}
return checkRunResults, resp, nil
}
// ListCheckSuiteOptions represents parameters to list check suites.
type ListCheckSuiteOptions struct {
CheckName *string `url:"check_name,omitempty"` // Filters checks suites by the name of the check run.
AppID *int `url:"app_id,omitempty"` // Filters check suites by GitHub App id.
ListOptions
}
// ListCheckSuiteResults represents the result of a check run list.
type ListCheckSuiteResults struct {
Total *int `json:"total_count,omitempty"`
CheckSuites []*CheckSuite `json:"check_suites,omitempty"`
}
// ListCheckSuitesForRef lists check suite for a specific ref.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#list-check-suites-for-a-specific-ref
func (s *ChecksService) ListCheckSuitesForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckSuiteOptions) (*ListCheckSuiteResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-suites", owner, repo, ref)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkSuiteResults *ListCheckSuiteResults
resp, err := s.client.Do(ctx, req, &checkSuiteResults)
if err != nil {
return nil, resp, err
}
return checkSuiteResults, resp, nil
}
// AutoTriggerCheck enables or disables automatic creation of CheckSuite events upon pushes to the repository.
type AutoTriggerCheck struct {
AppID *int64 `json:"app_id,omitempty"` // The id of the GitHub App. (Required.)
Setting *bool `json:"setting,omitempty"` // Set to "true" to enable automatic creation of CheckSuite events upon pushes to the repository, or "false" to disable them. Default: "true" (Required.)
}
// CheckSuitePreferenceOptions set options for check suite preferences for a repository.
type CheckSuitePreferenceOptions struct {
PreferenceList *PreferenceList `json:"auto_trigger_checks,omitempty"` // A list of auto trigger checks that can be set for a check suite in a repository.
}
// CheckSuitePreferenceResults represents the results of the preference set operation.
type CheckSuitePreferenceResults struct {
Preferences *PreferenceList `json:"preferences,omitempty"`
Repository *Repository `json:"repository,omitempty"`
}
// PreferenceList represents a list of auto trigger checks for repository
type PreferenceList struct {
AutoTriggerChecks []*AutoTriggerCheck `json:"auto_trigger_checks,omitempty"` // A slice of auto trigger checks that can be set for a check suite in a repository.
}
// SetCheckSuitePreferences changes the default automatic flow when creating check suites.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#set-preferences-for-check-suites-on-a-repository
func (s *ChecksService) SetCheckSuitePreferences(ctx context.Context, owner, repo string, opt CheckSuitePreferenceOptions) (*CheckSuitePreferenceResults, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites/preferences", owner, repo)
req, err := s.client.NewRequest("PATCH", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
var checkSuitePrefResults *CheckSuitePreferenceResults
resp, err := s.client.Do(ctx, req, &checkSuitePrefResults)
if err != nil {
return nil, resp, err
}
return checkSuitePrefResults, resp, nil
}
// CreateCheckSuiteOptions sets up parameters to manually create a check suites
type CreateCheckSuiteOptions struct {
HeadSHA string `json:"head_sha"` // The sha of the head commit. (Required.)
HeadBranch *string `json:"head_branch,omitempty"` // The name of the head branch where the code changes are implemented.
}
// CreateCheckSuite manually creates a check suite for a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#create-a-check-suite
func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string, opt CreateCheckSuiteOptions) (*CheckSuite, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites", owner, repo)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
checkSuite := new(CheckSuite)
resp, err := s.client.Do(ctx, req, checkSuite)
if err != nil {
return nil, resp, err
}
return checkSuite, resp, nil
}
// ReRequestCheckSuite triggers GitHub to rerequest an existing check suite, without pushing new code to a repository.
//
// GitHub API docs: https://developer.github.com/v3/checks/suites/#rerequest-check-suite
func (s *ChecksService) ReRequestCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/rerequest", owner, repo, checkSuiteID)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, err
}
req.Header.Set("Accept", mediaTypeCheckRunsPreview)
resp, err := s.client.Do(ctx, req, nil)
return resp, err
}

View File

@@ -0,0 +1,479 @@
// Copyright 2018 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestChecksService_GetCheckRun(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-runs/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
fmt.Fprint(w, `{
"id": 1,
"name":"testCheckRun",
"status": "completed",
"conclusion": "neutral",
"started_at": "2018-05-04T01:14:52Z",
"completed_at": "2018-05-04T01:14:52Z"}`)
})
checkRun, _, err := client.Checks.GetCheckRun(context.Background(), "o", "r", 1)
if err != nil {
t.Errorf("Checks.GetCheckRun return error: %v", err)
}
startedAt, _ := time.Parse(time.RFC3339, "2018-05-04T01:14:52Z")
completeAt, _ := time.Parse(time.RFC3339, "2018-05-04T01:14:52Z")
want := &CheckRun{
ID: Int64(1),
Status: String("completed"),
Conclusion: String("neutral"),
StartedAt: &Timestamp{startedAt},
CompletedAt: &Timestamp{completeAt},
Name: String("testCheckRun"),
}
if !reflect.DeepEqual(checkRun, want) {
t.Errorf("Checks.GetCheckRun return %+v, want %+v", checkRun, want)
}
}
func TestChecksService_GetCheckSuite(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-suites/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
fmt.Fprint(w, `{
"id": 1,
"head_branch":"master",
"head_sha": "deadbeef",
"conclusion": "neutral",
"before": "deadbeefb",
"after": "deadbeefa",
"status": "completed"}`)
})
checkSuite, _, err := client.Checks.GetCheckSuite(context.Background(), "o", "r", 1)
if err != nil {
t.Errorf("Checks.GetCheckSuite return error: %v", err)
}
want := &CheckSuite{
ID: Int64(1),
HeadBranch: String("master"),
HeadSHA: String("deadbeef"),
AfterSHA: String("deadbeefa"),
BeforeSHA: String("deadbeefb"),
Status: String("completed"),
Conclusion: String("neutral"),
}
if !reflect.DeepEqual(checkSuite, want) {
t.Errorf("Checks.GetCheckSuite return %+v, want %+v", checkSuite, want)
}
}
func TestChecksService_CreateCheckRun(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-runs", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
fmt.Fprint(w, `{
"id": 1,
"name":"testCreateCheckRun",
"head_sha":"deadbeef",
"status": "in_progress",
"conclusion": null,
"started_at": "2018-05-04T01:14:52Z",
"completed_at": null,
"output":{"title": "Mighty test report", "summary":"", "text":""}}`)
})
startedAt, _ := time.Parse(time.RFC3339, "2018-05-04T01:14:52Z")
checkRunOpt := CreateCheckRunOptions{
HeadBranch: "master",
Name: "testCreateCheckRun",
HeadSHA: "deadbeef",
Status: String("in_progress"),
StartedAt: &Timestamp{startedAt},
Output: &CheckRunOutput{
Title: String("Mighty test report"),
Summary: String(""),
Text: String(""),
},
}
checkRun, _, err := client.Checks.CreateCheckRun(context.Background(), "o", "r", checkRunOpt)
if err != nil {
t.Errorf("Checks.CreateCheckRun return error: %v", err)
}
want := &CheckRun{
ID: Int64(1),
Status: String("in_progress"),
StartedAt: &Timestamp{startedAt},
HeadSHA: String("deadbeef"),
Name: String("testCreateCheckRun"),
Output: &CheckRunOutput{
Title: String("Mighty test report"),
Summary: String(""),
Text: String(""),
},
}
if !reflect.DeepEqual(checkRun, want) {
t.Errorf("Checks.CreateCheckRun return %+v, want %+v", checkRun, want)
}
}
func TestChecksService_ListCheckRunAnnotations(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-runs/1/annotations", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
testFormValues(t, r, values{
"page": "1",
})
fmt.Fprint(w, `[{
"path": "README.md",
"blob_href": "https://github.com/octocat/Hello-World/blob/837db83be4137ca555d9a5598d0a1ea2987ecfee/README.md",
"start_line": 2,
"end_line": 2,
"annotation_level": "warning",
"message": "Check your spelling for 'banaas'.",
"title": "Spell check",
"raw_details": "Do you mean 'bananas' or 'banana'?"}]`,
)
})
checkRunAnnotations, _, err := client.Checks.ListCheckRunAnnotations(context.Background(), "o", "r", 1, &ListOptions{Page: 1})
if err != nil {
t.Errorf("Checks.ListCheckRunAnnotations return error: %v", err)
}
want := []*CheckRunAnnotation{{
Path: String("README.md"),
BlobHRef: String("https://github.com/octocat/Hello-World/blob/837db83be4137ca555d9a5598d0a1ea2987ecfee/README.md"),
StartLine: Int(2),
EndLine: Int(2),
AnnotationLevel: String("warning"),
Message: String("Check your spelling for 'banaas'."),
RawDetails: String("Do you mean 'bananas' or 'banana'?"),
Title: String("Spell check"),
}}
if !reflect.DeepEqual(checkRunAnnotations, want) {
t.Errorf("Checks.ListCheckRunAnnotations returned %+v, want %+v", checkRunAnnotations, want)
}
}
func TestChecksService_UpdateCheckRun(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-runs/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
fmt.Fprint(w, `{
"id": 1,
"name":"testUpdateCheckRun",
"head_sha":"deadbeef",
"status": "completed",
"conclusion": "neutral",
"started_at": "2018-05-04T01:14:52Z",
"completed_at": "2018-05-04T01:14:52Z",
"output":{"title": "Mighty test report", "summary":"There are 0 failures, 2 warnings and 1 notice", "text":"You may have misspelled some words."}}`)
})
startedAt, _ := time.Parse(time.RFC3339, "2018-05-04T01:14:52Z")
updateCheckRunOpt := UpdateCheckRunOptions{
HeadBranch: String("master"),
Name: "testUpdateCheckRun",
HeadSHA: String("deadbeef"),
Status: String("completed"),
CompletedAt: &Timestamp{startedAt},
Output: &CheckRunOutput{
Title: String("Mighty test report"),
Summary: String("There are 0 failures, 2 warnings and 1 notice"),
Text: String("You may have misspelled some words."),
},
}
checkRun, _, err := client.Checks.UpdateCheckRun(context.Background(), "o", "r", 1, updateCheckRunOpt)
if err != nil {
t.Errorf("Checks.UpdateCheckRun return error: %v", err)
}
want := &CheckRun{
ID: Int64(1),
Status: String("completed"),
StartedAt: &Timestamp{startedAt},
CompletedAt: &Timestamp{startedAt},
Conclusion: String("neutral"),
HeadSHA: String("deadbeef"),
Name: String("testUpdateCheckRun"),
Output: &CheckRunOutput{
Title: String("Mighty test report"),
Summary: String("There are 0 failures, 2 warnings and 1 notice"),
Text: String("You may have misspelled some words."),
},
}
if !reflect.DeepEqual(checkRun, want) {
t.Errorf("Checks.UpdateCheckRun return %+v, want %+v", checkRun, want)
}
}
func TestChecksService_ListCheckRunsForRef(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/commits/master/check-runs", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
testFormValues(t, r, values{
"check_name": "testing",
"page": "1",
"status": "completed",
"filter": "all",
})
fmt.Fprint(w, `{"total_count":1,
"check_runs": [{
"id": 1,
"head_sha": "deadbeef",
"status": "completed",
"conclusion": "neutral",
"started_at": "2018-05-04T01:14:52Z",
"completed_at": "2018-05-04T01:14:52Z"}]}`,
)
})
opt := &ListCheckRunsOptions{
CheckName: String("testing"),
Status: String("completed"),
Filter: String("all"),
ListOptions: ListOptions{Page: 1},
}
checkRuns, _, err := client.Checks.ListCheckRunsForRef(context.Background(), "o", "r", "master", opt)
if err != nil {
t.Errorf("Checks.ListCheckRunsForRef return error: %v", err)
}
startedAt, _ := time.Parse(time.RFC3339, "2018-05-04T01:14:52Z")
want := &ListCheckRunsResults{
Total: Int(1),
CheckRuns: []*CheckRun{{
ID: Int64(1),
Status: String("completed"),
StartedAt: &Timestamp{startedAt},
CompletedAt: &Timestamp{startedAt},
Conclusion: String("neutral"),
HeadSHA: String("deadbeef"),
}},
}
if !reflect.DeepEqual(checkRuns, want) {
t.Errorf("Checks.ListCheckRunsForRef returned %+v, want %+v", checkRuns, want)
}
}
func TestChecksService_ListCheckRunsCheckSuite(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-suites/1/check-runs", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
testFormValues(t, r, values{
"check_name": "testing",
"page": "1",
"status": "completed",
"filter": "all",
})
fmt.Fprint(w, `{"total_count":1,
"check_runs": [{
"id": 1,
"head_sha": "deadbeef",
"status": "completed",
"conclusion": "neutral",
"started_at": "2018-05-04T01:14:52Z",
"completed_at": "2018-05-04T01:14:52Z"}]}`,
)
})
opt := &ListCheckRunsOptions{
CheckName: String("testing"),
Status: String("completed"),
Filter: String("all"),
ListOptions: ListOptions{Page: 1},
}
checkRuns, _, err := client.Checks.ListCheckRunsCheckSuite(context.Background(), "o", "r", 1, opt)
if err != nil {
t.Errorf("Checks.ListCheckRunsCheckSuite return error: %v", err)
}
startedAt, _ := time.Parse(time.RFC3339, "2018-05-04T01:14:52Z")
want := &ListCheckRunsResults{
Total: Int(1),
CheckRuns: []*CheckRun{{
ID: Int64(1),
Status: String("completed"),
StartedAt: &Timestamp{startedAt},
CompletedAt: &Timestamp{startedAt},
Conclusion: String("neutral"),
HeadSHA: String("deadbeef"),
}},
}
if !reflect.DeepEqual(checkRuns, want) {
t.Errorf("Checks.ListCheckRunsCheckSuite returned %+v, want %+v", checkRuns, want)
}
}
func TestChecksService_ListCheckSuiteForRef(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/commits/master/check-suites", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
testFormValues(t, r, values{
"check_name": "testing",
"page": "1",
"app_id": "2",
})
fmt.Fprint(w, `{"total_count":1,
"check_suites": [{
"id": 1,
"head_sha": "deadbeef",
"head_branch": "master",
"status": "completed",
"conclusion": "neutral",
"before": "deadbeefb",
"after": "deadbeefa"}]}`,
)
})
opt := &ListCheckSuiteOptions{
CheckName: String("testing"),
AppID: Int(2),
ListOptions: ListOptions{Page: 1},
}
checkSuites, _, err := client.Checks.ListCheckSuitesForRef(context.Background(), "o", "r", "master", opt)
if err != nil {
t.Errorf("Checks.ListCheckSuitesForRef return error: %v", err)
}
want := &ListCheckSuiteResults{
Total: Int(1),
CheckSuites: []*CheckSuite{{
ID: Int64(1),
Status: String("completed"),
Conclusion: String("neutral"),
HeadSHA: String("deadbeef"),
HeadBranch: String("master"),
BeforeSHA: String("deadbeefb"),
AfterSHA: String("deadbeefa"),
}},
}
if !reflect.DeepEqual(checkSuites, want) {
t.Errorf("Checks.ListCheckSuitesForRef returned %+v, want %+v", checkSuites, want)
}
}
func TestChecksService_SetCheckSuitePreferences(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-suites/preferences", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
fmt.Fprint(w, `{"preferences":{"auto_trigger_checks":[{"app_id": 2,"setting": false}]}}`)
})
p := &PreferenceList{
AutoTriggerChecks: []*AutoTriggerCheck{{
AppID: Int64(2),
Setting: Bool(false),
}},
}
opt := CheckSuitePreferenceOptions{PreferenceList: p}
prefResults, _, err := client.Checks.SetCheckSuitePreferences(context.Background(), "o", "r", opt)
if err != nil {
t.Errorf("Checks.SetCheckSuitePreferences return error: %v", err)
}
want := &CheckSuitePreferenceResults{
Preferences: p,
}
if !reflect.DeepEqual(prefResults, want) {
t.Errorf("Checks.SetCheckSuitePreferences return %+v, want %+v", prefResults, want)
}
}
func TestChecksService_CreateCheckSuite(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-suites", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
fmt.Fprint(w, `{
"id": 2,
"head_branch":"master",
"head_sha":"deadbeef",
"status": "completed",
"conclusion": "neutral",
"before": "deadbeefb",
"after": "deadbeefa"}`)
})
checkSuiteOpt := CreateCheckSuiteOptions{
HeadSHA: "deadbeef",
HeadBranch: String("master"),
}
checkSuite, _, err := client.Checks.CreateCheckSuite(context.Background(), "o", "r", checkSuiteOpt)
if err != nil {
t.Errorf("Checks.CreateCheckSuite return error: %v", err)
}
want := &CheckSuite{
ID: Int64(2),
Status: String("completed"),
HeadSHA: String("deadbeef"),
HeadBranch: String("master"),
Conclusion: String("neutral"),
BeforeSHA: String("deadbeefb"),
AfterSHA: String("deadbeefa"),
}
if !reflect.DeepEqual(checkSuite, want) {
t.Errorf("Checks.CreateCheckSuite return %+v, want %+v", checkSuite, want)
}
}
func TestChecksService_ReRequestCheckSuite(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/check-suites/1/rerequest", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeCheckRunsPreview)
w.WriteHeader(http.StatusCreated)
})
resp, err := client.Checks.ReRequestCheckSuite(context.Background(), "o", "r", 1)
if err != nil {
t.Errorf("Checks.ReRequestCheckSuite return error: %v", err)
}
if got, want := resp.StatusCode, http.StatusCreated; got != want {
t.Errorf("Checks.ReRequestCheckSuite = %v, want %v", got, want)
}
}

View File

@@ -30,6 +30,13 @@ The services of a client divide the API into logical chunks and correspond to
the structure of the GitHub API documentation at
https://developer.github.com/v3/.
NOTE: Using the https://godoc.org/context package, one can easily
pass cancelation signals and deadlines to various services of the client for
handling a request. In case there is no context available, then context.Background()
can be used as a starting point.
For more sample code snippets, head over to the https://github.com/google/go-github/tree/master/example directory.
Authentication
The go-github library does not directly handle authentication. Instead, when
@@ -176,16 +183,5 @@ github.Response struct.
opt.Page = resp.NextPage
}
Google App Engine
Go on App Engine Classic (which as of this writing uses Go 1.6) can not use
the "context" import and still relies on "golang.org/x/net/context".
As a result, if you wish to continue to use "go-github" on App Engine Classic,
you will need to rewrite all the "context" imports using the following command:
gofmt -w -r '"context" -> "golang.org/x/net/context"' *.go
See "with_appengine.go" for more details.
*/
package github

126
vendor/github.com/google/go-github/github/event.go generated vendored Normal file
View File

@@ -0,0 +1,126 @@
// Copyright 2018 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"encoding/json"
"time"
)
// Event represents a GitHub event.
type Event struct {
Type *string `json:"type,omitempty"`
Public *bool `json:"public,omitempty"`
RawPayload *json.RawMessage `json:"payload,omitempty"`
Repo *Repository `json:"repo,omitempty"`
Actor *User `json:"actor,omitempty"`
Org *Organization `json:"org,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
ID *string `json:"id,omitempty"`
}
func (e Event) String() string {
return Stringify(e)
}
// ParsePayload parses the event payload. For recognized event types,
// a value of the corresponding struct type will be returned.
func (e *Event) ParsePayload() (payload interface{}, err error) {
switch *e.Type {
case "CheckRunEvent":
payload = &CheckRunEvent{}
case "CheckSuiteEvent":
payload = &CheckSuiteEvent{}
case "CommitCommentEvent":
payload = &CommitCommentEvent{}
case "CreateEvent":
payload = &CreateEvent{}
case "DeleteEvent":
payload = &DeleteEvent{}
case "DeploymentEvent":
payload = &DeploymentEvent{}
case "DeploymentStatusEvent":
payload = &DeploymentStatusEvent{}
case "ForkEvent":
payload = &ForkEvent{}
case "GitHubAppAuthorizationEvent":
payload = &GitHubAppAuthorizationEvent{}
case "GollumEvent":
payload = &GollumEvent{}
case "InstallationEvent":
payload = &InstallationEvent{}
case "InstallationRepositoriesEvent":
payload = &InstallationRepositoriesEvent{}
case "IssueCommentEvent":
payload = &IssueCommentEvent{}
case "IssuesEvent":
payload = &IssuesEvent{}
case "LabelEvent":
payload = &LabelEvent{}
case "MarketplacePurchaseEvent":
payload = &MarketplacePurchaseEvent{}
case "MemberEvent":
payload = &MemberEvent{}
case "MembershipEvent":
payload = &MembershipEvent{}
case "MilestoneEvent":
payload = &MilestoneEvent{}
case "OrganizationEvent":
payload = &OrganizationEvent{}
case "OrgBlockEvent":
payload = &OrgBlockEvent{}
case "PageBuildEvent":
payload = &PageBuildEvent{}
case "PingEvent":
payload = &PingEvent{}
case "ProjectEvent":
payload = &ProjectEvent{}
case "ProjectCardEvent":
payload = &ProjectCardEvent{}
case "ProjectColumnEvent":
payload = &ProjectColumnEvent{}
case "PublicEvent":
payload = &PublicEvent{}
case "PullRequestEvent":
payload = &PullRequestEvent{}
case "PullRequestReviewEvent":
payload = &PullRequestReviewEvent{}
case "PullRequestReviewCommentEvent":
payload = &PullRequestReviewCommentEvent{}
case "PushEvent":
payload = &PushEvent{}
case "ReleaseEvent":
payload = &ReleaseEvent{}
case "RepositoryEvent":
payload = &RepositoryEvent{}
case "RepositoryVulnerabilityAlertEvent":
payload = &RepositoryVulnerabilityAlertEvent{}
case "StatusEvent":
payload = &StatusEvent{}
case "TeamEvent":
payload = &TeamEvent{}
case "TeamAddEvent":
payload = &TeamAddEvent{}
case "WatchEvent":
payload = &WatchEvent{}
}
err = json.Unmarshal(*e.RawPayload, &payload)
return payload, err
}
// Payload returns the parsed event payload. For recognized event types,
// a value of the corresponding struct type will be returned.
//
// Deprecated: Use ParsePayload instead, which returns an error
// rather than panics if JSON unmarshaling raw payload fails.
func (e *Event) Payload() (payload interface{}) {
var err error
payload, err = e.ParsePayload()
if err != nil {
panic(err)
}
return payload
}

View File

@@ -7,6 +7,47 @@
package github
// RequestedAction is included in a CheckRunEvent when a user has invoked an action,
// i.e. when the CheckRunEvent's Action field is "requested_action".
type RequestedAction struct {
Identifier string `json:"identifier"` // The integrator reference of the action requested by the user.
}
// CheckRunEvent is triggered when a check run is "created", "updated", or "re-requested".
// The Webhook event name is "check_run".
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checkrunevent
type CheckRunEvent struct {
CheckRun *CheckRun `json:"check_run,omitempty"`
// The action performed. Can be "created", "updated", "rerequested" or "requested_action".
Action *string `json:"action,omitempty"`
// The following fields are only populated by Webhook events.
Repo *Repository `json:"repository,omitempty"`
Org *Organization `json:"organization,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
// The action requested by the user. Populated when the Action is "requested_action".
RequestedAction *RequestedAction `json:"requested_action,omitempty"` //
}
// CheckSuiteEvent is triggered when a check suite is "completed", "requested", or "re-requested".
// The Webhook event name is "check_suite".
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checksuiteevent
type CheckSuiteEvent struct {
CheckSuite *CheckSuite `json:"check_suite,omitempty"`
// The action performed. Can be "completed", "requested" or "re-requested".
Action *string `json:"action,omitempty"`
// The following fields are only populated by Webhook events.
Repo *Repository `json:"repository,omitempty"`
Org *Organization `json:"organization,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
}
// CommitCommentEvent is triggered when a commit comment is created.
// The Webhook event name is "commit_comment".
//
@@ -107,6 +148,18 @@ type ForkEvent struct {
Installation *Installation `json:"installation,omitempty"`
}
// GitHubAppAuthorizationEvent is triggered when a user's authorization for a
// GitHub Application is revoked.
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#githubappauthorizationevent
type GitHubAppAuthorizationEvent struct {
// The action performed. Can be "revoked".
Action *string `json:"action,omitempty"`
// The following fields are only populated by Webhook events.
Sender *User `json:"sender,omitempty"`
}
// Page represents a single Wiki page.
type Page struct {
PageName *string `json:"page_name,omitempty"`
@@ -194,6 +247,7 @@ type TeamChange struct {
type InstallationEvent struct {
// The action that was performed. Can be either "created" or "deleted".
Action *string `json:"action,omitempty"`
Repositories []*Repository `json:"repositories,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
}
@@ -268,6 +322,24 @@ type LabelEvent struct {
Installation *Installation `json:"installation,omitempty"`
}
// MarketplacePurchaseEvent is triggered when a user purchases, cancels, or changes
// their GitHub Marketplace plan.
// Webhook event name "marketplace_purchase".
//
// Github API docs: https://developer.github.com/v3/activity/events/types/#marketplacepurchaseevent
type MarketplacePurchaseEvent struct {
// Action is the action that was performed. Possible values are:
// "purchased", "cancelled", "pending_change", "pending_change_cancelled", "changed".
Action *string `json:"action,omitempty"`
// The following fields are only populated by Webhook events.
EffectiveDate *Timestamp `json:"effective_date,omitempty"`
MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"`
PreviousMarketplacePurchase *MarketplacePurchase `json:"previous_marketplace_purchase,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
}
// MemberEvent is triggered when a user is added as a collaborator to a repository.
// The Webhook event name is "member".
//
@@ -374,7 +446,7 @@ type PageBuildEvent struct {
Build *PagesBuild `json:"build,omitempty"`
// The following fields are only populated by Webhook events.
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
@@ -387,7 +459,7 @@ type PingEvent struct {
// Random string of GitHub zen.
Zen *string `json:"zen,omitempty"`
// The ID of the webhook that triggered the ping.
HookID *int `json:"hook_id,omitempty"`
HookID *int64 `json:"hook_id,omitempty"`
// The webhook configuration.
Hook *Hook `json:"hook,omitempty"`
Installation *Installation `json:"installation,omitempty"`
@@ -416,7 +488,7 @@ type ProjectEvent struct {
type ProjectCardEvent struct {
Action *string `json:"action,omitempty"`
Changes *ProjectCardChange `json:"changes,omitempty"`
AfterID *int `json:"after_id,omitempty"`
AfterID *int64 `json:"after_id,omitempty"`
ProjectCard *ProjectCard `json:"project_card,omitempty"`
// The following fields are only populated by Webhook events.
@@ -433,7 +505,7 @@ type ProjectCardEvent struct {
type ProjectColumnEvent struct {
Action *string `json:"action,omitempty"`
Changes *ProjectColumnChange `json:"changes,omitempty"`
AfterID *int `json:"after_id,omitempty"`
AfterID *int64 `json:"after_id,omitempty"`
ProjectColumn *ProjectColumn `json:"project_column,omitempty"`
// The following fields are only populated by Webhook events.
@@ -461,20 +533,31 @@ type PublicEvent struct {
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestevent
type PullRequestEvent struct {
// Action is the action that was performed. Possible values are: "assigned",
// "unassigned", "labeled", "unlabeled", "opened", "closed", or "reopened",
// "synchronize", "edited". If the action is "closed" and the merged key is false,
// Action is the action that was performed. Possible values are:
// "assigned", "unassigned", "review_requested", "review_request_removed", "labeled", "unlabeled",
// "opened", "closed", "reopened", "synchronize", "edited".
// If the action is "closed" and the merged key is false,
// the pull request was closed with unmerged commits. If the action is "closed"
// and the merged key is true, the pull request was merged.
Action *string `json:"action,omitempty"`
Assignee *User `json:"assignee,omitempty"`
Number *int `json:"number,omitempty"`
PullRequest *PullRequest `json:"pull_request,omitempty"`
// The following fields are only populated by Webhook events.
Changes *EditChange `json:"changes,omitempty"`
Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
Changes *EditChange `json:"changes,omitempty"`
// RequestedReviewer is populated in "review_requested", "review_request_removed" event deliveries.
// A request affecting multiple reviewers at once is split into multiple
// such event deliveries, each with a single, different RequestedReviewer.
RequestedReviewer *User `json:"requested_reviewer,omitempty"`
Repo *Repository `json:"repository,omitempty"`
Sender *User `json:"sender,omitempty"`
Installation *Installation `json:"installation,omitempty"`
Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries.
// The following field is only present when the webhook is triggered on
// a repository belonging to an organization.
Organization *Organization `json:"organization,omitempty"`
}
// PullRequestReviewEvent is triggered when a review is submitted on a pull
@@ -521,7 +604,7 @@ type PullRequestReviewCommentEvent struct {
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pushevent
type PushEvent struct {
PushID *int `json:"push_id,omitempty"`
PushID *int64 `json:"push_id,omitempty"`
Head *string `json:"head,omitempty"`
Ref *string `json:"ref,omitempty"`
Size *int `json:"size,omitempty"`
@@ -573,38 +656,39 @@ func (p PushEventCommit) String() string {
// PushEventRepository represents the repo object in a PushEvent payload.
type PushEventRepository struct {
ID *int `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
FullName *string `json:"full_name,omitempty"`
Owner *PushEventRepoOwner `json:"owner,omitempty"`
Private *bool `json:"private,omitempty"`
Description *string `json:"description,omitempty"`
Fork *bool `json:"fork,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
PushedAt *Timestamp `json:"pushed_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
Homepage *string `json:"homepage,omitempty"`
Size *int `json:"size,omitempty"`
StargazersCount *int `json:"stargazers_count,omitempty"`
WatchersCount *int `json:"watchers_count,omitempty"`
Language *string `json:"language,omitempty"`
HasIssues *bool `json:"has_issues,omitempty"`
HasDownloads *bool `json:"has_downloads,omitempty"`
HasWiki *bool `json:"has_wiki,omitempty"`
HasPages *bool `json:"has_pages,omitempty"`
ForksCount *int `json:"forks_count,omitempty"`
OpenIssuesCount *int `json:"open_issues_count,omitempty"`
DefaultBranch *string `json:"default_branch,omitempty"`
MasterBranch *string `json:"master_branch,omitempty"`
Organization *string `json:"organization,omitempty"`
URL *string `json:"url,omitempty"`
ArchiveURL *string `json:"archive_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
StatusesURL *string `json:"statuses_url,omitempty"`
GitURL *string `json:"git_url,omitempty"`
SSHURL *string `json:"ssh_url,omitempty"`
CloneURL *string `json:"clone_url,omitempty"`
SVNURL *string `json:"svn_url,omitempty"`
ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Name *string `json:"name,omitempty"`
FullName *string `json:"full_name,omitempty"`
Owner *User `json:"owner,omitempty"`
Private *bool `json:"private,omitempty"`
Description *string `json:"description,omitempty"`
Fork *bool `json:"fork,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
PushedAt *Timestamp `json:"pushed_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
Homepage *string `json:"homepage,omitempty"`
Size *int `json:"size,omitempty"`
StargazersCount *int `json:"stargazers_count,omitempty"`
WatchersCount *int `json:"watchers_count,omitempty"`
Language *string `json:"language,omitempty"`
HasIssues *bool `json:"has_issues,omitempty"`
HasDownloads *bool `json:"has_downloads,omitempty"`
HasWiki *bool `json:"has_wiki,omitempty"`
HasPages *bool `json:"has_pages,omitempty"`
ForksCount *int `json:"forks_count,omitempty"`
OpenIssuesCount *int `json:"open_issues_count,omitempty"`
DefaultBranch *string `json:"default_branch,omitempty"`
MasterBranch *string `json:"master_branch,omitempty"`
Organization *string `json:"organization,omitempty"`
URL *string `json:"url,omitempty"`
ArchiveURL *string `json:"archive_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
StatusesURL *string `json:"statuses_url,omitempty"`
GitURL *string `json:"git_url,omitempty"`
SSHURL *string `json:"ssh_url,omitempty"`
CloneURL *string `json:"clone_url,omitempty"`
SVNURL *string `json:"svn_url,omitempty"`
}
// PushEventRepoOwner is a basic representation of user/org in a PushEvent payload.
@@ -647,6 +731,27 @@ type RepositoryEvent struct {
Installation *Installation `json:"installation,omitempty"`
}
// RepositoryVulnerabilityAlertEvent is triggered when a security alert is created, dismissed, or resolved.
//
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryvulnerabilityalertevent
type RepositoryVulnerabilityAlertEvent struct {
// Action is the action that was performed. This can be: "create", "dismiss", "resolve".
Action *string `json:"action,omitempty"`
//The security alert of the vulnerable dependency.
Alert *struct {
ID *int64 `json:"id,omitempty"`
AffectedRange *string `json:"affected_range,omitempty"`
AffectedPackageName *string `json:"affected_package_name,omitempty"`
ExternalReference *string `json:"external_reference,omitempty"`
ExternalIdentifier *string `json:"external_identifier,omitempty"`
FixedIn *string `json:"fixed_in,omitempty"`
Dismisser *User `json:"dismisser,omitempty"`
DismissReason *string `json:"dismiss_reason,omitempty"`
DismissedAt *Timestamp `json:"dismissed_at,omitempty"`
} `json:"alert,omitempty"`
}
// StatusEvent is triggered when the status of a Git commit changes.
// The Webhook event name is "status".
//
@@ -663,7 +768,7 @@ type StatusEvent struct {
Branches []*Branch `json:"branches,omitempty"`
// The following fields are only populated by Webhook events.
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
Context *string `json:"context,omitempty"`
Commit *RepositoryCommit `json:"commit,omitempty"`

View File

@@ -3,6 +3,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// These examples are inlined in godoc.
package github_test
import (
@@ -10,7 +12,7 @@ import (
"fmt"
"log"
"github.com/google/go-github/github"
"github.com/google/go-github/v19/github"
)
func ExampleClient_Markdown() {
@@ -59,6 +61,35 @@ func ExampleRepositoriesService_List() {
fmt.Printf("Recently updated repositories by %q: %v", user, github.Stringify(repos))
}
func ExampleRepositoriesService_CreateFile() {
// In this example we're creating a new file in a repository using the
// Contents API. Only 1 file per commit can be managed through that API.
// Note that authentication is needed here as you are performing a modification
// so you will need to modify the example to provide an oauth client to
// github.NewClient() instead of nil. See the following documentation for more
// information on how to authenticate with the client:
// https://godoc.org/github.com/google/go-github/github#hdr-Authentication
client := github.NewClient(nil)
ctx := context.Background()
fileContent := []byte("This is the content of my file\nand the 2nd line of it")
// Note: the file needs to be absent from the repository as you are not
// specifying a SHA reference here.
opts := &github.RepositoryContentFileOptions{
Message: github.String("This is my commit message"),
Content: fileContent,
Branch: github.String("master"),
Committer: &github.CommitAuthor{Name: github.String("FirstName LastName"), Email: github.String("user@example.com")},
}
_, _, err := client.Repositories.CreateFile(ctx, "myOrganization", "myRepository", "myNewFile.md", opts)
if err != nil {
fmt.Println(err)
return
}
}
func ExampleUsersService_ListAll() {
client := github.NewClient(nil)
opts := &github.UserListOptions{}
@@ -74,3 +105,66 @@ func ExampleUsersService_ListAll() {
// Process users...
}
}
func ExamplePullRequestsService_Create() {
// In this example we're creating a PR and displaying the HTML url at the end.
// Note that authentication is needed here as you are performing a modification
// so you will need to modify the example to provide an oauth client to
// github.NewClient() instead of nil. See the following documentation for more
// information on how to authenticate with the client:
// https://godoc.org/github.com/google/go-github/github#hdr-Authentication
client := github.NewClient(nil)
newPR := &github.NewPullRequest{
Title: github.String("My awesome pull request"),
Head: github.String("branch_to_merge"),
Base: github.String("master"),
Body: github.String("This is the description of the PR created with the package `github.com/google/go-github/github`"),
MaintainerCanModify: github.Bool(true),
}
pr, _, err := client.PullRequests.Create(context.Background(), "myOrganization", "myRepository", newPR)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("PR created: %s\n", pr.GetHTMLURL())
}
func ExampleTeamsService_ListTeams() {
// This example shows how to get a team ID corresponding to a given team name.
// Note that authentication is needed here as you are performing a lookup on
// an organization's administrative configuration, so you will need to modify
// the example to provide an oauth client to github.NewClient() instead of nil.
// See the following documentation for more information on how to authenticate
// with the client:
// https://godoc.org/github.com/google/go-github/github#hdr-Authentication
client := github.NewClient(nil)
teamName := "Developers team"
ctx := context.Background()
opts := &github.ListOptions{}
for {
teams, resp, err := client.Teams.ListTeams(ctx, "myOrganization", opts)
if err != nil {
fmt.Println(err)
return
}
for _, t := range teams {
if t.GetName() == teamName {
fmt.Printf("Team %q has ID %d\n", teamName, t.GetID())
return
}
}
if resp.NextPage == 0 {
break
}
opts.Page = resp.NextPage
}
fmt.Printf("Team %q was not found\n", teamName)
}

View File

@@ -25,7 +25,6 @@ import (
"sort"
"strings"
"text/template"
"time"
)
const (
@@ -37,8 +36,8 @@ var (
sourceTmpl = template.Must(template.New("source").Parse(source))
// blacklist lists which "struct.method" combos to not generate.
blacklist = map[string]bool{
// blacklistStructMethod lists "struct.method" combos to skip.
blacklistStructMethod = map[string]bool{
"RepositoryContent.GetContent": true,
"Client.GetBaseURL": true,
"Client.GetUploadURL": true,
@@ -46,6 +45,10 @@ var (
"RateLimitError.GetResponse": true,
"AbuseRateLimitError.GetResponse": true,
}
// blacklistStruct lists structs to skip.
blacklistStruct = map[string]bool{
"Client": true,
}
)
func logf(fmt string, args ...interface{}) {
@@ -67,7 +70,7 @@ func main() {
for pkgName, pkg := range pkgs {
t := &templateData{
filename: pkgName + fileSuffix,
Year: time.Now().Year(),
Year: 2017,
Package: pkgName,
Imports: map[string]string{},
}
@@ -95,6 +98,16 @@ func (t *templateData) processAST(f *ast.File) error {
if !ok {
continue
}
// Skip unexported identifiers.
if !ts.Name.IsExported() {
logf("Struct %v is unexported; skipping.", ts.Name)
continue
}
// Check if the struct is blacklisted.
if blacklistStruct[ts.Name.Name] {
logf("Struct %v is blacklisted; skipping.", ts.Name)
continue
}
st, ok := ts.Type.(*ast.StructType)
if !ok {
continue
@@ -106,8 +119,14 @@ func (t *templateData) processAST(f *ast.File) error {
}
fieldName := field.Names[0]
if key := fmt.Sprintf("%v.Get%v", ts.Name, fieldName); blacklist[key] {
logf("Method %v blacklisted; skipping.", key)
// Skip unexported identifiers.
if !fieldName.IsExported() {
logf("Field %v is unexported; skipping.", fieldName)
continue
}
// Check if "struct.method" is blacklisted.
if key := fmt.Sprintf("%v.Get%v", ts.Name, fieldName); blacklistStructMethod[key] {
logf("Method %v is blacklisted; skipping.", key)
continue
}
@@ -139,7 +158,7 @@ func (t *templateData) dump() error {
return nil
}
// Sort getters by ReceiverType.FieldName
// Sort getters by ReceiverType.FieldName.
sort.Sort(byName(t.Getters))
var buf bytes.Buffer
@@ -155,7 +174,7 @@ func (t *templateData) dump() error {
return ioutil.WriteFile(t.filename, clean, 0644)
}
func newGetter(receiverType, fieldName, fieldType, zeroValue string) *getter {
func newGetter(receiverType, fieldName, fieldType, zeroValue string, namedStruct bool) *getter {
return &getter{
sortVal: strings.ToLower(receiverType) + "." + strings.ToLower(fieldName),
ReceiverVar: strings.ToLower(receiverType[:1]),
@@ -163,6 +182,7 @@ func newGetter(receiverType, fieldName, fieldType, zeroValue string) *getter {
FieldName: fieldName,
FieldType: fieldType,
ZeroValue: zeroValue,
NamedStruct: namedStruct,
}
}
@@ -176,13 +196,14 @@ func (t *templateData) addArrayType(x *ast.ArrayType, receiverType, fieldName st
return
}
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, "[]"+eltType, "nil"))
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, "[]"+eltType, "nil", false))
}
func (t *templateData) addIdent(x *ast.Ident, receiverType, fieldName string) {
var zeroValue string
var namedStruct = false
switch x.String() {
case "int":
case "int", "int64":
zeroValue = "0"
case "string":
zeroValue = `""`
@@ -190,11 +211,12 @@ func (t *templateData) addIdent(x *ast.Ident, receiverType, fieldName string) {
zeroValue = "false"
case "Timestamp":
zeroValue = "Timestamp{}"
default: // other structs handled by their receivers directly.
return
default:
zeroValue = "nil"
namedStruct = true
}
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, x.String(), zeroValue))
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, x.String(), zeroValue, namedStruct))
}
func (t *templateData) addMapType(x *ast.MapType, receiverType, fieldName string) {
@@ -218,11 +240,11 @@ func (t *templateData) addMapType(x *ast.MapType, receiverType, fieldName string
fieldType := fmt.Sprintf("map[%v]%v", keyType, valueType)
zeroValue := fmt.Sprintf("map[%v]%v{}", keyType, valueType)
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue))
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false))
}
func (t *templateData) addSelectorExpr(x *ast.SelectorExpr, receiverType, fieldName string) {
if strings.ToLower(fieldName[:1]) == fieldName[:1] { // non-exported field
if strings.ToLower(fieldName[:1]) == fieldName[:1] { // Non-exported field.
return
}
@@ -243,7 +265,7 @@ func (t *templateData) addSelectorExpr(x *ast.SelectorExpr, receiverType, fieldN
if xX == "time" && x.Sel.Name == "Duration" {
zeroValue = "0"
}
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue))
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false))
default:
logf("addSelectorExpr: xX %q, type %q, field %q: unknown x=%+v; skipping.", xX, receiverType, fieldName, x)
}
@@ -258,12 +280,13 @@ type templateData struct {
}
type getter struct {
sortVal string // lower-case version of "ReceiverType.FieldName"
ReceiverVar string // the one-letter variable name to match the ReceiverType
sortVal string // Lower-case version of "ReceiverType.FieldName".
ReceiverVar string // The one-letter variable name to match the ReceiverType.
ReceiverType string
FieldName string
FieldType string
ZeroValue string
NamedStruct bool // Getter for named struct.
}
type byName []*getter
@@ -288,6 +311,15 @@ import (
)
{{end}}
{{range .Getters}}
{{if .NamedStruct}}
// Get{{.FieldName}} returns the {{.FieldName}} field.
func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() *{{.FieldType}} {
if {{.ReceiverVar}} == nil {
return {{.ZeroValue}}
}
return {{.ReceiverVar}}.{{.FieldName}}
}
{{else}}
// Get{{.FieldName}} returns the {{.FieldName}} field if it's non-nil, zero value otherwise.
func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() {{.FieldType}} {
if {{.ReceiverVar}} == nil || {{.ReceiverVar}}.{{.FieldName}} == nil {
@@ -296,4 +328,5 @@ func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() {{.FieldType}} {
return *{{.ReceiverVar}}.{{.FieldName}}
}
{{end}}
{{end}}
`

View File

@@ -30,6 +30,7 @@ type Gist struct {
GitPushURL *string `json:"git_push_url,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
func (g Gist) String() string {
@@ -60,6 +61,7 @@ type GistCommit struct {
User *User `json:"user,omitempty"`
ChangeStatus *CommitStats `json:"change_status,omitempty"`
CommittedAt *Timestamp `json:"committed_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
func (gc GistCommit) String() string {
@@ -73,6 +75,7 @@ type GistFork struct {
ID *string `json:"id,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
func (gf GistFork) String() string {
@@ -175,6 +178,7 @@ func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, er
if err != nil {
return nil, nil, err
}
gist := new(Gist)
resp, err := s.client.Do(ctx, req, gist)
if err != nil {
@@ -193,6 +197,7 @@ func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist,
if err != nil {
return nil, nil, err
}
gist := new(Gist)
resp, err := s.client.Do(ctx, req, gist)
if err != nil {
@@ -211,6 +216,7 @@ func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response
if err != nil {
return nil, nil, err
}
g := new(Gist)
resp, err := s.client.Do(ctx, req, g)
if err != nil {
@@ -229,6 +235,7 @@ func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist,
if err != nil {
return nil, nil, err
}
g := new(Gist)
resp, err := s.client.Do(ctx, req, g)
if err != nil {

View File

@@ -13,7 +13,7 @@ import (
// GistComment represents a Gist comment.
type GistComment struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
Body *string `json:"body,omitempty"`
User *User `json:"user,omitempty"`
@@ -51,7 +51,7 @@ func (s *GistsService) ListComments(ctx context.Context, gistID string, opt *Lis
// GetComment retrieves a single comment from a gist.
//
// GitHub API docs: https://developer.github.com/v3/gists/comments/#get-a-single-comment
func (s *GistsService) GetComment(ctx context.Context, gistID string, commentID int) (*GistComment, *Response, error) {
func (s *GistsService) GetComment(ctx context.Context, gistID string, commentID int64) (*GistComment, *Response, error) {
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
@@ -89,7 +89,7 @@ func (s *GistsService) CreateComment(ctx context.Context, gistID string, comment
// EditComment edits an existing gist comment.
//
// GitHub API docs: https://developer.github.com/v3/gists/comments/#edit-a-comment
func (s *GistsService) EditComment(ctx context.Context, gistID string, commentID int, comment *GistComment) (*GistComment, *Response, error) {
func (s *GistsService) EditComment(ctx context.Context, gistID string, commentID int64, comment *GistComment) (*GistComment, *Response, error) {
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID)
req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil {
@@ -108,7 +108,7 @@ func (s *GistsService) EditComment(ctx context.Context, gistID string, commentID
// DeleteComment deletes a gist comment.
//
// GitHub API docs: https://developer.github.com/v3/gists/comments/#delete-a-comment
func (s *GistsService) DeleteComment(ctx context.Context, gistID string, commentID int) (*Response, error) {
func (s *GistsService) DeleteComment(ctx context.Context, gistID string, commentID int64) (*Response, error) {
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {

View File

@@ -15,7 +15,7 @@ import (
)
func TestGistsService_ListComments(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -30,19 +30,22 @@ func TestGistsService_ListComments(t *testing.T) {
t.Errorf("Gists.Comments returned error: %v", err)
}
want := []*GistComment{{ID: Int(1)}}
want := []*GistComment{{ID: Int64(1)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Gists.ListComments returned %+v, want %+v", comments, want)
}
}
func TestGistsService_ListComments_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.ListComments(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestGistsService_GetComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/comments/2", func(w http.ResponseWriter, r *http.Request) {
@@ -55,22 +58,25 @@ func TestGistsService_GetComment(t *testing.T) {
t.Errorf("Gists.GetComment returned error: %v", err)
}
want := &GistComment{ID: Int(1)}
want := &GistComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Gists.GetComment returned %+v, want %+v", comment, want)
}
}
func TestGistsService_GetComment_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.GetComment(context.Background(), "%", 1)
testURLParseError(t, err)
}
func TestGistsService_CreateComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &GistComment{ID: Int(1), Body: String("b")}
input := &GistComment{ID: Int64(1), Body: String("b")}
mux.HandleFunc("/gists/1/comments", func(w http.ResponseWriter, r *http.Request) {
v := new(GistComment)
@@ -89,22 +95,25 @@ func TestGistsService_CreateComment(t *testing.T) {
t.Errorf("Gists.CreateComment returned error: %v", err)
}
want := &GistComment{ID: Int(1)}
want := &GistComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Gists.CreateComment returned %+v, want %+v", comment, want)
}
}
func TestGistsService_CreateComment_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.CreateComment(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestGistsService_EditComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &GistComment{ID: Int(1), Body: String("b")}
input := &GistComment{ID: Int64(1), Body: String("b")}
mux.HandleFunc("/gists/1/comments/2", func(w http.ResponseWriter, r *http.Request) {
v := new(GistComment)
@@ -123,19 +132,22 @@ func TestGistsService_EditComment(t *testing.T) {
t.Errorf("Gists.EditComment returned error: %v", err)
}
want := &GistComment{ID: Int(1)}
want := &GistComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Gists.EditComment returned %+v, want %+v", comment, want)
}
}
func TestGistsService_EditComment_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.EditComment(context.Background(), "%", 1, nil)
testURLParseError(t, err)
}
func TestGistsService_DeleteComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/comments/2", func(w http.ResponseWriter, r *http.Request) {
@@ -149,6 +161,9 @@ func TestGistsService_DeleteComment(t *testing.T) {
}
func TestGistsService_DeleteComment_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Gists.DeleteComment(context.Background(), "%", 1)
testURLParseError(t, err)
}

View File

@@ -16,7 +16,7 @@ import (
)
func TestGistsService_List_specifiedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
since := "2013-01-01T00:00:00Z"
@@ -42,7 +42,7 @@ func TestGistsService_List_specifiedUser(t *testing.T) {
}
func TestGistsService_List_authenticatedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists", func(w http.ResponseWriter, r *http.Request) {
@@ -62,12 +62,15 @@ func TestGistsService_List_authenticatedUser(t *testing.T) {
}
func TestGistsService_List_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.List(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestGistsService_ListAll(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
since := "2013-01-01T00:00:00Z"
@@ -93,7 +96,7 @@ func TestGistsService_ListAll(t *testing.T) {
}
func TestGistsService_ListStarred(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
since := "2013-01-01T00:00:00Z"
@@ -119,7 +122,7 @@ func TestGistsService_ListStarred(t *testing.T) {
}
func TestGistsService_Get(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1", func(w http.ResponseWriter, r *http.Request) {
@@ -139,12 +142,15 @@ func TestGistsService_Get(t *testing.T) {
}
func TestGistsService_Get_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.Get(context.Background(), "%")
testURLParseError(t, err)
}
func TestGistsService_GetRevision(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/s", func(w http.ResponseWriter, r *http.Request) {
@@ -164,12 +170,15 @@ func TestGistsService_GetRevision(t *testing.T) {
}
func TestGistsService_GetRevision_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.GetRevision(context.Background(), "%", "%")
testURLParseError(t, err)
}
func TestGistsService_Create(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Gist{
@@ -222,7 +231,7 @@ func TestGistsService_Create(t *testing.T) {
}
func TestGistsService_Edit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Gist{
@@ -278,12 +287,15 @@ func TestGistsService_Edit(t *testing.T) {
}
func TestGistsService_Edit_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.Edit(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestGistsService_ListCommits(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/commits", func(w http.ResponseWriter, r *http.Request) {
@@ -316,8 +328,8 @@ func TestGistsService_ListCommits(t *testing.T) {
want := []*GistCommit{{
URL: String("https://api.github.com/gists/1/1"),
Version: String("1"),
User: &User{ID: Int(1)},
CommittedAt: &Timestamp{time.Date(2010, 1, 1, 00, 00, 00, 0, time.UTC)},
User: &User{ID: Int64(1)},
CommittedAt: &Timestamp{time.Date(2010, time.January, 1, 00, 00, 00, 0, time.UTC)},
ChangeStatus: &CommitStats{
Additions: Int(180),
Deletions: Int(0),
@@ -330,7 +342,7 @@ func TestGistsService_ListCommits(t *testing.T) {
}
func TestGistsService_ListCommits_withOptions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/commits", func(w http.ResponseWriter, r *http.Request) {
@@ -348,7 +360,7 @@ func TestGistsService_ListCommits_withOptions(t *testing.T) {
}
func TestGistsService_Delete(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1", func(w http.ResponseWriter, r *http.Request) {
@@ -362,12 +374,15 @@ func TestGistsService_Delete(t *testing.T) {
}
func TestGistsService_Delete_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Gists.Delete(context.Background(), "%")
testURLParseError(t, err)
}
func TestGistsService_Star(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
@@ -381,12 +396,15 @@ func TestGistsService_Star(t *testing.T) {
}
func TestGistsService_Star_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Gists.Star(context.Background(), "%")
testURLParseError(t, err)
}
func TestGistsService_Unstar(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
@@ -400,12 +418,15 @@ func TestGistsService_Unstar(t *testing.T) {
}
func TestGistsService_Unstar_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Gists.Unstar(context.Background(), "%")
testURLParseError(t, err)
}
func TestGistsService_IsStarred_hasStar(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
@@ -423,7 +444,7 @@ func TestGistsService_IsStarred_hasStar(t *testing.T) {
}
func TestGistsService_IsStarred_noStar(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/star", func(w http.ResponseWriter, r *http.Request) {
@@ -441,12 +462,15 @@ func TestGistsService_IsStarred_noStar(t *testing.T) {
}
func TestGistsService_IsStarred_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.IsStarred(context.Background(), "%")
testURLParseError(t, err)
}
func TestGistsService_Fork(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/forks", func(w http.ResponseWriter, r *http.Request) {
@@ -466,7 +490,7 @@ func TestGistsService_Fork(t *testing.T) {
}
func TestGistsService_ListForks(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gists/1/forks", func(w http.ResponseWriter, r *http.Request) {
@@ -492,9 +516,9 @@ func TestGistsService_ListForks(t *testing.T) {
want := []*GistFork{{
URL: String("https://api.github.com/gists/1"),
ID: String("1"),
User: &User{ID: Int(1)},
CreatedAt: &Timestamp{time.Date(2010, 1, 1, 00, 00, 00, 0, time.UTC)},
UpdatedAt: &Timestamp{time.Date(2013, 1, 1, 00, 00, 00, 0, time.UTC)}}}
User: &User{ID: Int64(1)},
CreatedAt: &Timestamp{time.Date(2010, time.January, 1, 00, 00, 00, 0, time.UTC)},
UpdatedAt: &Timestamp{time.Date(2013, time.January, 1, 00, 00, 00, 0, time.UTC)}}}
if !reflect.DeepEqual(gistForks, want) {
t.Errorf("Gists.ListForks returned %+v, want %+v", gistForks, want)
@@ -502,6 +526,9 @@ func TestGistsService_ListForks(t *testing.T) {
}
func TestGistsService_Fork_invalidID(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gists.Fork(context.Background(), "%")
testURLParseError(t, err)
}

View File

@@ -6,6 +6,7 @@
package github
import (
"bytes"
"context"
"fmt"
)
@@ -17,9 +18,10 @@ type Blob struct {
SHA *string `json:"sha,omitempty"`
Size *int `json:"size,omitempty"`
URL *string `json:"url,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
// GetBlob fetchs a blob from a repo given a SHA.
// GetBlob fetches a blob from a repo given a SHA.
//
// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob
func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) {
@@ -34,6 +36,23 @@ func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha
return blob, resp, err
}
// GetBlobRaw fetches a blob's contents from a repo.
// Unlike GetBlob, it returns the raw bytes rather than the base64-encoded data.
//
// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob
func (s *GitService) GetBlobRaw(ctx context.Context, owner, repo, sha string) ([]byte, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", "application/vnd.github.v3.raw")
var buf bytes.Buffer
resp, err := s.client.Do(ctx, req, &buf)
return buf.Bytes(), resp, err
}
// CreateBlob creates a blob object.
//
// GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob

View File

@@ -6,6 +6,7 @@
package github
import (
"bytes"
"context"
"encoding/json"
"fmt"
@@ -15,13 +16,12 @@ import (
)
func TestGitService_GetBlob(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/blobs/s", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
testMethod(t, r, "GET")
fmt.Fprint(w, `{
"sha": "s",
"content": "blob content"
@@ -44,12 +44,37 @@ func TestGitService_GetBlob(t *testing.T) {
}
func TestGitService_GetBlob_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Git.GetBlob(context.Background(), "%", "%", "%")
testURLParseError(t, err)
}
func TestGitService_GetBlobRaw(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/blobs/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", "application/vnd.github.v3.raw")
fmt.Fprint(w, `raw contents here`)
})
blob, _, err := client.Git.GetBlobRaw(context.Background(), "o", "r", "s")
if err != nil {
t.Errorf("Git.GetBlobRaw returned error: %v", err)
}
want := []byte("raw contents here")
if !bytes.Equal(blob, want) {
t.Errorf("GetBlobRaw returned %q, want %q", blob, want)
}
}
func TestGitService_CreateBlob(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Blob{
@@ -63,9 +88,7 @@ func TestGitService_CreateBlob(t *testing.T) {
v := new(Blob)
json.NewDecoder(r.Body).Decode(v)
if m := "POST"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
testMethod(t, r, "POST")
want := input
if !reflect.DeepEqual(v, want) {
@@ -93,6 +116,9 @@ func TestGitService_CreateBlob(t *testing.T) {
}
func TestGitService_CreateBlob_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Git.CreateBlob(context.Background(), "%", "%", &Blob{})
testURLParseError(t, err)
}

View File

@@ -31,6 +31,7 @@ type Commit struct {
HTMLURL *string `json:"html_url,omitempty"`
URL *string `json:"url,omitempty"`
Verification *SignatureVerification `json:"verification,omitempty"`
NodeID *string `json:"node_id,omitempty"`
// CommentCount is the number of GitHub comments on the commit. This
// is only populated for requests that fetch GitHub data like
@@ -57,7 +58,7 @@ func (c CommitAuthor) String() string {
return Stringify(c)
}
// GetCommit fetchs the Commit object for a given SHA.
// GetCommit fetches the Commit object for a given SHA.
//
// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit
func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) {
@@ -67,7 +68,7 @@ func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, s
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
c := new(Commit)

View File

@@ -15,7 +15,7 @@ import (
)
func TestGitService_GetCommit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/commits/s", func(w http.ResponseWriter, r *http.Request) {
@@ -36,12 +36,15 @@ func TestGitService_GetCommit(t *testing.T) {
}
func TestGitService_GetCommit_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Git.GetCommit(context.Background(), "%", "%", "%")
testURLParseError(t, err)
}
func TestGitService_CreateCommit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Commit{
@@ -79,6 +82,9 @@ func TestGitService_CreateCommit(t *testing.T) {
}
func TestGitService_CreateCommit_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Git.CreateCommit(context.Background(), "%", "%", &Commit{})
testURLParseError(t, err)
}

View File

@@ -18,6 +18,7 @@ type Reference struct {
Ref *string `json:"ref"`
URL *string `json:"url"`
Object *GitObject `json:"object"`
NodeID *string `json:"node_id,omitempty"`
}
func (r Reference) String() string {

View File

@@ -15,7 +15,7 @@ import (
)
func TestGitService_GetRef_singleRef(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
@@ -57,7 +57,7 @@ func TestGitService_GetRef_singleRef(t *testing.T) {
}
func TestGitService_GetRef_multipleRefs(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
@@ -95,7 +95,7 @@ func TestGitService_GetRef_multipleRefs(t *testing.T) {
}
func TestGitService_GetRefs_singleRef(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
@@ -138,7 +138,7 @@ func TestGitService_GetRefs_singleRef(t *testing.T) {
}
func TestGitService_GetRefs_multipleRefs(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
@@ -188,7 +188,7 @@ func TestGitService_GetRefs_multipleRefs(t *testing.T) {
// TestGitService_GetRefs_noRefs tests for behaviour resulting from an unexpected GH response. This should never actually happen.
func TestGitService_GetRefs_noRefs(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {
@@ -205,7 +205,7 @@ func TestGitService_GetRefs_noRefs(t *testing.T) {
}
func TestGitService_ListRefs(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs", func(w http.ResponseWriter, r *http.Request) {
@@ -264,7 +264,7 @@ func TestGitService_ListRefs(t *testing.T) {
}
func TestGitService_ListRefs_options(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/t", func(w http.ResponseWriter, r *http.Request) {
@@ -286,7 +286,7 @@ func TestGitService_ListRefs_options(t *testing.T) {
}
func TestGitService_CreateRef(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
args := &createRefRequest{
@@ -350,7 +350,7 @@ func TestGitService_CreateRef(t *testing.T) {
}
func TestGitService_UpdateRef(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
args := &updateRefRequest{
@@ -410,7 +410,7 @@ func TestGitService_UpdateRef(t *testing.T) {
}
func TestGitService_DeleteRef(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/refs/heads/b", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -19,6 +19,7 @@ type Tag struct {
Tagger *CommitAuthor `json:"tagger,omitempty"`
Object *GitObject `json:"object,omitempty"`
Verification *SignatureVerification `json:"verification,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
// createTagRequest represents the body of a CreateTag request. This is mostly
@@ -32,7 +33,7 @@ type createTagRequest struct {
Tagger *CommitAuthor `json:"tagger,omitempty"`
}
// GetTag fetchs a tag from a repo given a SHA.
// GetTag fetches a tag from a repo given a SHA.
//
// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag
func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) {
@@ -42,7 +43,7 @@ func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
tag := new(Tag)

View File

@@ -15,13 +15,12 @@ import (
)
func TestGitService_GetTag(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/tags/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
fmt.Fprint(w, `{"tag": "t"}`)
})
@@ -37,7 +36,7 @@ func TestGitService_GetTag(t *testing.T) {
}
func TestGitService_CreateTag(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &createTagRequest{Tag: String("t"), Object: String("s")}

View File

@@ -14,6 +14,12 @@ import (
type Tree struct {
SHA *string `json:"sha,omitempty"`
Entries []TreeEntry `json:"tree,omitempty"`
// Truncated is true if the number of items in the tree
// exceeded GitHub's maximum limit and the Entries were truncated
// in the response. Only populated for requests that fetch
// trees like Git.GetTree.
Truncated *bool `json:"truncated,omitempty"`
}
func (t Tree) String() string {

View File

@@ -15,16 +15,15 @@ import (
)
func TestGitService_GetTree(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/git/trees/s", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
testMethod(t, r, "GET")
fmt.Fprint(w, `{
"sha": "s",
"tree": [ { "type": "blob" } ]
"tree": [ { "type": "blob" } ],
"truncated": true
}`)
})
@@ -40,6 +39,7 @@ func TestGitService_GetTree(t *testing.T) {
Type: String("blob"),
},
},
Truncated: Bool(true),
}
if !reflect.DeepEqual(*tree, want) {
t.Errorf("Tree.Get returned %+v, want %+v", *tree, want)
@@ -47,12 +47,15 @@ func TestGitService_GetTree(t *testing.T) {
}
func TestGitService_GetTree_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Git.GetTree(context.Background(), "%", "%", "%", false)
testURLParseError(t, err)
}
func TestGitService_CreateTree(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := []TreeEntry{
@@ -68,9 +71,7 @@ func TestGitService_CreateTree(t *testing.T) {
v := new(createTree)
json.NewDecoder(r.Body).Decode(v)
if m := "POST"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
testMethod(t, r, "POST")
want := &createTree{
BaseTree: "b",
@@ -110,6 +111,7 @@ func TestGitService_CreateTree(t *testing.T) {
SHA: String("7c258a9869f33c1e1e1f74fbb32f07c86cb5a75b"),
},
},
nil,
}
if !reflect.DeepEqual(*tree, want) {
@@ -118,7 +120,7 @@ func TestGitService_CreateTree(t *testing.T) {
}
func TestGitService_CreateTree_Content(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := []TreeEntry{
@@ -133,9 +135,7 @@ func TestGitService_CreateTree_Content(t *testing.T) {
v := new(createTree)
json.NewDecoder(r.Body).Decode(v)
if m := "POST"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
testMethod(t, r, "POST")
want := &createTree{
BaseTree: "b",
@@ -178,6 +178,7 @@ func TestGitService_CreateTree_Content(t *testing.T) {
URL: String("https://api.github.com/repos/o/r/git/blobs/aad8feacf6f8063150476a7b2bd9770f2794c08b"),
},
},
nil,
}
if !reflect.DeepEqual(*tree, want) {
@@ -186,6 +187,9 @@ func TestGitService_CreateTree_Content(t *testing.T) {
}
func TestGitService_CreateTree_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Git.CreateTree(context.Background(), "%", "%", "", nil)
testURLParseError(t, err)
}

File diff suppressed because it is too large Load Diff

View File

@@ -27,10 +27,9 @@ import (
)
const (
libraryVersion = "12"
defaultBaseURL = "https://api.github.com/"
uploadBaseURL = "https://uploads.github.com/"
userAgent = "go-github/" + libraryVersion
userAgent = "go-github"
headerRateLimit = "X-RateLimit-Limit"
headerRateRemaining = "X-RateLimit-Remaining"
@@ -46,21 +45,18 @@ const (
// Media Type values to access preview APIs
// 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-11-11-protected-branches-api/
mediaTypeProtectedBranchesPreview = "application/vnd.github.loki-preview+json"
// https://help.github.com/enterprise/2.4/admin/guides/migrations/exporting-the-github-com-organization-s-repositories/
mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json"
// https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/
mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json"
// https://developer.github.com/changes/2018-10-16-deployments-environments-states-and-auto-inactive-updates/
mediaTypeExpandDeploymentStatusPreview = "application/vnd.github.flash-preview+json"
// https://developer.github.com/changes/2016-02-19-source-import-preview-api/
mediaTypeImportPreview = "application/vnd.github.barred-rock-preview"
@@ -100,8 +96,41 @@ const (
// https://developer.github.com/changes/2017-07-17-update-topics-on-repositories/
mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json"
// https://developer.github.com/changes/2017-07-26-team-review-request-thor-preview/
mediaTypeTeamReviewPreview = "application/vnd.github.thor-preview+json"
// https://developer.github.com/changes/2017-08-30-preview-nested-teams/
mediaTypeNestedTeamsPreview = "application/vnd.github.hellcat-preview+json"
// https://developer.github.com/changes/2017-11-09-repository-transfer-api-preview/
mediaTypeRepositoryTransferPreview = "application/vnd.github.nightshade-preview+json"
// https://developer.github.com/changes/2018-01-25-organization-invitation-api-preview/
mediaTypeOrganizationInvitationPreview = "application/vnd.github.dazzler-preview+json"
// https://developer.github.com/changes/2018-03-16-protected-branches-required-approving-reviews/
mediaTypeRequiredApprovingReviewsPreview = "application/vnd.github.luke-cage-preview+json"
// https://developer.github.com/changes/2018-02-22-label-description-search-preview/
mediaTypeLabelDescriptionSearchPreview = "application/vnd.github.symmetra-preview+json"
// https://developer.github.com/changes/2018-02-07-team-discussions-api/
mediaTypeTeamDiscussionsPreview = "application/vnd.github.echo-preview+json"
// https://developer.github.com/changes/2018-03-21-hovercard-api-preview/
mediaTypeHovercardPreview = "application/vnd.github.hagar-preview+json"
// https://developer.github.com/changes/2018-01-10-lock-reason-api-preview/
mediaTypeLockReasonPreview = "application/vnd.github.sailor-v-preview+json"
// https://developer.github.com/changes/2018-05-07-new-checks-api-public-beta/
mediaTypeCheckRunsPreview = "application/vnd.github.antiope-preview+json"
// https://developer.github.com/enterprise/2.13/v3/repos/pre_receive_hooks/
mediaTypePreReceiveHooksPreview = "application/vnd.github.eye-scream-preview"
// https://developer.github.com/changes/2018-02-22-protected-branches-required-signatures/
mediaTypeSignaturePreview = "application/vnd.github.zzzax-preview+json"
// https://developer.github.com/changes/2018-09-05-project-card-events/
mediaTypeProjectCardDetailsPreview = "application/vnd.github.starfox-preview+json"
)
// A Client manages communication with the GitHub API.
@@ -130,19 +159,22 @@ type Client struct {
Admin *AdminService
Apps *AppsService
Authorizations *AuthorizationsService
Checks *ChecksService
Gists *GistsService
Git *GitService
Gitignores *GitignoresService
Issues *IssuesService
Licenses *LicensesService
Marketplace *MarketplaceService
Migrations *MigrationService
Organizations *OrganizationsService
Projects *ProjectsService
PullRequests *PullRequestsService
Reactions *ReactionsService
Repositories *RepositoriesService
Search *SearchService
Teams *TeamsService
Users *UsersService
Licenses *LicensesService
Migrations *MigrationService
Reactions *ReactionsService
}
type service struct {
@@ -219,11 +251,13 @@ func NewClient(httpClient *http.Client) *Client {
c.Admin = (*AdminService)(&c.common)
c.Apps = (*AppsService)(&c.common)
c.Authorizations = (*AuthorizationsService)(&c.common)
c.Checks = (*ChecksService)(&c.common)
c.Gists = (*GistsService)(&c.common)
c.Git = (*GitService)(&c.common)
c.Gitignores = (*GitignoresService)(&c.common)
c.Issues = (*IssuesService)(&c.common)
c.Licenses = (*LicensesService)(&c.common)
c.Marketplace = &MarketplaceService{client: c}
c.Migrations = (*MigrationService)(&c.common)
c.Organizations = (*OrganizationsService)(&c.common)
c.Projects = (*ProjectsService)(&c.common)
@@ -231,10 +265,42 @@ func NewClient(httpClient *http.Client) *Client {
c.Reactions = (*ReactionsService)(&c.common)
c.Repositories = (*RepositoriesService)(&c.common)
c.Search = (*SearchService)(&c.common)
c.Teams = (*TeamsService)(&c.common)
c.Users = (*UsersService)(&c.common)
return c
}
// NewEnterpriseClient returns a new GitHub API client with provided
// base URL and upload URL (often the same URL).
// If either URL does not have a trailing slash, one is added automatically.
// If a nil httpClient is provided, http.DefaultClient will be used.
//
// Note that NewEnterpriseClient is a convenience helper only;
// its behavior is equivalent to using NewClient, followed by setting
// the BaseURL and UploadURL fields.
func NewEnterpriseClient(baseURL, uploadURL string, httpClient *http.Client) (*Client, error) {
baseEndpoint, err := url.Parse(baseURL)
if err != nil {
return nil, err
}
if !strings.HasSuffix(baseEndpoint.Path, "/") {
baseEndpoint.Path += "/"
}
uploadEndpoint, err := url.Parse(uploadURL)
if err != nil {
return nil, err
}
if !strings.HasSuffix(uploadEndpoint.Path, "/") {
uploadEndpoint.Path += "/"
}
c := NewClient(httpClient)
c.BaseURL = baseEndpoint
c.UploadURL = uploadEndpoint
return c, nil
}
// NewRequest creates an API request. A relative URL can be provided in urlStr,
// in which case it is resolved relative to the BaseURL of the Client.
// Relative URLs should always be specified without a preceding slash. If
@@ -252,7 +318,9 @@ func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Requ
var buf io.ReadWriter
if body != nil {
buf = new(bytes.Buffer)
err := json.NewEncoder(buf).Encode(body)
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(false)
err := enc.Encode(body)
if err != nil {
return nil, err
}
@@ -316,7 +384,9 @@ type Response struct {
FirstPage int
LastPage int
Rate
// Explicitly specify the Rate type so Rate's String() receiver doesn't
// propagate to Response.
Rate Rate
}
// newResponse creates a new Response for the provided http.Response.
@@ -431,12 +501,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
return nil, err
}
defer func() {
// Drain up to 512 bytes and close the body to let the Transport reuse the connection
io.CopyN(ioutil.Discard, resp.Body, 512)
resp.Body.Close()
}()
defer resp.Body.Close()
response := newResponse(resp)
@@ -446,8 +511,22 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
err = CheckResponse(resp)
if err != nil {
// even though there was an error, we still return the response
// in case the caller wants to inspect it further
// Special case for AcceptedErrors. If an AcceptedError
// has been encountered, the response's payload will be
// added to the AcceptedError and returned.
//
// Issue #1022
aerr, ok := err.(*AcceptedError)
if ok {
b, readErr := ioutil.ReadAll(resp.Body)
if readErr != nil {
return response, readErr
}
aerr.Raw = b
return response, aerr
}
return response, err
}
@@ -455,9 +534,12 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
if w, ok := v.(io.Writer); ok {
io.Copy(w, resp.Body)
} else {
err = json.NewDecoder(resp.Body).Decode(v)
if err == io.EOF {
err = nil // ignore EOF errors caused by empty response body
decErr := json.NewDecoder(resp.Body).Decode(v)
if decErr == io.EOF {
decErr = nil // ignore EOF errors caused by empty response body
}
if decErr != nil {
err = decErr
}
}
}
@@ -547,14 +629,17 @@ func (r *RateLimitError) Error() string {
// Technically, 202 Accepted is not a real error, it's just used to
// indicate that results are not ready yet, but should be available soon.
// The request can be repeated after some time.
type AcceptedError struct{}
type AcceptedError struct {
// Raw contains the response body.
Raw []byte
}
func (*AcceptedError) Error() string {
return "job scheduled on GitHub side; try again later"
}
// AbuseRateLimitError occurs when GitHub returns 403 Forbidden response with the
// "documentation_url" field value equal to "https://developer.github.com/v3#abuse-rate-limits".
// "documentation_url" field value equal to "https://developer.github.com/v3/#abuse-rate-limits".
type AbuseRateLimitError struct {
Response *http.Response // HTTP response that caused this error
Message string `json:"message"` // error message
@@ -646,7 +731,7 @@ func CheckResponse(r *http.Response) error {
Response: errorResponse.Response,
Message: errorResponse.Message,
}
case r.StatusCode == http.StatusForbidden && errorResponse.DocumentationURL == "https://developer.github.com/v3#abuse-rate-limits":
case r.StatusCode == http.StatusForbidden && strings.HasSuffix(errorResponse.DocumentationURL, "/v3/#abuse-rate-limits"):
abuseRateLimitError := &AbuseRateLimitError{
Response: errorResponse.Response,
Message: errorResponse.Message,
@@ -812,14 +897,21 @@ func (t *UnauthenticatedRateLimitedTransport) RoundTrip(req *http.Request) (*htt
// To set extra querystring params, we must make a copy of the Request so
// that we don't modify the Request we were given. This is required by the
// specification of http.RoundTripper.
req = cloneRequest(req)
q := req.URL.Query()
//
// Since we are going to modify only req.URL here, we only need a deep copy
// of req.URL.
req2 := new(http.Request)
*req2 = *req
req2.URL = new(url.URL)
*req2.URL = *req.URL
q := req2.URL.Query()
q.Set("client_id", t.ClientID)
q.Set("client_secret", t.ClientSecret)
req.URL.RawQuery = q.Encode()
req2.URL.RawQuery = q.Encode()
// Make the HTTP request.
return t.transport().RoundTrip(req)
return t.transport().RoundTrip(req2)
}
// Client returns an *http.Client that makes requests which are subject to the
@@ -851,12 +943,24 @@ type BasicAuthTransport struct {
// RoundTrip implements the RoundTripper interface.
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req = cloneRequest(req) // per RoundTrip contract
req.SetBasicAuth(t.Username, t.Password)
if t.OTP != "" {
req.Header.Set(headerOTP, t.OTP)
// To set extra headers, we must make a copy of the Request so
// that we don't modify the Request we were given. This is required by the
// specification of http.RoundTripper.
//
// Since we are going to modify only req.Header here, we only need a deep copy
// of req.Header.
req2 := new(http.Request)
*req2 = *req
req2.Header = make(http.Header, len(req.Header))
for k, s := range req.Header {
req2.Header[k] = append([]string(nil), s...)
}
return t.transport().RoundTrip(req)
req2.SetBasicAuth(t.Username, t.Password)
if t.OTP != "" {
req2.Header.Set(headerOTP, t.OTP)
}
return t.transport().RoundTrip(req2)
}
// Client returns an *http.Client that makes requests that are authenticated
@@ -872,20 +976,6 @@ func (t *BasicAuthTransport) transport() http.RoundTripper {
return http.DefaultTransport
}
// cloneRequest returns a clone of the provided *http.Request. The clone is a
// shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header, len(r.Header))
for k, s := range r.Header {
r2.Header[k] = append([]string(nil), s...)
}
return r2
}
// formatRateReset formats d to look like "[rate reset in 2s]" or
// "[rate reset in 87m02s]" for the positive durations. And like "[rate limit was reset 87m02s ago]"
// for the negative cases.
@@ -919,6 +1009,10 @@ func Bool(v bool) *bool { return &v }
// to store v and returns a pointer to it.
func Int(v int) *int { return &v }
// Int64 is a helper routine that allocates a new int64 value
// to store v and returns a pointer to it.
func Int64(v int64) *int64 { return &v }
// String is a helper routine that allocates a new string value
// to store v and returns a pointer to it.
func String(v string) *string { return &v }

View File

@@ -22,35 +22,45 @@ import (
"time"
)
var (
// mux is the HTTP request multiplexer used with the test server.
mux *http.ServeMux
// client is the GitHub client being tested.
client *Client
// server is a test HTTP server used to provide mock API responses.
server *httptest.Server
const (
// baseURLPath is a non-empty Client.BaseURL path to use during tests,
// to ensure relative URLs are used for all endpoints. See issue #752.
baseURLPath = "/api-v3"
)
// setup sets up a test HTTP server along with a github.Client that is
// configured to talk to that test server. Tests should register handlers on
// mux which provide mock responses for the API method being tested.
func setup() {
// test server
func setup() (client *Client, mux *http.ServeMux, serverURL string, teardown func()) {
// mux is the HTTP request multiplexer used with the test server.
mux = http.NewServeMux()
server = httptest.NewServer(mux)
// github client configured to use test server
// We want to ensure that tests catch mistakes where the endpoint URL is
// specified as absolute rather than relative. It only makes a difference
// when there's a non-empty base URL path. So, use that. See issue #752.
apiHandler := http.NewServeMux()
apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, mux))
apiHandler.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintln(os.Stderr, "FAIL: Client.BaseURL path prefix is not preserved in the request URL:")
fmt.Fprintln(os.Stderr)
fmt.Fprintln(os.Stderr, "\t"+req.URL.String())
fmt.Fprintln(os.Stderr)
fmt.Fprintln(os.Stderr, "\tDid you accidentally use an absolute endpoint URL rather than relative?")
fmt.Fprintln(os.Stderr, "\tSee https://github.com/google/go-github/issues/752 for information.")
http.Error(w, "Client.BaseURL path prefix is not preserved in the request URL.", http.StatusInternalServerError)
})
// server is a test HTTP server used to provide mock API responses.
server := httptest.NewServer(apiHandler)
// client is the GitHub client being tested and is
// configured to use test server.
client = NewClient(nil)
url, _ := url.Parse(server.URL + "/")
url, _ := url.Parse(server.URL + baseURLPath + "/")
client.BaseURL = url
client.UploadURL = url
}
// teardown closes the test HTTP server.
func teardown() {
server.Close()
return client, mux, server.URL, server.Close
}
// openTestFile creates a new file with the given name and content for testing.
@@ -164,6 +174,41 @@ func TestNewClient(t *testing.T) {
}
}
func TestNewEnterpriseClient(t *testing.T) {
baseURL := "https://custom-url/"
uploadURL := "https://custom-upload-url/"
c, err := NewEnterpriseClient(baseURL, uploadURL, nil)
if err != nil {
t.Fatalf("NewEnterpriseClient returned unexpected error: %v", err)
}
if got, want := c.BaseURL.String(), baseURL; got != want {
t.Errorf("NewClient BaseURL is %v, want %v", got, want)
}
if got, want := c.UploadURL.String(), uploadURL; got != want {
t.Errorf("NewClient UploadURL is %v, want %v", got, want)
}
}
func TestNewEnterpriseClient_addsTrailingSlashToURLs(t *testing.T) {
baseURL := "https://custom-url"
uploadURL := "https://custom-upload-url"
formattedBaseURL := baseURL + "/"
formattedUploadURL := uploadURL + "/"
c, err := NewEnterpriseClient(baseURL, uploadURL, nil)
if err != nil {
t.Fatalf("NewEnterpriseClient returned unexpected error: %v", err)
}
if got, want := c.BaseURL.String(), formattedBaseURL; got != want {
t.Errorf("NewClient BaseURL is %v, want %v", got, want)
}
if got, want := c.UploadURL.String(), formattedUploadURL; got != want {
t.Errorf("NewClient UploadURL is %v, want %v", got, want)
}
}
// Ensure that length of Client.rateLimits is the same as number of fields in RateLimits struct.
func TestClient_rateLimits(t *testing.T) {
if got, want := len(Client{}.rateLimits), reflect.TypeOf(RateLimits{}).NumField(); got != want {
@@ -201,7 +246,7 @@ func TestNewRequest_invalidJSON(t *testing.T) {
type T struct {
A map[interface{}]interface{}
}
_, err := c.NewRequest("GET", "/", &T{})
_, err := c.NewRequest("GET", ".", &T{})
if err == nil {
t.Error("Expected error to be returned.")
@@ -222,7 +267,7 @@ func TestNewRequest_badURL(t *testing.T) {
func TestNewRequest_emptyUserAgent(t *testing.T) {
c := NewClient(nil)
c.UserAgent = ""
req, err := c.NewRequest("GET", "/", nil)
req, err := c.NewRequest("GET", ".", nil)
if err != nil {
t.Fatalf("NewRequest returned unexpected error: %v", err)
}
@@ -239,7 +284,7 @@ func TestNewRequest_emptyUserAgent(t *testing.T) {
// subtle errors.
func TestNewRequest_emptyBody(t *testing.T) {
c := NewClient(nil)
req, err := c.NewRequest("GET", "/", nil)
req, err := c.NewRequest("GET", ".", nil)
if err != nil {
t.Fatalf("NewRequest returned unexpected error: %v", err)
}
@@ -360,7 +405,7 @@ func TestResponse_populatePageValues_invalid(t *testing.T) {
}
func TestDo(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
type foo struct {
@@ -368,13 +413,11 @@ func TestDo(t *testing.T) {
}
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
testMethod(t, r, "GET")
fmt.Fprint(w, `{"A":"a"}`)
})
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
body := new(foo)
client.Do(context.Background(), req, body)
@@ -385,18 +428,21 @@ func TestDo(t *testing.T) {
}
func TestDo_httpError(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Bad Request", 400)
})
req, _ := client.NewRequest("GET", "/", nil)
_, err := client.Do(context.Background(), req, nil)
req, _ := client.NewRequest("GET", ".", nil)
resp, err := client.Do(context.Background(), req, nil)
if err == nil {
t.Error("Expected HTTP 400 error.")
t.Fatal("Expected HTTP 400 error, got no error.")
}
if resp.StatusCode != 400 {
t.Errorf("Expected HTTP 400 error, got %d status code.", resp.StatusCode)
}
}
@@ -404,14 +450,14 @@ func TestDo_httpError(t *testing.T) {
// function. A redirect loop is pretty unlikely to occur within the GitHub
// API, but does allow us to exercise the right code path.
func TestDo_redirectLoop(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusFound)
http.Redirect(w, r, baseURLPath, http.StatusFound)
})
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
_, err := client.Do(context.Background(), req, nil)
if err == nil {
@@ -431,7 +477,7 @@ func TestDo_sanitizeURL(t *testing.T) {
}
unauthedClient := NewClient(tp.Client())
unauthedClient.BaseURL = &url.URL{Scheme: "http", Host: "127.0.0.1:0", Path: "/"} // Use port 0 on purpose to trigger a dial TCP error, expect to get "dial tcp 127.0.0.1:0: connect: can't assign requested address".
req, err := unauthedClient.NewRequest("GET", "/", nil)
req, err := unauthedClient.NewRequest("GET", ".", nil)
if err != nil {
t.Fatalf("NewRequest returned unexpected error: %v", err)
}
@@ -445,7 +491,7 @@ func TestDo_sanitizeURL(t *testing.T) {
}
func TestDo_rateLimit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -454,7 +500,7 @@ func TestDo_rateLimit(t *testing.T) {
w.Header().Set(headerRateReset, "1372700873")
})
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
resp, err := client.Do(context.Background(), req, nil)
if err != nil {
t.Errorf("Do returned unexpected error: %v", err)
@@ -465,7 +511,7 @@ func TestDo_rateLimit(t *testing.T) {
if got, want := resp.Rate.Remaining, 59; got != want {
t.Errorf("Client rate remaining = %v, want %v", got, want)
}
reset := time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC)
reset := time.Date(2013, time.July, 1, 17, 47, 53, 0, time.UTC)
if resp.Rate.Reset.UTC() != reset {
t.Errorf("Client rate reset = %v, want %v", resp.Rate.Reset, reset)
}
@@ -473,7 +519,7 @@ func TestDo_rateLimit(t *testing.T) {
// ensure rate limit is still parsed, even for error responses
func TestDo_rateLimit_errorResponse(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -483,7 +529,7 @@ func TestDo_rateLimit_errorResponse(t *testing.T) {
http.Error(w, "Bad Request", 400)
})
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
resp, err := client.Do(context.Background(), req, nil)
if err == nil {
t.Error("Expected error to be returned.")
@@ -497,7 +543,7 @@ func TestDo_rateLimit_errorResponse(t *testing.T) {
if got, want := resp.Rate.Remaining, 59; got != want {
t.Errorf("Client rate remaining = %v, want %v", got, want)
}
reset := time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC)
reset := time.Date(2013, time.July, 1, 17, 47, 53, 0, time.UTC)
if resp.Rate.Reset.UTC() != reset {
t.Errorf("Client rate reset = %v, want %v", resp.Rate.Reset, reset)
}
@@ -505,7 +551,7 @@ func TestDo_rateLimit_errorResponse(t *testing.T) {
// Ensure *RateLimitError is returned when API rate limit is exceeded.
func TestDo_rateLimit_rateLimitError(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -520,7 +566,7 @@ func TestDo_rateLimit_rateLimitError(t *testing.T) {
}`)
})
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
_, err := client.Do(context.Background(), req, nil)
if err == nil {
@@ -536,7 +582,7 @@ func TestDo_rateLimit_rateLimitError(t *testing.T) {
if got, want := rateLimitErr.Rate.Remaining, 0; got != want {
t.Errorf("rateLimitErr rate remaining = %v, want %v", got, want)
}
reset := time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC)
reset := time.Date(2013, time.July, 1, 17, 47, 53, 0, time.UTC)
if rateLimitErr.Rate.Reset.UTC() != reset {
t.Errorf("rateLimitErr rate reset = %v, want %v", rateLimitErr.Rate.Reset.UTC(), reset)
}
@@ -544,7 +590,7 @@ func TestDo_rateLimit_rateLimitError(t *testing.T) {
// Ensure a network call is not made when it's known that API rate limit is still exceeded.
func TestDo_rateLimit_noNetworkCall(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
reset := time.Now().UTC().Add(time.Minute).Round(time.Second) // Rate reset is a minute from now, with 1 second precision.
@@ -567,11 +613,11 @@ func TestDo_rateLimit_noNetworkCall(t *testing.T) {
})
// First request is made, and it makes the client aware of rate reset time being in the future.
req, _ := client.NewRequest("GET", "/first", nil)
req, _ := client.NewRequest("GET", "first", nil)
client.Do(context.Background(), req, nil)
// Second request should not cause a network call to be made, since client can predict a rate limit error.
req, _ = client.NewRequest("GET", "/second", nil)
req, _ = client.NewRequest("GET", "second", nil)
_, err := client.Do(context.Background(), req, nil)
if madeNetworkCall {
@@ -599,7 +645,7 @@ func TestDo_rateLimit_noNetworkCall(t *testing.T) {
// Ensure *AbuseRateLimitError is returned when the response indicates that
// the client has triggered an abuse detection mechanism.
func TestDo_rateLimit_abuseRateLimitError(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -609,11 +655,45 @@ func TestDo_rateLimit_abuseRateLimitError(t *testing.T) {
// there is no "Retry-After" header.
fmt.Fprintln(w, `{
"message": "You have triggered an abuse detection mechanism and have been temporarily blocked from content creation. Please retry your request again later.",
"documentation_url": "https://developer.github.com/v3#abuse-rate-limits"
"documentation_url": "https://developer.github.com/v3/#abuse-rate-limits"
}`)
})
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
_, err := client.Do(context.Background(), req, nil)
if err == nil {
t.Error("Expected error to be returned.")
}
abuseRateLimitErr, ok := err.(*AbuseRateLimitError)
if !ok {
t.Fatalf("Expected a *AbuseRateLimitError error; got %#v.", err)
}
if got, want := abuseRateLimitErr.RetryAfter, (*time.Duration)(nil); got != want {
t.Errorf("abuseRateLimitErr RetryAfter = %v, want %v", got, want)
}
}
// Ensure *AbuseRateLimitError is returned when the response indicates that
// the client has triggered an abuse detection mechanism on GitHub Enterprise.
func TestDo_rateLimit_abuseRateLimitErrorEnterprise(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusForbidden)
// When the abuse rate limit error is of the "temporarily blocked from content creation" type,
// there is no "Retry-After" header.
// This response returns a documentation url like the one returned for GitHub Enterprise, this
// url changes between versions but follows roughly the same format.
fmt.Fprintln(w, `{
"message": "You have triggered an abuse detection mechanism and have been temporarily blocked from content creation. Please retry your request again later.",
"documentation_url": "https://developer.github.com/enterprise/2.12/v3/#abuse-rate-limits"
}`)
})
req, _ := client.NewRequest("GET", ".", nil)
_, err := client.Do(context.Background(), req, nil)
if err == nil {
@@ -630,7 +710,7 @@ func TestDo_rateLimit_abuseRateLimitError(t *testing.T) {
// Ensure *AbuseRateLimitError.RetryAfter is parsed correctly.
func TestDo_rateLimit_abuseRateLimitError_retryAfter(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -639,11 +719,11 @@ func TestDo_rateLimit_abuseRateLimitError_retryAfter(t *testing.T) {
w.WriteHeader(http.StatusForbidden)
fmt.Fprintln(w, `{
"message": "You have triggered an abuse detection mechanism ...",
"documentation_url": "https://developer.github.com/v3#abuse-rate-limits"
"documentation_url": "https://developer.github.com/v3/#abuse-rate-limits"
}`)
})
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
_, err := client.Do(context.Background(), req, nil)
if err == nil {
@@ -662,7 +742,7 @@ func TestDo_rateLimit_abuseRateLimitError_retryAfter(t *testing.T) {
}
func TestDo_noContent(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -671,7 +751,7 @@ func TestDo_noContent(t *testing.T) {
var body json.RawMessage
req, _ := client.NewRequest("GET", "/", nil)
req, _ := client.NewRequest("GET", ".", nil)
_, err := client.Do(context.Background(), req, &body)
if err != nil {
t.Fatalf("Do returned unexpected error: %v", err)
@@ -720,7 +800,7 @@ func TestCheckResponse(t *testing.T) {
CreatedAt *Timestamp `json:"created_at,omitempty"`
}{
Reason: "dmca",
CreatedAt: &Timestamp{time.Date(2016, 3, 17, 15, 39, 46, 0, time.UTC)},
CreatedAt: &Timestamp{time.Date(2016, time.March, 17, 15, 39, 46, 0, time.UTC)},
},
}
if !reflect.DeepEqual(err, want) {
@@ -801,13 +881,11 @@ func TestError_Error(t *testing.T) {
}
func TestRateLimits(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/rate_limit", func(w http.ResponseWriter, r *http.Request) {
if m := "GET"; m != r.Method {
t.Errorf("Request method = %v, want %v", r.Method, m)
}
testMethod(t, r, "GET")
fmt.Fprint(w, `{"resources":{
"core": {"limit":2,"remaining":1,"reset":1372700873},
"search": {"limit":3,"remaining":2,"reset":1372700874}
@@ -823,12 +901,12 @@ func TestRateLimits(t *testing.T) {
Core: &Rate{
Limit: 2,
Remaining: 1,
Reset: Timestamp{time.Date(2013, 7, 1, 17, 47, 53, 0, time.UTC).Local()},
Reset: Timestamp{time.Date(2013, time.July, 1, 17, 47, 53, 0, time.UTC).Local()},
},
Search: &Rate{
Limit: 3,
Remaining: 2,
Reset: Timestamp{time.Date(2013, 7, 1, 17, 47, 54, 0, time.UTC).Local()},
Reset: Timestamp{time.Date(2013, time.July, 1, 17, 47, 54, 0, time.UTC).Local()},
},
}
if !reflect.DeepEqual(rate, want) {
@@ -844,7 +922,7 @@ func TestRateLimits(t *testing.T) {
}
func TestUnauthenticatedRateLimitedTransport(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
@@ -864,7 +942,7 @@ func TestUnauthenticatedRateLimitedTransport(t *testing.T) {
}
unauthedClient := NewClient(tp.Client())
unauthedClient.BaseURL = client.BaseURL
req, _ := unauthedClient.NewRequest("GET", "/", nil)
req, _ := unauthedClient.NewRequest("GET", ".", nil)
unauthedClient.Do(context.Background(), req, nil)
}
@@ -910,7 +988,7 @@ func TestUnauthenticatedRateLimitedTransport_transport(t *testing.T) {
}
func TestBasicAuthTransport(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
username, password, otp := "u", "p", "123456"
@@ -938,7 +1016,7 @@ func TestBasicAuthTransport(t *testing.T) {
}
basicAuthClient := NewClient(tp.Client())
basicAuthClient.BaseURL = client.BaseURL
req, _ := basicAuthClient.NewRequest("GET", "/", nil)
req, _ := basicAuthClient.NewRequest("GET", ".", nil)
basicAuthClient.Do(context.Background(), req, nil)
}
@@ -994,3 +1072,12 @@ func TestFormatRateReset(t *testing.T) {
t.Errorf("Format is wrong. got: %v, want: %v", got, want)
}
}
func TestNestedStructAccessorNoPanic(t *testing.T) {
issue := &Issue{User: nil}
got := issue.GetUser().GetPlan().GetName()
want := ""
if got != want {
t.Errorf("Issues.Get.GetUser().GetPlan().GetName() returned %+v, want %+v", got, want)
}
}

View File

@@ -14,7 +14,7 @@ import (
)
func TestGitignoresService_List(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gitignore/templates", func(w http.ResponseWriter, r *http.Request) {
@@ -34,7 +34,7 @@ func TestGitignoresService_List(t *testing.T) {
}
func TestGitignoresService_Get(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/gitignore/templates/name", func(w http.ResponseWriter, r *http.Request) {
@@ -54,6 +54,9 @@ func TestGitignoresService_Get(t *testing.T) {
}
func TestGitignoresService_Get_invalidTemplate(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Gitignores.Get(context.Background(), "%")
testURLParseError(t, err)
}

View File

@@ -8,6 +8,7 @@ package github
import (
"context"
"fmt"
"strings"
"time"
)
@@ -25,7 +26,7 @@ type IssuesService service
// this is an issue, and if PullRequestLinks is not nil, this is a pull request.
// The IsPullRequest helper method can be used to check that.
type Issue struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
Number *int `json:"number,omitempty"`
State *string `json:"state,omitempty"`
Locked *bool `json:"locked,omitempty"`
@@ -50,10 +51,15 @@ type Issue struct {
Repository *Repository `json:"repository,omitempty"`
Reactions *Reactions `json:"reactions,omitempty"`
Assignees []*User `json:"assignees,omitempty"`
NodeID *string `json:"node_id,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
TextMatches []TextMatch `json:"text_matches,omitempty"`
// ActiveLockReason is populated only when LockReason is provided while locking the issue.
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
ActiveLockReason *string `json:"active_lock_reason,omitempty"`
}
func (i Issue) String() string {
@@ -153,8 +159,9 @@ func (s *IssuesService) listIssues(ctx context.Context, u string, opt *IssueList
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeReactionsPreview)
// TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var issues []*Issue
resp, err := s.client.Do(ctx, req, &issues)
@@ -220,8 +227,9 @@ func (s *IssuesService) ListByRepo(ctx context.Context, owner string, repo strin
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeReactionsPreview)
// TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeIntegrationPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var issues []*Issue
resp, err := s.client.Do(ctx, req, &issues)
@@ -242,8 +250,9 @@ func (s *IssuesService) Get(ctx context.Context, owner string, repo string, numb
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeReactionsPreview)
// TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
issue := new(Issue)
resp, err := s.client.Do(ctx, req, issue)
@@ -264,6 +273,9 @@ func (s *IssuesService) Create(ctx context.Context, owner string, repo string, i
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
i := new(Issue)
resp, err := s.client.Do(ctx, req, i)
if err != nil {
@@ -283,6 +295,9 @@ func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, num
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
i := new(Issue)
resp, err := s.client.Do(ctx, req, i)
if err != nil {
@@ -292,16 +307,29 @@ func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, num
return i, resp, nil
}
// LockIssueOptions specifies the optional parameters to the
// IssuesService.Lock method.
type LockIssueOptions struct {
// LockReason specifies the reason to lock this issue.
// Providing a lock reason can help make it clearer to contributors why an issue
// was locked. Possible values are: "off-topic", "too heated", "resolved", and "spam".
LockReason string `json:"lock_reason,omitempty"`
}
// Lock an issue's conversation.
//
// GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue
func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int) (*Response, error) {
func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int, opt *LockIssueOptions) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number)
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", mediaTypeLockReasonPreview)
}
return s.client.Do(ctx, req, nil)
}

View File

@@ -15,7 +15,7 @@ import (
)
func TestIssuesService_ListAssignees(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees", func(w http.ResponseWriter, r *http.Request) {
@@ -30,19 +30,22 @@ func TestIssuesService_ListAssignees(t *testing.T) {
t.Errorf("Issues.ListAssignees returned error: %v", err)
}
want := []*User{{ID: Int(1)}}
want := []*User{{ID: Int64(1)}}
if !reflect.DeepEqual(assignees, want) {
t.Errorf("Issues.ListAssignees returned %+v, want %+v", assignees, want)
}
}
func TestIssuesService_ListAssignees_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListAssignees(context.Background(), "%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_IsAssignee_true(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) {
@@ -59,7 +62,7 @@ func TestIssuesService_IsAssignee_true(t *testing.T) {
}
func TestIssuesService_IsAssignee_false(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) {
@@ -77,7 +80,7 @@ func TestIssuesService_IsAssignee_false(t *testing.T) {
}
func TestIssuesService_IsAssignee_error(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/assignees/u", func(w http.ResponseWriter, r *http.Request) {
@@ -95,12 +98,15 @@ func TestIssuesService_IsAssignee_error(t *testing.T) {
}
func TestIssuesService_IsAssignee_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.IsAssignee(context.Background(), "%", "r", "u")
testURLParseError(t, err)
}
func TestIssuesService_AddAssignees(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/assignees", func(w http.ResponseWriter, r *http.Request) {
@@ -129,7 +135,7 @@ func TestIssuesService_AddAssignees(t *testing.T) {
}
func TestIssuesService_RemoveAssignees(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/assignees", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -13,15 +13,19 @@ import (
// IssueComment represents a comment left on an issue.
type IssueComment struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Body *string `json:"body,omitempty"`
User *User `json:"user,omitempty"`
Reactions *Reactions `json:"reactions,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
IssueURL *string `json:"issue_url,omitempty"`
// AuthorAssociation is the comment author's relationship to the issue's repository.
// Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
AuthorAssociation *string `json:"author_association,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
IssueURL *string `json:"issue_url,omitempty"`
}
func (i IssueComment) String() string {
@@ -79,8 +83,8 @@ func (s *IssuesService) ListComments(ctx context.Context, owner string, repo str
// GetComment fetches the specified issue comment.
//
// GitHub API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment
func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, id int) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id)
func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
@@ -118,10 +122,11 @@ func (s *IssuesService) CreateComment(ctx context.Context, owner string, repo st
}
// EditComment updates an issue comment.
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
//
// GitHub API docs: https://developer.github.com/v3/issues/comments/#edit-a-comment
func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, id int, comment *IssueComment) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id)
func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *IssueComment) (*IssueComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil {
return nil, nil, err
@@ -138,8 +143,8 @@ func (s *IssuesService) EditComment(ctx context.Context, owner string, repo stri
// DeleteComment deletes an issue comment.
//
// GitHub API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment
func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, id int) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, id)
func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err

View File

@@ -16,7 +16,7 @@ import (
)
func TestIssuesService_ListComments_allIssues(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -42,14 +42,14 @@ func TestIssuesService_ListComments_allIssues(t *testing.T) {
t.Errorf("Issues.ListComments returned error: %v", err)
}
want := []*IssueComment{{ID: Int(1)}}
want := []*IssueComment{{ID: Int64(1)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Issues.ListComments returned %+v, want %+v", comments, want)
}
}
func TestIssuesService_ListComments_specificIssue(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -63,19 +63,22 @@ func TestIssuesService_ListComments_specificIssue(t *testing.T) {
t.Errorf("Issues.ListComments returned error: %v", err)
}
want := []*IssueComment{{ID: Int(1)}}
want := []*IssueComment{{ID: Int64(1)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Issues.ListComments returned %+v, want %+v", comments, want)
}
}
func TestIssuesService_ListComments_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListComments(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_GetComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) {
@@ -89,19 +92,22 @@ func TestIssuesService_GetComment(t *testing.T) {
t.Errorf("Issues.GetComment returned error: %v", err)
}
want := &IssueComment{ID: Int(1)}
want := &IssueComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Issues.GetComment returned %+v, want %+v", comment, want)
}
}
func TestIssuesService_GetComment_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.GetComment(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}
func TestIssuesService_CreateComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &IssueComment{Body: String("b")}
@@ -123,19 +129,22 @@ func TestIssuesService_CreateComment(t *testing.T) {
t.Errorf("Issues.CreateComment returned error: %v", err)
}
want := &IssueComment{ID: Int(1)}
want := &IssueComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Issues.CreateComment returned %+v, want %+v", comment, want)
}
}
func TestIssuesService_CreateComment_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.CreateComment(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_EditComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &IssueComment{Body: String("b")}
@@ -157,19 +166,22 @@ func TestIssuesService_EditComment(t *testing.T) {
t.Errorf("Issues.EditComment returned error: %v", err)
}
want := &IssueComment{ID: Int(1)}
want := &IssueComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Issues.EditComment returned %+v, want %+v", comment, want)
}
}
func TestIssuesService_EditComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.EditComment(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_DeleteComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments/1", func(w http.ResponseWriter, r *http.Request) {
@@ -183,6 +195,9 @@ func TestIssuesService_DeleteComment(t *testing.T) {
}
func TestIssuesService_DeleteComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Issues.DeleteComment(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}

View File

@@ -8,12 +8,13 @@ package github
import (
"context"
"fmt"
"strings"
"time"
)
// IssueEvent represents an event that occurred around an Issue or Pull Request.
type IssueEvent struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
// The User that generated this event.
@@ -34,9 +35,13 @@ type IssueEvent struct {
// The Actor committed to master a commit mentioning the issue in its commit message.
// CommitID holds the SHA1 of the commit.
//
// reopened, locked, unlocked
// reopened, unlocked
// The Actor did that to the issue.
//
// locked
// The Actor locked the issue.
// LockReason holds the reason of locking the issue (if provided while locking).
//
// renamed
// The Actor changed the issue title from Rename.From to Rename.To.
//
@@ -64,12 +69,14 @@ type IssueEvent struct {
Issue *Issue `json:"issue,omitempty"`
// Only present on certain events; see above.
Assignee *User `json:"assignee,omitempty"`
Assigner *User `json:"assigner,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
Milestone *Milestone `json:"milestone,omitempty"`
Label *Label `json:"label,omitempty"`
Rename *Rename `json:"rename,omitempty"`
Assignee *User `json:"assignee,omitempty"`
Assigner *User `json:"assigner,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
Milestone *Milestone `json:"milestone,omitempty"`
Label *Label `json:"label,omitempty"`
Rename *Rename `json:"rename,omitempty"`
LockReason *string `json:"lock_reason,omitempty"`
ProjectCard *ProjectCard `json:"project_card,omitempty"`
}
// ListIssueEvents lists events for the specified issue.
@@ -87,6 +94,9 @@ func (s *IssuesService) ListIssueEvents(ctx context.Context, owner, repo string,
return nil, nil, err
}
acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeProjectCardDetailsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var events []*IssueEvent
resp, err := s.client.Do(ctx, req, &events)
if err != nil {
@@ -123,7 +133,7 @@ func (s *IssuesService) ListRepositoryEvents(ctx context.Context, owner, repo st
// GetEvent returns the specified issue event.
//
// GitHub API docs: https://developer.github.com/v3/issues/events/#get-a-single-event
func (s *IssuesService) GetEvent(ctx context.Context, owner, repo string, id int) (*IssueEvent, *Response, error) {
func (s *IssuesService) GetEvent(ctx context.Context, owner, repo string, id int64) (*IssueEvent, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/events/%v", owner, repo, id)
req, err := s.client.NewRequest("GET", u, nil)

View File

@@ -14,7 +14,7 @@ import (
)
func TestIssuesService_ListIssueEvents(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/events", func(w http.ResponseWriter, r *http.Request) {
@@ -32,14 +32,14 @@ func TestIssuesService_ListIssueEvents(t *testing.T) {
t.Errorf("Issues.ListIssueEvents returned error: %v", err)
}
want := []*IssueEvent{{ID: Int(1)}}
want := []*IssueEvent{{ID: Int64(1)}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Issues.ListIssueEvents returned %+v, want %+v", events, want)
}
}
func TestIssuesService_ListRepositoryEvents(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/events", func(w http.ResponseWriter, r *http.Request) {
@@ -57,14 +57,14 @@ func TestIssuesService_ListRepositoryEvents(t *testing.T) {
t.Errorf("Issues.ListRepositoryEvents returned error: %v", err)
}
want := []*IssueEvent{{ID: Int(1)}}
want := []*IssueEvent{{ID: Int64(1)}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Issues.ListRepositoryEvents returned %+v, want %+v", events, want)
}
}
func TestIssuesService_GetEvent(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/events/1", func(w http.ResponseWriter, r *http.Request) {
@@ -77,7 +77,7 @@ func TestIssuesService_GetEvent(t *testing.T) {
t.Errorf("Issues.GetEvent returned error: %v", err)
}
want := &IssueEvent{ID: Int(1)}
want := &IssueEvent{ID: Int64(1)}
if !reflect.DeepEqual(event, want) {
t.Errorf("Issues.GetEvent returned %+v, want %+v", event, want)
}

View File

@@ -12,10 +12,13 @@ import (
// Label represents a GitHub label on an Issue
type Label struct {
ID *int `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
Name *string `json:"name,omitempty"`
Color *string `json:"color,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
Name *string `json:"name,omitempty"`
Color *string `json:"color,omitempty"`
Description *string `json:"description,omitempty"`
Default *bool `json:"default,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
func (l Label) String() string {
@@ -37,6 +40,9 @@ func (s *IssuesService) ListLabels(ctx context.Context, owner string, repo strin
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var labels []*Label
resp, err := s.client.Do(ctx, req, &labels)
if err != nil {
@@ -56,6 +62,9 @@ func (s *IssuesService) GetLabel(ctx context.Context, owner string, repo string,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
label := new(Label)
resp, err := s.client.Do(ctx, req, label)
if err != nil {
@@ -75,6 +84,9 @@ func (s *IssuesService) CreateLabel(ctx context.Context, owner string, repo stri
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
l := new(Label)
resp, err := s.client.Do(ctx, req, l)
if err != nil {
@@ -94,6 +106,9 @@ func (s *IssuesService) EditLabel(ctx context.Context, owner string, repo string
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
l := new(Label)
resp, err := s.client.Do(ctx, req, l)
if err != nil {
@@ -130,6 +145,9 @@ func (s *IssuesService) ListLabelsByIssue(ctx context.Context, owner string, rep
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var labels []*Label
resp, err := s.client.Do(ctx, req, &labels)
if err != nil {
@@ -149,6 +167,9 @@ func (s *IssuesService) AddLabelsToIssue(ctx context.Context, owner string, repo
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var l []*Label
resp, err := s.client.Do(ctx, req, &l)
if err != nil {
@@ -167,6 +188,10 @@ func (s *IssuesService) RemoveLabelForIssue(ctx context.Context, owner string, r
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
return s.client.Do(ctx, req, nil)
}
@@ -180,6 +205,9 @@ func (s *IssuesService) ReplaceLabelsForIssue(ctx context.Context, owner string,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var l []*Label
resp, err := s.client.Do(ctx, req, &l)
if err != nil {
@@ -198,6 +226,10 @@ func (s *IssuesService) RemoveLabelsForIssue(ctx context.Context, owner string,
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
return s.client.Do(ctx, req, nil)
}
@@ -216,6 +248,9 @@ func (s *IssuesService) ListLabelsForMilestone(ctx context.Context, owner string
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
var labels []*Label
resp, err := s.client.Do(ctx, req, &labels)
if err != nil {

View File

@@ -15,11 +15,12 @@ import (
)
func TestIssuesService_ListLabels(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"name": "a"},{"name": "b"}]`)
})
@@ -37,17 +38,21 @@ func TestIssuesService_ListLabels(t *testing.T) {
}
func TestIssuesService_ListLabels_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListLabels(context.Background(), "%", "%", nil)
testURLParseError(t, err)
}
func TestIssuesService_GetLabel(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/labels/n", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"url":"u", "name": "n", "color": "c"}`)
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
fmt.Fprint(w, `{"url":"u", "name": "n", "color": "c", "description": "d"}`)
})
label, _, err := client.Issues.GetLabel(context.Background(), "o", "r", "n")
@@ -55,19 +60,22 @@ func TestIssuesService_GetLabel(t *testing.T) {
t.Errorf("Issues.GetLabel returned error: %v", err)
}
want := &Label{URL: String("u"), Name: String("n"), Color: String("c")}
want := &Label{URL: String("u"), Name: String("n"), Color: String("c"), Description: String("d")}
if !reflect.DeepEqual(label, want) {
t.Errorf("Issues.GetLabel returned %+v, want %+v", label, want)
}
}
func TestIssuesService_GetLabel_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.GetLabel(context.Background(), "%", "%", "%")
testURLParseError(t, err)
}
func TestIssuesService_CreateLabel(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Label{Name: String("n")}
@@ -77,6 +85,7 @@ func TestIssuesService_CreateLabel(t *testing.T) {
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@@ -96,12 +105,15 @@ func TestIssuesService_CreateLabel(t *testing.T) {
}
func TestIssuesService_CreateLabel_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.CreateLabel(context.Background(), "%", "%", nil)
testURLParseError(t, err)
}
func TestIssuesService_EditLabel(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Label{Name: String("z")}
@@ -111,6 +123,7 @@ func TestIssuesService_EditLabel(t *testing.T) {
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@@ -130,12 +143,15 @@ func TestIssuesService_EditLabel(t *testing.T) {
}
func TestIssuesService_EditLabel_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.EditLabel(context.Background(), "%", "%", "%", nil)
testURLParseError(t, err)
}
func TestIssuesService_DeleteLabel(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/labels/n", func(w http.ResponseWriter, r *http.Request) {
@@ -149,16 +165,20 @@ func TestIssuesService_DeleteLabel(t *testing.T) {
}
func TestIssuesService_DeleteLabel_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Issues.DeleteLabel(context.Background(), "%", "%", "%")
testURLParseError(t, err)
}
func TestIssuesService_ListLabelsByIssue(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"name":"a","id":1},{"name":"b","id":2}]`)
})
@@ -170,8 +190,8 @@ func TestIssuesService_ListLabelsByIssue(t *testing.T) {
}
want := []*Label{
{Name: String("a"), ID: Int(1)},
{Name: String("b"), ID: Int(2)},
{Name: String("a"), ID: Int64(1)},
{Name: String("b"), ID: Int64(2)},
}
if !reflect.DeepEqual(labels, want) {
t.Errorf("Issues.ListLabelsByIssue returned %+v, want %+v", labels, want)
@@ -179,12 +199,15 @@ func TestIssuesService_ListLabelsByIssue(t *testing.T) {
}
func TestIssuesService_ListLabelsByIssue_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListLabelsByIssue(context.Background(), "%", "%", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_AddLabelsToIssue(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := []string{"a", "b"}
@@ -194,6 +217,7 @@ func TestIssuesService_AddLabelsToIssue(t *testing.T) {
json.NewDecoder(r.Body).Decode(&v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@@ -213,15 +237,19 @@ func TestIssuesService_AddLabelsToIssue(t *testing.T) {
}
func TestIssuesService_AddLabelsToIssue_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.AddLabelsToIssue(context.Background(), "%", "%", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_RemoveLabelForIssue(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/labels/l", func(w http.ResponseWriter, r *http.Request) {
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
testMethod(t, r, "DELETE")
})
@@ -232,12 +260,15 @@ func TestIssuesService_RemoveLabelForIssue(t *testing.T) {
}
func TestIssuesService_RemoveLabelForIssue_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Issues.RemoveLabelForIssue(context.Background(), "%", "%", 1, "%")
testURLParseError(t, err)
}
func TestIssuesService_ReplaceLabelsForIssue(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := []string{"a", "b"}
@@ -247,6 +278,7 @@ func TestIssuesService_ReplaceLabelsForIssue(t *testing.T) {
json.NewDecoder(r.Body).Decode(&v)
testMethod(t, r, "PUT")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@@ -266,16 +298,20 @@ func TestIssuesService_ReplaceLabelsForIssue(t *testing.T) {
}
func TestIssuesService_ReplaceLabelsForIssue_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ReplaceLabelsForIssue(context.Background(), "%", "%", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_RemoveLabelsForIssue(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
})
_, err := client.Issues.RemoveLabelsForIssue(context.Background(), "o", "r", 1)
@@ -285,16 +321,20 @@ func TestIssuesService_RemoveLabelsForIssue(t *testing.T) {
}
func TestIssuesService_RemoveLabelsForIssue_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Issues.RemoveLabelsForIssue(context.Background(), "%", "%", 1)
testURLParseError(t, err)
}
func TestIssuesService_ListLabelsForMilestone(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones/1/labels", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"name": "a"},{"name": "b"}]`)
})
@@ -312,6 +352,9 @@ func TestIssuesService_ListLabelsForMilestone(t *testing.T) {
}
func TestIssuesService_ListLabelsForMilestone_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListLabelsForMilestone(context.Background(), "%", "%", 1, nil)
testURLParseError(t, err)
}

View File

@@ -16,7 +16,7 @@ type Milestone struct {
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
LabelsURL *string `json:"labels_url,omitempty"`
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
Number *int `json:"number,omitempty"`
State *string `json:"state,omitempty"`
Title *string `json:"title,omitempty"`
@@ -28,6 +28,7 @@ type Milestone struct {
UpdatedAt *time.Time `json:"updated_at,omitempty"`
ClosedAt *time.Time `json:"closed_at,omitempty"`
DueOn *time.Time `json:"due_on,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
func (m Milestone) String() string {

View File

@@ -15,7 +15,7 @@ import (
)
func TestIssuesService_ListMilestones(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones", func(w http.ResponseWriter, r *http.Request) {
@@ -42,12 +42,15 @@ func TestIssuesService_ListMilestones(t *testing.T) {
}
func TestIssuesService_ListMilestones_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListMilestones(context.Background(), "%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_GetMilestone(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) {
@@ -67,12 +70,15 @@ func TestIssuesService_GetMilestone(t *testing.T) {
}
func TestIssuesService_GetMilestone_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.GetMilestone(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}
func TestIssuesService_CreateMilestone(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Milestone{Title: String("t")}
@@ -101,12 +107,15 @@ func TestIssuesService_CreateMilestone(t *testing.T) {
}
func TestIssuesService_CreateMilestone_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.CreateMilestone(context.Background(), "%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_EditMilestone(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Milestone{Title: String("t")}
@@ -135,12 +144,15 @@ func TestIssuesService_EditMilestone(t *testing.T) {
}
func TestIssuesService_EditMilestone_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.EditMilestone(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_DeleteMilestone(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/milestones/1", func(w http.ResponseWriter, r *http.Request) {
@@ -154,6 +166,9 @@ func TestIssuesService_DeleteMilestone(t *testing.T) {
}
func TestIssuesService_DeleteMilestone_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Issues.DeleteMilestone(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}

View File

@@ -11,17 +11,19 @@ import (
"fmt"
"net/http"
"reflect"
"strings"
"testing"
"time"
)
func TestIssuesService_List_all(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
mux.HandleFunc("/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
testFormValues(t, r, values{
"filter": "all",
"state": "closed",
@@ -52,12 +54,13 @@ func TestIssuesService_List_all(t *testing.T) {
}
func TestIssuesService_List_owned(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
mux.HandleFunc("/user/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
fmt.Fprint(w, `[{"number":1}]`)
})
@@ -73,12 +76,13 @@ func TestIssuesService_List_owned(t *testing.T) {
}
func TestIssuesService_ListByOrg(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
mux.HandleFunc("/orgs/o/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
fmt.Fprint(w, `[{"number":1}]`)
})
@@ -94,17 +98,21 @@ func TestIssuesService_ListByOrg(t *testing.T) {
}
func TestIssuesService_ListByOrg_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListByOrg(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestIssuesService_ListByRepo(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeIntegrationPreview}
mux.HandleFunc("/repos/o/r/issues", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
testFormValues(t, r, values{
"milestone": "*",
"state": "closed",
@@ -136,17 +144,21 @@ func TestIssuesService_ListByRepo(t *testing.T) {
}
func TestIssuesService_ListByRepo_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.ListByRepo(context.Background(), "%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_Get(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
mux.HandleFunc("/repos/o/r/issues/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
fmt.Fprint(w, `{"number":1, "labels": [{"url": "u", "name": "n", "color": "c"}]}`)
})
@@ -169,12 +181,15 @@ func TestIssuesService_Get(t *testing.T) {
}
func TestIssuesService_Get_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.Get(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}
func TestIssuesService_Create(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &IssueRequest{
@@ -189,6 +204,7 @@ func TestIssuesService_Create(t *testing.T) {
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@@ -208,12 +224,15 @@ func TestIssuesService_Create(t *testing.T) {
}
func TestIssuesService_Create_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.Create(context.Background(), "%", "r", nil)
testURLParseError(t, err)
}
func TestIssuesService_Edit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &IssueRequest{Title: String("t")}
@@ -223,6 +242,7 @@ func TestIssuesService_Edit(t *testing.T) {
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@@ -242,12 +262,15 @@ func TestIssuesService_Edit(t *testing.T) {
}
func TestIssuesService_Edit_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Issues.Edit(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestIssuesService_Lock(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/lock", func(w http.ResponseWriter, r *http.Request) {
@@ -256,13 +279,30 @@ func TestIssuesService_Lock(t *testing.T) {
w.WriteHeader(http.StatusNoContent)
})
if _, err := client.Issues.Lock(context.Background(), "o", "r", 1); err != nil {
if _, err := client.Issues.Lock(context.Background(), "o", "r", 1, nil); err != nil {
t.Errorf("Issues.Lock returned error: %v", err)
}
}
func TestIssuesService_LockWithReason(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/lock", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
testHeader(t, r, "Accept", mediaTypeLockReasonPreview)
w.WriteHeader(http.StatusNoContent)
})
opt := &LockIssueOptions{LockReason: "off-topic"}
if _, err := client.Issues.Lock(context.Background(), "o", "r", 1, opt); err != nil {
t.Errorf("Issues.Lock returned error: %v", err)
}
}
func TestIssuesService_Unlock(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/lock", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -16,7 +16,7 @@ import (
// It is similar to an IssueEvent but may contain more information.
// GitHub API docs: https://developer.github.com/v3/issues/timeline/
type Timeline struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
CommitURL *string `json:"commit_url,omitempty"`
@@ -120,7 +120,7 @@ type Timeline struct {
// Source represents a reference's source.
type Source struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
Actor *User `json:"actor,omitempty"`
}

View File

@@ -14,7 +14,7 @@ import (
)
func TestIssuesService_ListIssueTimeline(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/timeline", func(w http.ResponseWriter, r *http.Request) {
@@ -33,7 +33,7 @@ func TestIssuesService_ListIssueTimeline(t *testing.T) {
t.Errorf("Issues.ListIssueTimeline returned error: %v", err)
}
want := []*Timeline{{ID: Int(1)}}
want := []*Timeline{{ID: Int64(1)}}
if !reflect.DeepEqual(events, want) {
t.Errorf("Issues.ListIssueTimeline = %+v, want %+v", events, want)
}

View File

@@ -67,9 +67,6 @@ func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, erro
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
var licenses []*License
resp, err := s.client.Do(ctx, req, &licenses)
if err != nil {
@@ -90,9 +87,6 @@ func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeLicensesPreview)
license := new(License)
resp, err := s.client.Do(ctx, req, license)
if err != nil {

View File

@@ -14,12 +14,11 @@ import (
)
func TestLicensesService_List(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/licenses", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeLicensesPreview)
fmt.Fprint(w, `[{"key":"mit","name":"MIT","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","featured":true}]`)
})
@@ -41,12 +40,11 @@ func TestLicensesService_List(t *testing.T) {
}
func TestLicensesService_Get(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/licenses/mit", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeLicensesPreview)
fmt.Fprint(w, `{"key":"mit","name":"MIT"}`)
})
@@ -62,6 +60,9 @@ func TestLicensesService_Get(t *testing.T) {
}
func TestLicensesService_Get_invalidTemplate(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Licenses.Get(context.Background(), "%")
testURLParseError(t, err)
}

View File

@@ -41,39 +41,43 @@ const (
var (
// eventTypeMapping maps webhooks types to their corresponding go-github struct types.
eventTypeMapping = map[string]string{
"commit_comment": "CommitCommentEvent",
"create": "CreateEvent",
"delete": "DeleteEvent",
"deployment": "DeploymentEvent",
"deployment_status": "DeploymentStatusEvent",
"fork": "ForkEvent",
"gollum": "GollumEvent",
"installation": "InstallationEvent",
"installation_repositories": "InstallationRepositoriesEvent",
"issue_comment": "IssueCommentEvent",
"issues": "IssuesEvent",
"label": "LabelEvent",
"member": "MemberEvent",
"membership": "MembershipEvent",
"milestone": "MilestoneEvent",
"organization": "OrganizationEvent",
"org_block": "OrgBlockEvent",
"page_build": "PageBuildEvent",
"ping": "PingEvent",
"project": "ProjectEvent",
"project_card": "ProjectCardEvent",
"project_column": "ProjectColumnEvent",
"public": "PublicEvent",
"pull_request_review": "PullRequestReviewEvent",
"pull_request_review_comment": "PullRequestReviewCommentEvent",
"pull_request": "PullRequestEvent",
"push": "PushEvent",
"repository": "RepositoryEvent",
"release": "ReleaseEvent",
"status": "StatusEvent",
"team": "TeamEvent",
"team_add": "TeamAddEvent",
"watch": "WatchEvent",
"check_run": "CheckRunEvent",
"check_suite": "CheckSuiteEvent",
"commit_comment": "CommitCommentEvent",
"create": "CreateEvent",
"delete": "DeleteEvent",
"deployment": "DeploymentEvent",
"deployment_status": "DeploymentStatusEvent",
"fork": "ForkEvent",
"gollum": "GollumEvent",
"installation": "InstallationEvent",
"installation_repositories": "InstallationRepositoriesEvent",
"issue_comment": "IssueCommentEvent",
"issues": "IssuesEvent",
"label": "LabelEvent",
"marketplace_purchase": "MarketplacePurchaseEvent",
"member": "MemberEvent",
"membership": "MembershipEvent",
"milestone": "MilestoneEvent",
"organization": "OrganizationEvent",
"org_block": "OrgBlockEvent",
"page_build": "PageBuildEvent",
"ping": "PingEvent",
"project": "ProjectEvent",
"project_card": "ProjectCardEvent",
"project_column": "ProjectColumnEvent",
"public": "PublicEvent",
"pull_request_review": "PullRequestReviewEvent",
"pull_request_review_comment": "PullRequestReviewCommentEvent",
"pull_request": "PullRequestEvent",
"push": "PushEvent",
"repository": "RepositoryEvent",
"repository_vulnerability_alert": "RepositoryVulnerabilityAlertEvent",
"release": "ReleaseEvent",
"status": "StatusEvent",
"team": "TeamEvent",
"team_add": "TeamAddEvent",
"watch": "WatchEvent",
}
)
@@ -172,19 +176,19 @@ func ValidatePayload(r *http.Request, secretKey []byte) (payload []byte, err err
}
sig := r.Header.Get(signatureHeader)
if err := validateSignature(sig, body, secretKey); err != nil {
if err := ValidateSignature(sig, body, secretKey); err != nil {
return nil, err
}
return payload, nil
}
// validateSignature validates the signature for the given payload.
// ValidateSignature validates the signature for the given payload.
// signature is the GitHub hash signature delivered in the X-Hub-Signature header.
// payload is the JSON payload sent by GitHub Webhooks.
// secretKey is the GitHub Webhook secret message.
//
// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
func validateSignature(signature string, payload, secretKey []byte) error {
func ValidateSignature(signature string, payload, secretKey []byte) error {
messageMAC, hashFunc, err := messageMAC(signature)
if err != nil {
return err

View File

@@ -161,6 +161,14 @@ func TestParseWebHook(t *testing.T) {
payload interface{}
messageType string
}{
{
payload: &CheckRunEvent{},
messageType: "check_run",
},
{
payload: &CheckSuiteEvent{},
messageType: "check_suite",
},
{
payload: &CommitCommentEvent{},
messageType: "commit_comment",
@@ -210,6 +218,10 @@ func TestParseWebHook(t *testing.T) {
payload: &LabelEvent{},
messageType: "label",
},
{
payload: &MarketplacePurchaseEvent{},
messageType: "marketplace_purchase",
},
{
payload: &MemberEvent{},
messageType: "member",
@@ -278,6 +290,10 @@ func TestParseWebHook(t *testing.T) {
payload: &RepositoryEvent{},
messageType: "repository",
},
{
payload: &RepositoryVulnerabilityAlertEvent{},
messageType: "repository_vulnerability_alert",
},
{
payload: &StatusEvent{},
messageType: "status",

View File

@@ -21,7 +21,7 @@ type MigrationService service
// Migration represents a GitHub migration (archival).
type Migration struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
GUID *string `json:"guid,omitempty"`
// State is the current state of a migration.
// Possible values are:
@@ -128,7 +128,7 @@ func (s *MigrationService) ListMigrations(ctx context.Context, org string) ([]*M
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migration/migrations/#get-the-status-of-a-migration
func (s *MigrationService) MigrationStatus(ctx context.Context, org string, id int) (*Migration, *Response, error) {
func (s *MigrationService) MigrationStatus(ctx context.Context, org string, id int64) (*Migration, *Response, error) {
u := fmt.Sprintf("orgs/%v/migrations/%v", org, id)
req, err := s.client.NewRequest("GET", u, nil)
@@ -152,7 +152,7 @@ func (s *MigrationService) MigrationStatus(ctx context.Context, org string, id i
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migration/migrations/#download-a-migration-archive
func (s *MigrationService) MigrationArchiveURL(ctx context.Context, org string, id int) (url string, err error) {
func (s *MigrationService) MigrationArchiveURL(ctx context.Context, org string, id int64) (url string, err error) {
u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id)
req, err := s.client.NewRequest("GET", u, nil)
@@ -189,7 +189,7 @@ func (s *MigrationService) MigrationArchiveURL(ctx context.Context, org string,
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive
func (s *MigrationService) DeleteMigration(ctx context.Context, org string, id int) (*Response, error) {
func (s *MigrationService) DeleteMigration(ctx context.Context, org string, id int64) (*Response, error) {
u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id)
req, err := s.client.NewRequest("DELETE", u, nil)
@@ -209,7 +209,7 @@ func (s *MigrationService) DeleteMigration(ctx context.Context, org string, id i
// is complete and you no longer need the source data.
//
// GitHub API docs: https://developer.github.com/v3/migration/migrations/#unlock-a-repository
func (s *MigrationService) UnlockRepo(ctx context.Context, org string, id int, repo string) (*Response, error) {
func (s *MigrationService) UnlockRepo(ctx context.Context, org string, id int64, repo string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/migrations/%v/repos/%v/lock", org, id, repo)
req, err := s.client.NewRequest("DELETE", u, nil)

View File

@@ -117,7 +117,7 @@ func (i Import) String() string {
//
// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors
type SourceImportAuthor struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
RemoteID *string `json:"remote_id,omitempty"`
RemoteName *string `json:"remote_name,omitempty"`
Email *string `json:"email,omitempty"`
@@ -247,7 +247,7 @@ func (s *MigrationService) CommitAuthors(ctx context.Context, owner, repo string
// commits to the repository.
//
// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#map-a-commit-author
func (s *MigrationService) MapCommitAuthor(ctx context.Context, owner, repo string, id int, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) {
func (s *MigrationService) MapCommitAuthor(ctx context.Context, owner, repo string, id int64, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/import/authors/%v", owner, repo, id)
req, err := s.client.NewRequest("PATCH", u, author)
if err != nil {

View File

@@ -15,7 +15,7 @@ import (
)
func TestMigrationService_StartImport(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Import{
@@ -50,7 +50,7 @@ func TestMigrationService_StartImport(t *testing.T) {
}
func TestMigrationService_ImportProgress(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/import", func(w http.ResponseWriter, r *http.Request) {
@@ -70,7 +70,7 @@ func TestMigrationService_ImportProgress(t *testing.T) {
}
func TestMigrationService_UpdateImport(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Import{
@@ -105,7 +105,7 @@ func TestMigrationService_UpdateImport(t *testing.T) {
}
func TestMigrationService_CommitAuthors(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/import/authors", func(w http.ResponseWriter, r *http.Request) {
@@ -119,8 +119,8 @@ func TestMigrationService_CommitAuthors(t *testing.T) {
t.Errorf("CommitAuthors returned error: %v", err)
}
want := []*SourceImportAuthor{
{ID: Int(1), Name: String("a")},
{ID: Int(2), Name: String("b")},
{ID: Int64(1), Name: String("a")},
{ID: Int64(2), Name: String("b")},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("CommitAuthors = %+v, want %+v", got, want)
@@ -128,7 +128,7 @@ func TestMigrationService_CommitAuthors(t *testing.T) {
}
func TestMigrationService_MapCommitAuthor(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &SourceImportAuthor{Name: String("n"), Email: String("e")}
@@ -150,14 +150,14 @@ func TestMigrationService_MapCommitAuthor(t *testing.T) {
if err != nil {
t.Errorf("MapCommitAuthor returned error: %v", err)
}
want := &SourceImportAuthor{ID: Int(1)}
want := &SourceImportAuthor{ID: Int64(1)}
if !reflect.DeepEqual(got, want) {
t.Errorf("MapCommitAuthor = %+v, want %+v", got, want)
}
}
func TestMigrationService_SetLFSPreference(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Import{UseLFS: String("opt_in")}
@@ -187,7 +187,7 @@ func TestMigrationService_SetLFSPreference(t *testing.T) {
}
func TestMigrationService_LargeFiles(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/import/large_files", func(w http.ResponseWriter, r *http.Request) {
@@ -210,7 +210,7 @@ func TestMigrationService_LargeFiles(t *testing.T) {
}
func TestMigrationService_CancelImport(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/import", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -15,7 +15,7 @@ import (
)
func TestMigrationService_StartMigration(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/migrations", func(w http.ResponseWriter, r *http.Request) {
@@ -40,7 +40,7 @@ func TestMigrationService_StartMigration(t *testing.T) {
}
func TestMigrationService_ListMigrations(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/migrations", func(w http.ResponseWriter, r *http.Request) {
@@ -61,7 +61,7 @@ func TestMigrationService_ListMigrations(t *testing.T) {
}
func TestMigrationService_MigrationStatus(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/migrations/1", func(w http.ResponseWriter, r *http.Request) {
@@ -82,7 +82,7 @@ func TestMigrationService_MigrationStatus(t *testing.T) {
}
func TestMigrationService_MigrationArchiveURL(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/migrations/1/archive", func(w http.ResponseWriter, r *http.Request) {
@@ -108,7 +108,7 @@ func TestMigrationService_MigrationArchiveURL(t *testing.T) {
}
func TestMigrationService_DeleteMigration(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/migrations/1/archive", func(w http.ResponseWriter, r *http.Request) {
@@ -124,7 +124,7 @@ func TestMigrationService_DeleteMigration(t *testing.T) {
}
func TestMigrationService_UnlockRepo(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/migrations/1/repos/r/lock", func(w http.ResponseWriter, r *http.Request) {
@@ -159,7 +159,7 @@ var migrationJSON = []byte(`{
}`)
var wantMigration = &Migration{
ID: Int(79),
ID: Int64(79),
GUID: String("0b989ba4-242f-11e5-81e1-c7b6966d2516"),
State: String("pending"),
LockRepositories: Bool(true),
@@ -169,7 +169,7 @@ var wantMigration = &Migration{
UpdatedAt: String("2015-07-06T15:33:38-07:00"),
Repositories: []*Repository{
{
ID: Int(1296269),
ID: Int64(1296269),
Name: String("Hello-World"),
FullName: String("octocat/Hello-World"),
Description: String("This your first repo!"),

View File

@@ -0,0 +1,214 @@
// Copyright 2018 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"errors"
"fmt"
"net/http"
)
// UserMigration represents a GitHub migration (archival).
type UserMigration struct {
ID *int64 `json:"id,omitempty"`
GUID *string `json:"guid,omitempty"`
// State is the current state of a migration.
// Possible values are:
// "pending" which means the migration hasn't started yet,
// "exporting" which means the migration is in progress,
// "exported" which means the migration finished successfully, or
// "failed" which means the migration failed.
State *string `json:"state,omitempty"`
// LockRepositories indicates whether repositories are locked (to prevent
// manipulation) while migrating data.
LockRepositories *bool `json:"lock_repositories,omitempty"`
// ExcludeAttachments indicates whether attachments should be excluded from
// the migration (to reduce migration archive file size).
ExcludeAttachments *bool `json:"exclude_attachments,omitempty"`
URL *string `json:"url,omitempty"`
CreatedAt *string `json:"created_at,omitempty"`
UpdatedAt *string `json:"updated_at,omitempty"`
Repositories []*Repository `json:"repositories,omitempty"`
}
func (m UserMigration) String() string {
return Stringify(m)
}
// UserMigrationOptions specifies the optional parameters to Migration methods.
type UserMigrationOptions struct {
// LockRepositories indicates whether repositories should be locked (to prevent
// manipulation) while migrating data.
LockRepositories bool
// ExcludeAttachments indicates whether attachments should be excluded from
// the migration (to reduce migration archive file size).
ExcludeAttachments bool
}
// startUserMigration represents the body of a StartMigration request.
type startUserMigration struct {
// Repositories is a slice of repository names to migrate.
Repositories []string `json:"repositories,omitempty"`
// LockRepositories indicates whether repositories should be locked (to prevent
// manipulation) while migrating data.
LockRepositories *bool `json:"lock_repositories,omitempty"`
// ExcludeAttachments indicates whether attachments should be excluded from
// the migration (to reduce migration archive file size).
ExcludeAttachments *bool `json:"exclude_attachments,omitempty"`
}
// StartUserMigration starts the generation of a migration archive.
// repos is a slice of repository names to migrate.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#start-a-user-migration
func (s *MigrationService) StartUserMigration(ctx context.Context, repos []string, opt *UserMigrationOptions) (*UserMigration, *Response, error) {
u := "user/migrations"
body := &startUserMigration{Repositories: repos}
if opt != nil {
body.LockRepositories = Bool(opt.LockRepositories)
body.ExcludeAttachments = Bool(opt.ExcludeAttachments)
}
req, err := s.client.NewRequest("POST", u, body)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
m := &UserMigration{}
resp, err := s.client.Do(ctx, req, m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// ListUserMigrations lists the most recent migrations.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-a-list-of-user-migrations
func (s *MigrationService) ListUserMigrations(ctx context.Context) ([]*UserMigration, *Response, error) {
u := "user/migrations"
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
var m []*UserMigration
resp, err := s.client.Do(ctx, req, &m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// UserMigrationStatus gets the status of a specific migration archive.
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-the-status-of-a-user-migration
func (s *MigrationService) UserMigrationStatus(ctx context.Context, id int64) (*UserMigration, *Response, error) {
u := fmt.Sprintf("user/migrations/%v", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
m := &UserMigration{}
resp, err := s.client.Do(ctx, req, m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// UserMigrationArchiveURL gets the URL for a specific migration archive.
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#download-a-user-migration-archive
func (s *MigrationService) UserMigrationArchiveURL(ctx context.Context, id int64) (string, error) {
url := fmt.Sprintf("user/migrations/%v/archive", id)
req, err := s.client.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
m := &UserMigration{}
var loc string
originalRedirect := s.client.client.CheckRedirect
s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
loc = req.URL.String()
return http.ErrUseLastResponse
}
defer func() {
s.client.client.CheckRedirect = originalRedirect
}()
resp, err := s.client.Do(ctx, req, m)
if err == nil {
return "", errors.New("expected redirect, none provided")
}
loc = resp.Header.Get("Location")
return loc, nil
}
// DeleteUserMigration will delete a previous migration archive.
// id is the migration ID.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#delete-a-user-migration-archive
func (s *MigrationService) DeleteUserMigration(ctx context.Context, id int64) (*Response, error) {
url := fmt.Sprintf("user/migrations/%v/archive", id)
req, err := s.client.NewRequest("DELETE", url, nil)
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
return s.client.Do(ctx, req, nil)
}
// UnlockUserRepository will unlock a repo that was locked for migration.
// id is migration ID.
// You should unlock each migrated repository and delete them when the migration
// is complete and you no longer need the source data.
//
// GitHub API docs: https://developer.github.com/v3/migrations/users/#unlock-a-user-repository
func (s *MigrationService) UnlockUserRepo(ctx context.Context, id int64, repo string) (*Response, error) {
url := fmt.Sprintf("user/migrations/%v/repos/%v/lock", id, repo)
req, err := s.client.NewRequest("DELETE", url, nil)
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeMigrationsPreview)
return s.client.Do(ctx, req, nil)
}

View File

@@ -0,0 +1,197 @@
// Copyright 2018 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"fmt"
"net/http"
"reflect"
"strings"
"testing"
)
func TestMigrationService_StartUserMigration(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/migrations", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeMigrationsPreview)
w.WriteHeader(http.StatusCreated)
w.Write(userMigrationJSON)
})
opt := &UserMigrationOptions{
LockRepositories: true,
ExcludeAttachments: false,
}
got, _, err := client.Migrations.StartUserMigration(context.Background(), []string{"r"}, opt)
if err != nil {
t.Errorf("StartUserMigration returned error: %v", err)
}
want := wantUserMigration
if !reflect.DeepEqual(want, got) {
t.Errorf("StartUserMigration = %v, want = %v", got, want)
}
}
func TestMigrationService_ListUserMigrations(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/migrations", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeMigrationsPreview)
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("[%s]", userMigrationJSON)))
})
got, _, err := client.Migrations.ListUserMigrations(context.Background())
if err != nil {
t.Errorf("ListUserMigrations returned error %v", err)
}
want := []*UserMigration{wantUserMigration}
if !reflect.DeepEqual(want, got) {
t.Errorf("ListUserMigrations = %v, want = %v", got, want)
}
}
func TestMigrationService_UserMigrationStatus(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/migrations/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeMigrationsPreview)
w.WriteHeader(http.StatusOK)
w.Write(userMigrationJSON)
})
got, _, err := client.Migrations.UserMigrationStatus(context.Background(), 1)
if err != nil {
t.Errorf("UserMigrationStatus returned error %v", err)
}
want := wantUserMigration
if !reflect.DeepEqual(want, got) {
t.Errorf("UserMigrationStatus = %v, want = %v", got, want)
}
}
func TestMigrationService_UserMigrationArchiveURL(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/migrations/1/archive", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeMigrationsPreview)
http.Redirect(w, r, "/go-github", http.StatusFound)
})
mux.HandleFunc("/go-github", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusOK)
})
got, err := client.Migrations.UserMigrationArchiveURL(context.Background(), 1)
if err != nil {
t.Errorf("UserMigrationArchiveURL returned error %v", err)
}
want := "/go-github"
if !strings.HasSuffix(got, want) {
t.Errorf("UserMigrationArchiveURL = %v, want = %v", got, want)
}
}
func TestMigrationService_DeleteUserMigration(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/migrations/1/archive", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
testHeader(t, r, "Accept", mediaTypeMigrationsPreview)
w.WriteHeader(http.StatusNoContent)
})
got, err := client.Migrations.DeleteUserMigration(context.Background(), 1)
if err != nil {
t.Errorf("DeleteUserMigration returned error %v", err)
}
if got.StatusCode != http.StatusNoContent {
t.Errorf("DeleteUserMigration returned status = %v, want = %v", got.StatusCode, http.StatusNoContent)
}
}
func TestMigrationService_UnlockUserRepo(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/migrations/1/repos/r/lock", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
testHeader(t, r, "Accept", mediaTypeMigrationsPreview)
w.WriteHeader(http.StatusNoContent)
})
got, err := client.Migrations.UnlockUserRepo(context.Background(), 1, "r")
if err != nil {
t.Errorf("UnlockUserRepo returned error %v", err)
}
if got.StatusCode != http.StatusNoContent {
t.Errorf("UnlockUserRepo returned status = %v, want = %v", got.StatusCode, http.StatusNoContent)
}
}
var userMigrationJSON = []byte(`{
"id": 79,
"guid": "0b989ba4-242f-11e5-81e1-c7b6966d2516",
"state": "pending",
"lock_repositories": true,
"exclude_attachments": false,
"url": "https://api.github.com/orgs/octo-org/migrations/79",
"created_at": "2015-07-06T15:33:38-07:00",
"updated_at": "2015-07-06T15:33:38-07:00",
"repositories": [
{
"id": 1296269,
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"description": "This your first repo!"
}
]
}`)
var wantUserMigration = &UserMigration{
ID: Int64(79),
GUID: String("0b989ba4-242f-11e5-81e1-c7b6966d2516"),
State: String("pending"),
LockRepositories: Bool(true),
ExcludeAttachments: Bool(false),
URL: String("https://api.github.com/orgs/octo-org/migrations/79"),
CreatedAt: String("2015-07-06T15:33:38-07:00"),
UpdatedAt: String("2015-07-06T15:33:38-07:00"),
Repositories: []*Repository{
{
ID: Int64(1296269),
Name: String("Hello-World"),
FullName: String("octocat/Hello-World"),
Description: String("This your first repo!"),
},
},
}

View File

@@ -158,6 +158,10 @@ type APIMeta struct {
// An array of IP addresses in CIDR format specifying the addresses
// which serve GitHub Pages websites.
Pages []string `json:"pages,omitempty"`
// An Array of IP addresses specifying the addresses that source imports
// will originate from on GitHub.com.
Importer []string `json:"importer,omitempty"`
}
// APIMeta returns information about GitHub.com, the service. Or, if you access

View File

@@ -15,7 +15,7 @@ import (
)
func TestMarkdown(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &markdownRequest{
@@ -48,7 +48,7 @@ func TestMarkdown(t *testing.T) {
}
func TestListEmojis(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/emojis", func(w http.ResponseWriter, r *http.Request) {
@@ -68,7 +68,7 @@ func TestListEmojis(t *testing.T) {
}
func TestListCodesOfConduct(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/codes_of_conduct", func(w http.ResponseWriter, r *http.Request) {
@@ -98,7 +98,7 @@ func TestListCodesOfConduct(t *testing.T) {
}
func TestGetCodeOfConduct(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/codes_of_conduct/k", func(w http.ResponseWriter, r *http.Request) {
@@ -129,12 +129,12 @@ func TestGetCodeOfConduct(t *testing.T) {
}
func TestAPIMeta(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/meta", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"hooks":["h"], "git":["g"], "pages":["p"], "verifiable_password_authentication": true}`)
fmt.Fprint(w, `{"hooks":["h"], "git":["g"], "pages":["p"], "importer":["i"], "verifiable_password_authentication": true}`)
})
meta, _, err := client.APIMeta(context.Background())
@@ -143,9 +143,11 @@ func TestAPIMeta(t *testing.T) {
}
want := &APIMeta{
Hooks: []string{"h"},
Git: []string{"g"},
Pages: []string{"p"},
Hooks: []string{"h"},
Git: []string{"g"},
Pages: []string{"p"},
Importer: []string{"i"},
VerifiablePasswordAuthentication: Bool(true),
}
if !reflect.DeepEqual(want, meta) {
@@ -154,7 +156,7 @@ func TestAPIMeta(t *testing.T) {
}
func TestOctocat(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := "input"
@@ -178,7 +180,7 @@ func TestOctocat(t *testing.T) {
}
func TestZen(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
output := "sample text"
@@ -200,7 +202,7 @@ func TestZen(t *testing.T) {
}
func TestListServiceHooks(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/hooks", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -19,30 +19,42 @@ type OrganizationsService service
// Organization represents a GitHub organization account.
type Organization struct {
Login *string `json:"login,omitempty"`
ID *int `json:"id,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
Name *string `json:"name,omitempty"`
Company *string `json:"company,omitempty"`
Blog *string `json:"blog,omitempty"`
Location *string `json:"location,omitempty"`
Email *string `json:"email,omitempty"`
Description *string `json:"description,omitempty"`
PublicRepos *int `json:"public_repos,omitempty"`
PublicGists *int `json:"public_gists,omitempty"`
Followers *int `json:"followers,omitempty"`
Following *int `json:"following,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
TotalPrivateRepos *int `json:"total_private_repos,omitempty"`
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"`
PrivateGists *int `json:"private_gists,omitempty"`
DiskUsage *int `json:"disk_usage,omitempty"`
Collaborators *int `json:"collaborators,omitempty"`
BillingEmail *string `json:"billing_email,omitempty"`
Type *string `json:"type,omitempty"`
Plan *Plan `json:"plan,omitempty"`
Login *string `json:"login,omitempty"`
ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
Name *string `json:"name,omitempty"`
Company *string `json:"company,omitempty"`
Blog *string `json:"blog,omitempty"`
Location *string `json:"location,omitempty"`
Email *string `json:"email,omitempty"`
Description *string `json:"description,omitempty"`
PublicRepos *int `json:"public_repos,omitempty"`
PublicGists *int `json:"public_gists,omitempty"`
Followers *int `json:"followers,omitempty"`
Following *int `json:"following,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
TotalPrivateRepos *int `json:"total_private_repos,omitempty"`
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"`
PrivateGists *int `json:"private_gists,omitempty"`
DiskUsage *int `json:"disk_usage,omitempty"`
Collaborators *int `json:"collaborators,omitempty"`
BillingEmail *string `json:"billing_email,omitempty"`
Type *string `json:"type,omitempty"`
Plan *Plan `json:"plan,omitempty"`
TwoFactorRequirementEnabled *bool `json:"two_factor_requirement_enabled,omitempty"`
// DefaultRepoPermission can be one of: "read", "write", "admin", or "none". (Default: "read").
// It is only used in OrganizationsService.Edit.
DefaultRepoPermission *string `json:"default_repository_permission,omitempty"`
// DefaultRepoSettings can be one of: "read", "write", "admin", or "none". (Default: "read").
// It is only used in OrganizationsService.Get.
DefaultRepoSettings *string `json:"default_repository_settings,omitempty"`
// MembersCanCreateRepos default value is true and is only used in Organizations.Edit.
MembersCanCreateRepos *bool `json:"members_can_create_repositories,omitempty"`
// API URLs
URL *string `json:"url,omitempty"`
@@ -74,8 +86,11 @@ func (p Plan) String() string {
// OrganizationsService.ListAll method.
type OrganizationsListOptions struct {
// Since filters Organizations by ID.
Since int `url:"since,omitempty"`
Since int64 `url:"since,omitempty"`
// Note: Pagination is powered exclusively by the Since parameter,
// ListOptions.Page has no effect.
// ListOptions.PerPage controls an undocumented GitHub API parameter.
ListOptions
}
@@ -157,7 +172,7 @@ func (s *OrganizationsService) Get(ctx context.Context, org string) (*Organizati
// GetByID fetches an organization.
//
// Note: GetByID uses the undocumented GitHub API endpoint /organizations/:id.
func (s *OrganizationsService) GetByID(ctx context.Context, id int) (*Organization, *Response, error) {
func (s *OrganizationsService) GetByID(ctx context.Context, id int64) (*Organization, *Response, error) {
u := fmt.Sprintf("organizations/%d", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {

View File

@@ -37,7 +37,7 @@ func (s *OrganizationsService) ListHooks(ctx context.Context, org string, opt *L
// GetHook returns a single specified Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook
func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int) (*Hook, *Response, error) {
func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int64) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
@@ -49,12 +49,22 @@ func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int)
}
// CreateHook creates a Hook for the specified org.
// Name and Config are required fields.
// Config is a required field.
//
// Note that only a subset of the hook fields are used and hook must
// not be nil.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook
func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks", org)
req, err := s.client.NewRequest("POST", u, hook)
hookReq := &createHookRequest{
Events: hook.Events,
Active: hook.Active,
Config: hook.Config,
}
req, err := s.client.NewRequest("POST", u, hookReq)
if err != nil {
return nil, nil, err
}
@@ -71,7 +81,7 @@ func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook
// EditHook updates a specified Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook
func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int, hook *Hook) (*Hook, *Response, error) {
func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int64, hook *Hook) (*Hook, *Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("PATCH", u, hook)
if err != nil {
@@ -85,7 +95,7 @@ func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int,
// PingHook triggers a 'ping' event to be sent to the Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook
func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int) (*Response, error) {
func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int64) (*Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
@@ -97,7 +107,7 @@ func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int)
// DeleteHook deletes a specified Hook.
//
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook
func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int) (*Response, error) {
func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int64) (*Response, error) {
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {

View File

@@ -15,7 +15,7 @@ import (
)
func TestOrganizationsService_ListHooks(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks", func(w http.ResponseWriter, r *http.Request) {
@@ -31,19 +31,52 @@ func TestOrganizationsService_ListHooks(t *testing.T) {
t.Errorf("Organizations.ListHooks returned error: %v", err)
}
want := []*Hook{{ID: Int(1)}, {ID: Int(2)}}
want := []*Hook{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(hooks, want) {
t.Errorf("Organizations.ListHooks returned %+v, want %+v", hooks, want)
}
}
func TestOrganizationsService_ListHooks_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.ListHooks(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_CreateHook(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
input := &Hook{CreatedAt: &referenceTime}
mux.HandleFunc("/orgs/o/hooks", func(w http.ResponseWriter, r *http.Request) {
v := new(createHookRequest)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
want := &createHookRequest{}
if !reflect.DeepEqual(v, want) {
t.Errorf("Request body = %+v, want %+v", v, want)
}
fmt.Fprint(w, `{"id":1}`)
})
hook, _, err := client.Organizations.CreateHook(context.Background(), "o", input)
if err != nil {
t.Errorf("Organizations.CreateHook returned error: %v", err)
}
want := &Hook{ID: Int64(1)}
if !reflect.DeepEqual(hook, want) {
t.Errorf("Organizations.CreateHook returned %+v, want %+v", hook, want)
}
}
func TestOrganizationsService_GetHook(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks/1", func(w http.ResponseWriter, r *http.Request) {
@@ -56,22 +89,25 @@ func TestOrganizationsService_GetHook(t *testing.T) {
t.Errorf("Organizations.GetHook returned error: %v", err)
}
want := &Hook{ID: Int(1)}
want := &Hook{ID: Int64(1)}
if !reflect.DeepEqual(hook, want) {
t.Errorf("Organizations.GetHook returned %+v, want %+v", hook, want)
}
}
func TestOrganizationsService_GetHook_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.GetHook(context.Background(), "%", 1)
testURLParseError(t, err)
}
func TestOrganizationsService_EditHook(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Hook{Name: String("t")}
input := &Hook{}
mux.HandleFunc("/orgs/o/hooks/1", func(w http.ResponseWriter, r *http.Request) {
v := new(Hook)
@@ -90,19 +126,22 @@ func TestOrganizationsService_EditHook(t *testing.T) {
t.Errorf("Organizations.EditHook returned error: %v", err)
}
want := &Hook{ID: Int(1)}
want := &Hook{ID: Int64(1)}
if !reflect.DeepEqual(hook, want) {
t.Errorf("Organizations.EditHook returned %+v, want %+v", hook, want)
}
}
func TestOrganizationsService_EditHook_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.EditHook(context.Background(), "%", 1, nil)
testURLParseError(t, err)
}
func TestOrganizationsService_PingHook(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks/1/pings", func(w http.ResponseWriter, r *http.Request) {
@@ -116,7 +155,7 @@ func TestOrganizationsService_PingHook(t *testing.T) {
}
func TestOrganizationsService_DeleteHook(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/hooks/1", func(w http.ResponseWriter, r *http.Request) {
@@ -130,6 +169,9 @@ func TestOrganizationsService_DeleteHook(t *testing.T) {
}
func TestOrganizationsService_DeleteHook_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Organizations.DeleteHook(context.Background(), "%", 1)
testURLParseError(t, err)
}

View File

@@ -59,7 +59,7 @@ type ListMembersOptions struct {
// Possible values are:
// all - all members of the organization, regardless of role
// admin - organization owners
// member - non-organization members
// member - non-owner organization members
//
// Default is "all".
Role string `url:"role,omitempty"`
@@ -297,3 +297,74 @@ func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, or
}
return pendingInvitations, resp, nil
}
// CreateOrgInvitationOptions specifies the parameters to the OrganizationService.Invite
// method.
type CreateOrgInvitationOptions struct {
// GitHub user ID for the person you are inviting. Not required if you provide Email.
InviteeID *int64 `json:"invitee_id,omitempty"`
// Email address of the person you are inviting, which can be an existing GitHub user.
// Not required if you provide InviteeID
Email *string `json:"email,omitempty"`
// Specify role for new member. Can be one of:
// * admin - Organization owners with full administrative rights to the
// organization and complete access to all repositories and teams.
// * direct_member - Non-owner organization members with ability to see
// other members and join teams by invitation.
// * billing_manager - Non-owner organization members with ability to
// manage the billing settings of your organization.
// Default is "direct_member".
Role *string `json:"role"`
TeamID []int64 `json:"team_ids"`
}
// CreateOrgInvitation invites people to an organization by using their GitHub user ID or their email address.
// In order to create invitations in an organization,
// the authenticated user must be an organization owner.
//
// https://developer.github.com/v3/orgs/members/#create-organization-invitation
func (s *OrganizationsService) CreateOrgInvitation(ctx context.Context, org string, opt *CreateOrgInvitationOptions) (*Invitation, *Response, error) {
u := fmt.Sprintf("orgs/%v/invitations", org)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeOrganizationInvitationPreview)
var invitation *Invitation
resp, err := s.client.Do(ctx, req, &invitation)
if err != nil {
return nil, resp, err
}
return invitation, resp, nil
}
// ListOrgInvitationTeams lists all teams associated with an invitation. In order to see invitations in an organization,
// the authenticated user must be an organization owner.
//
// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-organization-invitation-teams
func (s *OrganizationsService) ListOrgInvitationTeams(ctx context.Context, org, invitationID string, opt *ListOptions) ([]*Team, *Response, error) {
u := fmt.Sprintf("orgs/%v/invitations/%v/teams", org, invitationID)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeOrganizationInvitationPreview)
var orgInvitationTeams []*Team
resp, err := s.client.Do(ctx, req, &orgInvitationTeams)
if err != nil {
return nil, resp, err
}
return orgInvitationTeams, resp, nil
}

View File

@@ -16,7 +16,7 @@ import (
)
func TestOrganizationsService_ListMembers(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/members", func(w http.ResponseWriter, r *http.Request) {
@@ -40,19 +40,22 @@ func TestOrganizationsService_ListMembers(t *testing.T) {
t.Errorf("Organizations.ListMembers returned error: %v", err)
}
want := []*User{{ID: Int(1)}}
want := []*User{{ID: Int64(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListMembers returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_ListMembers_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.ListMembers(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_ListMembers_public(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members", func(w http.ResponseWriter, r *http.Request) {
@@ -66,14 +69,14 @@ func TestOrganizationsService_ListMembers_public(t *testing.T) {
t.Errorf("Organizations.ListMembers returned error: %v", err)
}
want := []*User{{ID: Int(1)}}
want := []*User{{ID: Int64(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListMembers returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_IsMember(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
@@ -92,7 +95,7 @@ func TestOrganizationsService_IsMember(t *testing.T) {
// ensure that a 404 response is interpreted as "false" and not an error
func TestOrganizationsService_IsMember_notMember(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
@@ -112,7 +115,7 @@ func TestOrganizationsService_IsMember_notMember(t *testing.T) {
// ensure that a 400 response is interpreted as an actual error, and not simply
// as "false" like the above case of a 404
func TestOrganizationsService_IsMember_error(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
@@ -130,12 +133,15 @@ func TestOrganizationsService_IsMember_error(t *testing.T) {
}
func TestOrganizationsService_IsMember_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.IsMember(context.Background(), "%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_IsPublicMember(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
@@ -154,7 +160,7 @@ func TestOrganizationsService_IsPublicMember(t *testing.T) {
// ensure that a 404 response is interpreted as "false" and not an error
func TestOrganizationsService_IsPublicMember_notMember(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
@@ -174,7 +180,7 @@ func TestOrganizationsService_IsPublicMember_notMember(t *testing.T) {
// ensure that a 400 response is interpreted as an actual error, and not simply
// as "false" like the above case of a 404
func TestOrganizationsService_IsPublicMember_error(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
@@ -192,12 +198,15 @@ func TestOrganizationsService_IsPublicMember_error(t *testing.T) {
}
func TestOrganizationsService_IsPublicMember_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.IsPublicMember(context.Background(), "%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_RemoveMember(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/members/u", func(w http.ResponseWriter, r *http.Request) {
@@ -211,12 +220,15 @@ func TestOrganizationsService_RemoveMember(t *testing.T) {
}
func TestOrganizationsService_RemoveMember_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Organizations.RemoveMember(context.Background(), "%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_ListOrgMemberships(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/memberships/orgs", func(w http.ResponseWriter, r *http.Request) {
@@ -244,7 +256,7 @@ func TestOrganizationsService_ListOrgMemberships(t *testing.T) {
}
func TestOrganizationsService_GetOrgMembership_AuthenticatedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/memberships/orgs/o", func(w http.ResponseWriter, r *http.Request) {
@@ -264,7 +276,7 @@ func TestOrganizationsService_GetOrgMembership_AuthenticatedUser(t *testing.T) {
}
func TestOrganizationsService_GetOrgMembership_SpecifiedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
@@ -284,7 +296,7 @@ func TestOrganizationsService_GetOrgMembership_SpecifiedUser(t *testing.T) {
}
func TestOrganizationsService_EditOrgMembership_AuthenticatedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Membership{State: String("active")}
@@ -313,7 +325,7 @@ func TestOrganizationsService_EditOrgMembership_AuthenticatedUser(t *testing.T)
}
func TestOrganizationsService_EditOrgMembership_SpecifiedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Membership{State: String("active")}
@@ -342,7 +354,7 @@ func TestOrganizationsService_EditOrgMembership_SpecifiedUser(t *testing.T) {
}
func TestOrganizationsService_RemoveOrgMembership(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/memberships/u", func(w http.ResponseWriter, r *http.Request) {
@@ -357,7 +369,7 @@ func TestOrganizationsService_RemoveOrgMembership(t *testing.T) {
}
func TestOrganizationsService_ListPendingOrgInvitations(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/invitations", func(w http.ResponseWriter, r *http.Request) {
@@ -388,7 +400,9 @@ func TestOrganizationsService_ListPendingOrgInvitations(t *testing.T) {
"received_events_url": "https://api.github.com/users/other_user/received_events/privacy",
"type": "User",
"site_admin": false
}
},
"team_count": 2,
"invitation_team_url": "https://api.github.com/organizations/2/invitations/1/teams"
}
]`)
})
@@ -399,17 +413,17 @@ func TestOrganizationsService_ListPendingOrgInvitations(t *testing.T) {
t.Errorf("Organizations.ListPendingOrgInvitations returned error: %v", err)
}
createdAt := time.Date(2017, 01, 21, 0, 0, 0, 0, time.UTC)
createdAt := time.Date(2017, time.January, 21, 0, 0, 0, 0, time.UTC)
want := []*Invitation{
{
ID: Int(1),
ID: Int64(1),
Login: String("monalisa"),
Email: String("octocat@github.com"),
Role: String("direct_member"),
CreatedAt: &createdAt,
Inviter: &User{
Login: String("other_user"),
ID: Int(1),
ID: Int64(1),
AvatarURL: String("https://github.com/images/error/other_user_happy.gif"),
GravatarID: String(""),
URL: String("https://api.github.com/users/other_user"),
@@ -426,9 +440,96 @@ func TestOrganizationsService_ListPendingOrgInvitations(t *testing.T) {
Type: String("User"),
SiteAdmin: Bool(false),
},
TeamCount: Int(2),
InvitationTeamURL: String("https://api.github.com/organizations/2/invitations/1/teams"),
}}
if !reflect.DeepEqual(invitations, want) {
t.Errorf("Organizations.ListPendingOrgInvitations returned %+v, want %+v", invitations, want)
}
}
func TestOrganizationsService_CreateOrgInvitation(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
input := &CreateOrgInvitationOptions{
Email: String("octocat@github.com"),
Role: String("direct_member"),
TeamID: []int64{
12,
26,
},
}
mux.HandleFunc("/orgs/o/invitations", func(w http.ResponseWriter, r *http.Request) {
v := new(CreateOrgInvitationOptions)
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeOrganizationInvitationPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprintln(w, `{"email": "octocat@github.com"}`)
})
invitations, _, err := client.Organizations.CreateOrgInvitation(context.Background(), "o", input)
if err != nil {
t.Errorf("Organizations.CreateOrgInvitation returned error: %v", err)
}
want := &Invitation{Email: String("octocat@github.com")}
if !reflect.DeepEqual(invitations, want) {
t.Errorf("Organizations.ListPendingOrgInvitations returned %+v, want %+v", invitations, want)
}
}
func TestOrganizationsService_ListOrgInvitationTeams(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/invitations/22/teams", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "1"})
testHeader(t, r, "Accept", mediaTypeOrganizationInvitationPreview)
fmt.Fprint(w, `[
{
"id": 1,
"url": "https://api.github.com/teams/1",
"name": "Justice League",
"slug": "justice-league",
"description": "A great team.",
"privacy": "closed",
"permission": "admin",
"members_url": "https://api.github.com/teams/1/members{/member}",
"repositories_url": "https://api.github.com/teams/1/repos"
}
]`)
})
opt := &ListOptions{Page: 1}
invitations, _, err := client.Organizations.ListOrgInvitationTeams(context.Background(), "o", "22", opt)
if err != nil {
t.Errorf("Organizations.ListOrgInvitationTeams returned error: %v", err)
}
want := []*Team{
{
ID: Int64(1),
URL: String("https://api.github.com/teams/1"),
Name: String("Justice League"),
Slug: String("justice-league"),
Description: String("A great team."),
Privacy: String("closed"),
Permission: String("admin"),
MembersURL: String("https://api.github.com/teams/1/members{/member}"),
RepositoriesURL: String("https://api.github.com/teams/1/repos"),
},
}
if !reflect.DeepEqual(invitations, want) {
t.Errorf("Organizations.ListOrgInvitationTeams returned %+v, want %+v", invitations, want)
}
}

View File

@@ -48,3 +48,34 @@ func (s *OrganizationsService) ListOutsideCollaborators(ctx context.Context, org
return members, resp, nil
}
// RemoveOutsideCollaborator removes a user from the list of outside collaborators;
// consequently, removing them from all the organization's repositories.
//
// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#remove-outside-collaborator
func (s *OrganizationsService) RemoveOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}
// ConvertMemberToOutsideCollaborator reduces the permission level of a member of the
// organization to that of an outside collaborator. Therefore, they will only
// have access to the repositories that their current team membership allows.
// Responses for converting a non-member or the last owner to an outside collaborator
// are listed in GitHub API docs.
//
// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#convert-member-to-outside-collaborator
func (s *OrganizationsService) ConvertMemberToOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) {
u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user)
req, err := s.client.NewRequest("PUT", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}

View File

@@ -14,7 +14,7 @@ import (
)
func TestOrganizationsService_ListOutsideCollaborators(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/outside_collaborators", func(w http.ResponseWriter, r *http.Request) {
@@ -35,13 +35,100 @@ func TestOrganizationsService_ListOutsideCollaborators(t *testing.T) {
t.Errorf("Organizations.ListOutsideCollaborators returned error: %v", err)
}
want := []*User{{ID: Int(1)}}
want := []*User{{ID: Int64(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListOutsideCollaborators returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_ListOutsideCollaborators_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.ListOutsideCollaborators(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_RemoveOutsideCollaborator(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
}
mux.HandleFunc("/orgs/o/outside_collaborators/u", handler)
_, err := client.Organizations.RemoveOutsideCollaborator(context.Background(), "o", "u")
if err != nil {
t.Errorf("Organizations.RemoveOutsideCollaborator returned error: %v", err)
}
}
func TestOrganizationsService_RemoveOutsideCollaborator_NonMember(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNotFound)
}
mux.HandleFunc("/orgs/o/outside_collaborators/u", handler)
_, err := client.Organizations.RemoveOutsideCollaborator(context.Background(), "o", "u")
if err, ok := err.(*ErrorResponse); !ok {
t.Errorf("Organizations.RemoveOutsideCollaborator did not return an error")
} else if err.Response.StatusCode != http.StatusNotFound {
t.Errorf("Organizations.RemoveOutsideCollaborator did not return 404 status code")
}
}
func TestOrganizationsService_RemoveOutsideCollaborator_Member(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusUnprocessableEntity)
}
mux.HandleFunc("/orgs/o/outside_collaborators/u", handler)
_, err := client.Organizations.RemoveOutsideCollaborator(context.Background(), "o", "u")
if err, ok := err.(*ErrorResponse); !ok {
t.Errorf("Organizations.RemoveOutsideCollaborator did not return an error")
} else if err.Response.StatusCode != http.StatusUnprocessableEntity {
t.Errorf("Organizations.RemoveOutsideCollaborator did not return 422 status code")
}
}
func TestOrganizationsService_ConvertMemberToOutsideCollaborator(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
}
mux.HandleFunc("/orgs/o/outside_collaborators/u", handler)
_, err := client.Organizations.ConvertMemberToOutsideCollaborator(context.Background(), "o", "u")
if err != nil {
t.Errorf("Organizations.ConvertMemberToOutsideCollaborator returned error: %v", err)
}
}
func TestOrganizationsService_ConvertMemberToOutsideCollaborator_NonMemberOrLastOwner(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
handler := func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
w.WriteHeader(http.StatusForbidden)
}
mux.HandleFunc("/orgs/o/outside_collaborators/u", handler)
_, err := client.Organizations.ConvertMemberToOutsideCollaborator(context.Background(), "o", "u")
if err, ok := err.(*ErrorResponse); !ok {
t.Errorf("Organizations.ConvertMemberToOutsideCollaborator did not return an error")
} else if err.Response.StatusCode != http.StatusForbidden {
t.Errorf("Organizations.ConvertMemberToOutsideCollaborator did not return 403 status code")
}
}

View File

@@ -15,7 +15,7 @@ import (
)
func TestOrganizationsService_ListProjects(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/projects", func(w http.ResponseWriter, r *http.Request) {
@@ -31,17 +31,17 @@ func TestOrganizationsService_ListProjects(t *testing.T) {
t.Errorf("Organizations.ListProjects returned error: %v", err)
}
want := []*Project{{ID: Int(1)}}
want := []*Project{{ID: Int64(1)}}
if !reflect.DeepEqual(projects, want) {
t.Errorf("Organizations.ListProjects returned %+v, want %+v", projects, want)
}
}
func TestOrganizationsService_CreateProject(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectOptions{Name: "Project Name", Body: "Project body."}
input := &ProjectOptions{Name: String("Project Name"), Body: String("Project body.")}
mux.HandleFunc("/orgs/o/projects", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
@@ -61,7 +61,7 @@ func TestOrganizationsService_CreateProject(t *testing.T) {
t.Errorf("Organizations.CreateProject returned error: %v", err)
}
want := &Project{ID: Int(1)}
want := &Project{ID: Int64(1)}
if !reflect.DeepEqual(project, want) {
t.Errorf("Organizations.CreateProject returned %+v, want %+v", project, want)
}

View File

@@ -1,431 +0,0 @@
// Copyright 2013 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"fmt"
"time"
)
// 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"`
Description *string `json:"description,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"`
MembersURL *string `json:"members_url,omitempty"`
RepositoriesURL *string `json:"repositories_url,omitempty"`
// LDAPDN is only available in GitHub Enterprise and when the team
// membership is synchronized with LDAP.
LDAPDN *string `json:"ldap_dn,omitempty"`
}
func (t Team) String() string {
return Stringify(t)
}
// Invitation represents a team member's invitation status.
type Invitation struct {
ID *int `json:"id,omitempty"`
Login *string `json:"login,omitempty"`
Email *string `json:"email,omitempty"`
// Role can be one of the values - 'direct_member', 'admin', 'billing_manager', 'hiring_manager', or 'reinstate'.
Role *string `json:"role,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
Inviter *User `json:"inviter,omitempty"`
}
func (i Invitation) String() string {
return Stringify(i)
}
// ListTeams lists all of the teams for an organization.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-teams
func (s *OrganizationsService) ListTeams(ctx context.Context, org string, opt *ListOptions) ([]*Team, *Response, error) {
u := fmt.Sprintf("orgs/%v/teams", org)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var teams []*Team
resp, err := s.client.Do(ctx, req, &teams)
if err != nil {
return nil, resp, err
}
return teams, resp, nil
}
// GetTeam fetches a team by ID.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team
func (s *OrganizationsService) GetTeam(ctx context.Context, team int) (*Team, *Response, error) {
u := fmt.Sprintf("teams/%v", team)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
t := new(Team)
resp, err := s.client.Do(ctx, req, t)
if err != nil {
return nil, resp, err
}
return t, resp, nil
}
// CreateTeam creates a new team within an organization.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#create-team
func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team *Team) (*Team, *Response, error) {
u := fmt.Sprintf("orgs/%v/teams", org)
req, err := s.client.NewRequest("POST", u, team)
if err != nil {
return nil, nil, err
}
t := new(Team)
resp, err := s.client.Do(ctx, req, t)
if err != nil {
return nil, resp, err
}
return t, resp, nil
}
// EditTeam edits a team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#edit-team
func (s *OrganizationsService) EditTeam(ctx context.Context, id int, team *Team) (*Team, *Response, error) {
u := fmt.Sprintf("teams/%v", id)
req, err := s.client.NewRequest("PATCH", u, team)
if err != nil {
return nil, nil, err
}
t := new(Team)
resp, err := s.client.Do(ctx, req, t)
if err != nil {
return nil, resp, err
}
return t, resp, nil
}
// DeleteTeam deletes a team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#delete-team
func (s *OrganizationsService) DeleteTeam(ctx context.Context, team int) (*Response, error) {
u := fmt.Sprintf("teams/%v", team)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(ctx, 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: https://developer.github.com/v3/orgs/teams/#list-team-members
func (s *OrganizationsService) ListTeamMembers(ctx context.Context, team int, opt *OrganizationListTeamMembersOptions) ([]*User, *Response, error) {
u := fmt.Sprintf("teams/%v/members", team)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var members []*User
resp, err := s.client.Do(ctx, req, &members)
if err != nil {
return nil, resp, err
}
return members, resp, nil
}
// IsTeamMember checks if a user is a member of the specified team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-member
func (s *OrganizationsService) IsTeamMember(ctx context.Context, team int, user string) (bool, *Response, error) {
u := fmt.Sprintf("teams/%v/members/%v", team, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return false, nil, err
}
resp, err := s.client.Do(ctx, req, nil)
member, err := parseBoolResponse(err)
return member, resp, err
}
// ListTeamRepos lists the repositories that the specified team has access to.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-team-repos
func (s *OrganizationsService) ListTeamRepos(ctx context.Context, team int, opt *ListOptions) ([]*Repository, *Response, error) {
u := fmt.Sprintf("teams/%v/repos", team)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when topics API fully launches.
req.Header.Set("Accept", mediaTypeTopicsPreview)
var repos []*Repository
resp, err := s.client.Do(ctx, req, &repos)
if err != nil {
return nil, resp, err
}
return repos, resp, nil
}
// 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: https://developer.github.com/v3/orgs/teams/#check-if-a-team-manages-a-repository
func (s *OrganizationsService) IsTeamRepo(ctx context.Context, 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 nil, nil, err
}
req.Header.Set("Accept", mediaTypeOrgPermissionRepo)
repository := new(Repository)
resp, err := s.client.Do(ctx, req, repository)
if err != nil {
return nil, resp, err
}
return repository, resp, nil
}
// 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
// specified repository must be owned by the organization to which the team
// belongs, or a direct fork of a repository owned by the organization.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-repo
func (s *OrganizationsService) AddTeamRepo(ctx context.Context, 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, opt)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}
// RemoveTeamRepo removes a repository from being managed by the specified
// team. Note that this does not delete the repository, it just removes it
// from the team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-repo
func (s *OrganizationsService) RemoveTeamRepo(ctx context.Context, team int, owner string, repo string) (*Response, error) {
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}
// ListUserTeams lists a user's teams
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-user-teams
func (s *OrganizationsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]*Team, *Response, error) {
u := "user/teams"
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var teams []*Team
resp, err := s.client.Do(ctx, req, &teams)
if err != nil {
return nil, resp, err
}
return teams, resp, nil
}
// GetTeamMembership returns the membership status for a user in a team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership
func (s *OrganizationsService) GetTeamMembership(ctx context.Context, team int, user string) (*Membership, *Response, error) {
u := fmt.Sprintf("teams/%v/memberships/%v", team, user)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
t := new(Membership)
resp, err := s.client.Do(ctx, req, t)
if err != nil {
return nil, resp, err
}
return t, resp, nil
}
// 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
// user must have 'admin' permissions to the team or be an owner of the
// organization that the team is associated with.
//
// If the user is already a part of the team's organization (meaning they're on
// at least one other team in the organization), this endpoint will add the
// user to the team.
//
// If the user is completely unaffiliated with the team's organization (meaning
// they're on none of the organization's teams), this endpoint will send an
// invitation to the user via email. This newly-created membership will be in
// the "pending" state until the user accepts the invitation, at which point
// the membership will transition to the "active" state and the user will be
// added as a member of the team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-membership
func (s *OrganizationsService) AddTeamMembership(ctx context.Context, 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, opt)
if err != nil {
return nil, nil, err
}
t := new(Membership)
resp, err := s.client.Do(ctx, req, t)
if err != nil {
return nil, resp, err
}
return t, resp, nil
}
// RemoveTeamMembership removes a user from a team.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-membership
func (s *OrganizationsService) RemoveTeamMembership(ctx context.Context, team int, user string) (*Response, error) {
u := fmt.Sprintf("teams/%v/memberships/%v", team, user)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
return s.client.Do(ctx, req, nil)
}
// ListPendingTeamInvitations get pending invitaion list in team.
// Warning: The API may change without advance notice during the preview period.
// Preview features are not supported for production use.
//
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-pending-team-invitations
func (s *OrganizationsService) ListPendingTeamInvitations(ctx context.Context, team int, opt *ListOptions) ([]*Invitation, *Response, error) {
u := fmt.Sprintf("teams/%v/invitations", team)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
var pendingInvitations []*Invitation
resp, err := s.client.Do(ctx, req, &pendingInvitations)
if err != nil {
return nil, resp, err
}
return pendingInvitations, resp, nil
}

View File

@@ -1,581 +0,0 @@
// Copyright 2013 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"context"
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestOrganizationsService_ListTeams(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/teams", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 2}
teams, _, err := client.Organizations.ListTeams(context.Background(), "o", opt)
if err != nil {
t.Errorf("Organizations.ListTeams returned error: %v", err)
}
want := []*Team{{ID: Int(1)}}
if !reflect.DeepEqual(teams, want) {
t.Errorf("Organizations.ListTeams returned %+v, want %+v", teams, want)
}
}
func TestOrganizationsService_ListTeams_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.ListTeams(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_GetTeam(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"id":1, "name":"n", "description": "d", "url":"u", "slug": "s", "permission":"p", "ldap_dn":"cn=n,ou=groups,dc=example,dc=com"}`)
})
team, _, err := client.Organizations.GetTeam(context.Background(), 1)
if err != nil {
t.Errorf("Organizations.GetTeam returned error: %v", err)
}
want := &Team{ID: Int(1), Name: String("n"), Description: String("d"), URL: String("u"), Slug: String("s"), Permission: String("p"), LDAPDN: String("cn=n,ou=groups,dc=example,dc=com")}
if !reflect.DeepEqual(team, want) {
t.Errorf("Organizations.GetTeam returned %+v, want %+v", team, want)
}
}
func TestOrganizationsService_CreateTeam(t *testing.T) {
setup()
defer teardown()
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")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
team, _, err := client.Organizations.CreateTeam(context.Background(), "o", input)
if err != nil {
t.Errorf("Organizations.CreateTeam returned error: %v", err)
}
want := &Team{ID: Int(1)}
if !reflect.DeepEqual(team, want) {
t.Errorf("Organizations.CreateTeam returned %+v, want %+v", team, want)
}
}
func TestOrganizationsService_CreateTeam_invalidOrg(t *testing.T) {
_, _, err := client.Organizations.CreateTeam(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_EditTeam(t *testing.T) {
setup()
defer teardown()
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")
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
})
team, _, err := client.Organizations.EditTeam(context.Background(), 1, input)
if err != nil {
t.Errorf("Organizations.EditTeam returned error: %v", err)
}
want := &Team{ID: Int(1)}
if !reflect.DeepEqual(team, want) {
t.Errorf("Organizations.EditTeam returned %+v, want %+v", team, want)
}
}
func TestOrganizationsService_DeleteTeam(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
})
_, err := client.Organizations.DeleteTeam(context.Background(), 1)
if err != nil {
t.Errorf("Organizations.DeleteTeam returned error: %v", err)
}
}
func TestOrganizationsService_ListTeamMembers(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"role": "member", "page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &OrganizationListTeamMembersOptions{Role: "member", ListOptions: ListOptions{Page: 2}}
members, _, err := client.Organizations.ListTeamMembers(context.Background(), 1, opt)
if err != nil {
t.Errorf("Organizations.ListTeamMembers returned error: %v", err)
}
want := []*User{{ID: Int(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListTeamMembers returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_IsTeamMember_true(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
})
member, _, err := client.Organizations.IsTeamMember(context.Background(), 1, "u")
if err != nil {
t.Errorf("Organizations.IsTeamMember returned error: %v", err)
}
if want := true; member != want {
t.Errorf("Organizations.IsTeamMember returned %+v, want %+v", member, want)
}
}
// ensure that a 404 response is interpreted as "false" and not an error
func TestOrganizationsService_IsTeamMember_false(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
member, _, err := client.Organizations.IsTeamMember(context.Background(), 1, "u")
if err != nil {
t.Errorf("Organizations.IsTeamMember returned error: %+v", err)
}
if want := false; member != want {
t.Errorf("Organizations.IsTeamMember returned %+v, want %+v", member, want)
}
}
// ensure that a 400 response is interpreted as an actual error, and not simply
// as "false" like the above case of a 404
func TestOrganizationsService_IsTeamMember_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
http.Error(w, "BadRequest", http.StatusBadRequest)
})
member, _, err := client.Organizations.IsTeamMember(context.Background(), 1, "u")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
if want := false; member != want {
t.Errorf("Organizations.IsTeamMember returned %+v, want %+v", member, want)
}
}
func TestOrganizationsService_IsTeamMember_invalidUser(t *testing.T) {
_, _, err := client.Organizations.IsTeamMember(context.Background(), 1, "%")
testURLParseError(t, err)
}
func TestOrganizationsService_PublicizeMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.PublicizeMembership(context.Background(), "o", "u")
if err != nil {
t.Errorf("Organizations.PublicizeMembership returned error: %v", err)
}
}
func TestOrganizationsService_PublicizeMembership_invalidOrg(t *testing.T) {
_, err := client.Organizations.PublicizeMembership(context.Background(), "%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_ConcealMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/orgs/o/public_members/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.ConcealMembership(context.Background(), "o", "u")
if err != nil {
t.Errorf("Organizations.ConcealMembership returned error: %v", err)
}
}
func TestOrganizationsService_ConcealMembership_invalidOrg(t *testing.T) {
_, err := client.Organizations.ConcealMembership(context.Background(), "%", "u")
testURLParseError(t, err)
}
func TestOrganizationsService_ListTeamRepos(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeTopicsPreview)
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 2}
members, _, err := client.Organizations.ListTeamRepos(context.Background(), 1, opt)
if err != nil {
t.Errorf("Organizations.ListTeamRepos returned error: %v", err)
}
want := []*Repository{{ID: Int(1)}}
if !reflect.DeepEqual(members, want) {
t.Errorf("Organizations.ListTeamRepos returned %+v, want %+v", members, want)
}
}
func TestOrganizationsService_IsTeamRepo_true(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeOrgPermissionRepo)
fmt.Fprint(w, `{"id":1}`)
})
repo, _, err := client.Organizations.IsTeamRepo(context.Background(), 1, "o", "r")
if err != nil {
t.Errorf("Organizations.IsTeamRepo returned error: %v", err)
}
want := &Repository{ID: Int(1)}
if !reflect.DeepEqual(repo, want) {
t.Errorf("Organizations.IsTeamRepo returned %+v, want %+v", repo, want)
}
}
func TestOrganizationsService_IsTeamRepo_false(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
w.WriteHeader(http.StatusNotFound)
})
repo, resp, err := client.Organizations.IsTeamRepo(context.Background(), 1, "o", "r")
if err == nil {
t.Errorf("Expected HTTP 404 response")
}
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)
}
}
func TestOrganizationsService_IsTeamRepo_error(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
http.Error(w, "BadRequest", http.StatusBadRequest)
})
repo, resp, err := client.Organizations.IsTeamRepo(context.Background(), 1, "o", "r")
if err == nil {
t.Errorf("Expected HTTP 400 response")
}
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)
}
}
func TestOrganizationsService_IsTeamRepo_invalidOwner(t *testing.T) {
_, _, err := client.Organizations.IsTeamRepo(context.Background(), 1, "%", "r")
testURLParseError(t, err)
}
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")
if !reflect.DeepEqual(v, opt) {
t.Errorf("Request body = %+v, want %+v", v, opt)
}
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.AddTeamRepo(context.Background(), 1, "o", "r", opt)
if err != nil {
t.Errorf("Organizations.AddTeamRepo returned error: %v", err)
}
}
func TestOrganizationsService_AddTeamRepo_noAccess(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
w.WriteHeader(http.StatusUnprocessableEntity)
})
_, err := client.Organizations.AddTeamRepo(context.Background(), 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(context.Background(), 1, "%", "r", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_RemoveTeamRepo(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/repos/o/r", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.RemoveTeamRepo(context.Background(), 1, "o", "r")
if err != nil {
t.Errorf("Organizations.RemoveTeamRepo returned error: %v", err)
}
}
func TestOrganizationsService_RemoveTeamRepo_invalidOwner(t *testing.T) {
_, err := client.Organizations.RemoveTeamRepo(context.Background(), 1, "%", "r")
testURLParseError(t, err)
}
func TestOrganizationsService_GetTeamMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{"url":"u", "state":"active"}`)
})
membership, _, err := client.Organizations.GetTeamMembership(context.Background(), 1, "u")
if err != nil {
t.Errorf("Organizations.GetTeamMembership returned error: %v", err)
}
want := &Membership{URL: String("u"), State: String("active")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.GetTeamMembership returned %+v, want %+v", membership, want)
}
}
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")
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(context.Background(), 1, "u", opt)
if err != nil {
t.Errorf("Organizations.AddTeamMembership returned error: %v", err)
}
want := &Membership{URL: String("u"), State: String("pending")}
if !reflect.DeepEqual(membership, want) {
t.Errorf("Organizations.AddTeamMembership returned %+v, want %+v", membership, want)
}
}
func TestOrganizationsService_RemoveTeamMembership(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/memberships/u", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Organizations.RemoveTeamMembership(context.Background(), 1, "u")
if err != nil {
t.Errorf("Organizations.RemoveTeamMembership returned error: %v", err)
}
}
func TestOrganizationsService_ListUserTeams(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/teams", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "1"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 1}
teams, _, err := client.Organizations.ListUserTeams(context.Background(), opt)
if err != nil {
t.Errorf("Organizations.ListUserTeams returned error: %v", err)
}
want := []*Team{{ID: Int(1)}}
if !reflect.DeepEqual(teams, want) {
t.Errorf("Organizations.ListUserTeams returned %+v, want %+v", teams, want)
}
}
func TestOrganizationsService_ListPendingTeamInvitations(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/teams/1/invitations", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"page": "1"})
fmt.Fprint(w, `[
{
"id": 1,
"login": "monalisa",
"email": "octocat@github.com",
"role": "direct_member",
"created_at": "2017-01-21T00:00:00Z",
"inviter": {
"login": "other_user",
"id": 1,
"avatar_url": "https://github.com/images/error/other_user_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/other_user",
"html_url": "https://github.com/other_user",
"followers_url": "https://api.github.com/users/other_user/followers",
"following_url": "https://api.github.com/users/other_user/following/other_user",
"gists_url": "https://api.github.com/users/other_user/gists/gist_id",
"starred_url": "https://api.github.com/users/other_user/starred/owner/repo",
"subscriptions_url": "https://api.github.com/users/other_user/subscriptions",
"organizations_url": "https://api.github.com/users/other_user/orgs",
"repos_url": "https://api.github.com/users/other_user/repos",
"events_url": "https://api.github.com/users/other_user/events/privacy",
"received_events_url": "https://api.github.com/users/other_user/received_events/privacy",
"type": "User",
"site_admin": false
}
}
]`)
})
opt := &ListOptions{Page: 1}
invitations, _, err := client.Organizations.ListPendingTeamInvitations(context.Background(), 1, opt)
if err != nil {
t.Errorf("Organizations.ListPendingTeamInvitations returned error: %v", err)
}
createdAt := time.Date(2017, 01, 21, 0, 0, 0, 0, time.UTC)
want := []*Invitation{
{
ID: Int(1),
Login: String("monalisa"),
Email: String("octocat@github.com"),
Role: String("direct_member"),
CreatedAt: &createdAt,
Inviter: &User{
Login: String("other_user"),
ID: Int(1),
AvatarURL: String("https://github.com/images/error/other_user_happy.gif"),
GravatarID: String(""),
URL: String("https://api.github.com/users/other_user"),
HTMLURL: String("https://github.com/other_user"),
FollowersURL: String("https://api.github.com/users/other_user/followers"),
FollowingURL: String("https://api.github.com/users/other_user/following/other_user"),
GistsURL: String("https://api.github.com/users/other_user/gists/gist_id"),
StarredURL: String("https://api.github.com/users/other_user/starred/owner/repo"),
SubscriptionsURL: String("https://api.github.com/users/other_user/subscriptions"),
OrganizationsURL: String("https://api.github.com/users/other_user/orgs"),
ReposURL: String("https://api.github.com/users/other_user/repos"),
EventsURL: String("https://api.github.com/users/other_user/events/privacy"),
ReceivedEventsURL: String("https://api.github.com/users/other_user/received_events/privacy"),
Type: String("User"),
SiteAdmin: Bool(false),
},
}}
if !reflect.DeepEqual(invitations, want) {
t.Errorf("Organizations.ListPendingTeamInvitations returned %+v, want %+v", invitations, want)
}
}

View File

@@ -15,10 +15,10 @@ import (
)
func TestOrganizationsService_ListAll(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
since := 1342004
since := int64(1342004)
mux.HandleFunc("/organizations", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testFormValues(t, r, values{"since": "1342004"})
@@ -31,14 +31,14 @@ func TestOrganizationsService_ListAll(t *testing.T) {
t.Errorf("Organizations.ListAll returned error: %v", err)
}
want := []*Organization{{ID: Int(4314092)}}
want := []*Organization{{ID: Int64(4314092)}}
if !reflect.DeepEqual(orgs, want) {
t.Errorf("Organizations.ListAll returned %+v, want %+v", orgs, want)
}
}
func TestOrganizationsService_List_authenticatedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/user/orgs", func(w http.ResponseWriter, r *http.Request) {
@@ -51,14 +51,14 @@ func TestOrganizationsService_List_authenticatedUser(t *testing.T) {
t.Errorf("Organizations.List returned error: %v", err)
}
want := []*Organization{{ID: Int(1)}, {ID: Int(2)}}
want := []*Organization{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(orgs, want) {
t.Errorf("Organizations.List returned %+v, want %+v", orgs, want)
}
}
func TestOrganizationsService_List_specifiedUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/users/u/orgs", func(w http.ResponseWriter, r *http.Request) {
@@ -73,19 +73,22 @@ func TestOrganizationsService_List_specifiedUser(t *testing.T) {
t.Errorf("Organizations.List returned error: %v", err)
}
want := []*Organization{{ID: Int(1)}, {ID: Int(2)}}
want := []*Organization{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(orgs, want) {
t.Errorf("Organizations.List returned %+v, want %+v", orgs, want)
}
}
func TestOrganizationsService_List_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.List(context.Background(), "%", nil)
testURLParseError(t, err)
}
func TestOrganizationsService_Get(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o", func(w http.ResponseWriter, r *http.Request) {
@@ -98,19 +101,22 @@ func TestOrganizationsService_Get(t *testing.T) {
t.Errorf("Organizations.Get returned error: %v", err)
}
want := &Organization{ID: Int(1), Login: String("l"), URL: String("u"), AvatarURL: String("a"), Location: String("l")}
want := &Organization{ID: Int64(1), Login: String("l"), URL: String("u"), AvatarURL: String("a"), Location: String("l")}
if !reflect.DeepEqual(org, want) {
t.Errorf("Organizations.Get returned %+v, want %+v", org, want)
}
}
func TestOrganizationsService_Get_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.Get(context.Background(), "%")
testURLParseError(t, err)
}
func TestOrganizationsService_GetByID(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/organizations/1", func(w http.ResponseWriter, r *http.Request) {
@@ -123,14 +129,14 @@ func TestOrganizationsService_GetByID(t *testing.T) {
t.Fatalf("Organizations.GetByID returned error: %v", err)
}
want := &Organization{ID: Int(1), Login: String("l"), URL: String("u"), AvatarURL: String("a"), Location: String("l")}
want := &Organization{ID: Int64(1), Login: String("l"), URL: String("u"), AvatarURL: String("a"), Location: String("l")}
if !reflect.DeepEqual(org, want) {
t.Errorf("Organizations.GetByID returned %+v, want %+v", org, want)
}
}
func TestOrganizationsService_Edit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &Organization{Login: String("l")}
@@ -152,13 +158,16 @@ func TestOrganizationsService_Edit(t *testing.T) {
t.Errorf("Organizations.Edit returned error: %v", err)
}
want := &Organization{ID: Int(1)}
want := &Organization{ID: Int64(1)}
if !reflect.DeepEqual(org, want) {
t.Errorf("Organizations.Edit returned %+v, want %+v", org, want)
}
}
func TestOrganizationsService_Edit_invalidOrg(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Organizations.Edit(context.Background(), "%", nil)
testURLParseError(t, err)
}

View File

@@ -14,7 +14,7 @@ import (
)
func TestOrganizationsService_ListBlockedUsers(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/blocks", func(w http.ResponseWriter, r *http.Request) {
@@ -39,7 +39,7 @@ func TestOrganizationsService_ListBlockedUsers(t *testing.T) {
}
func TestOrganizationsService_IsBlocked(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/blocks/u", func(w http.ResponseWriter, r *http.Request) {
@@ -58,7 +58,7 @@ func TestOrganizationsService_IsBlocked(t *testing.T) {
}
func TestOrganizationsService_BlockUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/blocks/u", func(w http.ResponseWriter, r *http.Request) {
@@ -74,7 +74,7 @@ func TestOrganizationsService_BlockUser(t *testing.T) {
}
func TestOrganizationsService_UnblockUser(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/orgs/o/blocks/u", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -18,14 +18,18 @@ type ProjectsService service
// Project represents a GitHub Project.
type Project struct {
ID *int `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
OwnerURL *string `json:"owner_url,omitempty"`
Name *string `json:"name,omitempty"`
Body *string `json:"body,omitempty"`
Number *int `json:"number,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
ID *int64 `json:"id,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
ColumnsURL *string `json:"columns_url,omitempty"`
OwnerURL *string `json:"owner_url,omitempty"`
Name *string `json:"name,omitempty"`
Body *string `json:"body,omitempty"`
Number *int `json:"number,omitempty"`
State *string `json:"state,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
// The User object that generated the project.
Creator *User `json:"creator,omitempty"`
@@ -38,14 +42,14 @@ func (p Project) String() string {
// GetProject gets a GitHub Project for a repo.
//
// GitHub API docs: https://developer.github.com/v3/projects/#get-a-project
func (s *ProjectsService) GetProject(ctx context.Context, id int) (*Project, *Response, error) {
func (s *ProjectsService) GetProject(ctx context.Context, id int64) (*Project, *Response, error) {
u := fmt.Sprintf("projects/%v", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
project := &Project{}
@@ -62,22 +66,37 @@ func (s *ProjectsService) GetProject(ctx context.Context, id int) (*Project, *Re
// ProjectsService.UpdateProject methods.
type ProjectOptions struct {
// The name of the project. (Required for creation; optional for update.)
Name string `json:"name,omitempty"`
Name *string `json:"name,omitempty"`
// The body of the project. (Optional.)
Body string `json:"body,omitempty"`
Body *string `json:"body,omitempty"`
// The following field(s) are only applicable for update.
// They should be left with zero values for creation.
// State of the project. Either "open" or "closed". (Optional.)
State *string `json:"state,omitempty"`
// The permission level that all members of the project's organization
// will have on this project.
// Setting the organization permission is only available
// for organization projects. (Optional.)
OrganizationPermission *string `json:"organization_permission,omitempty"`
// Sets visibility of the project within the organization.
// Setting visibility is only available
// for organization projects.(Optional.)
Public *bool `json:"public,omitempty"`
}
// UpdateProject updates a repository project.
//
// GitHub API docs: https://developer.github.com/v3/projects/#update-a-project
func (s *ProjectsService) UpdateProject(ctx context.Context, id int, opt *ProjectOptions) (*Project, *Response, error) {
func (s *ProjectsService) UpdateProject(ctx context.Context, id int64, opt *ProjectOptions) (*Project, *Response, error) {
u := fmt.Sprintf("projects/%v", id)
req, err := s.client.NewRequest("PATCH", u, opt)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
project := &Project{}
@@ -92,7 +111,7 @@ func (s *ProjectsService) UpdateProject(ctx context.Context, id int, opt *Projec
// DeleteProject deletes a GitHub Project from a repository.
//
// GitHub API docs: https://developer.github.com/v3/projects/#delete-a-project
func (s *ProjectsService) DeleteProject(ctx context.Context, id int) (*Response, error) {
func (s *ProjectsService) DeleteProject(ctx context.Context, id int64) (*Response, error) {
u := fmt.Sprintf("projects/%v", id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
@@ -109,17 +128,20 @@ func (s *ProjectsService) DeleteProject(ctx context.Context, id int) (*Response,
//
// GitHub API docs: https://developer.github.com/v3/repos/projects/
type ProjectColumn struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
URL *string `json:"url,omitempty"`
ProjectURL *string `json:"project_url,omitempty"`
CardsURL *string `json:"cards_url,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
}
// ListProjectColumns lists the columns of a GitHub Project for a repo.
//
// GitHub API docs: https://developer.github.com/v3/projects/columns/#list-project-columns
func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int, opt *ListOptions) ([]*ProjectColumn, *Response, error) {
func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int64, opt *ListOptions) ([]*ProjectColumn, *Response, error) {
u := fmt.Sprintf("projects/%v/columns", projectID)
u, err := addOptions(u, opt)
if err != nil {
@@ -131,7 +153,7 @@ func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
columns := []*ProjectColumn{}
@@ -146,14 +168,14 @@ func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int,
// GetProjectColumn gets a column of a GitHub Project for a repo.
//
// GitHub API docs: https://developer.github.com/v3/projects/columns/#get-a-project-column
func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int) (*ProjectColumn, *Response, error) {
func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int64) (*ProjectColumn, *Response, error) {
u := fmt.Sprintf("projects/columns/%v", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
column := &ProjectColumn{}
@@ -176,14 +198,14 @@ type ProjectColumnOptions struct {
// CreateProjectColumn creates a column for the specified (by number) project.
//
// GitHub API docs: https://developer.github.com/v3/projects/columns/#create-a-project-column
func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) {
func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int64, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) {
u := fmt.Sprintf("projects/%v/columns", projectID)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
column := &ProjectColumn{}
@@ -198,14 +220,14 @@ func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int
// UpdateProjectColumn updates a column of a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/columns/#update-a-project-column
func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) {
func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int64, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) {
u := fmt.Sprintf("projects/columns/%v", columnID)
req, err := s.client.NewRequest("PATCH", u, opt)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
column := &ProjectColumn{}
@@ -220,7 +242,7 @@ func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int,
// DeleteProjectColumn deletes a column from a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/columns/#delete-a-project-column
func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int) (*Response, error) {
func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int64) (*Response, error) {
u := fmt.Sprintf("projects/columns/%v", columnID)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
@@ -244,7 +266,7 @@ type ProjectColumnMoveOptions struct {
// MoveProjectColumn moves a column within a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/columns/#move-a-project-column
func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int, opt *ProjectColumnMoveOptions) (*Response, error) {
func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int64, opt *ProjectColumnMoveOptions) (*Response, error) {
u := fmt.Sprintf("projects/columns/%v/moves", columnID)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
@@ -264,20 +286,32 @@ type ProjectCard struct {
URL *string `json:"url,omitempty"`
ColumnURL *string `json:"column_url,omitempty"`
ContentURL *string `json:"content_url,omitempty"`
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
Note *string `json:"note,omitempty"`
Creator *User `json:"creator,omitempty"`
CreatedAt *Timestamp `json:"created_at,omitempty"`
UpdatedAt *Timestamp `json:"updated_at,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Archived *bool `json:"archived,omitempty"`
// The following fields are only populated by Webhook events.
ColumnID *int `json:"column_id,omitempty"`
ColumnID *int64 `json:"column_id,omitempty"`
}
// ProjectCardListOptions specifies the optional parameters to the
// ProjectsService.ListProjectCards method.
type ProjectCardListOptions struct {
// ArchivedState is used to list all, archived, or not_archived project cards.
// Defaults to not_archived when you omit this parameter.
ArchivedState *string `url:"archived_state,omitempty"`
ListOptions
}
// ListProjectCards lists the cards in a column of a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards
func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int, opt *ListOptions) ([]*ProjectCard, *Response, error) {
func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opt *ProjectCardListOptions) ([]*ProjectCard, *Response, error) {
u := fmt.Sprintf("projects/columns/%v/cards", columnID)
u, err := addOptions(u, opt)
if err != nil {
@@ -289,7 +323,7 @@ func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int, op
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
cards := []*ProjectCard{}
@@ -304,14 +338,14 @@ func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int, op
// GetProjectCard gets a card in a column of a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card
func (s *ProjectsService) GetProjectCard(ctx context.Context, columnID int) (*ProjectCard, *Response, error) {
func (s *ProjectsService) GetProjectCard(ctx context.Context, columnID int64) (*ProjectCard, *Response, error) {
u := fmt.Sprintf("projects/columns/cards/%v", columnID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
card := &ProjectCard{}
@@ -331,22 +365,25 @@ type ProjectCardOptions struct {
Note string `json:"note,omitempty"`
// The ID (not Number) of the Issue to associate with this card.
// Note and ContentID are mutually exclusive.
ContentID int `json:"content_id,omitempty"`
// The type of content to associate with this card. Possible values are: "Issue".
ContentID int64 `json:"content_id,omitempty"`
// The type of content to associate with this card. Possible values are: "Issue" and "PullRequest".
ContentType string `json:"content_type,omitempty"`
// Use true to archive a project card.
// Specify false if you need to restore a previously archived project card.
Archived *bool `json:"archived,omitempty"`
}
// CreateProjectCard creates a card in the specified column of a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/cards/#create-a-project-card
func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int, opt *ProjectCardOptions) (*ProjectCard, *Response, error) {
func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int64, opt *ProjectCardOptions) (*ProjectCard, *Response, error) {
u := fmt.Sprintf("projects/columns/%v/cards", columnID)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
card := &ProjectCard{}
@@ -361,14 +398,14 @@ func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int, o
// UpdateProjectCard updates a card of a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/cards/#update-a-project-card
func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int, opt *ProjectCardOptions) (*ProjectCard, *Response, error) {
func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int64, opt *ProjectCardOptions) (*ProjectCard, *Response, error) {
u := fmt.Sprintf("projects/columns/cards/%v", cardID)
req, err := s.client.NewRequest("PATCH", u, opt)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeProjectsPreview)
card := &ProjectCard{}
@@ -383,7 +420,7 @@ func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int, opt
// DeleteProjectCard deletes a card from a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/cards/#delete-a-project-card
func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int) (*Response, error) {
func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int64) (*Response, error) {
u := fmt.Sprintf("projects/columns/cards/%v", cardID)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
@@ -405,13 +442,13 @@ type ProjectCardMoveOptions struct {
// ColumnID is the ID of a column in the same project. Note that ColumnID
// is required when using Position "after:<card-id>" when that card is in
// another column; otherwise it is optional.
ColumnID int `json:"column_id,omitempty"`
ColumnID int64 `json:"column_id,omitempty"`
}
// MoveProjectCard moves a card within a GitHub Project.
//
// GitHub API docs: https://developer.github.com/v3/projects/cards/#move-a-project-card
func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int, opt *ProjectCardMoveOptions) (*Response, error) {
func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int64, opt *ProjectCardMoveOptions) (*Response, error) {
u := fmt.Sprintf("projects/columns/cards/%v/moves", cardID)
req, err := s.client.NewRequest("POST", u, opt)
if err != nil {

View File

@@ -11,14 +11,22 @@ import (
"fmt"
"net/http"
"reflect"
"strings"
"testing"
)
func TestProjectsService_UpdateProject(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectOptions{Name: "Project Name", Body: "Project body."}
input := &ProjectOptions{
Name: String("Project Name"),
Body: String("Project body."),
State: String("open"),
Public: Bool(true),
OrganizationPermission: String("read"),
}
mux.HandleFunc("/projects/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PATCH")
@@ -38,14 +46,14 @@ func TestProjectsService_UpdateProject(t *testing.T) {
t.Errorf("Projects.UpdateProject returned error: %v", err)
}
want := &Project{ID: Int(1)}
want := &Project{ID: Int64(1)}
if !reflect.DeepEqual(project, want) {
t.Errorf("Projects.UpdateProject returned %+v, want %+v", project, want)
}
}
func TestProjectsService_GetProject(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/projects/1", func(w http.ResponseWriter, r *http.Request) {
@@ -59,14 +67,14 @@ func TestProjectsService_GetProject(t *testing.T) {
t.Errorf("Projects.GetProject returned error: %v", err)
}
want := &Project{ID: Int(1)}
want := &Project{ID: Int64(1)}
if !reflect.DeepEqual(project, want) {
t.Errorf("Projects.GetProject returned %+v, want %+v", project, want)
}
}
func TestProjectsService_DeleteProject(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/projects/1", func(w http.ResponseWriter, r *http.Request) {
@@ -81,12 +89,13 @@ func TestProjectsService_DeleteProject(t *testing.T) {
}
func TestProjectsService_ListProjectColumns(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeProjectsPreview}
mux.HandleFunc("/projects/1/columns", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeProjectsPreview)
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
testFormValues(t, r, values{"page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
@@ -97,14 +106,14 @@ func TestProjectsService_ListProjectColumns(t *testing.T) {
t.Errorf("Projects.ListProjectColumns returned error: %v", err)
}
want := []*ProjectColumn{{ID: Int(1)}}
want := []*ProjectColumn{{ID: Int64(1)}}
if !reflect.DeepEqual(columns, want) {
t.Errorf("Projects.ListProjectColumns returned %+v, want %+v", columns, want)
}
}
func TestProjectsService_GetProjectColumn(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/projects/columns/1", func(w http.ResponseWriter, r *http.Request) {
@@ -118,14 +127,14 @@ func TestProjectsService_GetProjectColumn(t *testing.T) {
t.Errorf("Projects.GetProjectColumn returned error: %v", err)
}
want := &ProjectColumn{ID: Int(1)}
want := &ProjectColumn{ID: Int64(1)}
if !reflect.DeepEqual(column, want) {
t.Errorf("Projects.GetProjectColumn returned %+v, want %+v", column, want)
}
}
func TestProjectsService_CreateProjectColumn(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectColumnOptions{Name: "Column Name"}
@@ -148,14 +157,14 @@ func TestProjectsService_CreateProjectColumn(t *testing.T) {
t.Errorf("Projects.CreateProjectColumn returned error: %v", err)
}
want := &ProjectColumn{ID: Int(1)}
want := &ProjectColumn{ID: Int64(1)}
if !reflect.DeepEqual(column, want) {
t.Errorf("Projects.CreateProjectColumn returned %+v, want %+v", column, want)
}
}
func TestProjectsService_UpdateProjectColumn(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectColumnOptions{Name: "Column Name"}
@@ -178,14 +187,14 @@ func TestProjectsService_UpdateProjectColumn(t *testing.T) {
t.Errorf("Projects.UpdateProjectColumn returned error: %v", err)
}
want := &ProjectColumn{ID: Int(1)}
want := &ProjectColumn{ID: Int64(1)}
if !reflect.DeepEqual(column, want) {
t.Errorf("Projects.UpdateProjectColumn returned %+v, want %+v", column, want)
}
}
func TestProjectsService_DeleteProjectColumn(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/projects/columns/1", func(w http.ResponseWriter, r *http.Request) {
@@ -200,7 +209,7 @@ func TestProjectsService_DeleteProjectColumn(t *testing.T) {
}
func TestProjectsService_MoveProjectColumn(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectColumnMoveOptions{Position: "after:12345"}
@@ -223,30 +232,34 @@ func TestProjectsService_MoveProjectColumn(t *testing.T) {
}
func TestProjectsService_ListProjectCards(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/projects/columns/1/cards", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeProjectsPreview)
testFormValues(t, r, values{"page": "2"})
testFormValues(t, r, values{
"archived_state": "all",
"page": "2"})
fmt.Fprint(w, `[{"id":1}]`)
})
opt := &ListOptions{Page: 2}
opt := &ProjectCardListOptions{
ArchivedState: String("all"),
ListOptions: ListOptions{Page: 2}}
cards, _, err := client.Projects.ListProjectCards(context.Background(), 1, opt)
if err != nil {
t.Errorf("Projects.ListProjectCards returned error: %v", err)
}
want := []*ProjectCard{{ID: Int(1)}}
want := []*ProjectCard{{ID: Int64(1)}}
if !reflect.DeepEqual(cards, want) {
t.Errorf("Projects.ListProjectCards returned %+v, want %+v", cards, want)
}
}
func TestProjectsService_GetProjectCard(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/projects/columns/cards/1", func(w http.ResponseWriter, r *http.Request) {
@@ -260,14 +273,14 @@ func TestProjectsService_GetProjectCard(t *testing.T) {
t.Errorf("Projects.GetProjectCard returned error: %v", err)
}
want := &ProjectCard{ID: Int(1)}
want := &ProjectCard{ID: Int64(1)}
if !reflect.DeepEqual(card, want) {
t.Errorf("Projects.GetProjectCard returned %+v, want %+v", card, want)
}
}
func TestProjectsService_CreateProjectCard(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectCardOptions{
@@ -293,14 +306,14 @@ func TestProjectsService_CreateProjectCard(t *testing.T) {
t.Errorf("Projects.CreateProjectCard returned error: %v", err)
}
want := &ProjectCard{ID: Int(1)}
want := &ProjectCard{ID: Int64(1)}
if !reflect.DeepEqual(card, want) {
t.Errorf("Projects.CreateProjectCard returned %+v, want %+v", card, want)
}
}
func TestProjectsService_UpdateProjectCard(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectCardOptions{
@@ -318,7 +331,7 @@ func TestProjectsService_UpdateProjectCard(t *testing.T) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
fmt.Fprint(w, `{"id":1}`)
fmt.Fprint(w, `{"id":1, "archived":false}`)
})
card, _, err := client.Projects.UpdateProjectCard(context.Background(), 1, input)
@@ -326,14 +339,14 @@ func TestProjectsService_UpdateProjectCard(t *testing.T) {
t.Errorf("Projects.UpdateProjectCard returned error: %v", err)
}
want := &ProjectCard{ID: Int(1)}
want := &ProjectCard{ID: Int64(1), Archived: Bool(false)}
if !reflect.DeepEqual(card, want) {
t.Errorf("Projects.UpdateProjectCard returned %+v, want %+v", card, want)
}
}
func TestProjectsService_DeleteProjectCard(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/projects/columns/cards/1", func(w http.ResponseWriter, r *http.Request) {
@@ -348,7 +361,7 @@ func TestProjectsService_DeleteProjectCard(t *testing.T) {
}
func TestProjectsService_MoveProjectCard(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &ProjectCardMoveOptions{Position: "after:12345"}

View File

@@ -9,6 +9,7 @@ import (
"bytes"
"context"
"fmt"
"strings"
"time"
)
@@ -20,7 +21,7 @@ type PullRequestsService service
// PullRequest represents a GitHub pull request on a repository.
type PullRequest struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
Number *int `json:"number,omitempty"`
State *string `json:"state,omitempty"`
Title *string `json:"title,omitempty"`
@@ -29,9 +30,11 @@ type PullRequest struct {
UpdatedAt *time.Time `json:"updated_at,omitempty"`
ClosedAt *time.Time `json:"closed_at,omitempty"`
MergedAt *time.Time `json:"merged_at,omitempty"`
Labels []*Label `json:"labels,omitempty"`
User *User `json:"user,omitempty"`
Merged *bool `json:"merged,omitempty"`
Mergeable *bool `json:"mergeable,omitempty"`
MergeableState *string `json:"mergeable_state,omitempty"`
MergedBy *User `json:"merged_by,omitempty"`
MergeCommitSHA *string `json:"merge_commit_sha,omitempty"`
Comments *int `json:"comments,omitempty"`
@@ -45,21 +48,52 @@ type PullRequest struct {
StatusesURL *string `json:"statuses_url,omitempty"`
DiffURL *string `json:"diff_url,omitempty"`
PatchURL *string `json:"patch_url,omitempty"`
CommitsURL *string `json:"commits_url,omitempty"`
CommentsURL *string `json:"comments_url,omitempty"`
ReviewCommentsURL *string `json:"review_comments_url,omitempty"`
ReviewCommentURL *string `json:"review_comment_url,omitempty"`
Assignee *User `json:"assignee,omitempty"`
Assignees []*User `json:"assignees,omitempty"`
Milestone *Milestone `json:"milestone,omitempty"`
MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"`
AuthorAssociation *string `json:"author_association,omitempty"`
NodeID *string `json:"node_id,omitempty"`
RequestedReviewers []*User `json:"requested_reviewers,omitempty"`
Head *PullRequestBranch `json:"head,omitempty"`
Base *PullRequestBranch `json:"base,omitempty"`
// RequestedTeams is populated as part of the PullRequestEvent.
// See, https://developer.github.com/v3/activity/events/types/#pullrequestevent for an example.
RequestedTeams []*Team `json:"requested_teams,omitempty"`
Links *PRLinks `json:"_links,omitempty"`
Head *PullRequestBranch `json:"head,omitempty"`
Base *PullRequestBranch `json:"base,omitempty"`
// ActiveLockReason is populated only when LockReason is provided while locking the pull request.
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
ActiveLockReason *string `json:"active_lock_reason,omitempty"`
}
func (p PullRequest) String() string {
return Stringify(p)
}
// PRLink represents a single link object from Github pull request _links.
type PRLink struct {
HRef *string `json:"href,omitempty"`
}
// PRLinks represents the "_links" object in a Github pull request.
type PRLinks struct {
Self *PRLink `json:"self,omitempty"`
HTML *PRLink `json:"html,omitempty"`
Issue *PRLink `json:"issue,omitempty"`
Comments *PRLink `json:"comments,omitempty"`
ReviewComments *PRLink `json:"review_comments,omitempty"`
ReviewComment *PRLink `json:"review_comment,omitempty"`
Commits *PRLink `json:"commits,omitempty"`
Statuses *PRLink `json:"statuses,omitempty"`
}
// PullRequestBranch represents a base or head branch in a GitHub pull request.
type PullRequestBranch struct {
Label *string `json:"label,omitempty"`
@@ -73,7 +107,7 @@ type PullRequestBranch struct {
// PullRequestsService.List method.
type PullRequestListOptions struct {
// State filters pull requests based on their state. Possible values are:
// open, closed. Default is "open".
// open, closed, all. Default is "open".
State string `url:"state,omitempty"`
// Head filters pull requests by head user and branch name in the format of:
@@ -110,6 +144,10 @@ func (s *PullRequestsService) List(ctx context.Context, owner string, repo strin
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var pulls []*PullRequest
resp, err := s.client.Do(ctx, req, &pulls)
if err != nil {
@@ -129,6 +167,10 @@ func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
pull := new(PullRequest)
resp, err := s.client.Do(ctx, req, pull)
if err != nil {
@@ -138,7 +180,7 @@ func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string
return pull, resp, nil
}
// GetRaw gets raw (diff or patch) format of a pull request.
// GetRaw gets a single pull request in raw (diff or patch) format.
func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo string, number int, opt RawOptions) (string, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number)
req, err := s.client.NewRequest("GET", u, nil)
@@ -155,13 +197,13 @@ func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo str
return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type)
}
ret := new(bytes.Buffer)
resp, err := s.client.Do(ctx, req, ret)
var buf bytes.Buffer
resp, err := s.client.Do(ctx, req, &buf)
if err != nil {
return "", resp, err
}
return ret.String(), resp, nil
return buf.String(), resp, nil
}
// NewPullRequest represents a new pull request to be created.
@@ -184,6 +226,9 @@ func (s *PullRequestsService) Create(ctx context.Context, owner string, repo str
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview)
p := new(PullRequest)
resp, err := s.client.Do(ctx, req, p)
if err != nil {
@@ -230,6 +275,10 @@ func (s *PullRequestsService) Edit(ctx context.Context, owner string, repo strin
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
p := new(PullRequest)
resp, err := s.client.Do(ctx, req, p)
if err != nil {

View File

@@ -13,22 +13,26 @@ import (
// PullRequestComment represents a comment left on a pull request.
type PullRequestComment struct {
ID *int `json:"id,omitempty"`
InReplyTo *int `json:"in_reply_to,omitempty"`
Body *string `json:"body,omitempty"`
Path *string `json:"path,omitempty"`
DiffHunk *string `json:"diff_hunk,omitempty"`
Position *int `json:"position,omitempty"`
OriginalPosition *int `json:"original_position,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
OriginalCommitID *string `json:"original_commit_id,omitempty"`
User *User `json:"user,omitempty"`
Reactions *Reactions `json:"reactions,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
PullRequestURL *string `json:"pull_request_url,omitempty"`
ID *int64 `json:"id,omitempty"`
InReplyTo *int64 `json:"in_reply_to_id,omitempty"`
Body *string `json:"body,omitempty"`
Path *string `json:"path,omitempty"`
DiffHunk *string `json:"diff_hunk,omitempty"`
PullRequestReviewID *int64 `json:"pull_request_review_id,omitempty"`
Position *int `json:"position,omitempty"`
OriginalPosition *int `json:"original_position,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
OriginalCommitID *string `json:"original_commit_id,omitempty"`
User *User `json:"user,omitempty"`
Reactions *Reactions `json:"reactions,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
// AuthorAssociation is the comment author's relationship to the pull request's repository.
// Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
AuthorAssociation *string `json:"author_association,omitempty"`
URL *string `json:"url,omitempty"`
HTMLURL *string `json:"html_url,omitempty"`
PullRequestURL *string `json:"pull_request_url,omitempty"`
}
func (p PullRequestComment) String() string {
@@ -87,8 +91,8 @@ func (s *PullRequestsService) ListComments(ctx context.Context, owner string, re
// GetComment fetches the specified pull request comment.
//
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment
func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, number int) (*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number)
func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
@@ -125,11 +129,38 @@ func (s *PullRequestsService) CreateComment(ctx context.Context, owner string, r
return c, resp, nil
}
// CreateCommentInReplyTo creates a new comment as a reply to an existing pull request comment.
//
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#alternative-input
func (s *PullRequestsService) CreateCommentInReplyTo(ctx context.Context, owner string, repo string, number int, body string, commentID int64) (*PullRequestComment, *Response, error) {
comment := &struct {
Body string `json:"body,omitempty"`
InReplyTo int64 `json:"in_reply_to,omitempty"`
}{
Body: body,
InReplyTo: commentID,
}
u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number)
req, err := s.client.NewRequest("POST", u, comment)
if err != nil {
return nil, nil, err
}
c := new(PullRequestComment)
resp, err := s.client.Do(ctx, req, c)
if err != nil {
return nil, resp, err
}
return c, resp, nil
}
// EditComment updates a pull request comment.
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
//
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment
func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number)
func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *PullRequestComment) (*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil {
return nil, nil, err
@@ -147,8 +178,8 @@ func (s *PullRequestsService) EditComment(ctx context.Context, owner string, rep
// DeleteComment deletes a pull request comment.
//
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#delete-a-comment
func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, number int) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, number)
func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err

View File

@@ -16,7 +16,7 @@ import (
)
func TestPullRequestsService_ListComments_allPulls(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -42,20 +42,20 @@ func TestPullRequestsService_ListComments_allPulls(t *testing.T) {
t.Errorf("PullRequests.ListComments returned error: %v", err)
}
want := []*PullRequestComment{{ID: Int(1)}}
want := []*PullRequestComment{{ID: Int64(1)}}
if !reflect.DeepEqual(pulls, want) {
t.Errorf("PullRequests.ListComments returned %+v, want %+v", pulls, want)
}
}
func TestPullRequestsService_ListComments_specificPull(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/comments", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
fmt.Fprint(w, `[{"id":1}]`)
fmt.Fprint(w, `[{"id":1, "pull_request_review_id":42}]`)
})
pulls, _, err := client.PullRequests.ListComments(context.Background(), "o", "r", 1, nil)
@@ -63,19 +63,22 @@ func TestPullRequestsService_ListComments_specificPull(t *testing.T) {
t.Errorf("PullRequests.ListComments returned error: %v", err)
}
want := []*PullRequestComment{{ID: Int(1)}}
want := []*PullRequestComment{{ID: Int64(1), PullRequestReviewID: Int64(42)}}
if !reflect.DeepEqual(pulls, want) {
t.Errorf("PullRequests.ListComments returned %+v, want %+v", pulls, want)
}
}
func TestPullRequestsService_ListComments_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.ListComments(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestPullRequestsService_GetComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/comments/1", func(w http.ResponseWriter, r *http.Request) {
@@ -89,19 +92,22 @@ func TestPullRequestsService_GetComment(t *testing.T) {
t.Errorf("PullRequests.GetComment returned error: %v", err)
}
want := &PullRequestComment{ID: Int(1)}
want := &PullRequestComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("PullRequests.GetComment returned %+v, want %+v", comment, want)
}
}
func TestPullRequestsService_GetComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.GetComment(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}
func TestPullRequestsService_CreateComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &PullRequestComment{Body: String("b")}
@@ -123,19 +129,22 @@ func TestPullRequestsService_CreateComment(t *testing.T) {
t.Errorf("PullRequests.CreateComment returned error: %v", err)
}
want := &PullRequestComment{ID: Int(1)}
want := &PullRequestComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("PullRequests.CreateComment returned %+v, want %+v", comment, want)
}
}
func TestPullRequestsService_CreateComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.CreateComment(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestPullRequestsService_EditComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &PullRequestComment{Body: String("b")}
@@ -157,19 +166,22 @@ func TestPullRequestsService_EditComment(t *testing.T) {
t.Errorf("PullRequests.EditComment returned error: %v", err)
}
want := &PullRequestComment{ID: Int(1)}
want := &PullRequestComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("PullRequests.EditComment returned %+v, want %+v", comment, want)
}
}
func TestPullRequestsService_EditComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.EditComment(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestPullRequestsService_DeleteComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/comments/1", func(w http.ResponseWriter, r *http.Request) {
@@ -183,6 +195,9 @@ func TestPullRequestsService_DeleteComment(t *testing.T) {
}
func TestPullRequestsService_DeleteComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.PullRequests.DeleteComment(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}

View File

@@ -32,9 +32,6 @@ func (s *PullRequestsService) RequestReviewers(ctx context.Context, owner, repo
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTeamReviewPreview)
r := new(PullRequest)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
@@ -59,9 +56,6 @@ func (s *PullRequestsService) ListReviewers(ctx context.Context, owner, repo str
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTeamReviewPreview)
reviewers := new(Reviewers)
resp, err := s.client.Do(ctx, req, reviewers)
if err != nil {
@@ -81,8 +75,5 @@ func (s *PullRequestsService) RemoveReviewers(ctx context.Context, owner, repo s
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTeamReviewPreview)
return s.client.Do(ctx, req, reviewers)
return s.client.Do(ctx, req, nil)
}

View File

@@ -14,13 +14,12 @@ import (
)
func TestRequestReviewers(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/requested_reviewers", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testBody(t, r, `{"reviewers":["octocat","googlebot"],"team_reviewers":["justice-league","injustice-league"]}`+"\n")
testHeader(t, r, "Accept", mediaTypeTeamReviewPreview)
fmt.Fprint(w, `{"number":1}`)
})
@@ -36,12 +35,11 @@ func TestRequestReviewers(t *testing.T) {
}
func TestRemoveReviewers(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/requested_reviewers", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
testHeader(t, r, "Accept", mediaTypeTeamReviewPreview)
testBody(t, r, `{"reviewers":["octocat","googlebot"],"team_reviewers":["justice-league"]}`+"\n")
})
@@ -52,12 +50,11 @@ func TestRemoveReviewers(t *testing.T) {
}
func TestListReviewers(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/requested_reviewers", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeTeamReviewPreview)
fmt.Fprint(w, `{"users":[{"login":"octocat","id":1}],"teams":[{"id":1,"name":"Justice League"}]}`)
})
@@ -70,12 +67,12 @@ func TestListReviewers(t *testing.T) {
Users: []*User{
{
Login: String("octocat"),
ID: Int(1),
ID: Int64(1),
},
},
Teams: []*Team{
{
ID: Int(1),
ID: Int64(1),
Name: String("Justice League"),
},
},
@@ -86,7 +83,7 @@ func TestListReviewers(t *testing.T) {
}
func TestListReviewers_withOptions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/requested_reviewers", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -13,7 +13,7 @@ import (
// PullRequestReview represents a review of a pull request.
type PullRequestReview struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
User *User `json:"user,omitempty"`
Body *string `json:"body,omitempty"`
SubmittedAt *time.Time `json:"submitted_at,omitempty"`
@@ -94,7 +94,7 @@ func (s *PullRequestsService) ListReviews(ctx context.Context, owner, repo strin
// Read more about it here - https://github.com/google/go-github/issues/540
//
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-review
func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number, reviewID int) (*PullRequestReview, *Response, error) {
func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID)
req, err := s.client.NewRequest("GET", u, nil)
@@ -118,7 +118,7 @@ func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string,
// Read more about it here - https://github.com/google/go-github/issues/540
//
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review
func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number, reviewID int) (*PullRequestReview, *Response, error) {
func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID)
req, err := s.client.NewRequest("DELETE", u, nil)
@@ -142,7 +142,7 @@ func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, re
// Read more about it here - https://github.com/google/go-github/issues/540
//
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-comments-for-a-single-review
func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number, reviewID int, opt *ListOptions) ([]*PullRequestComment, *Response, error) {
func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number int, reviewID int64, opt *ListOptions) ([]*PullRequestComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/comments", owner, repo, number, reviewID)
u, err := addOptions(u, opt)
if err != nil {
@@ -194,7 +194,7 @@ func (s *PullRequestsService) CreateReview(ctx context.Context, owner, repo stri
// Read more about it here - https://github.com/google/go-github/issues/540
//
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review
func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number, reviewID int, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) {
func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/events", owner, repo, number, reviewID)
req, err := s.client.NewRequest("POST", u, review)
@@ -218,7 +218,7 @@ func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo stri
// Read more about it here - https://github.com/google/go-github/issues/540
//
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review
func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number, reviewID int, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) {
func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/dismissals", owner, repo, number, reviewID)
req, err := s.client.NewRequest("PUT", u, review)

View File

@@ -15,7 +15,7 @@ import (
)
func TestPullRequestsService_ListReviews(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/reviews", func(w http.ResponseWriter, r *http.Request) {
@@ -33,8 +33,8 @@ func TestPullRequestsService_ListReviews(t *testing.T) {
}
want := []*PullRequestReview{
{ID: Int(1)},
{ID: Int(2)},
{ID: Int64(1)},
{ID: Int64(2)},
}
if !reflect.DeepEqual(reviews, want) {
t.Errorf("PullRequests.ListReviews returned %+v, want %+v", reviews, want)
@@ -42,12 +42,15 @@ func TestPullRequestsService_ListReviews(t *testing.T) {
}
func TestPullRequestsService_ListReviews_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.ListReviews(context.Background(), "%", "r", 1, nil)
testURLParseError(t, err)
}
func TestPullRequestsService_GetReview(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/reviews/1", func(w http.ResponseWriter, r *http.Request) {
@@ -60,19 +63,22 @@ func TestPullRequestsService_GetReview(t *testing.T) {
t.Errorf("PullRequests.GetReview returned error: %v", err)
}
want := &PullRequestReview{ID: Int(1)}
want := &PullRequestReview{ID: Int64(1)}
if !reflect.DeepEqual(review, want) {
t.Errorf("PullRequests.GetReview returned %+v, want %+v", review, want)
}
}
func TestPullRequestsService_GetReview_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.GetReview(context.Background(), "%", "r", 1, 1)
testURLParseError(t, err)
}
func TestPullRequestsService_DeletePendingReview(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/reviews/1", func(w http.ResponseWriter, r *http.Request) {
@@ -85,19 +91,22 @@ func TestPullRequestsService_DeletePendingReview(t *testing.T) {
t.Errorf("PullRequests.DeletePendingReview returned error: %v", err)
}
want := &PullRequestReview{ID: Int(1)}
want := &PullRequestReview{ID: Int64(1)}
if !reflect.DeepEqual(review, want) {
t.Errorf("PullRequests.DeletePendingReview returned %+v, want %+v", review, want)
}
}
func TestPullRequestsService_DeletePendingReview_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.DeletePendingReview(context.Background(), "%", "r", 1, 1)
testURLParseError(t, err)
}
func TestPullRequestsService_ListReviewComments(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/reviews/1/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -111,8 +120,8 @@ func TestPullRequestsService_ListReviewComments(t *testing.T) {
}
want := []*PullRequestComment{
{ID: Int(1)},
{ID: Int(2)},
{ID: Int64(1)},
{ID: Int64(2)},
}
if !reflect.DeepEqual(comments, want) {
t.Errorf("PullRequests.ListReviewComments returned %+v, want %+v", comments, want)
@@ -120,7 +129,7 @@ func TestPullRequestsService_ListReviewComments(t *testing.T) {
}
func TestPullRequestsService_ListReviewComments_withOptions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/reviews/1/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -138,12 +147,15 @@ func TestPullRequestsService_ListReviewComments_withOptions(t *testing.T) {
}
func TestPullRequestsService_ListReviewComments_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.ListReviewComments(context.Background(), "%", "r", 1, 1, nil)
testURLParseError(t, err)
}
func TestPullRequestsService_CreateReview(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &PullRequestReviewRequest{
@@ -169,19 +181,22 @@ func TestPullRequestsService_CreateReview(t *testing.T) {
t.Errorf("PullRequests.CreateReview returned error: %v", err)
}
want := &PullRequestReview{ID: Int(1)}
want := &PullRequestReview{ID: Int64(1)}
if !reflect.DeepEqual(review, want) {
t.Errorf("PullRequests.CreateReview returned %+v, want %+v", review, want)
}
}
func TestPullRequestsService_CreateReview_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.CreateReview(context.Background(), "%", "r", 1, &PullRequestReviewRequest{})
testURLParseError(t, err)
}
func TestPullRequestsService_SubmitReview(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &PullRequestReviewRequest{
@@ -206,19 +221,22 @@ func TestPullRequestsService_SubmitReview(t *testing.T) {
t.Errorf("PullRequests.SubmitReview returned error: %v", err)
}
want := &PullRequestReview{ID: Int(1)}
want := &PullRequestReview{ID: Int64(1)}
if !reflect.DeepEqual(review, want) {
t.Errorf("PullRequests.SubmitReview returned %+v, want %+v", review, want)
}
}
func TestPullRequestsService_SubmitReview_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.SubmitReview(context.Background(), "%", "r", 1, 1, &PullRequestReviewRequest{})
testURLParseError(t, err)
}
func TestPullRequestsService_DismissReview(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &PullRequestReviewDismissalRequest{Message: String("m")}
@@ -240,13 +258,16 @@ func TestPullRequestsService_DismissReview(t *testing.T) {
t.Errorf("PullRequests.DismissReview returned error: %v", err)
}
want := &PullRequestReview{ID: Int(1)}
want := &PullRequestReview{ID: Int64(1)}
if !reflect.DeepEqual(review, want) {
t.Errorf("PullRequests.DismissReview returned %+v, want %+v", review, want)
}
}
func TestPullRequestsService_DismissReview_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.DismissReview(context.Background(), "%", "r", 1, 1, &PullRequestReviewDismissalRequest{})
testURLParseError(t, err)
}

View File

@@ -17,11 +17,13 @@ import (
)
func TestPullRequestsService_List(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
mux.HandleFunc("/repos/o/r/pulls", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
testFormValues(t, r, values{
"state": "closed",
"head": "h",
@@ -46,16 +48,21 @@ func TestPullRequestsService_List(t *testing.T) {
}
func TestPullRequestsService_List_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.List(context.Background(), "%", "r", nil)
testURLParseError(t, err)
}
func TestPullRequestsService_Get(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
fmt.Fprint(w, `{"number":1}`)
})
@@ -70,9 +77,10 @@ func TestPullRequestsService_Get(t *testing.T) {
}
}
func TestPullRequestsService_GetRawDiff(t *testing.T) {
setup()
func TestPullRequestsService_GetRaw_diff(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
const rawStr = "@@diff content"
mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
@@ -81,19 +89,20 @@ func TestPullRequestsService_GetRawDiff(t *testing.T) {
fmt.Fprint(w, rawStr)
})
ret, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Diff})
got, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Diff})
if err != nil {
t.Fatalf("PullRequests.GetRaw returned error: %v", err)
}
if ret != rawStr {
t.Errorf("PullRequests.GetRaw returned %s want %s", ret, rawStr)
want := rawStr
if got != want {
t.Errorf("PullRequests.GetRaw returned %s want %s", got, want)
}
}
func TestPullRequestsService_GetRawPatch(t *testing.T) {
setup()
func TestPullRequestsService_GetRaw_patch(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
const rawStr = "@@patch content"
mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
@@ -102,18 +111,18 @@ func TestPullRequestsService_GetRawPatch(t *testing.T) {
fmt.Fprint(w, rawStr)
})
ret, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Patch})
got, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{Patch})
if err != nil {
t.Fatalf("PullRequests.GetRaw returned error: %v", err)
}
if ret != rawStr {
t.Errorf("PullRequests.GetRaw returned %s want %s", ret, rawStr)
want := rawStr
if got != want {
t.Errorf("PullRequests.GetRaw returned %s want %s", got, want)
}
}
func TestPullRequestsService_GetRawInvalid(t *testing.T) {
setup()
func TestPullRequestsService_GetRaw_invalid(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.GetRaw(context.Background(), "o", "r", 1, RawOptions{100})
@@ -125,8 +134,61 @@ func TestPullRequestsService_GetRawInvalid(t *testing.T) {
}
}
func TestPullRequestsService_Get_links(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `{
"number":1,
"_links":{
"self":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/1347"},
"html":{"href":"https://github.com/octocat/Hello-World/pull/1347"},
"issue":{"href":"https://api.github.com/repos/octocat/Hello-World/issues/1347"},
"comments":{"href":"https://api.github.com/repos/octocat/Hello-World/issues/1347/comments"},
"review_comments":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments"},
"review_comment":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}"},
"commits":{"href":"https://api.github.com/repos/octocat/Hello-World/pulls/1347/commits"},
"statuses":{"href":"https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e"}
}
}`)
})
pull, _, err := client.PullRequests.Get(context.Background(), "o", "r", 1)
if err != nil {
t.Errorf("PullRequests.Get returned error: %v", err)
}
want := &PullRequest{
Number: Int(1),
Links: &PRLinks{
Self: &PRLink{
HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/1347"),
}, HTML: &PRLink{
HRef: String("https://github.com/octocat/Hello-World/pull/1347"),
}, Issue: &PRLink{
HRef: String("https://api.github.com/repos/octocat/Hello-World/issues/1347"),
}, Comments: &PRLink{
HRef: String("https://api.github.com/repos/octocat/Hello-World/issues/1347/comments"),
}, ReviewComments: &PRLink{
HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/1347/comments"),
}, ReviewComment: &PRLink{
HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/comments{/number}"),
}, Commits: &PRLink{
HRef: String("https://api.github.com/repos/octocat/Hello-World/pulls/1347/commits"),
}, Statuses: &PRLink{
HRef: String("https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e"),
},
},
}
if !reflect.DeepEqual(pull, want) {
t.Errorf("PullRequests.Get returned %+v, want %+v", pull, want)
}
}
func TestPullRequestsService_Get_headAndBase(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
@@ -143,11 +205,11 @@ func TestPullRequestsService_Get_headAndBase(t *testing.T) {
Number: Int(1),
Head: &PullRequestBranch{
Ref: String("r2"),
Repo: &Repository{ID: Int(2)},
Repo: &Repository{ID: Int64(2)},
},
Base: &PullRequestBranch{
Ref: String("r1"),
Repo: &Repository{ID: Int(1)},
Repo: &Repository{ID: Int64(1)},
},
}
if !reflect.DeepEqual(pull, want) {
@@ -156,7 +218,7 @@ func TestPullRequestsService_Get_headAndBase(t *testing.T) {
}
func TestPullRequestsService_Get_urlFields(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1", func(w http.ResponseWriter, r *http.Request) {
@@ -195,12 +257,15 @@ func TestPullRequestsService_Get_urlFields(t *testing.T) {
}
func TestPullRequestsService_Get_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.Get(context.Background(), "%", "r", 1)
testURLParseError(t, err)
}
func TestPullRequestsService_Create(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &NewPullRequest{Title: String("t")}
@@ -210,6 +275,7 @@ func TestPullRequestsService_Create(t *testing.T) {
json.NewDecoder(r.Body).Decode(v)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeLabelDescriptionSearchPreview)
if !reflect.DeepEqual(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}
@@ -229,12 +295,15 @@ func TestPullRequestsService_Create(t *testing.T) {
}
func TestPullRequestsService_Create_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.Create(context.Background(), "%", "r", nil)
testURLParseError(t, err)
}
func TestPullRequestsService_Edit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
tests := []struct {
@@ -264,8 +333,10 @@ func TestPullRequestsService_Edit(t *testing.T) {
for i, tt := range tests {
madeRequest := false
acceptHeaders := []string{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview}
mux.HandleFunc(fmt.Sprintf("/repos/o/r/pulls/%v", i), func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PATCH")
testHeader(t, r, "Accept", strings.Join(acceptHeaders, ", "))
testBody(t, r, tt.wantUpdate+"\n")
io.WriteString(w, tt.sendResponse)
madeRequest = true
@@ -287,12 +358,15 @@ func TestPullRequestsService_Edit(t *testing.T) {
}
func TestPullRequestsService_Edit_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.PullRequests.Edit(context.Background(), "%", "r", 1, &PullRequest{})
testURLParseError(t, err)
}
func TestPullRequestsService_ListCommits(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/commits", func(w http.ResponseWriter, r *http.Request) {
@@ -350,7 +424,7 @@ func TestPullRequestsService_ListCommits(t *testing.T) {
}
func TestPullRequestsService_ListFiles(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/files", func(w http.ResponseWriter, r *http.Request) {
@@ -412,7 +486,7 @@ func TestPullRequestsService_ListFiles(t *testing.T) {
}
func TestPullRequestsService_IsMerged(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/merge", func(w http.ResponseWriter, r *http.Request) {
@@ -432,7 +506,7 @@ func TestPullRequestsService_IsMerged(t *testing.T) {
}
func TestPullRequestsService_Merge(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/1/merge", func(w http.ResponseWriter, r *http.Request) {
@@ -463,7 +537,7 @@ func TestPullRequestsService_Merge(t *testing.T) {
// Test that different merge options produce expected PUT requests. See issue https://github.com/google/go-github/issues/500.
func TestPullRequestsService_Merge_options(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
tests := []struct {

View File

@@ -19,8 +19,9 @@ type ReactionsService service
// Reaction represents a GitHub reaction.
type Reaction struct {
// ID is the Reaction ID.
ID *int `json:"id,omitempty"`
User *User `json:"user,omitempty"`
ID *int64 `json:"id,omitempty"`
User *User `json:"user,omitempty"`
NodeID *string `json:"node_id,omitempty"`
// Content is the type of reaction.
// Possible values are:
// "+1", "-1", "laugh", "confused", "heart", "hooray".
@@ -46,7 +47,7 @@ func (r Reaction) String() string {
// ListCommentReactions lists the reactions for a commit comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment
func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)
u, err := addOptions(u, opt)
if err != nil {
@@ -58,7 +59,7 @@ func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction
@@ -73,9 +74,10 @@ func (s *ReactionsService) ListCommentReactions(ctx context.Context, owner, repo
// CreateCommentReaction creates a reaction for a commit comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int, content string) (*Reaction, *Response, error) {
func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)
body := &Reaction{Content: String(content)}
@@ -84,7 +86,7 @@ func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{}
@@ -111,7 +113,7 @@ func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo s
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction
@@ -126,6 +128,7 @@ func (s *ReactionsService) ListIssueReactions(ctx context.Context, owner, repo s
// CreateIssueReaction creates a reaction for an issue.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) {
@@ -137,7 +140,7 @@ func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo s
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{}
@@ -152,7 +155,7 @@ func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo s
// ListIssueCommentReactions lists the reactions for an issue comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)
u, err := addOptions(u, opt)
if err != nil {
@@ -164,7 +167,7 @@ func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction
@@ -179,9 +182,10 @@ func (s *ReactionsService) ListIssueCommentReactions(ctx context.Context, owner,
// CreateIssueCommentReaction creates a reaction for an issue comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int, content string) (*Reaction, *Response, error) {
func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)
body := &Reaction{Content: String(content)}
@@ -190,7 +194,7 @@ func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{}
@@ -205,7 +209,7 @@ func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner,
// ListPullRequestCommentReactions lists the reactions for a pull request review comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context, owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)
u, err := addOptions(u, opt)
if err != nil {
@@ -217,7 +221,7 @@ func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction
@@ -232,9 +236,10 @@ func (s *ReactionsService) ListPullRequestCommentReactions(ctx context.Context,
// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int, content string) (*Reaction, *Response, error) {
func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)
body := &Reaction{Content: String(content)}
@@ -243,7 +248,104 @@ func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
// TODO: remove custom Accept headers when APIs fully launch.
req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{}
resp, err := s.client.Do(ctx, req, m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// ListTeamDiscussionReactions lists the reactions for a team discussion.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion
func (s *ReactionsService) ListTeamDiscussionReactions(ctx context.Context, teamID int64, discussionNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction
resp, err := s.client.Do(ctx, req, &m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// CreateTeamDiscussionReaction creates a reaction for a team discussion.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion
func (s *ReactionsService) CreateTeamDiscussionReaction(ctx context.Context, teamID int64, discussionNumber int, content string) (*Reaction, *Response, error) {
u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber)
body := &Reaction{Content: String(content)}
req, err := s.client.NewRequest("POST", u, body)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{}
resp, err := s.client.Do(ctx, req, m)
if err != nil {
return nil, resp, err
}
return m, resp, nil
}
// ListTeamDiscussionCommentReactions lists the reactions for a team discussion comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-comment
func (s *ReactionsService) ListTeamDiscussionCommentReactions(ctx context.Context, teamID int64, discussionNumber, commentNumber int, opt *ListOptions) ([]*Reaction, *Response, error) {
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)
u, err := addOptions(u, opt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeReactionsPreview)
var m []*Reaction
resp, err := s.client.Do(ctx, req, &m)
return m, resp, nil
}
// CreateTeamDiscussionCommentReaction creates a reaction for a team discussion comment.
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-comment
func (s *ReactionsService) CreateTeamDiscussionCommentReaction(ctx context.Context, teamID int64, discussionNumber, commentNumber int, content string) (*Reaction, *Response, error) {
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber)
body := &Reaction{Content: String(content)}
req, err := s.client.NewRequest("POST", u, body)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeReactionsPreview)
m := &Reaction{}
@@ -258,7 +360,7 @@ func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context,
// DeleteReaction deletes a reaction.
//
// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive
func (s *ReactionsService) DeleteReaction(ctx context.Context, id int) (*Response, error) {
func (s *ReactionsService) DeleteReaction(ctx context.Context, id int64) (*Response, error) {
u := fmt.Sprintf("reactions/%v", id)
req, err := s.client.NewRequest("DELETE", u, nil)

View File

@@ -13,7 +13,7 @@ import (
)
func TestReactionsService_ListCommentReactions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -28,13 +28,14 @@ func TestReactionsService_ListCommentReactions(t *testing.T) {
if err != nil {
t.Errorf("ListCommentReactions returned error: %v", err)
}
if want := []*Reaction{{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}}; !reflect.DeepEqual(got, want) {
want := []*Reaction{{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}}
if !reflect.DeepEqual(got, want) {
t.Errorf("ListCommentReactions = %+v, want %+v", got, want)
}
}
func TestReactionsService_CreateCommentReaction(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -49,14 +50,14 @@ func TestReactionsService_CreateCommentReaction(t *testing.T) {
if err != nil {
t.Errorf("CreateCommentReaction returned error: %v", err)
}
want := &Reaction{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}
want := &Reaction{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}
if !reflect.DeepEqual(got, want) {
t.Errorf("CreateCommentReaction = %+v, want %+v", got, want)
}
}
func TestReactionsService_ListIssueReactions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -71,13 +72,14 @@ func TestReactionsService_ListIssueReactions(t *testing.T) {
if err != nil {
t.Errorf("ListIssueReactions returned error: %v", err)
}
if want := []*Reaction{{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}}; !reflect.DeepEqual(got, want) {
want := []*Reaction{{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}}
if !reflect.DeepEqual(got, want) {
t.Errorf("ListIssueReactions = %+v, want %+v", got, want)
}
}
func TestReactionsService_CreateIssueReaction(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -92,14 +94,14 @@ func TestReactionsService_CreateIssueReaction(t *testing.T) {
if err != nil {
t.Errorf("CreateIssueReaction returned error: %v", err)
}
want := &Reaction{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}
want := &Reaction{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}
if !reflect.DeepEqual(got, want) {
t.Errorf("CreateIssueReaction = %+v, want %+v", got, want)
}
}
func TestReactionsService_ListIssueCommentReactions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -114,13 +116,14 @@ func TestReactionsService_ListIssueCommentReactions(t *testing.T) {
if err != nil {
t.Errorf("ListIssueCommentReactions returned error: %v", err)
}
if want := []*Reaction{{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}}; !reflect.DeepEqual(got, want) {
want := []*Reaction{{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}}
if !reflect.DeepEqual(got, want) {
t.Errorf("ListIssueCommentReactions = %+v, want %+v", got, want)
}
}
func TestReactionsService_CreateIssueCommentReaction(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/issues/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -135,14 +138,14 @@ func TestReactionsService_CreateIssueCommentReaction(t *testing.T) {
if err != nil {
t.Errorf("CreateIssueCommentReaction returned error: %v", err)
}
want := &Reaction{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}
want := &Reaction{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}
if !reflect.DeepEqual(got, want) {
t.Errorf("CreateIssueCommentReaction = %+v, want %+v", got, want)
}
}
func TestReactionsService_ListPullRequestCommentReactions(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -157,13 +160,14 @@ func TestReactionsService_ListPullRequestCommentReactions(t *testing.T) {
if err != nil {
t.Errorf("ListPullRequestCommentReactions returned error: %v", err)
}
if want := []*Reaction{{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}}; !reflect.DeepEqual(got, want) {
want := []*Reaction{{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}}
if !reflect.DeepEqual(got, want) {
t.Errorf("ListPullRequestCommentReactions = %+v, want %+v", got, want)
}
}
func TestReactionsService_CreatePullRequestCommentReaction(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/pulls/comments/1/reactions", func(w http.ResponseWriter, r *http.Request) {
@@ -178,14 +182,102 @@ func TestReactionsService_CreatePullRequestCommentReaction(t *testing.T) {
if err != nil {
t.Errorf("CreatePullRequestCommentReaction returned error: %v", err)
}
want := &Reaction{ID: Int(1), User: &User{Login: String("l"), ID: Int(2)}, Content: String("+1")}
want := &Reaction{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}
if !reflect.DeepEqual(got, want) {
t.Errorf("CreatePullRequestCommentReaction = %+v, want %+v", got, want)
}
}
func TestReactionsService_ListTeamDiscussionReactions(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/teams/1/discussions/2/reactions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
w.WriteHeader(http.StatusOK)
w.Write([]byte(`[{"id":1,"user":{"login":"l","id":2},"content":"+1"}]`))
})
got, _, err := client.Reactions.ListTeamDiscussionReactions(context.Background(), 1, 2, nil)
if err != nil {
t.Errorf("ListTeamDiscussionReactions returned error: %v", err)
}
want := []*Reaction{{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}}
if !reflect.DeepEqual(got, want) {
t.Errorf("ListTeamDiscussionReactions = %+v, want %+v", got, want)
}
}
func TestReactionsService_CreateTeamDiscussionReaction(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/teams/1/discussions/2/reactions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"id":1,"user":{"login":"l","id":2},"content":"+1"}`))
})
got, _, err := client.Reactions.CreateTeamDiscussionReaction(context.Background(), 1, 2, "+1")
if err != nil {
t.Errorf("CreateTeamDiscussionReaction returned error: %v", err)
}
want := &Reaction{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}
if !reflect.DeepEqual(got, want) {
t.Errorf("CreateTeamDiscussionReaction = %+v, want %+v", got, want)
}
}
func TestReactionService_ListTeamDiscussionCommentReactions(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/teams/1/discussions/2/comments/3/reactions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
w.WriteHeader(http.StatusOK)
w.Write([]byte(`[{"id":1,"user":{"login":"l","id":2},"content":"+1"}]`))
})
got, _, err := client.Reactions.ListTeamDiscussionCommentReactions(context.Background(), 1, 2, 3, nil)
if err != nil {
t.Errorf("ListTeamDiscussionCommentReactions returned error: %v", err)
}
want := []*Reaction{{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}}
if !reflect.DeepEqual(got, want) {
t.Errorf("ListTeamDiscussionCommentReactions = %+v, want %+v", got, want)
}
}
func TestReactionService_CreateTeamDiscussionCommentReaction(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/teams/1/discussions/2/comments/3/reactions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeReactionsPreview)
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"id":1,"user":{"login":"l","id":2},"content":"+1"}`))
})
got, _, err := client.Reactions.CreateTeamDiscussionCommentReaction(context.Background(), 1, 2, 3, "+1")
if err != nil {
t.Errorf("CreateTeamDiscussionCommentReaction returned error: %v", err)
}
want := &Reaction{ID: Int64(1), User: &User{Login: String("l"), ID: Int64(2)}, Content: String("+1")}
if !reflect.DeepEqual(got, want) {
t.Errorf("CreateTeamDiscussionCommentReaction = %+v, want %+v", got, want)
}
}
func TestReactionsService_DeleteReaction(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/reactions/1", func(w http.ResponseWriter, r *http.Request) {

View File

@@ -7,7 +7,6 @@ package github
import (
"context"
"encoding/json"
"fmt"
"strings"
)
@@ -20,7 +19,8 @@ type RepositoriesService service
// Repository represents a GitHub repository.
type Repository struct {
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
NodeID *string `json:"node_id,omitempty"`
Owner *User `json:"owner,omitempty"`
Name *string `json:"name,omitempty"`
FullName *string `json:"full_name,omitempty"`
@@ -39,7 +39,7 @@ type Repository struct {
SSHURL *string `json:"ssh_url,omitempty"`
SVNURL *string `json:"svn_url,omitempty"`
Language *string `json:"language,omitempty"`
Fork *bool `json:"fork"`
Fork *bool `json:"fork,omitempty"`
ForksCount *int `json:"forks_count,omitempty"`
NetworkCount *int `json:"network_count,omitempty"`
OpenIssuesCount *int `json:"open_issues_count,omitempty"`
@@ -56,21 +56,23 @@ type Repository struct {
AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"`
AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"`
Topics []string `json:"topics,omitempty"`
Archived *bool `json:"archived,omitempty"`
// Only provided when using RepositoriesService.Get while in preview
License *License `json:"license,omitempty"`
// Additional mutable fields when creating and editing a repository
Private *bool `json:"private"`
HasIssues *bool `json:"has_issues"`
HasWiki *bool `json:"has_wiki"`
HasPages *bool `json:"has_pages"`
HasDownloads *bool `json:"has_downloads"`
Private *bool `json:"private,omitempty"`
HasIssues *bool `json:"has_issues,omitempty"`
HasWiki *bool `json:"has_wiki,omitempty"`
HasPages *bool `json:"has_pages,omitempty"`
HasProjects *bool `json:"has_projects,omitempty"`
HasDownloads *bool `json:"has_downloads,omitempty"`
LicenseTemplate *string `json:"license_template,omitempty"`
GitignoreTemplate *string `json:"gitignore_template,omitempty"`
// Creating an organization repository. Required for non-owners.
TeamID *int `json:"team_id"`
TeamID *int64 `json:"team_id,omitempty"`
// API URLs
URL *string `json:"url,omitempty"`
@@ -177,7 +179,7 @@ func (s *RepositoriesService) List(ctx context.Context, user string, opt *Reposi
}
// TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var repos []*Repository
@@ -215,7 +217,7 @@ func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opt *Re
}
// TODO: remove custom Accept headers when APIs fully launch.
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
var repos []*Repository
@@ -231,9 +233,7 @@ func (s *RepositoriesService) ListByOrg(ctx context.Context, org string, opt *Re
// RepositoriesService.ListAll method.
type RepositoryListAllOptions struct {
// ID of the last repository seen
Since int `url:"since,omitempty"`
ListOptions
Since int64 `url:"since,omitempty"`
}
// ListAll lists all GitHub repositories in the order that they were created.
@@ -259,10 +259,40 @@ func (s *RepositoriesService) ListAll(ctx context.Context, opt *RepositoryListAl
return repos, resp, nil
}
// createRepoRequest is a subset of Repository and is used internally
// by Create to pass only the known fields for the endpoint.
//
// See https://github.com/google/go-github/issues/1014 for more
// information.
type createRepoRequest struct {
// Name is required when creating a repo.
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Homepage *string `json:"homepage,omitempty"`
Private *bool `json:"private,omitempty"`
HasIssues *bool `json:"has_issues,omitempty"`
HasProjects *bool `json:"has_projects,omitempty"`
HasWiki *bool `json:"has_wiki,omitempty"`
// Creating an organization repository. Required for non-owners.
TeamID *int64 `json:"team_id,omitempty"`
AutoInit *bool `json:"auto_init,omitempty"`
GitignoreTemplate *string `json:"gitignore_template,omitempty"`
LicenseTemplate *string `json:"license_template,omitempty"`
AllowSquashMerge *bool `json:"allow_squash_merge,omitempty"`
AllowMergeCommit *bool `json:"allow_merge_commit,omitempty"`
AllowRebaseMerge *bool `json:"allow_rebase_merge,omitempty"`
}
// Create a new repository. If an organization is specified, the new
// repository will be created under that org. If the empty string is
// specified, it will be created for the authenticated user.
//
// Note that only a subset of the repo fields are used and repo must
// not be nil.
//
// GitHub API docs: https://developer.github.com/v3/repos/#create
func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repository) (*Repository, *Response, error) {
var u string
@@ -272,7 +302,24 @@ func (s *RepositoriesService) Create(ctx context.Context, org string, repo *Repo
u = "user/repos"
}
req, err := s.client.NewRequest("POST", u, repo)
repoReq := &createRepoRequest{
Name: repo.Name,
Description: repo.Description,
Homepage: repo.Homepage,
Private: repo.Private,
HasIssues: repo.HasIssues,
HasProjects: repo.HasProjects,
HasWiki: repo.HasWiki,
TeamID: repo.TeamID,
AutoInit: repo.AutoInit,
GitignoreTemplate: repo.GitignoreTemplate,
LicenseTemplate: repo.LicenseTemplate,
AllowSquashMerge: repo.AllowSquashMerge,
AllowMergeCommit: repo.AllowMergeCommit,
AllowRebaseMerge: repo.AllowRebaseMerge,
}
req, err := s.client.NewRequest("POST", u, repoReq)
if err != nil {
return nil, nil, err
}
@@ -298,7 +345,7 @@ func (s *RepositoriesService) Get(ctx context.Context, owner, repo string) (*Rep
// TODO: remove custom Accept header when the license support fully launches
// https://developer.github.com/v3/licenses/#get-a-repositorys-license
acceptHeaders := []string{mediaTypeLicensesPreview, mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
acceptHeaders := []string{mediaTypeCodesOfConductPreview, mediaTypeTopicsPreview}
req.Header.Set("Accept", strings.Join(acceptHeaders, ", "))
repository := new(Repository)
@@ -335,17 +382,13 @@ func (s *RepositoriesService) GetCodeOfConduct(ctx context.Context, owner, repo
// GetByID fetches a repository.
//
// Note: GetByID uses the undocumented GitHub API endpoint /repositories/:id.
func (s *RepositoriesService) GetByID(ctx context.Context, id int) (*Repository, *Response, error) {
func (s *RepositoriesService) GetByID(ctx context.Context, id int64) (*Repository, *Response, error) {
u := fmt.Sprintf("repositories/%d", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when the license support fully launches
// https://developer.github.com/v3/licenses/#get-a-repositorys-license
req.Header.Set("Accept", mediaTypeLicensesPreview)
repository := new(Repository)
resp, err := s.client.Do(ctx, req, repository)
if err != nil {
@@ -390,7 +433,7 @@ func (s *RepositoriesService) Delete(ctx context.Context, owner, repo string) (*
// Contributor represents a repository contributor
type Contributor struct {
Login *string `json:"login,omitempty"`
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
GravatarID *string `json:"gravatar_id,omitempty"`
URL *string `json:"url,omitempty"`
@@ -405,7 +448,7 @@ type Contributor struct {
EventsURL *string `json:"events_url,omitempty"`
ReceivedEventsURL *string `json:"received_events_url,omitempty"`
Type *string `json:"type,omitempty"`
SiteAdmin *bool `json:"site_admin"`
SiteAdmin *bool `json:"site_admin,omitempty"`
Contributions *int `json:"contributions,omitempty"`
}
@@ -483,6 +526,8 @@ func (s *RepositoriesService) ListTeams(ctx context.Context, owner string, repo
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
var teams []*Team
resp, err := s.client.Do(ctx, req, &teams)
if err != nil {
@@ -556,45 +601,40 @@ type RequiredStatusChecks struct {
Contexts []string `json:"contexts"`
}
// RequiredStatusChecksRequest represents a request to edit a protected branch's status checks.
type RequiredStatusChecksRequest struct {
Strict *bool `json:"strict,omitempty"`
Contexts []string `json:"contexts,omitempty"`
}
// PullRequestReviewsEnforcement represents the pull request reviews enforcement of a protected branch.
type PullRequestReviewsEnforcement struct {
// Specifies which users and teams can dismiss pull request reviews.
DismissalRestrictions DismissalRestrictions `json:"dismissal_restrictions"`
// Specifies if approved reviews are dismissed automatically, when a new commit is pushed.
DismissStaleReviews bool `json:"dismiss_stale_reviews"`
// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
// Valid values are 1-6.
RequiredApprovingReviewCount int `json:"required_approving_review_count"`
}
// PullRequestReviewsEnforcementRequest represents request to set the pull request review
// enforcement of a protected branch. It is separate from PullRequestReviewsEnforcement above
// because the request structure is different from the response structure.
type PullRequestReviewsEnforcementRequest struct {
// Specifies which users and teams should be allowed to dismiss pull request reviews. Can be nil to disable the restrictions.
DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions"`
// Specifies which users and teams should be allowed to dismiss pull request reviews.
// User and team dismissal restrictions are only available for
// organization-owned repositories. Must be nil for personal repositories.
DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"`
// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. (Required)
DismissStaleReviews bool `json:"dismiss_stale_reviews"`
}
// MarshalJSON implements the json.Marshaler interface.
// Converts nil value of PullRequestReviewsEnforcementRequest.DismissalRestrictionsRequest to empty array
func (req PullRequestReviewsEnforcementRequest) MarshalJSON() ([]byte, error) {
if req.DismissalRestrictionsRequest == nil {
newReq := struct {
R []interface{} `json:"dismissal_restrictions"`
D bool `json:"dismiss_stale_reviews"`
}{
R: []interface{}{},
D: req.DismissStaleReviews,
}
return json.Marshal(newReq)
}
newReq := struct {
R *DismissalRestrictionsRequest `json:"dismissal_restrictions"`
D bool `json:"dismiss_stale_reviews"`
}{
R: req.DismissalRestrictionsRequest,
D: req.DismissStaleReviews,
}
return json.Marshal(newReq)
// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
RequireCodeOwnerReviews bool `json:"require_code_owner_reviews"`
// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
// Valid values are 1-6.
RequiredApprovingReviewCount int `json:"required_approving_review_count"`
}
// PullRequestReviewsEnforcementUpdate represents request to patch the pull request review
@@ -605,6 +645,11 @@ type PullRequestReviewsEnforcementUpdate struct {
DismissalRestrictionsRequest *DismissalRestrictionsRequest `json:"dismissal_restrictions,omitempty"`
// Specifies if approved reviews can be dismissed automatically, when a new commit is pushed. Can be omitted.
DismissStaleReviews *bool `json:"dismiss_stale_reviews,omitempty"`
// RequireCodeOwnerReviews specifies if an approved review is required in pull requests including files with a designated code owner.
RequireCodeOwnerReviews bool `json:"require_code_owner_reviews,omitempty"`
// RequiredApprovingReviewCount specifies the number of approvals required before the pull request can be merged.
// Valid values are 1 - 6.
RequiredApprovingReviewCount int `json:"required_approving_review_count"`
}
// AdminEnforcement represents the configuration to enforce required status checks for repository administrators.
@@ -645,11 +690,19 @@ type DismissalRestrictions struct {
// restriction to allows only specific users or teams to dimiss pull request reviews. It is
// separate from DismissalRestrictions above because the request structure is
// different from the response structure.
// Note: Both Users and Teams must be nil, or both must be non-nil.
type DismissalRestrictionsRequest struct {
// The list of user logins who can dismiss pull request reviews. (Required; use []string{} instead of nil for empty list.)
Users []string `json:"users"`
// The list of team slugs which can dismiss pull request reviews. (Required; use []string{} instead of nil for empty list.)
Teams []string `json:"teams"`
// The list of user logins who can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.)
Users *[]string `json:"users,omitempty"`
// The list of team slugs which can dismiss pull request reviews. (Required; use nil to disable dismissal_restrictions or &[]string{} otherwise.)
Teams *[]string `json:"teams,omitempty"`
}
// SignaturesProtectedBranch represents the protection status of an individual branch.
type SignaturesProtectedBranch struct {
URL *string `json:"url,omitempty"`
// Commits pushed to matching branches must have verified signatures.
Enabled *bool `json:"enabled,omitempty"`
}
// ListBranches lists branches for the specified repository.
@@ -668,7 +721,7 @@ func (s *RepositoriesService) ListBranches(ctx context.Context, owner string, re
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
var branches []*Branch
resp, err := s.client.Do(ctx, req, &branches)
@@ -690,7 +743,7 @@ func (s *RepositoriesService) GetBranch(ctx context.Context, owner, repo, branch
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
b := new(Branch)
resp, err := s.client.Do(ctx, req, b)
@@ -712,7 +765,7 @@ func (s *RepositoriesService) GetBranchProtection(ctx context.Context, owner, re
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
p := new(Protection)
resp, err := s.client.Do(ctx, req, p)
@@ -734,7 +787,7 @@ func (s *RepositoriesService) GetRequiredStatusChecks(ctx context.Context, owner
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
p := new(RequiredStatusChecks)
resp, err := s.client.Do(ctx, req, p)
@@ -756,7 +809,7 @@ func (s *RepositoriesService) ListRequiredStatusChecksContexts(ctx context.Conte
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
resp, err = s.client.Do(ctx, req, &contexts)
if err != nil {
@@ -777,7 +830,7 @@ func (s *RepositoriesService) UpdateBranchProtection(ctx context.Context, owner,
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
p := new(Protection)
resp, err := s.client.Do(ctx, req, p)
@@ -799,11 +852,91 @@ func (s *RepositoriesService) RemoveBranchProtection(ctx context.Context, owner,
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
return s.client.Do(ctx, req, nil)
}
// GetSignaturesProtectedBranch gets required signatures of protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#get-required-signatures-of-protected-branch
func (s *RepositoriesService) GetSignaturesProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeSignaturePreview)
p := new(SignaturesProtectedBranch)
resp, err := s.client.Do(ctx, req, p)
if err != nil {
return nil, resp, err
}
return p, resp, nil
}
// RequireSignaturesOnProtectedBranch makes signed commits required on a protected branch.
// It requires admin access and branch protection to be enabled.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#add-required-signatures-of-protected-branch
func (s *RepositoriesService) RequireSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*SignaturesProtectedBranch, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
req, err := s.client.NewRequest("POST", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeSignaturePreview)
r := new(SignaturesProtectedBranch)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}
return r, resp, err
}
// OptionalSignaturesOnProtectedBranch removes required signed commits on a given branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#remove-required-signatures-of-protected-branch
func (s *RepositoriesService) OptionalSignaturesOnProtectedBranch(ctx context.Context, owner, repo, branch string) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_signatures", owner, repo, branch)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeSignaturePreview)
return s.client.Do(ctx, req, nil)
}
// UpdateRequiredStatusChecks updates the required status checks for a given protected branch.
//
// GitHub API docs: https://developer.github.com/v3/repos/branches/#update-required-status-checks-of-protected-branch
func (s *RepositoriesService) UpdateRequiredStatusChecks(ctx context.Context, owner, repo, branch string, sreq *RequiredStatusChecksRequest) (*RequiredStatusChecks, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/branches/%v/protection/required_status_checks", owner, repo, branch)
req, err := s.client.NewRequest("PATCH", u, sreq)
if err != nil {
return nil, nil, err
}
sc := new(RequiredStatusChecks)
resp, err := s.client.Do(ctx, req, sc)
if err != nil {
return nil, resp, err
}
return sc, resp, nil
}
// License gets the contents of a repository's license if one is detected.
//
// GitHub API docs: https://developer.github.com/v3/licenses/#get-the-contents-of-a-repositorys-license
@@ -834,7 +967,7 @@ func (s *RepositoriesService) GetPullRequestReviewEnforcement(ctx context.Contex
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r)
@@ -857,7 +990,7 @@ func (s *RepositoriesService) UpdatePullRequestReviewEnforcement(ctx context.Con
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r)
@@ -885,7 +1018,7 @@ func (s *RepositoriesService) DisableDismissalRestrictions(ctx context.Context,
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(PullRequestReviewsEnforcement)
resp, err := s.client.Do(ctx, req, r)
@@ -907,7 +1040,7 @@ func (s *RepositoriesService) RemovePullRequestReviewEnforcement(ctx context.Con
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
return s.client.Do(ctx, req, nil)
}
@@ -923,7 +1056,7 @@ func (s *RepositoriesService) GetAdminEnforcement(ctx context.Context, owner, re
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(AdminEnforcement)
resp, err := s.client.Do(ctx, req, r)
@@ -946,7 +1079,7 @@ func (s *RepositoriesService) AddAdminEnforcement(ctx context.Context, owner, re
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
r := new(AdminEnforcement)
resp, err := s.client.Do(ctx, req, r)
@@ -968,20 +1101,20 @@ func (s *RepositoriesService) RemoveAdminEnforcement(ctx context.Context, owner,
}
// TODO: remove custom Accept header when this API fully launches
req.Header.Set("Accept", mediaTypeProtectedBranchesPreview)
req.Header.Set("Accept", mediaTypeRequiredApprovingReviewsPreview)
return s.client.Do(ctx, req, nil)
}
// Topics represents a collection of repository topics.
type Topics struct {
Names []string `json:"names,omitempty"`
// repositoryTopics represents a collection of repository topics.
type repositoryTopics struct {
Names []string `json:"names"`
}
// ListAllTopics lists topics for a repository.
//
// GitHub API docs: https://developer.github.com/v3/repos/#list-all-topics-for-a-repository
func (s *RepositoriesService) ListAllTopics(ctx context.Context, owner, repo string) (*Topics, *Response, error) {
func (s *RepositoriesService) ListAllTopics(ctx context.Context, owner, repo string) ([]string, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/topics", owner, repo)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
@@ -991,21 +1124,27 @@ func (s *RepositoriesService) ListAllTopics(ctx context.Context, owner, repo str
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTopicsPreview)
topics := new(Topics)
topics := new(repositoryTopics)
resp, err := s.client.Do(ctx, req, topics)
if err != nil {
return nil, resp, err
}
return topics, resp, nil
return topics.Names, resp, nil
}
// ReplaceAllTopics replaces topics for a repository.
//
// GitHub API docs: https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository
func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo string, topics *Topics) (*Topics, *Response, error) {
func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo string, topics []string) ([]string, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/topics", owner, repo)
req, err := s.client.NewRequest("PUT", u, topics)
t := &repositoryTopics{
Names: topics,
}
if t.Names == nil {
t.Names = []string{}
}
req, err := s.client.NewRequest("PUT", u, t)
if err != nil {
return nil, nil, err
}
@@ -1013,11 +1152,46 @@ func (s *RepositoriesService) ReplaceAllTopics(ctx context.Context, owner, repo
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeTopicsPreview)
t := new(Topics)
t = new(repositoryTopics)
resp, err := s.client.Do(ctx, req, t)
if err != nil {
return nil, resp, err
}
return t, resp, nil
return t.Names, resp, nil
}
// TransferRequest represents a request to transfer a repository.
type TransferRequest struct {
NewOwner string `json:"new_owner"`
TeamID []int64 `json:"team_ids,omitempty"`
}
// Transfer transfers a repository from one account or organization to another.
//
// This method might return an *AcceptedError and a status code of
// 202. This is because this is the status that GitHub returns to signify that
// it has now scheduled the transfer of the repository in a background task.
// A follow up request, after a delay of a second or so, should result
// in a successful request.
//
// GitHub API docs: https://developer.github.com/v3/repos/#transfer-a-repository
func (s *RepositoriesService) Transfer(ctx context.Context, owner, repo string, transfer TransferRequest) (*Repository, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/transfer", owner, repo)
req, err := s.client.NewRequest("POST", u, &transfer)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeRepositoryTransferPreview)
r := new(Repository)
resp, err := s.client.Do(ctx, req, r)
if err != nil {
return nil, resp, err
}
return r, resp, nil
}

View File

@@ -41,6 +41,8 @@ func (s *RepositoriesService) ListCollaborators(ctx context.Context, owner, repo
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeNestedTeamsPreview)
var users []*User
resp, err := s.client.Do(ctx, req, &users)
if err != nil {

View File

@@ -15,11 +15,12 @@ import (
)
func TestRepositoriesService_ListCollaborators(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/collaborators", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeNestedTeamsPreview)
testFormValues(t, r, values{"page": "2"})
fmt.Fprintf(w, `[{"id":1}, {"id":2}]`)
})
@@ -32,14 +33,14 @@ func TestRepositoriesService_ListCollaborators(t *testing.T) {
t.Errorf("Repositories.ListCollaborators returned error: %v", err)
}
want := []*User{{ID: Int(1)}, {ID: Int(2)}}
want := []*User{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(users, want) {
t.Errorf("Repositori es.ListCollaborators returned %+v, want %+v", users, want)
}
}
func TestRepositoriesService_ListCollaborators_withAffiliation(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/collaborators", func(w http.ResponseWriter, r *http.Request) {
@@ -57,19 +58,22 @@ func TestRepositoriesService_ListCollaborators_withAffiliation(t *testing.T) {
t.Errorf("Repositories.ListCollaborators returned error: %v", err)
}
want := []*User{{ID: Int(1)}, {ID: Int(2)}}
want := []*User{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(users, want) {
t.Errorf("Repositories.ListCollaborators returned %+v, want %+v", users, want)
}
}
func TestRepositoriesService_ListCollaborators_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.ListCollaborators(context.Background(), "%", "%", nil)
testURLParseError(t, err)
}
func TestRepositoriesService_IsCollaborator_True(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/collaborators/u", func(w http.ResponseWriter, r *http.Request) {
@@ -88,7 +92,7 @@ func TestRepositoriesService_IsCollaborator_True(t *testing.T) {
}
func TestRepositoriesService_IsCollaborator_False(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/collaborators/u", func(w http.ResponseWriter, r *http.Request) {
@@ -107,12 +111,15 @@ func TestRepositoriesService_IsCollaborator_False(t *testing.T) {
}
func TestRepositoriesService_IsCollaborator_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.IsCollaborator(context.Background(), "%", "%", "%")
testURLParseError(t, err)
}
func TestRepositoryService_GetPermissionLevel(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/collaborators/u/permission", func(w http.ResponseWriter, r *http.Request) {
@@ -138,7 +145,7 @@ func TestRepositoryService_GetPermissionLevel(t *testing.T) {
}
func TestRepositoriesService_AddCollaborator(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
opt := &RepositoryAddCollaboratorOptions{Permission: "admin"}
@@ -163,12 +170,15 @@ func TestRepositoriesService_AddCollaborator(t *testing.T) {
}
func TestRepositoriesService_AddCollaborator_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Repositories.AddCollaborator(context.Background(), "%", "%", "%", nil)
testURLParseError(t, err)
}
func TestRepositoriesService_RemoveCollaborator(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/collaborators/u", func(w http.ResponseWriter, r *http.Request) {
@@ -183,6 +193,9 @@ func TestRepositoriesService_RemoveCollaborator(t *testing.T) {
}
func TestRepositoriesService_RemoveCollaborator_invalidUser(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Repositories.RemoveCollaborator(context.Background(), "%", "%", "%")
testURLParseError(t, err)
}

View File

@@ -15,7 +15,7 @@ import (
type RepositoryComment struct {
HTMLURL *string `json:"html_url,omitempty"`
URL *string `json:"url,omitempty"`
ID *int `json:"id,omitempty"`
ID *int64 `json:"id,omitempty"`
CommitID *string `json:"commit_id,omitempty"`
User *User `json:"user,omitempty"`
Reactions *Reactions `json:"reactions,omitempty"`
@@ -110,7 +110,7 @@ func (s *RepositoriesService) CreateComment(ctx context.Context, owner, repo, sh
// GetComment gets a single comment from a repository.
//
// GitHub API docs: https://developer.github.com/v3/repos/comments/#get-a-single-commit-comment
func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string, id int) (*RepositoryComment, *Response, error) {
func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string, id int64) (*RepositoryComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
@@ -132,7 +132,7 @@ func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string
// UpdateComment updates the body of a single comment.
//
// GitHub API docs: https://developer.github.com/v3/repos/comments/#update-a-commit-comment
func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo string, id int, comment *RepositoryComment) (*RepositoryComment, *Response, error) {
func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo string, id int64, comment *RepositoryComment) (*RepositoryComment, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id)
req, err := s.client.NewRequest("PATCH", u, comment)
if err != nil {
@@ -151,7 +151,7 @@ func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo str
// DeleteComment deletes a single comment from a repository.
//
// GitHub API docs: https://developer.github.com/v3/repos/comments/#delete-a-commit-comment
func (s *RepositoriesService) DeleteComment(ctx context.Context, owner, repo string, id int) (*Response, error) {
func (s *RepositoriesService) DeleteComment(ctx context.Context, owner, repo string, id int64) (*Response, error) {
u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {

View File

@@ -15,7 +15,7 @@ import (
)
func TestRepositoriesService_ListComments(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -31,19 +31,22 @@ func TestRepositoriesService_ListComments(t *testing.T) {
t.Errorf("Repositories.ListComments returned error: %v", err)
}
want := []*RepositoryComment{{ID: Int(1)}, {ID: Int(2)}}
want := []*RepositoryComment{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Repositories.ListComments returned %+v, want %+v", comments, want)
}
}
func TestRepositoriesService_ListComments_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.ListComments(context.Background(), "%", "%", nil)
testURLParseError(t, err)
}
func TestRepositoriesService_ListCommitComments(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/commits/s/comments", func(w http.ResponseWriter, r *http.Request) {
@@ -59,19 +62,22 @@ func TestRepositoriesService_ListCommitComments(t *testing.T) {
t.Errorf("Repositories.ListCommitComments returned error: %v", err)
}
want := []*RepositoryComment{{ID: Int(1)}, {ID: Int(2)}}
want := []*RepositoryComment{{ID: Int64(1)}, {ID: Int64(2)}}
if !reflect.DeepEqual(comments, want) {
t.Errorf("Repositories.ListCommitComments returned %+v, want %+v", comments, want)
}
}
func TestRepositoriesService_ListCommitComments_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.ListCommitComments(context.Background(), "%", "%", "%", nil)
testURLParseError(t, err)
}
func TestRepositoriesService_CreateComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &RepositoryComment{Body: String("b")}
@@ -93,19 +99,22 @@ func TestRepositoriesService_CreateComment(t *testing.T) {
t.Errorf("Repositories.CreateComment returned error: %v", err)
}
want := &RepositoryComment{ID: Int(1)}
want := &RepositoryComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Repositories.CreateComment returned %+v, want %+v", comment, want)
}
}
func TestRepositoriesService_CreateComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.CreateComment(context.Background(), "%", "%", "%", nil)
testURLParseError(t, err)
}
func TestRepositoriesService_GetComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/comments/1", func(w http.ResponseWriter, r *http.Request) {
@@ -119,19 +128,22 @@ func TestRepositoriesService_GetComment(t *testing.T) {
t.Errorf("Repositories.GetComment returned error: %v", err)
}
want := &RepositoryComment{ID: Int(1)}
want := &RepositoryComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Repositories.GetComment returned %+v, want %+v", comment, want)
}
}
func TestRepositoriesService_GetComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.GetComment(context.Background(), "%", "%", 1)
testURLParseError(t, err)
}
func TestRepositoriesService_UpdateComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
input := &RepositoryComment{Body: String("b")}
@@ -153,19 +165,22 @@ func TestRepositoriesService_UpdateComment(t *testing.T) {
t.Errorf("Repositories.UpdateComment returned error: %v", err)
}
want := &RepositoryComment{ID: Int(1)}
want := &RepositoryComment{ID: Int64(1)}
if !reflect.DeepEqual(comment, want) {
t.Errorf("Repositories.UpdateComment returned %+v, want %+v", comment, want)
}
}
func TestRepositoriesService_UpdateComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.UpdateComment(context.Background(), "%", "%", 1, nil)
testURLParseError(t, err)
}
func TestRepositoriesService_DeleteComment(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/comments/1", func(w http.ResponseWriter, r *http.Request) {
@@ -179,6 +194,9 @@ func TestRepositoriesService_DeleteComment(t *testing.T) {
}
func TestRepositoriesService_DeleteComment_invalidOwner(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, err := client.Repositories.DeleteComment(context.Background(), "%", "%", 1)
testURLParseError(t, err)
}

View File

@@ -48,16 +48,17 @@ func (c CommitStats) String() string {
// CommitFile represents a file modified in a commit.
type CommitFile struct {
SHA *string `json:"sha,omitempty"`
Filename *string `json:"filename,omitempty"`
Additions *int `json:"additions,omitempty"`
Deletions *int `json:"deletions,omitempty"`
Changes *int `json:"changes,omitempty"`
Status *string `json:"status,omitempty"`
Patch *string `json:"patch,omitempty"`
BlobURL *string `json:"blob_url,omitempty"`
RawURL *string `json:"raw_url,omitempty"`
ContentsURL *string `json:"contents_url,omitempty"`
SHA *string `json:"sha,omitempty"`
Filename *string `json:"filename,omitempty"`
Additions *int `json:"additions,omitempty"`
Deletions *int `json:"deletions,omitempty"`
Changes *int `json:"changes,omitempty"`
Status *string `json:"status,omitempty"`
Patch *string `json:"patch,omitempty"`
BlobURL *string `json:"blob_url,omitempty"`
RawURL *string `json:"raw_url,omitempty"`
ContentsURL *string `json:"contents_url,omitempty"`
PreviousFilename *string `json:"previous_filename,omitempty"`
}
func (c CommitFile) String() string {
@@ -140,10 +141,9 @@ func (s *RepositoriesService) ListCommits(ctx context.Context, owner, repo strin
}
// GetCommit fetches the specified commit, including all details about it.
// todo: support media formats - https://github.com/google/go-github/issues/6
//
// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit
// See also: https://developer.github.com//v3/git/commits/#get-a-single-commit provides the same functionality
// See also: https://developer.github.com/v3/git/commits/#get-a-single-commit provides the same functionality
func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
@@ -164,6 +164,32 @@ func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha st
return commit, resp, nil
}
// GetCommitRaw fetches the specified commit in raw (diff or patch) format.
func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opt RawOptions) (string, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return "", nil, err
}
switch opt.Type {
case Diff:
req.Header.Set("Accept", mediaTypeV3Diff)
case Patch:
req.Header.Set("Accept", mediaTypeV3Patch)
default:
return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type)
}
var buf bytes.Buffer
resp, err := s.client.Do(ctx, req, &buf)
if err != nil {
return "", resp, err
}
return buf.String(), resp, nil
}
// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is
// supplied and no new commits have occurred, a 304 Unmodified response is returned.
//
@@ -193,7 +219,7 @@ func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, owner, repo, re
// CompareCommits compares a range of commits with each other.
// todo: support media formats - https://github.com/google/go-github/issues/6
//
// GitHub API docs: https://developer.github.com/v3/repos/commits/index.html#compare-two-commits
// GitHub API docs: https://developer.github.com/v3/repos/commits/#compare-two-commits
func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head)

View File

@@ -10,12 +10,13 @@ import (
"fmt"
"net/http"
"reflect"
"strings"
"testing"
"time"
)
func TestRepositoriesService_ListCommits(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
// given
@@ -52,7 +53,7 @@ func TestRepositoriesService_ListCommits(t *testing.T) {
}
func TestRepositoriesService_GetCommit(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
@@ -126,8 +127,65 @@ func TestRepositoriesService_GetCommit(t *testing.T) {
}
}
func TestRepositoriesService_GetCommitRaw_diff(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
const rawStr = "@@diff content"
mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeV3Diff)
fmt.Fprint(w, rawStr)
})
got, _, err := client.Repositories.GetCommitRaw(context.Background(), "o", "r", "s", RawOptions{Type: Diff})
if err != nil {
t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
}
want := rawStr
if got != want {
t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
}
}
func TestRepositoriesService_GetCommitRaw_patch(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()
const rawStr = "@@patch content"
mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeV3Patch)
fmt.Fprint(w, rawStr)
})
got, _, err := client.Repositories.GetCommitRaw(context.Background(), "o", "r", "s", RawOptions{Type: Patch})
if err != nil {
t.Fatalf("Repositories.GetCommitRaw returned error: %v", err)
}
want := rawStr
if got != want {
t.Errorf("Repositories.GetCommitRaw returned %s want %s", got, want)
}
}
func TestRepositoriesService_GetCommitRaw_invalid(t *testing.T) {
client, _, _, teardown := setup()
defer teardown()
_, _, err := client.Repositories.GetCommitRaw(context.Background(), "o", "r", "s", RawOptions{100})
if err == nil {
t.Fatal("Repositories.GetCommitRaw should return error")
}
if !strings.Contains(err.Error(), "unsupported raw type") {
t.Error("Repositories.GetCommitRaw should return unsupported raw type error")
}
}
func TestRepositoriesService_GetCommitSHA1(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
const sha1 = "01234abcde"
@@ -168,7 +226,7 @@ func TestRepositoriesService_GetCommitSHA1(t *testing.T) {
}
func TestRepositoriesService_CompareCommits(t *testing.T) {
setup()
client, mux, _, teardown := setup()
defer teardown()
mux.HandleFunc("/repos/o/r/compare/b...h", func(w http.ResponseWriter, r *http.Request) {

Some files were not shown because too many files have changed in this diff Show More