From cd28eb3859cc60a1f5fe94c11abce3749bd04b69 Mon Sep 17 00:00:00 2001 From: Zachary Gershman Date: Tue, 21 Jun 2016 08:06:21 -0700 Subject: [PATCH] Bumps go-github and fixes incompatibilities --- Godeps/Godeps.json | 3 +- .../src/github.com/google/go-github/LICENSE | 5 +- .../google/go-github/github/activity.go | 55 +++ .../go-github/github/activity_events.go | 172 +++---- .../github/activity_notifications.go | 10 +- .../google/go-github/github/activity_star.go | 17 +- .../go-github/github/activity_watching.go | 8 +- .../google/go-github/github/authorizations.go | 323 ++++++++++++ .../github.com/google/go-github/github/doc.go | 2 +- .../google/go-github/github/event_types.go | 460 ++++++++++++++++++ .../google/go-github/github/gists.go | 12 +- .../google/go-github/github/gists_comments.go | 4 +- .../google/go-github/github/git_commits.go | 31 +- .../google/go-github/github/git_refs.go | 4 +- .../google/go-github/github/git_tags.go | 16 +- .../google/go-github/github/github.go | 202 ++++++-- .../google/go-github/github/issues.go | 63 ++- .../go-github/github/issues_assignees.go | 48 +- .../go-github/github/issues_comments.go | 13 +- .../google/go-github/github/issues_events.go | 8 +- .../google/go-github/github/issues_labels.go | 20 +- .../go-github/github/issues_milestones.go | 10 +- .../go-github/github/issues_timeline.go | 148 ++++++ .../google/go-github/github/licenses.go | 4 +- .../google/go-github/github/messages.go | 119 +++++ .../google/go-github/github/migrations.go | 225 +++++++++ .../github/migrations_source_import.go | 326 +++++++++++++ .../google/go-github/github/misc.go | 4 +- .../google/go-github/github/orgs.go | 39 +- .../google/go-github/github/orgs_hooks.go | 4 +- .../google/go-github/github/orgs_members.go | 12 +- .../google/go-github/github/orgs_teams.go | 48 +- .../google/go-github/github/pulls.go | 31 +- .../google/go-github/github/pulls_comments.go | 15 +- .../google/go-github/github/reactions.go | 272 +++++++++++ .../google/go-github/github/repos.go | 72 ++- .../go-github/github/repos_collaborators.go | 15 +- .../google/go-github/github/repos_comments.go | 18 +- .../google/go-github/github/repos_commits.go | 34 +- .../google/go-github/github/repos_contents.go | 43 +- .../go-github/github/repos_deployments.go | 81 +-- .../google/go-github/github/repos_forks.go | 4 +- .../google/go-github/github/repos_hooks.go | 6 +- .../go-github/github/repos_invitations.go | 91 ++++ .../google/go-github/github/repos_keys.go | 4 +- .../google/go-github/github/repos_pages.go | 4 +- .../google/go-github/github/repos_releases.go | 42 +- .../google/go-github/github/repos_stats.go | 20 +- .../google/go-github/github/repos_statuses.go | 4 +- .../google/go-github/github/search.go | 2 +- .../google/go-github/github/users.go | 83 +++- .../google/go-github/github/users_emails.go | 8 +- .../go-github/github/users_followers.go | 8 +- .../google/go-github/github/users_gpg_keys.go | 127 +++++ .../google/go-github/github/users_keys.go | 4 +- github.go | 10 +- 56 files changed, 3012 insertions(+), 401 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/authorizations.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/event_types.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/issues_timeline.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/messages.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/migrations.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/migrations_source_import.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/reactions.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/repos_invitations.go create mode 100644 Godeps/_workspace/src/github.com/google/go-github/github/users_gpg_keys.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 1a63f17..74e2c29 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,7 @@ { "ImportPath": "github.com/concourse/github-release-resource", "GoVersion": "go1.5", + "GodepVersion": "v74", "Packages": [ "./..." ], @@ -15,7 +16,7 @@ }, { "ImportPath": "github.com/google/go-github/github", - "Rev": "39d75606a4cbec14d6f9f9d4e295dad4e3711682" + "Rev": "07995e49c22dcb1e372c88ff12793b0194433e1c" }, { "ImportPath": "github.com/google/go-querystring/query", diff --git a/Godeps/_workspace/src/github.com/google/go-github/LICENSE b/Godeps/_workspace/src/github.com/google/go-github/LICENSE index 3a3a8ec..5582e4a 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/LICENSE +++ b/Godeps/_workspace/src/github.com/google/go-github/LICENSE @@ -29,8 +29,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------- Some documentation is taken from the GitHub Developer site -, which is available under a Creative Commons -Attribution 3.0 License: +, which is available under the following Creative +Commons Attribution 3.0 License. This applies only to the go-github source +code and would not apply to any compiled binaries. THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/activity.go b/Godeps/_workspace/src/github.com/google/go-github/github/activity.go index 355de62..88ad8d2 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/activity.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/activity.go @@ -12,3 +12,58 @@ package github type ActivityService struct { client *Client } + +// FeedLink represents a link to a related resource. +type FeedLink struct { + HRef *string `json:"href,omitempty"` + Type *string `json:"type,omitempty"` +} + +// Feeds represents timeline resources in Atom format. +type Feeds struct { + TimelineURL *string `json:"timeline_url,omitempty"` + UserURL *string `json:"user_url,omitempty"` + CurrentUserPublicURL *string `json:"current_user_public_url,omitempty"` + CurrentUserURL *string `json:"current_user_url,omitempty"` + CurrentUserActorURL *string `json:"current_user_actor_url,omitempty"` + CurrentUserOrganizationURL *string `json:"current_user_organization_url,omitempty"` + CurrentUserOrganizationURLs []string `json:"current_user_organization_urls,omitempty"` + Links *struct { + Timeline *FeedLink `json:"timeline,omitempty"` + User *FeedLink `json:"user,omitempty"` + CurrentUserPublic *FeedLink `json:"current_user_public,omitempty"` + CurrentUser *FeedLink `json:"current_user,omitempty"` + CurrentUserActor *FeedLink `json:"current_user_actor,omitempty"` + CurrentUserOrganization *FeedLink `json:"current_user_organization,omitempty"` + CurrentUserOrganizations []FeedLink `json:"current_user_organizations,omitempty"` + } `json:"_links,omitempty"` +} + +// ListFeeds lists all the feeds available to the authenticated user. +// +// GitHub provides several timeline resources in Atom format: +// Timeline: The GitHub global public timeline +// User: The public timeline for any user, using URI template +// Current user public: The public timeline for the authenticated user +// Current user: The private timeline for the authenticated user +// Current user actor: The private timeline for activity created by the +// authenticated user +// Current user organizations: The private timeline for the organizations +// the authenticated user is a member of. +// +// Note: Private feeds are only returned when authenticating via Basic Auth +// since current feed URIs use the older, non revocable auth tokens. +func (s *ActivityService) ListFeeds() (*Feeds, *Response, error) { + req, err := s.client.NewRequest("GET", "feeds", nil) + if err != nil { + return nil, nil, err + } + + f := &Feeds{} + resp, err := s.client.Do(req, f) + if err != nil { + return nil, resp, err + } + + return f, resp, nil +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/activity_events.go b/Godeps/_workspace/src/github.com/google/go-github/github/activity_events.go index 1e4c4c8..a0e5f08 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/activity_events.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/activity_events.go @@ -27,12 +27,54 @@ func (e Event) String() string { return Stringify(e) } -// Payload returns the parsed event payload. For recognized event types -// (PushEvent), a value of the corresponding struct type will be returned. +// Payload returns the parsed event payload. For recognized event types, +// a value of the corresponding struct type will be returned. func (e *Event) Payload() (payload interface{}) { 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 "IssueActivityEvent": + payload = &IssueActivityEvent{} + case "IssueCommentEvent": + payload = &IssueCommentEvent{} + case "IssuesEvent": + payload = &IssuesEvent{} + case "MemberEvent": + payload = &MemberEvent{} + case "MembershipEvent": + payload = &MembershipEvent{} + case "PageBuildEvent": + payload = &PageBuildEvent{} + case "PublicEvent": + payload = &PublicEvent{} + case "PullRequestEvent": + payload = &PullRequestEvent{} + case "PullRequestReviewCommentEvent": + payload = &PullRequestReviewCommentEvent{} case "PushEvent": payload = &PushEvent{} + case "ReleaseEvent": + payload = &ReleaseEvent{} + case "RepositoryEvent": + payload = &RepositoryEvent{} + case "StatusEvent": + payload = &StatusEvent{} + case "TeamAddEvent": + payload = &TeamAddEvent{} + case "WatchEvent": + payload = &WatchEvent{} } if err := json.Unmarshal(*e.RawPayload, &payload); err != nil { panic(err.Error()) @@ -40,104 +82,10 @@ func (e *Event) Payload() (payload interface{}) { return payload } -// PushEvent represents a git push to a GitHub repository. -// -// GitHub API docs: http://developer.github.com/v3/activity/events/types/#pushevent -type PushEvent struct { - PushID *int `json:"push_id,omitempty"` - Head *string `json:"head,omitempty"` - Ref *string `json:"ref,omitempty"` - Size *int `json:"size,omitempty"` - Commits []PushEventCommit `json:"commits,omitempty"` - Repo *PushEventRepository `json:"repository,omitempty"` -} - -func (p PushEvent) String() string { - return Stringify(p) -} - -// PushEventCommit represents a git commit in a GitHub PushEvent. -type PushEventCommit struct { - SHA *string `json:"sha,omitempty"` - Message *string `json:"message,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - URL *string `json:"url,omitempty"` - Distinct *bool `json:"distinct,omitempty"` - Added []string `json:"added,omitempty"` - Removed []string `json:"removed,omitempty"` - Modified []string `json:"modified,omitempty"` -} - -func (p PushEventCommit) String() string { - return Stringify(p) -} - -// 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"` -} - -// PushEventRepoOwner is a basic reporesntation of user/org in a PushEvent payload -type PushEventRepoOwner struct { - Name *string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` -} - -//PullRequestEvent represents the payload delivered by PullRequestEvent webhook -type PullRequestEvent struct { - Action *string `json:"action,omitempty"` - Number *int `json:"number,omitempty"` - PullRequest *PullRequest `json:"pull_request,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` -} - -// IssueActivityEvent represents the payload delivered by Issue webhook -type IssueActivityEvent struct { - Action *string `json:"action,omitempty"` - Issue *Issue `json:"issue,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` -} - -// IssueCommentEvent represents the payload delivered by IssueComment webhook -// -// This webhook also gets fired for comments on pull requests -type IssueCommentEvent struct { - Action *string `json:"action,omitempty"` - Issue *Issue `json:"issue,omitempty"` - Comment *IssueComment `json:"comment,omitempty"` - Repo *Repository `json:"repository,omitempty"` - Sender *User `json:"sender,omitempty"` -} - // ListEvents drinks from the firehose of all public events across GitHub. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events -func (s *ActivityService) ListEvents(opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListEvents(opt *ListOptions) ([]*Event, *Response, error) { u, err := addOptions("events", opt) if err != nil { return nil, nil, err @@ -148,7 +96,7 @@ func (s *ActivityService) ListEvents(opt *ListOptions) ([]Event, *Response, erro return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err @@ -160,7 +108,7 @@ func (s *ActivityService) ListEvents(opt *ListOptions) ([]Event, *Response, erro // ListRepositoryEvents lists events for a repository. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-repository-events -func (s *ActivityService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("repos/%v/%v/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -172,7 +120,7 @@ func (s *ActivityService) ListRepositoryEvents(owner, repo string, opt *ListOpti return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err @@ -184,7 +132,7 @@ func (s *ActivityService) ListRepositoryEvents(owner, repo string, opt *ListOpti // ListIssueEventsForRepository lists issue events for a repository. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository -func (s *ActivityService) ListIssueEventsForRepository(owner, repo string, opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListIssueEventsForRepository(owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -196,7 +144,7 @@ func (s *ActivityService) ListIssueEventsForRepository(owner, repo string, opt * return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err @@ -208,7 +156,7 @@ func (s *ActivityService) ListIssueEventsForRepository(owner, repo string, opt * // ListEventsForRepoNetwork lists public events for a network of repositories. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events-for-a-network-of-repositories -func (s *ActivityService) ListEventsForRepoNetwork(owner, repo string, opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListEventsForRepoNetwork(owner, repo string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("networks/%v/%v/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -220,7 +168,7 @@ func (s *ActivityService) ListEventsForRepoNetwork(owner, repo string, opt *List return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err @@ -232,7 +180,7 @@ func (s *ActivityService) ListEventsForRepoNetwork(owner, repo string, opt *List // ListEventsForOrganization lists public events for an organization. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-public-events-for-an-organization -func (s *ActivityService) ListEventsForOrganization(org string, opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListEventsForOrganization(org string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("orgs/%v/events", org) u, err := addOptions(u, opt) if err != nil { @@ -244,7 +192,7 @@ func (s *ActivityService) ListEventsForOrganization(org string, opt *ListOptions return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err @@ -257,7 +205,7 @@ func (s *ActivityService) ListEventsForOrganization(org string, opt *ListOptions // true, only public events will be returned. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-performed-by-a-user -func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { var u string if publicOnly { u = fmt.Sprintf("users/%v/events/public", user) @@ -274,7 +222,7 @@ func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err @@ -287,7 +235,7 @@ func (s *ActivityService) ListEventsPerformedByUser(user string, publicOnly bool // true, only public events will be returned. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received -func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { var u string if publicOnly { u = fmt.Sprintf("users/%v/received_events/public", user) @@ -304,7 +252,7 @@ func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err @@ -317,7 +265,7 @@ func (s *ActivityService) ListEventsReceivedByUser(user string, publicOnly bool, // must be authenticated as the user to view this. // // GitHub API docs: http://developer.github.com/v3/activity/events/#list-events-for-an-organization -func (s *ActivityService) ListUserEventsForOrganization(org, user string, opt *ListOptions) ([]Event, *Response, error) { +func (s *ActivityService) ListUserEventsForOrganization(org, user string, opt *ListOptions) ([]*Event, *Response, error) { u := fmt.Sprintf("users/%v/events/orgs/%v", user, org) u, err := addOptions(u, opt) if err != nil { @@ -329,7 +277,7 @@ func (s *ActivityService) ListUserEventsForOrganization(org, user string, opt *L return nil, nil, err } - events := new([]Event) + events := new([]*Event) resp, err := s.client.Do(req, events) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/activity_notifications.go b/Godeps/_workspace/src/github.com/google/go-github/github/activity_notifications.go index 290b954..8890388 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/activity_notifications.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/activity_notifications.go @@ -42,12 +42,14 @@ type NotificationListOptions struct { Participating bool `url:"participating,omitempty"` Since time.Time `url:"since,omitempty"` Before time.Time `url:"before,omitempty"` + + ListOptions } // ListNotifications lists all notifications for the authenticated user. // // GitHub API Docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications -func (s *ActivityService) ListNotifications(opt *NotificationListOptions) ([]Notification, *Response, error) { +func (s *ActivityService) ListNotifications(opt *NotificationListOptions) ([]*Notification, *Response, error) { u := fmt.Sprintf("notifications") u, err := addOptions(u, opt) if err != nil { @@ -59,7 +61,7 @@ func (s *ActivityService) ListNotifications(opt *NotificationListOptions) ([]Not return nil, nil, err } - var notifications []Notification + var notifications []*Notification resp, err := s.client.Do(req, ¬ifications) if err != nil { return nil, resp, err @@ -72,7 +74,7 @@ func (s *ActivityService) ListNotifications(opt *NotificationListOptions) ([]Not // for the authenticated user. // // GitHub API Docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository -func (s *ActivityService) ListRepositoryNotifications(owner, repo string, opt *NotificationListOptions) ([]Notification, *Response, error) { +func (s *ActivityService) ListRepositoryNotifications(owner, repo string, opt *NotificationListOptions) ([]*Notification, *Response, error) { u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -84,7 +86,7 @@ func (s *ActivityService) ListRepositoryNotifications(owner, repo string, opt *N return nil, nil, err } - var notifications []Notification + var notifications []*Notification resp, err := s.client.Do(req, ¬ifications) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go b/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go index fac4f41..5df6814 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/activity_star.go @@ -13,10 +13,16 @@ type StarredRepository struct { Repository *Repository `json:"repo,omitempty"` } +// Stargazer represents a user that has starred a repository. +type Stargazer struct { + StarredAt *Timestamp `json:"starred_at,omitempty"` + User *User `json:"user,omitempty"` +} + // ListStargazers lists people who have starred the specified repo. // // GitHub API Docs: https://developer.github.com/v3/activity/starring/#list-stargazers -func (s *ActivityService) ListStargazers(owner, repo string, opt *ListOptions) ([]User, *Response, error) { +func (s *ActivityService) ListStargazers(owner, repo string, opt *ListOptions) ([]*Stargazer, *Response, error) { u := fmt.Sprintf("repos/%s/%s/stargazers", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -28,7 +34,10 @@ func (s *ActivityService) ListStargazers(owner, repo string, opt *ListOptions) ( return nil, nil, err } - stargazers := new([]User) + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeStarringPreview) + + stargazers := new([]*Stargazer) resp, err := s.client.Do(req, stargazers) if err != nil { return nil, resp, err @@ -55,7 +64,7 @@ type ActivityListStarredOptions struct { // will list the starred repositories for the authenticated user. // // GitHub API docs: http://developer.github.com/v3/activity/starring/#list-repositories-being-starred -func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptions) ([]StarredRepository, *Response, error) { +func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptions) ([]*StarredRepository, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/starred", user) @@ -75,7 +84,7 @@ func (s *ActivityService) ListStarred(user string, opt *ActivityListStarredOptio // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeStarringPreview) - repos := new([]StarredRepository) + repos := new([]*StarredRepository) resp, err := s.client.Do(req, repos) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/activity_watching.go b/Godeps/_workspace/src/github.com/google/go-github/github/activity_watching.go index c002b3b..6bf91dd 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/activity_watching.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/activity_watching.go @@ -25,7 +25,7 @@ type Subscription struct { // ListWatchers lists watchers of a particular repo. // // GitHub API Docs: http://developer.github.com/v3/activity/watching/#list-watchers -func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([]User, *Response, error) { +func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([]*User, *Response, error) { u := fmt.Sprintf("repos/%s/%s/subscribers", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -37,7 +37,7 @@ func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([] return nil, nil, err } - watchers := new([]User) + watchers := new([]*User) resp, err := s.client.Do(req, watchers) if err != nil { return nil, resp, err @@ -50,7 +50,7 @@ func (s *ActivityService) ListWatchers(owner, repo string, opt *ListOptions) ([] // the empty string will fetch watched repos for the authenticated user. // // GitHub API Docs: https://developer.github.com/v3/activity/watching/#list-repositories-being-watched -func (s *ActivityService) ListWatched(user string, opt *ListOptions) ([]Repository, *Response, error) { +func (s *ActivityService) ListWatched(user string, opt *ListOptions) ([]*Repository, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/subscriptions", user) @@ -67,7 +67,7 @@ func (s *ActivityService) ListWatched(user string, opt *ListOptions) ([]Reposito return nil, nil, err } - watched := new([]Repository) + watched := new([]*Repository) resp, err := s.client.Do(req, watched) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/authorizations.go b/Godeps/_workspace/src/github.com/google/go-github/github/authorizations.go new file mode 100644 index 0000000..43af06c --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/authorizations.go @@ -0,0 +1,323 @@ +// Copyright 2015 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import "fmt" + +// Scope models a GitHub authorization scope. +// +// GitHub API docs:https://developer.github.com/v3/oauth/#scopes +type Scope string + +// This is the set of scopes for GitHub API V3 +const ( + ScopeNone Scope = "(no scope)" // REVISIT: is this actually returned, or just a documentation artifact? + ScopeUser Scope = "user" + ScopeUserEmail Scope = "user:email" + ScopeUserFollow Scope = "user:follow" + ScopePublicRepo Scope = "public_repo" + ScopeRepo Scope = "repo" + ScopeRepoDeployment Scope = "repo_deployment" + ScopeRepoStatus Scope = "repo:status" + ScopeDeleteRepo Scope = "delete_repo" + ScopeNotifications Scope = "notifications" + ScopeGist Scope = "gist" + ScopeReadRepoHook Scope = "read:repo_hook" + ScopeWriteRepoHook Scope = "write:repo_hook" + ScopeAdminRepoHook Scope = "admin:repo_hook" + ScopeAdminOrgHook Scope = "admin:org_hook" + ScopeReadOrg Scope = "read:org" + ScopeWriteOrg Scope = "write:org" + ScopeAdminOrg Scope = "admin:org" + ScopeReadPublicKey Scope = "read:public_key" + ScopeWritePublicKey Scope = "write:public_key" + ScopeAdminPublicKey Scope = "admin:public_key" + ScopeReadGPGKey Scope = "read:gpg_key" + ScopeWriteGPGKey Scope = "write:gpg_key" + ScopeAdminGPGKey Scope = "admin:gpg_key" +) + +// AuthorizationsService handles communication with the authorization related +// methods of the GitHub API. +// +// This service requires HTTP Basic Authentication; it cannot be accessed using +// an OAuth token. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/ +type AuthorizationsService struct { + client *Client +} + +// Authorization represents an individual GitHub authorization. +type Authorization struct { + ID *int `json:"id,omitempty"` + URL *string `json:"url,omitempty"` + Scopes []Scope `json:"scopes,omitempty"` + Token *string `json:"token,omitempty"` + TokenLastEight *string `json:"token_last_eight,omitempty"` + HashedToken *string `json:"hashed_token,omitempty"` + App *AuthorizationApp `json:"app,omitempty"` + Note *string `json:"note,omitempty"` + NoteURL *string `json:"note_url,omitempty"` + UpdateAt *Timestamp `json:"updated_at,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + Fingerprint *string `json:"fingerprint,omitempty"` + + // User is only populated by the Check and Reset methods. + User *User `json:"user,omitempty"` +} + +func (a Authorization) String() string { + return Stringify(a) +} + +// AuthorizationApp represents an individual GitHub app (in the context of authorization). +type AuthorizationApp struct { + URL *string `json:"url,omitempty"` + Name *string `json:"name,omitempty"` + ClientID *string `json:"client_id,omitempty"` +} + +func (a AuthorizationApp) String() string { + return Stringify(a) +} + +// AuthorizationRequest represents a request to create an authorization. +type AuthorizationRequest struct { + Scopes []Scope `json:"scopes,omitempty"` + Note *string `json:"note,omitempty"` + NoteURL *string `json:"note_url,omitempty"` + ClientID *string `json:"client_id,omitempty"` + ClientSecret *string `json:"client_secret,omitempty"` + Fingerprint *string `json:"fingerprint,omitempty"` +} + +func (a AuthorizationRequest) String() string { + return Stringify(a) +} + +// AuthorizationUpdateRequest represents a request to update an authorization. +// +// Note that for any one update, you must only provide one of the "scopes" +// fields. That is, you may provide only one of "Scopes", or "AddScopes", or +// "RemoveScopes". +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization +type AuthorizationUpdateRequest struct { + Scopes []string `json:"scopes,omitempty"` + AddScopes []string `json:"add_scopes,omitempty"` + RemoveScopes []string `json:"remove_scopes,omitempty"` + Note *string `json:"note,omitempty"` + NoteURL *string `json:"note_url,omitempty"` + Fingerprint *string `json:"fingerprint,omitempty"` +} + +func (a AuthorizationUpdateRequest) String() string { + return Stringify(a) +} + +// List the authorizations for the authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-authorizations +func (s *AuthorizationsService) List(opt *ListOptions) ([]*Authorization, *Response, error) { + u := "authorizations" + 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 + } + + auths := new([]*Authorization) + resp, err := s.client.Do(req, auths) + if err != nil { + return nil, resp, err + } + return *auths, resp, err +} + +// Get a single authorization. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization +func (s *AuthorizationsService) Get(id int) (*Authorization, *Response, error) { + u := fmt.Sprintf("authorizations/%d", id) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + a := new(Authorization) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + return a, resp, err +} + +// Create a new authorization for the specified OAuth application. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization +func (s *AuthorizationsService) Create(auth *AuthorizationRequest) (*Authorization, *Response, error) { + u := "authorizations" + + req, err := s.client.NewRequest("POST", u, auth) + if err != nil { + return nil, nil, err + } + + a := new(Authorization) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + return a, resp, err +} + +// GetOrCreateForApp creates a new authorization for the specified OAuth +// application, only if an authorization for that application doesn’t already +// exist for the user. +// +// If a new token is created, the HTTP status code will be "201 Created", and +// the returned Authorization.Token field will be populated. If an existing +// token is returned, the status code will be "200 OK" and the +// Authorization.Token field will be empty. +// +// clientID is the OAuth Client ID with which to create the token. +// +// GitHub API docs: +// - https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app +// - https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app-and-fingerprint +func (s *AuthorizationsService) GetOrCreateForApp(clientID string, auth *AuthorizationRequest) (*Authorization, *Response, error) { + var u string + if auth.Fingerprint == nil || *auth.Fingerprint == "" { + u = fmt.Sprintf("authorizations/clients/%v", clientID) + } else { + u = fmt.Sprintf("authorizations/clients/%v/%v", clientID, *auth.Fingerprint) + } + + req, err := s.client.NewRequest("PUT", u, auth) + if err != nil { + return nil, nil, err + } + + a := new(Authorization) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// Edit a single authorization. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization +func (s *AuthorizationsService) Edit(id int, auth *AuthorizationUpdateRequest) (*Authorization, *Response, error) { + u := fmt.Sprintf("authorizations/%d", id) + + req, err := s.client.NewRequest("PATCH", u, auth) + if err != nil { + return nil, nil, err + } + + a := new(Authorization) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// Delete a single authorization. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization +func (s *AuthorizationsService) Delete(id int) (*Response, error) { + u := fmt.Sprintf("authorizations/%d", id) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} + +// Check if an OAuth token is valid for a specific app. +// +// Note that this operation requires the use of BasicAuth, but where the +// username is the OAuth application clientID, and the password is its +// clientSecret. Invalid tokens will return a 404 Not Found. +// +// The returned Authorization.User field will be populated. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#check-an-authorization +func (s *AuthorizationsService) Check(clientID string, token string) (*Authorization, *Response, error) { + u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + a := new(Authorization) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// Reset is used to reset a valid OAuth token without end user involvement. +// Applications must save the "token" property in the response, because changes +// take effect immediately. +// +// Note that this operation requires the use of BasicAuth, but where the +// username is the OAuth application clientID, and the password is its +// clientSecret. Invalid tokens will return a 404 Not Found. +// +// The returned Authorization.User field will be populated. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization +func (s *AuthorizationsService) Reset(clientID string, token string) (*Authorization, *Response, error) { + u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) + + req, err := s.client.NewRequest("POST", u, nil) + if err != nil { + return nil, nil, err + } + + a := new(Authorization) + resp, err := s.client.Do(req, a) + if err != nil { + return nil, resp, err + } + + return a, resp, err +} + +// Revoke an authorization for an application. +// +// Note that this operation requires the use of BasicAuth, but where the +// username is the OAuth application clientID, and the password is its +// clientSecret. Invalid tokens will return a 404 Not Found. +// +// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application +func (s *AuthorizationsService) Revoke(clientID string, token string) (*Response, error) { + u := fmt.Sprintf("applications/%v/tokens/%v", clientID, token) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/doc.go b/Godeps/_workspace/src/github.com/google/go-github/github/doc.go index 0d32d49..6c6f53a 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/doc.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/doc.go @@ -116,7 +116,7 @@ PullRequestListOptions). Pages information is available via Response struct. ListOptions: github.ListOptions{PerPage: 10}, } // get all pages of results - var allRepos []github.Repository + var allRepos []*github.Repository for { repos, resp, err := client.Repositories.ListByOrg("github", opt) if err != nil { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/event_types.go b/Godeps/_workspace/src/github.com/google/go-github/github/event_types.go new file mode 100644 index 0000000..6f7202e --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/event_types.go @@ -0,0 +1,460 @@ +// Copyright 2016 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. + +// These event types are shared between the Events API and used as Webhook payloads. + +package github + +// CommitCommentEvent is triggered when a commit comment is created. +// The Webhook event name is "commit_comment". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#commitcommentevent +type CommitCommentEvent struct { + Comment *RepositoryComment `json:"comment,omitempty"` + + // The following fields are only populated by Webhook events. + Action *string `json:"action,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// CreateEvent represents a created repository, branch, or tag. +// The Webhook event name is "create". +// +// Note: webhooks will not receive this event for created repositories. +// Additionally, webhooks will not receive this event for tags if more +// than three tags are pushed at once. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#createevent +type CreateEvent struct { + Ref *string `json:"ref,omitempty"` + // RefType is the object that was created. Possible values are: "repository", "branch", "tag". + RefType *string `json:"ref_type,omitempty"` + MasterBranch *string `json:"master_branch,omitempty"` + Description *string `json:"description,omitempty"` + + // The following fields are only populated by Webhook events. + PusherType *string `json:"pusher_type,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// DeleteEvent represents a deleted branch or tag. +// The Webhook event name is "delete". +// +// Note: webhooks will not receive this event for tags if more than three tags +// are deleted at once. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#deleteevent +type DeleteEvent struct { + Ref *string `json:"ref,omitempty"` + // RefType is the object that was deleted. Possible values are: "branch", "tag". + RefType *string `json:"ref_type,omitempty"` + + // The following fields are only populated by Webhook events. + PusherType *string `json:"pusher_type,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// DeploymentEvent represents a deployment. +// The Webhook event name is "deployment". +// +// Events of this type are not visible in timelines, they are only used to trigger hooks. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#deploymentevent +type DeploymentEvent struct { + Deployment *Deployment `json:"deployment,omitempty"` + Repo *Repository `json:"repository,omitempty"` + + // The following fields are only populated by Webhook events. + Sender *User `json:"sender,omitempty"` +} + +// DeploymentStatusEvent represents a deployment status. +// The Webhook event name is "deployment_status". +// +// Events of this type are not visible in timelines, they are only used to trigger hooks. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#deploymentstatusevent +type DeploymentStatusEvent struct { + Deployment *Deployment `json:"deployment,omitempty"` + DeploymentStatus *DeploymentStatus `json:"deployment_status,omitempty"` + Repo *Repository `json:"repository,omitempty"` + + // The following fields are only populated by Webhook events. + Sender *User `json:"sender,omitempty"` +} + +// ForkEvent is triggered when a user forks a repository. +// The Webhook event name is "fork". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#forkevent +type ForkEvent struct { + // Forkee is the created repository. + Forkee *Repository `json:"forkee,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// Page represents a single Wiki page. +type Page struct { + PageName *string `json:"page_name,omitempty"` + Title *string `json:"title,omitempty"` + Summary *string `json:"summary,omitempty"` + Action *string `json:"action,omitempty"` + SHA *string `json:"sha,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` +} + +// GollumEvent is triggered when a Wiki page is created or updated. +// The Webhook event name is "gollum". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#gollumevent +type GollumEvent struct { + Pages []*Page `json:"pages,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// DEPRECATED: IssueActivityEvent represents the payload delivered by Issue webhook +// Use IssuesEvent instead. +type IssueActivityEvent struct { + Action *string `json:"action,omitempty"` + Issue *Issue `json:"issue,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// EditChange represents the changes when an issue, pull request, or comment has +// been edited. +type EditChange struct { + Title *struct { + From *string `json:"from,omitempty"` + } `json:"title,omitempty"` + Body *struct { + From *string `json:"from,omitempty"` + } `json:"body,omitempty"` +} + +// IssueCommentEvent is triggered when an issue comment is created on an issue +// or pull request. +// The Webhook event name is "issue_comment". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#issuecommentevent +type IssueCommentEvent struct { + // Action is the action that was performed on the comment. + // Possible values are: "created", "edited", "deleted". + Action *string `json:"action,omitempty"` + Issue *Issue `json:"issue,omitempty"` + Comment *IssueComment `json:"comment,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"` +} + +// IssuesEvent is triggered when an issue is assigned, unassigned, labeled, +// unlabeled, opened, closed, or reopened. +// The Webhook event name is "issues". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#issuesevent +type IssuesEvent struct { + // Action is the action that was performed. Possible values are: "assigned", + // "unassigned", "labeled", "unlabeled", "opened", "closed", "reopened", "edited". + Action *string `json:"action,omitempty"` + Issue *Issue `json:"issue,omitempty"` + Assignee *User `json:"assignee,omitempty"` + Label *Label `json:"label,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"` +} + +// MemberEvent is triggered when a user is added as a collaborator to a repository. +// The Webhook event name is "member". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#memberevent +type MemberEvent struct { + // Action is the action that was performed. Possible value is: "added". + Action *string `json:"action,omitempty"` + Member *User `json:"member,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// MembershipEvent is triggered when a user is added or removed from a team. +// The Webhook event name is "membership". +// +// Events of this type are not visible in timelines, they are only used to +// trigger organization webhooks. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#membershipevent +type MembershipEvent struct { + // Action is the action that was performed. Possible values are: "added", "removed". + Action *string `json:"action,omitempty"` + // Scope is the scope of the membership. Possible value is: "team". + Scope *string `json:"scope,omitempty"` + Member *User `json:"member,omitempty"` + Team *Team `json:"team,omitempty"` + + // The following fields are only populated by Webhook events. + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// PageBuildEvent represents an attempted build of a GitHub Pages site, whether +// successful or not. +// The Webhook event name is "page_build". +// +// This event is triggered on push to a GitHub Pages enabled branch (gh-pages +// for project pages, master for user and organization pages). +// +// Events of this type are not visible in timelines, they are only used to trigger hooks. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#pagebuildevent +type PageBuildEvent struct { + Build *PagesBuild `json:"build,omitempty"` + + // The following fields are only populated by Webhook events. + ID *int `json:"id,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// PublicEvent is triggered when a private repository is open sourced. +// According to GitHub: "Without a doubt: the best GitHub event." +// The Webhook event name is "public". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#publicevent +type PublicEvent struct { + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// PullRequestEvent is triggered when a pull request is assigned, unassigned, +// labeled, unlabeled, opened, closed, reopened, or synchronized. +// The Webhook event name is "pull_request". +// +// GitHub 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, + // 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"` + 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"` +} + +// PullRequestReviewCommentEvent is triggered when a comment is created on a +// portion of the unified diff of a pull request. +// The Webhook event name is "pull_request_review_comment". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewcommentevent +type PullRequestReviewCommentEvent struct { + // Action is the action that was performed on the comment. + // Possible values are: "created", "edited", "deleted". + Action *string `json:"action,omitempty"` + PullRequest *PullRequest `json:"pull_request,omitempty"` + Comment *PullRequestComment `json:"comment,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"` +} + +// PushEvent represents a git push to a GitHub repository. +// +// GitHub API docs: http://developer.github.com/v3/activity/events/types/#pushevent +type PushEvent struct { + PushID *int `json:"push_id,omitempty"` + Head *string `json:"head,omitempty"` + Ref *string `json:"ref,omitempty"` + Size *int `json:"size,omitempty"` + Commits []PushEventCommit `json:"commits,omitempty"` + Repo *PushEventRepository `json:"repository,omitempty"` + Before *string `json:"before,omitempty"` + DistinctSize *int `json:"distinct_size,omitempty"` + + // The following fields are only populated by Webhook events. + After *string `json:"after,omitempty"` + Created *bool `json:"created,omitempty"` + Deleted *bool `json:"deleted,omitempty"` + Forced *bool `json:"forced,omitempty"` + BaseRef *string `json:"base_ref,omitempty"` + Compare *string `json:"compare,omitempty"` + HeadCommit *PushEventCommit `json:"head_commit,omitempty"` + Pusher *User `json:"pusher,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +func (p PushEvent) String() string { + return Stringify(p) +} + +// PushEventCommit represents a git commit in a GitHub PushEvent. +type PushEventCommit struct { + SHA *string `json:"sha,omitempty"` + Message *string `json:"message,omitempty"` + Author *CommitAuthor `json:"author,omitempty"` + Committer *CommitAuthor `json:"committer,omitempty"` + URL *string `json:"url,omitempty"` + Distinct *bool `json:"distinct,omitempty"` + Added []string `json:"added,omitempty"` + Removed []string `json:"removed,omitempty"` + Modified []string `json:"modified,omitempty"` +} + +func (p PushEventCommit) String() string { + return Stringify(p) +} + +// 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"` + + // The following fields are only populated by Webhook events. + URL *string `json:"url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` +} + +// PushEventRepoOwner is a basic reporesntation of user/org in a PushEvent payload +type PushEventRepoOwner struct { + Name *string `json:"name,omitempty"` + Email *string `json:"email,omitempty"` +} + +// ReleaseEvent is triggered when a release is published. +// The Webhook event name is "release". +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#releaseevent +type ReleaseEvent struct { + // Action is the action that was performed. Possible value is: "published". + Action *string `json:"action,omitempty"` + Release *RepositoryRelease `json:"release,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// RepositoryEvent is triggered when a repository is created. +// The Webhook event name is "repository". +// +// Events of this type are not visible in timelines, they are only used to +// trigger organization webhooks. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#repositoryevent +type RepositoryEvent struct { + // Action is the action that was performed. Possible values are: "created", "deleted", + // "publicized", "privatized". + Action *string `json:"action,omitempty"` + Repo *Repository `json:"repository,omitempty"` + + // The following fields are only populated by Webhook events. + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// StatusEvent is triggered when the status of a Git commit changes. +// The Webhook event name is "status". +// +// Events of this type are not visible in timelines, they are only used to +// trigger hooks. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#statusevent +type StatusEvent struct { + SHA *string `json:"sha,omitempty"` + // State is the new state. Possible values are: "pending", "success", "failure", "error". + State *string `json:"state,omitempty"` + Description *string `json:"description,omitempty"` + TargetURL *string `json:"target_url,omitempty"` + Branches []*Branch `json:"branches,omitempty"` + + // The following fields are only populated by Webhook events. + ID *int `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Context *string `json:"context,omitempty"` + Commit *PushEventCommit `json:"commit,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + UpdatedAt *Timestamp `json:"updated_at,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// TeamAddEvent is triggered when a repository is added to a team. +// The Webhook event name is "team_add". +// +// Events of this type are not visible in timelines. These events are only used +// to trigger hooks. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#teamaddevent +type TeamAddEvent struct { + Team *Team `json:"team,omitempty"` + Repo *Repository `json:"repository,omitempty"` + + // The following fields are only populated by Webhook events. + Org *Organization `json:"organization,omitempty"` + Sender *User `json:"sender,omitempty"` +} + +// WatchEvent is related to starring a repository, not watching. See this API +// blog post for an explanation: https://developer.github.com/changes/2012-09-05-watcher-api/ +// +// The event’s actor is the user who starred a repository, and the event’s +// repository is the repository that was starred. +// +// GitHub docs: https://developer.github.com/v3/activity/events/types/#watchevent +type WatchEvent struct { + // Action is the action that was performed. Possible value is: "started". + Action *string `json:"action,omitempty"` + + // The following fields are only populated by Webhook events. + Repo *Repository `json:"repository,omitempty"` + Sender *User `json:"sender,omitempty"` +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/gists.go b/Godeps/_workspace/src/github.com/google/go-github/github/gists.go index a662d35..d4771b8 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/gists.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/gists.go @@ -67,7 +67,7 @@ type GistListOptions struct { // user. // // GitHub API docs: http://developer.github.com/v3/gists/#list-gists -func (s *GistsService) List(user string, opt *GistListOptions) ([]Gist, *Response, error) { +func (s *GistsService) List(user string, opt *GistListOptions) ([]*Gist, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/gists", user) @@ -84,7 +84,7 @@ func (s *GistsService) List(user string, opt *GistListOptions) ([]Gist, *Respons return nil, nil, err } - gists := new([]Gist) + gists := new([]*Gist) resp, err := s.client.Do(req, gists) if err != nil { return nil, resp, err @@ -96,7 +96,7 @@ func (s *GistsService) List(user string, opt *GistListOptions) ([]Gist, *Respons // ListAll lists all public gists. // // GitHub API docs: http://developer.github.com/v3/gists/#list-gists -func (s *GistsService) ListAll(opt *GistListOptions) ([]Gist, *Response, error) { +func (s *GistsService) ListAll(opt *GistListOptions) ([]*Gist, *Response, error) { u, err := addOptions("gists/public", opt) if err != nil { return nil, nil, err @@ -107,7 +107,7 @@ func (s *GistsService) ListAll(opt *GistListOptions) ([]Gist, *Response, error) return nil, nil, err } - gists := new([]Gist) + gists := new([]*Gist) resp, err := s.client.Do(req, gists) if err != nil { return nil, resp, err @@ -119,7 +119,7 @@ func (s *GistsService) ListAll(opt *GistListOptions) ([]Gist, *Response, error) // ListStarred lists starred gists of authenticated user. // // GitHub API docs: http://developer.github.com/v3/gists/#list-gists -func (s *GistsService) ListStarred(opt *GistListOptions) ([]Gist, *Response, error) { +func (s *GistsService) ListStarred(opt *GistListOptions) ([]*Gist, *Response, error) { u, err := addOptions("gists/starred", opt) if err != nil { return nil, nil, err @@ -130,7 +130,7 @@ func (s *GistsService) ListStarred(opt *GistListOptions) ([]Gist, *Response, err return nil, nil, err } - gists := new([]Gist) + gists := new([]*Gist) resp, err := s.client.Do(req, gists) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/gists_comments.go b/Godeps/_workspace/src/github.com/google/go-github/github/gists_comments.go index c5c21bd..95a7fc7 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/gists_comments.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/gists_comments.go @@ -26,7 +26,7 @@ func (g GistComment) String() string { // ListComments lists all comments for a gist. // // GitHub API docs: http://developer.github.com/v3/gists/comments/#list-comments-on-a-gist -func (s *GistsService) ListComments(gistID string, opt *ListOptions) ([]GistComment, *Response, error) { +func (s *GistsService) ListComments(gistID string, opt *ListOptions) ([]*GistComment, *Response, error) { u := fmt.Sprintf("gists/%v/comments", gistID) u, err := addOptions(u, opt) if err != nil { @@ -38,7 +38,7 @@ func (s *GistsService) ListComments(gistID string, opt *ListOptions) ([]GistComm return nil, nil, err } - comments := new([]GistComment) + comments := new([]*GistComment) resp, err := s.client.Do(req, comments) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/git_commits.go b/Godeps/_workspace/src/github.com/google/go-github/github/git_commits.go index 6584b77..0bcad41 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/git_commits.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/git_commits.go @@ -10,16 +10,25 @@ import ( "time" ) +// SignatureVerification represents GPG signature verification. +type SignatureVerification struct { + Verified *bool `json:"verified,omitempty"` + Reason *string `json:"reason,omitempty"` + Signature *string `json:"signature,omitempty"` + Payload *string `json:"payload,omitempty"` +} + // Commit represents a GitHub commit. type Commit struct { - SHA *string `json:"sha,omitempty"` - Author *CommitAuthor `json:"author,omitempty"` - Committer *CommitAuthor `json:"committer,omitempty"` - Message *string `json:"message,omitempty"` - Tree *Tree `json:"tree,omitempty"` - Parents []Commit `json:"parents,omitempty"` - Stats *CommitStats `json:"stats,omitempty"` - URL *string `json:"url,omitempty"` + SHA *string `json:"sha,omitempty"` + Author *CommitAuthor `json:"author,omitempty"` + Committer *CommitAuthor `json:"committer,omitempty"` + Message *string `json:"message,omitempty"` + Tree *Tree `json:"tree,omitempty"` + Parents []Commit `json:"parents,omitempty"` + Stats *CommitStats `json:"stats,omitempty"` + URL *string `json:"url,omitempty"` + Verification *SignatureVerification `json:"verification,omitempty"` // CommentCount is the number of GitHub comments on the commit. This // is only populated for requests that fetch GitHub data like @@ -37,6 +46,9 @@ type CommitAuthor struct { Date *time.Time `json:"date,omitempty"` Name *string `json:"name,omitempty"` Email *string `json:"email,omitempty"` + + // The following fields are only populated by Webhook events. + Login *string `json:"username,omitempty"` // Renamed for go-github consistency. } func (c CommitAuthor) String() string { @@ -53,6 +65,9 @@ func (s *GitService) GetCommit(owner string, repo string, sha string) (*Commit, return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeGitSigningPreview) + c := new(Commit) resp, err := s.client.Do(req, c) if err != nil { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/git_refs.go b/Godeps/_workspace/src/github.com/google/go-github/github/git_refs.go index 3d2f6c8..16cbd6b 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/git_refs.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/git_refs.go @@ -75,7 +75,7 @@ type ReferenceListOptions struct { // ListRefs lists all refs in a repository. // // GitHub API docs: http://developer.github.com/v3/git/refs/#get-all-references -func (s *GitService) ListRefs(owner, repo string, opt *ReferenceListOptions) ([]Reference, *Response, error) { +func (s *GitService) ListRefs(owner, repo string, opt *ReferenceListOptions) ([]*Reference, *Response, error) { var u string if opt != nil && opt.Type != "" { u = fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, opt.Type) @@ -92,7 +92,7 @@ func (s *GitService) ListRefs(owner, repo string, opt *ReferenceListOptions) ([] return nil, nil, err } - var rs []Reference + var rs []*Reference resp, err := s.client.Do(req, &rs) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/git_tags.go b/Godeps/_workspace/src/github.com/google/go-github/github/git_tags.go index 7b53f5c..01b9cb2 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/git_tags.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/git_tags.go @@ -11,12 +11,13 @@ import ( // Tag represents a tag object. type Tag struct { - Tag *string `json:"tag,omitempty"` - SHA *string `json:"sha,omitempty"` - URL *string `json:"url,omitempty"` - Message *string `json:"message,omitempty"` - Tagger *CommitAuthor `json:"tagger,omitempty"` - Object *GitObject `json:"object,omitempty"` + Tag *string `json:"tag,omitempty"` + SHA *string `json:"sha,omitempty"` + URL *string `json:"url,omitempty"` + Message *string `json:"message,omitempty"` + Tagger *CommitAuthor `json:"tagger,omitempty"` + Object *GitObject `json:"object,omitempty"` + Verification *SignatureVerification `json:"verification,omitempty"` } // createTagRequest represents the body of a CreateTag request. This is mostly @@ -40,6 +41,9 @@ func (s *GitService) GetTag(owner string, repo string, sha string) (*Tag, *Respo return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeGitSigningPreview) + tag := new(Tag) resp, err := s.client.Do(req, tag) return tag, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/github.go b/Godeps/_workspace/src/github.com/google/go-github/github/github.go index f9f27e2..8b19960 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/github.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/github.go @@ -29,7 +29,7 @@ const ( ) const ( - libraryVersion = "0.1" + libraryVersion = "2" defaultBaseURL = "https://api.github.com/" uploadBaseURL = "https://uploads.github.com/" userAgent = "go-github/" + libraryVersion @@ -39,8 +39,10 @@ const ( headerRateReset = "X-RateLimit-Reset" headerOTP = "X-GitHub-OTP" - mediaTypeV3 = "application/vnd.github.v3+json" - defaultMediaType = "application/octet-stream" + mediaTypeV3 = "application/vnd.github.v3+json" + defaultMediaType = "application/octet-stream" + mediaTypeV3SHA = "application/vnd.github.v3.sha" + mediaTypeOrgPermissionRepo = "application/vnd.github.v3.repository+json" // Media Type values to access preview APIs @@ -50,18 +52,46 @@ const ( // https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/ mediaTypeStarringPreview = "application/vnd.github.v3.star+json" - // https://developer.github.com/changes/2015-06-24-api-enhancements-for-working-with-organization-permissions/ - mediaTypeOrgPermissionPreview = "application/vnd.github.ironman-preview+json" - mediaTypeOrgPermissionRepoPreview = "application/vnd.github.ironman-preview.repository+json" - // https://developer.github.com/changes/2015-11-11-protected-branches-api/ mediaTypeProtectedBranchesPreview = "application/vnd.github.loki-preview+json" + + // https://developer.github.com/changes/2016-02-11-issue-locking-api/ + mediaTypeIssueLockingPreview = "application/vnd.github.the-key-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/2016-02-19-source-import-preview-api/ + mediaTypeImportPreview = "application/vnd.github.barred-rock-preview" + + // https://developer.github.com/changes/2016-05-12-reactions-api-preview/ + mediaTypeReactionsPreview = "application/vnd.github.squirrel-girl-preview" + + // https://developer.github.com/changes/2016-04-01-squash-api-preview/ + mediaTypeSquashPreview = "application/vnd.github.polaris-preview+json" + + // https://developer.github.com/changes/2016-04-04-git-signing-api-preview/ + mediaTypeGitSigningPreview = "application/vnd.github.cryptographer-preview+json" + + // https://developer.github.com/changes/2016-5-27-multiple-assignees/ + mediaTypeMultipleAssigneesPreview = "application/vnd.github.cerberus-preview+json" + + // https://developer.github.com/changes/2016-05-23-timeline-preview-api/ + mediaTypeTimelinePreview = "application/vnd.github.mockingbird-preview+json" + + // https://developer.github.com/changes/2016-06-14-repository-invitations/ + mediaTypeRepositoryInvitationsPreview = "application/vnd.github.swamp-thing-preview+json" ) // A Client manages communication with the GitHub API. type Client struct { // HTTP client used to communicate with the API. client *http.Client + // clientMu protects the client during calls that modify the CheckRedirect func. + clientMu sync.Mutex // Base URL for API requests. Defaults to the public GitHub API, but can be // set to a domain endpoint to use with GitHub Enterprise. BaseURL should @@ -74,21 +104,25 @@ type Client struct { // User agent used when communicating with the GitHub API. UserAgent string - rateMu sync.Mutex - rate Rate // Rate limit for the client as determined by the most recent API call. + rateMu sync.Mutex + rateLimits [categories]Rate // Rate limits for the client as determined by the most recent API calls. + mostRecent rateLimitCategory // Services used for talking to different parts of the GitHub API. - Activity *ActivityService - Gists *GistsService - Git *GitService - Gitignores *GitignoresService - Issues *IssuesService - Organizations *OrganizationsService - PullRequests *PullRequestsService - Repositories *RepositoriesService - Search *SearchService - Users *UsersService - Licenses *LicensesService + Activity *ActivityService + Authorizations *AuthorizationsService + Gists *GistsService + Git *GitService + Gitignores *GitignoresService + Issues *IssuesService + Organizations *OrganizationsService + PullRequests *PullRequestsService + Repositories *RepositoriesService + Search *SearchService + Users *UsersService + Licenses *LicensesService + Migrations *MigrationService + Reactions *ReactionsService } // ListOptions specifies the optional parameters to various List methods that @@ -141,6 +175,7 @@ func NewClient(httpClient *http.Client) *Client { c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent, UploadURL: uploadURL} c.Activity = &ActivityService{client: c} + c.Authorizations = &AuthorizationsService{client: c} c.Gists = &GistsService{client: c} c.Git = &GitService{client: c} c.Gitignores = &GitignoresService{client: c} @@ -151,6 +186,8 @@ func NewClient(httpClient *http.Client) *Client { c.Search = &SearchService{client: c} c.Users = &UsersService{client: c} c.Licenses = &LicensesService{client: c} + c.Migrations = &MigrationService{client: c} + c.Reactions = &ReactionsService{client: c} return c } @@ -303,11 +340,13 @@ func parseRate(r *http.Response) Rate { // Rate specifies the current rate limit for the client as determined by the // most recent API call. If the client is used in a multi-user application, -// this rate may not always be up-to-date. Call RateLimits() to check the -// current rate. +// this rate may not always be up-to-date. +// +// Deprecated: Use the Response.Rate returned from most recent API call instead. +// Call RateLimits() to check the current rate. func (c *Client) Rate() Rate { c.rateMu.Lock() - rate := c.rate + rate := c.rateLimits[c.mostRecent] c.rateMu.Unlock() return rate } @@ -316,19 +355,32 @@ func (c *Client) Rate() Rate { // JSON decoded and stored in the value pointed to by v, or returned as an // error if an API error has occurred. If v implements the io.Writer // interface, the raw response body will be written to v, without attempting to -// first decode it. +// first decode it. If rate limit is exceeded and reset time is in the future, +// Do returns *RateLimitError immediately without making a network API call. func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { + rateLimitCategory := category(req.URL.Path) + + // If we've hit rate limit, don't make further requests before Reset time. + if err := c.checkRateLimitBeforeDo(req, rateLimitCategory); err != nil { + return nil, err + } + resp, err := c.client.Do(req) if err != nil { return nil, err } - defer resp.Body.Close() + 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() + }() response := newResponse(resp) c.rateMu.Lock() - c.rate = response.Rate + c.rateLimits[rateLimitCategory] = response.Rate + c.mostRecent = rateLimitCategory c.rateMu.Unlock() err = CheckResponse(resp) @@ -348,9 +400,37 @@ func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) { } } } + return response, err } +// checkRateLimitBeforeDo does not make any network calls, but uses existing knowledge from +// current client state in order to quickly check if *RateLimitError can be immediately returned +// from Client.Do, and if so, returns it so that Client.Do can skip making a network API call unneccessarily. +// Otherwise it returns nil, and Client.Do should proceed normally. +func (c *Client) checkRateLimitBeforeDo(req *http.Request, rateLimitCategory rateLimitCategory) error { + c.rateMu.Lock() + rate := c.rateLimits[rateLimitCategory] + c.rateMu.Unlock() + if !rate.Reset.Time.IsZero() && rate.Remaining == 0 && time.Now().Before(rate.Reset.Time) { + // Create a fake response. + resp := &http.Response{ + Status: http.StatusText(http.StatusForbidden), + StatusCode: http.StatusForbidden, + Request: req, + Header: make(http.Header), + Body: ioutil.NopCloser(strings.NewReader("")), + } + return &RateLimitError{ + Rate: rate, + Response: resp, + Message: fmt.Sprintf("API rate limit of %v still exceeded until %v, not making remote request.", rate.Limit, rate.Reset.Time), + } + } + + return nil +} + /* An ErrorResponse reports one or more errors caused by an API request. @@ -360,6 +440,17 @@ type ErrorResponse struct { Response *http.Response // HTTP response that caused this error Message string `json:"message"` // error message Errors []Error `json:"errors"` // more detail on individual errors + // Block is only populated on certain types of errors such as code 451. + // See https://developer.github.com/changes/2016-03-17-the-451-status-code-is-now-supported/ + // for more information. + Block *struct { + Reason string `json:"reason,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + } `json:"block,omitempty"` + // Most errors will also include a documentation_url field pointing + // to some content that might help you resolve the error, see + // https://developer.github.com/v3/#client-errors + DocumentationURL string `json:"documentation_url,omitempty"` } func (r *ErrorResponse) Error() string { @@ -415,6 +506,9 @@ These are the possible validation error codes: the formatting of a field is invalid already_exists: another resource has the same valid as this field + custom: + some resources return this (e.g. github.User.CreateKey()), additional + information is set in the Message field of the Error GitHub API docs: http://developer.github.com/v3/#client-errors */ @@ -422,6 +516,7 @@ type Error struct { Resource string `json:"resource"` // resource on which the error occurred Field string `json:"field"` // field on which the error occurred Code string `json:"code"` // validation error code + Message string `json:"message"` // Message describing the error. Errors with Code == "custom" will always have this set. } func (e *Error) Error() string { @@ -500,6 +595,8 @@ type RateLimits struct { // The rate limit for non-search API requests. Unauthenticated // requests are limited to 60 per hour. Authenticated requests are // limited to 5,000 per hour. + // + // GitHub API docs: https://developer.github.com/v3/#rate-limiting Core *Rate `json:"core"` // The rate limit for search API requests. Unauthenticated requests @@ -514,6 +611,25 @@ func (r RateLimits) String() string { return Stringify(r) } +type rateLimitCategory uint8 + +const ( + coreCategory rateLimitCategory = iota + searchCategory + + categories // An array of this length will be able to contain all rate limit categories. +) + +// category returns the rate limit category of the endpoint, determined by Request.URL.Path. +func category(path string) rateLimitCategory { + switch { + default: + return coreCategory + case strings.HasPrefix(path, "/search/"): + return searchCategory + } +} + // Deprecated: RateLimit is deprecated, use RateLimits instead. func (c *Client) RateLimit() (*Rate, *Response, error) { limits, resp, err := c.RateLimits() @@ -539,6 +655,17 @@ func (c *Client) RateLimits() (*RateLimits, *Response, error) { return nil, nil, err } + if response.Resources != nil { + c.rateMu.Lock() + if response.Resources.Core != nil { + c.rateLimits[coreCategory] = *response.Resources.Core + } + if response.Resources.Search != nil { + c.rateLimits[searchCategory] = *response.Resources.Search + } + c.rateMu.Unlock() + } + return response.Resources, resp, err } @@ -661,25 +788,12 @@ func cloneRequest(r *http.Request) *http.Request { // Bool is a helper routine that allocates a new bool value // to store v and returns a pointer to it. -func Bool(v bool) *bool { - p := new(bool) - *p = v - return p -} +func Bool(v bool) *bool { return &v } -// Int is a helper routine that allocates a new int32 value -// to store v and returns a pointer to it, but unlike Int32 -// its argument value is an int. -func Int(v int) *int { - p := new(int) - *p = v - return p -} +// Int is a helper routine that allocates a new int value +// to store v and returns a pointer to it. +func Int(v int) *int { 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 { - p := new(string) - *p = v - return p -} +func String(v string) *string { return &v } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues.go index a60cede..a8c82db 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues.go @@ -35,6 +35,9 @@ type Issue struct { HTMLURL *string `json:"html_url,omitempty"` Milestone *Milestone `json:"milestone,omitempty"` PullRequestLinks *PullRequestLinks `json:"pull_request,omitempty"` + Repository *Repository `json:"repository,omitempty"` + Reactions *Reactions `json:"reactions,omitempty"` + Assignees []*User `json:"assignees,omitempty"` // TextMatches is only populated from search results that request text matches // See: search.go and https://developer.github.com/v3/search/#text-match-metadata @@ -55,6 +58,7 @@ type IssueRequest struct { Assignee *string `json:"assignee,omitempty"` State *string `json:"state,omitempty"` Milestone *int `json:"milestone,omitempty"` + Assignees *[]string `json:"assignees,omitempty"` } // IssueListOptions specifies the optional parameters to the IssuesService.List @@ -100,7 +104,7 @@ type PullRequestLinks struct { // repositories. // // GitHub API docs: http://developer.github.com/v3/issues/#list-issues -func (s *IssuesService) List(all bool, opt *IssueListOptions) ([]Issue, *Response, error) { +func (s *IssuesService) List(all bool, opt *IssueListOptions) ([]*Issue, *Response, error) { var u string if all { u = "issues" @@ -114,12 +118,12 @@ func (s *IssuesService) List(all bool, opt *IssueListOptions) ([]Issue, *Respons // authenticated user. // // GitHub API docs: http://developer.github.com/v3/issues/#list-issues -func (s *IssuesService) ListByOrg(org string, opt *IssueListOptions) ([]Issue, *Response, error) { +func (s *IssuesService) ListByOrg(org string, opt *IssueListOptions) ([]*Issue, *Response, error) { u := fmt.Sprintf("orgs/%v/issues", org) return s.listIssues(u, opt) } -func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]Issue, *Response, error) { +func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]*Issue, *Response, error) { u, err := addOptions(u, opt) if err != nil { return nil, nil, err @@ -130,7 +134,10 @@ func (s *IssuesService) listIssues(u string, opt *IssueListOptions) ([]Issue, *R return nil, nil, err } - issues := new([]Issue) + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + issues := new([]*Issue) resp, err := s.client.Do(req, issues) if err != nil { return nil, resp, err @@ -182,7 +189,7 @@ type IssueListByRepoOptions struct { // ListByRepo lists the issues for the specified repository. // // GitHub API docs: http://developer.github.com/v3/issues/#list-issues-for-a-repository -func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRepoOptions) ([]Issue, *Response, error) { +func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRepoOptions) ([]*Issue, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -194,7 +201,10 @@ func (s *IssuesService) ListByRepo(owner string, repo string, opt *IssueListByRe return nil, nil, err } - issues := new([]Issue) + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + issues := new([]*Issue) resp, err := s.client.Do(req, issues) if err != nil { return nil, resp, err @@ -213,6 +223,9 @@ func (s *IssuesService) Get(owner string, repo string, number int) (*Issue, *Res return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + issue := new(Issue) resp, err := s.client.Do(req, issue) if err != nil { @@ -232,6 +245,9 @@ func (s *IssuesService) Create(owner string, repo string, issue *IssueRequest) ( return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview) + i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { @@ -251,6 +267,9 @@ func (s *IssuesService) Edit(owner string, repo string, number int, issue *Issue return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview) + i := new(Issue) resp, err := s.client.Do(req, i) if err != nil { @@ -259,3 +278,35 @@ func (s *IssuesService) Edit(owner string, repo string, number int, issue *Issue return i, resp, err } + +// Lock an issue's conversation. +// +// GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue +func (s *IssuesService) Lock(owner string, repo string, number int) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) + req, err := s.client.NewRequest("PUT", u, nil) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeIssueLockingPreview) + + return s.client.Do(req, nil) +} + +// Unlock an issue's conversation. +// +// GitHub API docs: https://developer.github.com/v3/issues/#unlock-an-issue +func (s *IssuesService) Unlock(owner string, repo string, number int) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) + 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", mediaTypeIssueLockingPreview) + + return s.client.Do(req, nil) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues_assignees.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues_assignees.go index 6338c22..4b7bba2 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues_assignees.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues_assignees.go @@ -11,7 +11,7 @@ import "fmt" // which issues may be assigned. // // GitHub API docs: http://developer.github.com/v3/issues/assignees/#list-assignees -func (s *IssuesService) ListAssignees(owner string, repo string, opt *ListOptions) ([]User, *Response, error) { +func (s *IssuesService) ListAssignees(owner, repo string, opt *ListOptions) ([]*User, *Response, error) { u := fmt.Sprintf("repos/%v/%v/assignees", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -22,7 +22,7 @@ func (s *IssuesService) ListAssignees(owner string, repo string, opt *ListOption if err != nil { return nil, nil, err } - assignees := new([]User) + assignees := new([]*User) resp, err := s.client.Do(req, assignees) if err != nil { return nil, resp, err @@ -34,7 +34,7 @@ func (s *IssuesService) ListAssignees(owner string, repo string, opt *ListOption // IsAssignee checks if a user is an assignee for the specified repository. // // GitHub API docs: http://developer.github.com/v3/issues/assignees/#check-assignee -func (s *IssuesService) IsAssignee(owner string, repo string, user string) (bool, *Response, error) { +func (s *IssuesService) IsAssignee(owner, repo, user string) (bool, *Response, error) { u := fmt.Sprintf("repos/%v/%v/assignees/%v", owner, repo, user) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -44,3 +44,45 @@ func (s *IssuesService) IsAssignee(owner string, repo string, user string) (bool assignee, err := parseBoolResponse(err) return assignee, resp, err } + +// AddAssignees adds the provided GitHub users as assignees to the issue. +// +// GitHub API docs: https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue +func (s *IssuesService) AddAssignees(owner, repo string, number int, assignees []string) (*Issue, *Response, error) { + users := &struct { + Assignees []string `json:"assignees,omitempty"` + }{Assignees: assignees} + u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number) + req, err := s.client.NewRequest("POST", u, users) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview) + + issue := &Issue{} + resp, err := s.client.Do(req, issue) + return issue, resp, err +} + +// RemoveAssignees removes the provided GitHub users as assignees from the issue. +// +// GitHub API docs: https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue +func (s *IssuesService) RemoveAssignees(owner, repo string, number int, assignees []string) (*Issue, *Response, error) { + users := &struct { + Assignees []string `json:"assignees,omitempty"` + }{Assignees: assignees} + u := fmt.Sprintf("repos/%v/%v/issues/%v/assignees", owner, repo, number) + req, err := s.client.NewRequest("DELETE", u, users) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeMultipleAssigneesPreview) + + issue := &Issue{} + resp, err := s.client.Do(req, issue) + return issue, resp, err +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues_comments.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues_comments.go index db48e14..b24c5ae 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues_comments.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues_comments.go @@ -15,6 +15,7 @@ type IssueComment struct { ID *int `json:"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"` @@ -45,7 +46,7 @@ type IssueListCommentsOptions struct { // number of 0 will return all comments on all issues for the repository. // // GitHub API docs: http://developer.github.com/v3/issues/comments/#list-comments-on-an-issue -func (s *IssuesService) ListComments(owner string, repo string, number int, opt *IssueListCommentsOptions) ([]IssueComment, *Response, error) { +func (s *IssuesService) ListComments(owner string, repo string, number int, opt *IssueListCommentsOptions) ([]*IssueComment, *Response, error) { var u string if number == 0 { u = fmt.Sprintf("repos/%v/%v/issues/comments", owner, repo) @@ -61,7 +62,11 @@ func (s *IssuesService) ListComments(owner string, repo string, number int, opt if err != nil { return nil, nil, err } - comments := new([]IssueComment) + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + comments := new([]*IssueComment) resp, err := s.client.Do(req, comments) if err != nil { return nil, resp, err @@ -80,6 +85,10 @@ func (s *IssuesService) GetComment(owner string, repo string, id int) (*IssueCom if err != nil { return nil, nil, err } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comment := new(IssueComment) resp, err := s.client.Do(req, comment) if err != nil { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go index 9062d4d..71cf61a 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues_events.go @@ -73,7 +73,7 @@ type IssueEvent struct { // ListIssueEvents lists events for the specified issue. // // GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-an-issue -func (s *IssuesService) ListIssueEvents(owner, repo string, number int, opt *ListOptions) ([]IssueEvent, *Response, error) { +func (s *IssuesService) ListIssueEvents(owner, repo string, number int, opt *ListOptions) ([]*IssueEvent, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%v/events", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -85,7 +85,7 @@ func (s *IssuesService) ListIssueEvents(owner, repo string, number int, opt *Lis return nil, nil, err } - var events []IssueEvent + var events []*IssueEvent resp, err := s.client.Do(req, &events) if err != nil { return nil, resp, err @@ -97,7 +97,7 @@ func (s *IssuesService) ListIssueEvents(owner, repo string, number int, opt *Lis // ListRepositoryEvents lists events for the specified repository. // // GitHub API docs: https://developer.github.com/v3/issues/events/#list-events-for-a-repository -func (s *IssuesService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]IssueEvent, *Response, error) { +func (s *IssuesService) ListRepositoryEvents(owner, repo string, opt *ListOptions) ([]*IssueEvent, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/events", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -109,7 +109,7 @@ func (s *IssuesService) ListRepositoryEvents(owner, repo string, opt *ListOption return nil, nil, err } - var events []IssueEvent + var events []*IssueEvent resp, err := s.client.Do(req, &events) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues_labels.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues_labels.go index 88f9f3f..c654547 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues_labels.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues_labels.go @@ -21,7 +21,7 @@ func (l Label) String() string { // ListLabels lists all labels for a repository. // // GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) ListLabels(owner string, repo string, opt *ListOptions) ([]Label, *Response, error) { +func (s *IssuesService) ListLabels(owner string, repo string, opt *ListOptions) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -33,7 +33,7 @@ func (s *IssuesService) ListLabels(owner string, repo string, opt *ListOptions) return nil, nil, err } - labels := new([]Label) + labels := new([]*Label) resp, err := s.client.Do(req, labels) if err != nil { return nil, resp, err @@ -114,7 +114,7 @@ func (s *IssuesService) DeleteLabel(owner string, repo string, name string) (*Re // ListLabelsByIssue lists all labels for an issue. // // GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) ListLabelsByIssue(owner string, repo string, number int, opt *ListOptions) ([]Label, *Response, error) { +func (s *IssuesService) ListLabelsByIssue(owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -126,7 +126,7 @@ func (s *IssuesService) ListLabelsByIssue(owner string, repo string, number int, return nil, nil, err } - labels := new([]Label) + labels := new([]*Label) resp, err := s.client.Do(req, labels) if err != nil { return nil, resp, err @@ -138,14 +138,14 @@ func (s *IssuesService) ListLabelsByIssue(owner string, repo string, number int, // AddLabelsToIssue adds labels to an issue. // // GitHub API docs: http://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository -func (s *IssuesService) AddLabelsToIssue(owner string, repo string, number int, labels []string) ([]Label, *Response, error) { +func (s *IssuesService) AddLabelsToIssue(owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) req, err := s.client.NewRequest("POST", u, labels) if err != nil { return nil, nil, err } - l := new([]Label) + l := new([]*Label) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err @@ -169,14 +169,14 @@ func (s *IssuesService) RemoveLabelForIssue(owner string, repo string, number in // ReplaceLabelsForIssue replaces all labels for an issue. // // GitHub API docs: http://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue -func (s *IssuesService) ReplaceLabelsForIssue(owner string, repo string, number int, labels []string) ([]Label, *Response, error) { +func (s *IssuesService) ReplaceLabelsForIssue(owner string, repo string, number int, labels []string) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", owner, repo, number) req, err := s.client.NewRequest("PUT", u, labels) if err != nil { return nil, nil, err } - l := new([]Label) + l := new([]*Label) resp, err := s.client.Do(req, l) if err != nil { return nil, resp, err @@ -200,7 +200,7 @@ func (s *IssuesService) RemoveLabelsForIssue(owner string, repo string, number i // ListLabelsForMilestone lists labels for every issue in a milestone. // // GitHub API docs: http://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone -func (s *IssuesService) ListLabelsForMilestone(owner string, repo string, number int, opt *ListOptions) ([]Label, *Response, error) { +func (s *IssuesService) ListLabelsForMilestone(owner string, repo string, number int, opt *ListOptions) ([]*Label, *Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones/%d/labels", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -212,7 +212,7 @@ func (s *IssuesService) ListLabelsForMilestone(owner string, repo string, number return nil, nil, err } - labels := new([]Label) + labels := new([]*Label) resp, err := s.client.Do(req, labels) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues_milestones.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues_milestones.go index cbd7920..b7621ac 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/issues_milestones.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues_milestones.go @@ -13,6 +13,9 @@ import ( // Milestone represents a Github repository milestone. 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"` Number *int `json:"number,omitempty"` State *string `json:"state,omitempty"` Title *string `json:"title,omitempty"` @@ -22,6 +25,7 @@ type Milestone struct { ClosedIssues *int `json:"closed_issues,omitempty"` CreatedAt *time.Time `json:"created_at,omitempty"` UpdatedAt *time.Time `json:"updated_at,omitempty"` + ClosedAt *time.Time `json:"closed_at,omitempty"` DueOn *time.Time `json:"due_on,omitempty"` } @@ -43,12 +47,14 @@ type MilestoneListOptions struct { // Direction in which to sort milestones. Possible values are: asc, desc. // Default is "asc". Direction string `url:"direction,omitempty"` + + ListOptions } // ListMilestones lists all milestones for a repository. // // GitHub API docs: https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository -func (s *IssuesService) ListMilestones(owner string, repo string, opt *MilestoneListOptions) ([]Milestone, *Response, error) { +func (s *IssuesService) ListMilestones(owner string, repo string, opt *MilestoneListOptions) ([]*Milestone, *Response, error) { u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -60,7 +66,7 @@ func (s *IssuesService) ListMilestones(owner string, repo string, opt *Milestone return nil, nil, err } - milestones := new([]Milestone) + milestones := new([]*Milestone) resp, err := s.client.Do(req, milestones) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/issues_timeline.go b/Godeps/_workspace/src/github.com/google/go-github/github/issues_timeline.go new file mode 100644 index 0000000..d20eef8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/issues_timeline.go @@ -0,0 +1,148 @@ +// Copyright 2016 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "fmt" + "time" +) + +// Timeline represents an event that occurred around an Issue or Pull Request. +// +// 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"` + URL *string `json:"url,omitempty"` + CommitURL *string `json:"commit_url,omitempty"` + + // The User object that generated the event. + Actor *User `json:"actor,omitempty"` + + // Event identifies the actual type of Event that occurred. Possible values + // are: + // + // assigned + // The issue was assigned to the assignee. + // + // closed + // The issue was closed by the actor. When the commit_id is present, it + // identifies the commit that closed the issue using "closes / fixes #NN" + // syntax. + // + // commented + // A comment was added to the issue. + // + // committed + // A commit was added to the pull request's 'HEAD' branch. Only provided + // for pull requests. + // + // cross-referenced + // The issue was referenced from another issue. The 'source' attribute + // contains the 'id', 'actor', and 'url' of the reference's source. + // + // demilestoned + // The issue was removed from a milestone. + // + // head_ref_deleted + // The pull request's branch was deleted. + // + // head_ref_restored + // The pull request's branch was restored. + // + // labeled + // A label was added to the issue. + // + // locked + // The issue was locked by the actor. + // + // mentioned + // The actor was @mentioned in an issue body. + // + // merged + // The issue was merged by the actor. The 'commit_id' attribute is the + // SHA1 of the HEAD commit that was merged. + // + // milestoned + // The issue was added to a milestone. + // + // referenced + // The issue was referenced from a commit message. The 'commit_id' + // attribute is the commit SHA1 of where that happened. + // + // renamed + // The issue title was changed. + // + // reopened + // The issue was reopened by the actor. + // + // subscribed + // The actor subscribed to receive notifications for an issue. + // + // unassigned + // The assignee was unassigned from the issue. + // + // unlabeled + // A label was removed from the issue. + // + // unlocked + // The issue was unlocked by the actor. + // + // unsubscribed + // The actor unsubscribed to stop receiving notifications for an issue. + // + Event *string `json:"event,omitempty"` + + // The string SHA of a commit that referenced this Issue or Pull Request. + CommitID *string `json:"commit_id,omitempty"` + // The timestamp indicating when the event occurred. + CreatedAt *time.Time `json:"created_at,omitempty"` + // The Label object including `name` and `color` attributes. Only provided for + // 'labeled' and 'unlabeled' events. + Label *Label `json:"label,omitempty"` + // The User object which was assigned to (or unassigned from) this Issue or + // Pull Request. Only provided for 'assigned' and 'unassigned' events. + Assignee *User `json:"assignee,omitempty"` + // The Milestone object including a 'title' attribute. + // Only provided for 'milestoned' and 'demilestoned' events. + Milestone *Milestone `json:"milestone,omitempty"` + // The 'id', 'actor', and 'url' for the source of a reference from another issue. + // Only provided for 'cross-referenced' events. + Source *Source `json:"source,omitempty"` + // An object containing rename details including 'from' and 'to' attributes. + // Only provided for 'renamed' events. + Rename *Rename `json:"rename,omitempty"` +} + +// Source represents a reference's source. +type Source struct { + ID *int `json:"id,omitempty"` + URL *string `json:"url,omitempty"` + Actor *User `json:"actor,omitempty"` +} + +// ListIssueTimeline lists events for the specified issue. +// +// GitHub API docs: https://developer.github.com/v3/issues/timeline/#list-events-for-an-issue +func (s *IssuesService) ListIssueTimeline(owner, repo string, number int, opt *ListOptions) ([]*Timeline, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%v/timeline", owner, repo, number) + 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", mediaTypeTimelinePreview) + + var events []*Timeline + resp, err := s.client.Do(req, &events) + return events, resp, err +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go b/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go index fb2fb5a..93f6932 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/licenses.go @@ -39,7 +39,7 @@ func (l License) String() string { // List popular open source licenses. // // GitHub API docs: https://developer.github.com/v3/licenses/#list-all-licenses -func (s *LicensesService) List() ([]License, *Response, error) { +func (s *LicensesService) List() ([]*License, *Response, error) { req, err := s.client.NewRequest("GET", "licenses", nil) if err != nil { return nil, nil, err @@ -48,7 +48,7 @@ func (s *LicensesService) List() ([]License, *Response, error) { // TODO: remove custom Accept header when this API fully launches req.Header.Set("Accept", mediaTypeLicensesPreview) - licenses := new([]License) + licenses := new([]*License) resp, err := s.client.Do(req, licenses) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/messages.go b/Godeps/_workspace/src/github.com/google/go-github/github/messages.go new file mode 100644 index 0000000..9f0aba9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/messages.go @@ -0,0 +1,119 @@ +// Copyright 2016 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. + +// This file provides functions for validating payloads from GitHub Webhooks. +// GitHub docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github + +package github + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "errors" + "fmt" + "hash" + "io/ioutil" + "net/http" + "strings" +) + +const ( + // sha1Prefix is the prefix used by GitHub before the HMAC hexdigest. + sha1Prefix = "sha1" + // sha256Prefix and sha512Prefix are provided for future compatibility. + sha256Prefix = "sha256" + sha512Prefix = "sha512" + // signatureHeader is the GitHub header key used to pass the HMAC hexdigest. + signatureHeader = "X-Hub-Signature" +) + +// genMAC generates the HMAC signature for a message provided the secret key +// and hashFunc. +func genMAC(message, key []byte, hashFunc func() hash.Hash) []byte { + mac := hmac.New(hashFunc, key) + mac.Write(message) + return mac.Sum(nil) +} + +// checkMAC reports whether messageMAC is a valid HMAC tag for message. +func checkMAC(message, messageMAC, key []byte, hashFunc func() hash.Hash) bool { + expectedMAC := genMAC(message, key, hashFunc) + return hmac.Equal(messageMAC, expectedMAC) +} + +// messageMAC returns the hex-decoded HMAC tag from the signature and its +// corresponding hash function. +func messageMAC(signature string) ([]byte, func() hash.Hash, error) { + if signature == "" { + return nil, nil, errors.New("missing signature") + } + sigParts := strings.SplitN(signature, "=", 2) + if len(sigParts) != 2 { + return nil, nil, fmt.Errorf("error parsing signature %q", signature) + } + + var hashFunc func() hash.Hash + switch sigParts[0] { + case sha1Prefix: + hashFunc = sha1.New + case sha256Prefix: + hashFunc = sha256.New + case sha512Prefix: + hashFunc = sha512.New + default: + return nil, nil, fmt.Errorf("unknown hash type prefix: %q", sigParts[0]) + } + + buf, err := hex.DecodeString(sigParts[1]) + if err != nil { + return nil, nil, fmt.Errorf("error decoding signature %q: %v", signature, err) + } + return buf, hashFunc, nil +} + +// ValidatePayload validates an incoming GitHub Webhook event request +// and returns the (JSON) payload. +// secretKey is the GitHub Webhook secret message. +// +// Example usage: +// +// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) { +// payload, err := github.ValidatePayload(r, s.webhookSecretKey) +// if err != nil { ... } +// // Process payload... +// } +// +func ValidatePayload(r *http.Request, secretKey []byte) (payload []byte, err error) { + payload, err = ioutil.ReadAll(r.Body) + if err != nil { + return nil, err + } + + sig := r.Header.Get(signatureHeader) + if err := validateSignature(sig, payload, secretKey); err != nil { + return nil, err + } + return payload, nil +} + +// 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 docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github +func validateSignature(signature string, payload, secretKey []byte) error { + messageMAC, hashFunc, err := messageMAC(signature) + if err != nil { + return err + } + if !checkMAC(payload, messageMAC, secretKey, hashFunc) { + return errors.New("payload signature check failed") + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/migrations.go b/Godeps/_workspace/src/github.com/google/go-github/github/migrations.go new file mode 100644 index 0000000..8a7bc5f --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/migrations.go @@ -0,0 +1,225 @@ +// Copyright 2016 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 ( + "errors" + "fmt" + "net/http" + "strings" +) + +// MigrationService provides access to the migration related functions +// in the GitHub API. +// +// GitHub API docs: https://developer.github.com/v3/migration/ +type MigrationService struct { + client *Client +} + +// Migration represents a GitHub migration (archival). +type Migration struct { + ID *int `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 Migration) String() string { + return Stringify(m) +} + +// MigrationOptions specifies the optional parameters to Migration methods. +type MigrationOptions 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 +} + +// startMigration represents the body of a StartMigration request. +type startMigration 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"` +} + +// StartMigration starts the generation of a migration archive. +// repos is a slice of repository names to migrate. +// +// GitHub API docs: https://developer.github.com/v3/migration/migrations/#start-a-migration +func (s *MigrationService) StartMigration(org string, repos []string, opt *MigrationOptions) (*Migration, *Response, error) { + u := fmt.Sprintf("orgs/%v/migrations", org) + + body := &startMigration{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 := &Migration{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// ListMigrations lists the most recent migrations. +// +// GitHub API docs: https://developer.github.com/v3/migration/migrations/#get-a-list-of-migrations +func (s *MigrationService) ListMigrations(org string) ([]*Migration, *Response, error) { + u := fmt.Sprintf("orgs/%v/migrations", org) + + 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 []*Migration + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// MigrationStatus gets the status of a specific migration archive. +// 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(org string, id int) (*Migration, *Response, error) { + u := fmt.Sprintf("orgs/%v/migrations/%v", org, 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 := &Migration{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// MigrationArchiveURL fetches a migration archive URL. +// id is the migration ID. +// +// GitHub API docs: https://developer.github.com/v3/migration/migrations/#download-a-migration-archive +func (s *MigrationService) MigrationArchiveURL(org string, id int) (url string, err error) { + u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return "", err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeMigrationsPreview) + + s.client.clientMu.Lock() + defer s.client.clientMu.Unlock() + + // Disable the redirect mechanism because AWS fails if the GitHub auth token is provided. + var loc string + saveRedirect := s.client.client.CheckRedirect + s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + loc = req.URL.String() + return errors.New("disable redirect") + } + defer func() { s.client.client.CheckRedirect = saveRedirect }() + + _, err = s.client.Do(req, nil) // expect error from disable redirect + if err == nil { + return "", errors.New("expected redirect, none provided") + } + if !strings.Contains(err.Error(), "disable redirect") { + return "", err + } + return loc, nil +} + +// DeleteMigration deletes a previous migration archive. +// id is the migration ID. +// +// GitHub API docs: https://developer.github.com/v3/migration/migrations/#delete-a-migration-archive +func (s *MigrationService) DeleteMigration(org string, id int) (*Response, error) { + u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) + + 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", mediaTypeMigrationsPreview) + + return s.client.Do(req, nil) +} + +// UnlockRepo unlocks a repository that was locked for migration. +// id is the 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/migration/migrations/#unlock-a-repository +func (s *MigrationService) UnlockRepo(org string, id int, 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) + 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(req, nil) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/migrations_source_import.go b/Godeps/_workspace/src/github.com/google/go-github/github/migrations_source_import.go new file mode 100644 index 0000000..6ed4acf --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/migrations_source_import.go @@ -0,0 +1,326 @@ +// Copyright 2016 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import "fmt" + +// Import represents a repository import request. +type Import struct { + // The URL of the originating repository. + VCSURL *string `json:"vcs_url,omitempty"` + // The originating VCS type. Can be one of 'subversion', 'git', + // 'mercurial', or 'tfvc'. Without this parameter, the import job will + // take additional time to detect the VCS type before beginning the + // import. This detection step will be reflected in the response. + VCS *string `json:"vcs,omitempty"` + // VCSUsername and VCSPassword are only used for StartImport calls that + // are importing a password-protected repository. + VCSUsername *string `json:"vcs_username,omitempty"` + VCSPassword *string `json:"vcs_password,omitempty"` + // For a tfvc import, the name of the project that is being imported. + TFVCProject *string `json:"tfvc_project,omitempty"` + + // LFS related fields that may be preset in the Import Progress response + + // Describes whether the import has been opted in or out of using Git + // LFS. The value can be 'opt_in', 'opt_out', or 'undecided' if no + // action has been taken. + UseLFS *string `json:"use_lfs,omitempty"` + // Describes whether files larger than 100MB were found during the + // importing step. + HasLargeFiles *bool `json:"has_large_files,omitempty"` + // The total size in gigabytes of files larger than 100MB found in the + // originating repository. + LargeFilesSize *int `json:"large_files_size,omitempty"` + // The total number of files larger than 100MB found in the originating + // repository. To see a list of these files, call LargeFiles. + LargeFilesCount *int `json:"large_files_count,omitempty"` + + // Identifies the current status of an import. An import that does not + // have errors will progress through these steps: + // + // detecting - the "detection" step of the import is in progress + // because the request did not include a VCS parameter. The + // import is identifying the type of source control present at + // the URL. + // importing - the "raw" step of the import is in progress. This is + // where commit data is fetched from the original repository. + // The import progress response will include CommitCount (the + // total number of raw commits that will be imported) and + // Percent (0 - 100, the current progress through the import). + // mapping - the "rewrite" step of the import is in progress. This + // is where SVN branches are converted to Git branches, and + // where author updates are applied. The import progress + // response does not include progress information. + // pushing - the "push" step of the import is in progress. This is + // where the importer updates the repository on GitHub. The + // import progress response will include PushPercent, which is + // the percent value reported by git push when it is "Writing + // objects". + // complete - the import is complete, and the repository is ready + // on GitHub. + // + // If there are problems, you will see one of these in the status field: + // + // auth_failed - the import requires authentication in order to + // connect to the original repository. Make an UpdateImport + // request, and include VCSUsername and VCSPassword. + // error - the import encountered an error. The import progress + // response will include the FailedStep and an error message. + // Contact GitHub support for more information. + // detection_needs_auth - the importer requires authentication for + // the originating repository to continue detection. Make an + // UpdatImport request, and include VCSUsername and + // VCSPassword. + // detection_found_nothing - the importer didn't recognize any + // source control at the URL. + // detection_found_multiple - the importer found several projects + // or repositories at the provided URL. When this is the case, + // the Import Progress response will also include a + // ProjectChoices field with the possible project choices as + // values. Make an UpdateImport request, and include VCS and + // (if applicable) TFVCProject. + Status *string `json:"status,omitempty"` + CommitCount *int `json:"commit_count,omitempty"` + StatusText *string `json:"status_text,omitempty"` + AuthorsCount *int `json:"authors_count,omitempty"` + Percent *int `json:"percent,omitempty"` + PushPercent *int `json:"push_percent,omitempty"` + URL *string `json:"url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` + AuthorsURL *string `json:"authors_url,omitempty"` + RepositoryURL *string `json:"repository_url,omitempty"` + Message *string `json:"message,omitempty"` + FailedStep *string `json:"failed_step,omitempty"` + + // Human readable display name, provided when the Import appears as + // part of ProjectChoices. + HumanName *string `json:"human_name,omitempty"` + + // When the importer finds several projects or repositories at the + // provided URLs, this will identify the available choices. Call + // UpdateImport with the selected Import value. + ProjectChoices []Import `json:"project_choices,omitempty"` +} + +func (i Import) String() string { + return Stringify(i) +} + +// SourceImportAuthor identifies an author imported from a source repository. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors +type SourceImportAuthor struct { + ID *int `json:"id,omitempty"` + RemoteID *string `json:"remote_id,omitempty"` + RemoteName *string `json:"remote_name,omitempty"` + Email *string `json:"email,omitempty"` + Name *string `json:"name,omitempty"` + URL *string `json:"url,omitempty"` + ImportURL *string `json:"import_url,omitempty"` +} + +func (a SourceImportAuthor) String() string { + return Stringify(a) +} + +// LargeFile identifies a file larger than 100MB found during a repository import. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files +type LargeFile struct { + RefName *string `json:"ref_name,omitempty"` + Path *string `json:"path,omitempty"` + OID *string `json:"oid,omitempty"` + Size *int `json:"size,omitempty"` +} + +func (f LargeFile) String() string { + return Stringify(f) +} + +// StartImport initiates a repository import. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#start-an-import +func (s *MigrationService) StartImport(owner, repo string, in *Import) (*Import, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/import", owner, repo) + req, err := s.client.NewRequest("PUT", u, in) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeImportPreview) + + out := new(Import) + resp, err := s.client.Do(req, out) + if err != nil { + return nil, resp, err + } + + return out, resp, err +} + +// QueryImport queries for the status and progress of an ongoing repository import. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-import-progress +func (s *MigrationService) ImportProgress(owner, repo string) (*Import, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/import", owner, repo) + 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", mediaTypeImportPreview) + + out := new(Import) + resp, err := s.client.Do(req, out) + if err != nil { + return nil, resp, err + } + + return out, resp, err +} + +// UpdateImport initiates a repository import. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#update-existing-import +func (s *MigrationService) UpdateImport(owner, repo string, in *Import) (*Import, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/import", owner, repo) + req, err := s.client.NewRequest("PATCH", u, in) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeImportPreview) + + out := new(Import) + resp, err := s.client.Do(req, out) + if err != nil { + return nil, resp, err + } + + return out, resp, err +} + +// CommitAuthors gets the authors mapped from the original repository. +// +// Each type of source control system represents authors in a different way. +// For example, a Git commit author has a display name and an email address, +// but a Subversion commit author just has a username. The GitHub Importer will +// make the author information valid, but the author might not be correct. For +// example, it will change the bare Subversion username "hubot" into something +// like "hubot ". +// +// This method and MapCommitAuthor allow you to provide correct Git author +// information. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors +func (s *MigrationService) CommitAuthors(owner, repo string) ([]*SourceImportAuthor, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/import/authors", owner, repo) + 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", mediaTypeImportPreview) + + authors := new([]*SourceImportAuthor) + resp, err := s.client.Do(req, authors) + if err != nil { + return nil, resp, err + } + + return *authors, resp, err +} + +// MapCommitAuthor updates an author's identity for the import. Your +// application can continue updating authors any time before you push new +// commits to the repository. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#map-a-commit-author +func (s *MigrationService) MapCommitAuthor(owner, repo string, id int, 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 { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeImportPreview) + + out := new(SourceImportAuthor) + resp, err := s.client.Do(req, out) + if err != nil { + return nil, resp, err + } + + return out, resp, err +} + +// SetLFSPreference sets whether imported repositories should use Git LFS for +// files larger than 100MB. Only the UseLFS field on the provided Import is +// used. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#set-git-lfs-preference +func (s *MigrationService) SetLFSPreference(owner, repo string, in *Import) (*Import, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/import/lfs", owner, repo) + req, err := s.client.NewRequest("PATCH", u, in) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches + req.Header.Set("Accept", mediaTypeImportPreview) + + out := new(Import) + resp, err := s.client.Do(req, out) + if err != nil { + return nil, resp, err + } + + return out, resp, err +} + +// LargeFiles lists files larger than 100MB found during the import. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files +func (s *MigrationService) LargeFiles(owner, repo string) ([]*LargeFile, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/import/large_files", owner, repo) + 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", mediaTypeImportPreview) + + files := new([]*LargeFile) + resp, err := s.client.Do(req, files) + if err != nil { + return nil, resp, err + } + + return *files, resp, err +} + +// CancelImport stops an import for a repository. +// +// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#cancel-an-import +func (s *MigrationService) CancelImport(owner, repo string) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/import", owner, repo) + 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", mediaTypeImportPreview) + + return s.client.Do(req, nil) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/misc.go b/Godeps/_workspace/src/github.com/google/go-github/github/misc.go index 66e7f52..8576a4c 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/misc.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/misc.go @@ -180,14 +180,14 @@ func (s *ServiceHook) String() string { // ListServiceHooks lists all of the available service hooks. // // GitHub API docs: https://developer.github.com/webhooks/#services -func (c *Client) ListServiceHooks() ([]ServiceHook, *Response, error) { +func (c *Client) ListServiceHooks() ([]*ServiceHook, *Response, error) { u := "hooks" req, err := c.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - hooks := new([]ServiceHook) + hooks := new([]*ServiceHook) resp, err := c.Do(req, hooks) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs.go index 7596873..c71be22 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs.go @@ -68,11 +68,46 @@ func (p Plan) String() string { return Stringify(p) } +// OrganizationsListOptions specifies the optional parameters to the +// OrganizationsService.ListAll method. +type OrganizationsListOptions struct { + // Since filters Organizations by ID. + Since int `url:"since,omitempty"` + + ListOptions +} + +// ListAll lists all organizations, in the order that they were created on GitHub. +// +// Note: Pagination is powered exclusively by the since parameter. To continue +// listing the next set of organizations, use the ID of the last-returned organization +// as the opts.Since parameter for the next call. +// +// GitHub API docs: https://developer.github.com/v3/orgs/#list-all-organizations +func (s *OrganizationsService) ListAll(opt *OrganizationsListOptions) ([]*Organization, *Response, error) { + u, err := addOptions("organizations", opt) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + orgs := []*Organization{} + resp, err := s.client.Do(req, &orgs) + if err != nil { + return nil, resp, err + } + return orgs, resp, err +} + // List the organizations for a user. Passing the empty string will list // organizations for the authenticated user. // // GitHub API docs: http://developer.github.com/v3/orgs/#list-user-organizations -func (s *OrganizationsService) List(user string, opt *ListOptions) ([]Organization, *Response, error) { +func (s *OrganizationsService) List(user string, opt *ListOptions) ([]*Organization, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/orgs", user) @@ -89,7 +124,7 @@ func (s *OrganizationsService) List(user string, opt *ListOptions) ([]Organizati return nil, nil, err } - orgs := new([]Organization) + orgs := new([]*Organization) resp, err := s.client.Do(req, orgs) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_hooks.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_hooks.go index 3e7ad40..95b8322 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_hooks.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_hooks.go @@ -10,7 +10,7 @@ import "fmt" // ListHooks lists all Hooks for the specified organization. // // GitHub API docs: https://developer.github.com/v3/orgs/hooks/#list-hooks -func (s *OrganizationsService) ListHooks(org string, opt *ListOptions) ([]Hook, *Response, error) { +func (s *OrganizationsService) ListHooks(org string, opt *ListOptions) ([]*Hook, *Response, error) { u := fmt.Sprintf("orgs/%v/hooks", org) u, err := addOptions(u, opt) if err != nil { @@ -22,7 +22,7 @@ func (s *OrganizationsService) ListHooks(org string, opt *ListOptions) ([]Hook, return nil, nil, err } - hooks := new([]Hook) + hooks := new([]*Hook) resp, err := s.client.Do(req, hooks) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go index 01a9ba9..80454ad 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_members.go @@ -69,7 +69,7 @@ type ListMembersOptions struct { // public members, otherwise it will only return public members. // // GitHub API docs: http://developer.github.com/v3/orgs/members/#members-list -func (s *OrganizationsService) ListMembers(org string, opt *ListMembersOptions) ([]User, *Response, error) { +func (s *OrganizationsService) ListMembers(org string, opt *ListMembersOptions) ([]*User, *Response, error) { var u string if opt != nil && opt.PublicOnly { u = fmt.Sprintf("orgs/%v/public_members", org) @@ -86,11 +86,7 @@ func (s *OrganizationsService) ListMembers(org string, opt *ListMembersOptions) return nil, nil, err } - if opt != nil && opt.Role != "" { - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - } - - members := new([]User) + members := new([]*User) resp, err := s.client.Do(req, members) if err != nil { return nil, resp, err @@ -182,7 +178,7 @@ type ListOrgMembershipsOptions struct { // ListOrgMemberships lists the organization memberships for the authenticated user. // // GitHub API docs: https://developer.github.com/v3/orgs/members/#list-your-organization-memberships -func (s *OrganizationsService) ListOrgMemberships(opt *ListOrgMembershipsOptions) ([]Membership, *Response, error) { +func (s *OrganizationsService) ListOrgMemberships(opt *ListOrgMembershipsOptions) ([]*Membership, *Response, error) { u := "user/memberships/orgs" u, err := addOptions(u, opt) if err != nil { @@ -194,7 +190,7 @@ func (s *OrganizationsService) ListOrgMemberships(opt *ListOrgMembershipsOptions return nil, nil, err } - var memberships []Membership + var memberships []*Membership resp, err := s.client.Do(req, &memberships) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go index ce0e046..8e8550c 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/orgs_teams.go @@ -30,9 +30,11 @@ type Team struct { // 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"` + 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"` } func (t Team) String() string { @@ -42,7 +44,7 @@ func (t Team) String() string { // ListTeams lists all of the teams for an organization. // // GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-teams -func (s *OrganizationsService) ListTeams(org string, opt *ListOptions) ([]Team, *Response, error) { +func (s *OrganizationsService) ListTeams(org string, opt *ListOptions) ([]*Team, *Response, error) { u := fmt.Sprintf("orgs/%v/teams", org) u, err := addOptions(u, opt) if err != nil { @@ -54,7 +56,7 @@ func (s *OrganizationsService) ListTeams(org string, opt *ListOptions) ([]Team, return nil, nil, err } - teams := new([]Team) + teams := new([]*Team) resp, err := s.client.Do(req, teams) if err != nil { return nil, resp, err @@ -92,10 +94,6 @@ func (s *OrganizationsService) CreateTeam(org string, team *Team) (*Team, *Respo return nil, nil, err } - if team.Privacy != nil { - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - } - t := new(Team) resp, err := s.client.Do(req, t) if err != nil { @@ -115,10 +113,6 @@ func (s *OrganizationsService) EditTeam(id int, team *Team) (*Team, *Response, e return nil, nil, err } - if team.Privacy != nil { - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - } - t := new(Team) resp, err := s.client.Do(req, t) if err != nil { @@ -155,7 +149,7 @@ type OrganizationListTeamMembersOptions struct { // team. // // GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-team-members -func (s *OrganizationsService) ListTeamMembers(team int, opt *OrganizationListTeamMembersOptions) ([]User, *Response, error) { +func (s *OrganizationsService) ListTeamMembers(team int, opt *OrganizationListTeamMembersOptions) ([]*User, *Response, error) { u := fmt.Sprintf("teams/%v/members", team) u, err := addOptions(u, opt) if err != nil { @@ -167,11 +161,7 @@ func (s *OrganizationsService) ListTeamMembers(team int, opt *OrganizationListTe return nil, nil, err } - if opt != nil && opt.Role != "" { - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - } - - members := new([]User) + members := new([]*User) resp, err := s.client.Do(req, members) if err != nil { return nil, resp, err @@ -198,7 +188,7 @@ func (s *OrganizationsService) IsTeamMember(team int, user string) (bool, *Respo // ListTeamRepos lists the repositories that the specified team has access to. // // GitHub API docs: http://developer.github.com/v3/orgs/teams/#list-team-repos -func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]Repository, *Response, error) { +func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("teams/%v/repos", team) u, err := addOptions(u, opt) if err != nil { @@ -210,7 +200,7 @@ func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]Repo return nil, nil, err } - repos := new([]Repository) + repos := new([]*Repository) resp, err := s.client.Do(req, repos) if err != nil { return nil, resp, err @@ -223,7 +213,7 @@ func (s *OrganizationsService) ListTeamRepos(team int, opt *ListOptions) ([]Repo // repository is managed by team, a Repository is returned which includes the // permissions team has for that repo. // -// GitHub API docs: http://developer.github.com/v3/orgs/teams/#get-team-repo +// GitHub API docs: https://developer.github.com/v3/orgs/teams/#check-if-a-team-manages-a-repository func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) (*Repository, *Response, error) { u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) req, err := s.client.NewRequest("GET", u, nil) @@ -231,7 +221,7 @@ func (s *OrganizationsService) IsTeamRepo(team int, owner string, repo string) ( return nil, nil, err } - req.Header.Set("Accept", mediaTypeOrgPermissionRepoPreview) + req.Header.Set("Accept", mediaTypeOrgPermissionRepo) repository := new(Repository) resp, err := s.client.Do(req, repository) @@ -267,10 +257,6 @@ func (s *OrganizationsService) AddTeamRepo(team int, owner string, repo string, return nil, err } - if opt != nil { - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - } - return s.client.Do(req, nil) } @@ -291,7 +277,7 @@ func (s *OrganizationsService) RemoveTeamRepo(team int, owner string, repo strin // ListUserTeams lists a user's teams // GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-user-teams -func (s *OrganizationsService) ListUserTeams(opt *ListOptions) ([]Team, *Response, error) { +func (s *OrganizationsService) ListUserTeams(opt *ListOptions) ([]*Team, *Response, error) { u := "user/teams" u, err := addOptions(u, opt) if err != nil { @@ -303,7 +289,7 @@ func (s *OrganizationsService) ListUserTeams(opt *ListOptions) ([]Team, *Respons return nil, nil, err } - teams := new([]Team) + teams := new([]*Team) resp, err := s.client.Do(req, teams) if err != nil { return nil, resp, err @@ -370,10 +356,6 @@ func (s *OrganizationsService) AddTeamMembership(team int, user string, opt *Org return nil, nil, err } - if opt != nil { - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - } - t := new(Membership) resp, err := s.client.Do(req, t) if err != nil { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/pulls.go b/Godeps/_workspace/src/github.com/google/go-github/github/pulls.go index 71cf2e2..535ee46 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/pulls.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/pulls.go @@ -43,6 +43,7 @@ type PullRequest struct { StatusesURL *string `json:"statuses_url,omitempty"` DiffURL *string `json:"diff_url,omitempty"` PatchURL *string `json:"patch_url,omitempty"` + Assignee *User `json:"assignee,omitempty"` // probably only in webhooks Head *PullRequestBranch `json:"head,omitempty"` Base *PullRequestBranch `json:"base,omitempty"` @@ -90,7 +91,7 @@ type PullRequestListOptions struct { // List the pull requests for the specified repository. // // GitHub API docs: http://developer.github.com/v3/pulls/#list-pull-requests -func (s *PullRequestsService) List(owner string, repo string, opt *PullRequestListOptions) ([]PullRequest, *Response, error) { +func (s *PullRequestsService) List(owner string, repo string, opt *PullRequestListOptions) ([]*PullRequest, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -102,7 +103,7 @@ func (s *PullRequestsService) List(owner string, repo string, opt *PullRequestLi return nil, nil, err } - pulls := new([]PullRequest) + pulls := new([]*PullRequest) resp, err := s.client.Do(req, pulls) if err != nil { return nil, resp, err @@ -180,7 +181,7 @@ func (s *PullRequestsService) Edit(owner string, repo string, number int, pull * // ListCommits lists the commits in a pull request. // // GitHub API docs: https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request -func (s *PullRequestsService) ListCommits(owner string, repo string, number int, opt *ListOptions) ([]RepositoryCommit, *Response, error) { +func (s *PullRequestsService) ListCommits(owner string, repo string, number int, opt *ListOptions) ([]*RepositoryCommit, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/commits", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -192,7 +193,7 @@ func (s *PullRequestsService) ListCommits(owner string, repo string, number int, return nil, nil, err } - commits := new([]RepositoryCommit) + commits := new([]*RepositoryCommit) resp, err := s.client.Do(req, commits) if err != nil { return nil, resp, err @@ -204,7 +205,7 @@ func (s *PullRequestsService) ListCommits(owner string, repo string, number int, // ListFiles lists the files in a pull request. // // GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests-files -func (s *PullRequestsService) ListFiles(owner string, repo string, number int, opt *ListOptions) ([]CommitFile, *Response, error) { +func (s *PullRequestsService) ListFiles(owner string, repo string, number int, opt *ListOptions) ([]*CommitFile, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/files", owner, repo, number) u, err := addOptions(u, opt) if err != nil { @@ -216,7 +217,7 @@ func (s *PullRequestsService) ListFiles(owner string, repo string, number int, o return nil, nil, err } - commitFiles := new([]CommitFile) + commitFiles := new([]*CommitFile) resp, err := s.client.Do(req, commitFiles) if err != nil { return nil, resp, err @@ -247,20 +248,30 @@ type PullRequestMergeResult struct { Message *string `json:"message,omitempty"` } +// PullRequestOptions lets you define how a pull request will be merged. +type PullRequestOptions struct { + Squash bool +} + type pullRequestMergeRequest struct { CommitMessage *string `json:"commit_message"` + Squash *bool `json:"squash,omitempty"` } // Merge a pull request (Merge Button™). // // GitHub API docs: https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-buttontrade -func (s *PullRequestsService) Merge(owner string, repo string, number int, commitMessage string) (*PullRequestMergeResult, *Response, error) { +func (s *PullRequestsService) Merge(owner string, repo string, number int, commitMessage string, options *PullRequestOptions) (*PullRequestMergeResult, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) - req, err := s.client.NewRequest("PUT", u, &pullRequestMergeRequest{ - CommitMessage: &commitMessage, - }) + pullRequestBody := &pullRequestMergeRequest{CommitMessage: &commitMessage} + if options != nil { + pullRequestBody.Squash = &options.Squash + } + req, err := s.client.NewRequest("PUT", u, pullRequestBody) + // TODO: This header will be unnecessary when the API is no longer in preview. + req.Header.Set("Accept", mediaTypeSquashPreview) if err != nil { return nil, nil, err } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go b/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go index f165d5f..c7af85a 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/pulls_comments.go @@ -13,6 +13,7 @@ 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"` @@ -21,8 +22,12 @@ type PullRequestComment struct { 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"` } func (p PullRequestComment) String() string { @@ -49,7 +54,7 @@ type PullRequestListCommentsOptions struct { // the repository. // // GitHub API docs: https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request -func (s *PullRequestsService) ListComments(owner string, repo string, number int, opt *PullRequestListCommentsOptions) ([]PullRequestComment, *Response, error) { +func (s *PullRequestsService) ListComments(owner string, repo string, number int, opt *PullRequestListCommentsOptions) ([]*PullRequestComment, *Response, error) { var u string if number == 0 { u = fmt.Sprintf("repos/%v/%v/pulls/comments", owner, repo) @@ -66,7 +71,10 @@ func (s *PullRequestsService) ListComments(owner string, repo string, number int return nil, nil, err } - comments := new([]PullRequestComment) + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + comments := new([]*PullRequestComment) resp, err := s.client.Do(req, comments) if err != nil { return nil, resp, err @@ -85,6 +93,9 @@ func (s *PullRequestsService) GetComment(owner string, repo string, number int) return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + comment := new(PullRequestComment) resp, err := s.client.Do(req, comment) if err != nil { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/reactions.go b/Godeps/_workspace/src/github.com/google/go-github/github/reactions.go new file mode 100644 index 0000000..68a16af --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/reactions.go @@ -0,0 +1,272 @@ +// Copyright 2016 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import "fmt" + +// ReactionsService provides access to the reactions-related functions in the +// GitHub API. +// +// GitHub API docs: https://developer.github.com/v3/reactions/ +type ReactionsService struct { + client *Client +} + +// Reaction represents a GitHub reaction. +type Reaction struct { + // ID is the Reaction ID. + ID *int `json:"id,omitempty"` + User *User `json:"user,omitempty"` + // Content is the type of reaction. + // Possible values are: + // "+1", "-1", "laugh", "confused", "heart", "hooray". + Content *string `json:"content,omitempty"` +} + +// Reactions represents a summary of GitHub reactions. +type Reactions struct { + TotalCount *int `json:"total_count,omitempty"` + PlusOne *int `json:"+1,omitempty"` + MinusOne *int `json:"-1,omitempty"` + Laugh *int `json:"laugh,omitempty"` + Confused *int `json:"confused,omitempty"` + Heart *int `json:"heart,omitempty"` + Hooray *int `json:"hooray,omitempty"` + URL *string `json:"url,omitempty"` +} + +func (r Reaction) String() string { + return Stringify(r) +} + +// 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(owner, repo string, id int, 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 { + 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", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// 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. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment +func (s ReactionsService) CreateCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) + + body := &Reaction{Content: String(content)} + 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", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// ListIssueReactions lists the reactions for an issue. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue +func (s *ReactionsService) ListIssueReactions(owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) + 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", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// 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. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue +func (s ReactionsService) CreateIssueReaction(owner, repo string, number int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number) + + body := &Reaction{Content: String(content)} + 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", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// 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(owner, repo string, id int, 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 { + 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", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// 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. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment +func (s ReactionsService) CreateIssueCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) + + body := &Reaction{Content: String(content)} + 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", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// 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(owner, repo string, id int, 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 { + 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", mediaTypeReactionsPreview) + + var m []*Reaction + resp, err := s.client.Do(req, &m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// 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. +// +// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment +func (s ReactionsService) CreatePullRequestCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) + + body := &Reaction{Content: String(content)} + 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", mediaTypeReactionsPreview) + + m := &Reaction{} + resp, err := s.client.Do(req, m) + if err != nil { + return nil, resp, err + } + + return m, resp, nil +} + +// DeleteReaction deletes a reaction. +// +// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive +func (s *ReactionsService) DeleteReaction(id int) (*Response, error) { + u := fmt.Sprintf("reactions/%v", id) + + 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", mediaTypeReactionsPreview) + + return s.client.Do(req, nil) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos.go index 365520b..3439e69 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos.go @@ -129,7 +129,7 @@ type RepositoryListOptions struct { // repositories for the authenticated user. // // GitHub API docs: http://developer.github.com/v3/repos/#list-user-repositories -func (s *RepositoriesService) List(user string, opt *RepositoryListOptions) ([]Repository, *Response, error) { +func (s *RepositoriesService) List(user string, opt *RepositoryListOptions) ([]*Repository, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/repos", user) @@ -149,7 +149,7 @@ func (s *RepositoriesService) List(user string, opt *RepositoryListOptions) ([]R // TODO: remove custom Accept header when license support fully launches req.Header.Set("Accept", mediaTypeLicensesPreview) - repos := new([]Repository) + repos := new([]*Repository) resp, err := s.client.Do(req, repos) if err != nil { return nil, resp, err @@ -171,7 +171,7 @@ type RepositoryListByOrgOptions struct { // ListByOrg lists the repositories for an organization. // // GitHub API docs: http://developer.github.com/v3/repos/#list-organization-repositories -func (s *RepositoriesService) ListByOrg(org string, opt *RepositoryListByOrgOptions) ([]Repository, *Response, error) { +func (s *RepositoriesService) ListByOrg(org string, opt *RepositoryListByOrgOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("orgs/%v/repos", org) u, err := addOptions(u, opt) if err != nil { @@ -186,7 +186,7 @@ func (s *RepositoriesService) ListByOrg(org string, opt *RepositoryListByOrgOpti // TODO: remove custom Accept header when license support fully launches req.Header.Set("Accept", mediaTypeLicensesPreview) - repos := new([]Repository) + repos := new([]*Repository) resp, err := s.client.Do(req, repos) if err != nil { return nil, resp, err @@ -207,7 +207,7 @@ type RepositoryListAllOptions struct { // ListAll lists all GitHub repositories in the order that they were created. // // GitHub API docs: http://developer.github.com/v3/repos/#list-all-public-repositories -func (s *RepositoriesService) ListAll(opt *RepositoryListAllOptions) ([]Repository, *Response, error) { +func (s *RepositoriesService) ListAll(opt *RepositoryListAllOptions) ([]*Repository, *Response, error) { u, err := addOptions("repositories", opt) if err != nil { return nil, nil, err @@ -218,7 +218,7 @@ func (s *RepositoriesService) ListAll(opt *RepositoryListAllOptions) ([]Reposito return nil, nil, err } - repos := new([]Repository) + repos := new([]*Repository) resp, err := s.client.Do(req, repos) if err != nil { return nil, resp, err @@ -277,6 +277,29 @@ func (s *RepositoriesService) Get(owner, repo string) (*Repository, *Response, e return repository, resp, err } +// GetByID fetches a repository. +// +// Note: GetByID uses the undocumented GitHub API endpoint /repositories/:id. +func (s *RepositoriesService) GetByID(id int) (*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(req, repository) + if err != nil { + return nil, resp, err + } + + return repository, resp, err +} + // Edit updates a repository. // // GitHub API docs: http://developer.github.com/v3/repos/#edit @@ -343,7 +366,7 @@ type ListContributorsOptions struct { // ListContributors lists contributors for a repository. // // GitHub API docs: http://developer.github.com/v3/repos/#list-contributors -func (s *RepositoriesService) ListContributors(owner string, repository string, opt *ListContributorsOptions) ([]Contributor, *Response, error) { +func (s *RepositoriesService) ListContributors(owner string, repository string, opt *ListContributorsOptions) ([]*Contributor, *Response, error) { u := fmt.Sprintf("repos/%v/%v/contributors", owner, repository) u, err := addOptions(u, opt) if err != nil { @@ -355,7 +378,7 @@ func (s *RepositoriesService) ListContributors(owner string, repository string, return nil, nil, err } - contributor := new([]Contributor) + contributor := new([]*Contributor) resp, err := s.client.Do(req, contributor) if err != nil { return nil, nil, err @@ -393,7 +416,7 @@ func (s *RepositoriesService) ListLanguages(owner string, repo string) (map[stri // ListTeams lists the teams for the specified repository. // // GitHub API docs: https://developer.github.com/v3/repos/#list-teams -func (s *RepositoriesService) ListTeams(owner string, repo string, opt *ListOptions) ([]Team, *Response, error) { +func (s *RepositoriesService) ListTeams(owner string, repo string, opt *ListOptions) ([]*Team, *Response, error) { u := fmt.Sprintf("repos/%v/%v/teams", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -405,7 +428,7 @@ func (s *RepositoriesService) ListTeams(owner string, repo string, opt *ListOpti return nil, nil, err } - teams := new([]Team) + teams := new([]*Team) resp, err := s.client.Do(req, teams) if err != nil { return nil, resp, err @@ -425,7 +448,7 @@ type RepositoryTag struct { // ListTags lists tags for the specified repository. // // GitHub API docs: https://developer.github.com/v3/repos/#list-tags -func (s *RepositoriesService) ListTags(owner string, repo string, opt *ListOptions) ([]RepositoryTag, *Response, error) { +func (s *RepositoriesService) ListTags(owner string, repo string, opt *ListOptions) ([]*RepositoryTag, *Response, error) { u := fmt.Sprintf("repos/%v/%v/tags", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -437,7 +460,7 @@ func (s *RepositoriesService) ListTags(owner string, repo string, opt *ListOptio return nil, nil, err } - tags := new([]RepositoryTag) + tags := new([]*RepositoryTag) resp, err := s.client.Do(req, tags) if err != nil { return nil, resp, err @@ -474,7 +497,7 @@ type RequiredStatusChecks struct { // ListBranches lists branches for the specified repository. // // GitHub API docs: http://developer.github.com/v3/repos/#list-branches -func (s *RepositoriesService) ListBranches(owner string, repo string, opt *ListOptions) ([]Branch, *Response, error) { +func (s *RepositoriesService) ListBranches(owner string, repo string, opt *ListOptions) ([]*Branch, *Response, error) { u := fmt.Sprintf("repos/%v/%v/branches", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -486,7 +509,9 @@ func (s *RepositoriesService) ListBranches(owner string, repo string, opt *ListO return nil, nil, err } - branches := new([]Branch) + req.Header.Set("Accept", mediaTypeProtectedBranchesPreview) + + branches := new([]*Branch) resp, err := s.client.Do(req, branches) if err != nil { return nil, resp, err @@ -536,3 +561,22 @@ func (s *RepositoriesService) EditBranch(owner, repo, branchName string, branch return b, resp, err } + +// 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 +func (s *RepositoriesService) License(owner, repo string) (*License, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/license", owner, repo) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + r := &Repository{} + resp, err := s.client.Do(req, r) + if err != nil { + return nil, resp, err + } + + return r.License, resp, err +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go index 61dc4ef..68a9f46 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_collaborators.go @@ -10,7 +10,7 @@ import "fmt" // ListCollaborators lists the Github users that have access to the repository. // // GitHub API docs: http://developer.github.com/v3/repos/collaborators/#list -func (s *RepositoriesService) ListCollaborators(owner, repo string, opt *ListOptions) ([]User, *Response, error) { +func (s *RepositoriesService) ListCollaborators(owner, repo string, opt *ListOptions) ([]*User, *Response, error) { u := fmt.Sprintf("repos/%v/%v/collaborators", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -22,9 +22,7 @@ func (s *RepositoriesService) ListCollaborators(owner, repo string, opt *ListOpt return nil, nil, err } - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - - users := new([]User) + users := new([]*User) resp, err := s.client.Do(req, users) if err != nil { return nil, resp, err @@ -60,13 +58,13 @@ type RepositoryAddCollaboratorOptions struct { // push - team members can pull and push, but not administer this repository // admin - team members can pull, push and administer this repository // - // Default value is "pull". This option is only valid for organization-owned repositories. + // Default value is "push". This option is only valid for organization-owned repositories. Permission string `json:"permission,omitempty"` } // AddCollaborator adds the specified Github user as collaborator to the given repo. // -// GitHub API docs: http://developer.github.com/v3/repos/collaborators/#add-collaborator +// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator func (s *RepositoriesService) AddCollaborator(owner, repo, user string, opt *RepositoryAddCollaboratorOptions) (*Response, error) { u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) req, err := s.client.NewRequest("PUT", u, opt) @@ -74,9 +72,8 @@ func (s *RepositoriesService) AddCollaborator(owner, repo, user string, opt *Rep return nil, err } - if opt != nil { - req.Header.Set("Accept", mediaTypeOrgPermissionPreview) - } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) return s.client.Do(req, nil) } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_comments.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_comments.go index 2d090bb..34a8d02 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_comments.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_comments.go @@ -17,6 +17,7 @@ type RepositoryComment struct { ID *int `json:"id,omitempty"` CommitID *string `json:"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"` @@ -34,7 +35,7 @@ func (r RepositoryComment) String() string { // ListComments lists all the comments for the repository. // // GitHub API docs: http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository -func (s *RepositoriesService) ListComments(owner, repo string, opt *ListOptions) ([]RepositoryComment, *Response, error) { +func (s *RepositoriesService) ListComments(owner, repo string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/comments", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -46,7 +47,10 @@ func (s *RepositoriesService) ListComments(owner, repo string, opt *ListOptions) return nil, nil, err } - comments := new([]RepositoryComment) + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + comments := new([]*RepositoryComment) resp, err := s.client.Do(req, comments) if err != nil { return nil, resp, err @@ -58,7 +62,7 @@ func (s *RepositoriesService) ListComments(owner, repo string, opt *ListOptions) // ListCommitComments lists all the comments for a given commit SHA. // // GitHub API docs: http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit -func (s *RepositoriesService) ListCommitComments(owner, repo, sha string, opt *ListOptions) ([]RepositoryComment, *Response, error) { +func (s *RepositoriesService) ListCommitComments(owner, repo, sha string, opt *ListOptions) ([]*RepositoryComment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) u, err := addOptions(u, opt) if err != nil { @@ -70,7 +74,10 @@ func (s *RepositoriesService) ListCommitComments(owner, repo, sha string, opt *L return nil, nil, err } - comments := new([]RepositoryComment) + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + + comments := new([]*RepositoryComment) resp, err := s.client.Do(req, comments) if err != nil { return nil, resp, err @@ -109,6 +116,9 @@ func (s *RepositoriesService) GetComment(owner, repo string, id int) (*Repositor return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeReactionsPreview) + c := new(RepositoryComment) resp, err := s.client.Do(req, c) if err != nil { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_commits.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_commits.go index 6401cb4..f4b462c 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_commits.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_commits.go @@ -6,6 +6,7 @@ package github import ( + "bytes" "fmt" "time" ) @@ -103,7 +104,7 @@ type CommitsListOptions struct { // ListCommits lists the commits of a repository. // // GitHub API docs: http://developer.github.com/v3/repos/commits/#list -func (s *RepositoriesService) ListCommits(owner, repo string, opt *CommitsListOptions) ([]RepositoryCommit, *Response, error) { +func (s *RepositoriesService) ListCommits(owner, repo string, opt *CommitsListOptions) ([]*RepositoryCommit, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -115,7 +116,7 @@ func (s *RepositoriesService) ListCommits(owner, repo string, opt *CommitsListOp return nil, nil, err } - commits := new([]RepositoryCommit) + commits := new([]*RepositoryCommit) resp, err := s.client.Do(req, commits) if err != nil { return nil, resp, err @@ -137,6 +138,9 @@ func (s *RepositoriesService) GetCommit(owner, repo, sha string) (*RepositoryCom return nil, nil, err } + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeGitSigningPreview) + commit := new(RepositoryCommit) resp, err := s.client.Do(req, commit) if err != nil { @@ -146,6 +150,32 @@ func (s *RepositoriesService) GetCommit(owner, repo, sha string) (*RepositoryCom return commit, resp, err } +// 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. +// +// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference +func (s *RepositoriesService) GetCommitSHA1(owner, repo, ref, lastSHA string) (string, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, ref) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return "", nil, err + } + if lastSHA != "" { + req.Header.Set("If-None-Match", `"`+lastSHA+`"`) + } + + req.Header.Set("Accept", mediaTypeV3SHA) + + var buf bytes.Buffer + resp, err := s.client.Do(req, &buf) + if err != nil { + return "", resp, err + } + + return buf.String(), resp, err +} + // CompareCommits compares a range of commits with each other. // todo: support media formats - https://github.com/google/go-github/issues/6 // diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_contents.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_contents.go index 520cf2f..ebf4d04 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_contents.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_contents.go @@ -21,11 +21,14 @@ import ( // RepositoryContent represents a file or directory in a github repository. type RepositoryContent struct { - Type *string `json:"type,omitempty"` - Encoding *string `json:"encoding,omitempty"` - Size *int `json:"size,omitempty"` - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` + Type *string `json:"type,omitempty"` + Encoding *string `json:"encoding,omitempty"` + Size *int `json:"size,omitempty"` + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` + // Content contains the actual file content, which may be encoded. + // Callers should call GetContent which will decode the content if + // necessary. Content *string `json:"content,omitempty"` SHA *string `json:"sha,omitempty"` URL *string `json:"url,omitempty"` @@ -56,11 +59,14 @@ type RepositoryContentGetOptions struct { Ref string `url:"ref,omitempty"` } +// String converts RepositoryContent to a string. It's primarily for testing. func (r RepositoryContent) String() string { return Stringify(r) } // Decode decodes the file content if it is base64 encoded. +// +// Deprecated: Use GetContent instead. func (r *RepositoryContent) Decode() ([]byte, error) { if *r.Encoding != "base64" { return nil, errors.New("cannot decode non-base64") @@ -72,6 +78,27 @@ func (r *RepositoryContent) Decode() ([]byte, error) { return o, nil } +// GetContent returns the content of r, decoding it if necessary. +func (r *RepositoryContent) GetContent() (string, error) { + var encoding string + if r.Encoding != nil { + encoding = *r.Encoding + } + + switch encoding { + case "base64": + c, err := base64.StdEncoding.DecodeString(*r.Content) + return string(c), err + case "": + if r.Content == nil { + return "", nil + } + return *r.Content, nil + default: + return "", fmt.Errorf("unsupported content encoding: %v", encoding) + } +} + // GetReadme gets the Readme file for the repository. // // GitHub API docs: http://developer.github.com/v3/repos/contents/#get-the-readme @@ -127,9 +154,9 @@ func (s *RepositoriesService) DownloadContents(owner, repo, filepath string, opt // value and the other will be nil. // // GitHub API docs: http://developer.github.com/v3/repos/contents/#get-contents -func (s *RepositoriesService) GetContents(owner, repo, path string, opt *RepositoryContentGetOptions) (fileContent *RepositoryContent, - directoryContent []*RepositoryContent, resp *Response, err error) { - u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) +func (s *RepositoriesService) GetContents(owner, repo, path string, opt *RepositoryContentGetOptions) (fileContent *RepositoryContent, directoryContent []*RepositoryContent, resp *Response, err error) { + escapedPath := (&url.URL{Path: path}).String() + u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, escapedPath) u, err = addOptions(u, opt) if err != nil { return nil, nil, nil, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_deployments.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_deployments.go index 77c7949..f3272b0 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_deployments.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_deployments.go @@ -12,28 +12,32 @@ import ( // Deployment represents a deployment in a repo type Deployment struct { - URL *string `json:"url,omitempty"` - ID *int `json:"id,omitempty"` - SHA *string `json:"sha,omitempty"` - Ref *string `json:"ref,omitempty"` - Task *string `json:"task,omitempty"` - Payload json.RawMessage `json:"payload,omitempty"` - Environment *string `json:"environment,omitempty"` - Description *string `json:"description,omitempty"` - Creator *User `json:"creator,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"pushed_at,omitempty"` + URL *string `json:"url,omitempty"` + ID *int `json:"id,omitempty"` + SHA *string `json:"sha,omitempty"` + Ref *string `json:"ref,omitempty"` + Task *string `json:"task,omitempty"` + Payload json.RawMessage `json:"payload,omitempty"` + Environment *string `json:"environment,omitempty"` + Description *string `json:"description,omitempty"` + Creator *User `json:"creator,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + UpdatedAt *Timestamp `json:"pushed_at,omitempty"` + StatusesURL *string `json:"statuses_url,omitempty"` + RepositoryURL *string `json:"repository_url,omitempty"` } // DeploymentRequest represents a deployment request type DeploymentRequest struct { - Ref *string `json:"ref,omitempty"` - Task *string `json:"task,omitempty"` - AutoMerge *bool `json:"auto_merge,omitempty"` - RequiredContexts *[]string `json:"required_contexts,omitempty"` - Payload *string `json:"payload,omitempty"` - Environment *string `json:"environment,omitempty"` - Description *string `json:"description,omitempty"` + Ref *string `json:"ref,omitempty"` + Task *string `json:"task,omitempty"` + AutoMerge *bool `json:"auto_merge,omitempty"` + RequiredContexts *[]string `json:"required_contexts,omitempty"` + Payload *string `json:"payload,omitempty"` + Environment *string `json:"environment,omitempty"` + Description *string `json:"description,omitempty"` + TransientEnvironment *bool `json:"transient_environment,omitempty"` + ProductionEnvironment *bool `json:"production_environment,omitempty"` } // DeploymentsListOptions specifies the optional parameters to the @@ -57,7 +61,7 @@ type DeploymentsListOptions struct { // ListDeployments lists the deployments of a repository. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployments -func (s *RepositoriesService) ListDeployments(owner, repo string, opt *DeploymentsListOptions) ([]Deployment, *Response, error) { +func (s *RepositoriesService) ListDeployments(owner, repo string, opt *DeploymentsListOptions) ([]*Deployment, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -69,7 +73,7 @@ func (s *RepositoriesService) ListDeployments(owner, repo string, opt *Deploymen return nil, nil, err } - deployments := new([]Deployment) + deployments := new([]*Deployment) resp, err := s.client.Do(req, deployments) if err != nil { return nil, resp, err @@ -89,6 +93,9 @@ func (s *RepositoriesService) CreateDeployment(owner, repo string, request *Depl return nil, nil, err } + // TODO: remove custom Accept header when deployment support fully launches + req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) + d := new(Deployment) resp, err := s.client.Do(req, d) if err != nil { @@ -101,26 +108,33 @@ func (s *RepositoriesService) CreateDeployment(owner, repo string, request *Depl // DeploymentStatus represents the status of a // particular deployment. type DeploymentStatus struct { - ID *int `json:"id,omitempty"` - State *string `json:"state,omitempty"` - Creator *User `json:"creator,omitempty"` - Description *string `json:"description,omitempty"` - TargetURL *string `json:"target_url,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` - UpdatedAt *Timestamp `json:"pushed_at,omitempty"` + ID *int `json:"id,omitempty"` + // State is the deployment state. + // Possible values are: "pending", "success", "failure", "error", "inactive". + State *string `json:"state,omitempty"` + Creator *User `json:"creator,omitempty"` + Description *string `json:"description,omitempty"` + TargetURL *string `json:"target_url,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + UpdatedAt *Timestamp `json:"pushed_at,omitempty"` + DeploymentURL *string `json:"deployment_url,omitempty"` + RepositoryURL *string `json:"repository_url,omitempty"` } // DeploymentStatusRequest represents a deployment request type DeploymentStatusRequest struct { - State *string `json:"state,omitempty"` - TargetURL *string `json:"target_url,omitempty"` - Description *string `json:"description,omitempty"` + State *string `json:"state,omitempty"` + TargetURL *string `json:"target_url,omitempty"` // Deprecated. Use LogURL instead. + LogURL *string `json:"log_url,omitempty"` + Description *string `json:"description,omitempty"` + EnvironmentURL *string `json:"environment_url,omitempty"` + AutoInactive *bool `json:"auto_inactive,omitempty"` } // ListDeploymentStatuses lists the statuses of a given deployment of a repository. // // GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployment-statuses -func (s *RepositoriesService) ListDeploymentStatuses(owner, repo string, deployment int, opt *ListOptions) ([]DeploymentStatus, *Response, error) { +func (s *RepositoriesService) ListDeploymentStatuses(owner, repo string, deployment int, opt *ListOptions) ([]*DeploymentStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) u, err := addOptions(u, opt) if err != nil { @@ -132,7 +146,7 @@ func (s *RepositoriesService) ListDeploymentStatuses(owner, repo string, deploym return nil, nil, err } - statuses := new([]DeploymentStatus) + statuses := new([]*DeploymentStatus) resp, err := s.client.Do(req, statuses) if err != nil { return nil, resp, err @@ -152,6 +166,9 @@ func (s *RepositoriesService) CreateDeploymentStatus(owner, repo string, deploym return nil, nil, err } + // TODO: remove custom Accept header when deployment support fully launches + req.Header.Set("Accept", mediaTypeDeploymentStatusPreview) + d := new(DeploymentStatus) resp, err := s.client.Do(req, d) if err != nil { diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_forks.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_forks.go index 1fec829..92e9f27 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_forks.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_forks.go @@ -20,7 +20,7 @@ type RepositoryListForksOptions struct { // ListForks lists the forks of the specified repository. // // GitHub API docs: http://developer.github.com/v3/repos/forks/#list-forks -func (s *RepositoriesService) ListForks(owner, repo string, opt *RepositoryListForksOptions) ([]Repository, *Response, error) { +func (s *RepositoriesService) ListForks(owner, repo string, opt *RepositoryListForksOptions) ([]*Repository, *Response, error) { u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -32,7 +32,7 @@ func (s *RepositoriesService) ListForks(owner, repo string, opt *RepositoryListF return nil, nil, err } - repos := new([]Repository) + repos := new([]*Repository) resp, err := s.client.Do(req, repos) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_hooks.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_hooks.go index 4370c16..fe725b4 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_hooks.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_hooks.go @@ -105,7 +105,7 @@ func (s *RepositoriesService) CreateHook(owner, repo string, hook *Hook) (*Hook, // ListHooks lists all Hooks for the specified repository. // // GitHub API docs: http://developer.github.com/v3/repos/hooks/#list -func (s *RepositoriesService) ListHooks(owner, repo string, opt *ListOptions) ([]Hook, *Response, error) { +func (s *RepositoriesService) ListHooks(owner, repo string, opt *ListOptions) ([]*Hook, *Response, error) { u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -117,7 +117,7 @@ func (s *RepositoriesService) ListHooks(owner, repo string, opt *ListOptions) ([ return nil, nil, err } - hooks := new([]Hook) + hooks := new([]*Hook) resp, err := s.client.Do(req, hooks) if err != nil { return nil, resp, err @@ -191,6 +191,6 @@ func (s *RepositoriesService) TestHook(owner, repo string, id int) (*Response, e } // ListServiceHooks is deprecated. Use Client.ListServiceHooks instead. -func (s *RepositoriesService) ListServiceHooks() ([]ServiceHook, *Response, error) { +func (s *RepositoriesService) ListServiceHooks() ([]*ServiceHook, *Response, error) { return s.client.ListServiceHooks() } diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_invitations.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_invitations.go new file mode 100644 index 0000000..f2806d1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_invitations.go @@ -0,0 +1,91 @@ +// Copyright 2016 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import "fmt" + +// RepositoryInvitation represents an invitation to collaborate on a repo. +type RepositoryInvitation struct { + ID *int `json:"id,omitempty"` + Repo *Repository `json:"repository,omitempty"` + Invitee *User `json:"invitee,omitempty"` + Inviter *User `json:"inviter,omitempty"` + + // Permissions represents the permissions that the associated user will have + // on the repository. Possible values are: "read", "write", "admin". + Permissions *string `json:"permissions,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + URL *string `json:"url,omitempty"` + HTMLURL *string `json:"html_url,omitempty"` +} + +// ListInvitations lists all currently-open repository invitations. +// +// GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-invitations-for-a-repository +func (s *RepositoriesService) ListInvitations(repoID int, opt *ListOptions) ([]*RepositoryInvitation, *Response, error) { + u := fmt.Sprintf("repositories/%v/invitations", repoID) + 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", mediaTypeRepositoryInvitationsPreview) + + invites := []*RepositoryInvitation{} + resp, err := s.client.Do(req, &invites) + if err != nil { + return nil, resp, err + } + + return invites, resp, err +} + +// DeleteInvitation deletes a repository invitation. +// +// GitHub API docs: https://developer.github.com/v3/repos/invitations/#delete-a-repository-invitation +func (s *RepositoriesService) DeleteInvitation(repoID, invitationID int) (*Response, error) { + u := fmt.Sprintf("repositories/%v/invitations/%v", repoID, invitationID) + 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", mediaTypeRepositoryInvitationsPreview) + + return s.client.Do(req, nil) +} + +// UpdateInvitation updates the permissions associated with a repository +// invitation. +// +// permissions represents the permissions that the associated user will have +// on the repository. Possible values are: "read", "write", "admin". +// +// GitHub API docs: https://developer.github.com/v3/repos/invitations/#update-a-repository-invitation +func (s *RepositoriesService) UpdateInvitation(repoID, invitationID int, permissions string) (*RepositoryInvitation, *Response, error) { + opts := &struct { + Permissions string `json:"permissions"` + }{Permissions: permissions} + u := fmt.Sprintf("repositories/%v/invitations/%v", repoID, invitationID) + req, err := s.client.NewRequest("PATCH", u, opts) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) + + invite := &RepositoryInvitation{} + resp, err := s.client.Do(req, invite) + return invite, resp, err +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_keys.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_keys.go index 0d12ec9..0bb404a 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_keys.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_keys.go @@ -12,7 +12,7 @@ import "fmt" // ListKeys lists the deploy keys for a repository. // // GitHub API docs: http://developer.github.com/v3/repos/keys/#list -func (s *RepositoriesService) ListKeys(owner string, repo string, opt *ListOptions) ([]Key, *Response, error) { +func (s *RepositoriesService) ListKeys(owner string, repo string, opt *ListOptions) ([]*Key, *Response, error) { u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -24,7 +24,7 @@ func (s *RepositoriesService) ListKeys(owner string, repo string, opt *ListOptio return nil, nil, err } - keys := new([]Key) + keys := new([]*Key) resp, err := s.client.Do(req, keys) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_pages.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_pages.go index 2384eaf..8594edc 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_pages.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_pages.go @@ -54,14 +54,14 @@ func (s *RepositoriesService) GetPagesInfo(owner string, repo string) (*Pages, * // ListPagesBuilds lists the builds for a GitHub Pages site. // // GitHub API docs: https://developer.github.com/v3/repos/pages/#list-pages-builds -func (s *RepositoriesService) ListPagesBuilds(owner string, repo string) ([]PagesBuild, *Response, error) { +func (s *RepositoriesService) ListPagesBuilds(owner string, repo string) ([]*PagesBuild, *Response, error) { u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - var pages []PagesBuild + var pages []*PagesBuild resp, err := s.client.Do(req, &pages) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go index 4e4e2ab..e889b0d 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_releases.go @@ -10,8 +10,10 @@ import ( "fmt" "io" "mime" + "net/http" "os" "path/filepath" + "strings" ) // RepositoryRelease represents a GitHub release in a repository. @@ -32,6 +34,7 @@ type RepositoryRelease struct { UploadURL *string `json:"upload_url,omitempty"` ZipballURL *string `json:"zipball_url,omitempty"` TarballURL *string `json:"tarball_url,omitempty"` + Author *CommitAuthor `json:"author,omitempty"` } func (r RepositoryRelease) String() string { @@ -61,7 +64,7 @@ func (r ReleaseAsset) String() string { // ListReleases lists the releases for a repository. // // GitHub API docs: http://developer.github.com/v3/repos/releases/#list-releases-for-a-repository -func (s *RepositoriesService) ListReleases(owner, repo string, opt *ListOptions) ([]RepositoryRelease, *Response, error) { +func (s *RepositoriesService) ListReleases(owner, repo string, opt *ListOptions) ([]*RepositoryRelease, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) u, err := addOptions(u, opt) if err != nil { @@ -73,7 +76,7 @@ func (s *RepositoriesService) ListReleases(owner, repo string, opt *ListOptions) return nil, nil, err } - releases := new([]RepositoryRelease) + releases := new([]*RepositoryRelease) resp, err := s.client.Do(req, releases) if err != nil { return nil, resp, err @@ -173,7 +176,7 @@ func (s *RepositoriesService) DeleteRelease(owner, repo string, id int) (*Respon // ListReleaseAssets lists the release's assets. // // GitHub API docs : http://developer.github.com/v3/repos/releases/#list-assets-for-a-release -func (s *RepositoriesService) ListReleaseAssets(owner, repo string, id int, opt *ListOptions) ([]ReleaseAsset, *Response, error) { +func (s *RepositoriesService) ListReleaseAssets(owner, repo string, id int, opt *ListOptions) ([]*ReleaseAsset, *Response, error) { u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) u, err := addOptions(u, opt) if err != nil { @@ -185,7 +188,7 @@ func (s *RepositoriesService) ListReleaseAssets(owner, repo string, id int, opt return nil, nil, err } - assets := new([]ReleaseAsset) + assets := new([]*ReleaseAsset) resp, err := s.client.Do(req, assets) if err != nil { return nil, resp, nil @@ -212,27 +215,48 @@ func (s *RepositoriesService) GetReleaseAsset(owner, repo string, id int) (*Rele return asset, resp, err } -// DownloadReleaseAsset downloads a release asset. +// DownloadReleaseAsset downloads a release asset or returns a redirect URL. // // DownloadReleaseAsset returns an io.ReadCloser that reads the contents of the // specified release asset. It is the caller's responsibility to close the ReadCloser. +// If a redirect is returned, the redirect URL will be returned as a string instead +// of the io.ReadCloser. Exactly one of rc and redirectURL will be zero. // // GitHub API docs : http://developer.github.com/v3/repos/releases/#get-a-single-release-asset -func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) (io.ReadCloser, error) { +func (s *RepositoriesService) DownloadReleaseAsset(owner, repo string, id int) (rc io.ReadCloser, redirectURL string, err error) { u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) req, err := s.client.NewRequest("GET", u, nil) if err != nil { - return nil, err + return nil, "", err } req.Header.Set("Accept", defaultMediaType) + s.client.clientMu.Lock() + defer s.client.clientMu.Unlock() + + var loc string + saveRedirect := s.client.client.CheckRedirect + s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + loc = req.URL.String() + return errors.New("disable redirect") + } + defer func() { s.client.client.CheckRedirect = saveRedirect }() + resp, err := s.client.client.Do(req) if err != nil { - return nil, err + if !strings.Contains(err.Error(), "disable redirect") { + return nil, "", err + } + return nil, loc, nil } - return resp.Body, nil + if err := CheckResponse(resp); err != nil { + resp.Body.Close() + return nil, "", err + } + + return resp.Body, "", nil } // EditReleaseAsset edits a repository release asset. diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_stats.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_stats.go index 3474b55..e4f75a5 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_stats.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_stats.go @@ -45,14 +45,14 @@ func (w WeeklyStats) String() string { // delay of a second or so, should result in a successful request. // // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#contributors -func (s *RepositoriesService) ListContributorsStats(owner, repo string) ([]ContributorStats, *Response, error) { +func (s *RepositoriesService) ListContributorsStats(owner, repo string) ([]*ContributorStats, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/contributors", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - var contributorStats []ContributorStats + var contributorStats []*ContributorStats resp, err := s.client.Do(req, &contributorStats) if err != nil { return nil, resp, err @@ -84,14 +84,14 @@ func (w WeeklyCommitActivity) String() string { // delay of a second or so, should result in a successful request. // // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#commit-activity -func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]WeeklyCommitActivity, *Response, error) { +func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]*WeeklyCommitActivity, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/commit_activity", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { return nil, nil, err } - var weeklyCommitActivity []WeeklyCommitActivity + var weeklyCommitActivity []*WeeklyCommitActivity resp, err := s.client.Do(req, &weeklyCommitActivity) if err != nil { return nil, resp, err @@ -105,7 +105,7 @@ func (s *RepositoriesService) ListCommitActivity(owner, repo string) ([]WeeklyCo // additions and deletions, but not total commits. // // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#code-frequency -func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]WeeklyStats, *Response, error) { +func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]*WeeklyStats, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/code_frequency", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -116,12 +116,12 @@ func (s *RepositoriesService) ListCodeFrequency(owner, repo string) ([]WeeklySta resp, err := s.client.Do(req, &weeks) // convert int slices into WeeklyStats - var stats []WeeklyStats + var stats []*WeeklyStats for _, week := range weeks { if len(week) != 3 { continue } - stat := WeeklyStats{ + stat := &WeeklyStats{ Week: &Timestamp{time.Unix(int64(week[0]), 0)}, Additions: Int(week[1]), Deletions: Int(week[2]), @@ -186,7 +186,7 @@ type PunchCard struct { // ListPunchCard returns the number of commits per hour in each day. // // GitHub API Docs: https://developer.github.com/v3/repos/statistics/#punch-card -func (s *RepositoriesService) ListPunchCard(owner, repo string) ([]PunchCard, *Response, error) { +func (s *RepositoriesService) ListPunchCard(owner, repo string) ([]*PunchCard, *Response, error) { u := fmt.Sprintf("repos/%v/%v/stats/punch_card", owner, repo) req, err := s.client.NewRequest("GET", u, nil) if err != nil { @@ -197,12 +197,12 @@ func (s *RepositoriesService) ListPunchCard(owner, repo string) ([]PunchCard, *R resp, err := s.client.Do(req, &results) // convert int slices into Punchcards - var cards []PunchCard + var cards []*PunchCard for _, result := range results { if len(result) != 3 { continue } - card := PunchCard{ + card := &PunchCard{ Day: Int(result[0]), Hour: Int(result[1]), Commits: Int(result[2]), diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/repos_statuses.go b/Godeps/_workspace/src/github.com/google/go-github/github/repos_statuses.go index 7a6ee7c..6478ee2 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/repos_statuses.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/repos_statuses.go @@ -42,7 +42,7 @@ func (r RepoStatus) String() string { // reference. ref can be a SHA, a branch name, or a tag name. // // GitHub API docs: http://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref -func (s *RepositoriesService) ListStatuses(owner, repo, ref string, opt *ListOptions) ([]RepoStatus, *Response, error) { +func (s *RepositoriesService) ListStatuses(owner, repo, ref string, opt *ListOptions) ([]*RepoStatus, *Response, error) { u := fmt.Sprintf("repos/%v/%v/commits/%v/statuses", owner, repo, ref) u, err := addOptions(u, opt) if err != nil { @@ -54,7 +54,7 @@ func (s *RepositoriesService) ListStatuses(owner, repo, ref string, opt *ListOpt return nil, nil, err } - statuses := new([]RepoStatus) + statuses := new([]*RepoStatus) resp, err := s.client.Do(req, statuses) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/search.go b/Godeps/_workspace/src/github.com/google/go-github/github/search.go index d9e9b41..073b6c0 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/search.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/search.go @@ -148,7 +148,7 @@ func (s *SearchService) search(searchType string, query string, opt *SearchOptio return nil, err } - if opt.TextMatch { + if opt != nil && opt.TextMatch { // Accept header defaults to "application/vnd.github.v3+json" // We change it here to fetch back text-match metadata req.Header.Set("Accept", "application/vnd.github.v3.text-match+json") diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/users.go b/Godeps/_workspace/src/github.com/google/go-github/github/users.go index d8c74e2..1720804 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/users.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/users.go @@ -95,6 +95,25 @@ func (s *UsersService) Get(user string) (*User, *Response, error) { return uResp, resp, err } +// GetByID fetches a user. +// +// Note: GetByID uses the undocumented GitHub API endpoint /user/:id. +func (s *UsersService) GetByID(id int) (*User, *Response, error) { + u := fmt.Sprintf("user/%d", id) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + user := new(User) + resp, err := s.client.Do(req, user) + if err != nil { + return nil, resp, err + } + + return user, resp, err +} + // Edit the authenticated user. // // GitHub API docs: http://developer.github.com/v3/users/#update-the-authenticated-user @@ -119,12 +138,16 @@ func (s *UsersService) Edit(user *User) (*User, *Response, error) { type UserListOptions struct { // ID of the last user seen Since int `url:"since,omitempty"` + + ListOptions } // ListAll lists all GitHub users. // +// To paginate through all users, populate 'Since' with the ID of the last user. +// // GitHub API docs: http://developer.github.com/v3/users/#get-all-users -func (s *UsersService) ListAll(opt *UserListOptions) ([]User, *Response, error) { +func (s *UsersService) ListAll(opt *UserListOptions) ([]*User, *Response, error) { u, err := addOptions("users", opt) if err != nil { return nil, nil, err @@ -135,7 +158,7 @@ func (s *UsersService) ListAll(opt *UserListOptions) ([]User, *Response, error) return nil, nil, err } - users := new([]User) + users := new([]*User) resp, err := s.client.Do(req, users) if err != nil { return nil, resp, err @@ -143,3 +166,59 @@ func (s *UsersService) ListAll(opt *UserListOptions) ([]User, *Response, error) return *users, resp, err } + +// ListInvitations lists all currently-open repository invitations for the +// authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/repos/invitations/#list-a-users-repository-invitations +func (s *UsersService) ListInvitations() ([]*RepositoryInvitation, *Response, error) { + req, err := s.client.NewRequest("GET", "user/repository_invitations", nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) + + invites := []*RepositoryInvitation{} + resp, err := s.client.Do(req, &invites) + if err != nil { + return nil, resp, err + } + + return invites, resp, err +} + +// AcceptInvitation accepts the currently-open repository invitation for the +// authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/repos/invitations/#accept-a-repository-invitation +func (s *UsersService) AcceptInvitation(invitationID int) (*Response, error) { + u := fmt.Sprintf("user/repository_invitations/%v", invitationID) + req, err := s.client.NewRequest("PATCH", u, nil) + if err != nil { + return nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeRepositoryInvitationsPreview) + + return s.client.Do(req, nil) +} + +// DeclineInvitation declines the currently-open repository invitation for the +// authenticated user. +// +// GitHub API docs: https://developer.github.com/v3/repos/invitations/#decline-a-repository-invitation +func (s *UsersService) DeclineInvitation(invitationID int) (*Response, error) { + u := fmt.Sprintf("user/repository_invitations/%v", invitationID) + 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", mediaTypeRepositoryInvitationsPreview) + + return s.client.Do(req, nil) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/users_emails.go b/Godeps/_workspace/src/github.com/google/go-github/github/users_emails.go index 7553191..e4a5898 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/users_emails.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/users_emails.go @@ -15,7 +15,7 @@ type UserEmail struct { // ListEmails lists all email addresses for the authenticated user. // // GitHub API docs: http://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user -func (s *UsersService) ListEmails(opt *ListOptions) ([]UserEmail, *Response, error) { +func (s *UsersService) ListEmails(opt *ListOptions) ([]*UserEmail, *Response, error) { u := "user/emails" u, err := addOptions(u, opt) if err != nil { @@ -27,7 +27,7 @@ func (s *UsersService) ListEmails(opt *ListOptions) ([]UserEmail, *Response, err return nil, nil, err } - emails := new([]UserEmail) + emails := new([]*UserEmail) resp, err := s.client.Do(req, emails) if err != nil { return nil, resp, err @@ -39,14 +39,14 @@ func (s *UsersService) ListEmails(opt *ListOptions) ([]UserEmail, *Response, err // AddEmails adds email addresses of the authenticated user. // // GitHub API docs: http://developer.github.com/v3/users/emails/#add-email-addresses -func (s *UsersService) AddEmails(emails []string) ([]UserEmail, *Response, error) { +func (s *UsersService) AddEmails(emails []string) ([]*UserEmail, *Response, error) { u := "user/emails" req, err := s.client.NewRequest("POST", u, emails) if err != nil { return nil, nil, err } - e := new([]UserEmail) + e := new([]*UserEmail) resp, err := s.client.Do(req, e) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/users_followers.go b/Godeps/_workspace/src/github.com/google/go-github/github/users_followers.go index 7ecbed9..38a1662 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/users_followers.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/users_followers.go @@ -11,7 +11,7 @@ import "fmt" // fetch followers for the authenticated user. // // GitHub API docs: http://developer.github.com/v3/users/followers/#list-followers-of-a-user -func (s *UsersService) ListFollowers(user string, opt *ListOptions) ([]User, *Response, error) { +func (s *UsersService) ListFollowers(user string, opt *ListOptions) ([]*User, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/followers", user) @@ -28,7 +28,7 @@ func (s *UsersService) ListFollowers(user string, opt *ListOptions) ([]User, *Re return nil, nil, err } - users := new([]User) + users := new([]*User) resp, err := s.client.Do(req, users) if err != nil { return nil, resp, err @@ -41,7 +41,7 @@ func (s *UsersService) ListFollowers(user string, opt *ListOptions) ([]User, *Re // string will list people the authenticated user is following. // // GitHub API docs: http://developer.github.com/v3/users/followers/#list-users-followed-by-another-user -func (s *UsersService) ListFollowing(user string, opt *ListOptions) ([]User, *Response, error) { +func (s *UsersService) ListFollowing(user string, opt *ListOptions) ([]*User, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/following", user) @@ -58,7 +58,7 @@ func (s *UsersService) ListFollowing(user string, opt *ListOptions) ([]User, *Re return nil, nil, err } - users := new([]User) + users := new([]*User) resp, err := s.client.Do(req, users) if err != nil { return nil, resp, err diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/users_gpg_keys.go b/Godeps/_workspace/src/github.com/google/go-github/github/users_gpg_keys.go new file mode 100644 index 0000000..08cfbed --- /dev/null +++ b/Godeps/_workspace/src/github.com/google/go-github/github/users_gpg_keys.go @@ -0,0 +1,127 @@ +// Copyright 2016 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "fmt" + "time" +) + +// GPGKey represents a GitHub user's public GPG key used to verify GPG signed commits and tags. +// +// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/ +type GPGKey struct { + ID *int `json:"id,omitempty"` + PrimaryKeyID *int `json:"primary_key_id,omitempty"` + KeyID *string `json:"key_id,omitempty"` + PublicKey *string `json:"public_key,omitempty"` + Emails []GPGEmail `json:"emails,omitempty"` + Subkeys []GPGKey `json:"subkeys,omitempty"` + CanSign *bool `json:"can_sign,omitempty"` + CanEncryptComms *bool `json:"can_encrypt_comms,omitempty"` + CanEncryptStorage *bool `json:"can_encrypt_storage,omitempty"` + CanCertify *bool `json:"can_certify,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + ExpiresAt *time.Time `json:"expires_at,omitempty"` +} + +// String stringifies a GPGKey. +func (k GPGKey) String() string { + return Stringify(k) +} + +// GPGEmail represents an email address associated to a GPG key. +type GPGEmail struct { + Email *string `json:"email,omitempty"` + Verified *bool `json:"verified,omitempty"` +} + +// ListGPGKeys lists the current user's GPG keys. It requires authentication +// via Basic Auth or via OAuth with at least read:gpg_key scope. +// +// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-your-gpg-keys +func (s *UsersService) ListGPGKeys() ([]*GPGKey, *Response, error) { + req, err := s.client.NewRequest("GET", "user/gpg_keys", nil) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeGitSigningPreview) + + var keys []*GPGKey + resp, err := s.client.Do(req, &keys) + if err != nil { + return nil, resp, err + } + + return keys, resp, err +} + +// GetGPGKey gets extended details for a single GPG key. It requires authentication +// via Basic Auth or via OAuth with at least read:gpg_key scope. +// +// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#get-a-single-gpg-key +func (s *UsersService) GetGPGKey(id int) (*GPGKey, *Response, error) { + u := fmt.Sprintf("user/gpg_keys/%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", mediaTypeGitSigningPreview) + + key := &GPGKey{} + resp, err := s.client.Do(req, key) + if err != nil { + return nil, resp, err + } + + return key, resp, err +} + +// CreateGPGKey creates a GPG key. It requires authenticatation via Basic Auth +// or OAuth with at least write:gpg_key scope. +// +// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#create-a-gpg-key +func (s *UsersService) CreateGPGKey(armoredPublicKey string) (*GPGKey, *Response, error) { + gpgKey := &struct { + ArmoredPublicKey string `json:"armored_public_key"` + }{ArmoredPublicKey: armoredPublicKey} + req, err := s.client.NewRequest("POST", "user/gpg_keys", gpgKey) + if err != nil { + return nil, nil, err + } + + // TODO: remove custom Accept header when this API fully launches. + req.Header.Set("Accept", mediaTypeGitSigningPreview) + + key := &GPGKey{} + resp, err := s.client.Do(req, key) + if err != nil { + return nil, resp, err + } + + return key, resp, err +} + +// DeleteGPGKey deletes a GPG key. It requires authentication via Basic Auth or +// via OAuth with at least admin:gpg_key scope. +// +// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#delete-a-gpg-key +func (s *UsersService) DeleteGPGKey(id int) (*Response, error) { + u := fmt.Sprintf("user/gpg_keys/%v", id) + 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", mediaTypeGitSigningPreview) + + return s.client.Do(req, nil) +} diff --git a/Godeps/_workspace/src/github.com/google/go-github/github/users_keys.go b/Godeps/_workspace/src/github.com/google/go-github/github/users_keys.go index dcbd773..6a663f5 100644 --- a/Godeps/_workspace/src/github.com/google/go-github/github/users_keys.go +++ b/Godeps/_workspace/src/github.com/google/go-github/github/users_keys.go @@ -23,7 +23,7 @@ func (k Key) String() string { // string will fetch keys for the authenticated user. // // GitHub API docs: http://developer.github.com/v3/users/keys/#list-public-keys-for-a-user -func (s *UsersService) ListKeys(user string, opt *ListOptions) ([]Key, *Response, error) { +func (s *UsersService) ListKeys(user string, opt *ListOptions) ([]*Key, *Response, error) { var u string if user != "" { u = fmt.Sprintf("users/%v/keys", user) @@ -40,7 +40,7 @@ func (s *UsersService) ListKeys(user string, opt *ListOptions) ([]Key, *Response return nil, nil, err } - keys := new([]Key) + keys := new([]*Key) resp, err := s.client.Do(req, keys) if err != nil { return nil, resp, err diff --git a/github.go b/github.go index 7246fa0..0a1a47a 100644 --- a/github.go +++ b/github.go @@ -79,10 +79,10 @@ func NewGitHubClient(source Source) (*GitHubClient, error) { }, nil } -func (g *GitHubClient) ListReleases() ([]github.RepositoryRelease, error) { +func (g *GitHubClient) ListReleases() ([]*github.RepositoryRelease, error) { releases, res, err := g.client.Repositories.ListReleases(g.user, g.repository, nil) if err != nil { - return []github.RepositoryRelease{}, err + return []*github.RepositoryRelease{}, err } err = res.Body.Close() @@ -153,10 +153,10 @@ func (g *GitHubClient) UpdateRelease(release github.RepositoryRelease) (*github. return updatedRelease, nil } -func (g *GitHubClient) ListReleaseAssets(release github.RepositoryRelease) ([]github.ReleaseAsset, error) { +func (g *GitHubClient) ListReleaseAssets(release github.RepositoryRelease) ([]*github.ReleaseAsset, error) { assets, res, err := g.client.Repositories.ListReleaseAssets(g.user, g.repository, *release.ID, nil) if err != nil { - return []github.ReleaseAsset{}, err + return []*github.ReleaseAsset{}, err } err = res.Body.Close() @@ -194,7 +194,7 @@ func (g *GitHubClient) DeleteReleaseAsset(asset github.ReleaseAsset) error { } func (g *GitHubClient) DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadCloser, error) { - res, err := g.client.Repositories.DownloadReleaseAsset(g.user, g.repository, *asset.ID) + res, _, err := g.client.Repositories.DownloadReleaseAsset(g.user, g.repository, *asset.ID) if err != nil { return nil, err }