mirror of https://github.com/gogits/gogs.git
Lu, Haixun
7 years ago
87 changed files with 27719 additions and 0 deletions
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2013 The go-github AUTHORS. All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above |
||||
copyright notice, this list of conditions and the following disclaimer |
||||
in the documentation and/or other materials provided with the |
||||
distribution. |
||||
* Neither the name of Google Inc. nor the names of its |
||||
contributors may be used to endorse or promote products derived from |
||||
this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,69 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import "context" |
||||
|
||||
// ActivityService handles communication with the activity related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/
|
||||
type ActivityService service |
||||
|
||||
// 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(ctx context.Context) (*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(ctx, req, f) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return f, resp, nil |
||||
} |
@ -0,0 +1,324 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// Event represents a GitHub event.
|
||||
type Event struct { |
||||
Type *string `json:"type,omitempty"` |
||||
Public *bool `json:"public,omitempty"` |
||||
RawPayload *json.RawMessage `json:"payload,omitempty"` |
||||
Repo *Repository `json:"repo,omitempty"` |
||||
Actor *User `json:"actor,omitempty"` |
||||
Org *Organization `json:"org,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
ID *string `json:"id,omitempty"` |
||||
} |
||||
|
||||
func (e Event) String() string { |
||||
return Stringify(e) |
||||
} |
||||
|
||||
// ParsePayload parses the event payload. For recognized event types,
|
||||
// a value of the corresponding struct type will be returned.
|
||||
func (e *Event) ParsePayload() (payload interface{}, err error) { |
||||
switch *e.Type { |
||||
case "CommitCommentEvent": |
||||
payload = &CommitCommentEvent{} |
||||
case "CreateEvent": |
||||
payload = &CreateEvent{} |
||||
case "DeleteEvent": |
||||
payload = &DeleteEvent{} |
||||
case "DeploymentEvent": |
||||
payload = &DeploymentEvent{} |
||||
case "DeploymentStatusEvent": |
||||
payload = &DeploymentStatusEvent{} |
||||
case "ForkEvent": |
||||
payload = &ForkEvent{} |
||||
case "GollumEvent": |
||||
payload = &GollumEvent{} |
||||
case "InstallationEvent": |
||||
payload = &InstallationEvent{} |
||||
case "InstallationRepositoriesEvent": |
||||
payload = &InstallationRepositoriesEvent{} |
||||
case "IssueCommentEvent": |
||||
payload = &IssueCommentEvent{} |
||||
case "IssuesEvent": |
||||
payload = &IssuesEvent{} |
||||
case "LabelEvent": |
||||
payload = &LabelEvent{} |
||||
case "MarketplacePurchaseEvent": |
||||
payload = &MarketplacePurchaseEvent{} |
||||
case "MemberEvent": |
||||
payload = &MemberEvent{} |
||||
case "MembershipEvent": |
||||
payload = &MembershipEvent{} |
||||
case "MilestoneEvent": |
||||
payload = &MilestoneEvent{} |
||||
case "OrganizationEvent": |
||||
payload = &OrganizationEvent{} |
||||
case "OrgBlockEvent": |
||||
payload = &OrgBlockEvent{} |
||||
case "PageBuildEvent": |
||||
payload = &PageBuildEvent{} |
||||
case "PingEvent": |
||||
payload = &PingEvent{} |
||||
case "ProjectEvent": |
||||
payload = &ProjectEvent{} |
||||
case "ProjectCardEvent": |
||||
payload = &ProjectCardEvent{} |
||||
case "ProjectColumnEvent": |
||||
payload = &ProjectColumnEvent{} |
||||
case "PublicEvent": |
||||
payload = &PublicEvent{} |
||||
case "PullRequestEvent": |
||||
payload = &PullRequestEvent{} |
||||
case "PullRequestReviewEvent": |
||||
payload = &PullRequestReviewEvent{} |
||||
case "PullRequestReviewCommentEvent": |
||||
payload = &PullRequestReviewCommentEvent{} |
||||
case "PushEvent": |
||||
payload = &PushEvent{} |
||||
case "ReleaseEvent": |
||||
payload = &ReleaseEvent{} |
||||
case "RepositoryEvent": |
||||
payload = &RepositoryEvent{} |
||||
case "StatusEvent": |
||||
payload = &StatusEvent{} |
||||
case "TeamEvent": |
||||
payload = &TeamEvent{} |
||||
case "TeamAddEvent": |
||||
payload = &TeamAddEvent{} |
||||
case "WatchEvent": |
||||
payload = &WatchEvent{} |
||||
} |
||||
err = json.Unmarshal(*e.RawPayload, &payload) |
||||
return payload, err |
||||
} |
||||
|
||||
// Payload returns the parsed event payload. For recognized event types,
|
||||
// a value of the corresponding struct type will be returned.
|
||||
//
|
||||
// Deprecated: Use ParsePayload instead, which returns an error
|
||||
// rather than panics if JSON unmarshaling raw payload fails.
|
||||
func (e *Event) Payload() (payload interface{}) { |
||||
var err error |
||||
payload, err = e.ParsePayload() |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return payload |
||||
} |
||||
|
||||
// ListEvents drinks from the firehose of all public events across GitHub.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events
|
||||
func (s *ActivityService) ListEvents(ctx context.Context, opt *ListOptions) ([]*Event, *Response, error) { |
||||
u, err := addOptions("events", opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*Event |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// ListRepositoryEvents lists events for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-repository-events
|
||||
func (s *ActivityService) ListRepositoryEvents(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*Event |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// ListIssueEventsForRepository lists issue events for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository
|
||||
func (s *ActivityService) ListIssueEventsForRepository(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*IssueEvent |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// ListEventsForRepoNetwork lists public events for a network of repositories.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-a-network-of-repositories
|
||||
func (s *ActivityService) ListEventsForRepoNetwork(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*Event |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// ListEventsForOrganization lists public events for an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-public-events-for-an-organization
|
||||
func (s *ActivityService) ListEventsForOrganization(ctx context.Context, org string, opt *ListOptions) ([]*Event, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/events", org) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*Event |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// ListEventsPerformedByUser lists the events performed by a user. If publicOnly is
|
||||
// true, only public events will be returned.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-performed-by-a-user
|
||||
func (s *ActivityService) ListEventsPerformedByUser(ctx context.Context, user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { |
||||
var u string |
||||
if publicOnly { |
||||
u = fmt.Sprintf("users/%v/events/public", user) |
||||
} else { |
||||
u = fmt.Sprintf("users/%v/events", user) |
||||
} |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*Event |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// ListEventsReceivedByUser lists the events received by a user. If publicOnly is
|
||||
// true, only public events will be returned.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-that-a-user-has-received
|
||||
func (s *ActivityService) ListEventsReceivedByUser(ctx context.Context, user string, publicOnly bool, opt *ListOptions) ([]*Event, *Response, error) { |
||||
var u string |
||||
if publicOnly { |
||||
u = fmt.Sprintf("users/%v/received_events/public", user) |
||||
} else { |
||||
u = fmt.Sprintf("users/%v/received_events", user) |
||||
} |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*Event |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// ListUserEventsForOrganization provides the user’s organization dashboard. You
|
||||
// must be authenticated as the user to view this.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/#list-events-for-an-organization
|
||||
func (s *ActivityService) ListUserEventsForOrganization(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*Event |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
@ -0,0 +1,223 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// Notification identifies a GitHub notification for a user.
|
||||
type Notification struct { |
||||
ID *string `json:"id,omitempty"` |
||||
Repository *Repository `json:"repository,omitempty"` |
||||
Subject *NotificationSubject `json:"subject,omitempty"` |
||||
|
||||
// Reason identifies the event that triggered the notification.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#notification-reasons
|
||||
Reason *string `json:"reason,omitempty"` |
||||
|
||||
Unread *bool `json:"unread,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
LastReadAt *time.Time `json:"last_read_at,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
} |
||||
|
||||
// NotificationSubject identifies the subject of a notification.
|
||||
type NotificationSubject struct { |
||||
Title *string `json:"title,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
LatestCommentURL *string `json:"latest_comment_url,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
} |
||||
|
||||
// NotificationListOptions specifies the optional parameters to the
|
||||
// ActivityService.ListNotifications method.
|
||||
type NotificationListOptions struct { |
||||
All bool `url:"all,omitempty"` |
||||
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(ctx context.Context, opt *NotificationListOptions) ([]*Notification, *Response, error) { |
||||
u := fmt.Sprintf("notifications") |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var notifications []*Notification |
||||
resp, err := s.client.Do(ctx, req, ¬ifications) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return notifications, resp, nil |
||||
} |
||||
|
||||
// ListRepositoryNotifications lists all notifications in a given repository
|
||||
// for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#list-your-notifications-in-a-repository
|
||||
func (s *ActivityService) ListRepositoryNotifications(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var notifications []*Notification |
||||
resp, err := s.client.Do(ctx, req, ¬ifications) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return notifications, resp, nil |
||||
} |
||||
|
||||
type markReadOptions struct { |
||||
LastReadAt time.Time `json:"last_read_at,omitempty"` |
||||
} |
||||
|
||||
// MarkNotificationsRead marks all notifications up to lastRead as read.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-as-read
|
||||
func (s *ActivityService) MarkNotificationsRead(ctx context.Context, lastRead time.Time) (*Response, error) { |
||||
opts := &markReadOptions{ |
||||
LastReadAt: lastRead, |
||||
} |
||||
req, err := s.client.NewRequest("PUT", "notifications", opts) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// MarkRepositoryNotificationsRead marks all notifications up to lastRead in
|
||||
// the specified repository as read.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository
|
||||
func (s *ActivityService) MarkRepositoryNotificationsRead(ctx context.Context, owner, repo string, lastRead time.Time) (*Response, error) { |
||||
opts := &markReadOptions{ |
||||
LastReadAt: lastRead, |
||||
} |
||||
u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo) |
||||
req, err := s.client.NewRequest("PUT", u, opts) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// GetThread gets the specified notification thread.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#view-a-single-thread
|
||||
func (s *ActivityService) GetThread(ctx context.Context, id string) (*Notification, *Response, error) { |
||||
u := fmt.Sprintf("notifications/threads/%v", id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
notification := new(Notification) |
||||
resp, err := s.client.Do(ctx, req, notification) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return notification, resp, nil |
||||
} |
||||
|
||||
// MarkThreadRead marks the specified thread as read.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-a-thread-as-read
|
||||
func (s *ActivityService) MarkThreadRead(ctx context.Context, id string) (*Response, error) { |
||||
u := fmt.Sprintf("notifications/threads/%v", id) |
||||
|
||||
req, err := s.client.NewRequest("PATCH", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// GetThreadSubscription checks to see if the authenticated user is subscribed
|
||||
// to a thread.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#get-a-thread-subscription
|
||||
func (s *ActivityService) GetThreadSubscription(ctx context.Context, id string) (*Subscription, *Response, error) { |
||||
u := fmt.Sprintf("notifications/threads/%v/subscription", id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
sub := new(Subscription) |
||||
resp, err := s.client.Do(ctx, req, sub) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return sub, resp, nil |
||||
} |
||||
|
||||
// SetThreadSubscription sets the subscription for the specified thread for the
|
||||
// authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#set-a-thread-subscription
|
||||
func (s *ActivityService) SetThreadSubscription(ctx context.Context, id string, subscription *Subscription) (*Subscription, *Response, error) { |
||||
u := fmt.Sprintf("notifications/threads/%v/subscription", id) |
||||
|
||||
req, err := s.client.NewRequest("PUT", u, subscription) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
sub := new(Subscription) |
||||
resp, err := s.client.Do(ctx, req, sub) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return sub, resp, nil |
||||
} |
||||
|
||||
// DeleteThreadSubscription deletes the subscription for the specified thread
|
||||
// for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#delete-a-thread-subscription
|
||||
func (s *ActivityService) DeleteThreadSubscription(ctx context.Context, id string) (*Response, error) { |
||||
u := fmt.Sprintf("notifications/threads/%v/subscription", id) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,135 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// StarredRepository is returned by ListStarred.
|
||||
type StarredRepository struct { |
||||
StarredAt *Timestamp `json:"starred_at,omitempty"` |
||||
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(ctx context.Context, 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 { |
||||
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", mediaTypeStarringPreview) |
||||
|
||||
var stargazers []*Stargazer |
||||
resp, err := s.client.Do(ctx, req, &stargazers) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return stargazers, resp, nil |
||||
} |
||||
|
||||
// ActivityListStarredOptions specifies the optional parameters to the
|
||||
// ActivityService.ListStarred method.
|
||||
type ActivityListStarredOptions struct { |
||||
// How to sort the repository list. Possible values are: created, updated,
|
||||
// pushed, full_name. Default is "full_name".
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// Direction in which to sort repositories. Possible values are: asc, desc.
|
||||
// Default is "asc" when sort is "full_name", otherwise default is "desc".
|
||||
Direction string `url:"direction,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListStarred lists all the repos starred by a user. Passing the empty string
|
||||
// will list the starred repositories for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/starring/#list-repositories-being-starred
|
||||
func (s *ActivityService) ListStarred(ctx context.Context, user string, opt *ActivityListStarredOptions) ([]*StarredRepository, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/starred", user) |
||||
} else { |
||||
u = "user/starred" |
||||
} |
||||
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", mediaTypeStarringPreview) |
||||
|
||||
var repos []*StarredRepository |
||||
resp, err := s.client.Do(ctx, req, &repos) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return repos, resp, nil |
||||
} |
||||
|
||||
// IsStarred checks if a repository is starred by authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository
|
||||
func (s *ActivityService) IsStarred(ctx context.Context, owner, repo string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("user/starred/%v/%v", owner, repo) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
starred, err := parseBoolResponse(err) |
||||
return starred, resp, err |
||||
} |
||||
|
||||
// Star a repository as the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/starring/#star-a-repository
|
||||
func (s *ActivityService) Star(ctx context.Context, owner, repo string) (*Response, error) { |
||||
u := fmt.Sprintf("user/starred/%v/%v", owner, repo) |
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// Unstar a repository as the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/starring/#unstar-a-repository
|
||||
func (s *ActivityService) Unstar(ctx context.Context, owner, repo string) (*Response, error) { |
||||
u := fmt.Sprintf("user/starred/%v/%v", owner, repo) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,146 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// Subscription identifies a repository or thread subscription.
|
||||
type Subscription struct { |
||||
Subscribed *bool `json:"subscribed,omitempty"` |
||||
Ignored *bool `json:"ignored,omitempty"` |
||||
Reason *string `json:"reason,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
|
||||
// only populated for repository subscriptions
|
||||
RepositoryURL *string `json:"repository_url,omitempty"` |
||||
|
||||
// only populated for thread subscriptions
|
||||
ThreadURL *string `json:"thread_url,omitempty"` |
||||
} |
||||
|
||||
// ListWatchers lists watchers of a particular repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/watching/#list-watchers
|
||||
func (s *ActivityService) ListWatchers(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var watchers []*User |
||||
resp, err := s.client.Do(ctx, req, &watchers) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return watchers, resp, nil |
||||
} |
||||
|
||||
// ListWatched lists the repositories the specified user is watching. Passing
|
||||
// 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(ctx context.Context, user string, opt *ListOptions) ([]*Repository, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/subscriptions", user) |
||||
} else { |
||||
u = "user/subscriptions" |
||||
} |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var watched []*Repository |
||||
resp, err := s.client.Do(ctx, req, &watched) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return watched, resp, nil |
||||
} |
||||
|
||||
// GetRepositorySubscription returns the subscription for the specified
|
||||
// repository for the authenticated user. If the authenticated user is not
|
||||
// watching the repository, a nil Subscription is returned.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/watching/#get-a-repository-subscription
|
||||
func (s *ActivityService) GetRepositorySubscription(ctx context.Context, owner, repo string) (*Subscription, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
sub := new(Subscription) |
||||
resp, err := s.client.Do(ctx, req, sub) |
||||
if err != nil { |
||||
// if it's just a 404, don't return that as an error
|
||||
_, err = parseBoolResponse(err) |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return sub, resp, nil |
||||
} |
||||
|
||||
// SetRepositorySubscription sets the subscription for the specified repository
|
||||
// for the authenticated user.
|
||||
//
|
||||
// To watch a repository, set subscription.Subscribed to true.
|
||||
// To ignore notifications made within a repository, set subscription.Ignored to true.
|
||||
// To stop watching a repository, use DeleteRepositorySubscription.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/watching/#set-a-repository-subscription
|
||||
func (s *ActivityService) SetRepositorySubscription(ctx context.Context, owner, repo string, subscription *Subscription) (*Subscription, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) |
||||
|
||||
req, err := s.client.NewRequest("PUT", u, subscription) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
sub := new(Subscription) |
||||
resp, err := s.client.Do(ctx, req, sub) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return sub, resp, nil |
||||
} |
||||
|
||||
// DeleteRepositorySubscription deletes the subscription for the specified
|
||||
// repository for the authenticated user.
|
||||
//
|
||||
// This is used to stop watching a repository. To control whether or not to
|
||||
// receive notifications from a repository, use SetRepositorySubscription.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription
|
||||
func (s *ActivityService) DeleteRepositorySubscription(ctx context.Context, owner, repo string) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/subscription", owner, repo) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,101 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// AdminService handles communication with the admin related methods of the
|
||||
// GitHub API. These API routes are normally only accessible for GitHub
|
||||
// Enterprise installations.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/enterprise/
|
||||
type AdminService service |
||||
|
||||
// TeamLDAPMapping represents the mapping between a GitHub team and an LDAP group.
|
||||
type TeamLDAPMapping struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
LDAPDN *string `json:"ldap_dn,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Slug *string `json:"slug,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Privacy *string `json:"privacy,omitempty"` |
||||
Permission *string `json:"permission,omitempty"` |
||||
|
||||
MembersURL *string `json:"members_url,omitempty"` |
||||
RepositoriesURL *string `json:"repositories_url,omitempty"` |
||||
} |
||||
|
||||
func (m TeamLDAPMapping) String() string { |
||||
return Stringify(m) |
||||
} |
||||
|
||||
// UserLDAPMapping represents the mapping between a GitHub user and an LDAP user.
|
||||
type UserLDAPMapping struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
LDAPDN *string `json:"ldap_dn,omitempty"` |
||||
Login *string `json:"login,omitempty"` |
||||
AvatarURL *string `json:"avatar_url,omitempty"` |
||||
GravatarID *string `json:"gravatar_id,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
SiteAdmin *bool `json:"site_admin,omitempty"` |
||||
|
||||
URL *string `json:"url,omitempty"` |
||||
EventsURL *string `json:"events_url,omitempty"` |
||||
FollowingURL *string `json:"following_url,omitempty"` |
||||
FollowersURL *string `json:"followers_url,omitempty"` |
||||
GistsURL *string `json:"gists_url,omitempty"` |
||||
OrganizationsURL *string `json:"organizations_url,omitempty"` |
||||
ReceivedEventsURL *string `json:"received_events_url,omitempty"` |
||||
ReposURL *string `json:"repos_url,omitempty"` |
||||
StarredURL *string `json:"starred_url,omitempty"` |
||||
SubscriptionsURL *string `json:"subscriptions_url,omitempty"` |
||||
} |
||||
|
||||
func (m UserLDAPMapping) String() string { |
||||
return Stringify(m) |
||||
} |
||||
|
||||
// UpdateUserLDAPMapping updates the mapping between a GitHub user and an LDAP user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-user
|
||||
func (s *AdminService) UpdateUserLDAPMapping(ctx context.Context, user string, mapping *UserLDAPMapping) (*UserLDAPMapping, *Response, error) { |
||||
u := fmt.Sprintf("admin/ldap/users/%v/mapping", user) |
||||
req, err := s.client.NewRequest("PATCH", u, mapping) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
m := new(UserLDAPMapping) |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// UpdateTeamLDAPMapping updates the mapping between a GitHub team and an LDAP group.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/enterprise/ldap/#update-ldap-mapping-for-a-team
|
||||
func (s *AdminService) UpdateTeamLDAPMapping(ctx context.Context, team int64, mapping *TeamLDAPMapping) (*TeamLDAPMapping, *Response, error) { |
||||
u := fmt.Sprintf("admin/ldap/teams/%v/mapping", team) |
||||
req, err := s.client.NewRequest("PATCH", u, mapping) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
m := new(TeamLDAPMapping) |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
@ -0,0 +1,171 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// AdminStats represents a variety of stats of a Github Enterprise
|
||||
// installation.
|
||||
type AdminStats struct { |
||||
Issues *IssueStats `json:"issues,omitempty"` |
||||
Hooks *HookStats `json:"hooks,omitempty"` |
||||
Milestones *MilestoneStats `json:"milestones,omitempty"` |
||||
Orgs *OrgStats `json:"orgs,omitempty"` |
||||
Comments *CommentStats `json:"comments,omitempty"` |
||||
Pages *PageStats `json:"pages,omitempty"` |
||||
Users *UserStats `json:"users,omitempty"` |
||||
Gists *GistStats `json:"gists,omitempty"` |
||||
Pulls *PullStats `json:"pulls,omitempty"` |
||||
Repos *RepoStats `json:"repos,omitempty"` |
||||
} |
||||
|
||||
func (s AdminStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// IssueStats represents the number of total, open and closed issues.
|
||||
type IssueStats struct { |
||||
TotalIssues *int `json:"total_issues,omitempty"` |
||||
OpenIssues *int `json:"open_issues,omitempty"` |
||||
ClosedIssues *int `json:"closed_issues,omitempty"` |
||||
} |
||||
|
||||
func (s IssueStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// HookStats represents the number of total, active and inactive hooks.
|
||||
type HookStats struct { |
||||
TotalHooks *int `json:"total_hooks,omitempty"` |
||||
ActiveHooks *int `json:"active_hooks,omitempty"` |
||||
InactiveHooks *int `json:"inactive_hooks,omitempty"` |
||||
} |
||||
|
||||
func (s HookStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// MilestoneStats represents the number of total, open and close milestones.
|
||||
type MilestoneStats struct { |
||||
TotalMilestones *int `json:"total_milestones,omitempty"` |
||||
OpenMilestones *int `json:"open_milestones,omitempty"` |
||||
ClosedMilestones *int `json:"closed_milestones,omitempty"` |
||||
} |
||||
|
||||
func (s MilestoneStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// OrgStats represents the number of total, disabled organizations and the team
|
||||
// and team member count.
|
||||
type OrgStats struct { |
||||
TotalOrgs *int `json:"total_orgs,omitempty"` |
||||
DisabledOrgs *int `json:"disabled_orgs,omitempty"` |
||||
TotalTeams *int `json:"total_teams,omitempty"` |
||||
TotalTeamMembers *int `json:"total_team_members,omitempty"` |
||||
} |
||||
|
||||
func (s OrgStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// CommentStats represents the number of total comments on commits, gists, issues
|
||||
// and pull requests.
|
||||
type CommentStats struct { |
||||
TotalCommitComments *int `json:"total_commit_comments,omitempty"` |
||||
TotalGistComments *int `json:"total_gist_comments,omitempty"` |
||||
TotalIssueComments *int `json:"total_issue_comments,omitempty"` |
||||
TotalPullRequestComments *int `json:"total_pull_request_comments,omitempty"` |
||||
} |
||||
|
||||
func (s CommentStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// PageStats represents the total number of github pages.
|
||||
type PageStats struct { |
||||
TotalPages *int `json:"total_pages,omitempty"` |
||||
} |
||||
|
||||
func (s PageStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// UserStats represents the number of total, admin and suspended users.
|
||||
type UserStats struct { |
||||
TotalUsers *int `json:"total_users,omitempty"` |
||||
AdminUsers *int `json:"admin_users,omitempty"` |
||||
SuspendedUsers *int `json:"suspended_users,omitempty"` |
||||
} |
||||
|
||||
func (s UserStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// GistStats represents the number of total, private and public gists.
|
||||
type GistStats struct { |
||||
TotalGists *int `json:"total_gists,omitempty"` |
||||
PrivateGists *int `json:"private_gists,omitempty"` |
||||
PublicGists *int `json:"public_gists,omitempty"` |
||||
} |
||||
|
||||
func (s GistStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// PullStats represents the number of total, merged, mergable and unmergeable
|
||||
// pull-requests.
|
||||
type PullStats struct { |
||||
TotalPulls *int `json:"total_pulls,omitempty"` |
||||
MergedPulls *int `json:"merged_pulls,omitempty"` |
||||
MergablePulls *int `json:"mergeable_pulls,omitempty"` |
||||
UnmergablePulls *int `json:"unmergeable_pulls,omitempty"` |
||||
} |
||||
|
||||
func (s PullStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// RepoStats represents the number of total, root, fork, organization repositories
|
||||
// together with the total number of pushes and wikis.
|
||||
type RepoStats struct { |
||||
TotalRepos *int `json:"total_repos,omitempty"` |
||||
RootRepos *int `json:"root_repos,omitempty"` |
||||
ForkRepos *int `json:"fork_repos,omitempty"` |
||||
OrgRepos *int `json:"org_repos,omitempty"` |
||||
TotalPushes *int `json:"total_pushes,omitempty"` |
||||
TotalWikis *int `json:"total_wikis,omitempty"` |
||||
} |
||||
|
||||
func (s RepoStats) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// GetAdminStats returns a variety of metrics about a Github Enterprise
|
||||
// installation.
|
||||
//
|
||||
// Please note that this is only available to site administrators,
|
||||
// otherwise it will error with a 404 not found (instead of 401 or 403).
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/enterprise-admin/admin_stats/
|
||||
func (s *AdminService) GetAdminStats(ctx context.Context) (*AdminStats, *Response, error) { |
||||
u := fmt.Sprintf("enterprise/stats/all") |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
m := new(AdminStats) |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
@ -0,0 +1,197 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// AppsService provides access to the installation related functions
|
||||
// in the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/
|
||||
type AppsService service |
||||
|
||||
// App represents a GitHub App.
|
||||
type App struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
Owner *User `json:"owner,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
ExternalURL *string `json:"external_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
} |
||||
|
||||
// InstallationToken represents an installation token.
|
||||
type InstallationToken struct { |
||||
Token *string `json:"token,omitempty"` |
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"` |
||||
} |
||||
|
||||
// InstallationPermissions lists the permissions for metadata, contents, issues and single file for an installation.
|
||||
type InstallationPermissions struct { |
||||
Metadata *string `json:"metadata,omitempty"` |
||||
Contents *string `json:"contents,omitempty"` |
||||
Issues *string `json:"issues,omitempty"` |
||||
SingleFile *string `json:"single_file,omitempty"` |
||||
} |
||||
|
||||
// Installation represents a GitHub Apps installation.
|
||||
type Installation struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
AppID *int64 `json:"app_id,omitempty"` |
||||
TargetID *int64 `json:"target_id,omitempty"` |
||||
Account *User `json:"account,omitempty"` |
||||
AccessTokensURL *string `json:"access_tokens_url,omitempty"` |
||||
RepositoriesURL *string `json:"repositories_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
TargetType *string `json:"target_type,omitempty"` |
||||
SingleFileName *string `json:"single_file_name,omitempty"` |
||||
RepositorySelection *string `json:"repository_selection,omitempty"` |
||||
Events []string `json:"events,omitempty"` |
||||
Permissions *InstallationPermissions `json:"permissions,omitempty"` |
||||
} |
||||
|
||||
func (i Installation) String() string { |
||||
return Stringify(i) |
||||
} |
||||
|
||||
// Get a single GitHub App. Passing the empty string will get
|
||||
// the authenticated GitHub App.
|
||||
//
|
||||
// Note: appSlug is just the URL-friendly name of your GitHub App.
|
||||
// You can find this on the settings page for your GitHub App
|
||||
// (e.g., https://github.com/settings/apps/:app_slug).
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app
|
||||
func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) { |
||||
var u string |
||||
if appSlug != "" { |
||||
u = fmt.Sprintf("apps/%v", appSlug) |
||||
} else { |
||||
u = "app" |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
app := new(App) |
||||
resp, err := s.client.Do(ctx, req, app) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return app, resp, nil |
||||
} |
||||
|
||||
// ListInstallations lists the installations that the current GitHub App has.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#find-installations
|
||||
func (s *AppsService) ListInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { |
||||
u, err := addOptions("app/installations", opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
var i []*Installation |
||||
resp, err := s.client.Do(ctx, req, &i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i, resp, nil |
||||
} |
||||
|
||||
// GetInstallation returns the specified installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-installation
|
||||
func (s *AppsService) GetInstallation(ctx context.Context, id int64) (*Installation, *Response, error) { |
||||
u := fmt.Sprintf("app/installations/%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", mediaTypeIntegrationPreview) |
||||
|
||||
i := new(Installation) |
||||
resp, err := s.client.Do(ctx, req, i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i, resp, nil |
||||
} |
||||
|
||||
// ListUserInstallations lists installations that are accessible to the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user
|
||||
func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { |
||||
u, err := addOptions("user/installations", opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
var i struct { |
||||
Installations []*Installation `json:"installations"` |
||||
} |
||||
resp, err := s.client.Do(ctx, req, &i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i.Installations, resp, nil |
||||
} |
||||
|
||||
// CreateInstallationToken creates a new installation token.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
|
||||
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*InstallationToken, *Response, error) { |
||||
u := fmt.Sprintf("installations/%v/access_tokens", id) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
t := new(InstallationToken) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
@ -0,0 +1,101 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListRepos lists the repositories that are accessible to the authenticated installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories
|
||||
func (s *AppsService) ListRepos(ctx context.Context, opt *ListOptions) ([]*Repository, *Response, error) { |
||||
u, err := addOptions("installation/repositories", opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
var r struct { |
||||
Repositories []*Repository `json:"repositories"` |
||||
} |
||||
resp, err := s.client.Do(ctx, req, &r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r.Repositories, resp, nil |
||||
} |
||||
|
||||
// ListUserRepos lists repositories that are accessible
|
||||
// to the authenticated user for an installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/installations/#list-repositories-accessible-to-the-user-for-an-installation
|
||||
func (s *AppsService) ListUserRepos(ctx context.Context, id int64, opt *ListOptions) ([]*Repository, *Response, error) { |
||||
u := fmt.Sprintf("user/installations/%v/repositories", id) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
var r struct { |
||||
Repositories []*Repository `json:"repositories"` |
||||
} |
||||
resp, err := s.client.Do(ctx, req, &r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r.Repositories, resp, nil |
||||
} |
||||
|
||||
// AddRepository adds a single repository to an installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/installations/#add-repository-to-installation
|
||||
func (s *AppsService) AddRepository(ctx context.Context, instID, repoID int64) (*Repository, *Response, error) { |
||||
u := fmt.Sprintf("apps/installations/%v/repositories/%v", instID, repoID) |
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
r := new(Repository) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
||||
|
||||
// RemoveRepository removes a single repository from an installation.
|
||||
//
|
||||
// GitHub docs: https://developer.github.com/v3/apps/installations/#remove-repository-from-installation
|
||||
func (s *AppsService) RemoveRepository(ctx context.Context, instID, repoID int64) (*Response, error) { |
||||
u := fmt.Sprintf("apps/installations/%v/repositories/%v", instID, repoID) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,180 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// MarketplaceService handles communication with the marketplace related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
|
||||
type MarketplaceService struct { |
||||
client *Client |
||||
// Stubbed controls whether endpoints that return stubbed data are used
|
||||
// instead of production endpoints. Stubbed data is fake data that's useful
|
||||
// for testing your GitHub Apps. Stubbed data is hard-coded and will not
|
||||
// change based on actual subscriptions.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
|
||||
Stubbed bool |
||||
} |
||||
|
||||
// MarketplacePlan represents a GitHub Apps Marketplace Listing Plan.
|
||||
type MarketplacePlan struct { |
||||
URL *string `json:"url,omitempty"` |
||||
AccountsURL *string `json:"accounts_url,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
MonthlyPriceInCents *int `json:"monthly_price_in_cents,omitempty"` |
||||
YearlyPriceInCents *int `json:"yearly_price_in_cents,omitempty"` |
||||
PriceModel *string `json:"price_model,omitempty"` |
||||
UnitName *string `json:"unit_name,omitempty"` |
||||
Bullets *[]string `json:"bullets,omitempty"` |
||||
} |
||||
|
||||
// MarketplacePurchase represents a GitHub Apps Marketplace Purchase.
|
||||
type MarketplacePurchase struct { |
||||
BillingCycle *string `json:"billing_cycle,omitempty"` |
||||
NextBillingDate *string `json:"next_billing_date,omitempty"` |
||||
UnitCount *int `json:"unit_count,omitempty"` |
||||
Plan *MarketplacePlan `json:"plan,omitempty"` |
||||
Account *MarketplacePlanAccount `json:"account,omitempty"` |
||||
} |
||||
|
||||
// MarketplacePlanAccount represents a GitHub Account (user or organization) on a specific plan.
|
||||
type MarketplacePlanAccount struct { |
||||
URL *string `json:"url,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
Login *string `json:"login,omitempty"` |
||||
Email *string `json:"email,omitempty"` |
||||
OrganizationBillingEmail *string `json:"organization_billing_email,omitempty"` |
||||
MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` |
||||
} |
||||
|
||||
// ListPlans lists all plans for your Marketplace listing.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-plans-for-your-marketplace-listing
|
||||
func (s *MarketplaceService) ListPlans(ctx context.Context, opt *ListOptions) ([]*MarketplacePlan, *Response, error) { |
||||
uri := s.marketplaceURI("plans") |
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMarketplacePreview) |
||||
|
||||
var plans []*MarketplacePlan |
||||
resp, err := s.client.Do(ctx, req, &plans) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return plans, resp, nil |
||||
} |
||||
|
||||
// ListPlanAccountsForPlan lists all GitHub accounts (user or organization) on a specific plan.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-github-accounts-user-or-organization-on-a-specific-plan
|
||||
func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { |
||||
uri := s.marketplaceURI(fmt.Sprintf("plans/%v/accounts", planID)) |
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMarketplacePreview) |
||||
|
||||
var accounts []*MarketplacePlanAccount |
||||
resp, err := s.client.Do(ctx, req, &accounts) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return accounts, resp, nil |
||||
} |
||||
|
||||
// ListPlanAccountsForAccount lists all GitHub accounts (user or organization) associated with an account.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#check-if-a-github-account-is-associated-with-any-marketplace-listing
|
||||
func (s *MarketplaceService) ListPlanAccountsForAccount(ctx context.Context, accountID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { |
||||
uri := s.marketplaceURI(fmt.Sprintf("accounts/%v", accountID)) |
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMarketplacePreview) |
||||
|
||||
var accounts []*MarketplacePlanAccount |
||||
resp, err := s.client.Do(ctx, req, &accounts) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return accounts, resp, nil |
||||
} |
||||
|
||||
// ListMarketplacePurchasesForUser lists all GitHub marketplace purchases made by a user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#get-a-users-marketplace-purchases
|
||||
func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context, opt *ListOptions) ([]*MarketplacePurchase, *Response, error) { |
||||
uri := "user/marketplace_purchases" |
||||
if s.Stubbed { |
||||
uri = "user/marketplace_purchases/stubbed" |
||||
} |
||||
|
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMarketplacePreview) |
||||
|
||||
var purchases []*MarketplacePurchase |
||||
resp, err := s.client.Do(ctx, req, &purchases) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return purchases, resp, nil |
||||
} |
||||
|
||||
func (s *MarketplaceService) marketplaceURI(endpoint string) string { |
||||
url := "marketplace_listing" |
||||
if s.Stubbed { |
||||
url = "marketplace_listing/stubbed" |
||||
} |
||||
return url + "/" + endpoint |
||||
} |
@ -0,0 +1,435 @@
|
||||
// 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 ( |
||||
"context" |
||||
"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 service |
||||
|
||||
// Authorization represents an individual GitHub authorization.
|
||||
type Authorization struct { |
||||
ID *int64 `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"` |
||||
UpdatedAt *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) |
||||
} |
||||
|
||||
// Grant represents an OAuth application that has been granted access to an account.
|
||||
type Grant struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
App *AuthorizationApp `json:"app,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
Scopes []string `json:"scopes,omitempty"` |
||||
} |
||||
|
||||
func (g Grant) String() string { |
||||
return Stringify(g) |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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 |
||||
} |
||||
|
||||
var auths []*Authorization |
||||
resp, err := s.client.Do(ctx, req, &auths) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return auths, resp, nil |
||||
} |
||||
|
||||
// Get a single authorization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization
|
||||
func (s *AuthorizationsService) Get(ctx context.Context, id int64) (*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(ctx, req, a) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return a, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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(ctx, req, a) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return a, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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(ctx, req, a) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return a, resp, nil |
||||
} |
||||
|
||||
// Edit a single authorization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization
|
||||
func (s *AuthorizationsService) Edit(ctx context.Context, id int64, 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(ctx, req, a) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return a, resp, nil |
||||
} |
||||
|
||||
// Delete a single authorization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization
|
||||
func (s *AuthorizationsService) Delete(ctx context.Context, id int64) (*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(ctx, 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(ctx context.Context, 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(ctx, req, a) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return a, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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(ctx, req, a) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return a, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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(ctx, req, nil) |
||||
} |
||||
|
||||
// ListGrants lists the set of OAuth applications that have been granted
|
||||
// access to a user's account. This will return one entry for each application
|
||||
// that has been granted access to the account, regardless of the number of
|
||||
// tokens an application has generated for the user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#list-your-grants
|
||||
func (s *AuthorizationsService) ListGrants(ctx context.Context, opt *ListOptions) ([]*Grant, *Response, error) { |
||||
u, err := addOptions("applications/grants", opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
grants := []*Grant{} |
||||
resp, err := s.client.Do(ctx, req, &grants) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return grants, resp, nil |
||||
} |
||||
|
||||
// GetGrant gets a single OAuth application grant.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#get-a-single-grant
|
||||
func (s *AuthorizationsService) GetGrant(ctx context.Context, id int64) (*Grant, *Response, error) { |
||||
u := fmt.Sprintf("applications/grants/%d", id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
grant := new(Grant) |
||||
resp, err := s.client.Do(ctx, req, grant) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return grant, resp, nil |
||||
} |
||||
|
||||
// DeleteGrant deletes an OAuth application grant. Deleting an application's
|
||||
// grant will also delete all OAuth tokens associated with the application for
|
||||
// the user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/oauth_authorizations/#delete-a-grant
|
||||
func (s *AuthorizationsService) DeleteGrant(ctx context.Context, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("applications/grants/%d", id) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// CreateImpersonation creates an impersonation OAuth token.
|
||||
//
|
||||
// This requires admin permissions. With the returned Authorization.Token
|
||||
// you can e.g. create or delete a user's public SSH key. NOTE: creating a
|
||||
// new token automatically revokes an existing one.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/enterprise/2.5/v3/users/administration/#create-an-impersonation-oauth-token
|
||||
func (s *AuthorizationsService) CreateImpersonation(ctx context.Context, username string, authReq *AuthorizationRequest) (*Authorization, *Response, error) { |
||||
u := fmt.Sprintf("admin/users/%v/authorizations", username) |
||||
req, err := s.client.NewRequest("POST", u, authReq) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
a := new(Authorization) |
||||
resp, err := s.client.Do(ctx, req, a) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return a, resp, nil |
||||
} |
||||
|
||||
// DeleteImpersonation deletes an impersonation OAuth token.
|
||||
//
|
||||
// NOTE: there can be only one at a time.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/enterprise/2.5/v3/users/administration/#delete-an-impersonation-oauth-token
|
||||
func (s *AuthorizationsService) DeleteImpersonation(ctx context.Context, username string) (*Response, error) { |
||||
u := fmt.Sprintf("admin/users/%v/authorizations", username) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,187 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/* |
||||
Package github provides a client for using the GitHub API. |
||||
|
||||
Usage: |
||||
|
||||
import "github.com/google/go-github/github" |
||||
|
||||
Construct a new GitHub client, then use the various services on the client to |
||||
access different parts of the GitHub API. For example: |
||||
|
||||
client := github.NewClient(nil) |
||||
|
||||
// list all organizations for user "willnorris"
|
||||
orgs, _, err := client.Organizations.List(ctx, "willnorris", nil) |
||||
|
||||
Some API methods have optional parameters that can be passed. For example: |
||||
|
||||
client := github.NewClient(nil) |
||||
|
||||
// list public repositories for org "github"
|
||||
opt := &github.RepositoryListByOrgOptions{Type: "public"} |
||||
repos, _, err := client.Repositories.ListByOrg(ctx, "github", opt) |
||||
|
||||
The services of a client divide the API into logical chunks and correspond to |
||||
the structure of the GitHub API documentation at |
||||
https://developer.github.com/v3/.
|
||||
|
||||
NOTE: Using the https://godoc.org/context package, one can easily
|
||||
pass cancelation signals and deadlines to various services of the client for |
||||
handling a request. In case there is no context available, then context.Background() |
||||
can be used as a starting point. |
||||
|
||||
For more sample code snippets, head over to the https://github.com/google/go-github/tree/master/example directory.
|
||||
|
||||
Authentication |
||||
|
||||
The go-github library does not directly handle authentication. Instead, when |
||||
creating a new client, pass an http.Client that can handle authentication for |
||||
you. The easiest and recommended way to do this is using the golang.org/x/oauth2 |
||||
library, but you can always use any other library that provides an http.Client. |
||||
If you have an OAuth2 access token (for example, a personal API token), you can |
||||
use it with the oauth2 library using: |
||||
|
||||
import "golang.org/x/oauth2" |
||||
|
||||
func main() { |
||||
ctx := context.Background() |
||||
ts := oauth2.StaticTokenSource( |
||||
&oauth2.Token{AccessToken: "... your access token ..."}, |
||||
) |
||||
tc := oauth2.NewClient(ctx, ts) |
||||
|
||||
client := github.NewClient(tc) |
||||
|
||||
// list all repositories for the authenticated user
|
||||
repos, _, err := client.Repositories.List(ctx, "", nil) |
||||
} |
||||
|
||||
Note that when using an authenticated Client, all calls made by the client will |
||||
include the specified OAuth token. Therefore, authenticated clients should |
||||
almost never be shared between different users. |
||||
|
||||
See the oauth2 docs for complete instructions on using that library. |
||||
|
||||
For API methods that require HTTP Basic Authentication, use the |
||||
BasicAuthTransport. |
||||
|
||||
GitHub Apps authentication can be provided by the |
||||
https://github.com/bradleyfalzon/ghinstallation package.
|
||||
|
||||
import "github.com/bradleyfalzon/ghinstallation" |
||||
|
||||
func main() { |
||||
// Wrap the shared transport for use with the integration ID 1 authenticating with installation ID 99.
|
||||
itr, err := ghinstallation.NewKeyFromFile(http.DefaultTransport, 1, 99, "2016-10-19.private-key.pem") |
||||
if err != nil { |
||||
// Handle error.
|
||||
} |
||||
|
||||
// Use installation transport with client
|
||||
client := github.NewClient(&http.Client{Transport: itr}) |
||||
|
||||
// Use client...
|
||||
} |
||||
|
||||
Rate Limiting |
||||
|
||||
GitHub imposes a rate limit on all API clients. Unauthenticated clients are |
||||
limited to 60 requests per hour, while authenticated clients can make up to |
||||
5,000 requests per hour. The Search API has a custom rate limit. Unauthenticated |
||||
clients are limited to 10 requests per minute, while authenticated clients |
||||
can make up to 30 requests per minute. To receive the higher rate limit when |
||||
making calls that are not issued on behalf of a user, |
||||
use UnauthenticatedRateLimitedTransport. |
||||
|
||||
The returned Response.Rate value contains the rate limit information |
||||
from the most recent API call. If a recent enough response isn't |
||||
available, you can use RateLimits to fetch the most up-to-date rate |
||||
limit data for the client. |
||||
|
||||
To detect an API rate limit error, you can check if its type is *github.RateLimitError: |
||||
|
||||
repos, _, err := client.Repositories.List(ctx, "", nil) |
||||
if _, ok := err.(*github.RateLimitError); ok { |
||||
log.Println("hit rate limit") |
||||
} |
||||
|
||||
Learn more about GitHub rate limiting at |
||||
https://developer.github.com/v3/#rate-limiting.
|
||||
|
||||
Accepted Status |
||||
|
||||
Some endpoints may return a 202 Accepted status code, meaning that the |
||||
information required is not yet ready and was scheduled to be gathered on |
||||
the GitHub side. Methods known to behave like this are documented specifying |
||||
this behavior. |
||||
|
||||
To detect this condition of error, you can check if its type is |
||||
*github.AcceptedError: |
||||
|
||||
stats, _, err := client.Repositories.ListContributorsStats(ctx, org, repo) |
||||
if _, ok := err.(*github.AcceptedError); ok { |
||||
log.Println("scheduled on GitHub side") |
||||
} |
||||
|
||||
Conditional Requests |
||||
|
||||
The GitHub API has good support for conditional requests which will help |
||||
prevent you from burning through your rate limit, as well as help speed up your |
||||
application. go-github does not handle conditional requests directly, but is |
||||
instead designed to work with a caching http.Transport. We recommend using |
||||
https://github.com/gregjones/httpcache for that.
|
||||
|
||||
Learn more about GitHub conditional requests at |
||||
https://developer.github.com/v3/#conditional-requests.
|
||||
|
||||
Creating and Updating Resources |
||||
|
||||
All structs for GitHub resources use pointer values for all non-repeated fields. |
||||
This allows distinguishing between unset fields and those set to a zero-value. |
||||
Helper functions have been provided to easily create these pointers for string, |
||||
bool, and int values. For example: |
||||
|
||||
// create a new private repository named "foo"
|
||||
repo := &github.Repository{ |
||||
Name: github.String("foo"), |
||||
Private: github.Bool(true), |
||||
} |
||||
client.Repositories.Create(ctx, "", repo) |
||||
|
||||
Users who have worked with protocol buffers should find this pattern familiar. |
||||
|
||||
Pagination |
||||
|
||||
All requests for resource collections (repos, pull requests, issues, etc.) |
||||
support pagination. Pagination options are described in the |
||||
github.ListOptions struct and passed to the list methods directly or as an |
||||
embedded type of a more specific list options struct (for example |
||||
github.PullRequestListOptions). Pages information is available via the |
||||
github.Response struct. |
||||
|
||||
client := github.NewClient(nil) |
||||
|
||||
opt := &github.RepositoryListByOrgOptions{ |
||||
ListOptions: github.ListOptions{PerPage: 10}, |
||||
} |
||||
// get all pages of results
|
||||
var allRepos []*github.Repository |
||||
for { |
||||
repos, resp, err := client.Repositories.ListByOrg(ctx, "github", opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
allRepos = append(allRepos, repos...) |
||||
if resp.NextPage == 0 { |
||||
break |
||||
} |
||||
opt.Page = resp.NextPage |
||||
} |
||||
|
||||
*/ |
||||
package github |
@ -0,0 +1,752 @@
|
||||
// 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 API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// ForkEvent is triggered when a user forks a repository.
|
||||
// The Webhook event name is "fork".
|
||||
//
|
||||
// GitHub API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,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"` |
||||
} |
||||
|
||||
// ProjectChange represents the changes when a project has been edited.
|
||||
type ProjectChange struct { |
||||
Name *struct { |
||||
From *string `json:"from,omitempty"` |
||||
} `json:"name,omitempty"` |
||||
Body *struct { |
||||
From *string `json:"from,omitempty"` |
||||
} `json:"body,omitempty"` |
||||
} |
||||
|
||||
// ProjectCardChange represents the changes when a project card has been edited.
|
||||
type ProjectCardChange struct { |
||||
Note *struct { |
||||
From *string `json:"from,omitempty"` |
||||
} `json:"note,omitempty"` |
||||
} |
||||
|
||||
// ProjectColumnChange represents the changes when a project column has been edited.
|
||||
type ProjectColumnChange struct { |
||||
Name *struct { |
||||
From *string `json:"from,omitempty"` |
||||
} `json:"name,omitempty"` |
||||
} |
||||
|
||||
// TeamChange represents the changes when a team has been edited.
|
||||
type TeamChange struct { |
||||
Description *struct { |
||||
From *string `json:"from,omitempty"` |
||||
} `json:"description,omitempty"` |
||||
Name *struct { |
||||
From *string `json:"from,omitempty"` |
||||
} `json:"name,omitempty"` |
||||
Privacy *struct { |
||||
From *string `json:"from,omitempty"` |
||||
} `json:"privacy,omitempty"` |
||||
Repository *struct { |
||||
Permissions *struct { |
||||
From *struct { |
||||
Admin *bool `json:"admin,omitempty"` |
||||
Pull *bool `json:"pull,omitempty"` |
||||
Push *bool `json:"push,omitempty"` |
||||
} `json:"from,omitempty"` |
||||
} `json:"permissions,omitempty"` |
||||
} `json:"repository,omitempty"` |
||||
} |
||||
|
||||
// InstallationEvent is triggered when a GitHub App has been installed or uninstalled.
|
||||
// The Webhook event name is "installation".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#installationevent
|
||||
type InstallationEvent struct { |
||||
// The action that was performed. Can be either "created" or "deleted".
|
||||
Action *string `json:"action,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// InstallationRepositoriesEvent is triggered when a repository is added or
|
||||
// removed from an installation. The Webhook event name is "installation_repositories".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#installationrepositoriesevent
|
||||
type InstallationRepositoriesEvent struct { |
||||
// The action that was performed. Can be either "added" or "removed".
|
||||
Action *string `json:"action,omitempty"` |
||||
RepositoriesAdded []*Repository `json:"repositories_added,omitempty"` |
||||
RepositoriesRemoved []*Repository `json:"repositories_removed,omitempty"` |
||||
RepositorySelection *string `json:"repository_selection,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// IssueCommentEvent is triggered when an issue comment is created on an issue
|
||||
// or pull request.
|
||||
// The Webhook event name is "issue_comment".
|
||||
//
|
||||
// GitHub API 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"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// IssuesEvent is triggered when an issue is assigned, unassigned, labeled,
|
||||
// unlabeled, opened, closed, or reopened.
|
||||
// The Webhook event name is "issues".
|
||||
//
|
||||
// GitHub API 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"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// LabelEvent is triggered when a repository's label is created, edited, or deleted.
|
||||
// The Webhook event name is "label"
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#labelevent
|
||||
type LabelEvent struct { |
||||
// Action is the action that was performed. Possible values are:
|
||||
// "created", "edited", "deleted"
|
||||
Action *string `json:"action,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"` |
||||
Org *Organization `json:"organization,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// MarketplacePurchaseEvent is triggered when a user purchases, cancels, or changes
|
||||
// their GitHub Marketplace plan.
|
||||
// Webhook event name "marketplace_purchase".
|
||||
//
|
||||
// Github API docs: https://developer.github.com/v3/activity/events/types/#marketplacepurchaseevent
|
||||
type MarketplacePurchaseEvent struct { |
||||
// Action is the action that was performed. Possible values are:
|
||||
// "purchased", "cancelled", "changed".
|
||||
Action *string `json:"action,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
EffectiveDate *Timestamp `json:"effective_date,omitempty"` |
||||
MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` |
||||
PreviousMarketplacePurchase *MarketplacePurchase `json:"previous_marketplace_purchase,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// MemberEvent is triggered when a user is added as a collaborator to a repository.
|
||||
// The Webhook event name is "member".
|
||||
//
|
||||
// GitHub API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// MilestoneEvent is triggered when a milestone is created, closed, opened, edited, or deleted.
|
||||
// The Webhook event name is "milestone".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#milestoneevent
|
||||
type MilestoneEvent struct { |
||||
// Action is the action that was performed. Possible values are:
|
||||
// "created", "closed", "opened", "edited", "deleted"
|
||||
Action *string `json:"action,omitempty"` |
||||
Milestone *Milestone `json:"milestone,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"` |
||||
Org *Organization `json:"organization,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// OrganizationEvent is triggered when a user is added, removed, or invited to an organization.
|
||||
// Events of this type are not visible in timelines. These events are only used to trigger organization hooks.
|
||||
// Webhook event name is "organization".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#organizationevent
|
||||
type OrganizationEvent struct { |
||||
// Action is the action that was performed.
|
||||
// Can be one of "member_added", "member_removed", or "member_invited".
|
||||
Action *string `json:"action,omitempty"` |
||||
|
||||
// Invitaion is the invitation for the user or email if the action is "member_invited".
|
||||
Invitation *Invitation `json:"invitation,omitempty"` |
||||
|
||||
// Membership is the membership between the user and the organization.
|
||||
// Not present when the action is "member_invited".
|
||||
Membership *Membership `json:"membership,omitempty"` |
||||
|
||||
Organization *Organization `json:"organization,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// OrgBlockEvent is triggered when an organization blocks or unblocks a user.
|
||||
// The Webhook event name is "org_block".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#orgblockevent
|
||||
type OrgBlockEvent struct { |
||||
// Action is the action that was performed.
|
||||
// Can be "blocked" or "unblocked".
|
||||
Action *string `json:"action,omitempty"` |
||||
BlockedUser *User `json:"blocked_user,omitempty"` |
||||
Organization *Organization `json:"organization,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Installation *Installation `json:"installation,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 API 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 *int64 `json:"id,omitempty"` |
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// PingEvent is triggered when a Webhook is added to GitHub.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/webhooks/#ping-event
|
||||
type PingEvent struct { |
||||
// Random string of GitHub zen.
|
||||
Zen *string `json:"zen,omitempty"` |
||||
// The ID of the webhook that triggered the ping.
|
||||
HookID *int64 `json:"hook_id,omitempty"` |
||||
// The webhook configuration.
|
||||
Hook *Hook `json:"hook,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// ProjectEvent is triggered when project is created, modified or deleted.
|
||||
// The webhook event name is "project".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectevent
|
||||
type ProjectEvent struct { |
||||
Action *string `json:"action,omitempty"` |
||||
Changes *ProjectChange `json:"changes,omitempty"` |
||||
Project *Project `json:"project,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Org *Organization `json:"organization,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// ProjectCardEvent is triggered when a project card is created, updated, moved, converted to an issue, or deleted.
|
||||
// The webhook event name is "project_card".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcardevent
|
||||
type ProjectCardEvent struct { |
||||
Action *string `json:"action,omitempty"` |
||||
Changes *ProjectCardChange `json:"changes,omitempty"` |
||||
AfterID *int64 `json:"after_id,omitempty"` |
||||
ProjectCard *ProjectCard `json:"project_card,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Org *Organization `json:"organization,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// ProjectColumnEvent is triggered when a project column is created, updated, moved, or deleted.
|
||||
// The webhook event name is "project_column".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#projectcolumnevent
|
||||
type ProjectColumnEvent struct { |
||||
Action *string `json:"action,omitempty"` |
||||
Changes *ProjectColumnChange `json:"changes,omitempty"` |
||||
AfterID *int64 `json:"after_id,omitempty"` |
||||
ProjectColumn *ProjectColumn `json:"project_column,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Org *Organization `json:"organization,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// 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 API 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"` |
||||
Installation *Installation `json:"installation,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 API docs: https://developer.github.com/v3/activity/events/types/#pullrequestevent
|
||||
type PullRequestEvent struct { |
||||
// Action is the action that was performed. Possible values are:
|
||||
// "assigned", "unassigned", "review_requested", "review_request_removed", "labeled", "unlabeled",
|
||||
// "opened", "closed", "reopened", "synchronize", "edited".
|
||||
// If the action is "closed" and the merged key is false,
|
||||
// the pull request was closed with unmerged commits. If the action is "closed"
|
||||
// and the merged key is true, the pull request was merged.
|
||||
Action *string `json:"action,omitempty"` |
||||
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"` |
||||
// RequestedReviewer is populated in "review_requested", "review_request_removed" event deliveries.
|
||||
// A request affecting multiple reviewers at once is split into multiple
|
||||
// such event deliveries, each with a single, different RequestedReviewer.
|
||||
RequestedReviewer *User `json:"requested_reviewer,omitempty"` |
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries.
|
||||
} |
||||
|
||||
// PullRequestReviewEvent is triggered when a review is submitted on a pull
|
||||
// request.
|
||||
// The Webhook event name is "pull_request_review".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pullrequestreviewevent
|
||||
type PullRequestReviewEvent struct { |
||||
// Action is always "submitted".
|
||||
Action *string `json:"action,omitempty"` |
||||
Review *PullRequestReview `json:"review,omitempty"` |
||||
PullRequest *PullRequest `json:"pull_request,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
|
||||
// The following field is only present when the webhook is triggered on
|
||||
// a repository belonging to an organization.
|
||||
Organization *Organization `json:"organization,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 API 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"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// PushEvent represents a git push to a GitHub repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#pushevent
|
||||
type PushEvent struct { |
||||
PushID *int64 `json:"push_id,omitempty"` |
||||
Head *string `json:"head,omitempty"` |
||||
Ref *string `json:"ref,omitempty"` |
||||
Size *int `json:"size,omitempty"` |
||||
Commits []PushEventCommit `json:"commits,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"` |
||||
Repo *PushEventRepository `json:"repository,omitempty"` |
||||
HeadCommit *PushEventCommit `json:"head_commit,omitempty"` |
||||
Pusher *User `json:"pusher,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
func (p PushEvent) String() string { |
||||
return Stringify(p) |
||||
} |
||||
|
||||
// PushEventCommit represents a git commit in a GitHub PushEvent.
|
||||
type PushEventCommit struct { |
||||
Message *string `json:"message,omitempty"` |
||||
Author *CommitAuthor `json:"author,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Distinct *bool `json:"distinct,omitempty"` |
||||
|
||||
// The following fields are only populated by Events API.
|
||||
SHA *string `json:"sha,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
ID *string `json:"id,omitempty"` |
||||
TreeID *string `json:"tree_id,omitempty"` |
||||
Timestamp *Timestamp `json:"timestamp,omitempty"` |
||||
Committer *CommitAuthor `json:"committer,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 *int64 `json:"id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
FullName *string `json:"full_name,omitempty"` |
||||
Owner *PushEventRepoOwner `json:"owner,omitempty"` |
||||
Private *bool `json:"private,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Fork *bool `json:"fork,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
PushedAt *Timestamp `json:"pushed_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
Homepage *string `json:"homepage,omitempty"` |
||||
Size *int `json:"size,omitempty"` |
||||
StargazersCount *int `json:"stargazers_count,omitempty"` |
||||
WatchersCount *int `json:"watchers_count,omitempty"` |
||||
Language *string `json:"language,omitempty"` |
||||
HasIssues *bool `json:"has_issues,omitempty"` |
||||
HasDownloads *bool `json:"has_downloads,omitempty"` |
||||
HasWiki *bool `json:"has_wiki,omitempty"` |
||||
HasPages *bool `json:"has_pages,omitempty"` |
||||
ForksCount *int `json:"forks_count,omitempty"` |
||||
OpenIssuesCount *int `json:"open_issues_count,omitempty"` |
||||
DefaultBranch *string `json:"default_branch,omitempty"` |
||||
MasterBranch *string `json:"master_branch,omitempty"` |
||||
Organization *string `json:"organization,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
ArchiveURL *string `json:"archive_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
StatusesURL *string `json:"statuses_url,omitempty"` |
||||
GitURL *string `json:"git_url,omitempty"` |
||||
SSHURL *string `json:"ssh_url,omitempty"` |
||||
CloneURL *string `json:"clone_url,omitempty"` |
||||
SVNURL *string `json:"svn_url,omitempty"` |
||||
} |
||||
|
||||
// PushEventRepoOwner is a basic representation 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 API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,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 API 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 *int64 `json:"id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Context *string `json:"context,omitempty"` |
||||
Commit *RepositoryCommit `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"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// TeamEvent is triggered when an organization's team is created, modified or deleted.
|
||||
// The Webhook event name is "team".
|
||||
//
|
||||
// Events of this type are not visible in timelines. These events are only used
|
||||
// to trigger hooks.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#teamevent
|
||||
type TeamEvent struct { |
||||
Action *string `json:"action,omitempty"` |
||||
Team *Team `json:"team,omitempty"` |
||||
Changes *TeamChange `json:"changes,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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,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 API 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"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
@ -0,0 +1,332 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
|
||||
// gen-accessors generates accessor methods for structs with pointer fields.
|
||||
//
|
||||
// It is meant to be used by the go-github authors in conjunction with the
|
||||
// go generate tool before sending a commit to GitHub.
|
||||
package main |
||||
|
||||
import ( |
||||
"bytes" |
||||
"flag" |
||||
"fmt" |
||||
"go/ast" |
||||
"go/format" |
||||
"go/parser" |
||||
"go/token" |
||||
"io/ioutil" |
||||
"log" |
||||
"os" |
||||
"sort" |
||||
"strings" |
||||
"text/template" |
||||
) |
||||
|
||||
const ( |
||||
fileSuffix = "-accessors.go" |
||||
) |
||||
|
||||
var ( |
||||
verbose = flag.Bool("v", false, "Print verbose log messages") |
||||
|
||||
sourceTmpl = template.Must(template.New("source").Parse(source)) |
||||
|
||||
// blacklistStructMethod lists "struct.method" combos to skip.
|
||||
blacklistStructMethod = map[string]bool{ |
||||
"RepositoryContent.GetContent": true, |
||||
"Client.GetBaseURL": true, |
||||
"Client.GetUploadURL": true, |
||||
"ErrorResponse.GetResponse": true, |
||||
"RateLimitError.GetResponse": true, |
||||
"AbuseRateLimitError.GetResponse": true, |
||||
} |
||||
// blacklistStruct lists structs to skip.
|
||||
blacklistStruct = map[string]bool{ |
||||
"Client": true, |
||||
} |
||||
) |
||||
|
||||
func logf(fmt string, args ...interface{}) { |
||||
if *verbose { |
||||
log.Printf(fmt, args...) |
||||
} |
||||
} |
||||
|
||||
func main() { |
||||
flag.Parse() |
||||
fset := token.NewFileSet() |
||||
|
||||
pkgs, err := parser.ParseDir(fset, ".", sourceFilter, 0) |
||||
if err != nil { |
||||
log.Fatal(err) |
||||
return |
||||
} |
||||
|
||||
for pkgName, pkg := range pkgs { |
||||
t := &templateData{ |
||||
filename: pkgName + fileSuffix, |
||||
Year: 2017, |
||||
Package: pkgName, |
||||
Imports: map[string]string{}, |
||||
} |
||||
for filename, f := range pkg.Files { |
||||
logf("Processing %v...", filename) |
||||
if err := t.processAST(f); err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
} |
||||
if err := t.dump(); err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
} |
||||
logf("Done.") |
||||
} |
||||
|
||||
func (t *templateData) processAST(f *ast.File) error { |
||||
for _, decl := range f.Decls { |
||||
gd, ok := decl.(*ast.GenDecl) |
||||
if !ok { |
||||
continue |
||||
} |
||||
for _, spec := range gd.Specs { |
||||
ts, ok := spec.(*ast.TypeSpec) |
||||
if !ok { |
||||
continue |
||||
} |
||||
// Skip unexported identifiers.
|
||||
if !ts.Name.IsExported() { |
||||
logf("Struct %v is unexported; skipping.", ts.Name) |
||||
continue |
||||
} |
||||
// Check if the struct is blacklisted.
|
||||
if blacklistStruct[ts.Name.Name] { |
||||
logf("Struct %v is blacklisted; skipping.", ts.Name) |
||||
continue |
||||
} |
||||
st, ok := ts.Type.(*ast.StructType) |
||||
if !ok { |
||||
continue |
||||
} |
||||
for _, field := range st.Fields.List { |
||||
se, ok := field.Type.(*ast.StarExpr) |
||||
if len(field.Names) == 0 || !ok { |
||||
continue |
||||
} |
||||
|
||||
fieldName := field.Names[0] |
||||
// Skip unexported identifiers.
|
||||
if !fieldName.IsExported() { |
||||
logf("Field %v is unexported; skipping.", fieldName) |
||||
continue |
||||
} |
||||
// Check if "struct.method" is blacklisted.
|
||||
if key := fmt.Sprintf("%v.Get%v", ts.Name, fieldName); blacklistStructMethod[key] { |
||||
logf("Method %v is blacklisted; skipping.", key) |
||||
continue |
||||
} |
||||
|
||||
switch x := se.X.(type) { |
||||
case *ast.ArrayType: |
||||
t.addArrayType(x, ts.Name.String(), fieldName.String()) |
||||
case *ast.Ident: |
||||
t.addIdent(x, ts.Name.String(), fieldName.String()) |
||||
case *ast.MapType: |
||||
t.addMapType(x, ts.Name.String(), fieldName.String()) |
||||
case *ast.SelectorExpr: |
||||
t.addSelectorExpr(x, ts.Name.String(), fieldName.String()) |
||||
default: |
||||
logf("processAST: type %q, field %q, unknown %T: %+v", ts.Name, fieldName, x, x) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func sourceFilter(fi os.FileInfo) bool { |
||||
return !strings.HasSuffix(fi.Name(), "_test.go") && !strings.HasSuffix(fi.Name(), fileSuffix) |
||||
} |
||||
|
||||
func (t *templateData) dump() error { |
||||
if len(t.Getters) == 0 { |
||||
logf("No getters for %v; skipping.", t.filename) |
||||
return nil |
||||
} |
||||
|
||||
// Sort getters by ReceiverType.FieldName.
|
||||
sort.Sort(byName(t.Getters)) |
||||
|
||||
var buf bytes.Buffer |
||||
if err := sourceTmpl.Execute(&buf, t); err != nil { |
||||
return err |
||||
} |
||||
clean, err := format.Source(buf.Bytes()) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
logf("Writing %v...", t.filename) |
||||
return ioutil.WriteFile(t.filename, clean, 0644) |
||||
} |
||||
|
||||
func newGetter(receiverType, fieldName, fieldType, zeroValue string, namedStruct bool) *getter { |
||||
return &getter{ |
||||
sortVal: strings.ToLower(receiverType) + "." + strings.ToLower(fieldName), |
||||
ReceiverVar: strings.ToLower(receiverType[:1]), |
||||
ReceiverType: receiverType, |
||||
FieldName: fieldName, |
||||
FieldType: fieldType, |
||||
ZeroValue: zeroValue, |
||||
NamedStruct: namedStruct, |
||||
} |
||||
} |
||||
|
||||
func (t *templateData) addArrayType(x *ast.ArrayType, receiverType, fieldName string) { |
||||
var eltType string |
||||
switch elt := x.Elt.(type) { |
||||
case *ast.Ident: |
||||
eltType = elt.String() |
||||
default: |
||||
logf("addArrayType: type %q, field %q: unknown elt type: %T %+v; skipping.", receiverType, fieldName, elt, elt) |
||||
return |
||||
} |
||||
|
||||
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, "[]"+eltType, "nil", false)) |
||||
} |
||||
|
||||
func (t *templateData) addIdent(x *ast.Ident, receiverType, fieldName string) { |
||||
var zeroValue string |
||||
var namedStruct = false |
||||
switch x.String() { |
||||
case "int", "int64": |
||||
zeroValue = "0" |
||||
case "string": |
||||
zeroValue = `""` |
||||
case "bool": |
||||
zeroValue = "false" |
||||
case "Timestamp": |
||||
zeroValue = "Timestamp{}" |
||||
default: |
||||
zeroValue = "nil" |
||||
namedStruct = true |
||||
} |
||||
|
||||
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, x.String(), zeroValue, namedStruct)) |
||||
} |
||||
|
||||
func (t *templateData) addMapType(x *ast.MapType, receiverType, fieldName string) { |
||||
var keyType string |
||||
switch key := x.Key.(type) { |
||||
case *ast.Ident: |
||||
keyType = key.String() |
||||
default: |
||||
logf("addMapType: type %q, field %q: unknown key type: %T %+v; skipping.", receiverType, fieldName, key, key) |
||||
return |
||||
} |
||||
|
||||
var valueType string |
||||
switch value := x.Value.(type) { |
||||
case *ast.Ident: |
||||
valueType = value.String() |
||||
default: |
||||
logf("addMapType: type %q, field %q: unknown value type: %T %+v; skipping.", receiverType, fieldName, value, value) |
||||
return |
||||
} |
||||
|
||||
fieldType := fmt.Sprintf("map[%v]%v", keyType, valueType) |
||||
zeroValue := fmt.Sprintf("map[%v]%v{}", keyType, valueType) |
||||
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false)) |
||||
} |
||||
|
||||
func (t *templateData) addSelectorExpr(x *ast.SelectorExpr, receiverType, fieldName string) { |
||||
if strings.ToLower(fieldName[:1]) == fieldName[:1] { // Non-exported field.
|
||||
return |
||||
} |
||||
|
||||
var xX string |
||||
if xx, ok := x.X.(*ast.Ident); ok { |
||||
xX = xx.String() |
||||
} |
||||
|
||||
switch xX { |
||||
case "time", "json": |
||||
if xX == "json" { |
||||
t.Imports["encoding/json"] = "encoding/json" |
||||
} else { |
||||
t.Imports[xX] = xX |
||||
} |
||||
fieldType := fmt.Sprintf("%v.%v", xX, x.Sel.Name) |
||||
zeroValue := fmt.Sprintf("%v.%v{}", xX, x.Sel.Name) |
||||
if xX == "time" && x.Sel.Name == "Duration" { |
||||
zeroValue = "0" |
||||
} |
||||
t.Getters = append(t.Getters, newGetter(receiverType, fieldName, fieldType, zeroValue, false)) |
||||
default: |
||||
logf("addSelectorExpr: xX %q, type %q, field %q: unknown x=%+v; skipping.", xX, receiverType, fieldName, x) |
||||
} |
||||
} |
||||
|
||||
type templateData struct { |
||||
filename string |
||||
Year int |
||||
Package string |
||||
Imports map[string]string |
||||
Getters []*getter |
||||
} |
||||
|
||||
type getter struct { |
||||
sortVal string // Lower-case version of "ReceiverType.FieldName".
|
||||
ReceiverVar string // The one-letter variable name to match the ReceiverType.
|
||||
ReceiverType string |
||||
FieldName string |
||||
FieldType string |
||||
ZeroValue string |
||||
NamedStruct bool // Getter for named struct.
|
||||
} |
||||
|
||||
type byName []*getter |
||||
|
||||
func (b byName) Len() int { return len(b) } |
||||
func (b byName) Less(i, j int) bool { return b[i].sortVal < b[j].sortVal } |
||||
func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } |
||||
|
||||
const source = `// Copyright {{.Year}} 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.
|
||||
|
||||
// Code generated by gen-accessors; DO NOT EDIT.
|
||||
|
||||
package {{.Package}} |
||||
{{with .Imports}} |
||||
import ( |
||||
{{- range . -}} |
||||
"{{.}}" |
||||
{{end -}} |
||||
) |
||||
{{end}} |
||||
{{range .Getters}} |
||||
{{if .NamedStruct}} |
||||
// Get{{.FieldName}} returns the {{.FieldName}} field.
|
||||
func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() *{{.FieldType}} { |
||||
if {{.ReceiverVar}} == nil { |
||||
return {{.ZeroValue}} |
||||
} |
||||
return {{.ReceiverVar}}.{{.FieldName}} |
||||
} |
||||
{{else}} |
||||
// Get{{.FieldName}} returns the {{.FieldName}} field if it's non-nil, zero value otherwise.
|
||||
func ({{.ReceiverVar}} *{{.ReceiverType}}) Get{{.FieldName}}() {{.FieldType}} { |
||||
if {{.ReceiverVar}} == nil || {{.ReceiverVar}}.{{.FieldName}} == nil { |
||||
return {{.ZeroValue}} |
||||
} |
||||
return *{{.ReceiverVar}}.{{.FieldName}} |
||||
} |
||||
{{end}} |
||||
{{end}} |
||||
` |
@ -0,0 +1,388 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// GistsService handles communication with the Gist related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/
|
||||
type GistsService service |
||||
|
||||
// Gist represents a GitHub's gist.
|
||||
type Gist struct { |
||||
ID *string `json:"id,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Public *bool `json:"public,omitempty"` |
||||
Owner *User `json:"owner,omitempty"` |
||||
Files map[GistFilename]GistFile `json:"files,omitempty"` |
||||
Comments *int `json:"comments,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
GitPullURL *string `json:"git_pull_url,omitempty"` |
||||
GitPushURL *string `json:"git_push_url,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (g Gist) String() string { |
||||
return Stringify(g) |
||||
} |
||||
|
||||
// GistFilename represents filename on a gist.
|
||||
type GistFilename string |
||||
|
||||
// GistFile represents a file on a gist.
|
||||
type GistFile struct { |
||||
Size *int `json:"size,omitempty"` |
||||
Filename *string `json:"filename,omitempty"` |
||||
Language *string `json:"language,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
RawURL *string `json:"raw_url,omitempty"` |
||||
Content *string `json:"content,omitempty"` |
||||
} |
||||
|
||||
func (g GistFile) String() string { |
||||
return Stringify(g) |
||||
} |
||||
|
||||
// GistCommit represents a commit on a gist.
|
||||
type GistCommit struct { |
||||
URL *string `json:"url,omitempty"` |
||||
Version *string `json:"version,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
ChangeStatus *CommitStats `json:"change_status,omitempty"` |
||||
CommittedAt *Timestamp `json:"committed_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (gc GistCommit) String() string { |
||||
return Stringify(gc) |
||||
} |
||||
|
||||
// GistFork represents a fork of a gist.
|
||||
type GistFork struct { |
||||
URL *string `json:"url,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
ID *string `json:"id,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (gf GistFork) String() string { |
||||
return Stringify(gf) |
||||
} |
||||
|
||||
// GistListOptions specifies the optional parameters to the
|
||||
// GistsService.List, GistsService.ListAll, and GistsService.ListStarred methods.
|
||||
type GistListOptions struct { |
||||
// Since filters Gists by time.
|
||||
Since time.Time `url:"since,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// List gists for a user. Passing the empty string will list
|
||||
// all public gists if called anonymously. However, if the call
|
||||
// is authenticated, it will returns all gists for the authenticated
|
||||
// user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#list-gists
|
||||
func (s *GistsService) List(ctx context.Context, user string, opt *GistListOptions) ([]*Gist, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/gists", user) |
||||
} else { |
||||
u = "gists" |
||||
} |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var gists []*Gist |
||||
resp, err := s.client.Do(ctx, req, &gists) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gists, resp, nil |
||||
} |
||||
|
||||
// ListAll lists all public gists.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#list-gists
|
||||
func (s *GistsService) ListAll(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) { |
||||
u, err := addOptions("gists/public", 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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var gists []*Gist |
||||
resp, err := s.client.Do(ctx, req, &gists) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gists, resp, nil |
||||
} |
||||
|
||||
// ListStarred lists starred gists of authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#list-gists
|
||||
func (s *GistsService) ListStarred(ctx context.Context, opt *GistListOptions) ([]*Gist, *Response, error) { |
||||
u, err := addOptions("gists/starred", 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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var gists []*Gist |
||||
resp, err := s.client.Do(ctx, req, &gists) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gists, resp, nil |
||||
} |
||||
|
||||
// Get a single gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#get-a-single-gist
|
||||
func (s *GistsService) Get(ctx context.Context, id string) (*Gist, *Response, error) { |
||||
u := fmt.Sprintf("gists/%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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
gist := new(Gist) |
||||
resp, err := s.client.Do(ctx, req, gist) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gist, resp, nil |
||||
} |
||||
|
||||
// GetRevision gets a specific revision of a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#get-a-specific-revision-of-a-gist
|
||||
func (s *GistsService) GetRevision(ctx context.Context, id, sha string) (*Gist, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/%v", id, sha) |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
gist := new(Gist) |
||||
resp, err := s.client.Do(ctx, req, gist) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gist, resp, nil |
||||
} |
||||
|
||||
// Create a gist for authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#create-a-gist
|
||||
func (s *GistsService) Create(ctx context.Context, gist *Gist) (*Gist, *Response, error) { |
||||
u := "gists" |
||||
req, err := s.client.NewRequest("POST", u, gist) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
g := new(Gist) |
||||
resp, err := s.client.Do(ctx, req, g) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return g, resp, nil |
||||
} |
||||
|
||||
// Edit a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#edit-a-gist
|
||||
func (s *GistsService) Edit(ctx context.Context, id string, gist *Gist) (*Gist, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v", id) |
||||
req, err := s.client.NewRequest("PATCH", u, gist) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
g := new(Gist) |
||||
resp, err := s.client.Do(ctx, req, g) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return g, resp, nil |
||||
} |
||||
|
||||
// ListCommits lists commits of a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-commits
|
||||
func (s *GistsService) ListCommits(ctx context.Context, id string, opt *ListOptions) ([]*GistCommit, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/commits", 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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var gistCommits []*GistCommit |
||||
resp, err := s.client.Do(ctx, req, &gistCommits) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gistCommits, resp, nil |
||||
} |
||||
|
||||
// Delete a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#delete-a-gist
|
||||
func (s *GistsService) Delete(ctx context.Context, id string) (*Response, error) { |
||||
u := fmt.Sprintf("gists/%v", id) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// Star a gist on behalf of authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#star-a-gist
|
||||
func (s *GistsService) Star(ctx context.Context, id string) (*Response, error) { |
||||
u := fmt.Sprintf("gists/%v/star", id) |
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// Unstar a gist on a behalf of authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#unstar-a-gist
|
||||
func (s *GistsService) Unstar(ctx context.Context, id string) (*Response, error) { |
||||
u := fmt.Sprintf("gists/%v/star", id) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// IsStarred checks if a gist is starred by authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#check-if-a-gist-is-starred
|
||||
func (s *GistsService) IsStarred(ctx context.Context, id string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/star", id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
starred, err := parseBoolResponse(err) |
||||
return starred, resp, err |
||||
} |
||||
|
||||
// Fork a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#fork-a-gist
|
||||
func (s *GistsService) Fork(ctx context.Context, id string) (*Gist, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/forks", id) |
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
g := new(Gist) |
||||
resp, err := s.client.Do(ctx, req, g) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return g, resp, nil |
||||
} |
||||
|
||||
// ListForks lists forks of a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/#list-gist-forks
|
||||
func (s *GistsService) ListForks(ctx context.Context, id string) ([]*GistFork, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/forks", 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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var gistForks []*GistFork |
||||
resp, err := s.client.Do(ctx, req, &gistForks) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gistForks, resp, nil |
||||
} |
@ -0,0 +1,119 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// GistComment represents a Gist comment.
|
||||
type GistComment struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
} |
||||
|
||||
func (g GistComment) String() string { |
||||
return Stringify(g) |
||||
} |
||||
|
||||
// ListComments lists all comments for a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/comments/#list-comments-on-a-gist
|
||||
func (s *GistsService) ListComments(ctx context.Context, gistID string, opt *ListOptions) ([]*GistComment, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/comments", gistID) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var comments []*GistComment |
||||
resp, err := s.client.Do(ctx, req, &comments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comments, resp, nil |
||||
} |
||||
|
||||
// GetComment retrieves a single comment from a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/comments/#get-a-single-comment
|
||||
func (s *GistsService) GetComment(ctx context.Context, gistID string, commentID int64) (*GistComment, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(GistComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// CreateComment creates a comment for a gist.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/comments/#create-a-comment
|
||||
func (s *GistsService) CreateComment(ctx context.Context, gistID string, comment *GistComment) (*GistComment, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/comments", gistID) |
||||
req, err := s.client.NewRequest("POST", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(GistComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// EditComment edits an existing gist comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/comments/#edit-a-comment
|
||||
func (s *GistsService) EditComment(ctx context.Context, gistID string, commentID int64, comment *GistComment) (*GistComment, *Response, error) { |
||||
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) |
||||
req, err := s.client.NewRequest("PATCH", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(GistComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// DeleteComment deletes a gist comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gists/comments/#delete-a-comment
|
||||
func (s *GistsService) DeleteComment(ctx context.Context, gistID string, commentID int64) (*Response, error) { |
||||
u := fmt.Sprintf("gists/%v/comments/%v", gistID, commentID) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,12 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
// GitService handles communication with the git data related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/
|
||||
type GitService service |
@ -0,0 +1,75 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// Blob represents a blob object.
|
||||
type Blob struct { |
||||
Content *string `json:"content,omitempty"` |
||||
Encoding *string `json:"encoding,omitempty"` |
||||
SHA *string `json:"sha,omitempty"` |
||||
Size *int `json:"size,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
// GetBlob fetches a blob from a repo given a SHA.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob
|
||||
func (s *GitService) GetBlob(ctx context.Context, owner string, repo string, sha string) (*Blob, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
blob := new(Blob) |
||||
resp, err := s.client.Do(ctx, req, blob) |
||||
return blob, resp, err |
||||
} |
||||
|
||||
// GetBlobRaw fetches a blob's contents from a repo.
|
||||
// Unlike GetBlob, it returns the raw bytes rather than the base64-encoded data.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/blobs/#get-a-blob
|
||||
func (s *GitService) GetBlobRaw(ctx context.Context, owner, repo, sha string) ([]byte, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/blobs/%v", owner, repo, sha) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
req.Header.Set("Accept", "application/vnd.github.v3.raw") |
||||
|
||||
var buf bytes.Buffer |
||||
resp, err := s.client.Do(ctx, req, &buf) |
||||
return buf.Bytes(), resp, err |
||||
} |
||||
|
||||
// CreateBlob creates a blob object.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/blobs/#create-a-blob
|
||||
func (s *GitService) CreateBlob(ctx context.Context, owner string, repo string, blob *Blob) (*Blob, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/blobs", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, blob) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
t := new(Blob) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
return t, resp, err |
||||
} |
@ -0,0 +1,139 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
"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"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Verification *SignatureVerification `json:"verification,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
|
||||
// CommentCount is the number of GitHub comments on the commit. This
|
||||
// is only populated for requests that fetch GitHub data like
|
||||
// Pulls.ListCommits, Repositories.ListCommits, etc.
|
||||
CommentCount *int `json:"comment_count,omitempty"` |
||||
} |
||||
|
||||
func (c Commit) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// CommitAuthor represents the author or committer of a commit. The commit
|
||||
// author may not correspond to a GitHub User.
|
||||
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 { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// GetCommit fetchs the Commit object for a given SHA.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit
|
||||
func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/commits/%v", owner, repo, sha) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeGitSigningPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
c := new(Commit) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// createCommit represents the body of a CreateCommit request.
|
||||
type createCommit struct { |
||||
Author *CommitAuthor `json:"author,omitempty"` |
||||
Committer *CommitAuthor `json:"committer,omitempty"` |
||||
Message *string `json:"message,omitempty"` |
||||
Tree *string `json:"tree,omitempty"` |
||||
Parents []string `json:"parents,omitempty"` |
||||
} |
||||
|
||||
// CreateCommit creates a new commit in a repository.
|
||||
// commit must not be nil.
|
||||
//
|
||||
// The commit.Committer is optional and will be filled with the commit.Author
|
||||
// data if omitted. If the commit.Author is omitted, it will be filled in with
|
||||
// the authenticated user’s information and the current date.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/commits/#create-a-commit
|
||||
func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string, commit *Commit) (*Commit, *Response, error) { |
||||
if commit == nil { |
||||
return nil, nil, fmt.Errorf("commit must be provided") |
||||
} |
||||
|
||||
u := fmt.Sprintf("repos/%v/%v/git/commits", owner, repo) |
||||
|
||||
parents := make([]string, len(commit.Parents)) |
||||
for i, parent := range commit.Parents { |
||||
parents[i] = *parent.SHA |
||||
} |
||||
|
||||
body := &createCommit{ |
||||
Author: commit.Author, |
||||
Committer: commit.Committer, |
||||
Message: commit.Message, |
||||
Parents: parents, |
||||
} |
||||
if commit.Tree != nil { |
||||
body.Tree = commit.Tree.SHA |
||||
} |
||||
|
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
c := new(Commit) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
@ -0,0 +1,233 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// Reference represents a GitHub reference.
|
||||
type Reference struct { |
||||
Ref *string `json:"ref"` |
||||
URL *string `json:"url"` |
||||
Object *GitObject `json:"object"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (r Reference) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// GitObject represents a Git object.
|
||||
type GitObject struct { |
||||
Type *string `json:"type"` |
||||
SHA *string `json:"sha"` |
||||
URL *string `json:"url"` |
||||
} |
||||
|
||||
func (o GitObject) String() string { |
||||
return Stringify(o) |
||||
} |
||||
|
||||
// createRefRequest represents the payload for creating a reference.
|
||||
type createRefRequest struct { |
||||
Ref *string `json:"ref"` |
||||
SHA *string `json:"sha"` |
||||
} |
||||
|
||||
// updateRefRequest represents the payload for updating a reference.
|
||||
type updateRefRequest struct { |
||||
SHA *string `json:"sha"` |
||||
Force *bool `json:"force"` |
||||
} |
||||
|
||||
// GetRef fetches a single Reference object for a given Git ref.
|
||||
// If there is no exact match, GetRef will return an error.
|
||||
//
|
||||
// Note: The GitHub API can return multiple matches.
|
||||
// If you wish to use this functionality please use the GetRefs() method.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
|
||||
func (s *GitService) GetRef(ctx context.Context, owner string, repo string, ref string) (*Reference, *Response, error) { |
||||
ref = strings.TrimPrefix(ref, "refs/") |
||||
u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, ref) |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
r := new(Reference) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if _, ok := err.(*json.UnmarshalTypeError); ok { |
||||
// Multiple refs, means there wasn't an exact match.
|
||||
return nil, resp, errors.New("no exact match found for this ref") |
||||
} else if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
||||
|
||||
// GetRefs fetches a slice of Reference objects for a given Git ref.
|
||||
// If there is an exact match, only that ref is returned.
|
||||
// If there is no exact match, GitHub returns all refs that start with ref.
|
||||
// If returned error is nil, there will be at least 1 ref returned.
|
||||
// For example:
|
||||
//
|
||||
// "heads/featureA" -> ["refs/heads/featureA"] // Exact match, single ref is returned.
|
||||
// "heads/feature" -> ["refs/heads/featureA", "refs/heads/featureB"] // All refs that start with ref.
|
||||
// "heads/notexist" -> [] // Returns an error.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-a-reference
|
||||
func (s *GitService) GetRefs(ctx context.Context, owner string, repo string, ref string) ([]*Reference, *Response, error) { |
||||
ref = strings.TrimPrefix(ref, "refs/") |
||||
u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, ref) |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var rawJSON json.RawMessage |
||||
resp, err := s.client.Do(ctx, req, &rawJSON) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
// Prioritize the most common case: a single returned ref.
|
||||
r := new(Reference) |
||||
singleUnmarshalError := json.Unmarshal(rawJSON, r) |
||||
if singleUnmarshalError == nil { |
||||
return []*Reference{r}, resp, nil |
||||
} |
||||
|
||||
// Attempt to unmarshal multiple refs.
|
||||
var rs []*Reference |
||||
multipleUnmarshalError := json.Unmarshal(rawJSON, &rs) |
||||
if multipleUnmarshalError == nil { |
||||
if len(rs) == 0 { |
||||
return nil, resp, fmt.Errorf("unexpected response from GitHub API: an array of refs with length 0") |
||||
} |
||||
return rs, resp, nil |
||||
} |
||||
|
||||
return nil, resp, fmt.Errorf("unmarshalling failed for both single and multiple refs: %s and %s", singleUnmarshalError, multipleUnmarshalError) |
||||
} |
||||
|
||||
// ReferenceListOptions specifies optional parameters to the
|
||||
// GitService.ListRefs method.
|
||||
type ReferenceListOptions struct { |
||||
Type string `url:"-"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListRefs lists all refs in a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/refs/#get-all-references
|
||||
func (s *GitService) ListRefs(ctx context.Context, 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) |
||||
} else { |
||||
u = fmt.Sprintf("repos/%v/%v/git/refs", owner, repo) |
||||
} |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var rs []*Reference |
||||
resp, err := s.client.Do(ctx, req, &rs) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return rs, resp, nil |
||||
} |
||||
|
||||
// CreateRef creates a new ref in a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/refs/#create-a-reference
|
||||
func (s *GitService) CreateRef(ctx context.Context, owner string, repo string, ref *Reference) (*Reference, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/refs", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, &createRefRequest{ |
||||
// back-compat with previous behavior that didn't require 'refs/' prefix
|
||||
Ref: String("refs/" + strings.TrimPrefix(*ref.Ref, "refs/")), |
||||
SHA: ref.Object.SHA, |
||||
}) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
r := new(Reference) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
||||
|
||||
// UpdateRef updates an existing ref in a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/refs/#update-a-reference
|
||||
func (s *GitService) UpdateRef(ctx context.Context, owner string, repo string, ref *Reference, force bool) (*Reference, *Response, error) { |
||||
refPath := strings.TrimPrefix(*ref.Ref, "refs/") |
||||
u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, refPath) |
||||
req, err := s.client.NewRequest("PATCH", u, &updateRefRequest{ |
||||
SHA: ref.Object.SHA, |
||||
Force: &force, |
||||
}) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
r := new(Reference) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
||||
|
||||
// DeleteRef deletes a ref from a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/refs/#delete-a-reference
|
||||
func (s *GitService) DeleteRef(ctx context.Context, owner string, repo string, ref string) (*Response, error) { |
||||
ref = strings.TrimPrefix(ref, "refs/") |
||||
u := fmt.Sprintf("repos/%v/%v/git/refs/%v", owner, repo, ref) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,84 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// 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"` |
||||
Verification *SignatureVerification `json:"verification,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
// createTagRequest represents the body of a CreateTag request. This is mostly
|
||||
// identical to Tag with the exception that the object SHA and Type are
|
||||
// top-level fields, rather than being nested inside a JSON object.
|
||||
type createTagRequest struct { |
||||
Tag *string `json:"tag,omitempty"` |
||||
Message *string `json:"message,omitempty"` |
||||
Object *string `json:"object,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
Tagger *CommitAuthor `json:"tagger,omitempty"` |
||||
} |
||||
|
||||
// GetTag fetchs a tag from a repo given a SHA.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag
|
||||
func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/tags/%v", owner, repo, sha) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeGitSigningPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
tag := new(Tag) |
||||
resp, err := s.client.Do(ctx, req, tag) |
||||
return tag, resp, err |
||||
} |
||||
|
||||
// CreateTag creates a tag object.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/tags/#create-a-tag-object
|
||||
func (s *GitService) CreateTag(ctx context.Context, owner string, repo string, tag *Tag) (*Tag, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/tags", owner, repo) |
||||
|
||||
// convert Tag into a createTagRequest
|
||||
tagRequest := &createTagRequest{ |
||||
Tag: tag.Tag, |
||||
Message: tag.Message, |
||||
Tagger: tag.Tagger, |
||||
} |
||||
if tag.Object != nil { |
||||
tagRequest.Object = tag.Object.SHA |
||||
tagRequest.Type = tag.Object.Type |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("POST", u, tagRequest) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
t := new(Tag) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
return t, resp, err |
||||
} |
@ -0,0 +1,93 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// Tree represents a GitHub tree.
|
||||
type Tree struct { |
||||
SHA *string `json:"sha,omitempty"` |
||||
Entries []TreeEntry `json:"tree,omitempty"` |
||||
} |
||||
|
||||
func (t Tree) String() string { |
||||
return Stringify(t) |
||||
} |
||||
|
||||
// TreeEntry represents the contents of a tree structure. TreeEntry can
|
||||
// represent either a blob, a commit (in the case of a submodule), or another
|
||||
// tree.
|
||||
type TreeEntry struct { |
||||
SHA *string `json:"sha,omitempty"` |
||||
Path *string `json:"path,omitempty"` |
||||
Mode *string `json:"mode,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
Size *int `json:"size,omitempty"` |
||||
Content *string `json:"content,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
} |
||||
|
||||
func (t TreeEntry) String() string { |
||||
return Stringify(t) |
||||
} |
||||
|
||||
// GetTree fetches the Tree object for a given sha hash from a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/trees/#get-a-tree
|
||||
func (s *GitService) GetTree(ctx context.Context, owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/trees/%v", owner, repo, sha) |
||||
if recursive { |
||||
u += "?recursive=1" |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
t := new(Tree) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
||||
|
||||
// createTree represents the body of a CreateTree request.
|
||||
type createTree struct { |
||||
BaseTree string `json:"base_tree,omitempty"` |
||||
Entries []TreeEntry `json:"tree"` |
||||
} |
||||
|
||||
// CreateTree creates a new tree in a repository. If both a tree and a nested
|
||||
// path modifying that tree are specified, it will overwrite the contents of
|
||||
// that tree with the new path contents and write a new tree out.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/trees/#create-a-tree
|
||||
func (s *GitService) CreateTree(ctx context.Context, owner string, repo string, baseTree string, entries []TreeEntry) (*Tree, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo) |
||||
|
||||
body := &createTree{ |
||||
BaseTree: baseTree, |
||||
Entries: entries, |
||||
} |
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
t := new(Tree) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,989 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen-accessors.go
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"io" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"net/url" |
||||
"reflect" |
||||
"strconv" |
||||
"strings" |
||||
"sync" |
||||
"time" |
||||
|
||||
"github.com/google/go-querystring/query" |
||||
) |
||||
|
||||
const ( |
||||
defaultBaseURL = "https://api.github.com/" |
||||
uploadBaseURL = "https://uploads.github.com/" |
||||
userAgent = "go-github" |
||||
|
||||
headerRateLimit = "X-RateLimit-Limit" |
||||
headerRateRemaining = "X-RateLimit-Remaining" |
||||
headerRateReset = "X-RateLimit-Reset" |
||||
headerOTP = "X-GitHub-OTP" |
||||
|
||||
mediaTypeV3 = "application/vnd.github.v3+json" |
||||
defaultMediaType = "application/octet-stream" |
||||
mediaTypeV3SHA = "application/vnd.github.v3.sha" |
||||
mediaTypeV3Diff = "application/vnd.github.v3.diff" |
||||
mediaTypeV3Patch = "application/vnd.github.v3.patch" |
||||
mediaTypeOrgPermissionRepo = "application/vnd.github.v3.repository+json" |
||||
|
||||
// Media Type values to access preview APIs
|
||||
|
||||
// https://developer.github.com/changes/2015-03-09-licenses-api/
|
||||
mediaTypeLicensesPreview = "application/vnd.github.drax-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2014-12-09-new-attributes-for-stars-api/
|
||||
mediaTypeStarringPreview = "application/vnd.github.v3.star+json" |
||||
|
||||
// https://developer.github.com/changes/2015-11-11-protected-branches-api/
|
||||
mediaTypeProtectedBranchesPreview = "application/vnd.github.loki-preview+json" |
||||
|
||||
// https://help.github.com/enterprise/2.4/admin/guides/migrations/exporting-the-github-com-organization-s-repositories/
|
||||
mediaTypeMigrationsPreview = "application/vnd.github.wyandotte-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2016-04-06-deployment-and-deployment-status-enhancements/
|
||||
mediaTypeDeploymentStatusPreview = "application/vnd.github.ant-man-preview+json" |
||||
|
||||
// https://developer.github.com/changes/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-04-git-signing-api-preview/
|
||||
mediaTypeGitSigningPreview = "application/vnd.github.cryptographer-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" |
||||
|
||||
// https://developer.github.com/changes/2016-07-06-github-pages-preiew-api/
|
||||
mediaTypePagesPreview = "application/vnd.github.mister-fantastic-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2016-09-14-projects-api/
|
||||
mediaTypeProjectsPreview = "application/vnd.github.inertia-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2016-09-14-Integrations-Early-Access/
|
||||
mediaTypeIntegrationPreview = "application/vnd.github.machine-man-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-01-05-commit-search-api/
|
||||
mediaTypeCommitSearchPreview = "application/vnd.github.cloak-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-02-28-user-blocking-apis-and-webhook/
|
||||
mediaTypeBlockUsersPreview = "application/vnd.github.giant-sentry-fist-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-02-09-community-health/
|
||||
mediaTypeRepositoryCommunityHealthMetricsPreview = "application/vnd.github.black-panther-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-05-23-coc-api/
|
||||
mediaTypeCodesOfConductPreview = "application/vnd.github.scarlet-witch-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-07-17-update-topics-on-repositories/
|
||||
mediaTypeTopicsPreview = "application/vnd.github.mercy-preview+json" |
||||
|
||||
// https://developer.github.com/v3/apps/marketplace/
|
||||
mediaTypeMarketplacePreview = "application/vnd.github.valkyrie-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-08-30-preview-nested-teams/
|
||||
mediaTypeNestedTeamsPreview = "application/vnd.github.hellcat-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-11-09-repository-transfer-api-preview/
|
||||
mediaTypeRepositoryTransferPreview = "application/vnd.github.nightshade-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2017-12-19-graphql-node-id/
|
||||
mediaTypeGraphQLNodeIDPreview = "application/vnd.github.jean-grey-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2018-01-25-organization-invitation-api-preview/
|
||||
mediaTypeOrganizationInvitationPreview = "application/vnd.github.dazzler-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2018-02-22-label-description-search-preview/
|
||||
mediaTypeLabelDescriptionSearchPreview = "application/vnd.github.symmetra-preview+json" |
||||
|
||||
// https://developer.github.com/changes/2018-02-07-team-discussions-api/
|
||||
mediaTypeTeamDiscussionsPreview = "application/vnd.github.echo-preview+json" |
||||
) |
||||
|
||||
// A Client manages communication with the GitHub API.
|
||||
type Client struct { |
||||
clientMu sync.Mutex // clientMu protects the client during calls that modify the CheckRedirect func.
|
||||
client *http.Client // HTTP client used to communicate with the API.
|
||||
|
||||
// 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
|
||||
// always be specified with a trailing slash.
|
||||
BaseURL *url.URL |
||||
|
||||
// Base URL for uploading files.
|
||||
UploadURL *url.URL |
||||
|
||||
// User agent used when communicating with the GitHub API.
|
||||
UserAgent string |
||||
|
||||
rateMu sync.Mutex |
||||
rateLimits [categories]Rate // Rate limits for the client as determined by the most recent API calls.
|
||||
|
||||
common service // Reuse a single struct instead of allocating one for each service on the heap.
|
||||
|
||||
// Services used for talking to different parts of the GitHub API.
|
||||
Activity *ActivityService |
||||
Admin *AdminService |
||||
Apps *AppsService |
||||
Authorizations *AuthorizationsService |
||||
Gists *GistsService |
||||
Git *GitService |
||||
Gitignores *GitignoresService |
||||
Issues *IssuesService |
||||
Licenses *LicensesService |
||||
Marketplace *MarketplaceService |
||||
Migrations *MigrationService |
||||
Organizations *OrganizationsService |
||||
Projects *ProjectsService |
||||
PullRequests *PullRequestsService |
||||
Reactions *ReactionsService |
||||
Repositories *RepositoriesService |
||||
Search *SearchService |
||||
Teams *TeamsService |
||||
Users *UsersService |
||||
} |
||||
|
||||
type service struct { |
||||
client *Client |
||||
} |
||||
|
||||
// ListOptions specifies the optional parameters to various List methods that
|
||||
// support pagination.
|
||||
type ListOptions struct { |
||||
// For paginated result sets, page of results to retrieve.
|
||||
Page int `url:"page,omitempty"` |
||||
|
||||
// For paginated result sets, the number of results to include per page.
|
||||
PerPage int `url:"per_page,omitempty"` |
||||
} |
||||
|
||||
// UploadOptions specifies the parameters to methods that support uploads.
|
||||
type UploadOptions struct { |
||||
Name string `url:"name,omitempty"` |
||||
} |
||||
|
||||
// RawType represents type of raw format of a request instead of JSON.
|
||||
type RawType uint8 |
||||
|
||||
const ( |
||||
// Diff format.
|
||||
Diff RawType = 1 + iota |
||||
// Patch format.
|
||||
Patch |
||||
) |
||||
|
||||
// RawOptions specifies parameters when user wants to get raw format of
|
||||
// a response instead of JSON.
|
||||
type RawOptions struct { |
||||
Type RawType |
||||
} |
||||
|
||||
// addOptions adds the parameters in opt as URL query parameters to s. opt
|
||||
// must be a struct whose fields may contain "url" tags.
|
||||
func addOptions(s string, opt interface{}) (string, error) { |
||||
v := reflect.ValueOf(opt) |
||||
if v.Kind() == reflect.Ptr && v.IsNil() { |
||||
return s, nil |
||||
} |
||||
|
||||
u, err := url.Parse(s) |
||||
if err != nil { |
||||
return s, err |
||||
} |
||||
|
||||
qs, err := query.Values(opt) |
||||
if err != nil { |
||||
return s, err |
||||
} |
||||
|
||||
u.RawQuery = qs.Encode() |
||||
return u.String(), nil |
||||
} |
||||
|
||||
// NewClient returns a new GitHub API client. If a nil httpClient is
|
||||
// provided, http.DefaultClient will be used. To use API methods which require
|
||||
// authentication, provide an http.Client that will perform the authentication
|
||||
// for you (such as that provided by the golang.org/x/oauth2 library).
|
||||
func NewClient(httpClient *http.Client) *Client { |
||||
if httpClient == nil { |
||||
httpClient = http.DefaultClient |
||||
} |
||||
baseURL, _ := url.Parse(defaultBaseURL) |
||||
uploadURL, _ := url.Parse(uploadBaseURL) |
||||
|
||||
c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent, UploadURL: uploadURL} |
||||
c.common.client = c |
||||
c.Activity = (*ActivityService)(&c.common) |
||||
c.Admin = (*AdminService)(&c.common) |
||||
c.Apps = (*AppsService)(&c.common) |
||||
c.Authorizations = (*AuthorizationsService)(&c.common) |
||||
c.Gists = (*GistsService)(&c.common) |
||||
c.Git = (*GitService)(&c.common) |
||||
c.Gitignores = (*GitignoresService)(&c.common) |
||||
c.Issues = (*IssuesService)(&c.common) |
||||
c.Licenses = (*LicensesService)(&c.common) |
||||
c.Marketplace = &MarketplaceService{client: c} |
||||
c.Migrations = (*MigrationService)(&c.common) |
||||
c.Organizations = (*OrganizationsService)(&c.common) |
||||
c.Projects = (*ProjectsService)(&c.common) |
||||
c.PullRequests = (*PullRequestsService)(&c.common) |
||||
c.Reactions = (*ReactionsService)(&c.common) |
||||
c.Repositories = (*RepositoriesService)(&c.common) |
||||
c.Search = (*SearchService)(&c.common) |
||||
c.Teams = (*TeamsService)(&c.common) |
||||
c.Users = (*UsersService)(&c.common) |
||||
return c |
||||
} |
||||
|
||||
// NewEnterpriseClient returns a new GitHub API client with provided
|
||||
// base URL and upload URL (often the same URL).
|
||||
// If either URL does not have a trailing slash, one is added automatically.
|
||||
// If a nil httpClient is provided, http.DefaultClient will be used.
|
||||
//
|
||||
// Note that NewEnterpriseClient is a convenience helper only;
|
||||
// its behavior is equivalent to using NewClient, followed by setting
|
||||
// the BaseURL and UploadURL fields.
|
||||
func NewEnterpriseClient(baseURL, uploadURL string, httpClient *http.Client) (*Client, error) { |
||||
baseEndpoint, err := url.Parse(baseURL) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if !strings.HasSuffix(baseEndpoint.Path, "/") { |
||||
baseEndpoint.Path += "/" |
||||
} |
||||
|
||||
uploadEndpoint, err := url.Parse(uploadURL) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if !strings.HasSuffix(uploadEndpoint.Path, "/") { |
||||
uploadEndpoint.Path += "/" |
||||
} |
||||
|
||||
c := NewClient(httpClient) |
||||
c.BaseURL = baseEndpoint |
||||
c.UploadURL = uploadEndpoint |
||||
return c, nil |
||||
} |
||||
|
||||
// NewRequest creates an API request. A relative URL can be provided in urlStr,
|
||||
// in which case it is resolved relative to the BaseURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash. If
|
||||
// specified, the value pointed to by body is JSON encoded and included as the
|
||||
// request body.
|
||||
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) { |
||||
if !strings.HasSuffix(c.BaseURL.Path, "/") { |
||||
return nil, fmt.Errorf("BaseURL must have a trailing slash, but %q does not", c.BaseURL) |
||||
} |
||||
u, err := c.BaseURL.Parse(urlStr) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
var buf io.ReadWriter |
||||
if body != nil { |
||||
buf = new(bytes.Buffer) |
||||
enc := json.NewEncoder(buf) |
||||
enc.SetEscapeHTML(false) |
||||
err := enc.Encode(body) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
req, err := http.NewRequest(method, u.String(), buf) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if body != nil { |
||||
req.Header.Set("Content-Type", "application/json") |
||||
} |
||||
req.Header.Set("Accept", mediaTypeV3) |
||||
if c.UserAgent != "" { |
||||
req.Header.Set("User-Agent", c.UserAgent) |
||||
} |
||||
return req, nil |
||||
} |
||||
|
||||
// NewUploadRequest creates an upload request. A relative URL can be provided in
|
||||
// urlStr, in which case it is resolved relative to the UploadURL of the Client.
|
||||
// Relative URLs should always be specified without a preceding slash.
|
||||
func (c *Client) NewUploadRequest(urlStr string, reader io.Reader, size int64, mediaType string) (*http.Request, error) { |
||||
if !strings.HasSuffix(c.UploadURL.Path, "/") { |
||||
return nil, fmt.Errorf("UploadURL must have a trailing slash, but %q does not", c.UploadURL) |
||||
} |
||||
u, err := c.UploadURL.Parse(urlStr) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
req, err := http.NewRequest("POST", u.String(), reader) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
req.ContentLength = size |
||||
|
||||
if mediaType == "" { |
||||
mediaType = defaultMediaType |
||||
} |
||||
req.Header.Set("Content-Type", mediaType) |
||||
req.Header.Set("Accept", mediaTypeV3) |
||||
req.Header.Set("User-Agent", c.UserAgent) |
||||
return req, nil |
||||
} |
||||
|
||||
// Response is a GitHub API response. This wraps the standard http.Response
|
||||
// returned from GitHub and provides convenient access to things like
|
||||
// pagination links.
|
||||
type Response struct { |
||||
*http.Response |
||||
|
||||
// These fields provide the page values for paginating through a set of
|
||||
// results. Any or all of these may be set to the zero value for
|
||||
// responses that are not part of a paginated set, or for which there
|
||||
// are no additional pages.
|
||||
|
||||
NextPage int |
||||
PrevPage int |
||||
FirstPage int |
||||
LastPage int |
||||
|
||||
Rate |
||||
} |
||||
|
||||
// newResponse creates a new Response for the provided http.Response.
|
||||
// r must not be nil.
|
||||
func newResponse(r *http.Response) *Response { |
||||
response := &Response{Response: r} |
||||
response.populatePageValues() |
||||
response.Rate = parseRate(r) |
||||
return response |
||||
} |
||||
|
||||
// populatePageValues parses the HTTP Link response headers and populates the
|
||||
// various pagination link values in the Response.
|
||||
func (r *Response) populatePageValues() { |
||||
if links, ok := r.Response.Header["Link"]; ok && len(links) > 0 { |
||||
for _, link := range strings.Split(links[0], ",") { |
||||
segments := strings.Split(strings.TrimSpace(link), ";") |
||||
|
||||
// link must at least have href and rel
|
||||
if len(segments) < 2 { |
||||
continue |
||||
} |
||||
|
||||
// ensure href is properly formatted
|
||||
if !strings.HasPrefix(segments[0], "<") || !strings.HasSuffix(segments[0], ">") { |
||||
continue |
||||
} |
||||
|
||||
// try to pull out page parameter
|
||||
url, err := url.Parse(segments[0][1 : len(segments[0])-1]) |
||||
if err != nil { |
||||
continue |
||||
} |
||||
page := url.Query().Get("page") |
||||
if page == "" { |
||||
continue |
||||
} |
||||
|
||||
for _, segment := range segments[1:] { |
||||
switch strings.TrimSpace(segment) { |
||||
case `rel="next"`: |
||||
r.NextPage, _ = strconv.Atoi(page) |
||||
case `rel="prev"`: |
||||
r.PrevPage, _ = strconv.Atoi(page) |
||||
case `rel="first"`: |
||||
r.FirstPage, _ = strconv.Atoi(page) |
||||
case `rel="last"`: |
||||
r.LastPage, _ = strconv.Atoi(page) |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// parseRate parses the rate related headers.
|
||||
func parseRate(r *http.Response) Rate { |
||||
var rate Rate |
||||
if limit := r.Header.Get(headerRateLimit); limit != "" { |
||||
rate.Limit, _ = strconv.Atoi(limit) |
||||
} |
||||
if remaining := r.Header.Get(headerRateRemaining); remaining != "" { |
||||
rate.Remaining, _ = strconv.Atoi(remaining) |
||||
} |
||||
if reset := r.Header.Get(headerRateReset); reset != "" { |
||||
if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 { |
||||
rate.Reset = Timestamp{time.Unix(v, 0)} |
||||
} |
||||
} |
||||
return rate |
||||
} |
||||
|
||||
// Do sends an API request and returns the API response. The API response is
|
||||
// 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. If rate limit is exceeded and reset time is in the future,
|
||||
// Do returns *RateLimitError immediately without making a network API call.
|
||||
//
|
||||
// The provided ctx must be non-nil. If it is canceled or times out,
|
||||
// ctx.Err() will be returned.
|
||||
func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) { |
||||
req = withContext(ctx, req) |
||||
|
||||
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 &Response{ |
||||
Response: err.Response, |
||||
Rate: err.Rate, |
||||
}, err |
||||
} |
||||
|
||||
resp, err := c.client.Do(req) |
||||
if err != nil { |
||||
// If we got an error, and the context has been canceled,
|
||||
// the context's error is probably more useful.
|
||||
select { |
||||
case <-ctx.Done(): |
||||
return nil, ctx.Err() |
||||
default: |
||||
} |
||||
|
||||
// If the error type is *url.Error, sanitize its URL before returning.
|
||||
if e, ok := err.(*url.Error); ok { |
||||
if url, err := url.Parse(e.URL); err == nil { |
||||
e.URL = sanitizeURL(url).String() |
||||
return nil, e |
||||
} |
||||
} |
||||
|
||||
return nil, err |
||||
} |
||||
defer resp.Body.Close() |
||||
|
||||
response := newResponse(resp) |
||||
|
||||
c.rateMu.Lock() |
||||
c.rateLimits[rateLimitCategory] = response.Rate |
||||
c.rateMu.Unlock() |
||||
|
||||
err = CheckResponse(resp) |
||||
if err != nil { |
||||
// Even though there was an error, we still return the response
|
||||
// in case the caller wants to inspect it further.
|
||||
// However, if the error is AcceptedError, decode it below before
|
||||
// returning from this function and closing the response body.
|
||||
if _, ok := err.(*AcceptedError); !ok { |
||||
return response, err |
||||
} |
||||
} |
||||
|
||||
if v != nil { |
||||
if w, ok := v.(io.Writer); ok { |
||||
io.Copy(w, resp.Body) |
||||
} else { |
||||
decErr := json.NewDecoder(resp.Body).Decode(v) |
||||
if decErr == io.EOF { |
||||
decErr = nil // ignore EOF errors caused by empty response body
|
||||
} |
||||
if decErr != nil { |
||||
err = decErr |
||||
} |
||||
} |
||||
} |
||||
|
||||
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 unnecessarily.
|
||||
// Otherwise it returns nil, and Client.Do should proceed normally.
|
||||
func (c *Client) checkRateLimitBeforeDo(req *http.Request, rateLimitCategory rateLimitCategory) *RateLimitError { |
||||
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. |
||||
|
||||
GitHub API docs: https://developer.github.com/v3/#client-errors
|
||||
*/ |
||||
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 { |
||||
return fmt.Sprintf("%v %v: %d %v %+v", |
||||
r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), |
||||
r.Response.StatusCode, r.Message, r.Errors) |
||||
} |
||||
|
||||
// TwoFactorAuthError occurs when using HTTP Basic Authentication for a user
|
||||
// that has two-factor authentication enabled. The request can be reattempted
|
||||
// by providing a one-time password in the request.
|
||||
type TwoFactorAuthError ErrorResponse |
||||
|
||||
func (r *TwoFactorAuthError) Error() string { return (*ErrorResponse)(r).Error() } |
||||
|
||||
// RateLimitError occurs when GitHub returns 403 Forbidden response with a rate limit
|
||||
// remaining value of 0, and error message starts with "API rate limit exceeded for ".
|
||||
type RateLimitError struct { |
||||
Rate Rate // Rate specifies last known rate limit for the client
|
||||
Response *http.Response // HTTP response that caused this error
|
||||
Message string `json:"message"` // error message
|
||||
} |
||||
|
||||
func (r *RateLimitError) Error() string { |
||||
return fmt.Sprintf("%v %v: %d %v %v", |
||||
r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), |
||||
r.Response.StatusCode, r.Message, formatRateReset(r.Rate.Reset.Time.Sub(time.Now()))) |
||||
} |
||||
|
||||
// AcceptedError occurs when GitHub returns 202 Accepted response with an
|
||||
// empty body, which means a job was scheduled on the GitHub side to process
|
||||
// the information needed and cache it.
|
||||
// Technically, 202 Accepted is not a real error, it's just used to
|
||||
// indicate that results are not ready yet, but should be available soon.
|
||||
// The request can be repeated after some time.
|
||||
type AcceptedError struct{} |
||||
|
||||
func (*AcceptedError) Error() string { |
||||
return "job scheduled on GitHub side; try again later" |
||||
} |
||||
|
||||
// AbuseRateLimitError occurs when GitHub returns 403 Forbidden response with the
|
||||
// "documentation_url" field value equal to "https://developer.github.com/v3/#abuse-rate-limits".
|
||||
type AbuseRateLimitError struct { |
||||
Response *http.Response // HTTP response that caused this error
|
||||
Message string `json:"message"` // error message
|
||||
|
||||
// RetryAfter is provided with some abuse rate limit errors. If present,
|
||||
// it is the amount of time that the client should wait before retrying.
|
||||
// Otherwise, the client should try again later (after an unspecified amount of time).
|
||||
RetryAfter *time.Duration |
||||
} |
||||
|
||||
func (r *AbuseRateLimitError) Error() string { |
||||
return fmt.Sprintf("%v %v: %d %v", |
||||
r.Response.Request.Method, sanitizeURL(r.Response.Request.URL), |
||||
r.Response.StatusCode, r.Message) |
||||
} |
||||
|
||||
// sanitizeURL redacts the client_secret parameter from the URL which may be
|
||||
// exposed to the user.
|
||||
func sanitizeURL(uri *url.URL) *url.URL { |
||||
if uri == nil { |
||||
return nil |
||||
} |
||||
params := uri.Query() |
||||
if len(params.Get("client_secret")) > 0 { |
||||
params.Set("client_secret", "REDACTED") |
||||
uri.RawQuery = params.Encode() |
||||
} |
||||
return uri |
||||
} |
||||
|
||||
/* |
||||
An Error reports more details on an individual error in an ErrorResponse. |
||||
These are the possible validation error codes: |
||||
|
||||
missing: |
||||
resource does not exist |
||||
missing_field: |
||||
a required field on a resource has not been set |
||||
invalid: |
||||
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: https://developer.github.com/v3/#client-errors
|
||||
*/ |
||||
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 { |
||||
return fmt.Sprintf("%v error caused by %v field on %v resource", |
||||
e.Code, e.Field, e.Resource) |
||||
} |
||||
|
||||
// CheckResponse checks the API response for errors, and returns them if
|
||||
// present. A response is considered an error if it has a status code outside
|
||||
// the 200 range or equal to 202 Accepted.
|
||||
// API error responses are expected to have either no response
|
||||
// body, or a JSON response body that maps to ErrorResponse. Any other
|
||||
// response body will be silently ignored.
|
||||
//
|
||||
// The error type will be *RateLimitError for rate limit exceeded errors,
|
||||
// *AcceptedError for 202 Accepted status codes,
|
||||
// and *TwoFactorAuthError for two-factor authentication errors.
|
||||
func CheckResponse(r *http.Response) error { |
||||
if r.StatusCode == http.StatusAccepted { |
||||
return &AcceptedError{} |
||||
} |
||||
if c := r.StatusCode; 200 <= c && c <= 299 { |
||||
return nil |
||||
} |
||||
errorResponse := &ErrorResponse{Response: r} |
||||
data, err := ioutil.ReadAll(r.Body) |
||||
if err == nil && data != nil { |
||||
json.Unmarshal(data, errorResponse) |
||||
} |
||||
switch { |
||||
case r.StatusCode == http.StatusUnauthorized && strings.HasPrefix(r.Header.Get(headerOTP), "required"): |
||||
return (*TwoFactorAuthError)(errorResponse) |
||||
case r.StatusCode == http.StatusForbidden && r.Header.Get(headerRateRemaining) == "0" && strings.HasPrefix(errorResponse.Message, "API rate limit exceeded for "): |
||||
return &RateLimitError{ |
||||
Rate: parseRate(r), |
||||
Response: errorResponse.Response, |
||||
Message: errorResponse.Message, |
||||
} |
||||
case r.StatusCode == http.StatusForbidden && strings.HasSuffix(errorResponse.DocumentationURL, "/v3/#abuse-rate-limits"): |
||||
abuseRateLimitError := &AbuseRateLimitError{ |
||||
Response: errorResponse.Response, |
||||
Message: errorResponse.Message, |
||||
} |
||||
if v := r.Header["Retry-After"]; len(v) > 0 { |
||||
// According to GitHub support, the "Retry-After" header value will be
|
||||
// an integer which represents the number of seconds that one should
|
||||
// wait before resuming making requests.
|
||||
retryAfterSeconds, _ := strconv.ParseInt(v[0], 10, 64) // Error handling is noop.
|
||||
retryAfter := time.Duration(retryAfterSeconds) * time.Second |
||||
abuseRateLimitError.RetryAfter = &retryAfter |
||||
} |
||||
return abuseRateLimitError |
||||
default: |
||||
return errorResponse |
||||
} |
||||
} |
||||
|
||||
// parseBoolResponse determines the boolean result from a GitHub API response.
|
||||
// Several GitHub API methods return boolean responses indicated by the HTTP
|
||||
// status code in the response (true indicated by a 204, false indicated by a
|
||||
// 404). This helper function will determine that result and hide the 404
|
||||
// error if present. Any other error will be returned through as-is.
|
||||
func parseBoolResponse(err error) (bool, error) { |
||||
if err == nil { |
||||
return true, nil |
||||
} |
||||
|
||||
if err, ok := err.(*ErrorResponse); ok && err.Response.StatusCode == http.StatusNotFound { |
||||
// Simply false. In this one case, we do not pass the error through.
|
||||
return false, nil |
||||
} |
||||
|
||||
// some other real error occurred
|
||||
return false, err |
||||
} |
||||
|
||||
// Rate represents the rate limit for the current client.
|
||||
type Rate struct { |
||||
// The number of requests per hour the client is currently limited to.
|
||||
Limit int `json:"limit"` |
||||
|
||||
// The number of remaining requests the client can make this hour.
|
||||
Remaining int `json:"remaining"` |
||||
|
||||
// The time at which the current rate limit will reset.
|
||||
Reset Timestamp `json:"reset"` |
||||
} |
||||
|
||||
func (r Rate) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// RateLimits represents the rate limits for the current client.
|
||||
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
|
||||
// are limited to 10 requests per minutes. Authenticated requests are
|
||||
// limited to 30 per minute.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#rate-limit
|
||||
Search *Rate `json:"search"` |
||||
} |
||||
|
||||
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 |
||||
} |
||||
} |
||||
|
||||
// RateLimits returns the rate limits for the current client.
|
||||
func (c *Client) RateLimits(ctx context.Context) (*RateLimits, *Response, error) { |
||||
req, err := c.NewRequest("GET", "rate_limit", nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
response := new(struct { |
||||
Resources *RateLimits `json:"resources"` |
||||
}) |
||||
resp, err := c.Do(ctx, req, response) |
||||
if err != nil { |
||||
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, nil |
||||
} |
||||
|
||||
/* |
||||
UnauthenticatedRateLimitedTransport allows you to make unauthenticated calls |
||||
that need to use a higher rate limit associated with your OAuth application. |
||||
|
||||
t := &github.UnauthenticatedRateLimitedTransport{ |
||||
ClientID: "your app's client ID", |
||||
ClientSecret: "your app's client secret", |
||||
} |
||||
client := github.NewClient(t.Client()) |
||||
|
||||
This will append the querystring params client_id=xxx&client_secret=yyy to all |
||||
requests. |
||||
|
||||
See https://developer.github.com/v3/#unauthenticated-rate-limited-requests for
|
||||
more information. |
||||
*/ |
||||
type UnauthenticatedRateLimitedTransport struct { |
||||
// ClientID is the GitHub OAuth client ID of the current application, which
|
||||
// can be found by selecting its entry in the list at
|
||||
// https://github.com/settings/applications.
|
||||
ClientID string |
||||
|
||||
// ClientSecret is the GitHub OAuth client secret of the current
|
||||
// application.
|
||||
ClientSecret string |
||||
|
||||
// Transport is the underlying HTTP transport to use when making requests.
|
||||
// It will default to http.DefaultTransport if nil.
|
||||
Transport http.RoundTripper |
||||
} |
||||
|
||||
// RoundTrip implements the RoundTripper interface.
|
||||
func (t *UnauthenticatedRateLimitedTransport) RoundTrip(req *http.Request) (*http.Response, error) { |
||||
if t.ClientID == "" { |
||||
return nil, errors.New("t.ClientID is empty") |
||||
} |
||||
if t.ClientSecret == "" { |
||||
return nil, errors.New("t.ClientSecret is empty") |
||||
} |
||||
|
||||
// To set extra querystring params, we must make a copy of the Request so
|
||||
// that we don't modify the Request we were given. This is required by the
|
||||
// specification of http.RoundTripper.
|
||||
//
|
||||
// Since we are going to modify only req.URL here, we only need a deep copy
|
||||
// of req.URL.
|
||||
req2 := new(http.Request) |
||||
*req2 = *req |
||||
req2.URL = new(url.URL) |
||||
*req2.URL = *req.URL |
||||
|
||||
q := req2.URL.Query() |
||||
q.Set("client_id", t.ClientID) |
||||
q.Set("client_secret", t.ClientSecret) |
||||
req2.URL.RawQuery = q.Encode() |
||||
|
||||
// Make the HTTP request.
|
||||
return t.transport().RoundTrip(req2) |
||||
} |
||||
|
||||
// Client returns an *http.Client that makes requests which are subject to the
|
||||
// rate limit of your OAuth application.
|
||||
func (t *UnauthenticatedRateLimitedTransport) Client() *http.Client { |
||||
return &http.Client{Transport: t} |
||||
} |
||||
|
||||
func (t *UnauthenticatedRateLimitedTransport) transport() http.RoundTripper { |
||||
if t.Transport != nil { |
||||
return t.Transport |
||||
} |
||||
return http.DefaultTransport |
||||
} |
||||
|
||||
// BasicAuthTransport is an http.RoundTripper that authenticates all requests
|
||||
// using HTTP Basic Authentication with the provided username and password. It
|
||||
// additionally supports users who have two-factor authentication enabled on
|
||||
// their GitHub account.
|
||||
type BasicAuthTransport struct { |
||||
Username string // GitHub username
|
||||
Password string // GitHub password
|
||||
OTP string // one-time password for users with two-factor auth enabled
|
||||
|
||||
// Transport is the underlying HTTP transport to use when making requests.
|
||||
// It will default to http.DefaultTransport if nil.
|
||||
Transport http.RoundTripper |
||||
} |
||||
|
||||
// RoundTrip implements the RoundTripper interface.
|
||||
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { |
||||
// To set extra headers, we must make a copy of the Request so
|
||||
// that we don't modify the Request we were given. This is required by the
|
||||
// specification of http.RoundTripper.
|
||||
//
|
||||
// Since we are going to modify only req.Header here, we only need a deep copy
|
||||
// of req.Header.
|
||||
req2 := new(http.Request) |
||||
*req2 = *req |
||||
req2.Header = make(http.Header, len(req.Header)) |
||||
for k, s := range req.Header { |
||||
req2.Header[k] = append([]string(nil), s...) |
||||
} |
||||
|
||||
req2.SetBasicAuth(t.Username, t.Password) |
||||
if t.OTP != "" { |
||||
req2.Header.Set(headerOTP, t.OTP) |
||||
} |
||||
return t.transport().RoundTrip(req2) |
||||
} |
||||
|
||||
// Client returns an *http.Client that makes requests that are authenticated
|
||||
// using HTTP Basic Authentication.
|
||||
func (t *BasicAuthTransport) Client() *http.Client { |
||||
return &http.Client{Transport: t} |
||||
} |
||||
|
||||
func (t *BasicAuthTransport) transport() http.RoundTripper { |
||||
if t.Transport != nil { |
||||
return t.Transport |
||||
} |
||||
return http.DefaultTransport |
||||
} |
||||
|
||||
// formatRateReset formats d to look like "[rate reset in 2s]" or
|
||||
// "[rate reset in 87m02s]" for the positive durations. And like "[rate limit was reset 87m02s ago]"
|
||||
// for the negative cases.
|
||||
func formatRateReset(d time.Duration) string { |
||||
isNegative := d < 0 |
||||
if isNegative { |
||||
d *= -1 |
||||
} |
||||
secondsTotal := int(0.5 + d.Seconds()) |
||||
minutes := secondsTotal / 60 |
||||
seconds := secondsTotal - minutes*60 |
||||
|
||||
var timeString string |
||||
if minutes > 0 { |
||||
timeString = fmt.Sprintf("%dm%02ds", minutes, seconds) |
||||
} else { |
||||
timeString = fmt.Sprintf("%ds", seconds) |
||||
} |
||||
|
||||
if isNegative { |
||||
return fmt.Sprintf("[rate limit was reset %v ago]", timeString) |
||||
} |
||||
return fmt.Sprintf("[rate reset in %v]", timeString) |
||||
} |
||||
|
||||
// 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 { return &v } |
||||
|
||||
// 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 } |
||||
|
||||
// Int64 is a helper routine that allocates a new int64 value
|
||||
// to store v and returns a pointer to it.
|
||||
func Int64(v int64) *int64 { return &v } |
||||
|
||||
// String is a helper routine that allocates a new string value
|
||||
// to store v and returns a pointer to it.
|
||||
func String(v string) *string { return &v } |
@ -0,0 +1,64 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// GitignoresService provides access to the gitignore related functions in the
|
||||
// GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gitignore/
|
||||
type GitignoresService service |
||||
|
||||
// Gitignore represents a .gitignore file as returned by the GitHub API.
|
||||
type Gitignore struct { |
||||
Name *string `json:"name,omitempty"` |
||||
Source *string `json:"source,omitempty"` |
||||
} |
||||
|
||||
func (g Gitignore) String() string { |
||||
return Stringify(g) |
||||
} |
||||
|
||||
// List all available Gitignore templates.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gitignore/#listing-available-templates
|
||||
func (s GitignoresService) List(ctx context.Context) ([]string, *Response, error) { |
||||
req, err := s.client.NewRequest("GET", "gitignore/templates", nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var availableTemplates []string |
||||
resp, err := s.client.Do(ctx, req, &availableTemplates) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return availableTemplates, resp, nil |
||||
} |
||||
|
||||
// Get a Gitignore by name.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/gitignore/#get-a-single-template
|
||||
func (s GitignoresService) Get(ctx context.Context, name string) (*Gitignore, *Response, error) { |
||||
u := fmt.Sprintf("gitignore/templates/%v", name) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
gitignore := new(Gitignore) |
||||
resp, err := s.client.Do(ctx, req, gitignore) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return gitignore, resp, nil |
||||
} |
@ -0,0 +1,332 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
// IssuesService handles communication with the issue related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/
|
||||
type IssuesService service |
||||
|
||||
// Issue represents a GitHub issue on a repository.
|
||||
//
|
||||
// Note: As far as the GitHub API is concerned, every pull request is an issue,
|
||||
// but not every issue is a pull request. Some endpoints, events, and webhooks
|
||||
// may also return pull requests via this struct. If PullRequestLinks is nil,
|
||||
// this is an issue, and if PullRequestLinks is not nil, this is a pull request.
|
||||
// The IsPullRequest helper method can be used to check that.
|
||||
type Issue struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
Number *int `json:"number,omitempty"` |
||||
State *string `json:"state,omitempty"` |
||||
Locked *bool `json:"locked,omitempty"` |
||||
Title *string `json:"title,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
Labels []Label `json:"labels,omitempty"` |
||||
Assignee *User `json:"assignee,omitempty"` |
||||
Comments *int `json:"comments,omitempty"` |
||||
ClosedAt *time.Time `json:"closed_at,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
ClosedBy *User `json:"closed_by,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
CommentsURL *string `json:"comments_url,omitempty"` |
||||
EventsURL *string `json:"events_url,omitempty"` |
||||
LabelsURL *string `json:"labels_url,omitempty"` |
||||
RepositoryURL *string `json:"repository_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"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
|
||||
// TextMatches is only populated from search results that request text matches
|
||||
// See: search.go and https://developer.github.com/v3/search/#text-match-metadata
|
||||
TextMatches []TextMatch `json:"text_matches,omitempty"` |
||||
} |
||||
|
||||
func (i Issue) String() string { |
||||
return Stringify(i) |
||||
} |
||||
|
||||
// IsPullRequest reports whether the issue is also a pull request. It uses the
|
||||
// method recommended by GitHub's API documentation, which is to check whether
|
||||
// PullRequestLinks is non-nil.
|
||||
func (i Issue) IsPullRequest() bool { |
||||
return i.PullRequestLinks != nil |
||||
} |
||||
|
||||
// IssueRequest represents a request to create/edit an issue.
|
||||
// It is separate from Issue above because otherwise Labels
|
||||
// and Assignee fail to serialize to the correct JSON.
|
||||
type IssueRequest struct { |
||||
Title *string `json:"title,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Labels *[]string `json:"labels,omitempty"` |
||||
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
|
||||
// and IssuesService.ListByOrg methods.
|
||||
type IssueListOptions struct { |
||||
// Filter specifies which issues to list. Possible values are: assigned,
|
||||
// created, mentioned, subscribed, all. Default is "assigned".
|
||||
Filter string `url:"filter,omitempty"` |
||||
|
||||
// State filters issues based on their state. Possible values are: open,
|
||||
// closed, all. Default is "open".
|
||||
State string `url:"state,omitempty"` |
||||
|
||||
// Labels filters issues based on their label.
|
||||
Labels []string `url:"labels,comma,omitempty"` |
||||
|
||||
// Sort specifies how to sort issues. Possible values are: created, updated,
|
||||
// and comments. Default value is "created".
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// Direction in which to sort issues. Possible values are: asc, desc.
|
||||
// Default is "desc".
|
||||
Direction string `url:"direction,omitempty"` |
||||
|
||||
// Since filters issues by time.
|
||||
Since time.Time `url:"since,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// PullRequestLinks object is added to the Issue object when it's an issue included
|
||||
// in the IssueCommentEvent webhook payload, if the webhook is fired by a comment on a PR.
|
||||
type PullRequestLinks struct { |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
DiffURL *string `json:"diff_url,omitempty"` |
||||
PatchURL *string `json:"patch_url,omitempty"` |
||||
} |
||||
|
||||
// List the issues for the authenticated user. If all is true, list issues
|
||||
// across all the user's visible repositories including owned, member, and
|
||||
// organization repositories; if false, list only owned and member
|
||||
// repositories.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#list-issues
|
||||
func (s *IssuesService) List(ctx context.Context, all bool, opt *IssueListOptions) ([]*Issue, *Response, error) { |
||||
var u string |
||||
if all { |
||||
u = "issues" |
||||
} else { |
||||
u = "user/issues" |
||||
} |
||||
return s.listIssues(ctx, u, opt) |
||||
} |
||||
|
||||
// ListByOrg fetches the issues in the specified organization for the
|
||||
// authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#list-issues
|
||||
func (s *IssuesService) ListByOrg(ctx context.Context, org string, opt *IssueListOptions) ([]*Issue, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/issues", org) |
||||
return s.listIssues(ctx, u, opt) |
||||
} |
||||
|
||||
func (s *IssuesService) listIssues(ctx context.Context, u string, opt *IssueListOptions) ([]*Issue, *Response, error) { |
||||
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 headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var issues []*Issue |
||||
resp, err := s.client.Do(ctx, req, &issues) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return issues, resp, nil |
||||
} |
||||
|
||||
// IssueListByRepoOptions specifies the optional parameters to the
|
||||
// IssuesService.ListByRepo method.
|
||||
type IssueListByRepoOptions struct { |
||||
// Milestone limits issues for the specified milestone. Possible values are
|
||||
// a milestone number, "none" for issues with no milestone, "*" for issues
|
||||
// with any milestone.
|
||||
Milestone string `url:"milestone,omitempty"` |
||||
|
||||
// State filters issues based on their state. Possible values are: open,
|
||||
// closed, all. Default is "open".
|
||||
State string `url:"state,omitempty"` |
||||
|
||||
// Assignee filters issues based on their assignee. Possible values are a
|
||||
// user name, "none" for issues that are not assigned, "*" for issues with
|
||||
// any assigned user.
|
||||
Assignee string `url:"assignee,omitempty"` |
||||
|
||||
// Creator filters issues based on their creator.
|
||||
Creator string `url:"creator,omitempty"` |
||||
|
||||
// Mentioned filters issues to those mentioned a specific user.
|
||||
Mentioned string `url:"mentioned,omitempty"` |
||||
|
||||
// Labels filters issues based on their label.
|
||||
Labels []string `url:"labels,omitempty,comma"` |
||||
|
||||
// Sort specifies how to sort issues. Possible values are: created, updated,
|
||||
// and comments. Default value is "created".
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// Direction in which to sort issues. Possible values are: asc, desc.
|
||||
// Default is "desc".
|
||||
Direction string `url:"direction,omitempty"` |
||||
|
||||
// Since filters issues by time.
|
||||
Since time.Time `url:"since,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListByRepo lists the issues for the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#list-issues-for-a-repository
|
||||
func (s *IssuesService) ListByRepo(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var issues []*Issue |
||||
resp, err := s.client.Do(ctx, req, &issues) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return issues, resp, nil |
||||
} |
||||
|
||||
// Get a single issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#get-a-single-issue
|
||||
func (s *IssuesService) Get(ctx context.Context, owner string, repo string, number int) (*Issue, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
issue := new(Issue) |
||||
resp, err := s.client.Do(ctx, req, issue) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return issue, resp, nil |
||||
} |
||||
|
||||
// Create a new issue on the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#create-an-issue
|
||||
func (s *IssuesService) Create(ctx context.Context, owner string, repo string, issue *IssueRequest) (*Issue, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, issue) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
i := new(Issue) |
||||
resp, err := s.client.Do(ctx, req, i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i, resp, nil |
||||
} |
||||
|
||||
// Edit an issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#edit-an-issue
|
||||
func (s *IssuesService) Edit(ctx context.Context, owner string, repo string, number int, issue *IssueRequest) (*Issue, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/%d", owner, repo, number) |
||||
req, err := s.client.NewRequest("PATCH", u, issue) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
i := new(Issue) |
||||
resp, err := s.client.Do(ctx, req, i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i, resp, nil |
||||
} |
||||
|
||||
// Lock an issue's conversation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue
|
||||
func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int) (*Response, error) { |
||||
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 |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// Unlock an issue's conversation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#unlock-an-issue
|
||||
func (s *IssuesService) Unlock(ctx context.Context, 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 |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,85 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListAssignees fetches all available assignees (owners and collaborators) to
|
||||
// which issues may be assigned.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/assignees/#list-assignees
|
||||
func (s *IssuesService) ListAssignees(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
var assignees []*User |
||||
resp, err := s.client.Do(ctx, req, &assignees) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return assignees, resp, nil |
||||
} |
||||
|
||||
// IsAssignee checks if a user is an assignee for the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/assignees/#check-assignee
|
||||
func (s *IssuesService) IsAssignee(ctx context.Context, 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 { |
||||
return false, nil, err |
||||
} |
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
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(ctx context.Context, 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 |
||||
} |
||||
|
||||
issue := &Issue{} |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, 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 |
||||
} |
||||
|
||||
issue := &Issue{} |
||||
resp, err := s.client.Do(ctx, req, issue) |
||||
return issue, resp, err |
||||
} |
@ -0,0 +1,152 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// IssueComment represents a comment left on an issue.
|
||||
type IssueComment struct { |
||||
ID *int64 `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"` |
||||
// AuthorAssociation is the comment author's relationship to the issue's repository.
|
||||
// Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
|
||||
AuthorAssociation *string `json:"author_association,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
IssueURL *string `json:"issue_url,omitempty"` |
||||
} |
||||
|
||||
func (i IssueComment) String() string { |
||||
return Stringify(i) |
||||
} |
||||
|
||||
// IssueListCommentsOptions specifies the optional parameters to the
|
||||
// IssuesService.ListComments method.
|
||||
type IssueListCommentsOptions struct { |
||||
// Sort specifies how to sort comments. Possible values are: created, updated.
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// Direction in which to sort comments. Possible values are: asc, desc.
|
||||
Direction string `url:"direction,omitempty"` |
||||
|
||||
// Since filters comments by time.
|
||||
Since time.Time `url:"since,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListComments lists all comments on the specified issue. Specifying an issue
|
||||
// number of 0 will return all comments on all issues for the repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue
|
||||
func (s *IssuesService) ListComments(ctx context.Context, 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) |
||||
} else { |
||||
u = fmt.Sprintf("repos/%v/%v/issues/%d/comments", 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 comments []*IssueComment |
||||
resp, err := s.client.Do(ctx, req, &comments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comments, resp, nil |
||||
} |
||||
|
||||
// GetComment fetches the specified issue comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/comments/#get-a-single-comment
|
||||
func (s *IssuesService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*IssueComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
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(ctx, req, comment) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comment, resp, nil |
||||
} |
||||
|
||||
// CreateComment creates a new comment on the specified issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/comments/#create-a-comment
|
||||
func (s *IssuesService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *IssueComment) (*IssueComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/%d/comments", owner, repo, number) |
||||
req, err := s.client.NewRequest("POST", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
c := new(IssueComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// EditComment updates an issue comment.
|
||||
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/comments/#edit-a-comment
|
||||
func (s *IssuesService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *IssueComment) (*IssueComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) |
||||
req, err := s.client.NewRequest("PATCH", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
c := new(IssueComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// DeleteComment deletes an issue comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/comments/#delete-a-comment
|
||||
func (s *IssuesService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/comments/%d", owner, repo, commentID) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,151 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// IssueEvent represents an event that occurred around an Issue or Pull Request.
|
||||
type IssueEvent struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
|
||||
// The User that generated this event.
|
||||
Actor *User `json:"actor,omitempty"` |
||||
|
||||
// Event identifies the actual type of Event that occurred. Possible
|
||||
// values are:
|
||||
//
|
||||
// closed
|
||||
// The Actor closed the issue.
|
||||
// If the issue was closed by commit message, CommitID holds the SHA1 hash of the commit.
|
||||
//
|
||||
// merged
|
||||
// The Actor merged into master a branch containing a commit mentioning the issue.
|
||||
// CommitID holds the SHA1 of the merge commit.
|
||||
//
|
||||
// referenced
|
||||
// The Actor committed to master a commit mentioning the issue in its commit message.
|
||||
// CommitID holds the SHA1 of the commit.
|
||||
//
|
||||
// reopened, locked, unlocked
|
||||
// The Actor did that to the issue.
|
||||
//
|
||||
// renamed
|
||||
// The Actor changed the issue title from Rename.From to Rename.To.
|
||||
//
|
||||
// mentioned
|
||||
// Someone unspecified @mentioned the Actor [sic] in an issue comment body.
|
||||
//
|
||||
// assigned, unassigned
|
||||
// The Assigner assigned the issue to or removed the assignment from the Assignee.
|
||||
//
|
||||
// labeled, unlabeled
|
||||
// The Actor added or removed the Label from the issue.
|
||||
//
|
||||
// milestoned, demilestoned
|
||||
// The Actor added or removed the issue from the Milestone.
|
||||
//
|
||||
// subscribed, unsubscribed
|
||||
// The Actor subscribed to or unsubscribed from notifications for an issue.
|
||||
//
|
||||
// head_ref_deleted, head_ref_restored
|
||||
// The pull request’s branch was deleted or restored.
|
||||
//
|
||||
Event *string `json:"event,omitempty"` |
||||
|
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
Issue *Issue `json:"issue,omitempty"` |
||||
|
||||
// Only present on certain events; see above.
|
||||
Assignee *User `json:"assignee,omitempty"` |
||||
Assigner *User `json:"assigner,omitempty"` |
||||
CommitID *string `json:"commit_id,omitempty"` |
||||
Milestone *Milestone `json:"milestone,omitempty"` |
||||
Label *Label `json:"label,omitempty"` |
||||
Rename *Rename `json:"rename,omitempty"` |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*IssueEvent |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var events []*IssueEvent |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return events, resp, nil |
||||
} |
||||
|
||||
// GetEvent returns the specified issue event.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/events/#get-a-single-event
|
||||
func (s *IssuesService) GetEvent(ctx context.Context, owner, repo string, id int64) (*IssueEvent, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/events/%v", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
event := new(IssueEvent) |
||||
resp, err := s.client.Do(ctx, req, event) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return event, resp, nil |
||||
} |
||||
|
||||
// Rename contains details for 'renamed' events.
|
||||
type Rename struct { |
||||
From *string `json:"from,omitempty"` |
||||
To *string `json:"to,omitempty"` |
||||
} |
||||
|
||||
func (r Rename) String() string { |
||||
return Stringify(r) |
||||
} |
@ -0,0 +1,270 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// Label represents a GitHub label on an Issue
|
||||
type Label struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Color *string `json:"color,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Default *bool `json:"default,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (l Label) String() string { |
||||
return Stringify(l) |
||||
} |
||||
|
||||
// ListLabels lists all labels for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository
|
||||
func (s *IssuesService) ListLabels(ctx context.Context, 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 { |
||||
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.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var labels []*Label |
||||
resp, err := s.client.Do(ctx, req, &labels) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return labels, resp, nil |
||||
} |
||||
|
||||
// GetLabel gets a single label.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-a-single-label
|
||||
func (s *IssuesService) GetLabel(ctx context.Context, owner string, repo string, name string) (*Label, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) |
||||
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.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
label := new(Label) |
||||
resp, err := s.client.Do(ctx, req, label) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return label, resp, nil |
||||
} |
||||
|
||||
// CreateLabel creates a new label on the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#create-a-label
|
||||
func (s *IssuesService) CreateLabel(ctx context.Context, owner string, repo string, label *Label) (*Label, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/labels", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, label) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
l := new(Label) |
||||
resp, err := s.client.Do(ctx, req, l) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return l, resp, nil |
||||
} |
||||
|
||||
// EditLabel edits a label.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#update-a-label
|
||||
func (s *IssuesService) EditLabel(ctx context.Context, owner string, repo string, name string, label *Label) (*Label, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) |
||||
req, err := s.client.NewRequest("PATCH", u, label) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
l := new(Label) |
||||
resp, err := s.client.Do(ctx, req, l) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return l, resp, nil |
||||
} |
||||
|
||||
// DeleteLabel deletes a label.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#delete-a-label
|
||||
func (s *IssuesService) DeleteLabel(ctx context.Context, owner string, repo string, name string) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/labels/%v", owner, repo, name) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ListLabelsByIssue lists all labels for an issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#list-labels-on-an-issue
|
||||
func (s *IssuesService) ListLabelsByIssue(ctx context.Context, 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 { |
||||
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.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var labels []*Label |
||||
resp, err := s.client.Do(ctx, req, &labels) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return labels, resp, nil |
||||
} |
||||
|
||||
// AddLabelsToIssue adds labels to an issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue
|
||||
func (s *IssuesService) AddLabelsToIssue(ctx context.Context, 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 |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var l []*Label |
||||
resp, err := s.client.Do(ctx, req, &l) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return l, resp, nil |
||||
} |
||||
|
||||
// RemoveLabelForIssue removes a label for an issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue
|
||||
func (s *IssuesService) RemoveLabelForIssue(ctx context.Context, owner string, repo string, number int, label string) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/%d/labels/%v", owner, repo, number, label) |
||||
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", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ReplaceLabelsForIssue replaces all labels for an issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#replace-all-labels-for-an-issue
|
||||
func (s *IssuesService) ReplaceLabelsForIssue(ctx context.Context, 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 |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var l []*Label |
||||
resp, err := s.client.Do(ctx, req, &l) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return l, resp, nil |
||||
} |
||||
|
||||
// RemoveLabelsForIssue removes all labels for an issue.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#remove-all-labels-from-an-issue
|
||||
func (s *IssuesService) RemoveLabelsForIssue(ctx context.Context, owner string, repo string, number int) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/%d/labels", 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", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ListLabelsForMilestone lists labels for every issue in a milestone.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/labels/#get-labels-for-every-issue-in-a-milestone
|
||||
func (s *IssuesService) ListLabelsForMilestone(ctx context.Context, 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 { |
||||
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.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var labels []*Label |
||||
resp, err := s.client.Do(ctx, req, &labels) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return labels, resp, nil |
||||
} |
@ -0,0 +1,160 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// 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 *int64 `json:"id,omitempty"` |
||||
Number *int `json:"number,omitempty"` |
||||
State *string `json:"state,omitempty"` |
||||
Title *string `json:"title,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Creator *User `json:"creator,omitempty"` |
||||
OpenIssues *int `json:"open_issues,omitempty"` |
||||
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"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (m Milestone) String() string { |
||||
return Stringify(m) |
||||
} |
||||
|
||||
// MilestoneListOptions specifies the optional parameters to the
|
||||
// IssuesService.ListMilestones method.
|
||||
type MilestoneListOptions struct { |
||||
// State filters milestones based on their state. Possible values are:
|
||||
// open, closed, all. Default is "open".
|
||||
State string `url:"state,omitempty"` |
||||
|
||||
// Sort specifies how to sort milestones. Possible values are: due_on, completeness.
|
||||
// Default value is "due_on".
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// 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(ctx context.Context, 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 { |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var milestones []*Milestone |
||||
resp, err := s.client.Do(ctx, req, &milestones) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return milestones, resp, nil |
||||
} |
||||
|
||||
// GetMilestone gets a single milestone.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#get-a-single-milestone
|
||||
func (s *IssuesService) GetMilestone(ctx context.Context, owner string, repo string, number int) (*Milestone, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
milestone := new(Milestone) |
||||
resp, err := s.client.Do(ctx, req, milestone) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return milestone, resp, nil |
||||
} |
||||
|
||||
// CreateMilestone creates a new milestone on the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#create-a-milestone
|
||||
func (s *IssuesService) CreateMilestone(ctx context.Context, owner string, repo string, milestone *Milestone) (*Milestone, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/milestones", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, milestone) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
m := new(Milestone) |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// EditMilestone edits a milestone.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#update-a-milestone
|
||||
func (s *IssuesService) EditMilestone(ctx context.Context, owner string, repo string, number int, milestone *Milestone) (*Milestone, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) |
||||
req, err := s.client.NewRequest("PATCH", u, milestone) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
m := new(Milestone) |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// DeleteMilestone deletes a milestone.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/milestones/#delete-a-milestone
|
||||
func (s *IssuesService) DeleteMilestone(ctx context.Context, owner string, repo string, number int) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/milestones/%d", owner, repo, number) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,149 @@
|
||||
// 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 ( |
||||
"context" |
||||
"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 *int64 `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 *int64 `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(ctx context.Context, 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(ctx, req, &events) |
||||
return events, resp, err |
||||
} |
@ -0,0 +1,103 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// LicensesService handles communication with the license related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/licenses/
|
||||
type LicensesService service |
||||
|
||||
// RepositoryLicense represents the license for a repository.
|
||||
type RepositoryLicense struct { |
||||
Name *string `json:"name,omitempty"` |
||||
Path *string `json:"path,omitempty"` |
||||
|
||||
SHA *string `json:"sha,omitempty"` |
||||
Size *int `json:"size,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
GitURL *string `json:"git_url,omitempty"` |
||||
DownloadURL *string `json:"download_url,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
Content *string `json:"content,omitempty"` |
||||
Encoding *string `json:"encoding,omitempty"` |
||||
License *License `json:"license,omitempty"` |
||||
} |
||||
|
||||
func (l RepositoryLicense) String() string { |
||||
return Stringify(l) |
||||
} |
||||
|
||||
// License represents an open source license.
|
||||
type License struct { |
||||
Key *string `json:"key,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
|
||||
SPDXID *string `json:"spdx_id,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
Featured *bool `json:"featured,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Implementation *string `json:"implementation,omitempty"` |
||||
Permissions *[]string `json:"permissions,omitempty"` |
||||
Conditions *[]string `json:"conditions,omitempty"` |
||||
Limitations *[]string `json:"limitations,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
} |
||||
|
||||
func (l License) String() string { |
||||
return Stringify(l) |
||||
} |
||||
|
||||
// List popular open source licenses.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/licenses/#list-all-licenses
|
||||
func (s *LicensesService) List(ctx context.Context) ([]*License, *Response, error) { |
||||
req, err := s.client.NewRequest("GET", "licenses", nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches
|
||||
req.Header.Set("Accept", mediaTypeLicensesPreview) |
||||
|
||||
var licenses []*License |
||||
resp, err := s.client.Do(ctx, req, &licenses) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return licenses, resp, nil |
||||
} |
||||
|
||||
// Get extended metadata for one license.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/licenses/#get-an-individual-license
|
||||
func (s *LicensesService) Get(ctx context.Context, licenseName string) (*License, *Response, error) { |
||||
u := fmt.Sprintf("licenses/%s", licenseName) |
||||
|
||||
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", mediaTypeLicensesPreview) |
||||
|
||||
license := new(License) |
||||
resp, err := s.client.Do(ctx, req, license) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return license, resp, nil |
||||
} |
@ -0,0 +1,245 @@
|
||||
// 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 API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"crypto/hmac" |
||||
"crypto/sha1" |
||||
"crypto/sha256" |
||||
"crypto/sha512" |
||||
"encoding/hex" |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"hash" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"net/url" |
||||
"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" |
||||
// eventTypeHeader is the GitHub header key used to pass the event type.
|
||||
eventTypeHeader = "X-Github-Event" |
||||
// deliveryIDHeader is the GitHub header key used to pass the unique ID for the webhook event.
|
||||
deliveryIDHeader = "X-Github-Delivery" |
||||
) |
||||
|
||||
var ( |
||||
// eventTypeMapping maps webhooks types to their corresponding go-github struct types.
|
||||
eventTypeMapping = map[string]string{ |
||||
"commit_comment": "CommitCommentEvent", |
||||
"create": "CreateEvent", |
||||
"delete": "DeleteEvent", |
||||
"deployment": "DeploymentEvent", |
||||
"deployment_status": "DeploymentStatusEvent", |
||||
"fork": "ForkEvent", |
||||
"gollum": "GollumEvent", |
||||
"installation": "InstallationEvent", |
||||
"installation_repositories": "InstallationRepositoriesEvent", |
||||
"issue_comment": "IssueCommentEvent", |
||||
"issues": "IssuesEvent", |
||||
"label": "LabelEvent", |
||||
"marketplace_purchase": "MarketplacePurchaseEvent", |
||||
"member": "MemberEvent", |
||||
"membership": "MembershipEvent", |
||||
"milestone": "MilestoneEvent", |
||||
"organization": "OrganizationEvent", |
||||
"org_block": "OrgBlockEvent", |
||||
"page_build": "PageBuildEvent", |
||||
"ping": "PingEvent", |
||||
"project": "ProjectEvent", |
||||
"project_card": "ProjectCardEvent", |
||||
"project_column": "ProjectColumnEvent", |
||||
"public": "PublicEvent", |
||||
"pull_request_review": "PullRequestReviewEvent", |
||||
"pull_request_review_comment": "PullRequestReviewCommentEvent", |
||||
"pull_request": "PullRequestEvent", |
||||
"push": "PushEvent", |
||||
"repository": "RepositoryEvent", |
||||
"release": "ReleaseEvent", |
||||
"status": "StatusEvent", |
||||
"team": "TeamEvent", |
||||
"team_add": "TeamAddEvent", |
||||
"watch": "WatchEvent", |
||||
} |
||||
) |
||||
|
||||
// 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.
|
||||
// The Content-Type header of the payload can be "application/json" or "application/x-www-form-urlencoded".
|
||||
// If the Content-Type is neither then an error is returned.
|
||||
// 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) { |
||||
var body []byte // Raw body that GitHub uses to calculate the signature.
|
||||
|
||||
switch ct := r.Header.Get("Content-Type"); ct { |
||||
case "application/json": |
||||
var err error |
||||
if body, err = ioutil.ReadAll(r.Body); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// If the content type is application/json,
|
||||
// the JSON payload is just the original body.
|
||||
payload = body |
||||
|
||||
case "application/x-www-form-urlencoded": |
||||
// payloadFormParam is the name of the form parameter that the JSON payload
|
||||
// will be in if a webhook has its content type set to application/x-www-form-urlencoded.
|
||||
const payloadFormParam = "payload" |
||||
|
||||
var err error |
||||
if body, err = ioutil.ReadAll(r.Body); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// If the content type is application/x-www-form-urlencoded,
|
||||
// the JSON payload will be under the "payload" form param.
|
||||
form, err := url.ParseQuery(string(body)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
payload = []byte(form.Get(payloadFormParam)) |
||||
|
||||
default: |
||||
return nil, fmt.Errorf("Webhook request has unsupported Content-Type %q", ct) |
||||
} |
||||
|
||||
sig := r.Header.Get(signatureHeader) |
||||
if err := validateSignature(sig, body, 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 API 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 |
||||
} |
||||
|
||||
// WebHookType returns the event type of webhook request r.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#webhook-headers
|
||||
func WebHookType(r *http.Request) string { |
||||
return r.Header.Get(eventTypeHeader) |
||||
} |
||||
|
||||
// DeliveryID returns the unique delivery ID of webhook request r.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#webhook-headers
|
||||
func DeliveryID(r *http.Request) string { |
||||
return r.Header.Get(deliveryIDHeader) |
||||
} |
||||
|
||||
// ParseWebHook parses the event payload. For recognized event types, a
|
||||
// value of the corresponding struct type will be returned (as returned
|
||||
// by Event.ParsePayload()). An error will be returned for unrecognized event
|
||||
// types.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// payload, err := github.ValidatePayload(r, s.webhookSecretKey)
|
||||
// if err != nil { ... }
|
||||
// event, err := github.ParseWebHook(github.WebHookType(r), payload)
|
||||
// if err != nil { ... }
|
||||
// switch event := event.(type) {
|
||||
// case *github.CommitCommentEvent:
|
||||
// processCommitCommentEvent(event)
|
||||
// case *github.CreateEvent:
|
||||
// processCreateEvent(event)
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
//
|
||||
func ParseWebHook(messageType string, payload []byte) (interface{}, error) { |
||||
eventType, ok := eventTypeMapping[messageType] |
||||
if !ok { |
||||
return nil, fmt.Errorf("unknown X-Github-Event in message: %v", messageType) |
||||
} |
||||
|
||||
event := Event{ |
||||
Type: &eventType, |
||||
RawPayload: (*json.RawMessage)(&payload), |
||||
} |
||||
return event.ParsePayload() |
||||
} |
@ -0,0 +1,224 @@
|
||||
// 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 ( |
||||
"context" |
||||
"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 service |
||||
|
||||
// Migration represents a GitHub migration (archival).
|
||||
type Migration struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
GUID *string `json:"guid,omitempty"` |
||||
// State is the current state of a migration.
|
||||
// Possible values are:
|
||||
// "pending" which means the migration hasn't started yet,
|
||||
// "exporting" which means the migration is in progress,
|
||||
// "exported" which means the migration finished successfully, or
|
||||
// "failed" which means the migration failed.
|
||||
State *string `json:"state,omitempty"` |
||||
// LockRepositories indicates whether repositories are locked (to prevent
|
||||
// manipulation) while migrating data.
|
||||
LockRepositories *bool `json:"lock_repositories,omitempty"` |
||||
// ExcludeAttachments indicates whether attachments should be excluded from
|
||||
// the migration (to reduce migration archive file size).
|
||||
ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
CreatedAt *string `json:"created_at,omitempty"` |
||||
UpdatedAt *string `json:"updated_at,omitempty"` |
||||
Repositories []*Repository `json:"repositories,omitempty"` |
||||
} |
||||
|
||||
func (m 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(ctx context.Context, 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(ctx, 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(ctx context.Context, 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(ctx, 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(ctx context.Context, org string, id int64) (*Migration, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/migrations/%v", org, id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
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(ctx, 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(ctx context.Context, org string, id int64) (url string, err error) { |
||||
u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
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(ctx, 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(ctx context.Context, org string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/migrations/%v/archive", org, id) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// 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(ctx context.Context, org string, id int64, repo string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/migrations/%v/repos/%v/lock", org, id, repo) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,329 @@
|
||||
// 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 ( |
||||
"context" |
||||
"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 *int64 `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(ctx context.Context, 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(ctx, req, out) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return out, resp, nil |
||||
} |
||||
|
||||
// ImportProgress 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(ctx context.Context, 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(ctx, req, out) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return out, resp, nil |
||||
} |
||||
|
||||
// UpdateImport initiates a repository import.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#update-existing-import
|
||||
func (s *MigrationService) UpdateImport(ctx context.Context, 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(ctx, req, out) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return out, resp, nil |
||||
} |
||||
|
||||
// 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 <hubot@12341234-abab-fefe-8787-fedcba987654>".
|
||||
//
|
||||
// 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(ctx context.Context, 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) |
||||
|
||||
var authors []*SourceImportAuthor |
||||
resp, err := s.client.Do(ctx, req, &authors) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return authors, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, owner, repo string, id int64, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/import/authors/%v", owner, repo, id) |
||||
req, err := s.client.NewRequest("PATCH", u, author) |
||||
if err != nil { |
||||
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(ctx, req, out) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return out, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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(ctx, req, out) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return out, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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) |
||||
|
||||
var files []*LargeFile |
||||
resp, err := s.client.Do(ctx, req, &files) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return files, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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(ctx, req, nil) |
||||
} |
@ -0,0 +1,257 @@
|
||||
// Copyright 2014 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 ( |
||||
"bytes" |
||||
"context" |
||||
"fmt" |
||||
"net/url" |
||||
) |
||||
|
||||
// MarkdownOptions specifies optional parameters to the Markdown method.
|
||||
type MarkdownOptions struct { |
||||
// Mode identifies the rendering mode. Possible values are:
|
||||
// markdown - render a document as plain Markdown, just like
|
||||
// README files are rendered.
|
||||
//
|
||||
// gfm - to render a document as user-content, e.g. like user
|
||||
// comments or issues are rendered. In GFM mode, hard line breaks are
|
||||
// always taken into account, and issue and user mentions are linked
|
||||
// accordingly.
|
||||
//
|
||||
// Default is "markdown".
|
||||
Mode string |
||||
|
||||
// Context identifies the repository context. Only taken into account
|
||||
// when rendering as "gfm".
|
||||
Context string |
||||
} |
||||
|
||||
type markdownRequest struct { |
||||
Text *string `json:"text,omitempty"` |
||||
Mode *string `json:"mode,omitempty"` |
||||
Context *string `json:"context,omitempty"` |
||||
} |
||||
|
||||
// Markdown renders an arbitrary Markdown document.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/markdown/
|
||||
func (c *Client) Markdown(ctx context.Context, text string, opt *MarkdownOptions) (string, *Response, error) { |
||||
request := &markdownRequest{Text: String(text)} |
||||
if opt != nil { |
||||
if opt.Mode != "" { |
||||
request.Mode = String(opt.Mode) |
||||
} |
||||
if opt.Context != "" { |
||||
request.Context = String(opt.Context) |
||||
} |
||||
} |
||||
|
||||
req, err := c.NewRequest("POST", "markdown", request) |
||||
if err != nil { |
||||
return "", nil, err |
||||
} |
||||
|
||||
buf := new(bytes.Buffer) |
||||
resp, err := c.Do(ctx, req, buf) |
||||
if err != nil { |
||||
return "", resp, err |
||||
} |
||||
|
||||
return buf.String(), resp, nil |
||||
} |
||||
|
||||
// ListEmojis returns the emojis available to use on GitHub.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/emojis/
|
||||
func (c *Client) ListEmojis(ctx context.Context) (map[string]string, *Response, error) { |
||||
req, err := c.NewRequest("GET", "emojis", nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var emoji map[string]string |
||||
resp, err := c.Do(ctx, req, &emoji) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return emoji, resp, nil |
||||
} |
||||
|
||||
// CodeOfConduct represents a code of conduct.
|
||||
type CodeOfConduct struct { |
||||
Name *string `json:"name,omitempty"` |
||||
Key *string `json:"key,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
} |
||||
|
||||
func (c *CodeOfConduct) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// ListCodesOfConduct returns all codes of conduct.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/codes_of_conduct/#list-all-codes-of-conduct
|
||||
func (c *Client) ListCodesOfConduct(ctx context.Context) ([]*CodeOfConduct, *Response, error) { |
||||
req, err := c.NewRequest("GET", "codes_of_conduct", nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeCodesOfConductPreview) |
||||
|
||||
var cs []*CodeOfConduct |
||||
resp, err := c.Do(ctx, req, &cs) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return cs, resp, nil |
||||
} |
||||
|
||||
// GetCodeOfConduct returns an individual code of conduct.
|
||||
//
|
||||
// https://developer.github.com/v3/codes_of_conduct/#get-an-individual-code-of-conduct
|
||||
func (c *Client) GetCodeOfConduct(ctx context.Context, key string) (*CodeOfConduct, *Response, error) { |
||||
u := fmt.Sprintf("codes_of_conduct/%s", key) |
||||
req, err := c.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", mediaTypeCodesOfConductPreview) |
||||
|
||||
coc := new(CodeOfConduct) |
||||
resp, err := c.Do(ctx, req, coc) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return coc, resp, nil |
||||
} |
||||
|
||||
// APIMeta represents metadata about the GitHub API.
|
||||
type APIMeta struct { |
||||
// An Array of IP addresses in CIDR format specifying the addresses
|
||||
// that incoming service hooks will originate from on GitHub.com.
|
||||
Hooks []string `json:"hooks,omitempty"` |
||||
|
||||
// An Array of IP addresses in CIDR format specifying the Git servers
|
||||
// for GitHub.com.
|
||||
Git []string `json:"git,omitempty"` |
||||
|
||||
// Whether authentication with username and password is supported.
|
||||
// (GitHub Enterprise instances using CAS or OAuth for authentication
|
||||
// will return false. Features like Basic Authentication with a
|
||||
// username and password, sudo mode, and two-factor authentication are
|
||||
// not supported on these servers.)
|
||||
VerifiablePasswordAuthentication *bool `json:"verifiable_password_authentication,omitempty"` |
||||
|
||||
// An array of IP addresses in CIDR format specifying the addresses
|
||||
// which serve GitHub Pages websites.
|
||||
Pages []string `json:"pages,omitempty"` |
||||
|
||||
// An Array of IP addresses specifying the addresses that source imports
|
||||
// will originate from on GitHub.com.
|
||||
Importer []string `json:"importer,omitempty"` |
||||
} |
||||
|
||||
// APIMeta returns information about GitHub.com, the service. Or, if you access
|
||||
// this endpoint on your organization’s GitHub Enterprise installation, this
|
||||
// endpoint provides information about that installation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/meta/
|
||||
func (c *Client) APIMeta(ctx context.Context) (*APIMeta, *Response, error) { |
||||
req, err := c.NewRequest("GET", "meta", nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
meta := new(APIMeta) |
||||
resp, err := c.Do(ctx, req, meta) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return meta, resp, nil |
||||
} |
||||
|
||||
// Octocat returns an ASCII art octocat with the specified message in a speech
|
||||
// bubble. If message is empty, a random zen phrase is used.
|
||||
func (c *Client) Octocat(ctx context.Context, message string) (string, *Response, error) { |
||||
u := "octocat" |
||||
if message != "" { |
||||
u = fmt.Sprintf("%s?s=%s", u, url.QueryEscape(message)) |
||||
} |
||||
|
||||
req, err := c.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return "", nil, err |
||||
} |
||||
|
||||
buf := new(bytes.Buffer) |
||||
resp, err := c.Do(ctx, req, buf) |
||||
if err != nil { |
||||
return "", resp, err |
||||
} |
||||
|
||||
return buf.String(), resp, nil |
||||
} |
||||
|
||||
// Zen returns a random line from The Zen of GitHub.
|
||||
//
|
||||
// see also: http://warpspire.com/posts/taste/
|
||||
func (c *Client) Zen(ctx context.Context) (string, *Response, error) { |
||||
req, err := c.NewRequest("GET", "zen", nil) |
||||
if err != nil { |
||||
return "", nil, err |
||||
} |
||||
|
||||
buf := new(bytes.Buffer) |
||||
resp, err := c.Do(ctx, req, buf) |
||||
if err != nil { |
||||
return "", resp, err |
||||
} |
||||
|
||||
return buf.String(), resp, nil |
||||
} |
||||
|
||||
// ServiceHook represents a hook that has configuration settings, a list of
|
||||
// available events, and default events.
|
||||
type ServiceHook struct { |
||||
Name *string `json:"name,omitempty"` |
||||
Events []string `json:"events,omitempty"` |
||||
SupportedEvents []string `json:"supported_events,omitempty"` |
||||
Schema [][]string `json:"schema,omitempty"` |
||||
} |
||||
|
||||
func (s *ServiceHook) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// ListServiceHooks lists all of the available service hooks.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/webhooks/#services
|
||||
func (c *Client) ListServiceHooks(ctx context.Context) ([]*ServiceHook, *Response, error) { |
||||
u := "hooks" |
||||
req, err := c.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var hooks []*ServiceHook |
||||
resp, err := c.Do(ctx, req, &hooks) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return hooks, resp, nil |
||||
} |
@ -0,0 +1,212 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// OrganizationsService provides access to the organization related functions
|
||||
// in the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/
|
||||
type OrganizationsService service |
||||
|
||||
// Organization represents a GitHub organization account.
|
||||
type Organization struct { |
||||
Login *string `json:"login,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
AvatarURL *string `json:"avatar_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Company *string `json:"company,omitempty"` |
||||
Blog *string `json:"blog,omitempty"` |
||||
Location *string `json:"location,omitempty"` |
||||
Email *string `json:"email,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
PublicRepos *int `json:"public_repos,omitempty"` |
||||
PublicGists *int `json:"public_gists,omitempty"` |
||||
Followers *int `json:"followers,omitempty"` |
||||
Following *int `json:"following,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
TotalPrivateRepos *int `json:"total_private_repos,omitempty"` |
||||
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"` |
||||
PrivateGists *int `json:"private_gists,omitempty"` |
||||
DiskUsage *int `json:"disk_usage,omitempty"` |
||||
Collaborators *int `json:"collaborators,omitempty"` |
||||
BillingEmail *string `json:"billing_email,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
Plan *Plan `json:"plan,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
|
||||
// API URLs
|
||||
URL *string `json:"url,omitempty"` |
||||
EventsURL *string `json:"events_url,omitempty"` |
||||
HooksURL *string `json:"hooks_url,omitempty"` |
||||
IssuesURL *string `json:"issues_url,omitempty"` |
||||
MembersURL *string `json:"members_url,omitempty"` |
||||
PublicMembersURL *string `json:"public_members_url,omitempty"` |
||||
ReposURL *string `json:"repos_url,omitempty"` |
||||
} |
||||
|
||||
func (o Organization) String() string { |
||||
return Stringify(o) |
||||
} |
||||
|
||||
// Plan represents the payment plan for an account. See plans at https://github.com/plans.
|
||||
type Plan struct { |
||||
Name *string `json:"name,omitempty"` |
||||
Space *int `json:"space,omitempty"` |
||||
Collaborators *int `json:"collaborators,omitempty"` |
||||
PrivateRepos *int `json:"private_repos,omitempty"` |
||||
} |
||||
|
||||
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 int64 `url:"since,omitempty"` |
||||
|
||||
// Note: Pagination is powered exclusively by the Since parameter,
|
||||
// ListOptions.Page has no effect.
|
||||
// ListOptions.PerPage controls an undocumented GitHub API parameter.
|
||||
ListOptions |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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 |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
orgs := []*Organization{} |
||||
resp, err := s.client.Do(ctx, req, &orgs) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return orgs, resp, nil |
||||
} |
||||
|
||||
// List the organizations for a user. Passing the empty string will list
|
||||
// organizations for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/#list-user-organizations
|
||||
func (s *OrganizationsService) List(ctx context.Context, user string, opt *ListOptions) ([]*Organization, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/orgs", user) |
||||
} else { |
||||
u = "user/orgs" |
||||
} |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var orgs []*Organization |
||||
resp, err := s.client.Do(ctx, req, &orgs) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return orgs, resp, nil |
||||
} |
||||
|
||||
// Get fetches an organization by name.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/#get-an-organization
|
||||
func (s *OrganizationsService) Get(ctx context.Context, org string) (*Organization, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v", 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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
organization := new(Organization) |
||||
resp, err := s.client.Do(ctx, req, organization) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return organization, resp, nil |
||||
} |
||||
|
||||
// GetByID fetches an organization.
|
||||
//
|
||||
// Note: GetByID uses the undocumented GitHub API endpoint /organizations/:id.
|
||||
func (s *OrganizationsService) GetByID(ctx context.Context, id int64) (*Organization, *Response, error) { |
||||
u := fmt.Sprintf("organizations/%d", id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
organization := new(Organization) |
||||
resp, err := s.client.Do(ctx, req, organization) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return organization, resp, nil |
||||
} |
||||
|
||||
// Edit an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/#edit-an-organization
|
||||
func (s *OrganizationsService) Edit(ctx context.Context, name string, org *Organization) (*Organization, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v", name) |
||||
req, err := s.client.NewRequest("PATCH", u, org) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
o := new(Organization) |
||||
resp, err := s.client.Do(ctx, req, o) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return o, resp, nil |
||||
} |
@ -0,0 +1,107 @@
|
||||
// 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 ( |
||||
"context" |
||||
"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(ctx context.Context, org string, opt *ListOptions) ([]*Hook, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/hooks", org) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var hooks []*Hook |
||||
resp, err := s.client.Do(ctx, req, &hooks) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return hooks, resp, nil |
||||
} |
||||
|
||||
// GetHook returns a single specified Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook
|
||||
func (s *OrganizationsService) GetHook(ctx context.Context, org string, id int64) (*Hook, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
hook := new(Hook) |
||||
resp, err := s.client.Do(ctx, req, hook) |
||||
return hook, resp, err |
||||
} |
||||
|
||||
// CreateHook creates a Hook for the specified org.
|
||||
// Name and Config are required fields.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook
|
||||
func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/hooks", org) |
||||
req, err := s.client.NewRequest("POST", u, hook) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
h := new(Hook) |
||||
resp, err := s.client.Do(ctx, req, h) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return h, resp, nil |
||||
} |
||||
|
||||
// EditHook updates a specified Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#edit-a-hook
|
||||
func (s *OrganizationsService) EditHook(ctx context.Context, org string, id int64, hook *Hook) (*Hook, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) |
||||
req, err := s.client.NewRequest("PATCH", u, hook) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
h := new(Hook) |
||||
resp, err := s.client.Do(ctx, req, h) |
||||
return h, resp, err |
||||
} |
||||
|
||||
// PingHook triggers a 'ping' event to be sent to the Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook
|
||||
func (s *OrganizationsService) PingHook(ctx context.Context, org string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/hooks/%d/pings", org, id) |
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// DeleteHook deletes a specified Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#delete-a-hook
|
||||
func (s *OrganizationsService) DeleteHook(ctx context.Context, org string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/hooks/%d", org, id) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,370 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// Membership represents the status of a user's membership in an organization or team.
|
||||
type Membership struct { |
||||
URL *string `json:"url,omitempty"` |
||||
|
||||
// State is the user's status within the organization or team.
|
||||
// Possible values are: "active", "pending"
|
||||
State *string `json:"state,omitempty"` |
||||
|
||||
// Role identifies the user's role within the organization or team.
|
||||
// Possible values for organization membership:
|
||||
// member - non-owner organization member
|
||||
// admin - organization owner
|
||||
//
|
||||
// Possible values for team membership are:
|
||||
// member - a normal member of the team
|
||||
// maintainer - a team maintainer. Able to add/remove other team
|
||||
// members, promote other team members to team
|
||||
// maintainer, and edit the team’s name and description
|
||||
Role *string `json:"role,omitempty"` |
||||
|
||||
// For organization membership, the API URL of the organization.
|
||||
OrganizationURL *string `json:"organization_url,omitempty"` |
||||
|
||||
// For organization membership, the organization the membership is for.
|
||||
Organization *Organization `json:"organization,omitempty"` |
||||
|
||||
// For organization membership, the user the membership is for.
|
||||
User *User `json:"user,omitempty"` |
||||
} |
||||
|
||||
func (m Membership) String() string { |
||||
return Stringify(m) |
||||
} |
||||
|
||||
// ListMembersOptions specifies optional parameters to the
|
||||
// OrganizationsService.ListMembers method.
|
||||
type ListMembersOptions struct { |
||||
// If true (or if the authenticated user is not an owner of the
|
||||
// organization), list only publicly visible members.
|
||||
PublicOnly bool `url:"-"` |
||||
|
||||
// Filter members returned in the list. Possible values are:
|
||||
// 2fa_disabled, all. Default is "all".
|
||||
Filter string `url:"filter,omitempty"` |
||||
|
||||
// Role filters members returned by their role in the organization.
|
||||
// Possible values are:
|
||||
// all - all members of the organization, regardless of role
|
||||
// admin - organization owners
|
||||
// member - non-organization members
|
||||
//
|
||||
// Default is "all".
|
||||
Role string `url:"role,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListMembers lists the members for an organization. If the authenticated
|
||||
// user is an owner of the organization, this will return both concealed and
|
||||
// public members, otherwise it will only return public members.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#members-list
|
||||
func (s *OrganizationsService) ListMembers(ctx context.Context, org string, opt *ListMembersOptions) ([]*User, *Response, error) { |
||||
var u string |
||||
if opt != nil && opt.PublicOnly { |
||||
u = fmt.Sprintf("orgs/%v/public_members", org) |
||||
} else { |
||||
u = fmt.Sprintf("orgs/%v/members", org) |
||||
} |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var members []*User |
||||
resp, err := s.client.Do(ctx, req, &members) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return members, resp, nil |
||||
} |
||||
|
||||
// IsMember checks if a user is a member of an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-membership
|
||||
func (s *OrganizationsService) IsMember(ctx context.Context, org, user string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/members/%v", org, user) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
member, err := parseBoolResponse(err) |
||||
return member, resp, err |
||||
} |
||||
|
||||
// IsPublicMember checks if a user is a public member of an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#check-public-membership
|
||||
func (s *OrganizationsService) IsPublicMember(ctx context.Context, org, user string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
member, err := parseBoolResponse(err) |
||||
return member, resp, err |
||||
} |
||||
|
||||
// RemoveMember removes a user from all teams of an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-a-member
|
||||
func (s *OrganizationsService) RemoveMember(ctx context.Context, org, user string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/members/%v", org, user) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// PublicizeMembership publicizes a user's membership in an organization. (A
|
||||
// user cannot publicize the membership for another user.)
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#publicize-a-users-membership
|
||||
func (s *OrganizationsService) PublicizeMembership(ctx context.Context, org, user string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) |
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ConcealMembership conceals a user's membership in an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#conceal-a-users-membership
|
||||
func (s *OrganizationsService) ConcealMembership(ctx context.Context, org, user string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/public_members/%v", org, user) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ListOrgMembershipsOptions specifies optional parameters to the
|
||||
// OrganizationsService.ListOrgMemberships method.
|
||||
type ListOrgMembershipsOptions struct { |
||||
// Filter memberships to include only those with the specified state.
|
||||
// Possible values are: "active", "pending".
|
||||
State string `url:"state,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// 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(ctx context.Context, opt *ListOrgMembershipsOptions) ([]*Membership, *Response, error) { |
||||
u := "user/memberships/orgs" |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var memberships []*Membership |
||||
resp, err := s.client.Do(ctx, req, &memberships) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return memberships, resp, nil |
||||
} |
||||
|
||||
// GetOrgMembership gets the membership for a user in a specified organization.
|
||||
// Passing an empty string for user will get the membership for the
|
||||
// authenticated user.
|
||||
//
|
||||
// GitHub API docs:
|
||||
// https://developer.github.com/v3/orgs/members/#get-organization-membership
|
||||
// https://developer.github.com/v3/orgs/members/#get-your-organization-membership
|
||||
func (s *OrganizationsService) GetOrgMembership(ctx context.Context, user, org string) (*Membership, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) |
||||
} else { |
||||
u = fmt.Sprintf("user/memberships/orgs/%v", org) |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
membership := new(Membership) |
||||
resp, err := s.client.Do(ctx, req, membership) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return membership, resp, nil |
||||
} |
||||
|
||||
// EditOrgMembership edits the membership for user in specified organization.
|
||||
// Passing an empty string for user will edit the membership for the
|
||||
// authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#add-or-update-organization-membership
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#edit-your-organization-membership
|
||||
func (s *OrganizationsService) EditOrgMembership(ctx context.Context, user, org string, membership *Membership) (*Membership, *Response, error) { |
||||
var u, method string |
||||
if user != "" { |
||||
u = fmt.Sprintf("orgs/%v/memberships/%v", org, user) |
||||
method = "PUT" |
||||
} else { |
||||
u = fmt.Sprintf("user/memberships/orgs/%v", org) |
||||
method = "PATCH" |
||||
} |
||||
|
||||
req, err := s.client.NewRequest(method, u, membership) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
m := new(Membership) |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// RemoveOrgMembership removes user from the specified organization. If the
|
||||
// user has been invited to the organization, this will cancel their invitation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#remove-organization-membership
|
||||
func (s *OrganizationsService) RemoveOrgMembership(ctx context.Context, user, org string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/memberships/%v", org, user) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ListPendingOrgInvitations returns a list of pending invitations.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-pending-organization-invitations
|
||||
func (s *OrganizationsService) ListPendingOrgInvitations(ctx context.Context, org string, opt *ListOptions) ([]*Invitation, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/invitations", org) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var pendingInvitations []*Invitation |
||||
resp, err := s.client.Do(ctx, req, &pendingInvitations) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return pendingInvitations, resp, nil |
||||
} |
||||
|
||||
// CreateOrgInvitationOptions specifies the parameters to the OrganizationService.Invite
|
||||
// method.
|
||||
type CreateOrgInvitationOptions struct { |
||||
// GitHub user ID for the person you are inviting. Not required if you provide Email.
|
||||
InviteeID *int64 `json:"invitee_id,omitempty"` |
||||
// Email address of the person you are inviting, which can be an existing GitHub user.
|
||||
// Not required if you provide InviteeID
|
||||
Email *string `json:"email,omitempty"` |
||||
// Specify role for new member. Can be one of:
|
||||
// * admin - Organization owners with full administrative rights to the
|
||||
// organization and complete access to all repositories and teams.
|
||||
// * direct_member - Non-owner organization members with ability to see
|
||||
// other members and join teams by invitation.
|
||||
// * billing_manager - Non-owner organization members with ability to
|
||||
// manage the billing settings of your organization.
|
||||
// Default is "direct_member".
|
||||
Role *string `json:"role"` |
||||
TeamID []int64 `json:"team_ids"` |
||||
} |
||||
|
||||
// CreateOrgInvitation invites people to an organization by using their GitHub user ID or their email address.
|
||||
// In order to create invitations in an organization,
|
||||
// the authenticated user must be an organization owner.
|
||||
//
|
||||
// https://developer.github.com/v3/orgs/members/#create-organization-invitation
|
||||
func (s *OrganizationsService) CreateOrgInvitation(ctx context.Context, org string, opt *CreateOrgInvitationOptions) (*Invitation, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/invitations", org) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeOrganizationInvitationPreview) |
||||
|
||||
var invitation *Invitation |
||||
resp, err := s.client.Do(ctx, req, &invitation) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return invitation, resp, nil |
||||
} |
||||
|
||||
// ListOrgInvitationTeams lists all teams associated with an invitation. In order to see invitations in an organization,
|
||||
// the authenticated user must be an organization owner.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/members/#list-organization-invitation-teams
|
||||
func (s *OrganizationsService) ListOrgInvitationTeams(ctx context.Context, org, invitationID string, opt *ListOptions) ([]*Team, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/invitations/%v/teams", org, invitationID) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeOrganizationInvitationPreview) |
||||
|
||||
var orgInvitationTeams []*Team |
||||
resp, err := s.client.Do(ctx, req, &orgInvitationTeams) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return orgInvitationTeams, resp, nil |
||||
} |
@ -0,0 +1,81 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListOutsideCollaboratorsOptions specifies optional parameters to the
|
||||
// OrganizationsService.ListOutsideCollaborators method.
|
||||
type ListOutsideCollaboratorsOptions struct { |
||||
// Filter outside collaborators returned in the list. Possible values are:
|
||||
// 2fa_disabled, all. Default is "all".
|
||||
Filter string `url:"filter,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListOutsideCollaborators lists outside collaborators of organization's repositories.
|
||||
// This will only work if the authenticated
|
||||
// user is an owner of the organization.
|
||||
//
|
||||
// Warning: The API may change without advance notice during the preview period.
|
||||
// Preview features are not supported for production use.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#list-outside-collaborators
|
||||
func (s *OrganizationsService) ListOutsideCollaborators(ctx context.Context, org string, opt *ListOutsideCollaboratorsOptions) ([]*User, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/outside_collaborators", org) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var members []*User |
||||
resp, err := s.client.Do(ctx, req, &members) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return members, resp, nil |
||||
} |
||||
|
||||
// RemoveOutsideCollaborator removes a user from the list of outside collaborators;
|
||||
// consequently, removing them from all the organization's repositories.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#remove-outside-collaborator
|
||||
func (s *OrganizationsService) RemoveOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ConvertMemberToOutsideCollaborator reduces the permission level of a member of the
|
||||
// organization to that of an outside collaborator. Therefore, they will only
|
||||
// have access to the repositories that their current team membership allows.
|
||||
// Responses for converting a non-member or the last owner to an outside collaborator
|
||||
// are listed in GitHub API docs.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/outside_collaborators/#convert-member-to-outside-collaborator
|
||||
func (s *OrganizationsService) ConvertMemberToOutsideCollaborator(ctx context.Context, org string, user string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/outside_collaborators/%v", org, user) |
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,60 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListProjects lists the projects for an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#list-organization-projects
|
||||
func (s *OrganizationsService) ListProjects(ctx context.Context, org string, opt *ProjectListOptions) ([]*Project, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/projects", org) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
var projects []*Project |
||||
resp, err := s.client.Do(ctx, req, &projects) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return projects, resp, nil |
||||
} |
||||
|
||||
// CreateProject creates a GitHub Project for the specified organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#create-an-organization-project
|
||||
func (s *OrganizationsService) CreateProject(ctx context.Context, org string, opt *ProjectOptions) (*Project, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/projects", org) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
project := &Project{} |
||||
resp, err := s.client.Do(ctx, req, project) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return project, resp, nil |
||||
} |
@ -0,0 +1,514 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
// Team represents a team within a GitHub organization. Teams are used to
|
||||
// manage access to an organization's repositories.
|
||||
type Team struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Slug *string `json:"slug,omitempty"` |
||||
|
||||
// Permission specifies the default permission for repositories owned by the team.
|
||||
Permission *string `json:"permission,omitempty"` |
||||
|
||||
// Privacy identifies the level of privacy this team should have.
|
||||
// Possible values are:
|
||||
// secret - only visible to organization owners and members of this team
|
||||
// closed - visible to all members of this organization
|
||||
// Default is "secret".
|
||||
Privacy *string `json:"privacy,omitempty"` |
||||
|
||||
MembersCount *int `json:"members_count,omitempty"` |
||||
ReposCount *int `json:"repos_count,omitempty"` |
||||
Organization *Organization `json:"organization,omitempty"` |
||||
MembersURL *string `json:"members_url,omitempty"` |
||||
RepositoriesURL *string `json:"repositories_url,omitempty"` |
||||
Parent *Team `json:"parent,omitempty"` |
||||
|
||||
// LDAPDN is only available in GitHub Enterprise and when the team
|
||||
// membership is synchronized with LDAP.
|
||||
LDAPDN *string `json:"ldap_dn,omitempty"` |
||||
} |
||||
|
||||
func (t Team) String() string { |
||||
return Stringify(t) |
||||
} |
||||
|
||||
// Invitation represents a team member's invitation status.
|
||||
type Invitation struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
Login *string `json:"login,omitempty"` |
||||
Email *string `json:"email,omitempty"` |
||||
// Role can be one of the values - 'direct_member', 'admin', 'billing_manager', 'hiring_manager', or 'reinstate'.
|
||||
Role *string `json:"role,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
Inviter *User `json:"inviter,omitempty"` |
||||
TeamCount *int `json:"team_count,omitempty"` |
||||
InvitationTeamURL *string `json:"invitation_team_url,omitempty"` |
||||
} |
||||
|
||||
func (i Invitation) String() string { |
||||
return Stringify(i) |
||||
} |
||||
|
||||
// ListTeams lists all of the teams for an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-teams
|
||||
func (s *OrganizationsService) ListTeams(ctx context.Context, org string, opt *ListOptions) ([]*Team, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/teams", org) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
var teams []*Team |
||||
resp, err := s.client.Do(ctx, req, &teams) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return teams, resp, nil |
||||
} |
||||
|
||||
// GetTeam fetches a team by ID.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team
|
||||
func (s *OrganizationsService) GetTeam(ctx context.Context, team int64) (*Team, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v", team) |
||||
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", mediaTypeNestedTeamsPreview) |
||||
|
||||
t := new(Team) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
||||
|
||||
// NewTeam represents a team to be created or modified.
|
||||
type NewTeam struct { |
||||
Name string `json:"name"` // Name of the team. (Required.)
|
||||
Description *string `json:"description,omitempty"` |
||||
Maintainers []string `json:"maintainers,omitempty"` |
||||
RepoNames []string `json:"repo_names,omitempty"` |
||||
ParentTeamID *int64 `json:"parent_team_id,omitempty"` |
||||
|
||||
// Deprecated: Permission is deprecated when creating or editing a team in an org
|
||||
// using the new GitHub permission model. It no longer identifies the
|
||||
// permission a team has on its repos, but only specifies the default
|
||||
// permission a repo is initially added with. Avoid confusion by
|
||||
// specifying a permission value when calling AddTeamRepo.
|
||||
Permission *string `json:"permission,omitempty"` |
||||
|
||||
// Privacy identifies the level of privacy this team should have.
|
||||
// Possible values are:
|
||||
// secret - only visible to organization owners and members of this team
|
||||
// closed - visible to all members of this organization
|
||||
// Default is "secret".
|
||||
Privacy *string `json:"privacy,omitempty"` |
||||
|
||||
// LDAPDN may be used in GitHub Enterprise when the team membership
|
||||
// is synchronized with LDAP.
|
||||
LDAPDN *string `json:"ldap_dn,omitempty"` |
||||
} |
||||
|
||||
func (s NewTeam) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// CreateTeam creates a new team within an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#create-team
|
||||
func (s *OrganizationsService) CreateTeam(ctx context.Context, org string, team *NewTeam) (*Team, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/teams", org) |
||||
req, err := s.client.NewRequest("POST", u, team) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
t := new(Team) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
||||
|
||||
// EditTeam edits a team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#edit-team
|
||||
func (s *OrganizationsService) EditTeam(ctx context.Context, id int64, team *NewTeam) (*Team, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v", id) |
||||
req, err := s.client.NewRequest("PATCH", u, team) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
t := new(Team) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
||||
|
||||
// DeleteTeam deletes a team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#delete-team
|
||||
func (s *OrganizationsService) DeleteTeam(ctx context.Context, team int64) (*Response, error) { |
||||
u := fmt.Sprintf("teams/%v", team) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// OrganizationListTeamMembersOptions specifies the optional parameters to the
|
||||
// OrganizationsService.ListTeamMembers method.
|
||||
type OrganizationListTeamMembersOptions struct { |
||||
// Role filters members returned by their role in the team. Possible
|
||||
// values are "all", "member", "maintainer". Default is "all".
|
||||
Role string `url:"role,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListChildTeams lists child teams for a team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-child-teams
|
||||
func (s *OrganizationsService) ListChildTeams(ctx context.Context, teamID int64, opt *ListOptions) ([]*Team, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/teams", teamID) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
var teams []*Team |
||||
resp, err := s.client.Do(ctx, req, &teams) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return teams, resp, nil |
||||
} |
||||
|
||||
// ListTeamMembers lists all of the users who are members of the specified
|
||||
// team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-team-members
|
||||
func (s *OrganizationsService) ListTeamMembers(ctx context.Context, team int64, opt *OrganizationListTeamMembersOptions) ([]*User, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/members", team) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
var members []*User |
||||
resp, err := s.client.Do(ctx, req, &members) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return members, resp, nil |
||||
} |
||||
|
||||
// IsTeamMember checks if a user is a member of the specified team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-member
|
||||
//
|
||||
// Deprecated: This API has been marked as deprecated in the Github API docs,
|
||||
// OrganizationsService.GetTeamMembership method should be used instead.
|
||||
func (s *OrganizationsService) IsTeamMember(ctx context.Context, team int64, user string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/members/%v", team, user) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
member, err := parseBoolResponse(err) |
||||
return member, resp, err |
||||
} |
||||
|
||||
// ListTeamRepos lists the repositories that the specified team has access to.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-team-repos
|
||||
func (s *OrganizationsService) ListTeamRepos(ctx context.Context, team int64, opt *ListOptions) ([]*Repository, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/repos", team) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when topics API fully launches.
|
||||
headers := []string{mediaTypeTopicsPreview, mediaTypeNestedTeamsPreview} |
||||
req.Header.Set("Accept", strings.Join(headers, ", ")) |
||||
|
||||
var repos []*Repository |
||||
resp, err := s.client.Do(ctx, req, &repos) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return repos, resp, nil |
||||
} |
||||
|
||||
// IsTeamRepo checks if a team manages the specified repository. If the
|
||||
// repository is managed by team, a Repository is returned which includes the
|
||||
// permissions team has for that repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#check-if-a-team-manages-a-repository
|
||||
func (s *OrganizationsService) IsTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Repository, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
headers := []string{mediaTypeOrgPermissionRepo, mediaTypeNestedTeamsPreview} |
||||
req.Header.Set("Accept", strings.Join(headers, ", ")) |
||||
|
||||
repository := new(Repository) |
||||
resp, err := s.client.Do(ctx, req, repository) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return repository, resp, nil |
||||
} |
||||
|
||||
// OrganizationAddTeamRepoOptions specifies the optional parameters to the
|
||||
// OrganizationsService.AddTeamRepo method.
|
||||
type OrganizationAddTeamRepoOptions struct { |
||||
// Permission specifies the permission to grant the team on this repository.
|
||||
// Possible values are:
|
||||
// pull - team members can pull, but not push to or administer this repository
|
||||
// push - team members can pull and push, but not administer this repository
|
||||
// admin - team members can pull, push and administer this repository
|
||||
//
|
||||
// If not specified, the team's permission attribute will be used.
|
||||
Permission string `json:"permission,omitempty"` |
||||
} |
||||
|
||||
// AddTeamRepo adds a repository to be managed by the specified team. The
|
||||
// specified repository must be owned by the organization to which the team
|
||||
// belongs, or a direct fork of a repository owned by the organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-repo
|
||||
func (s *OrganizationsService) AddTeamRepo(ctx context.Context, team int64, owner string, repo string, opt *OrganizationAddTeamRepoOptions) (*Response, error) { |
||||
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) |
||||
req, err := s.client.NewRequest("PUT", u, opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// RemoveTeamRepo removes a repository from being managed by the specified
|
||||
// team. Note that this does not delete the repository, it just removes it
|
||||
// from the team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-repo
|
||||
func (s *OrganizationsService) RemoveTeamRepo(ctx context.Context, team int64, owner string, repo string) (*Response, error) { |
||||
u := fmt.Sprintf("teams/%v/repos/%v/%v", team, owner, repo) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ListUserTeams lists a user's teams
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-user-teams
|
||||
func (s *OrganizationsService) ListUserTeams(ctx context.Context, opt *ListOptions) ([]*Team, *Response, error) { |
||||
u := "user/teams" |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
var teams []*Team |
||||
resp, err := s.client.Do(ctx, req, &teams) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return teams, resp, nil |
||||
} |
||||
|
||||
// GetTeamMembership returns the membership status for a user in a team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership
|
||||
func (s *OrganizationsService) GetTeamMembership(ctx context.Context, team int64, user string) (*Membership, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/memberships/%v", team, user) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
t := new(Membership) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
||||
|
||||
// OrganizationAddTeamMembershipOptions does stuff specifies the optional
|
||||
// parameters to the OrganizationsService.AddTeamMembership method.
|
||||
type OrganizationAddTeamMembershipOptions struct { |
||||
// Role specifies the role the user should have in the team. Possible
|
||||
// values are:
|
||||
// member - a normal member of the team
|
||||
// maintainer - a team maintainer. Able to add/remove other team
|
||||
// members, promote other team members to team
|
||||
// maintainer, and edit the team’s name and description
|
||||
//
|
||||
// Default value is "member".
|
||||
Role string `json:"role,omitempty"` |
||||
} |
||||
|
||||
// AddTeamMembership adds or invites a user to a team.
|
||||
//
|
||||
// In order to add a membership between a user and a team, the authenticated
|
||||
// user must have 'admin' permissions to the team or be an owner of the
|
||||
// organization that the team is associated with.
|
||||
//
|
||||
// If the user is already a part of the team's organization (meaning they're on
|
||||
// at least one other team in the organization), this endpoint will add the
|
||||
// user to the team.
|
||||
//
|
||||
// If the user is completely unaffiliated with the team's organization (meaning
|
||||
// they're on none of the organization's teams), this endpoint will send an
|
||||
// invitation to the user via email. This newly-created membership will be in
|
||||
// the "pending" state until the user accepts the invitation, at which point
|
||||
// the membership will transition to the "active" state and the user will be
|
||||
// added as a member of the team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#add-team-membership
|
||||
func (s *OrganizationsService) AddTeamMembership(ctx context.Context, team int64, user string, opt *OrganizationAddTeamMembershipOptions) (*Membership, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/memberships/%v", team, user) |
||||
req, err := s.client.NewRequest("PUT", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
t := new(Membership) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
||||
|
||||
// RemoveTeamMembership removes a user from a team.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#remove-team-membership
|
||||
func (s *OrganizationsService) RemoveTeamMembership(ctx context.Context, team int64, user string) (*Response, error) { |
||||
u := fmt.Sprintf("teams/%v/memberships/%v", team, user) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ListPendingTeamInvitations get pending invitaion list in team.
|
||||
// Warning: The API may change without advance notice during the preview period.
|
||||
// Preview features are not supported for production use.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/teams/#list-pending-team-invitations
|
||||
func (s *OrganizationsService) ListPendingTeamInvitations(ctx context.Context, team int64, opt *ListOptions) ([]*Invitation, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/invitations", team) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var pendingInvitations []*Invitation |
||||
resp, err := s.client.Do(ctx, req, &pendingInvitations) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return pendingInvitations, resp, nil |
||||
} |
@ -0,0 +1,91 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListBlockedUsers lists all the users blocked by an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#list-blocked-users
|
||||
func (s *OrganizationsService) ListBlockedUsers(ctx context.Context, org string, opt *ListOptions) ([]*User, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/blocks", org) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeBlockUsersPreview) |
||||
|
||||
var blockedUsers []*User |
||||
resp, err := s.client.Do(ctx, req, &blockedUsers) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return blockedUsers, resp, nil |
||||
} |
||||
|
||||
// IsBlocked reports whether specified user is blocked from an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#check-whether-a-user-is-blocked-from-an-organization
|
||||
func (s *OrganizationsService) IsBlocked(ctx context.Context, org string, user string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeBlockUsersPreview) |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
isBlocked, err := parseBoolResponse(err) |
||||
return isBlocked, resp, err |
||||
} |
||||
|
||||
// BlockUser blocks specified user from an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#block-a-user
|
||||
func (s *OrganizationsService) BlockUser(ctx context.Context, org string, user string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) |
||||
|
||||
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", mediaTypeBlockUsersPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// UnblockUser unblocks specified user from an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/blocking/#unblock-a-user
|
||||
func (s *OrganizationsService) UnblockUser(ctx context.Context, org string, user string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/blocks/%v", org, user) |
||||
|
||||
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", mediaTypeBlockUsersPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,445 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// ProjectsService provides access to the projects functions in the
|
||||
// GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/
|
||||
type ProjectsService service |
||||
|
||||
// Project represents a GitHub Project.
|
||||
type Project struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
OwnerURL *string `json:"owner_url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Number *int `json:"number,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
|
||||
// The User object that generated the project.
|
||||
Creator *User `json:"creator,omitempty"` |
||||
} |
||||
|
||||
func (p Project) String() string { |
||||
return Stringify(p) |
||||
} |
||||
|
||||
// GetProject gets a GitHub Project for a repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#get-a-project
|
||||
func (s *ProjectsService) GetProject(ctx context.Context, id int64) (*Project, *Response, error) { |
||||
u := fmt.Sprintf("projects/%v", id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
project := &Project{} |
||||
resp, err := s.client.Do(ctx, req, project) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return project, resp, nil |
||||
} |
||||
|
||||
// ProjectOptions specifies the parameters to the
|
||||
// RepositoriesService.CreateProject and
|
||||
// ProjectsService.UpdateProject methods.
|
||||
type ProjectOptions struct { |
||||
// The name of the project. (Required for creation; optional for update.)
|
||||
Name string `json:"name,omitempty"` |
||||
// The body of the project. (Optional.)
|
||||
Body string `json:"body,omitempty"` |
||||
|
||||
// The following field(s) are only applicable for update.
|
||||
// They should be left with zero values for creation.
|
||||
|
||||
// State of the project. Either "open" or "closed". (Optional.)
|
||||
State string `json:"state,omitempty"` |
||||
} |
||||
|
||||
// UpdateProject updates a repository project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#update-a-project
|
||||
func (s *ProjectsService) UpdateProject(ctx context.Context, id int64, opt *ProjectOptions) (*Project, *Response, error) { |
||||
u := fmt.Sprintf("projects/%v", id) |
||||
req, err := s.client.NewRequest("PATCH", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
project := &Project{} |
||||
resp, err := s.client.Do(ctx, req, project) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return project, resp, nil |
||||
} |
||||
|
||||
// DeleteProject deletes a GitHub Project from a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#delete-a-project
|
||||
func (s *ProjectsService) DeleteProject(ctx context.Context, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("projects/%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", mediaTypeProjectsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ProjectColumn represents a column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/projects/
|
||||
type ProjectColumn struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
ProjectURL *string `json:"project_url,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
// ListProjectColumns lists the columns of a GitHub Project for a repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/columns/#list-project-columns
|
||||
func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID int64, opt *ListOptions) ([]*ProjectColumn, *Response, error) { |
||||
u := fmt.Sprintf("projects/%v/columns", projectID) |
||||
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 headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
columns := []*ProjectColumn{} |
||||
resp, err := s.client.Do(ctx, req, &columns) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return columns, resp, nil |
||||
} |
||||
|
||||
// GetProjectColumn gets a column of a GitHub Project for a repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/columns/#get-a-project-column
|
||||
func (s *ProjectsService) GetProjectColumn(ctx context.Context, id int64) (*ProjectColumn, *Response, error) { |
||||
u := fmt.Sprintf("projects/columns/%v", id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
column := &ProjectColumn{} |
||||
resp, err := s.client.Do(ctx, req, column) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return column, resp, nil |
||||
} |
||||
|
||||
// ProjectColumnOptions specifies the parameters to the
|
||||
// ProjectsService.CreateProjectColumn and
|
||||
// ProjectsService.UpdateProjectColumn methods.
|
||||
type ProjectColumnOptions struct { |
||||
// The name of the project column. (Required for creation and update.)
|
||||
Name string `json:"name"` |
||||
} |
||||
|
||||
// CreateProjectColumn creates a column for the specified (by number) project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/columns/#create-a-project-column
|
||||
func (s *ProjectsService) CreateProjectColumn(ctx context.Context, projectID int64, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { |
||||
u := fmt.Sprintf("projects/%v/columns", projectID) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
column := &ProjectColumn{} |
||||
resp, err := s.client.Do(ctx, req, column) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return column, resp, nil |
||||
} |
||||
|
||||
// UpdateProjectColumn updates a column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/columns/#update-a-project-column
|
||||
func (s *ProjectsService) UpdateProjectColumn(ctx context.Context, columnID int64, opt *ProjectColumnOptions) (*ProjectColumn, *Response, error) { |
||||
u := fmt.Sprintf("projects/columns/%v", columnID) |
||||
req, err := s.client.NewRequest("PATCH", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
column := &ProjectColumn{} |
||||
resp, err := s.client.Do(ctx, req, column) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return column, resp, nil |
||||
} |
||||
|
||||
// DeleteProjectColumn deletes a column from a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/columns/#delete-a-project-column
|
||||
func (s *ProjectsService) DeleteProjectColumn(ctx context.Context, columnID int64) (*Response, error) { |
||||
u := fmt.Sprintf("projects/columns/%v", columnID) |
||||
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", mediaTypeProjectsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ProjectColumnMoveOptions specifies the parameters to the
|
||||
// ProjectsService.MoveProjectColumn method.
|
||||
type ProjectColumnMoveOptions struct { |
||||
// Position can be one of "first", "last", or "after:<column-id>", where
|
||||
// <column-id> is the ID of a column in the same project. (Required.)
|
||||
Position string `json:"position"` |
||||
} |
||||
|
||||
// MoveProjectColumn moves a column within a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/columns/#move-a-project-column
|
||||
func (s *ProjectsService) MoveProjectColumn(ctx context.Context, columnID int64, opt *ProjectColumnMoveOptions) (*Response, error) { |
||||
u := fmt.Sprintf("projects/columns/%v/moves", columnID) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ProjectCard represents a card in a column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card
|
||||
type ProjectCard struct { |
||||
URL *string `json:"url,omitempty"` |
||||
ColumnURL *string `json:"column_url,omitempty"` |
||||
ContentURL *string `json:"content_url,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
Note *string `json:"note,omitempty"` |
||||
Creator *User `json:"creator,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
ColumnID *int64 `json:"column_id,omitempty"` |
||||
} |
||||
|
||||
// ListProjectCards lists the cards in a column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards
|
||||
func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opt *ListOptions) ([]*ProjectCard, *Response, error) { |
||||
u := fmt.Sprintf("projects/columns/%v/cards", columnID) |
||||
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 headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
cards := []*ProjectCard{} |
||||
resp, err := s.client.Do(ctx, req, &cards) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return cards, resp, nil |
||||
} |
||||
|
||||
// GetProjectCard gets a card in a column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#get-a-project-card
|
||||
func (s *ProjectsService) GetProjectCard(ctx context.Context, columnID int64) (*ProjectCard, *Response, error) { |
||||
u := fmt.Sprintf("projects/columns/cards/%v", columnID) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
card := &ProjectCard{} |
||||
resp, err := s.client.Do(ctx, req, card) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return card, resp, nil |
||||
} |
||||
|
||||
// ProjectCardOptions specifies the parameters to the
|
||||
// ProjectsService.CreateProjectCard and
|
||||
// ProjectsService.UpdateProjectCard methods.
|
||||
type ProjectCardOptions struct { |
||||
// The note of the card. Note and ContentID are mutually exclusive.
|
||||
Note string `json:"note,omitempty"` |
||||
// The ID (not Number) of the Issue to associate with this card.
|
||||
// Note and ContentID are mutually exclusive.
|
||||
ContentID int64 `json:"content_id,omitempty"` |
||||
// The type of content to associate with this card. Possible values are: "Issue".
|
||||
ContentType string `json:"content_type,omitempty"` |
||||
} |
||||
|
||||
// CreateProjectCard creates a card in the specified column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#create-a-project-card
|
||||
func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID int64, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { |
||||
u := fmt.Sprintf("projects/columns/%v/cards", columnID) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
card := &ProjectCard{} |
||||
resp, err := s.client.Do(ctx, req, card) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return card, resp, nil |
||||
} |
||||
|
||||
// UpdateProjectCard updates a card of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#update-a-project-card
|
||||
func (s *ProjectsService) UpdateProjectCard(ctx context.Context, cardID int64, opt *ProjectCardOptions) (*ProjectCard, *Response, error) { |
||||
u := fmt.Sprintf("projects/columns/cards/%v", cardID) |
||||
req, err := s.client.NewRequest("PATCH", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
card := &ProjectCard{} |
||||
resp, err := s.client.Do(ctx, req, card) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return card, resp, nil |
||||
} |
||||
|
||||
// DeleteProjectCard deletes a card from a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#delete-a-project-card
|
||||
func (s *ProjectsService) DeleteProjectCard(ctx context.Context, cardID int64) (*Response, error) { |
||||
u := fmt.Sprintf("projects/columns/cards/%v", cardID) |
||||
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", mediaTypeProjectsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ProjectCardMoveOptions specifies the parameters to the
|
||||
// ProjectsService.MoveProjectCard method.
|
||||
type ProjectCardMoveOptions struct { |
||||
// Position can be one of "top", "bottom", or "after:<card-id>", where
|
||||
// <card-id> is the ID of a card in the same project.
|
||||
Position string `json:"position"` |
||||
// ColumnID is the ID of a column in the same project. Note that ColumnID
|
||||
// is required when using Position "after:<card-id>" when that card is in
|
||||
// another column; otherwise it is optional.
|
||||
ColumnID int64 `json:"column_id,omitempty"` |
||||
} |
||||
|
||||
// MoveProjectCard moves a card within a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#move-a-project-card
|
||||
func (s *ProjectsService) MoveProjectCard(ctx context.Context, cardID int64, opt *ProjectCardMoveOptions) (*Response, error) { |
||||
u := fmt.Sprintf("projects/columns/cards/%v/moves", cardID) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,380 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
// PullRequestsService handles communication with the pull request related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/
|
||||
type PullRequestsService service |
||||
|
||||
// PullRequest represents a GitHub pull request on a repository.
|
||||
type PullRequest struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
Number *int `json:"number,omitempty"` |
||||
State *string `json:"state,omitempty"` |
||||
Title *string `json:"title,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
ClosedAt *time.Time `json:"closed_at,omitempty"` |
||||
MergedAt *time.Time `json:"merged_at,omitempty"` |
||||
Labels []*Label `json:"labels,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
Merged *bool `json:"merged,omitempty"` |
||||
Mergeable *bool `json:"mergeable,omitempty"` |
||||
MergeableState *string `json:"mergeable_state,omitempty"` |
||||
MergedBy *User `json:"merged_by,omitempty"` |
||||
MergeCommitSHA *string `json:"merge_commit_sha,omitempty"` |
||||
Comments *int `json:"comments,omitempty"` |
||||
Commits *int `json:"commits,omitempty"` |
||||
Additions *int `json:"additions,omitempty"` |
||||
Deletions *int `json:"deletions,omitempty"` |
||||
ChangedFiles *int `json:"changed_files,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
IssueURL *string `json:"issue_url,omitempty"` |
||||
StatusesURL *string `json:"statuses_url,omitempty"` |
||||
DiffURL *string `json:"diff_url,omitempty"` |
||||
PatchURL *string `json:"patch_url,omitempty"` |
||||
CommitsURL *string `json:"commits_url,omitempty"` |
||||
CommentsURL *string `json:"comments_url,omitempty"` |
||||
ReviewCommentsURL *string `json:"review_comments_url,omitempty"` |
||||
ReviewCommentURL *string `json:"review_comment_url,omitempty"` |
||||
Assignee *User `json:"assignee,omitempty"` |
||||
Assignees []*User `json:"assignees,omitempty"` |
||||
Milestone *Milestone `json:"milestone,omitempty"` |
||||
MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` |
||||
AuthorAssociation *string `json:"author_association,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
RequestedReviewers []*User `json:"requested_reviewers,omitempty"` |
||||
|
||||
Head *PullRequestBranch `json:"head,omitempty"` |
||||
Base *PullRequestBranch `json:"base,omitempty"` |
||||
} |
||||
|
||||
func (p PullRequest) String() string { |
||||
return Stringify(p) |
||||
} |
||||
|
||||
// PullRequestBranch represents a base or head branch in a GitHub pull request.
|
||||
type PullRequestBranch struct { |
||||
Label *string `json:"label,omitempty"` |
||||
Ref *string `json:"ref,omitempty"` |
||||
SHA *string `json:"sha,omitempty"` |
||||
Repo *Repository `json:"repo,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
} |
||||
|
||||
// PullRequestListOptions specifies the optional parameters to the
|
||||
// PullRequestsService.List method.
|
||||
type PullRequestListOptions struct { |
||||
// State filters pull requests based on their state. Possible values are:
|
||||
// open, closed. Default is "open".
|
||||
State string `url:"state,omitempty"` |
||||
|
||||
// Head filters pull requests by head user and branch name in the format of:
|
||||
// "user:ref-name".
|
||||
Head string `url:"head,omitempty"` |
||||
|
||||
// Base filters pull requests by base branch name.
|
||||
Base string `url:"base,omitempty"` |
||||
|
||||
// Sort specifies how to sort pull requests. Possible values are: created,
|
||||
// updated, popularity, long-running. Default is "created".
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// Direction in which to sort pull requests. Possible values are: asc, desc.
|
||||
// If Sort is "created" or not specified, Default is "desc", otherwise Default
|
||||
// is "asc"
|
||||
Direction string `url:"direction,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// List the pull requests for the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/#list-pull-requests
|
||||
func (s *PullRequestsService) List(ctx context.Context, 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 { |
||||
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.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var pulls []*PullRequest |
||||
resp, err := s.client.Do(ctx, req, &pulls) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return pulls, resp, nil |
||||
} |
||||
|
||||
// Get a single pull request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/#get-a-single-pull-request
|
||||
func (s *PullRequestsService) Get(ctx context.Context, owner string, repo string, number int) (*PullRequest, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) |
||||
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.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
pull := new(PullRequest) |
||||
resp, err := s.client.Do(ctx, req, pull) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return pull, resp, nil |
||||
} |
||||
|
||||
// GetRaw gets a single pull request in raw (diff or patch) format.
|
||||
func (s *PullRequestsService) GetRaw(ctx context.Context, owner string, repo string, number int, opt RawOptions) (string, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return "", nil, err |
||||
} |
||||
|
||||
switch opt.Type { |
||||
case Diff: |
||||
req.Header.Set("Accept", mediaTypeV3Diff) |
||||
case Patch: |
||||
req.Header.Set("Accept", mediaTypeV3Patch) |
||||
default: |
||||
return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type) |
||||
} |
||||
|
||||
var buf bytes.Buffer |
||||
resp, err := s.client.Do(ctx, req, &buf) |
||||
if err != nil { |
||||
return "", resp, err |
||||
} |
||||
|
||||
return buf.String(), resp, nil |
||||
} |
||||
|
||||
// NewPullRequest represents a new pull request to be created.
|
||||
type NewPullRequest struct { |
||||
Title *string `json:"title,omitempty"` |
||||
Head *string `json:"head,omitempty"` |
||||
Base *string `json:"base,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Issue *int `json:"issue,omitempty"` |
||||
MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` |
||||
} |
||||
|
||||
// Create a new pull request on the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/#create-a-pull-request
|
||||
func (s *PullRequestsService) Create(ctx context.Context, owner string, repo string, pull *NewPullRequest) (*PullRequest, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, pull) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
p := new(PullRequest) |
||||
resp, err := s.client.Do(ctx, req, p) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return p, resp, nil |
||||
} |
||||
|
||||
type pullRequestUpdate struct { |
||||
Title *string `json:"title,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
State *string `json:"state,omitempty"` |
||||
Base *string `json:"base,omitempty"` |
||||
MaintainerCanModify *bool `json:"maintainer_can_modify,omitempty"` |
||||
} |
||||
|
||||
// Edit a pull request.
|
||||
// pull must not be nil.
|
||||
//
|
||||
// The following fields are editable: Title, Body, State, Base.Ref and MaintainerCanModify.
|
||||
// Base.Ref updates the base branch of the pull request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/#update-a-pull-request
|
||||
func (s *PullRequestsService) Edit(ctx context.Context, owner string, repo string, number int, pull *PullRequest) (*PullRequest, *Response, error) { |
||||
if pull == nil { |
||||
return nil, nil, fmt.Errorf("pull must be provided") |
||||
} |
||||
|
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d", owner, repo, number) |
||||
|
||||
update := &pullRequestUpdate{ |
||||
Title: pull.Title, |
||||
Body: pull.Body, |
||||
State: pull.State, |
||||
MaintainerCanModify: pull.MaintainerCanModify, |
||||
} |
||||
if pull.Base != nil { |
||||
update.Base = pull.Base.Ref |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("PATCH", u, update) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
acceptHeaders := []string{mediaTypeGraphQLNodeIDPreview, mediaTypeLabelDescriptionSearchPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
p := new(PullRequest) |
||||
resp, err := s.client.Do(ctx, req, p) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return p, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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 { |
||||
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", mediaTypeGitSigningPreview) |
||||
|
||||
var commits []*RepositoryCommit |
||||
resp, err := s.client.Do(ctx, req, &commits) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return commits, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var commitFiles []*CommitFile |
||||
resp, err := s.client.Do(ctx, req, &commitFiles) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return commitFiles, resp, nil |
||||
} |
||||
|
||||
// IsMerged checks if a pull request has been merged.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/#get-if-a-pull-request-has-been-merged
|
||||
func (s *PullRequestsService) IsMerged(ctx context.Context, owner string, repo string, number int) (bool, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/merge", owner, repo, number) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
merged, err := parseBoolResponse(err) |
||||
return merged, resp, err |
||||
} |
||||
|
||||
// PullRequestMergeResult represents the result of merging a pull request.
|
||||
type PullRequestMergeResult struct { |
||||
SHA *string `json:"sha,omitempty"` |
||||
Merged *bool `json:"merged,omitempty"` |
||||
Message *string `json:"message,omitempty"` |
||||
} |
||||
|
||||
// PullRequestOptions lets you define how a pull request will be merged.
|
||||
type PullRequestOptions struct { |
||||
CommitTitle string // Extra detail to append to automatic commit message. (Optional.)
|
||||
SHA string // SHA that pull request head must match to allow merge. (Optional.)
|
||||
|
||||
// The merge method to use. Possible values include: "merge", "squash", and "rebase" with the default being merge. (Optional.)
|
||||
MergeMethod string |
||||
} |
||||
|
||||
type pullRequestMergeRequest struct { |
||||
CommitMessage string `json:"commit_message"` |
||||
CommitTitle string `json:"commit_title,omitempty"` |
||||
MergeMethod string `json:"merge_method,omitempty"` |
||||
SHA string `json:"sha,omitempty"` |
||||
} |
||||
|
||||
// Merge a pull request (Merge Button™).
|
||||
// commitMessage is the title for the automatic commit message.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-buttontrade
|
||||
func (s *PullRequestsService) Merge(ctx context.Context, 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) |
||||
|
||||
pullRequestBody := &pullRequestMergeRequest{CommitMessage: commitMessage} |
||||
if options != nil { |
||||
pullRequestBody.CommitTitle = options.CommitTitle |
||||
pullRequestBody.MergeMethod = options.MergeMethod |
||||
pullRequestBody.SHA = options.SHA |
||||
} |
||||
req, err := s.client.NewRequest("PUT", u, pullRequestBody) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
mergeResult := new(PullRequestMergeResult) |
||||
resp, err := s.client.Do(ctx, req, mergeResult) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return mergeResult, resp, nil |
||||
} |
@ -0,0 +1,162 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// PullRequestComment represents a comment left on a pull request.
|
||||
type PullRequestComment struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
InReplyTo *int64 `json:"in_reply_to,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Path *string `json:"path,omitempty"` |
||||
DiffHunk *string `json:"diff_hunk,omitempty"` |
||||
PullRequestReviewID *int64 `json:"pull_request_review_id,omitempty"` |
||||
Position *int `json:"position,omitempty"` |
||||
OriginalPosition *int `json:"original_position,omitempty"` |
||||
CommitID *string `json:"commit_id,omitempty"` |
||||
OriginalCommitID *string `json:"original_commit_id,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
Reactions *Reactions `json:"reactions,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
// AuthorAssociation is the comment author's relationship to the pull request's repository.
|
||||
// Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
|
||||
AuthorAssociation *string `json:"author_association,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
PullRequestURL *string `json:"pull_request_url,omitempty"` |
||||
} |
||||
|
||||
func (p PullRequestComment) String() string { |
||||
return Stringify(p) |
||||
} |
||||
|
||||
// PullRequestListCommentsOptions specifies the optional parameters to the
|
||||
// PullRequestsService.ListComments method.
|
||||
type PullRequestListCommentsOptions struct { |
||||
// Sort specifies how to sort comments. Possible values are: created, updated.
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// Direction in which to sort comments. Possible values are: asc, desc.
|
||||
Direction string `url:"direction,omitempty"` |
||||
|
||||
// Since filters comments by time.
|
||||
Since time.Time `url:"since,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListComments lists all comments on the specified pull request. Specifying a
|
||||
// pull request number of 0 will return all comments on all pull requests for
|
||||
// the repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request
|
||||
func (s *PullRequestsService) ListComments(ctx context.Context, 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) |
||||
} else { |
||||
u = fmt.Sprintf("repos/%v/%v/pulls/%d/comments", 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 comments []*PullRequestComment |
||||
resp, err := s.client.Do(ctx, req, &comments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comments, resp, nil |
||||
} |
||||
|
||||
// GetComment fetches the specified pull request comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#get-a-single-comment
|
||||
func (s *PullRequestsService) GetComment(ctx context.Context, owner string, repo string, commentID int64) (*PullRequestComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
comment := new(PullRequestComment) |
||||
resp, err := s.client.Do(ctx, req, comment) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comment, resp, nil |
||||
} |
||||
|
||||
// CreateComment creates a new comment on the specified pull request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#create-a-comment
|
||||
func (s *PullRequestsService) CreateComment(ctx context.Context, owner string, repo string, number int, comment *PullRequestComment) (*PullRequestComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) |
||||
req, err := s.client.NewRequest("POST", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(PullRequestComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// EditComment updates a pull request comment.
|
||||
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment
|
||||
func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, commentID int64, comment *PullRequestComment) (*PullRequestComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) |
||||
req, err := s.client.NewRequest("PATCH", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(PullRequestComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// DeleteComment deletes a pull request comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#delete-a-comment
|
||||
func (s *PullRequestsService) DeleteComment(ctx context.Context, owner string, repo string, commentID int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%d", owner, repo, commentID) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,79 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ReviewersRequest specifies users and teams for a pull request review request.
|
||||
type ReviewersRequest struct { |
||||
Reviewers []string `json:"reviewers,omitempty"` |
||||
TeamReviewers []string `json:"team_reviewers,omitempty"` |
||||
} |
||||
|
||||
// Reviewers represents reviewers of a pull request.
|
||||
type Reviewers struct { |
||||
Users []*User `json:"users,omitempty"` |
||||
Teams []*Team `json:"teams,omitempty"` |
||||
} |
||||
|
||||
// RequestReviewers creates a review request for the provided reviewers for the specified pull request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#create-a-review-request
|
||||
func (s *PullRequestsService) RequestReviewers(ctx context.Context, owner, repo string, number int, reviewers ReviewersRequest) (*PullRequest, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) |
||||
req, err := s.client.NewRequest("POST", u, &reviewers) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
r := new(PullRequest) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
||||
|
||||
// ListReviewers lists reviewers whose reviews have been requested on the specified pull request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#list-review-requests
|
||||
func (s *PullRequestsService) ListReviewers(ctx context.Context, owner, repo string, number int, opt *ListOptions) (*Reviewers, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/requested_reviewers", 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 |
||||
} |
||||
|
||||
reviewers := new(Reviewers) |
||||
resp, err := s.client.Do(ctx, req, reviewers) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return reviewers, resp, nil |
||||
} |
||||
|
||||
// RemoveReviewers removes the review request for the provided reviewers for the specified pull request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/review_requests/#delete-a-review-request
|
||||
func (s *PullRequestsService) RemoveReviewers(ctx context.Context, owner, repo string, number int, reviewers ReviewersRequest) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/pulls/%d/requested_reviewers", owner, repo, number) |
||||
req, err := s.client.NewRequest("DELETE", u, &reviewers) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,236 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// PullRequestReview represents a review of a pull request.
|
||||
type PullRequestReview struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
SubmittedAt *time.Time `json:"submitted_at,omitempty"` |
||||
CommitID *string `json:"commit_id,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
PullRequestURL *string `json:"pull_request_url,omitempty"` |
||||
State *string `json:"state,omitempty"` |
||||
} |
||||
|
||||
func (p PullRequestReview) String() string { |
||||
return Stringify(p) |
||||
} |
||||
|
||||
// DraftReviewComment represents a comment part of the review.
|
||||
type DraftReviewComment struct { |
||||
Path *string `json:"path,omitempty"` |
||||
Position *int `json:"position,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
} |
||||
|
||||
func (c DraftReviewComment) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// PullRequestReviewRequest represents a request to create a review.
|
||||
type PullRequestReviewRequest struct { |
||||
CommitID *string `json:"commit_id,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Event *string `json:"event,omitempty"` |
||||
Comments []*DraftReviewComment `json:"comments,omitempty"` |
||||
} |
||||
|
||||
func (r PullRequestReviewRequest) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// PullRequestReviewDismissalRequest represents a request to dismiss a review.
|
||||
type PullRequestReviewDismissalRequest struct { |
||||
Message *string `json:"message,omitempty"` |
||||
} |
||||
|
||||
func (r PullRequestReviewDismissalRequest) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// ListReviews lists all reviews on the specified pull request.
|
||||
//
|
||||
// TODO: Follow up with GitHub support about an issue with this method's
|
||||
// returned error format and remove this comment once it's fixed.
|
||||
// Read more about it here - https://github.com/google/go-github/issues/540
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#list-reviews-on-a-pull-request
|
||||
func (s *PullRequestsService) ListReviews(ctx context.Context, owner, repo string, number int, opt *ListOptions) ([]*PullRequestReview, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", 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 |
||||
} |
||||
|
||||
var reviews []*PullRequestReview |
||||
resp, err := s.client.Do(ctx, req, &reviews) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return reviews, resp, nil |
||||
} |
||||
|
||||
// GetReview fetches the specified pull request review.
|
||||
//
|
||||
// TODO: Follow up with GitHub support about an issue with this method's
|
||||
// returned error format and remove this comment once it's fixed.
|
||||
// Read more about it here - https://github.com/google/go-github/issues/540
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-a-single-review
|
||||
func (s *PullRequestsService) GetReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
review := new(PullRequestReview) |
||||
resp, err := s.client.Do(ctx, req, review) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return review, resp, nil |
||||
} |
||||
|
||||
// DeletePendingReview deletes the specified pull request pending review.
|
||||
//
|
||||
// TODO: Follow up with GitHub support about an issue with this method's
|
||||
// returned error format and remove this comment once it's fixed.
|
||||
// Read more about it here - https://github.com/google/go-github/issues/540
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#delete-a-pending-review
|
||||
func (s *PullRequestsService) DeletePendingReview(ctx context.Context, owner, repo string, number int, reviewID int64) (*PullRequestReview, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d", owner, repo, number, reviewID) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
review := new(PullRequestReview) |
||||
resp, err := s.client.Do(ctx, req, review) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return review, resp, nil |
||||
} |
||||
|
||||
// ListReviewComments lists all the comments for the specified review.
|
||||
//
|
||||
// TODO: Follow up with GitHub support about an issue with this method's
|
||||
// returned error format and remove this comment once it's fixed.
|
||||
// Read more about it here - https://github.com/google/go-github/issues/540
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#get-comments-for-a-single-review
|
||||
func (s *PullRequestsService) ListReviewComments(ctx context.Context, owner, repo string, number int, reviewID int64, opt *ListOptions) ([]*PullRequestComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/comments", owner, repo, number, reviewID) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var comments []*PullRequestComment |
||||
resp, err := s.client.Do(ctx, req, &comments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comments, resp, nil |
||||
} |
||||
|
||||
// CreateReview creates a new review on the specified pull request.
|
||||
//
|
||||
// TODO: Follow up with GitHub support about an issue with this method's
|
||||
// returned error format and remove this comment once it's fixed.
|
||||
// Read more about it here - https://github.com/google/go-github/issues/540
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review
|
||||
func (s *PullRequestsService) CreateReview(ctx context.Context, owner, repo string, number int, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews", owner, repo, number) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, review) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
r := new(PullRequestReview) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
||||
|
||||
// SubmitReview submits a specified review on the specified pull request.
|
||||
//
|
||||
// TODO: Follow up with GitHub support about an issue with this method's
|
||||
// returned error format and remove this comment once it's fixed.
|
||||
// Read more about it here - https://github.com/google/go-github/issues/540
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#submit-a-pull-request-review
|
||||
func (s *PullRequestsService) SubmitReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewRequest) (*PullRequestReview, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/events", owner, repo, number, reviewID) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, review) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
r := new(PullRequestReview) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
||||
|
||||
// DismissReview dismisses a specified review on the specified pull request.
|
||||
//
|
||||
// TODO: Follow up with GitHub support about an issue with this method's
|
||||
// returned error format and remove this comment once it's fixed.
|
||||
// Read more about it here - https://github.com/google/go-github/issues/540
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/reviews/#dismiss-a-pull-request-review
|
||||
func (s *PullRequestsService) DismissReview(ctx context.Context, owner, repo string, number int, reviewID int64, review *PullRequestReviewDismissalRequest) (*PullRequestReview, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/reviews/%d/dismissals", owner, repo, number, reviewID) |
||||
|
||||
req, err := s.client.NewRequest("PUT", u, review) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
r := new(PullRequestReview) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return r, resp, nil |
||||
} |
@ -0,0 +1,283 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// ReactionsService provides access to the reactions-related functions in the
|
||||
// GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/
|
||||
type ReactionsService service |
||||
|
||||
// Reaction represents a GitHub reaction.
|
||||
type Reaction struct { |
||||
// ID is the Reaction ID.
|
||||
ID *int64 `json:"id,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
// Content is the type of reaction.
|
||||
// Possible values are:
|
||||
// "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||
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(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id) |
||||
|
||||
body := &Reaction{Content: String(content)} |
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, 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 headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, 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 headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id) |
||||
|
||||
body := &Reaction{Content: String(content)} |
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, owner, repo string, id int64, opt *ListOptions) ([]*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, owner, repo string, id int64, content string) (*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id) |
||||
|
||||
body := &Reaction{Content: String(content)} |
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeReactionsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, 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(ctx context.Context, id int64) (*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(ctx, req, nil) |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,140 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListCollaboratorsOptions specifies the optional parameters to the
|
||||
// RepositoriesService.ListCollaborators method.
|
||||
type ListCollaboratorsOptions struct { |
||||
// Affiliation specifies how collaborators should be filtered by their affiliation.
|
||||
// Possible values are:
|
||||
// outside - All outside collaborators of an organization-owned repository
|
||||
// direct - All collaborators with permissions to an organization-owned repository,
|
||||
// regardless of organization membership status
|
||||
// all - All collaborators the authenticated user can see
|
||||
//
|
||||
// Default value is "all".
|
||||
Affiliation string `url:"affiliation,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListCollaborators lists the GitHub users that have access to the repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#list-collaborators
|
||||
func (s *RepositoriesService) ListCollaborators(ctx context.Context, owner, repo string, opt *ListCollaboratorsOptions) ([]*User, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/collaborators", owner, repo) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeNestedTeamsPreview) |
||||
|
||||
var users []*User |
||||
resp, err := s.client.Do(ctx, req, &users) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return users, resp, nil |
||||
} |
||||
|
||||
// IsCollaborator checks whether the specified GitHub user has collaborator
|
||||
// access to the given repo.
|
||||
// Note: This will return false if the user is not a collaborator OR the user
|
||||
// is not a GitHub user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#get
|
||||
func (s *RepositoriesService) IsCollaborator(ctx context.Context, owner, repo, user string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
isCollab, err := parseBoolResponse(err) |
||||
return isCollab, resp, err |
||||
} |
||||
|
||||
// RepositoryPermissionLevel represents the permission level an organization
|
||||
// member has for a given repository.
|
||||
type RepositoryPermissionLevel struct { |
||||
// Possible values: "admin", "write", "read", "none"
|
||||
Permission *string `json:"permission,omitempty"` |
||||
|
||||
User *User `json:"user,omitempty"` |
||||
} |
||||
|
||||
// GetPermissionLevel retrieves the specific permission level a collaborator has for a given repository.
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level
|
||||
func (s *RepositoriesService) GetPermissionLevel(ctx context.Context, owner, repo, user string) (*RepositoryPermissionLevel, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/collaborators/%v/permission", owner, repo, user) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
rpl := new(RepositoryPermissionLevel) |
||||
resp, err := s.client.Do(ctx, req, rpl) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return rpl, resp, nil |
||||
} |
||||
|
||||
// RepositoryAddCollaboratorOptions specifies the optional parameters to the
|
||||
// RepositoriesService.AddCollaborator method.
|
||||
type RepositoryAddCollaboratorOptions struct { |
||||
// Permission specifies the permission to grant the user on this repository.
|
||||
// Possible values are:
|
||||
// pull - team members can pull, but not push to or administer this repository
|
||||
// push - team members can pull and push, but not administer this repository
|
||||
// admin - team members can pull, push and administer this repository
|
||||
//
|
||||
// Default value is "push". This option is only valid for organization-owned repositories.
|
||||
Permission string `json:"permission,omitempty"` |
||||
} |
||||
|
||||
// AddCollaborator sends an invitation to the specified GitHub user
|
||||
// to become a collaborator to the given repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator
|
||||
func (s *RepositoriesService) AddCollaborator(ctx context.Context, 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) |
||||
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(ctx, req, nil) |
||||
} |
||||
|
||||
// RemoveCollaborator removes the specified GitHub user as collaborator from the given repo.
|
||||
// Note: Does not return error if a valid user that is not a collaborator is removed.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/collaborators/#remove-collaborator
|
||||
func (s *RepositoriesService) RemoveCollaborator(ctx context.Context, owner, repo, user string) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/collaborators/%v", owner, repo, user) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,161 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// RepositoryComment represents a comment for a commit, file, or line in a repository.
|
||||
type RepositoryComment struct { |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
ID *int64 `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"` |
||||
|
||||
// User-mutable fields
|
||||
Body *string `json:"body"` |
||||
// User-initialized fields
|
||||
Path *string `json:"path,omitempty"` |
||||
Position *int `json:"position,omitempty"` |
||||
} |
||||
|
||||
func (r RepositoryComment) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// ListComments lists all the comments for the repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository
|
||||
func (s *RepositoriesService) ListComments(ctx context.Context, 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 { |
||||
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 comments []*RepositoryComment |
||||
resp, err := s.client.Do(ctx, req, &comments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comments, resp, nil |
||||
} |
||||
|
||||
// ListCommitComments lists all the comments for a given commit SHA.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit
|
||||
func (s *RepositoriesService) ListCommitComments(ctx context.Context, 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 { |
||||
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 comments []*RepositoryComment |
||||
resp, err := s.client.Do(ctx, req, &comments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comments, resp, nil |
||||
} |
||||
|
||||
// CreateComment creates a comment for the given commit.
|
||||
// Note: GitHub allows for comments to be created for non-existing files and positions.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/comments/#create-a-commit-comment
|
||||
func (s *RepositoriesService) CreateComment(ctx context.Context, owner, repo, sha string, comment *RepositoryComment) (*RepositoryComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha) |
||||
req, err := s.client.NewRequest("POST", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(RepositoryComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// GetComment gets a single comment from a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/comments/#get-a-single-commit-comment
|
||||
func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string, id int64) (*RepositoryComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
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(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// UpdateComment updates the body of a single comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/comments/#update-a-commit-comment
|
||||
func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo string, id int64, comment *RepositoryComment) (*RepositoryComment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) |
||||
req, err := s.client.NewRequest("PATCH", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(RepositoryComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// DeleteComment deletes a single comment from a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/comments/#delete-a-commit-comment
|
||||
func (s *RepositoriesService) DeleteComment(ctx context.Context, owner, repo string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,237 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// RepositoryCommit represents a commit in a repo.
|
||||
// Note that it's wrapping a Commit, so author/committer information is in two places,
|
||||
// but contain different details about them: in RepositoryCommit "github details", in Commit - "git details".
|
||||
type RepositoryCommit struct { |
||||
SHA *string `json:"sha,omitempty"` |
||||
Commit *Commit `json:"commit,omitempty"` |
||||
Author *User `json:"author,omitempty"` |
||||
Committer *User `json:"committer,omitempty"` |
||||
Parents []Commit `json:"parents,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
CommentsURL *string `json:"comments_url,omitempty"` |
||||
|
||||
// Details about how many changes were made in this commit. Only filled in during GetCommit!
|
||||
Stats *CommitStats `json:"stats,omitempty"` |
||||
// Details about which files, and how this commit touched. Only filled in during GetCommit!
|
||||
Files []CommitFile `json:"files,omitempty"` |
||||
} |
||||
|
||||
func (r RepositoryCommit) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// CommitStats represents the number of additions / deletions from a file in a given RepositoryCommit or GistCommit.
|
||||
type CommitStats struct { |
||||
Additions *int `json:"additions,omitempty"` |
||||
Deletions *int `json:"deletions,omitempty"` |
||||
Total *int `json:"total,omitempty"` |
||||
} |
||||
|
||||
func (c CommitStats) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// CommitFile represents a file modified in a commit.
|
||||
type CommitFile struct { |
||||
SHA *string `json:"sha,omitempty"` |
||||
Filename *string `json:"filename,omitempty"` |
||||
Additions *int `json:"additions,omitempty"` |
||||
Deletions *int `json:"deletions,omitempty"` |
||||
Changes *int `json:"changes,omitempty"` |
||||
Status *string `json:"status,omitempty"` |
||||
Patch *string `json:"patch,omitempty"` |
||||
BlobURL *string `json:"blob_url,omitempty"` |
||||
RawURL *string `json:"raw_url,omitempty"` |
||||
ContentsURL *string `json:"contents_url,omitempty"` |
||||
} |
||||
|
||||
func (c CommitFile) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// CommitsComparison is the result of comparing two commits.
|
||||
// See CompareCommits() for details.
|
||||
type CommitsComparison struct { |
||||
BaseCommit *RepositoryCommit `json:"base_commit,omitempty"` |
||||
MergeBaseCommit *RepositoryCommit `json:"merge_base_commit,omitempty"` |
||||
|
||||
// Head can be 'behind' or 'ahead'
|
||||
Status *string `json:"status,omitempty"` |
||||
AheadBy *int `json:"ahead_by,omitempty"` |
||||
BehindBy *int `json:"behind_by,omitempty"` |
||||
TotalCommits *int `json:"total_commits,omitempty"` |
||||
|
||||
Commits []RepositoryCommit `json:"commits,omitempty"` |
||||
|
||||
Files []CommitFile `json:"files,omitempty"` |
||||
|
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
PermalinkURL *string `json:"permalink_url,omitempty"` |
||||
DiffURL *string `json:"diff_url,omitempty"` |
||||
PatchURL *string `json:"patch_url,omitempty"` |
||||
URL *string `json:"url,omitempty"` // API URL.
|
||||
} |
||||
|
||||
func (c CommitsComparison) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// CommitsListOptions specifies the optional parameters to the
|
||||
// RepositoriesService.ListCommits method.
|
||||
type CommitsListOptions struct { |
||||
// SHA or branch to start listing Commits from.
|
||||
SHA string `url:"sha,omitempty"` |
||||
|
||||
// Path that should be touched by the returned Commits.
|
||||
Path string `url:"path,omitempty"` |
||||
|
||||
// Author of by which to filter Commits.
|
||||
Author string `url:"author,omitempty"` |
||||
|
||||
// Since when should Commits be included in the response.
|
||||
Since time.Time `url:"since,omitempty"` |
||||
|
||||
// Until when should Commits be included in the response.
|
||||
Until time.Time `url:"until,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListCommits lists the commits of a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/commits/#list
|
||||
func (s *RepositoriesService) ListCommits(ctx context.Context, 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 { |
||||
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", mediaTypeGitSigningPreview) |
||||
|
||||
var commits []*RepositoryCommit |
||||
resp, err := s.client.Do(ctx, req, &commits) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return commits, resp, nil |
||||
} |
||||
|
||||
// GetCommit fetches the specified commit, including all details about it.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-a-single-commit
|
||||
// See also: https://developer.github.com/v3/git/commits/#get-a-single-commit provides the same functionality
|
||||
func (s *RepositoriesService) GetCommit(ctx context.Context, owner, repo, sha string) (*RepositoryCommit, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) |
||||
|
||||
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) |
||||
|
||||
commit := new(RepositoryCommit) |
||||
resp, err := s.client.Do(ctx, req, commit) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return commit, resp, nil |
||||
} |
||||
|
||||
// GetCommitRaw fetches the specified commit in raw (diff or patch) format.
|
||||
func (s *RepositoriesService) GetCommitRaw(ctx context.Context, owner string, repo string, sha string, opt RawOptions) (string, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v", owner, repo, sha) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return "", nil, err |
||||
} |
||||
|
||||
switch opt.Type { |
||||
case Diff: |
||||
req.Header.Set("Accept", mediaTypeV3Diff) |
||||
case Patch: |
||||
req.Header.Set("Accept", mediaTypeV3Patch) |
||||
default: |
||||
return "", nil, fmt.Errorf("unsupported raw type %d", opt.Type) |
||||
} |
||||
|
||||
var buf bytes.Buffer |
||||
resp, err := s.client.Do(ctx, req, &buf) |
||||
if err != nil { |
||||
return "", resp, err |
||||
} |
||||
|
||||
return buf.String(), resp, nil |
||||
} |
||||
|
||||
// GetCommitSHA1 gets the SHA-1 of a commit reference. If a last-known SHA1 is
|
||||
// supplied and no new commits have occurred, a 304 Unmodified response is returned.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference
|
||||
func (s *RepositoriesService) GetCommitSHA1(ctx context.Context, 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(ctx, req, &buf) |
||||
if err != nil { |
||||
return "", resp, err |
||||
} |
||||
|
||||
return buf.String(), resp, nil |
||||
} |
||||
|
||||
// CompareCommits compares a range of commits with each other.
|
||||
// todo: support media formats - https://github.com/google/go-github/issues/6
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/commits/index.html#compare-two-commits
|
||||
func (s *RepositoriesService) CompareCommits(ctx context.Context, owner, repo string, base, head string) (*CommitsComparison, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/compare/%v...%v", owner, repo, base, head) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
comp := new(CommitsComparison) |
||||
resp, err := s.client.Do(ctx, req, comp) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comp, resp, nil |
||||
} |
@ -0,0 +1,57 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// Metric represents the different fields for one file in community health files.
|
||||
type Metric struct { |
||||
Name *string `json:"name"` |
||||
Key *string `json:"key"` |
||||
URL *string `json:"url"` |
||||
HTMLURL *string `json:"html_url"` |
||||
} |
||||
|
||||
// CommunityHealthFiles represents the different files in the community health metrics response.
|
||||
type CommunityHealthFiles struct { |
||||
CodeOfConduct *Metric `json:"code_of_conduct"` |
||||
Contributing *Metric `json:"contributing"` |
||||
License *Metric `json:"license"` |
||||
Readme *Metric `json:"readme"` |
||||
} |
||||
|
||||
// CommunityHealthMetrics represents a response containing the community metrics of a repository.
|
||||
type CommunityHealthMetrics struct { |
||||
HealthPercentage *int `json:"health_percentage"` |
||||
Files *CommunityHealthFiles `json:"files"` |
||||
UpdatedAt *time.Time `json:"updated_at"` |
||||
} |
||||
|
||||
// GetCommunityHealthMetrics retrieves all the community health metrics for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/community/#retrieve-community-health-metrics
|
||||
func (s *RepositoriesService) GetCommunityHealthMetrics(ctx context.Context, owner, repo string) (*CommunityHealthMetrics, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/community/profile", 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", mediaTypeRepositoryCommunityHealthMetricsPreview) |
||||
|
||||
metrics := &CommunityHealthMetrics{} |
||||
resp, err := s.client.Do(ctx, req, metrics) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return metrics, resp, nil |
||||
} |
@ -0,0 +1,266 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Repository contents API methods.
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/contents/
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/base64" |
||||
"encoding/json" |
||||
"fmt" |
||||
"io" |
||||
"net/http" |
||||
"net/url" |
||||
"path" |
||||
) |
||||
|
||||
// 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"` |
||||
// 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"` |
||||
GitURL *string `json:"git_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
DownloadURL *string `json:"download_url,omitempty"` |
||||
} |
||||
|
||||
// RepositoryContentResponse holds the parsed response from CreateFile, UpdateFile, and DeleteFile.
|
||||
type RepositoryContentResponse struct { |
||||
Content *RepositoryContent `json:"content,omitempty"` |
||||
Commit `json:"commit,omitempty"` |
||||
} |
||||
|
||||
// RepositoryContentFileOptions specifies optional parameters for CreateFile, UpdateFile, and DeleteFile.
|
||||
type RepositoryContentFileOptions struct { |
||||
Message *string `json:"message,omitempty"` |
||||
Content []byte `json:"content,omitempty"` // unencoded
|
||||
SHA *string `json:"sha,omitempty"` |
||||
Branch *string `json:"branch,omitempty"` |
||||
Author *CommitAuthor `json:"author,omitempty"` |
||||
Committer *CommitAuthor `json:"committer,omitempty"` |
||||
} |
||||
|
||||
// RepositoryContentGetOptions represents an optional ref parameter, which can be a SHA,
|
||||
// branch, or tag
|
||||
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) |
||||
} |
||||
|
||||
// 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: https://developer.github.com/v3/repos/contents/#get-the-readme
|
||||
func (s *RepositoriesService) GetReadme(ctx context.Context, owner, repo string, opt *RepositoryContentGetOptions) (*RepositoryContent, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/readme", owner, repo) |
||||
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 |
||||
} |
||||
readme := new(RepositoryContent) |
||||
resp, err := s.client.Do(ctx, req, readme) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return readme, resp, nil |
||||
} |
||||
|
||||
// DownloadContents returns an io.ReadCloser that reads the contents of the
|
||||
// specified file. This function will work with files of any size, as opposed
|
||||
// to GetContents which is limited to 1 Mb files. It is the caller's
|
||||
// responsibility to close the ReadCloser.
|
||||
func (s *RepositoriesService) DownloadContents(ctx context.Context, owner, repo, filepath string, opt *RepositoryContentGetOptions) (io.ReadCloser, error) { |
||||
dir := path.Dir(filepath) |
||||
filename := path.Base(filepath) |
||||
_, dirContents, _, err := s.GetContents(ctx, owner, repo, dir, opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
for _, contents := range dirContents { |
||||
if *contents.Name == filename { |
||||
if contents.DownloadURL == nil || *contents.DownloadURL == "" { |
||||
return nil, fmt.Errorf("No download link found for %s", filepath) |
||||
} |
||||
resp, err := s.client.client.Get(*contents.DownloadURL) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return resp.Body, nil |
||||
} |
||||
} |
||||
return nil, fmt.Errorf("No file named %s found in %s", filename, dir) |
||||
} |
||||
|
||||
// GetContents can return either the metadata and content of a single file
|
||||
// (when path references a file) or the metadata of all the files and/or
|
||||
// subdirectories of a directory (when path references a directory). To make it
|
||||
// easy to distinguish between both result types and to mimic the API as much
|
||||
// as possible, both result types will be returned but only one will contain a
|
||||
// value and the other will be nil.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-contents
|
||||
func (s *RepositoriesService) GetContents(ctx context.Context, 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 |
||||
} |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, nil, err |
||||
} |
||||
var rawJSON json.RawMessage |
||||
resp, err = s.client.Do(ctx, req, &rawJSON) |
||||
if err != nil { |
||||
return nil, nil, resp, err |
||||
} |
||||
fileUnmarshalError := json.Unmarshal(rawJSON, &fileContent) |
||||
if fileUnmarshalError == nil { |
||||
return fileContent, nil, resp, nil |
||||
} |
||||
directoryUnmarshalError := json.Unmarshal(rawJSON, &directoryContent) |
||||
if directoryUnmarshalError == nil { |
||||
return nil, directoryContent, resp, nil |
||||
} |
||||
return nil, nil, resp, fmt.Errorf("unmarshalling failed for both file and directory content: %s and %s", fileUnmarshalError, directoryUnmarshalError) |
||||
} |
||||
|
||||
// CreateFile creates a new file in a repository at the given path and returns
|
||||
// the commit and file metadata.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/contents/#create-a-file
|
||||
func (s *RepositoriesService) CreateFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) |
||||
req, err := s.client.NewRequest("PUT", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
createResponse := new(RepositoryContentResponse) |
||||
resp, err := s.client.Do(ctx, req, createResponse) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return createResponse, resp, nil |
||||
} |
||||
|
||||
// UpdateFile updates a file in a repository at the given path and returns the
|
||||
// commit and file metadata. Requires the blob SHA of the file being updated.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/contents/#update-a-file
|
||||
func (s *RepositoriesService) UpdateFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) |
||||
req, err := s.client.NewRequest("PUT", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
updateResponse := new(RepositoryContentResponse) |
||||
resp, err := s.client.Do(ctx, req, updateResponse) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return updateResponse, resp, nil |
||||
} |
||||
|
||||
// DeleteFile deletes a file from a repository and returns the commit.
|
||||
// Requires the blob SHA of the file to be deleted.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/contents/#delete-a-file
|
||||
func (s *RepositoriesService) DeleteFile(ctx context.Context, owner, repo, path string, opt *RepositoryContentFileOptions) (*RepositoryContentResponse, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path) |
||||
req, err := s.client.NewRequest("DELETE", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
deleteResponse := new(RepositoryContentResponse) |
||||
resp, err := s.client.Do(ctx, req, deleteResponse) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return deleteResponse, resp, nil |
||||
} |
||||
|
||||
// archiveFormat is used to define the archive type when calling GetArchiveLink.
|
||||
type archiveFormat string |
||||
|
||||
const ( |
||||
// Tarball specifies an archive in gzipped tar format.
|
||||
Tarball archiveFormat = "tarball" |
||||
|
||||
// Zipball specifies an archive in zip format.
|
||||
Zipball archiveFormat = "zipball" |
||||
) |
||||
|
||||
// GetArchiveLink returns an URL to download a tarball or zipball archive for a
|
||||
// repository. The archiveFormat can be specified by either the github.Tarball
|
||||
// or github.Zipball constant.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/contents/#get-archive-link
|
||||
func (s *RepositoriesService) GetArchiveLink(ctx context.Context, owner, repo string, archiveformat archiveFormat, opt *RepositoryContentGetOptions) (*url.URL, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/%s", owner, repo, archiveformat) |
||||
if opt != nil && opt.Ref != "" { |
||||
u += fmt.Sprintf("/%s", opt.Ref) |
||||
} |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
var resp *http.Response |
||||
// Use http.DefaultTransport if no custom Transport is configured
|
||||
req = withContext(ctx, req) |
||||
if s.client.client.Transport == nil { |
||||
resp, err = http.DefaultTransport.RoundTrip(req) |
||||
} else { |
||||
resp, err = s.client.client.Transport.RoundTrip(req) |
||||
} |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
resp.Body.Close() |
||||
if resp.StatusCode != http.StatusFound { |
||||
return nil, newResponse(resp), fmt.Errorf("unexpected status code: %s", resp.Status) |
||||
} |
||||
parsedURL, err := url.Parse(resp.Header.Get("Location")) |
||||
return parsedURL, newResponse(resp), err |
||||
} |
@ -0,0 +1,237 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"encoding/json" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// Deployment represents a deployment in a repo
|
||||
type Deployment struct { |
||||
URL *string `json:"url,omitempty"` |
||||
ID *int64 `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:"updated_at,omitempty"` |
||||
StatusesURL *string `json:"statuses_url,omitempty"` |
||||
RepositoryURL *string `json:"repository_url,omitempty"` |
||||
NodeID *string `json:"node_id,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"` |
||||
TransientEnvironment *bool `json:"transient_environment,omitempty"` |
||||
ProductionEnvironment *bool `json:"production_environment,omitempty"` |
||||
} |
||||
|
||||
// DeploymentsListOptions specifies the optional parameters to the
|
||||
// RepositoriesService.ListDeployments method.
|
||||
type DeploymentsListOptions struct { |
||||
// SHA of the Deployment.
|
||||
SHA string `url:"sha,omitempty"` |
||||
|
||||
// List deployments for a given ref.
|
||||
Ref string `url:"ref,omitempty"` |
||||
|
||||
// List deployments for a given task.
|
||||
Task string `url:"task,omitempty"` |
||||
|
||||
// List deployments for a given environment.
|
||||
Environment string `url:"environment,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListDeployments lists the deployments of a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/deployments/#list-deployments
|
||||
func (s *RepositoriesService) ListDeployments(ctx context.Context, 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 { |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var deployments []*Deployment |
||||
resp, err := s.client.Do(ctx, req, &deployments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return deployments, resp, nil |
||||
} |
||||
|
||||
// GetDeployment returns a single deployment of a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment
|
||||
func (s *RepositoriesService) GetDeployment(ctx context.Context, owner, repo string, deploymentID int64) (*Deployment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/deployments/%v", owner, repo, deploymentID) |
||||
|
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
deployment := new(Deployment) |
||||
resp, err := s.client.Do(ctx, req, deployment) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return deployment, resp, nil |
||||
} |
||||
|
||||
// CreateDeployment creates a new deployment for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment
|
||||
func (s *RepositoriesService) CreateDeployment(ctx context.Context, owner, repo string, request *DeploymentRequest) (*Deployment, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/deployments", owner, repo) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, request) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
d := new(Deployment) |
||||
resp, err := s.client.Do(ctx, req, d) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return d, resp, nil |
||||
} |
||||
|
||||
// DeploymentStatus represents the status of a
|
||||
// particular deployment.
|
||||
type DeploymentStatus struct { |
||||
ID *int64 `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:"updated_at,omitempty"` |
||||
DeploymentURL *string `json:"deployment_url,omitempty"` |
||||
RepositoryURL *string `json:"repository_url,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
// DeploymentStatusRequest represents a deployment request
|
||||
type DeploymentStatusRequest struct { |
||||
State *string `json:"state,omitempty"` |
||||
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(ctx context.Context, owner, repo string, deployment int64, 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 { |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var statuses []*DeploymentStatus |
||||
resp, err := s.client.Do(ctx, req, &statuses) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return statuses, resp, nil |
||||
} |
||||
|
||||
// GetDeploymentStatus returns a single deployment status of a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/deployments/#get-a-single-deployment-status
|
||||
func (s *RepositoriesService) GetDeploymentStatus(ctx context.Context, owner, repo string, deploymentID, deploymentStatusID int64) (*DeploymentStatus, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses/%v", owner, repo, deploymentID, deploymentStatusID) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
d := new(DeploymentStatus) |
||||
resp, err := s.client.Do(ctx, req, d) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return d, resp, nil |
||||
} |
||||
|
||||
// CreateDeploymentStatus creates a new status for a deployment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/deployments/#create-a-deployment-status
|
||||
func (s *RepositoriesService) CreateDeploymentStatus(ctx context.Context, owner, repo string, deployment int64, request *DeploymentStatusRequest) (*DeploymentStatus, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/deployments/%v/statuses", owner, repo, deployment) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, request) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeDeploymentStatusPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
d := new(DeploymentStatus) |
||||
resp, err := s.client.Do(ctx, req, d) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return d, resp, nil |
||||
} |
@ -0,0 +1,89 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// RepositoryListForksOptions specifies the optional parameters to the
|
||||
// RepositoriesService.ListForks method.
|
||||
type RepositoryListForksOptions struct { |
||||
// How to sort the forks list. Possible values are: newest, oldest,
|
||||
// watchers. Default is "newest".
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListForks lists the forks of the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/forks/#list-forks
|
||||
func (s *RepositoriesService) ListForks(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when topics API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTopicsPreview) |
||||
|
||||
var repos []*Repository |
||||
resp, err := s.client.Do(ctx, req, &repos) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return repos, resp, nil |
||||
} |
||||
|
||||
// RepositoryCreateForkOptions specifies the optional parameters to the
|
||||
// RepositoriesService.CreateFork method.
|
||||
type RepositoryCreateForkOptions struct { |
||||
// The organization to fork the repository into.
|
||||
Organization string `url:"organization,omitempty"` |
||||
} |
||||
|
||||
// CreateFork creates a fork of the specified repository.
|
||||
//
|
||||
// This method might return an *AcceptedError and a status code of
|
||||
// 202. This is because this is the status that GitHub returns to signify that
|
||||
// it is now computing creating the fork in a background task. In this event,
|
||||
// the Repository value will be returned, which includes the details about the pending fork.
|
||||
// A follow up request, after a delay of a second or so, should result
|
||||
// in a successful request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/forks/#create-a-fork
|
||||
func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string, opt *RepositoryCreateForkOptions) (*Repository, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/forks", owner, repo) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
fork := new(Repository) |
||||
resp, err := s.client.Do(ctx, req, fork) |
||||
if _, ok := err.(*AcceptedError); ok { |
||||
return fork, resp, err |
||||
} |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return fork, resp, nil |
||||
} |
@ -0,0 +1,192 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// WebHookPayload represents the data that is received from GitHub when a push
|
||||
// event hook is triggered. The format of these payloads pre-date most of the
|
||||
// GitHub v3 API, so there are lots of minor incompatibilities with the types
|
||||
// defined in the rest of the API. Therefore, several types are duplicated
|
||||
// here to account for these differences.
|
||||
//
|
||||
// GitHub API docs: https://help.github.com/articles/post-receive-hooks
|
||||
type WebHookPayload struct { |
||||
After *string `json:"after,omitempty"` |
||||
Before *string `json:"before,omitempty"` |
||||
Commits []WebHookCommit `json:"commits,omitempty"` |
||||
Compare *string `json:"compare,omitempty"` |
||||
Created *bool `json:"created,omitempty"` |
||||
Deleted *bool `json:"deleted,omitempty"` |
||||
Forced *bool `json:"forced,omitempty"` |
||||
HeadCommit *WebHookCommit `json:"head_commit,omitempty"` |
||||
Pusher *User `json:"pusher,omitempty"` |
||||
Ref *string `json:"ref,omitempty"` |
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
} |
||||
|
||||
func (w WebHookPayload) String() string { |
||||
return Stringify(w) |
||||
} |
||||
|
||||
// WebHookCommit represents the commit variant we receive from GitHub in a
|
||||
// WebHookPayload.
|
||||
type WebHookCommit struct { |
||||
Added []string `json:"added,omitempty"` |
||||
Author *WebHookAuthor `json:"author,omitempty"` |
||||
Committer *WebHookAuthor `json:"committer,omitempty"` |
||||
Distinct *bool `json:"distinct,omitempty"` |
||||
ID *string `json:"id,omitempty"` |
||||
Message *string `json:"message,omitempty"` |
||||
Modified []string `json:"modified,omitempty"` |
||||
Removed []string `json:"removed,omitempty"` |
||||
Timestamp *time.Time `json:"timestamp,omitempty"` |
||||
} |
||||
|
||||
func (w WebHookCommit) String() string { |
||||
return Stringify(w) |
||||
} |
||||
|
||||
// WebHookAuthor represents the author or committer of a commit, as specified
|
||||
// in a WebHookCommit. The commit author may not correspond to a GitHub User.
|
||||
type WebHookAuthor struct { |
||||
Email *string `json:"email,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Username *string `json:"username,omitempty"` |
||||
} |
||||
|
||||
func (w WebHookAuthor) String() string { |
||||
return Stringify(w) |
||||
} |
||||
|
||||
// Hook represents a GitHub (web and service) hook for a repository.
|
||||
type Hook struct { |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Events []string `json:"events,omitempty"` |
||||
Active *bool `json:"active,omitempty"` |
||||
Config map[string]interface{} `json:"config,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
} |
||||
|
||||
func (h Hook) String() string { |
||||
return Stringify(h) |
||||
} |
||||
|
||||
// CreateHook creates a Hook for the specified repository.
|
||||
// Name and Config are required fields.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#create-a-hook
|
||||
func (s *RepositoriesService) CreateHook(ctx context.Context, owner, repo string, hook *Hook) (*Hook, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/hooks", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, hook) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
h := new(Hook) |
||||
resp, err := s.client.Do(ctx, req, h) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return h, resp, nil |
||||
} |
||||
|
||||
// ListHooks lists all Hooks for the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#list
|
||||
func (s *RepositoriesService) ListHooks(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var hooks []*Hook |
||||
resp, err := s.client.Do(ctx, req, &hooks) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return hooks, resp, nil |
||||
} |
||||
|
||||
// GetHook returns a single specified Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#get-single-hook
|
||||
func (s *RepositoriesService) GetHook(ctx context.Context, owner, repo string, id int64) (*Hook, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
hook := new(Hook) |
||||
resp, err := s.client.Do(ctx, req, hook) |
||||
return hook, resp, err |
||||
} |
||||
|
||||
// EditHook updates a specified Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#edit-a-hook
|
||||
func (s *RepositoriesService) EditHook(ctx context.Context, owner, repo string, id int64, hook *Hook) (*Hook, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) |
||||
req, err := s.client.NewRequest("PATCH", u, hook) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
h := new(Hook) |
||||
resp, err := s.client.Do(ctx, req, h) |
||||
return h, resp, err |
||||
} |
||||
|
||||
// DeleteHook deletes a specified Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#delete-a-hook
|
||||
func (s *RepositoriesService) DeleteHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/hooks/%d", owner, repo, id) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// PingHook triggers a 'ping' event to be sent to the Hook.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#ping-a-hook
|
||||
func (s *RepositoriesService) PingHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/hooks/%d/pings", owner, repo, id) |
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// TestHook triggers a test Hook by github.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/hooks/#test-a-push-hook
|
||||
func (s *RepositoriesService) TestHook(ctx context.Context, owner, repo string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/hooks/%d/tests", owner, repo, id) |
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,98 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// RepositoryInvitation represents an invitation to collaborate on a repo.
|
||||
type RepositoryInvitation struct { |
||||
ID *int64 `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(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryInvitation, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/invitations", owner, repo) |
||||
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(ctx, req, &invites) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return invites, resp, nil |
||||
} |
||||
|
||||
// DeleteInvitation deletes a repository invitation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/invitations/#delete-a-repository-invitation
|
||||
func (s *RepositoriesService) DeleteInvitation(ctx context.Context, owner, repo string, invitationID int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, 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(ctx, 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(ctx context.Context, owner, repo string, invitationID int64, permissions string) (*RepositoryInvitation, *Response, error) { |
||||
opts := &struct { |
||||
Permissions string `json:"permissions"` |
||||
}{Permissions: permissions} |
||||
u := fmt.Sprintf("repos/%v/%v/invitations/%v", owner, repo, 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(ctx, req, invite) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return invite, resp, nil |
||||
} |
@ -0,0 +1,111 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// The Key type is defined in users_keys.go
|
||||
|
||||
// ListKeys lists the deploy keys for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/keys/#list
|
||||
func (s *RepositoriesService) ListKeys(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var keys []*Key |
||||
resp, err := s.client.Do(ctx, req, &keys) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return keys, resp, nil |
||||
} |
||||
|
||||
// GetKey fetches a single deploy key.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/keys/#get
|
||||
func (s *RepositoriesService) GetKey(ctx context.Context, owner string, repo string, id int64) (*Key, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
key := new(Key) |
||||
resp, err := s.client.Do(ctx, req, key) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return key, resp, nil |
||||
} |
||||
|
||||
// CreateKey adds a deploy key for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/keys/#create
|
||||
func (s *RepositoriesService) CreateKey(ctx context.Context, owner string, repo string, key *Key) (*Key, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/keys", owner, repo) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, key) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
k := new(Key) |
||||
resp, err := s.client.Do(ctx, req, k) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return k, resp, nil |
||||
} |
||||
|
||||
// EditKey edits a deploy key.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/keys/#edit
|
||||
func (s *RepositoriesService) EditKey(ctx context.Context, owner string, repo string, id int64, key *Key) (*Key, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("PATCH", u, key) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
k := new(Key) |
||||
resp, err := s.client.Do(ctx, req, k) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return k, resp, nil |
||||
} |
||||
|
||||
// DeleteKey deletes a deploy key.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/keys/#delete
|
||||
func (s *RepositoriesService) DeleteKey(ctx context.Context, owner string, repo string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/keys/%v", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,38 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// RepositoryMergeRequest represents a request to merge a branch in a
|
||||
// repository.
|
||||
type RepositoryMergeRequest struct { |
||||
Base *string `json:"base,omitempty"` |
||||
Head *string `json:"head,omitempty"` |
||||
CommitMessage *string `json:"commit_message,omitempty"` |
||||
} |
||||
|
||||
// Merge a branch in the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/merging/#perform-a-merge
|
||||
func (s *RepositoriesService) Merge(ctx context.Context, owner, repo string, request *RepositoryMergeRequest) (*RepositoryCommit, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/merges", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, request) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
commit := new(RepositoryCommit) |
||||
resp, err := s.client.Do(ctx, req, commit) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return commit, resp, nil |
||||
} |
@ -0,0 +1,143 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// Pages represents a GitHub Pages site configuration.
|
||||
type Pages struct { |
||||
URL *string `json:"url,omitempty"` |
||||
Status *string `json:"status,omitempty"` |
||||
CNAME *string `json:"cname,omitempty"` |
||||
Custom404 *bool `json:"custom_404,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
} |
||||
|
||||
// PagesError represents a build error for a GitHub Pages site.
|
||||
type PagesError struct { |
||||
Message *string `json:"message,omitempty"` |
||||
} |
||||
|
||||
// PagesBuild represents the build information for a GitHub Pages site.
|
||||
type PagesBuild struct { |
||||
URL *string `json:"url,omitempty"` |
||||
Status *string `json:"status,omitempty"` |
||||
Error *PagesError `json:"error,omitempty"` |
||||
Pusher *User `json:"pusher,omitempty"` |
||||
Commit *string `json:"commit,omitempty"` |
||||
Duration *int `json:"duration,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
} |
||||
|
||||
// GetPagesInfo fetches information about a GitHub Pages site.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/pages/#get-information-about-a-pages-site
|
||||
func (s *RepositoriesService) GetPagesInfo(ctx context.Context, owner, repo string) (*Pages, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pages", 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", mediaTypePagesPreview) |
||||
|
||||
site := new(Pages) |
||||
resp, err := s.client.Do(ctx, req, site) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return site, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, owner, repo string, opt *ListOptions) ([]*PagesBuild, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var pages []*PagesBuild |
||||
resp, err := s.client.Do(ctx, req, &pages) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return pages, resp, nil |
||||
} |
||||
|
||||
// GetLatestPagesBuild fetches the latest build information for a GitHub pages site.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/pages/#list-latest-pages-build
|
||||
func (s *RepositoriesService) GetLatestPagesBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pages/builds/latest", owner, repo) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
build := new(PagesBuild) |
||||
resp, err := s.client.Do(ctx, req, build) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return build, resp, nil |
||||
} |
||||
|
||||
// GetPageBuild fetches the specific build information for a GitHub pages site.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/pages/#list-a-specific-pages-build
|
||||
func (s *RepositoriesService) GetPageBuild(ctx context.Context, owner, repo string, id int64) (*PagesBuild, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pages/builds/%v", owner, repo, id) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
build := new(PagesBuild) |
||||
resp, err := s.client.Do(ctx, req, build) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return build, resp, nil |
||||
} |
||||
|
||||
// RequestPageBuild requests a build of a GitHub Pages site without needing to push new commit.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/pages/#request-a-page-build
|
||||
func (s *RepositoriesService) RequestPageBuild(ctx context.Context, owner, repo string) (*PagesBuild, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/pages/builds", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypePagesPreview) |
||||
|
||||
build := new(PagesBuild) |
||||
resp, err := s.client.Do(ctx, req, build) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return build, resp, nil |
||||
} |
@ -0,0 +1,72 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
// ProjectListOptions specifies the optional parameters to the
|
||||
// OrganizationsService.ListProjects and RepositoriesService.ListProjects methods.
|
||||
type ProjectListOptions struct { |
||||
// Indicates the state of the projects to return. Can be either open, closed, or all. Default: open
|
||||
State string `url:"state,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListProjects lists the projects for a repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#list-repository-projects
|
||||
func (s *RepositoriesService) ListProjects(ctx context.Context, owner, repo string, opt *ProjectListOptions) ([]*Project, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) |
||||
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 headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var projects []*Project |
||||
resp, err := s.client.Do(ctx, req, &projects) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return projects, resp, nil |
||||
} |
||||
|
||||
// CreateProject creates a GitHub Project for the specified repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#create-a-repository-project
|
||||
func (s *RepositoriesService) CreateProject(ctx context.Context, owner, repo string, opt *ProjectOptions) (*Project, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/projects", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept headers when APIs fully launch.
|
||||
acceptHeaders := []string{mediaTypeProjectsPreview, mediaTypeGraphQLNodeIDPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
project := &Project{} |
||||
resp, err := s.client.Do(ctx, req, project) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return project, resp, nil |
||||
} |
@ -0,0 +1,353 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"errors" |
||||
"fmt" |
||||
"io" |
||||
"mime" |
||||
"net/http" |
||||
"os" |
||||
"path/filepath" |
||||
"strings" |
||||
) |
||||
|
||||
// RepositoryRelease represents a GitHub release in a repository.
|
||||
type RepositoryRelease struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
TagName *string `json:"tag_name,omitempty"` |
||||
TargetCommitish *string `json:"target_commitish,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Draft *bool `json:"draft,omitempty"` |
||||
Prerelease *bool `json:"prerelease,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
PublishedAt *Timestamp `json:"published_at,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
AssetsURL *string `json:"assets_url,omitempty"` |
||||
Assets []ReleaseAsset `json:"assets,omitempty"` |
||||
UploadURL *string `json:"upload_url,omitempty"` |
||||
ZipballURL *string `json:"zipball_url,omitempty"` |
||||
TarballURL *string `json:"tarball_url,omitempty"` |
||||
Author *User `json:"author,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (r RepositoryRelease) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// ReleaseAsset represents a GitHub release asset in a repository.
|
||||
type ReleaseAsset struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Label *string `json:"label,omitempty"` |
||||
State *string `json:"state,omitempty"` |
||||
ContentType *string `json:"content_type,omitempty"` |
||||
Size *int `json:"size,omitempty"` |
||||
DownloadCount *int `json:"download_count,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
BrowserDownloadURL *string `json:"browser_download_url,omitempty"` |
||||
Uploader *User `json:"uploader,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
func (r ReleaseAsset) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// ListReleases lists the releases for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository
|
||||
func (s *RepositoriesService) ListReleases(ctx context.Context, 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 { |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var releases []*RepositoryRelease |
||||
resp, err := s.client.Do(ctx, req, &releases) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return releases, resp, nil |
||||
} |
||||
|
||||
// GetRelease fetches a single release.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release
|
||||
func (s *RepositoriesService) GetRelease(ctx context.Context, owner, repo string, id int64) (*RepositoryRelease, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) |
||||
return s.getSingleRelease(ctx, u) |
||||
} |
||||
|
||||
// GetLatestRelease fetches the latest published release for the repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-the-latest-release
|
||||
func (s *RepositoriesService) GetLatestRelease(ctx context.Context, owner, repo string) (*RepositoryRelease, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/latest", owner, repo) |
||||
return s.getSingleRelease(ctx, u) |
||||
} |
||||
|
||||
// GetReleaseByTag fetches a release with the specified tag.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name
|
||||
func (s *RepositoriesService) GetReleaseByTag(ctx context.Context, owner, repo, tag string) (*RepositoryRelease, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/tags/%s", owner, repo, tag) |
||||
return s.getSingleRelease(ctx, u) |
||||
} |
||||
|
||||
func (s *RepositoriesService) getSingleRelease(ctx context.Context, url string) (*RepositoryRelease, *Response, error) { |
||||
req, err := s.client.NewRequest("GET", url, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
release := new(RepositoryRelease) |
||||
resp, err := s.client.Do(ctx, req, release) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return release, resp, nil |
||||
} |
||||
|
||||
// CreateRelease adds a new release for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#create-a-release
|
||||
func (s *RepositoriesService) CreateRelease(ctx context.Context, owner, repo string, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases", owner, repo) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, release) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
r := new(RepositoryRelease) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return r, resp, nil |
||||
} |
||||
|
||||
// EditRelease edits a repository release.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release
|
||||
func (s *RepositoriesService) EditRelease(ctx context.Context, owner, repo string, id int64, release *RepositoryRelease) (*RepositoryRelease, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("PATCH", u, release) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
r := new(RepositoryRelease) |
||||
resp, err := s.client.Do(ctx, req, r) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return r, resp, nil |
||||
} |
||||
|
||||
// DeleteRelease delete a single release from a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release
|
||||
func (s *RepositoriesService) DeleteRelease(ctx context.Context, owner, repo string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/%d", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// ListReleaseAssets lists the release's assets.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#list-assets-for-a-release
|
||||
func (s *RepositoriesService) ListReleaseAssets(ctx context.Context, owner, repo string, id int64, 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 { |
||||
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", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
var assets []*ReleaseAsset |
||||
resp, err := s.client.Do(ctx, req, &assets) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return assets, resp, nil |
||||
} |
||||
|
||||
// GetReleaseAsset fetches a single release asset.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset
|
||||
func (s *RepositoriesService) GetReleaseAsset(ctx context.Context, owner, repo string, id int64) (*ReleaseAsset, *Response, 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, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
asset := new(ReleaseAsset) |
||||
resp, err := s.client.Do(ctx, req, asset) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return asset, resp, nil |
||||
} |
||||
|
||||
// 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: https://developer.github.com/v3/repos/releases/#get-a-single-release-asset
|
||||
func (s *RepositoriesService) DownloadReleaseAsset(ctx context.Context, owner, repo string, id int64) (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 |
||||
} |
||||
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 }() |
||||
|
||||
req = withContext(ctx, req) |
||||
resp, err := s.client.client.Do(req) |
||||
if err != nil { |
||||
if !strings.Contains(err.Error(), "disable redirect") { |
||||
return nil, "", err |
||||
} |
||||
return nil, loc, nil // Intentionally return no error with valid redirect URL.
|
||||
} |
||||
|
||||
if err := CheckResponse(resp); err != nil { |
||||
resp.Body.Close() |
||||
return nil, "", err |
||||
} |
||||
|
||||
return resp.Body, "", nil |
||||
} |
||||
|
||||
// EditReleaseAsset edits a repository release asset.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#edit-a-release-asset
|
||||
func (s *RepositoriesService) EditReleaseAsset(ctx context.Context, owner, repo string, id int64, release *ReleaseAsset) (*ReleaseAsset, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("PATCH", u, release) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
asset := new(ReleaseAsset) |
||||
resp, err := s.client.Do(ctx, req, asset) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return asset, resp, nil |
||||
} |
||||
|
||||
// DeleteReleaseAsset delete a single release asset from a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#delete-a-release-asset
|
||||
func (s *RepositoriesService) DeleteReleaseAsset(ctx context.Context, owner, repo string, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/assets/%d", owner, repo, id) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// UploadReleaseAsset creates an asset by uploading a file into a release repository.
|
||||
// To upload assets that cannot be represented by an os.File, call NewUploadRequest directly.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/releases/#upload-a-release-asset
|
||||
func (s *RepositoriesService) UploadReleaseAsset(ctx context.Context, owner, repo string, id int64, opt *UploadOptions, file *os.File) (*ReleaseAsset, *Response, error) { |
||||
u := fmt.Sprintf("repos/%s/%s/releases/%d/assets", owner, repo, id) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
stat, err := file.Stat() |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
if stat.IsDir() { |
||||
return nil, nil, errors.New("the asset to upload can't be a directory") |
||||
} |
||||
|
||||
mediaType := mime.TypeByExtension(filepath.Ext(file.Name())) |
||||
req, err := s.client.NewUploadRequest(u, file, stat.Size(), mediaType) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeGraphQLNodeIDPreview) |
||||
|
||||
asset := new(ReleaseAsset) |
||||
resp, err := s.client.Do(ctx, req, asset) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return asset, resp, nil |
||||
} |
@ -0,0 +1,226 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// ContributorStats represents a contributor to a repository and their
|
||||
// weekly contributions to a given repo.
|
||||
type ContributorStats struct { |
||||
Author *Contributor `json:"author,omitempty"` |
||||
Total *int `json:"total,omitempty"` |
||||
Weeks []WeeklyStats `json:"weeks,omitempty"` |
||||
} |
||||
|
||||
func (c ContributorStats) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// WeeklyStats represents the number of additions, deletions and commits
|
||||
// a Contributor made in a given week.
|
||||
type WeeklyStats struct { |
||||
Week *Timestamp `json:"w,omitempty"` |
||||
Additions *int `json:"a,omitempty"` |
||||
Deletions *int `json:"d,omitempty"` |
||||
Commits *int `json:"c,omitempty"` |
||||
} |
||||
|
||||
func (w WeeklyStats) String() string { |
||||
return Stringify(w) |
||||
} |
||||
|
||||
// ListContributorsStats gets a repo's contributor list with additions,
|
||||
// deletions and commit counts.
|
||||
//
|
||||
// If this is the first time these statistics are requested for the given
|
||||
// repository, this method will return an *AcceptedError and a status code of
|
||||
// 202. This is because this is the status that GitHub returns to signify that
|
||||
// it is now computing the requested statistics. A follow up request, after a
|
||||
// delay of a second or so, should result in a successful request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statistics/#contributors
|
||||
func (s *RepositoriesService) ListContributorsStats(ctx context.Context, 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 |
||||
resp, err := s.client.Do(ctx, req, &contributorStats) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return contributorStats, resp, nil |
||||
} |
||||
|
||||
// WeeklyCommitActivity represents the weekly commit activity for a repository.
|
||||
// The days array is a group of commits per day, starting on Sunday.
|
||||
type WeeklyCommitActivity struct { |
||||
Days []int `json:"days,omitempty"` |
||||
Total *int `json:"total,omitempty"` |
||||
Week *Timestamp `json:"week,omitempty"` |
||||
} |
||||
|
||||
func (w WeeklyCommitActivity) String() string { |
||||
return Stringify(w) |
||||
} |
||||
|
||||
// ListCommitActivity returns the last year of commit activity
|
||||
// grouped by week. The days array is a group of commits per day,
|
||||
// starting on Sunday.
|
||||
//
|
||||
// If this is the first time these statistics are requested for the given
|
||||
// repository, this method will return an *AcceptedError and a status code of
|
||||
// 202. This is because this is the status that GitHub returns to signify that
|
||||
// it is now computing the requested statistics. A follow up request, after a
|
||||
// delay of a second or so, should result in a successful request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statistics/#commit-activity
|
||||
func (s *RepositoriesService) ListCommitActivity(ctx context.Context, 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 |
||||
resp, err := s.client.Do(ctx, req, &weeklyCommitActivity) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return weeklyCommitActivity, resp, nil |
||||
} |
||||
|
||||
// ListCodeFrequency returns a weekly aggregate of the number of additions and
|
||||
// deletions pushed to a repository. Returned WeeklyStats will contain
|
||||
// additions and deletions, but not total commits.
|
||||
//
|
||||
// If this is the first time these statistics are requested for the given
|
||||
// repository, this method will return an *AcceptedError and a status code of
|
||||
// 202. This is because this is the status that GitHub returns to signify that
|
||||
// it is now computing the requested statistics. A follow up request, after a
|
||||
// delay of a second or so, should result in a successful request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statistics/#code-frequency
|
||||
func (s *RepositoriesService) ListCodeFrequency(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var weeks [][]int |
||||
resp, err := s.client.Do(ctx, req, &weeks) |
||||
|
||||
// convert int slices into WeeklyStats
|
||||
var stats []*WeeklyStats |
||||
for _, week := range weeks { |
||||
if len(week) != 3 { |
||||
continue |
||||
} |
||||
stat := &WeeklyStats{ |
||||
Week: &Timestamp{time.Unix(int64(week[0]), 0)}, |
||||
Additions: Int(week[1]), |
||||
Deletions: Int(week[2]), |
||||
} |
||||
stats = append(stats, stat) |
||||
} |
||||
|
||||
return stats, resp, err |
||||
} |
||||
|
||||
// RepositoryParticipation is the number of commits by everyone
|
||||
// who has contributed to the repository (including the owner)
|
||||
// as well as the number of commits by the owner themself.
|
||||
type RepositoryParticipation struct { |
||||
All []int `json:"all,omitempty"` |
||||
Owner []int `json:"owner,omitempty"` |
||||
} |
||||
|
||||
func (r RepositoryParticipation) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// ListParticipation returns the total commit counts for the 'owner'
|
||||
// and total commit counts in 'all'. 'all' is everyone combined,
|
||||
// including the 'owner' in the last 52 weeks. If you’d like to get
|
||||
// the commit counts for non-owners, you can subtract 'all' from 'owner'.
|
||||
//
|
||||
// The array order is oldest week (index 0) to most recent week.
|
||||
//
|
||||
// If this is the first time these statistics are requested for the given
|
||||
// repository, this method will return an *AcceptedError and a status code of
|
||||
// 202. This is because this is the status that GitHub returns to signify that
|
||||
// it is now computing the requested statistics. A follow up request, after a
|
||||
// delay of a second or so, should result in a successful request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statistics/#participation
|
||||
func (s *RepositoriesService) ListParticipation(ctx context.Context, owner, repo string) (*RepositoryParticipation, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/stats/participation", owner, repo) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
participation := new(RepositoryParticipation) |
||||
resp, err := s.client.Do(ctx, req, participation) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return participation, resp, nil |
||||
} |
||||
|
||||
// PunchCard represents the number of commits made during a given hour of a
|
||||
// day of the week.
|
||||
type PunchCard struct { |
||||
Day *int // Day of the week (0-6: =Sunday - Saturday).
|
||||
Hour *int // Hour of day (0-23).
|
||||
Commits *int // Number of commits.
|
||||
} |
||||
|
||||
// ListPunchCard returns the number of commits per hour in each day.
|
||||
//
|
||||
// If this is the first time these statistics are requested for the given
|
||||
// repository, this method will return an *AcceptedError and a status code of
|
||||
// 202. This is because this is the status that GitHub returns to signify that
|
||||
// it is now computing the requested statistics. A follow up request, after a
|
||||
// delay of a second or so, should result in a successful request.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statistics/#punch-card
|
||||
func (s *RepositoriesService) ListPunchCard(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var results [][]int |
||||
resp, err := s.client.Do(ctx, req, &results) |
||||
|
||||
// convert int slices into Punchcards
|
||||
var cards []*PunchCard |
||||
for _, result := range results { |
||||
if len(result) != 3 { |
||||
continue |
||||
} |
||||
card := &PunchCard{ |
||||
Day: Int(result[0]), |
||||
Hour: Int(result[1]), |
||||
Commits: Int(result[2]), |
||||
} |
||||
cards = append(cards, card) |
||||
} |
||||
|
||||
return cards, resp, err |
||||
} |
@ -0,0 +1,129 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// RepoStatus represents the status of a repository at a particular reference.
|
||||
type RepoStatus struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
|
||||
// State is the current state of the repository. Possible values are:
|
||||
// pending, success, error, or failure.
|
||||
State *string `json:"state,omitempty"` |
||||
|
||||
// TargetURL is the URL of the page representing this status. It will be
|
||||
// linked from the GitHub UI to allow users to see the source of the status.
|
||||
TargetURL *string `json:"target_url,omitempty"` |
||||
|
||||
// Description is a short high level summary of the status.
|
||||
Description *string `json:"description,omitempty"` |
||||
|
||||
// A string label to differentiate this status from the statuses of other systems.
|
||||
Context *string `json:"context,omitempty"` |
||||
|
||||
Creator *User `json:"creator,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
} |
||||
|
||||
func (r RepoStatus) String() string { |
||||
return Stringify(r) |
||||
} |
||||
|
||||
// ListStatuses lists the statuses of a repository at the specified
|
||||
// reference. ref can be a SHA, a branch name, or a tag name.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref
|
||||
func (s *RepositoriesService) ListStatuses(ctx context.Context, 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 { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var statuses []*RepoStatus |
||||
resp, err := s.client.Do(ctx, req, &statuses) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return statuses, resp, nil |
||||
} |
||||
|
||||
// CreateStatus creates a new status for a repository at the specified
|
||||
// reference. Ref can be a SHA, a branch name, or a tag name.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statuses/#create-a-status
|
||||
func (s *RepositoriesService) CreateStatus(ctx context.Context, owner, repo, ref string, status *RepoStatus) (*RepoStatus, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/statuses/%v", owner, repo, ref) |
||||
req, err := s.client.NewRequest("POST", u, status) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
repoStatus := new(RepoStatus) |
||||
resp, err := s.client.Do(ctx, req, repoStatus) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return repoStatus, resp, nil |
||||
} |
||||
|
||||
// CombinedStatus represents the combined status of a repository at a particular reference.
|
||||
type CombinedStatus struct { |
||||
// State is the combined state of the repository. Possible values are:
|
||||
// failure, pending, or success.
|
||||
State *string `json:"state,omitempty"` |
||||
|
||||
Name *string `json:"name,omitempty"` |
||||
SHA *string `json:"sha,omitempty"` |
||||
TotalCount *int `json:"total_count,omitempty"` |
||||
Statuses []RepoStatus `json:"statuses,omitempty"` |
||||
|
||||
CommitURL *string `json:"commit_url,omitempty"` |
||||
RepositoryURL *string `json:"repository_url,omitempty"` |
||||
} |
||||
|
||||
func (s CombinedStatus) String() string { |
||||
return Stringify(s) |
||||
} |
||||
|
||||
// GetCombinedStatus returns the combined status of a repository at the specified
|
||||
// reference. ref can be a SHA, a branch name, or a tag name.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
|
||||
func (s *RepositoriesService) GetCombinedStatus(ctx context.Context, owner, repo, ref string, opt *ListOptions) (*CombinedStatus, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v/status", owner, repo, ref) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
status := new(CombinedStatus) |
||||
resp, err := s.client.Do(ctx, req, status) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return status, resp, nil |
||||
} |
@ -0,0 +1,141 @@
|
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// TrafficReferrer represent information about traffic from a referrer .
|
||||
type TrafficReferrer struct { |
||||
Referrer *string `json:"referrer,omitempty"` |
||||
Count *int `json:"count,omitempty"` |
||||
Uniques *int `json:"uniques,omitempty"` |
||||
} |
||||
|
||||
// TrafficPath represent information about the traffic on a path of the repo.
|
||||
type TrafficPath struct { |
||||
Path *string `json:"path,omitempty"` |
||||
Title *string `json:"title,omitempty"` |
||||
Count *int `json:"count,omitempty"` |
||||
Uniques *int `json:"uniques,omitempty"` |
||||
} |
||||
|
||||
// TrafficData represent information about a specific timestamp in views or clones list.
|
||||
type TrafficData struct { |
||||
Timestamp *Timestamp `json:"timestamp,omitempty"` |
||||
Count *int `json:"count,omitempty"` |
||||
Uniques *int `json:"uniques,omitempty"` |
||||
} |
||||
|
||||
// TrafficViews represent information about the number of views in the last 14 days.
|
||||
type TrafficViews struct { |
||||
Views []*TrafficData `json:"views,omitempty"` |
||||
Count *int `json:"count,omitempty"` |
||||
Uniques *int `json:"uniques,omitempty"` |
||||
} |
||||
|
||||
// TrafficClones represent information about the number of clones in the last 14 days.
|
||||
type TrafficClones struct { |
||||
Clones []*TrafficData `json:"clones,omitempty"` |
||||
Count *int `json:"count,omitempty"` |
||||
Uniques *int `json:"uniques,omitempty"` |
||||
} |
||||
|
||||
// TrafficBreakdownOptions specifies the parameters to methods that support breakdown per day or week.
|
||||
// Can be one of: day, week. Default: day.
|
||||
type TrafficBreakdownOptions struct { |
||||
Per string `url:"per,omitempty"` |
||||
} |
||||
|
||||
// ListTrafficReferrers list the top 10 referrers over the last 14 days.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-referrers
|
||||
func (s *RepositoriesService) ListTrafficReferrers(ctx context.Context, owner, repo string) ([]*TrafficReferrer, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/traffic/popular/referrers", owner, repo) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var trafficReferrers []*TrafficReferrer |
||||
resp, err := s.client.Do(ctx, req, &trafficReferrers) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return trafficReferrers, resp, nil |
||||
} |
||||
|
||||
// ListTrafficPaths list the top 10 popular content over the last 14 days.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/traffic/#list-paths
|
||||
func (s *RepositoriesService) ListTrafficPaths(ctx context.Context, owner, repo string) ([]*TrafficPath, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/traffic/popular/paths", owner, repo) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var paths []*TrafficPath |
||||
resp, err := s.client.Do(ctx, req, &paths) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return paths, resp, nil |
||||
} |
||||
|
||||
// ListTrafficViews get total number of views for the last 14 days and breaks it down either per day or week.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/traffic/#views
|
||||
func (s *RepositoriesService) ListTrafficViews(ctx context.Context, owner, repo string, opt *TrafficBreakdownOptions) (*TrafficViews, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/traffic/views", owner, repo) |
||||
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 |
||||
} |
||||
|
||||
trafficViews := new(TrafficViews) |
||||
resp, err := s.client.Do(ctx, req, &trafficViews) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return trafficViews, resp, nil |
||||
} |
||||
|
||||
// ListTrafficClones get total number of clones for the last 14 days and breaks it down either per day or week for the last 14 days.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/repos/traffic/#views
|
||||
func (s *RepositoriesService) ListTrafficClones(ctx context.Context, owner, repo string, opt *TrafficBreakdownOptions) (*TrafficClones, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/traffic/clones", owner, repo) |
||||
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 |
||||
} |
||||
|
||||
trafficClones := new(TrafficClones) |
||||
resp, err := s.client.Do(ctx, req, &trafficClones) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return trafficClones, resp, nil |
||||
} |
@ -0,0 +1,255 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"strconv" |
||||
|
||||
qs "github.com/google/go-querystring/query" |
||||
) |
||||
|
||||
// SearchService provides access to the search related functions
|
||||
// in the GitHub API.
|
||||
//
|
||||
// Each method takes a query string defining the search keywords and any search qualifiers.
|
||||
// For example, when searching issues, the query "gopher is:issue language:go" will search
|
||||
// for issues containing the word "gopher" in Go repositories. The method call
|
||||
// opts := &github.SearchOptions{Sort: "created", Order: "asc"}
|
||||
// cl.Search.Issues(ctx, "gopher is:issue language:go", opts)
|
||||
// will search for such issues, sorting by creation date in ascending order
|
||||
// (i.e., oldest first).
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/
|
||||
type SearchService service |
||||
|
||||
// SearchOptions specifies optional parameters to the SearchService methods.
|
||||
type SearchOptions struct { |
||||
// How to sort the search results. Possible values are:
|
||||
// - for repositories: stars, fork, updated
|
||||
// - for commits: author-date, committer-date
|
||||
// - for code: indexed
|
||||
// - for issues: comments, created, updated
|
||||
// - for users: followers, repositories, joined
|
||||
//
|
||||
// Default is to sort by best match.
|
||||
Sort string `url:"sort,omitempty"` |
||||
|
||||
// Sort order if sort parameter is provided. Possible values are: asc,
|
||||
// desc. Default is desc.
|
||||
Order string `url:"order,omitempty"` |
||||
|
||||
// Whether to retrieve text match metadata with a query
|
||||
TextMatch bool `url:"-"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// Common search parameters.
|
||||
type searchParameters struct { |
||||
Query string |
||||
RepositoryID *int64 // Sent if non-nil.
|
||||
} |
||||
|
||||
// RepositoriesSearchResult represents the result of a repositories search.
|
||||
type RepositoriesSearchResult struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
IncompleteResults *bool `json:"incomplete_results,omitempty"` |
||||
Repositories []Repository `json:"items,omitempty"` |
||||
} |
||||
|
||||
// Repositories searches repositories via various criteria.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#search-repositories
|
||||
func (s *SearchService) Repositories(ctx context.Context, query string, opt *SearchOptions) (*RepositoriesSearchResult, *Response, error) { |
||||
result := new(RepositoriesSearchResult) |
||||
resp, err := s.search(ctx, "repositories", &searchParameters{Query: query}, opt, result) |
||||
return result, resp, err |
||||
} |
||||
|
||||
// CommitsSearchResult represents the result of a commits search.
|
||||
type CommitsSearchResult struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
IncompleteResults *bool `json:"incomplete_results,omitempty"` |
||||
Commits []*CommitResult `json:"items,omitempty"` |
||||
} |
||||
|
||||
// CommitResult represents a commit object as returned in commit search endpoint response.
|
||||
type CommitResult struct { |
||||
SHA *string `json:"sha,omitempty"` |
||||
Commit *Commit `json:"commit,omitempty"` |
||||
Author *User `json:"author,omitempty"` |
||||
Committer *User `json:"committer,omitempty"` |
||||
Parents []*Commit `json:"parents,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
CommentsURL *string `json:"comments_url,omitempty"` |
||||
|
||||
Repository *Repository `json:"repository,omitempty"` |
||||
Score *float64 `json:"score,omitempty"` |
||||
} |
||||
|
||||
// Commits searches commits via various criteria.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#search-commits
|
||||
func (s *SearchService) Commits(ctx context.Context, query string, opt *SearchOptions) (*CommitsSearchResult, *Response, error) { |
||||
result := new(CommitsSearchResult) |
||||
resp, err := s.search(ctx, "commits", &searchParameters{Query: query}, opt, result) |
||||
return result, resp, err |
||||
} |
||||
|
||||
// IssuesSearchResult represents the result of an issues search.
|
||||
type IssuesSearchResult struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
IncompleteResults *bool `json:"incomplete_results,omitempty"` |
||||
Issues []Issue `json:"items,omitempty"` |
||||
} |
||||
|
||||
// Issues searches issues via various criteria.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#search-issues
|
||||
func (s *SearchService) Issues(ctx context.Context, query string, opt *SearchOptions) (*IssuesSearchResult, *Response, error) { |
||||
result := new(IssuesSearchResult) |
||||
resp, err := s.search(ctx, "issues", &searchParameters{Query: query}, opt, result) |
||||
return result, resp, err |
||||
} |
||||
|
||||
// UsersSearchResult represents the result of a users search.
|
||||
type UsersSearchResult struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
IncompleteResults *bool `json:"incomplete_results,omitempty"` |
||||
Users []User `json:"items,omitempty"` |
||||
} |
||||
|
||||
// Users searches users via various criteria.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#search-users
|
||||
func (s *SearchService) Users(ctx context.Context, query string, opt *SearchOptions) (*UsersSearchResult, *Response, error) { |
||||
result := new(UsersSearchResult) |
||||
resp, err := s.search(ctx, "users", &searchParameters{Query: query}, opt, result) |
||||
return result, resp, err |
||||
} |
||||
|
||||
// Match represents a single text match.
|
||||
type Match struct { |
||||
Text *string `json:"text,omitempty"` |
||||
Indices []int `json:"indices,omitempty"` |
||||
} |
||||
|
||||
// TextMatch represents a text match for a SearchResult
|
||||
type TextMatch struct { |
||||
ObjectURL *string `json:"object_url,omitempty"` |
||||
ObjectType *string `json:"object_type,omitempty"` |
||||
Property *string `json:"property,omitempty"` |
||||
Fragment *string `json:"fragment,omitempty"` |
||||
Matches []Match `json:"matches,omitempty"` |
||||
} |
||||
|
||||
func (tm TextMatch) String() string { |
||||
return Stringify(tm) |
||||
} |
||||
|
||||
// CodeSearchResult represents the result of a code search.
|
||||
type CodeSearchResult struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
IncompleteResults *bool `json:"incomplete_results,omitempty"` |
||||
CodeResults []CodeResult `json:"items,omitempty"` |
||||
} |
||||
|
||||
// CodeResult represents a single search result.
|
||||
type CodeResult struct { |
||||
Name *string `json:"name,omitempty"` |
||||
Path *string `json:"path,omitempty"` |
||||
SHA *string `json:"sha,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
Repository *Repository `json:"repository,omitempty"` |
||||
TextMatches []TextMatch `json:"text_matches,omitempty"` |
||||
} |
||||
|
||||
func (c CodeResult) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// Code searches code via various criteria.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#search-code
|
||||
func (s *SearchService) Code(ctx context.Context, query string, opt *SearchOptions) (*CodeSearchResult, *Response, error) { |
||||
result := new(CodeSearchResult) |
||||
resp, err := s.search(ctx, "code", &searchParameters{Query: query}, opt, result) |
||||
return result, resp, err |
||||
} |
||||
|
||||
// LabelsSearchResult represents the result of a code search.
|
||||
type LabelsSearchResult struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
IncompleteResults *bool `json:"incomplete_results,omitempty"` |
||||
Labels []*LabelResult `json:"items,omitempty"` |
||||
} |
||||
|
||||
// LabelResult represents a single search result.
|
||||
type LabelResult struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Color *string `json:"color,omitempty"` |
||||
Default *bool `json:"default,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Score *float64 `json:"score,omitempty"` |
||||
} |
||||
|
||||
func (l LabelResult) String() string { |
||||
return Stringify(l) |
||||
} |
||||
|
||||
// Labels searches labels in the repository with ID repoID via various criteria.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/search/#search-labels
|
||||
func (s *SearchService) Labels(ctx context.Context, repoID int64, query string, opt *SearchOptions) (*LabelsSearchResult, *Response, error) { |
||||
result := new(LabelsSearchResult) |
||||
resp, err := s.search(ctx, "labels", &searchParameters{RepositoryID: &repoID, Query: query}, opt, result) |
||||
return result, resp, err |
||||
} |
||||
|
||||
// Helper function that executes search queries against different
|
||||
// GitHub search types (repositories, commits, code, issues, users, labels)
|
||||
func (s *SearchService) search(ctx context.Context, searchType string, parameters *searchParameters, opt *SearchOptions, result interface{}) (*Response, error) { |
||||
params, err := qs.Values(opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
params.Set("q", parameters.Query) |
||||
if parameters.RepositoryID != nil { |
||||
params.Set("repository_id", strconv.FormatInt(*parameters.RepositoryID, 10)) |
||||
} |
||||
u := fmt.Sprintf("search/%s?%s", searchType, params.Encode()) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
switch { |
||||
case searchType == "commits": |
||||
// Accept header for search commits preview endpoint
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeCommitSearchPreview) |
||||
case searchType == "repositories": |
||||
// Accept header for search repositories based on topics preview endpoint
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTopicsPreview) |
||||
case searchType == "labels": |
||||
// Accept header for search labels based on label description preview endpoint.
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
case 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") |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, result) |
||||
} |
@ -0,0 +1,93 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"io" |
||||
|
||||
"reflect" |
||||
) |
||||
|
||||
var timestampType = reflect.TypeOf(Timestamp{}) |
||||
|
||||
// Stringify attempts to create a reasonable string representation of types in
|
||||
// the GitHub library. It does things like resolve pointers to their values
|
||||
// and omits struct fields with nil values.
|
||||
func Stringify(message interface{}) string { |
||||
var buf bytes.Buffer |
||||
v := reflect.ValueOf(message) |
||||
stringifyValue(&buf, v) |
||||
return buf.String() |
||||
} |
||||
|
||||
// stringifyValue was heavily inspired by the goprotobuf library.
|
||||
|
||||
func stringifyValue(w io.Writer, val reflect.Value) { |
||||
if val.Kind() == reflect.Ptr && val.IsNil() { |
||||
w.Write([]byte("<nil>")) |
||||
return |
||||
} |
||||
|
||||
v := reflect.Indirect(val) |
||||
|
||||
switch v.Kind() { |
||||
case reflect.String: |
||||
fmt.Fprintf(w, `"%s"`, v) |
||||
case reflect.Slice: |
||||
w.Write([]byte{'['}) |
||||
for i := 0; i < v.Len(); i++ { |
||||
if i > 0 { |
||||
w.Write([]byte{' '}) |
||||
} |
||||
|
||||
stringifyValue(w, v.Index(i)) |
||||
} |
||||
|
||||
w.Write([]byte{']'}) |
||||
return |
||||
case reflect.Struct: |
||||
if v.Type().Name() != "" { |
||||
w.Write([]byte(v.Type().String())) |
||||
} |
||||
|
||||
// special handling of Timestamp values
|
||||
if v.Type() == timestampType { |
||||
fmt.Fprintf(w, "{%s}", v.Interface()) |
||||
return |
||||
} |
||||
|
||||
w.Write([]byte{'{'}) |
||||
|
||||
var sep bool |
||||
for i := 0; i < v.NumField(); i++ { |
||||
fv := v.Field(i) |
||||
if fv.Kind() == reflect.Ptr && fv.IsNil() { |
||||
continue |
||||
} |
||||
if fv.Kind() == reflect.Slice && fv.IsNil() { |
||||
continue |
||||
} |
||||
|
||||
if sep { |
||||
w.Write([]byte(", ")) |
||||
} else { |
||||
sep = true |
||||
} |
||||
|
||||
w.Write([]byte(v.Type().Field(i).Name)) |
||||
w.Write([]byte{':'}) |
||||
stringifyValue(w, fv) |
||||
} |
||||
|
||||
w.Write([]byte{'}'}) |
||||
default: |
||||
if v.CanInterface() { |
||||
fmt.Fprint(w, v.Interface()) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,7 @@
|
||||
package github |
||||
|
||||
// TeamsService provides access to the team-related functions
|
||||
// in the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/
|
||||
type TeamsService service |
@ -0,0 +1,154 @@
|
||||
// Copyright 2018 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// DiscussionComment represents a GitHub dicussion in a team.
|
||||
type DiscussionComment struct { |
||||
Author *User `json:"author,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
BodyHTML *string `json:"body_html,omitempty"` |
||||
BodyVersion *string `json:"body_version,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
LastEditedAt *Timestamp `json:"last_edited_at,omitempty"` |
||||
DiscussionURL *string `json:"discussion_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
Number *int64 `json:"number,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
} |
||||
|
||||
func (c DiscussionComment) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// DiscussionCommentListOptions specifies optional parameters to the
|
||||
// TeamServices.ListComments method.
|
||||
type DiscussionCommentListOptions struct { |
||||
// Sorts the discussion comments by the date they were created.
|
||||
// Accepted values are asc and desc. Default is desc.
|
||||
Direction string `url:"direction,omitempty"` |
||||
} |
||||
|
||||
// ListComments lists all comments on a team discussion.
|
||||
// Authenticated user must grant read:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#list-comments
|
||||
func (s *TeamsService) ListComments(ctx context.Context, teamID int64, discussionNumber int, options *DiscussionCommentListOptions) ([]*DiscussionComment, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discussionNumber) |
||||
u, err := addOptions(u, options) |
||||
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", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
var comments []*DiscussionComment |
||||
resp, err := s.client.Do(ctx, req, &comments) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return comments, resp, nil |
||||
} |
||||
|
||||
// GetComment gets a specific comment on a team discussion.
|
||||
// Authenticated user must grant read:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#get-a-single-comment
|
||||
func (s *TeamsService) GetComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*DiscussionComment, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) |
||||
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", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
discussionComment := &DiscussionComment{} |
||||
resp, err := s.client.Do(ctx, req, discussionComment) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return discussionComment, resp, nil |
||||
} |
||||
|
||||
// CreateComment creates a new discussion post on a team discussion.
|
||||
// Authenticated user must grant write:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#create-a-comment
|
||||
func (s *TeamsService) CreateComment(ctx context.Context, teamID int64, discsusionNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/comments", teamID, discsusionNumber) |
||||
req, err := s.client.NewRequest("POST", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
discussionComment := &DiscussionComment{} |
||||
resp, err := s.client.Do(ctx, req, discussionComment) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return discussionComment, resp, nil |
||||
} |
||||
|
||||
// EditComment edits the body text of a discussion comment.
|
||||
// Authenticated user must grant write:discussion scope.
|
||||
// User is allowed to edit body of a comment only.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#edit-a-comment
|
||||
func (s *TeamsService) EditComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int, comment DiscussionComment) (*DiscussionComment, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) |
||||
req, err := s.client.NewRequest("PATCH", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
discussionComment := &DiscussionComment{} |
||||
resp, err := s.client.Do(ctx, req, discussionComment) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return discussionComment, resp, nil |
||||
} |
||||
|
||||
// DeleteComment deletes a comment on a team discussion.
|
||||
// Authenticated user must grant write:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussion_comments/#delete-a-comment
|
||||
func (s *TeamsService) DeleteComment(ctx context.Context, teamID int64, discussionNumber, commentNumber int) (*Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v", teamID, discussionNumber, commentNumber) |
||||
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", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,159 @@
|
||||
// Copyright 2018 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// TeamDiscussion represents a GitHub dicussion in a team.
|
||||
type TeamDiscussion struct { |
||||
Author *User `json:"author,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
BodyHTML *string `json:"body_html,omitempty"` |
||||
BodyVersion *string `json:"body_version,omitempty"` |
||||
CommentsCount *int64 `json:"comments_count,omitempty"` |
||||
CommentsURL *string `json:"comments_url,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
LastEditedAt *Timestamp `json:"last_edited_at,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
Number *int64 `json:"number,omitempty"` |
||||
Pinned *bool `json:"pinned,omitempty"` |
||||
Private *bool `json:"private,omitempty"` |
||||
TeamURL *string `json:"team_url,omitempty"` |
||||
Title *string `json:"title,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
} |
||||
|
||||
func (d TeamDiscussion) String() string { |
||||
return Stringify(d) |
||||
} |
||||
|
||||
// DiscussionListOptions specifies optional parameters to the
|
||||
// TeamServices.ListDiscussions method.
|
||||
type DiscussionListOptions struct { |
||||
// Sorts the discussion by the date they were created.
|
||||
// Accepted values are asc and desc. Default is desc.
|
||||
Direction string `url:"direction,omitempty"` |
||||
} |
||||
|
||||
// ListDiscussions lists all discussions on team's page.
|
||||
// Authenticated user must grant read:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussions/#list-discussions
|
||||
func (s *TeamsService) ListDiscussions(ctx context.Context, teamID int64, options *DiscussionListOptions) ([]*TeamDiscussion, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions", teamID) |
||||
u, err := addOptions(u, options) |
||||
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", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
var teamDiscussions []*TeamDiscussion |
||||
resp, err := s.client.Do(ctx, req, &teamDiscussions) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return teamDiscussions, resp, nil |
||||
} |
||||
|
||||
// GetDiscussion gets a specific discussion on a team's page.
|
||||
// Authenticated user must grant read:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussions/#get-a-single-discussion
|
||||
func (s *TeamsService) GetDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*TeamDiscussion, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) |
||||
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", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
teamDiscussion := &TeamDiscussion{} |
||||
resp, err := s.client.Do(ctx, req, teamDiscussion) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return teamDiscussion, resp, nil |
||||
} |
||||
|
||||
// CreateDiscussion creates a new discussion post on a team's page.
|
||||
// Authenticated user must grant write:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussions/#create-a-discussion
|
||||
func (s *TeamsService) CreateDiscussion(ctx context.Context, teamID int64, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions", teamID) |
||||
req, err := s.client.NewRequest("POST", u, discussion) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
teamDiscussion := &TeamDiscussion{} |
||||
resp, err := s.client.Do(ctx, req, teamDiscussion) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return teamDiscussion, resp, nil |
||||
} |
||||
|
||||
// EditDiscussion edits the title and body text of a discussion post.
|
||||
// Authenticated user must grant write:discussion scope.
|
||||
// User is allowed to change Title and Body of a discussion only.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussions/#edit-a-discussion
|
||||
func (s *TeamsService) EditDiscussion(ctx context.Context, teamID int64, discussionNumber int, discussion TeamDiscussion) (*TeamDiscussion, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) |
||||
req, err := s.client.NewRequest("PATCH", u, discussion) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
teamDiscussion := &TeamDiscussion{} |
||||
resp, err := s.client.Do(ctx, req, teamDiscussion) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return teamDiscussion, resp, nil |
||||
} |
||||
|
||||
// DeleteDiscussion deletes a discussion from team's page.
|
||||
// Authenticated user must grant write:discussion scope.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/teams/discussions/#delete-a-discussion
|
||||
func (s *TeamsService) DeleteDiscussion(ctx context.Context, teamID int64, discussionNumber int) (*Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v", teamID, discussionNumber) |
||||
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", mediaTypeTeamDiscussionsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,41 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"strconv" |
||||
"time" |
||||
) |
||||
|
||||
// Timestamp represents a time that can be unmarshalled from a JSON string
|
||||
// formatted as either an RFC3339 or Unix timestamp. This is necessary for some
|
||||
// fields since the GitHub API is inconsistent in how it represents times. All
|
||||
// exported methods of time.Time can be called on Timestamp.
|
||||
type Timestamp struct { |
||||
time.Time |
||||
} |
||||
|
||||
func (t Timestamp) String() string { |
||||
return t.Time.String() |
||||
} |
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
// Time is expected in RFC3339 or Unix format.
|
||||
func (t *Timestamp) UnmarshalJSON(data []byte) (err error) { |
||||
str := string(data) |
||||
i, err := strconv.ParseInt(str, 10, 64) |
||||
if err == nil { |
||||
(*t).Time = time.Unix(i, 0) |
||||
} else { |
||||
(*t).Time, err = time.Parse(`"`+time.RFC3339+`"`, str) |
||||
} |
||||
return |
||||
} |
||||
|
||||
// Equal reports whether t and u are equal based on time.Equal
|
||||
func (t Timestamp) Equal(u Timestamp) bool { |
||||
return t.Time.Equal(u.Time) |
||||
} |
@ -0,0 +1,233 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// UsersService handles communication with the user related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/
|
||||
type UsersService service |
||||
|
||||
// User represents a GitHub user.
|
||||
type User struct { |
||||
Login *string `json:"login,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
AvatarURL *string `json:"avatar_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
GravatarID *string `json:"gravatar_id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Company *string `json:"company,omitempty"` |
||||
Blog *string `json:"blog,omitempty"` |
||||
Location *string `json:"location,omitempty"` |
||||
Email *string `json:"email,omitempty"` |
||||
Hireable *bool `json:"hireable,omitempty"` |
||||
Bio *string `json:"bio,omitempty"` |
||||
PublicRepos *int `json:"public_repos,omitempty"` |
||||
PublicGists *int `json:"public_gists,omitempty"` |
||||
Followers *int `json:"followers,omitempty"` |
||||
Following *int `json:"following,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
SuspendedAt *Timestamp `json:"suspended_at,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
SiteAdmin *bool `json:"site_admin,omitempty"` |
||||
TotalPrivateRepos *int `json:"total_private_repos,omitempty"` |
||||
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"` |
||||
PrivateGists *int `json:"private_gists,omitempty"` |
||||
DiskUsage *int `json:"disk_usage,omitempty"` |
||||
Collaborators *int `json:"collaborators,omitempty"` |
||||
Plan *Plan `json:"plan,omitempty"` |
||||
|
||||
// API URLs
|
||||
URL *string `json:"url,omitempty"` |
||||
EventsURL *string `json:"events_url,omitempty"` |
||||
FollowingURL *string `json:"following_url,omitempty"` |
||||
FollowersURL *string `json:"followers_url,omitempty"` |
||||
GistsURL *string `json:"gists_url,omitempty"` |
||||
OrganizationsURL *string `json:"organizations_url,omitempty"` |
||||
ReceivedEventsURL *string `json:"received_events_url,omitempty"` |
||||
ReposURL *string `json:"repos_url,omitempty"` |
||||
StarredURL *string `json:"starred_url,omitempty"` |
||||
SubscriptionsURL *string `json:"subscriptions_url,omitempty"` |
||||
|
||||
// TextMatches is only populated from search results that request text matches
|
||||
// See: search.go and https://developer.github.com/v3/search/#text-match-metadata
|
||||
TextMatches []TextMatch `json:"text_matches,omitempty"` |
||||
|
||||
// Permissions identifies the permissions that a user has on a given
|
||||
// repository. This is only populated when calling Repositories.ListCollaborators.
|
||||
Permissions *map[string]bool `json:"permissions,omitempty"` |
||||
} |
||||
|
||||
func (u User) String() string { |
||||
return Stringify(u) |
||||
} |
||||
|
||||
// Get fetches a user. Passing the empty string will fetch the authenticated
|
||||
// user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/#get-a-single-user
|
||||
func (s *UsersService) Get(ctx context.Context, user string) (*User, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v", user) |
||||
} else { |
||||
u = "user" |
||||
} |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
uResp := new(User) |
||||
resp, err := s.client.Do(ctx, req, uResp) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return uResp, resp, nil |
||||
} |
||||
|
||||
// GetByID fetches a user.
|
||||
//
|
||||
// Note: GetByID uses the undocumented GitHub API endpoint /user/:id.
|
||||
func (s *UsersService) GetByID(ctx context.Context, id int64) (*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(ctx, req, user) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return user, resp, nil |
||||
} |
||||
|
||||
// Edit the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/#update-the-authenticated-user
|
||||
func (s *UsersService) Edit(ctx context.Context, user *User) (*User, *Response, error) { |
||||
u := "user" |
||||
req, err := s.client.NewRequest("PATCH", u, user) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
uResp := new(User) |
||||
resp, err := s.client.Do(ctx, req, uResp) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return uResp, resp, nil |
||||
} |
||||
|
||||
// UserListOptions specifies optional parameters to the UsersService.ListAll
|
||||
// method.
|
||||
type UserListOptions struct { |
||||
// ID of the last user seen
|
||||
Since int64 `url:"since,omitempty"` |
||||
|
||||
// Note: Pagination is powered exclusively by the Since parameter,
|
||||
// ListOptions.Page has no effect.
|
||||
// ListOptions.PerPage controls an undocumented GitHub API parameter.
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListAll lists all GitHub users.
|
||||
//
|
||||
// To paginate through all users, populate 'Since' with the ID of the last user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/#get-all-users
|
||||
func (s *UsersService) ListAll(ctx context.Context, opt *UserListOptions) ([]*User, *Response, error) { |
||||
u, err := addOptions("users", opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var users []*User |
||||
resp, err := s.client.Do(ctx, req, &users) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return users, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, opt *ListOptions) ([]*RepositoryInvitation, *Response, error) { |
||||
u, err := addOptions("user/repository_invitations", 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(ctx, req, &invites) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return invites, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, invitationID int64) (*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(ctx, 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(ctx context.Context, invitationID int64) (*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(ctx, req, nil) |
||||
} |
@ -0,0 +1,67 @@
|
||||
// Copyright 2014 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// PromoteSiteAdmin promotes a user to a site administrator of a GitHub Enterprise instance.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/administration/#promote-an-ordinary-user-to-a-site-administrator
|
||||
func (s *UsersService) PromoteSiteAdmin(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("users/%v/site_admin", user) |
||||
|
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// DemoteSiteAdmin demotes a user from site administrator of a GitHub Enterprise instance.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/administration/#demote-a-site-administrator-to-an-ordinary-user
|
||||
func (s *UsersService) DemoteSiteAdmin(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("users/%v/site_admin", user) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// Suspend a user on a GitHub Enterprise instance.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/administration/#suspend-a-user
|
||||
func (s *UsersService) Suspend(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("users/%v/suspended", user) |
||||
|
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// Unsuspend a user on a GitHub Enterprise instance.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/administration/#unsuspend-a-user
|
||||
func (s *UsersService) Unsuspend(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("users/%v/suspended", user) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,91 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListBlockedUsers lists all the blocked users by the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/blocking/#list-blocked-users
|
||||
func (s *UsersService) ListBlockedUsers(ctx context.Context, opt *ListOptions) ([]*User, *Response, error) { |
||||
u := "user/blocks" |
||||
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", mediaTypeBlockUsersPreview) |
||||
|
||||
var blockedUsers []*User |
||||
resp, err := s.client.Do(ctx, req, &blockedUsers) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return blockedUsers, resp, nil |
||||
} |
||||
|
||||
// IsBlocked reports whether specified user is blocked by the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/blocking/#check-whether-youve-blocked-a-user
|
||||
func (s *UsersService) IsBlocked(ctx context.Context, user string) (bool, *Response, error) { |
||||
u := fmt.Sprintf("user/blocks/%v", user) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeBlockUsersPreview) |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
isBlocked, err := parseBoolResponse(err) |
||||
return isBlocked, resp, err |
||||
} |
||||
|
||||
// BlockUser blocks specified user for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/blocking/#block-a-user
|
||||
func (s *UsersService) BlockUser(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("user/blocks/%v", user) |
||||
|
||||
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", mediaTypeBlockUsersPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// UnblockUser unblocks specified user for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/blocking/#unblock-a-user
|
||||
func (s *UsersService) UnblockUser(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("user/blocks/%v", user) |
||||
|
||||
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", mediaTypeBlockUsersPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,71 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import "context" |
||||
|
||||
// UserEmail represents user's email address
|
||||
type UserEmail struct { |
||||
Email *string `json:"email,omitempty"` |
||||
Primary *bool `json:"primary,omitempty"` |
||||
Verified *bool `json:"verified,omitempty"` |
||||
} |
||||
|
||||
// ListEmails lists all email addresses for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user
|
||||
func (s *UsersService) ListEmails(ctx context.Context, opt *ListOptions) ([]*UserEmail, *Response, error) { |
||||
u := "user/emails" |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var emails []*UserEmail |
||||
resp, err := s.client.Do(ctx, req, &emails) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return emails, resp, nil |
||||
} |
||||
|
||||
// AddEmails adds email addresses of the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/emails/#add-email-addresses
|
||||
func (s *UsersService) AddEmails(ctx context.Context, emails []string) ([]*UserEmail, *Response, error) { |
||||
u := "user/emails" |
||||
req, err := s.client.NewRequest("POST", u, emails) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var e []*UserEmail |
||||
resp, err := s.client.Do(ctx, req, &e) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return e, resp, nil |
||||
} |
||||
|
||||
// DeleteEmails deletes email addresses from authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/emails/#delete-email-addresses
|
||||
func (s *UsersService) DeleteEmails(ctx context.Context, emails []string) (*Response, error) { |
||||
u := "user/emails" |
||||
req, err := s.client.NewRequest("DELETE", u, emails) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,119 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// ListFollowers lists the followers for a user. Passing the empty string will
|
||||
// fetch followers for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/followers/#list-followers-of-a-user
|
||||
func (s *UsersService) ListFollowers(ctx context.Context, user string, opt *ListOptions) ([]*User, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/followers", user) |
||||
} else { |
||||
u = "user/followers" |
||||
} |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var users []*User |
||||
resp, err := s.client.Do(ctx, req, &users) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return users, resp, nil |
||||
} |
||||
|
||||
// ListFollowing lists the people that a user is following. Passing the empty
|
||||
// string will list people the authenticated user is following.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/followers/#list-users-followed-by-another-user
|
||||
func (s *UsersService) ListFollowing(ctx context.Context, user string, opt *ListOptions) ([]*User, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/following", user) |
||||
} else { |
||||
u = "user/following" |
||||
} |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var users []*User |
||||
resp, err := s.client.Do(ctx, req, &users) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return users, resp, nil |
||||
} |
||||
|
||||
// IsFollowing checks if "user" is following "target". Passing the empty
|
||||
// string for "user" will check if the authenticated user is following "target".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user
|
||||
func (s *UsersService) IsFollowing(ctx context.Context, user, target string) (bool, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/following/%v", user, target) |
||||
} else { |
||||
u = fmt.Sprintf("user/following/%v", target) |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return false, nil, err |
||||
} |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
following, err := parseBoolResponse(err) |
||||
return following, resp, err |
||||
} |
||||
|
||||
// Follow will cause the authenticated user to follow the specified user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/followers/#follow-a-user
|
||||
func (s *UsersService) Follow(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("user/following/%v", user) |
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// Unfollow will cause the authenticated user to unfollow the specified user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/followers/#unfollow-a-user
|
||||
func (s *UsersService) Unfollow(ctx context.Context, user string) (*Response, error) { |
||||
u := fmt.Sprintf("user/following/%v", user) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,140 @@
|
||||
// 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 ( |
||||
"context" |
||||
"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 *int64 `json:"id,omitempty"` |
||||
PrimaryKeyID *int64 `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 public GPG keys for a user. Passing the empty
|
||||
// string will fetch keys for the authenticated user. 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-gpg-keys-for-a-user
|
||||
func (s *UsersService) ListGPGKeys(ctx context.Context, user string, opt *ListOptions) ([]*GPGKey, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/gpg_keys", user) |
||||
} else { |
||||
u = "user/gpg_keys" |
||||
} |
||||
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", mediaTypeGitSigningPreview) |
||||
|
||||
var keys []*GPGKey |
||||
resp, err := s.client.Do(ctx, req, &keys) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return keys, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, id int64) (*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(ctx, req, key) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return key, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, 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(ctx, req, key) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return key, resp, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, id int64) (*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(ctx, req, nil) |
||||
} |
@ -0,0 +1,108 @@
|
||||
// Copyright 2013 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// Key represents a public SSH key used to authenticate a user or deploy script.
|
||||
type Key struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
Key *string `json:"key,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
Title *string `json:"title,omitempty"` |
||||
ReadOnly *bool `json:"read_only,omitempty"` |
||||
} |
||||
|
||||
func (k Key) String() string { |
||||
return Stringify(k) |
||||
} |
||||
|
||||
// ListKeys lists the verified public keys for a user. Passing the empty
|
||||
// string will fetch keys for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/keys/#list-public-keys-for-a-user
|
||||
func (s *UsersService) ListKeys(ctx context.Context, user string, opt *ListOptions) ([]*Key, *Response, error) { |
||||
var u string |
||||
if user != "" { |
||||
u = fmt.Sprintf("users/%v/keys", user) |
||||
} else { |
||||
u = "user/keys" |
||||
} |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var keys []*Key |
||||
resp, err := s.client.Do(ctx, req, &keys) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return keys, resp, nil |
||||
} |
||||
|
||||
// GetKey fetches a single public key.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/keys/#get-a-single-public-key
|
||||
func (s *UsersService) GetKey(ctx context.Context, id int64) (*Key, *Response, error) { |
||||
u := fmt.Sprintf("user/keys/%v", id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
key := new(Key) |
||||
resp, err := s.client.Do(ctx, req, key) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return key, resp, nil |
||||
} |
||||
|
||||
// CreateKey adds a public key for the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/keys/#create-a-public-key
|
||||
func (s *UsersService) CreateKey(ctx context.Context, key *Key) (*Key, *Response, error) { |
||||
u := "user/keys" |
||||
|
||||
req, err := s.client.NewRequest("POST", u, key) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
k := new(Key) |
||||
resp, err := s.client.Do(ctx, req, k) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return k, resp, nil |
||||
} |
||||
|
||||
// DeleteKey deletes a public key.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/users/keys/#delete-a-public-key
|
||||
func (s *UsersService) DeleteKey(ctx context.Context, id int64) (*Response, error) { |
||||
u := fmt.Sprintf("user/keys/%v", id) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,20 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
// This file provides glue for making github work on App Engine.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"net/http" |
||||
) |
||||
|
||||
func withContext(ctx context.Context, req *http.Request) *http.Request { |
||||
// No-op because App Engine adds context to a request differently.
|
||||
return req |
||||
} |
@ -0,0 +1,19 @@
|
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
|
||||
// This file provides glue for making github work without App Engine.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"net/http" |
||||
) |
||||
|
||||
func withContext(ctx context.Context, req *http.Request) *http.Request { |
||||
return req.WithContext(ctx) |
||||
} |
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2013 Google. All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above |
||||
copyright notice, this list of conditions and the following disclaimer |
||||
in the documentation and/or other materials provided with the |
||||
distribution. |
||||
* Neither the name of Google Inc. nor the names of its |
||||
contributors may be used to endorse or promote products derived from |
||||
this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,320 @@
|
||||
// Copyright 2013 The Go 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 query implements encoding of structs into URL query parameters.
|
||||
//
|
||||
// As a simple example:
|
||||
//
|
||||
// type Options struct {
|
||||
// Query string `url:"q"`
|
||||
// ShowAll bool `url:"all"`
|
||||
// Page int `url:"page"`
|
||||
// }
|
||||
//
|
||||
// opt := Options{ "foo", true, 2 }
|
||||
// v, _ := query.Values(opt)
|
||||
// fmt.Print(v.Encode()) // will output: "q=foo&all=true&page=2"
|
||||
//
|
||||
// The exact mapping between Go values and url.Values is described in the
|
||||
// documentation for the Values() function.
|
||||
package query |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"net/url" |
||||
"reflect" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
var timeType = reflect.TypeOf(time.Time{}) |
||||
|
||||
var encoderType = reflect.TypeOf(new(Encoder)).Elem() |
||||
|
||||
// Encoder is an interface implemented by any type that wishes to encode
|
||||
// itself into URL values in a non-standard way.
|
||||
type Encoder interface { |
||||
EncodeValues(key string, v *url.Values) error |
||||
} |
||||
|
||||
// Values returns the url.Values encoding of v.
|
||||
//
|
||||
// Values expects to be passed a struct, and traverses it recursively using the
|
||||
// following encoding rules.
|
||||
//
|
||||
// Each exported struct field is encoded as a URL parameter unless
|
||||
//
|
||||
// - the field's tag is "-", or
|
||||
// - the field is empty and its tag specifies the "omitempty" option
|
||||
//
|
||||
// The empty values are false, 0, any nil pointer or interface value, any array
|
||||
// slice, map, or string of length zero, and any time.Time that returns true
|
||||
// for IsZero().
|
||||
//
|
||||
// The URL parameter name defaults to the struct field name but can be
|
||||
// specified in the struct field's tag value. The "url" key in the struct
|
||||
// field's tag value is the key name, followed by an optional comma and
|
||||
// options. For example:
|
||||
//
|
||||
// // Field is ignored by this package.
|
||||
// Field int `url:"-"`
|
||||
//
|
||||
// // Field appears as URL parameter "myName".
|
||||
// Field int `url:"myName"`
|
||||
//
|
||||
// // Field appears as URL parameter "myName" and the field is omitted if
|
||||
// // its value is empty
|
||||
// Field int `url:"myName,omitempty"`
|
||||
//
|
||||
// // Field appears as URL parameter "Field" (the default), but the field
|
||||
// // is skipped if empty. Note the leading comma.
|
||||
// Field int `url:",omitempty"`
|
||||
//
|
||||
// For encoding individual field values, the following type-dependent rules
|
||||
// apply:
|
||||
//
|
||||
// Boolean values default to encoding as the strings "true" or "false".
|
||||
// Including the "int" option signals that the field should be encoded as the
|
||||
// strings "1" or "0".
|
||||
//
|
||||
// time.Time values default to encoding as RFC3339 timestamps. Including the
|
||||
// "unix" option signals that the field should be encoded as a Unix time (see
|
||||
// time.Unix())
|
||||
//
|
||||
// Slice and Array values default to encoding as multiple URL values of the
|
||||
// same name. Including the "comma" option signals that the field should be
|
||||
// encoded as a single comma-delimited value. Including the "space" option
|
||||
// similarly encodes the value as a single space-delimited string. Including
|
||||
// the "semicolon" option will encode the value as a semicolon-delimited string.
|
||||
// Including the "brackets" option signals that the multiple URL values should
|
||||
// have "[]" appended to the value name. "numbered" will append a number to
|
||||
// the end of each incidence of the value name, example:
|
||||
// name0=value0&name1=value1, etc.
|
||||
//
|
||||
// Anonymous struct fields are usually encoded as if their inner exported
|
||||
// fields were fields in the outer struct, subject to the standard Go
|
||||
// visibility rules. An anonymous struct field with a name given in its URL
|
||||
// tag is treated as having that name, rather than being anonymous.
|
||||
//
|
||||
// Non-nil pointer values are encoded as the value pointed to.
|
||||
//
|
||||
// Nested structs are encoded including parent fields in value names for
|
||||
// scoping. e.g:
|
||||
//
|
||||
// "user[name]=acme&user[addr][postcode]=1234&user[addr][city]=SFO"
|
||||
//
|
||||
// All other values are encoded using their default string representation.
|
||||
//
|
||||
// Multiple fields that encode to the same URL parameter name will be included
|
||||
// as multiple URL values of the same name.
|
||||
func Values(v interface{}) (url.Values, error) { |
||||
values := make(url.Values) |
||||
val := reflect.ValueOf(v) |
||||
for val.Kind() == reflect.Ptr { |
||||
if val.IsNil() { |
||||
return values, nil |
||||
} |
||||
val = val.Elem() |
||||
} |
||||
|
||||
if v == nil { |
||||
return values, nil |
||||
} |
||||
|
||||
if val.Kind() != reflect.Struct { |
||||
return nil, fmt.Errorf("query: Values() expects struct input. Got %v", val.Kind()) |
||||
} |
||||
|
||||
err := reflectValue(values, val, "") |
||||
return values, err |
||||
} |
||||
|
||||
// reflectValue populates the values parameter from the struct fields in val.
|
||||
// Embedded structs are followed recursively (using the rules defined in the
|
||||
// Values function documentation) breadth-first.
|
||||
func reflectValue(values url.Values, val reflect.Value, scope string) error { |
||||
var embedded []reflect.Value |
||||
|
||||
typ := val.Type() |
||||
for i := 0; i < typ.NumField(); i++ { |
||||
sf := typ.Field(i) |
||||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||
continue |
||||
} |
||||
|
||||
sv := val.Field(i) |
||||
tag := sf.Tag.Get("url") |
||||
if tag == "-" { |
||||
continue |
||||
} |
||||
name, opts := parseTag(tag) |
||||
if name == "" { |
||||
if sf.Anonymous && sv.Kind() == reflect.Struct { |
||||
// save embedded struct for later processing
|
||||
embedded = append(embedded, sv) |
||||
continue |
||||
} |
||||
|
||||
name = sf.Name |
||||
} |
||||
|
||||
if scope != "" { |
||||
name = scope + "[" + name + "]" |
||||
} |
||||
|
||||
if opts.Contains("omitempty") && isEmptyValue(sv) { |
||||
continue |
||||
} |
||||
|
||||
if sv.Type().Implements(encoderType) { |
||||
if !reflect.Indirect(sv).IsValid() { |
||||
sv = reflect.New(sv.Type().Elem()) |
||||
} |
||||
|
||||
m := sv.Interface().(Encoder) |
||||
if err := m.EncodeValues(name, &values); err != nil { |
||||
return err |
||||
} |
||||
continue |
||||
} |
||||
|
||||
if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array { |
||||
var del byte |
||||
if opts.Contains("comma") { |
||||
del = ',' |
||||
} else if opts.Contains("space") { |
||||
del = ' ' |
||||
} else if opts.Contains("semicolon") { |
||||
del = ';' |
||||
} else if opts.Contains("brackets") { |
||||
name = name + "[]" |
||||
} |
||||
|
||||
if del != 0 { |
||||
s := new(bytes.Buffer) |
||||
first := true |
||||
for i := 0; i < sv.Len(); i++ { |
||||
if first { |
||||
first = false |
||||
} else { |
||||
s.WriteByte(del) |
||||
} |
||||
s.WriteString(valueString(sv.Index(i), opts)) |
||||
} |
||||
values.Add(name, s.String()) |
||||
} else { |
||||
for i := 0; i < sv.Len(); i++ { |
||||
k := name |
||||
if opts.Contains("numbered") { |
||||
k = fmt.Sprintf("%s%d", name, i) |
||||
} |
||||
values.Add(k, valueString(sv.Index(i), opts)) |
||||
} |
||||
} |
||||
continue |
||||
} |
||||
|
||||
for sv.Kind() == reflect.Ptr { |
||||
if sv.IsNil() { |
||||
break |
||||
} |
||||
sv = sv.Elem() |
||||
} |
||||
|
||||
if sv.Type() == timeType { |
||||
values.Add(name, valueString(sv, opts)) |
||||
continue |
||||
} |
||||
|
||||
if sv.Kind() == reflect.Struct { |
||||
reflectValue(values, sv, name) |
||||
continue |
||||
} |
||||
|
||||
values.Add(name, valueString(sv, opts)) |
||||
} |
||||
|
||||
for _, f := range embedded { |
||||
if err := reflectValue(values, f, scope); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// valueString returns the string representation of a value.
|
||||
func valueString(v reflect.Value, opts tagOptions) string { |
||||
for v.Kind() == reflect.Ptr { |
||||
if v.IsNil() { |
||||
return "" |
||||
} |
||||
v = v.Elem() |
||||
} |
||||
|
||||
if v.Kind() == reflect.Bool && opts.Contains("int") { |
||||
if v.Bool() { |
||||
return "1" |
||||
} |
||||
return "0" |
||||
} |
||||
|
||||
if v.Type() == timeType { |
||||
t := v.Interface().(time.Time) |
||||
if opts.Contains("unix") { |
||||
return strconv.FormatInt(t.Unix(), 10) |
||||
} |
||||
return t.Format(time.RFC3339) |
||||
} |
||||
|
||||
return fmt.Sprint(v.Interface()) |
||||
} |
||||
|
||||
// isEmptyValue checks if a value should be considered empty for the purposes
|
||||
// of omitting fields with the "omitempty" option.
|
||||
func isEmptyValue(v reflect.Value) bool { |
||||
switch v.Kind() { |
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String: |
||||
return v.Len() == 0 |
||||
case reflect.Bool: |
||||
return !v.Bool() |
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
||||
return v.Int() == 0 |
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: |
||||
return v.Uint() == 0 |
||||
case reflect.Float32, reflect.Float64: |
||||
return v.Float() == 0 |
||||
case reflect.Interface, reflect.Ptr: |
||||
return v.IsNil() |
||||
} |
||||
|
||||
if v.Type() == timeType { |
||||
return v.Interface().(time.Time).IsZero() |
||||
} |
||||
|
||||
return false |
||||
} |
||||
|
||||
// tagOptions is the string following a comma in a struct field's "url" tag, or
|
||||
// the empty string. It does not include the leading comma.
|
||||
type tagOptions []string |
||||
|
||||
// parseTag splits a struct field's url tag into its name and comma-separated
|
||||
// options.
|
||||
func parseTag(tag string) (string, tagOptions) { |
||||
s := strings.Split(tag, ",") |
||||
return s[0], s[1:] |
||||
} |
||||
|
||||
// Contains checks whether the tagOptions contains the specified option.
|
||||
func (o tagOptions) Contains(option string) bool { |
||||
for _, s := range o { |
||||
if s == option { |
||||
return true |
||||
} |
||||
} |
||||
return false |
||||
} |
Loading…
Reference in new issue