Improve migrations to support migrating milestones/labels/issues/comments/pullrequests (#6290)
* add migrations * fix package dependency * fix lints * implements migrations except pull requests * add releases * migrating releases * fix bug * fix lint * fix migrate releases * fix tests * add rollback * pull request migtations * fix import * fix go module vendor * add tests for upload to gitea * more migrate options * fix swagger-check * fix misspell * add options on migration UI * fix log error * improve UI options on migrating * add support for username password when migrating from github * fix tests * remove comments and fix migrate limitation * improve error handles * migrate API will also support migrate milestones/labels/issues/pulls/releases * fix tests and remove unused codes * add DownloaderFactory and docs about how to create a new Downloader * fix misspell * fix migration docs * Add hints about migrate options on migration page * fix teststokarchuk/v1.17
parent
1c7c739eb9
commit
08069dc465
@ -0,0 +1,72 @@ |
||||
--- |
||||
date: "2019-04-15T17:29:00+08:00" |
||||
title: "Advanced: Migrations Interfaces" |
||||
slug: "migrations-interfaces" |
||||
weight: 30 |
||||
toc: true |
||||
draft: false |
||||
menu: |
||||
sidebar: |
||||
parent: "advanced" |
||||
name: "Migrations Interfaces" |
||||
weight: 55 |
||||
identifier: "migrations-interfaces" |
||||
--- |
||||
|
||||
# Migration Features |
||||
|
||||
The new migration features were introduced in Gitea 1.9.0. It defines two interfaces to support migrating |
||||
repositories data from other git host platforms to gitea or, in the future migrating gitea data to other |
||||
git host platforms. Currently, only the migrations from github via APIv3 to Gitea is implemented. |
||||
|
||||
First of all, Gitea defines some standard objects in packages `modules/migrations/base`. They are |
||||
`Repository`, `Milestone`, `Release`, `Label`, `Issue`, `Comment`, `PullRequest`. |
||||
|
||||
## Downloader Interfaces |
||||
|
||||
To migrate from a new git host platform, there are two steps to be updated. |
||||
|
||||
- You should implement a `Downloader` which will get all kinds of repository informations. |
||||
- You should implement a `DownloaderFactory` which is used to detect if the URL matches and |
||||
create a Downloader. |
||||
- You'll need to register the `DownloaderFactory` via `RegisterDownloaderFactory` on init. |
||||
|
||||
```Go |
||||
type Downloader interface { |
||||
GetRepoInfo() (*Repository, error) |
||||
GetMilestones() ([]*Milestone, error) |
||||
GetReleases() ([]*Release, error) |
||||
GetLabels() ([]*Label, error) |
||||
GetIssues(start, limit int) ([]*Issue, error) |
||||
GetComments(issueNumber int64) ([]*Comment, error) |
||||
GetPullRequests(start, limit int) ([]*PullRequest, error) |
||||
} |
||||
``` |
||||
|
||||
```Go |
||||
type DownloaderFactory interface { |
||||
Match(opts MigrateOptions) (bool, error) |
||||
New(opts MigrateOptions) (Downloader, error) |
||||
} |
||||
``` |
||||
|
||||
## Uploader Interface |
||||
|
||||
Currently, only a `GiteaLocalUploader` is implemented, so we only save downloaded |
||||
data via this `Uploader` on the local Gitea instance. Other uploaders are not supported |
||||
and will be implemented in future. |
||||
|
||||
```Go |
||||
// Uploader uploads all the informations |
||||
type Uploader interface { |
||||
CreateRepo(repo *Repository, includeWiki bool) error |
||||
CreateMilestone(milestone *Milestone) error |
||||
CreateRelease(release *Release) error |
||||
CreateLabel(label *Label) error |
||||
CreateIssue(issue *Issue) error |
||||
CreateComment(issueNumber int64, comment *Comment) error |
||||
CreatePullRequest(pr *PullRequest) error |
||||
Rollback() error |
||||
} |
||||
|
||||
``` |
@ -0,0 +1,145 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package models |
||||
|
||||
import "github.com/go-xorm/xorm" |
||||
|
||||
// InsertIssue insert one issue to database
|
||||
func InsertIssue(issue *Issue, labelIDs []int64) error { |
||||
sess := x.NewSession() |
||||
if err := sess.Begin(); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if err := insertIssue(sess, issue, labelIDs); err != nil { |
||||
return err |
||||
} |
||||
return sess.Commit() |
||||
} |
||||
|
||||
func insertIssue(sess *xorm.Session, issue *Issue, labelIDs []int64) error { |
||||
if issue.MilestoneID > 0 { |
||||
sess.Incr("num_issues") |
||||
if issue.IsClosed { |
||||
sess.Incr("num_closed_issues") |
||||
} |
||||
if _, err := sess.ID(issue.MilestoneID).NoAutoTime().Update(new(Milestone)); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
if _, err := sess.NoAutoTime().Insert(issue); err != nil { |
||||
return err |
||||
} |
||||
var issueLabels = make([]IssueLabel, 0, len(labelIDs)) |
||||
for _, labelID := range labelIDs { |
||||
issueLabels = append(issueLabels, IssueLabel{ |
||||
IssueID: issue.ID, |
||||
LabelID: labelID, |
||||
}) |
||||
} |
||||
if _, err := sess.Insert(issueLabels); err != nil { |
||||
return err |
||||
} |
||||
if !issue.IsPull { |
||||
sess.ID(issue.RepoID).Incr("num_issues") |
||||
if issue.IsClosed { |
||||
sess.Incr("num_closed_issues") |
||||
} |
||||
} else { |
||||
sess.ID(issue.RepoID).Incr("num_pulls") |
||||
if issue.IsClosed { |
||||
sess.Incr("num_closed_pulls") |
||||
} |
||||
} |
||||
if _, err := sess.NoAutoTime().Update(issue.Repo); err != nil { |
||||
return err |
||||
} |
||||
|
||||
sess.Incr("num_issues") |
||||
if issue.IsClosed { |
||||
sess.Incr("num_closed_issues") |
||||
} |
||||
if _, err := sess.In("id", labelIDs).Update(new(Label)); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if issue.MilestoneID > 0 { |
||||
if _, err := sess.ID(issue.MilestoneID).SetExpr("completeness", "num_closed_issues * 100 / num_issues").Update(new(Milestone)); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// InsertComment inserted a comment
|
||||
func InsertComment(comment *Comment) error { |
||||
sess := x.NewSession() |
||||
defer sess.Close() |
||||
if err := sess.Begin(); err != nil { |
||||
return err |
||||
} |
||||
if _, err := sess.NoAutoTime().Insert(comment); err != nil { |
||||
return err |
||||
} |
||||
if _, err := sess.ID(comment.IssueID).Incr("num_comments").Update(new(Issue)); err != nil { |
||||
return err |
||||
} |
||||
return sess.Commit() |
||||
} |
||||
|
||||
// InsertPullRequest inserted a pull request
|
||||
func InsertPullRequest(pr *PullRequest, labelIDs []int64) error { |
||||
sess := x.NewSession() |
||||
defer sess.Close() |
||||
if err := sess.Begin(); err != nil { |
||||
return err |
||||
} |
||||
if err := insertIssue(sess, pr.Issue, labelIDs); err != nil { |
||||
return err |
||||
} |
||||
pr.IssueID = pr.Issue.ID |
||||
if _, err := sess.NoAutoTime().Insert(pr); err != nil { |
||||
return err |
||||
} |
||||
return sess.Commit() |
||||
} |
||||
|
||||
// MigrateRelease migrates release
|
||||
func MigrateRelease(rel *Release) error { |
||||
sess := x.NewSession() |
||||
if err := sess.Begin(); err != nil { |
||||
return err |
||||
} |
||||
|
||||
var oriRel = Release{ |
||||
RepoID: rel.RepoID, |
||||
TagName: rel.TagName, |
||||
} |
||||
exist, err := sess.Get(&oriRel) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if !exist { |
||||
if _, err := sess.NoAutoTime().Insert(rel); err != nil { |
||||
return err |
||||
} |
||||
} else { |
||||
rel.ID = oriRel.ID |
||||
if _, err := sess.ID(rel.ID).Cols("target, title, note, is_tag, num_commits").Update(rel); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
for i := 0; i < len(rel.Attachments); i++ { |
||||
rel.Attachments[i].ReleaseID = rel.ID |
||||
} |
||||
|
||||
if _, err := sess.NoAutoTime().Insert(rel.Attachments); err != nil { |
||||
return err |
||||
} |
||||
|
||||
return sess.Commit() |
||||
} |
@ -0,0 +1,17 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
import "time" |
||||
|
||||
// Comment is a standard comment information
|
||||
type Comment struct { |
||||
PosterName string |
||||
PosterEmail string |
||||
Created time.Time |
||||
Content string |
||||
Reactions *Reactions |
||||
} |
@ -0,0 +1,23 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
// Downloader downloads the site repo informations
|
||||
type Downloader interface { |
||||
GetRepoInfo() (*Repository, error) |
||||
GetMilestones() ([]*Milestone, error) |
||||
GetReleases() ([]*Release, error) |
||||
GetLabels() ([]*Label, error) |
||||
GetIssues(start, limit int) ([]*Issue, error) |
||||
GetComments(issueNumber int64) ([]*Comment, error) |
||||
GetPullRequests(start, limit int) ([]*PullRequest, error) |
||||
} |
||||
|
||||
// DownloaderFactory defines an interface to match a downloader implementation and create a downloader
|
||||
type DownloaderFactory interface { |
||||
Match(opts MigrateOptions) (bool, error) |
||||
New(opts MigrateOptions) (Downloader, error) |
||||
} |
@ -0,0 +1,24 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
import "time" |
||||
|
||||
// Issue is a standard issue information
|
||||
type Issue struct { |
||||
Number int64 |
||||
PosterName string |
||||
PosterEmail string |
||||
Title string |
||||
Content string |
||||
Milestone string |
||||
State string // closed, open
|
||||
IsLocked bool |
||||
Created time.Time |
||||
Closed *time.Time |
||||
Labels []*Label |
||||
Reactions *Reactions |
||||
} |
@ -0,0 +1,13 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
// Label defines a standard label informations
|
||||
type Label struct { |
||||
Name string |
||||
Color string |
||||
Description string |
||||
} |
@ -0,0 +1,19 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
import "time" |
||||
|
||||
// Milestone defines a standard milestone
|
||||
type Milestone struct { |
||||
Title string |
||||
Description string |
||||
Deadline *time.Time |
||||
Created time.Time |
||||
Updated *time.Time |
||||
Closed *time.Time |
||||
State string |
||||
} |
@ -0,0 +1,26 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
// MigrateOptions defines the way a repository gets migrated
|
||||
type MigrateOptions struct { |
||||
RemoteURL string |
||||
AuthUsername string |
||||
AuthPassword string |
||||
Name string |
||||
Description string |
||||
|
||||
Wiki bool |
||||
Issues bool |
||||
Milestones bool |
||||
Labels bool |
||||
Releases bool |
||||
Comments bool |
||||
PullRequests bool |
||||
Private bool |
||||
Mirror bool |
||||
IgnoreIssueAuthor bool // if true will not add original author information before issues or comments content.
|
||||
} |
@ -0,0 +1,53 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
import ( |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// PullRequest defines a standard pull request information
|
||||
type PullRequest struct { |
||||
Number int64 |
||||
Title string |
||||
PosterName string |
||||
PosterEmail string |
||||
Content string |
||||
Milestone string |
||||
State string |
||||
Created time.Time |
||||
Closed *time.Time |
||||
Labels []*Label |
||||
PatchURL string |
||||
Merged bool |
||||
MergedTime *time.Time |
||||
MergeCommitSHA string |
||||
Head PullRequestBranch |
||||
Base PullRequestBranch |
||||
Assignee string |
||||
Assignees []string |
||||
IsLocked bool |
||||
} |
||||
|
||||
// IsForkPullRequest returns true if the pull request from a forked repository but not the same repository
|
||||
func (p *PullRequest) IsForkPullRequest() bool { |
||||
return p.Head.RepoPath() != p.Base.RepoPath() |
||||
} |
||||
|
||||
// PullRequestBranch represents a pull request branch
|
||||
type PullRequestBranch struct { |
||||
CloneURL string |
||||
Ref string |
||||
SHA string |
||||
RepoName string |
||||
OwnerName string |
||||
} |
||||
|
||||
// RepoPath returns pull request repo path
|
||||
func (p PullRequestBranch) RepoPath() string { |
||||
return fmt.Sprintf("%s/%s", p.OwnerName, p.RepoName) |
||||
} |
@ -0,0 +1,17 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
// Reactions represents a summary of reactions.
|
||||
type Reactions struct { |
||||
TotalCount int |
||||
PlusOne int |
||||
MinusOne int |
||||
Laugh int |
||||
Confused int |
||||
Heart int |
||||
Hooray int |
||||
} |
@ -0,0 +1,31 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
import "time" |
||||
|
||||
// ReleaseAsset represents a release asset
|
||||
type ReleaseAsset struct { |
||||
URL string |
||||
Name string |
||||
ContentType *string |
||||
Size *int |
||||
DownloadCount *int |
||||
Created time.Time |
||||
Updated time.Time |
||||
} |
||||
|
||||
// Release represents a release
|
||||
type Release struct { |
||||
TagName string |
||||
TargetCommitish string |
||||
Name string |
||||
Body string |
||||
Draft bool |
||||
Prerelease bool |
||||
Assets []ReleaseAsset |
||||
Created time.Time |
||||
Published time.Time |
||||
} |
@ -0,0 +1,18 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
// Repository defines a standard repository information
|
||||
type Repository struct { |
||||
Name string |
||||
Owner string |
||||
IsPrivate bool |
||||
IsMirror bool |
||||
Description string |
||||
AuthUsername string |
||||
AuthPassword string |
||||
CloneURL string |
||||
} |
@ -0,0 +1,18 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base |
||||
|
||||
// Uploader uploads all the informations
|
||||
type Uploader interface { |
||||
CreateRepo(repo *Repository, includeWiki bool) error |
||||
CreateMilestone(milestone *Milestone) error |
||||
CreateRelease(release *Release) error |
||||
CreateLabel(label *Label) error |
||||
CreateIssue(issue *Issue) error |
||||
CreateComment(issueNumber int64, comment *Comment) error |
||||
CreatePullRequest(pr *PullRequest) error |
||||
Rollback() error |
||||
} |
@ -0,0 +1,29 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"errors" |
||||
|
||||
"github.com/google/go-github/v24/github" |
||||
) |
||||
|
||||
var ( |
||||
// ErrNotSupported returns the error not supported
|
||||
ErrNotSupported = errors.New("not supported") |
||||
) |
||||
|
||||
// IsRateLimitError returns true if the err is github.RateLimitError
|
||||
func IsRateLimitError(err error) bool { |
||||
_, ok := err.(*github.RateLimitError) |
||||
return ok |
||||
} |
||||
|
||||
// IsTwoFactorAuthError returns true if the err is github.TwoFactorAuthError
|
||||
func IsTwoFactorAuthError(err error) bool { |
||||
_, ok := err.(*github.TwoFactorAuthError) |
||||
return ok |
||||
} |
@ -0,0 +1,69 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"code.gitea.io/gitea/modules/migrations/base" |
||||
) |
||||
|
||||
var ( |
||||
_ base.Downloader = &PlainGitDownloader{} |
||||
) |
||||
|
||||
// PlainGitDownloader implements a Downloader interface to clone git from a http/https URL
|
||||
type PlainGitDownloader struct { |
||||
ownerName string |
||||
repoName string |
||||
remoteURL string |
||||
} |
||||
|
||||
// NewPlainGitDownloader creates a git Downloader
|
||||
func NewPlainGitDownloader(ownerName, repoName, remoteURL string) *PlainGitDownloader { |
||||
return &PlainGitDownloader{ |
||||
ownerName: ownerName, |
||||
repoName: repoName, |
||||
remoteURL: remoteURL, |
||||
} |
||||
} |
||||
|
||||
// GetRepoInfo returns a repository information
|
||||
func (g *PlainGitDownloader) GetRepoInfo() (*base.Repository, error) { |
||||
// convert github repo to stand Repo
|
||||
return &base.Repository{ |
||||
Owner: g.ownerName, |
||||
Name: g.repoName, |
||||
CloneURL: g.remoteURL, |
||||
}, nil |
||||
} |
||||
|
||||
// GetMilestones returns milestones
|
||||
func (g *PlainGitDownloader) GetMilestones() ([]*base.Milestone, error) { |
||||
return nil, ErrNotSupported |
||||
} |
||||
|
||||
// GetLabels returns labels
|
||||
func (g *PlainGitDownloader) GetLabels() ([]*base.Label, error) { |
||||
return nil, ErrNotSupported |
||||
} |
||||
|
||||
// GetReleases returns releases
|
||||
func (g *PlainGitDownloader) GetReleases() ([]*base.Release, error) { |
||||
return nil, ErrNotSupported |
||||
} |
||||
|
||||
// GetIssues returns issues according start and limit
|
||||
func (g *PlainGitDownloader) GetIssues(start, limit int) ([]*base.Issue, error) { |
||||
return nil, ErrNotSupported |
||||
} |
||||
|
||||
// GetComments returns comments according issueNumber
|
||||
func (g *PlainGitDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { |
||||
return nil, ErrNotSupported |
||||
} |
||||
|
||||
// GetPullRequests returns pull requests according start and limit
|
||||
func (g *PlainGitDownloader) GetPullRequests(start, limit int) ([]*base.PullRequest, error) { |
||||
return nil, ErrNotSupported |
||||
} |
@ -0,0 +1,403 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io" |
||||
"net/http" |
||||
"os" |
||||
"path" |
||||
"path/filepath" |
||||
"strings" |
||||
"sync" |
||||
"time" |
||||
|
||||
"code.gitea.io/gitea/models" |
||||
"code.gitea.io/gitea/modules/git" |
||||
"code.gitea.io/gitea/modules/log" |
||||
"code.gitea.io/gitea/modules/migrations/base" |
||||
"code.gitea.io/gitea/modules/setting" |
||||
"code.gitea.io/gitea/modules/util" |
||||
|
||||
gouuid "github.com/satori/go.uuid" |
||||
) |
||||
|
||||
var ( |
||||
_ base.Uploader = &GiteaLocalUploader{} |
||||
) |
||||
|
||||
// GiteaLocalUploader implements an Uploader to gitea sites
|
||||
type GiteaLocalUploader struct { |
||||
doer *models.User |
||||
repoOwner string |
||||
repoName string |
||||
repo *models.Repository |
||||
labels sync.Map |
||||
milestones sync.Map |
||||
issues sync.Map |
||||
gitRepo *git.Repository |
||||
prHeadCache map[string]struct{} |
||||
} |
||||
|
||||
// NewGiteaLocalUploader creates an gitea Uploader via gitea API v1
|
||||
func NewGiteaLocalUploader(doer *models.User, repoOwner, repoName string) *GiteaLocalUploader { |
||||
return &GiteaLocalUploader{ |
||||
doer: doer, |
||||
repoOwner: repoOwner, |
||||
repoName: repoName, |
||||
prHeadCache: make(map[string]struct{}), |
||||
} |
||||
} |
||||
|
||||
// CreateRepo creates a repository
|
||||
func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, includeWiki bool) error { |
||||
owner, err := models.GetUserByName(g.repoOwner) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
r, err := models.MigrateRepository(g.doer, owner, models.MigrateRepoOptions{ |
||||
Name: g.repoName, |
||||
Description: repo.Description, |
||||
IsMirror: repo.IsMirror, |
||||
RemoteAddr: repo.CloneURL, |
||||
IsPrivate: repo.IsPrivate, |
||||
Wiki: includeWiki, |
||||
}) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
g.repo = r |
||||
g.gitRepo, err = git.OpenRepository(r.RepoPath()) |
||||
return err |
||||
} |
||||
|
||||
// CreateMilestone creates milestone
|
||||
func (g *GiteaLocalUploader) CreateMilestone(milestone *base.Milestone) error { |
||||
var deadline util.TimeStamp |
||||
if milestone.Deadline != nil { |
||||
deadline = util.TimeStamp(milestone.Deadline.Unix()) |
||||
} |
||||
if deadline == 0 { |
||||
deadline = util.TimeStamp(time.Date(9999, 1, 1, 0, 0, 0, 0, setting.UILocation).Unix()) |
||||
} |
||||
var ms = models.Milestone{ |
||||
RepoID: g.repo.ID, |
||||
Name: milestone.Title, |
||||
Content: milestone.Description, |
||||
IsClosed: milestone.State == "close", |
||||
DeadlineUnix: deadline, |
||||
} |
||||
if ms.IsClosed && milestone.Closed != nil { |
||||
ms.ClosedDateUnix = util.TimeStamp(milestone.Closed.Unix()) |
||||
} |
||||
err := models.NewMilestone(&ms) |
||||
|
||||
if err != nil { |
||||
return err |
||||
} |
||||
g.milestones.Store(ms.Name, ms.ID) |
||||
return nil |
||||
} |
||||
|
||||
// CreateLabel creates label
|
||||
func (g *GiteaLocalUploader) CreateLabel(label *base.Label) error { |
||||
var lb = models.Label{ |
||||
RepoID: g.repo.ID, |
||||
Name: label.Name, |
||||
Description: label.Description, |
||||
Color: fmt.Sprintf("#%s", label.Color), |
||||
} |
||||
err := models.NewLabel(&lb) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
g.labels.Store(lb.Name, lb.ID) |
||||
return nil |
||||
} |
||||
|
||||
// CreateRelease creates release
|
||||
func (g *GiteaLocalUploader) CreateRelease(release *base.Release) error { |
||||
var rel = models.Release{ |
||||
RepoID: g.repo.ID, |
||||
PublisherID: g.doer.ID, |
||||
TagName: release.TagName, |
||||
LowerTagName: strings.ToLower(release.TagName), |
||||
Target: release.TargetCommitish, |
||||
Title: release.Name, |
||||
Sha1: release.TargetCommitish, |
||||
Note: release.Body, |
||||
IsDraft: release.Draft, |
||||
IsPrerelease: release.Prerelease, |
||||
IsTag: false, |
||||
CreatedUnix: util.TimeStamp(release.Created.Unix()), |
||||
} |
||||
|
||||
// calc NumCommits
|
||||
commit, err := g.gitRepo.GetCommit(rel.TagName) |
||||
if err != nil { |
||||
return fmt.Errorf("GetCommit: %v", err) |
||||
} |
||||
rel.NumCommits, err = commit.CommitsCount() |
||||
if err != nil { |
||||
return fmt.Errorf("CommitsCount: %v", err) |
||||
} |
||||
|
||||
for _, asset := range release.Assets { |
||||
var attach = models.Attachment{ |
||||
UUID: gouuid.NewV4().String(), |
||||
Name: asset.Name, |
||||
DownloadCount: int64(*asset.DownloadCount), |
||||
Size: int64(*asset.Size), |
||||
CreatedUnix: util.TimeStamp(asset.Created.Unix()), |
||||
} |
||||
|
||||
// download attachment
|
||||
resp, err := http.Get(asset.URL) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer resp.Body.Close() |
||||
|
||||
localPath := attach.LocalPath() |
||||
if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil { |
||||
return fmt.Errorf("MkdirAll: %v", err) |
||||
} |
||||
|
||||
fw, err := os.Create(localPath) |
||||
if err != nil { |
||||
return fmt.Errorf("Create: %v", err) |
||||
} |
||||
defer fw.Close() |
||||
|
||||
if _, err := io.Copy(fw, resp.Body); err != nil { |
||||
return err |
||||
} |
||||
|
||||
rel.Attachments = append(rel.Attachments, &attach) |
||||
} |
||||
|
||||
return models.MigrateRelease(&rel) |
||||
} |
||||
|
||||
// CreateIssue creates issue
|
||||
func (g *GiteaLocalUploader) CreateIssue(issue *base.Issue) error { |
||||
var labelIDs []int64 |
||||
for _, label := range issue.Labels { |
||||
id, ok := g.labels.Load(label.Name) |
||||
if !ok { |
||||
return fmt.Errorf("Label %s missing when create issue", label.Name) |
||||
} |
||||
labelIDs = append(labelIDs, id.(int64)) |
||||
} |
||||
|
||||
var milestoneID int64 |
||||
if issue.Milestone != "" { |
||||
milestone, ok := g.milestones.Load(issue.Milestone) |
||||
if !ok { |
||||
return fmt.Errorf("Milestone %s missing when create issue", issue.Milestone) |
||||
} |
||||
milestoneID = milestone.(int64) |
||||
} |
||||
|
||||
var is = models.Issue{ |
||||
RepoID: g.repo.ID, |
||||
Repo: g.repo, |
||||
Index: issue.Number, |
||||
PosterID: g.doer.ID, |
||||
Title: issue.Title, |
||||
Content: issue.Content, |
||||
IsClosed: issue.State == "closed", |
||||
IsLocked: issue.IsLocked, |
||||
MilestoneID: milestoneID, |
||||
CreatedUnix: util.TimeStamp(issue.Created.Unix()), |
||||
} |
||||
if issue.Closed != nil { |
||||
is.ClosedUnix = util.TimeStamp(issue.Closed.Unix()) |
||||
} |
||||
|
||||
err := models.InsertIssue(&is, labelIDs) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
g.issues.Store(issue.Number, is.ID) |
||||
// TODO: add reactions
|
||||
return err |
||||
} |
||||
|
||||
// CreateComment creates comment
|
||||
func (g *GiteaLocalUploader) CreateComment(issueNumber int64, comment *base.Comment) error { |
||||
var issueID int64 |
||||
if issueIDStr, ok := g.issues.Load(issueNumber); !ok { |
||||
issue, err := models.GetIssueByIndex(g.repo.ID, issueNumber) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
issueID = issue.ID |
||||
g.issues.Store(issueNumber, issueID) |
||||
} else { |
||||
issueID = issueIDStr.(int64) |
||||
} |
||||
|
||||
var cm = models.Comment{ |
||||
IssueID: issueID, |
||||
Type: models.CommentTypeComment, |
||||
PosterID: g.doer.ID, |
||||
Content: comment.Content, |
||||
CreatedUnix: util.TimeStamp(comment.Created.Unix()), |
||||
} |
||||
err := models.InsertComment(&cm) |
||||
// TODO: Reactions
|
||||
return err |
||||
} |
||||
|
||||
// CreatePullRequest creates pull request
|
||||
func (g *GiteaLocalUploader) CreatePullRequest(pr *base.PullRequest) error { |
||||
var labelIDs []int64 |
||||
for _, label := range pr.Labels { |
||||
id, ok := g.labels.Load(label.Name) |
||||
if !ok { |
||||
return fmt.Errorf("Label %s missing when create issue", label.Name) |
||||
} |
||||
labelIDs = append(labelIDs, id.(int64)) |
||||
} |
||||
|
||||
var milestoneID int64 |
||||
if pr.Milestone != "" { |
||||
milestone, ok := g.milestones.Load(pr.Milestone) |
||||
if !ok { |
||||
return fmt.Errorf("Milestone %s missing when create issue", pr.Milestone) |
||||
} |
||||
milestoneID = milestone.(int64) |
||||
} |
||||
|
||||
// download patch file
|
||||
resp, err := http.Get(pr.PatchURL) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer resp.Body.Close() |
||||
pullDir := filepath.Join(g.repo.RepoPath(), "pulls") |
||||
if err = os.MkdirAll(pullDir, os.ModePerm); err != nil { |
||||
return err |
||||
} |
||||
f, err := os.Create(filepath.Join(pullDir, fmt.Sprintf("%d.patch", pr.Number))) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer f.Close() |
||||
_, err = io.Copy(f, resp.Body) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// set head information
|
||||
pullHead := filepath.Join(g.repo.RepoPath(), "refs", "pull", fmt.Sprintf("%d", pr.Number)) |
||||
if err := os.MkdirAll(pullHead, os.ModePerm); err != nil { |
||||
return err |
||||
} |
||||
p, err := os.Create(filepath.Join(pullHead, "head")) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer p.Close() |
||||
_, err = p.WriteString(pr.Head.SHA) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var head = "unknown repository" |
||||
if pr.IsForkPullRequest() { |
||||
if pr.Head.OwnerName != "" { |
||||
remote := pr.Head.OwnerName |
||||
_, ok := g.prHeadCache[remote] |
||||
if !ok { |
||||
// git remote add
|
||||
err := g.gitRepo.AddRemote(remote, pr.Head.CloneURL, true) |
||||
if err != nil { |
||||
log.Error("AddRemote failed: %s", err) |
||||
} else { |
||||
g.prHeadCache[remote] = struct{}{} |
||||
ok = true |
||||
} |
||||
} |
||||
|
||||
if ok { |
||||
_, err = git.NewCommand("fetch", remote, pr.Head.Ref).RunInDir(g.repo.RepoPath()) |
||||
if err != nil { |
||||
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err) |
||||
} else { |
||||
headBranch := filepath.Join(g.repo.RepoPath(), "refs", "heads", pr.Head.OwnerName, pr.Head.Ref) |
||||
if err := os.MkdirAll(filepath.Dir(headBranch), os.ModePerm); err != nil { |
||||
return err |
||||
} |
||||
b, err := os.Create(headBranch) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer b.Close() |
||||
_, err = b.WriteString(pr.Head.SHA) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
head = pr.Head.OwnerName + "/" + pr.Head.Ref |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
head = pr.Head.Ref |
||||
} |
||||
|
||||
var pullRequest = models.PullRequest{ |
||||
HeadRepoID: g.repo.ID, |
||||
HeadBranch: head, |
||||
HeadUserName: g.repoOwner, |
||||
BaseRepoID: g.repo.ID, |
||||
BaseBranch: pr.Base.Ref, |
||||
MergeBase: pr.Base.SHA, |
||||
Index: pr.Number, |
||||
HasMerged: pr.Merged, |
||||
|
||||
Issue: &models.Issue{ |
||||
RepoID: g.repo.ID, |
||||
Repo: g.repo, |
||||
Title: pr.Title, |
||||
Index: pr.Number, |
||||
PosterID: g.doer.ID, |
||||
Content: pr.Content, |
||||
MilestoneID: milestoneID, |
||||
IsPull: true, |
||||
IsClosed: pr.State == "closed", |
||||
IsLocked: pr.IsLocked, |
||||
CreatedUnix: util.TimeStamp(pr.Created.Unix()), |
||||
}, |
||||
} |
||||
|
||||
if pullRequest.Issue.IsClosed && pr.Closed != nil { |
||||
pullRequest.Issue.ClosedUnix = util.TimeStamp(pr.Closed.Unix()) |
||||
} |
||||
if pullRequest.HasMerged && pr.MergedTime != nil { |
||||
pullRequest.MergedUnix = util.TimeStamp(pr.MergedTime.Unix()) |
||||
pullRequest.MergedCommitID = pr.MergeCommitSHA |
||||
pullRequest.MergerID = g.doer.ID |
||||
} |
||||
|
||||
// TODO: reactions
|
||||
// TODO: assignees
|
||||
|
||||
return models.InsertPullRequest(&pullRequest, labelIDs) |
||||
} |
||||
|
||||
// Rollback when migrating failed, this will rollback all the changes.
|
||||
func (g *GiteaLocalUploader) Rollback() error { |
||||
if g.repo != nil && g.repo.ID > 0 { |
||||
if err := models.DeleteRepository(g.doer, g.repo.OwnerID, g.repo.ID); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,95 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
"code.gitea.io/gitea/models" |
||||
"code.gitea.io/gitea/modules/util" |
||||
|
||||
"github.com/stretchr/testify/assert" |
||||
) |
||||
|
||||
func TestGiteaUploadRepo(t *testing.T) { |
||||
// FIXME: Since no accesskey or user/password will trigger rate limit of github, just skip
|
||||
t.Skip() |
||||
|
||||
models.PrepareTestEnv(t) |
||||
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User) |
||||
|
||||
var ( |
||||
downloader = NewGithubDownloaderV3("", "", "go-xorm", "builder") |
||||
repoName = "builder-" + time.Now().Format("2006-01-02-15-04-05") |
||||
uploader = NewGiteaLocalUploader(user, user.Name, repoName) |
||||
) |
||||
|
||||
err := migrateRepository(downloader, uploader, MigrateOptions{ |
||||
RemoteURL: "https://github.com/go-xorm/builder", |
||||
Name: repoName, |
||||
AuthUsername: "", |
||||
|
||||
Wiki: true, |
||||
Issues: true, |
||||
Milestones: true, |
||||
Labels: true, |
||||
Releases: true, |
||||
Comments: true, |
||||
PullRequests: true, |
||||
Private: true, |
||||
Mirror: false, |
||||
IgnoreIssueAuthor: false, |
||||
}) |
||||
assert.NoError(t, err) |
||||
|
||||
repo := models.AssertExistsAndLoadBean(t, &models.Repository{OwnerID: user.ID, Name: repoName}).(*models.Repository) |
||||
assert.True(t, repo.HasWiki()) |
||||
|
||||
milestones, err := models.GetMilestones(repo.ID, 0, false, "") |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 1, len(milestones)) |
||||
|
||||
milestones, err = models.GetMilestones(repo.ID, 0, true, "") |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 0, len(milestones)) |
||||
|
||||
labels, err := models.GetLabelsByRepoID(repo.ID, "") |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 11, len(labels)) |
||||
|
||||
releases, err := models.GetReleasesByRepoID(repo.ID, models.FindReleasesOptions{ |
||||
IncludeTags: true, |
||||
}, 0, 10) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 8, len(releases)) |
||||
|
||||
releases, err = models.GetReleasesByRepoID(repo.ID, models.FindReleasesOptions{ |
||||
IncludeTags: false, |
||||
}, 0, 10) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 1, len(releases)) |
||||
|
||||
issues, err := models.Issues(&models.IssuesOptions{ |
||||
RepoIDs: []int64{repo.ID}, |
||||
IsPull: util.OptionalBoolFalse, |
||||
SortType: "oldest", |
||||
}) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 14, len(issues)) |
||||
assert.NoError(t, issues[0].LoadDiscussComments()) |
||||
assert.EqualValues(t, 0, len(issues[0].Comments)) |
||||
|
||||
pulls, _, err := models.PullRequests(repo.ID, &models.PullRequestsOptions{ |
||||
SortType: "oldest", |
||||
}) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 34, len(pulls)) |
||||
assert.NoError(t, pulls[0].LoadIssue()) |
||||
assert.NoError(t, pulls[0].Issue.LoadDiscussComments()) |
||||
assert.EqualValues(t, 2, len(pulls[0].Issue.Comments)) |
||||
} |
@ -0,0 +1,475 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"net/http" |
||||
"net/url" |
||||
"strings" |
||||
|
||||
"code.gitea.io/gitea/modules/log" |
||||
"code.gitea.io/gitea/modules/migrations/base" |
||||
|
||||
"github.com/google/go-github/v24/github" |
||||
"golang.org/x/oauth2" |
||||
) |
||||
|
||||
var ( |
||||
_ base.Downloader = &GithubDownloaderV3{} |
||||
_ base.DownloaderFactory = &GithubDownloaderV3Factory{} |
||||
) |
||||
|
||||
func init() { |
||||
RegisterDownloaderFactory(&GithubDownloaderV3Factory{}) |
||||
} |
||||
|
||||
// GithubDownloaderV3Factory defines a github downloader v3 factory
|
||||
type GithubDownloaderV3Factory struct { |
||||
} |
||||
|
||||
// Match returns ture if the migration remote URL matched this downloader factory
|
||||
func (f *GithubDownloaderV3Factory) Match(opts base.MigrateOptions) (bool, error) { |
||||
u, err := url.Parse(opts.RemoteURL) |
||||
if err != nil { |
||||
return false, err |
||||
} |
||||
|
||||
return u.Host == "github.com" && opts.AuthUsername != "", nil |
||||
} |
||||
|
||||
// New returns a Downloader related to this factory according MigrateOptions
|
||||
func (f *GithubDownloaderV3Factory) New(opts base.MigrateOptions) (base.Downloader, error) { |
||||
u, err := url.Parse(opts.RemoteURL) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
fields := strings.Split(u.Path, "/") |
||||
oldOwner := fields[1] |
||||
oldName := strings.TrimSuffix(fields[2], ".git") |
||||
|
||||
log.Trace("Create github downloader: %s/%s", oldOwner, oldName) |
||||
|
||||
return NewGithubDownloaderV3(opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil |
||||
} |
||||
|
||||
// GithubDownloaderV3 implements a Downloader interface to get repository informations
|
||||
// from github via APIv3
|
||||
type GithubDownloaderV3 struct { |
||||
ctx context.Context |
||||
client *github.Client |
||||
repoOwner string |
||||
repoName string |
||||
userName string |
||||
password string |
||||
} |
||||
|
||||
// NewGithubDownloaderV3 creates a github Downloader via github v3 API
|
||||
func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *GithubDownloaderV3 { |
||||
var downloader = GithubDownloaderV3{ |
||||
userName: userName, |
||||
password: password, |
||||
ctx: context.Background(), |
||||
repoOwner: repoOwner, |
||||
repoName: repoName, |
||||
} |
||||
|
||||
var client *http.Client |
||||
if userName != "" { |
||||
if password == "" { |
||||
ts := oauth2.StaticTokenSource( |
||||
&oauth2.Token{AccessToken: userName}, |
||||
) |
||||
client = oauth2.NewClient(downloader.ctx, ts) |
||||
} else { |
||||
client = &http.Client{ |
||||
Transport: &http.Transport{ |
||||
Proxy: func(req *http.Request) (*url.URL, error) { |
||||
req.SetBasicAuth(userName, password) |
||||
return nil, nil |
||||
}, |
||||
}, |
||||
} |
||||
} |
||||
} |
||||
downloader.client = github.NewClient(client) |
||||
return &downloader |
||||
} |
||||
|
||||
// GetRepoInfo returns a repository information
|
||||
func (g *GithubDownloaderV3) GetRepoInfo() (*base.Repository, error) { |
||||
gr, _, err := g.client.Repositories.Get(g.ctx, g.repoOwner, g.repoName) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// convert github repo to stand Repo
|
||||
return &base.Repository{ |
||||
Owner: g.repoOwner, |
||||
Name: gr.GetName(), |
||||
IsPrivate: *gr.Private, |
||||
Description: gr.GetDescription(), |
||||
CloneURL: gr.GetCloneURL(), |
||||
}, nil |
||||
} |
||||
|
||||
// GetMilestones returns milestones
|
||||
func (g *GithubDownloaderV3) GetMilestones() ([]*base.Milestone, error) { |
||||
var perPage = 100 |
||||
var milestones = make([]*base.Milestone, 0, perPage) |
||||
for i := 1; ; i++ { |
||||
ms, _, err := g.client.Issues.ListMilestones(g.ctx, g.repoOwner, g.repoName, |
||||
&github.MilestoneListOptions{ |
||||
State: "all", |
||||
ListOptions: github.ListOptions{ |
||||
Page: i, |
||||
PerPage: perPage, |
||||
}}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
for _, m := range ms { |
||||
var desc string |
||||
if m.Description != nil { |
||||
desc = *m.Description |
||||
} |
||||
var state = "open" |
||||
if m.State != nil { |
||||
state = *m.State |
||||
} |
||||
milestones = append(milestones, &base.Milestone{ |
||||
Title: *m.Title, |
||||
Description: desc, |
||||
Deadline: m.DueOn, |
||||
State: state, |
||||
Created: *m.CreatedAt, |
||||
Updated: m.UpdatedAt, |
||||
Closed: m.ClosedAt, |
||||
}) |
||||
} |
||||
if len(ms) < perPage { |
||||
break |
||||
} |
||||
} |
||||
return milestones, nil |
||||
} |
||||
|
||||
func convertGithubLabel(label *github.Label) *base.Label { |
||||
var desc string |
||||
if label.Description != nil { |
||||
desc = *label.Description |
||||
} |
||||
return &base.Label{ |
||||
Name: *label.Name, |
||||
Color: *label.Color, |
||||
Description: desc, |
||||
} |
||||
} |
||||
|
||||
// GetLabels returns labels
|
||||
func (g *GithubDownloaderV3) GetLabels() ([]*base.Label, error) { |
||||
var perPage = 100 |
||||
var labels = make([]*base.Label, 0, perPage) |
||||
for i := 1; ; i++ { |
||||
ls, _, err := g.client.Issues.ListLabels(g.ctx, g.repoOwner, g.repoName, |
||||
&github.ListOptions{ |
||||
Page: i, |
||||
PerPage: perPage, |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
for _, label := range ls { |
||||
labels = append(labels, convertGithubLabel(label)) |
||||
} |
||||
if len(ls) < perPage { |
||||
break |
||||
} |
||||
} |
||||
return labels, nil |
||||
} |
||||
|
||||
func (g *GithubDownloaderV3) convertGithubRelease(rel *github.RepositoryRelease) *base.Release { |
||||
var ( |
||||
name string |
||||
desc string |
||||
) |
||||
if rel.Body != nil { |
||||
desc = *rel.Body |
||||
} |
||||
if rel.Name != nil { |
||||
name = *rel.Name |
||||
} |
||||
|
||||
r := &base.Release{ |
||||
TagName: *rel.TagName, |
||||
TargetCommitish: *rel.TargetCommitish, |
||||
Name: name, |
||||
Body: desc, |
||||
Draft: *rel.Draft, |
||||
Prerelease: *rel.Prerelease, |
||||
Created: rel.CreatedAt.Time, |
||||
Published: rel.PublishedAt.Time, |
||||
} |
||||
|
||||
for _, asset := range rel.Assets { |
||||
u, _ := url.Parse(*asset.BrowserDownloadURL) |
||||
u.User = url.UserPassword(g.userName, g.password) |
||||
r.Assets = append(r.Assets, base.ReleaseAsset{ |
||||
URL: u.String(), |
||||
Name: *asset.Name, |
||||
ContentType: asset.ContentType, |
||||
Size: asset.Size, |
||||
DownloadCount: asset.DownloadCount, |
||||
Created: asset.CreatedAt.Time, |
||||
Updated: asset.UpdatedAt.Time, |
||||
}) |
||||
} |
||||
return r |
||||
} |
||||
|
||||
// GetReleases returns releases
|
||||
func (g *GithubDownloaderV3) GetReleases() ([]*base.Release, error) { |
||||
var perPage = 100 |
||||
var releases = make([]*base.Release, 0, perPage) |
||||
for i := 1; ; i++ { |
||||
ls, _, err := g.client.Repositories.ListReleases(g.ctx, g.repoOwner, g.repoName, |
||||
&github.ListOptions{ |
||||
Page: i, |
||||
PerPage: perPage, |
||||
}) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
for _, release := range ls { |
||||
releases = append(releases, g.convertGithubRelease(release)) |
||||
} |
||||
if len(ls) < perPage { |
||||
break |
||||
} |
||||
} |
||||
return releases, nil |
||||
} |
||||
|
||||
func convertGithubReactions(reactions *github.Reactions) *base.Reactions { |
||||
return &base.Reactions{ |
||||
TotalCount: *reactions.TotalCount, |
||||
PlusOne: *reactions.PlusOne, |
||||
MinusOne: *reactions.MinusOne, |
||||
Laugh: *reactions.Laugh, |
||||
Confused: *reactions.Confused, |
||||
Heart: *reactions.Heart, |
||||
Hooray: *reactions.Hooray, |
||||
} |
||||
} |
||||
|
||||
// GetIssues returns issues according start and limit
|
||||
func (g *GithubDownloaderV3) GetIssues(start, limit int) ([]*base.Issue, error) { |
||||
var perPage = 100 |
||||
opt := &github.IssueListByRepoOptions{ |
||||
Sort: "created", |
||||
Direction: "asc", |
||||
State: "all", |
||||
ListOptions: github.ListOptions{ |
||||
PerPage: perPage, |
||||
}, |
||||
} |
||||
var allIssues = make([]*base.Issue, 0, limit) |
||||
for { |
||||
issues, resp, err := g.client.Issues.ListByRepo(g.ctx, g.repoOwner, g.repoName, opt) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error while listing repos: %v", err) |
||||
} |
||||
for _, issue := range issues { |
||||
if issue.IsPullRequest() { |
||||
continue |
||||
} |
||||
var body string |
||||
if issue.Body != nil { |
||||
body = *issue.Body |
||||
} |
||||
var milestone string |
||||
if issue.Milestone != nil { |
||||
milestone = *issue.Milestone.Title |
||||
} |
||||
var labels = make([]*base.Label, 0, len(issue.Labels)) |
||||
for _, l := range issue.Labels { |
||||
labels = append(labels, convertGithubLabel(&l)) |
||||
} |
||||
var reactions *base.Reactions |
||||
if issue.Reactions != nil { |
||||
reactions = convertGithubReactions(issue.Reactions) |
||||
} |
||||
|
||||
var email string |
||||
if issue.User.Email != nil { |
||||
email = *issue.User.Email |
||||
} |
||||
allIssues = append(allIssues, &base.Issue{ |
||||
Title: *issue.Title, |
||||
Number: int64(*issue.Number), |
||||
PosterName: *issue.User.Login, |
||||
PosterEmail: email, |
||||
Content: body, |
||||
Milestone: milestone, |
||||
State: *issue.State, |
||||
Created: *issue.CreatedAt, |
||||
Labels: labels, |
||||
Reactions: reactions, |
||||
Closed: issue.ClosedAt, |
||||
IsLocked: *issue.Locked, |
||||
}) |
||||
if len(allIssues) >= limit { |
||||
return allIssues, nil |
||||
} |
||||
} |
||||
if resp.NextPage == 0 { |
||||
break |
||||
} |
||||
opt.Page = resp.NextPage |
||||
} |
||||
return allIssues, nil |
||||
} |
||||
|
||||
// GetComments returns comments according issueNumber
|
||||
func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, error) { |
||||
var allComments = make([]*base.Comment, 0, 100) |
||||
opt := &github.IssueListCommentsOptions{ |
||||
Sort: "created", |
||||
Direction: "asc", |
||||
ListOptions: github.ListOptions{ |
||||
PerPage: 100, |
||||
}, |
||||
} |
||||
for { |
||||
comments, resp, err := g.client.Issues.ListComments(g.ctx, g.repoOwner, g.repoName, int(issueNumber), opt) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error while listing repos: %v", err) |
||||
} |
||||
for _, comment := range comments { |
||||
var email string |
||||
if comment.User.Email != nil { |
||||
email = *comment.User.Email |
||||
} |
||||
var reactions *base.Reactions |
||||
if comment.Reactions != nil { |
||||
reactions = convertGithubReactions(comment.Reactions) |
||||
} |
||||
allComments = append(allComments, &base.Comment{ |
||||
PosterName: *comment.User.Login, |
||||
PosterEmail: email, |
||||
Content: *comment.Body, |
||||
Created: *comment.CreatedAt, |
||||
Reactions: reactions, |
||||
}) |
||||
} |
||||
if resp.NextPage == 0 { |
||||
break |
||||
} |
||||
opt.Page = resp.NextPage |
||||
} |
||||
return allComments, nil |
||||
} |
||||
|
||||
// GetPullRequests returns pull requests according start and limit
|
||||
func (g *GithubDownloaderV3) GetPullRequests(start, limit int) ([]*base.PullRequest, error) { |
||||
opt := &github.PullRequestListOptions{ |
||||
Sort: "created", |
||||
Direction: "asc", |
||||
State: "all", |
||||
ListOptions: github.ListOptions{ |
||||
PerPage: 100, |
||||
}, |
||||
} |
||||
var allPRs = make([]*base.PullRequest, 0, 100) |
||||
for { |
||||
prs, resp, err := g.client.PullRequests.List(g.ctx, g.repoOwner, g.repoName, opt) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error while listing repos: %v", err) |
||||
} |
||||
for _, pr := range prs { |
||||
var body string |
||||
if pr.Body != nil { |
||||
body = *pr.Body |
||||
} |
||||
var milestone string |
||||
if pr.Milestone != nil { |
||||
milestone = *pr.Milestone.Title |
||||
} |
||||
var labels = make([]*base.Label, 0, len(pr.Labels)) |
||||
for _, l := range pr.Labels { |
||||
labels = append(labels, convertGithubLabel(l)) |
||||
} |
||||
|
||||
// FIXME: This API missing reactions, we may need another extra request to get reactions
|
||||
|
||||
var email string |
||||
if pr.User.Email != nil { |
||||
email = *pr.User.Email |
||||
} |
||||
var merged bool |
||||
// pr.Merged is not valid, so use MergedAt to test if it's merged
|
||||
if pr.MergedAt != nil { |
||||
merged = true |
||||
} |
||||
|
||||
var headRepoName string |
||||
var cloneURL string |
||||
if pr.Head.Repo != nil { |
||||
headRepoName = *pr.Head.Repo.Name |
||||
cloneURL = *pr.Head.Repo.CloneURL |
||||
} |
||||
var mergeCommitSHA string |
||||
if pr.MergeCommitSHA != nil { |
||||
mergeCommitSHA = *pr.MergeCommitSHA |
||||
} |
||||
|
||||
allPRs = append(allPRs, &base.PullRequest{ |
||||
Title: *pr.Title, |
||||
Number: int64(*pr.Number), |
||||
PosterName: *pr.User.Login, |
||||
PosterEmail: email, |
||||
Content: body, |
||||
Milestone: milestone, |
||||
State: *pr.State, |
||||
Created: *pr.CreatedAt, |
||||
Closed: pr.ClosedAt, |
||||
Labels: labels, |
||||
Merged: merged, |
||||
MergeCommitSHA: mergeCommitSHA, |
||||
MergedTime: pr.MergedAt, |
||||
IsLocked: pr.ActiveLockReason != nil, |
||||
Head: base.PullRequestBranch{ |
||||
Ref: *pr.Head.Ref, |
||||
SHA: *pr.Head.SHA, |
||||
RepoName: headRepoName, |
||||
OwnerName: *pr.Head.User.Login, |
||||
CloneURL: cloneURL, |
||||
}, |
||||
Base: base.PullRequestBranch{ |
||||
Ref: *pr.Base.Ref, |
||||
SHA: *pr.Base.SHA, |
||||
RepoName: *pr.Base.Repo.Name, |
||||
OwnerName: *pr.Base.User.Login, |
||||
}, |
||||
PatchURL: *pr.PatchURL, |
||||
}) |
||||
if len(allPRs) >= limit { |
||||
return allPRs, nil |
||||
} |
||||
} |
||||
if resp.NextPage == 0 { |
||||
break |
||||
} |
||||
opt.Page = resp.NextPage |
||||
} |
||||
return allPRs, nil |
||||
} |
@ -0,0 +1,448 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
"code.gitea.io/gitea/modules/migrations/base" |
||||
|
||||
"github.com/stretchr/testify/assert" |
||||
) |
||||
|
||||
func assertMilestoneEqual(t *testing.T, title, dueOn, created, updated, closed, state string, ms *base.Milestone) { |
||||
var tmPtr *time.Time |
||||
if dueOn != "" { |
||||
tm, err := time.Parse("2006-01-02 15:04:05 -0700 MST", dueOn) |
||||
assert.NoError(t, err) |
||||
tmPtr = &tm |
||||
} |
||||
var ( |
||||
createdTM time.Time |
||||
updatedTM *time.Time |
||||
closedTM *time.Time |
||||
) |
||||
if created != "" { |
||||
var err error |
||||
createdTM, err = time.Parse("2006-01-02 15:04:05 -0700 MST", created) |
||||
assert.NoError(t, err) |
||||
} |
||||
if updated != "" { |
||||
updatedTemp, err := time.Parse("2006-01-02 15:04:05 -0700 MST", updated) |
||||
assert.NoError(t, err) |
||||
updatedTM = &updatedTemp |
||||
} |
||||
if closed != "" { |
||||
closedTemp, err := time.Parse("2006-01-02 15:04:05 -0700 MST", closed) |
||||
assert.NoError(t, err) |
||||
closedTM = &closedTemp |
||||
} |
||||
|
||||
assert.EqualValues(t, &base.Milestone{ |
||||
Title: title, |
||||
Deadline: tmPtr, |
||||
State: state, |
||||
Created: createdTM, |
||||
Updated: updatedTM, |
||||
Closed: closedTM, |
||||
}, ms) |
||||
} |
||||
|
||||
func assertLabelEqual(t *testing.T, name, color string, label *base.Label) { |
||||
assert.EqualValues(t, &base.Label{ |
||||
Name: name, |
||||
Color: color, |
||||
}, label) |
||||
} |
||||
|
||||
func TestGitHubDownloadRepo(t *testing.T) { |
||||
downloader := NewGithubDownloaderV3("", "", "go-gitea", "gitea") |
||||
repo, err := downloader.GetRepoInfo() |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, &base.Repository{ |
||||
Name: "gitea", |
||||
Owner: "go-gitea", |
||||
Description: "Git with a cup of tea, painless self-hosted git service", |
||||
CloneURL: "https://github.com/go-gitea/gitea.git", |
||||
}, repo) |
||||
|
||||
milestones, err := downloader.GetMilestones() |
||||
assert.NoError(t, err) |
||||
// before this tool release, we have 39 milestones on github.com/go-gitea/gitea
|
||||
assert.True(t, len(milestones) >= 39) |
||||
|
||||
for _, milestone := range milestones { |
||||
switch milestone.Title { |
||||
case "1.0.0": |
||||
assertMilestoneEqual(t, "1.0.0", "2016-12-23 08:00:00 +0000 UTC", |
||||
"2016-11-02 18:06:55 +0000 UTC", |
||||
"2016-12-29 10:26:00 +0000 UTC", |
||||
"2016-12-24 00:40:56 +0000 UTC", |
||||
"closed", milestone) |
||||
case "1.1.0": |
||||
assertMilestoneEqual(t, "1.1.0", "2017-02-24 08:00:00 +0000 UTC", |
||||
"2016-11-03 08:40:10 +0000 UTC", |
||||
"2017-06-15 05:04:36 +0000 UTC", |
||||
"2017-03-09 21:22:21 +0000 UTC", |
||||
"closed", milestone) |
||||
case "1.2.0": |
||||
assertMilestoneEqual(t, "1.2.0", "2017-04-24 07:00:00 +0000 UTC", |
||||
"2016-11-03 08:40:15 +0000 UTC", |
||||
"2017-12-10 02:43:29 +0000 UTC", |
||||
"2017-10-12 08:24:28 +0000 UTC", |
||||
"closed", milestone) |
||||
case "1.3.0": |
||||
assertMilestoneEqual(t, "1.3.0", "2017-11-29 08:00:00 +0000 UTC", |
||||
"2017-03-03 08:08:59 +0000 UTC", |
||||
"2017-12-04 07:48:44 +0000 UTC", |
||||
"2017-11-29 18:39:00 +0000 UTC", |
||||
"closed", milestone) |
||||
case "1.4.0": |
||||
assertMilestoneEqual(t, "1.4.0", "2018-01-25 08:00:00 +0000 UTC", |
||||
"2017-08-23 11:02:37 +0000 UTC", |
||||
"2018-03-25 20:01:56 +0000 UTC", |
||||
"2018-03-25 20:01:56 +0000 UTC", |
||||
"closed", milestone) |
||||
case "1.5.0": |
||||
assertMilestoneEqual(t, "1.5.0", "2018-06-15 07:00:00 +0000 UTC", |
||||
"2017-12-30 04:21:56 +0000 UTC", |
||||
"2018-09-05 16:34:22 +0000 UTC", |
||||
"2018-08-11 08:45:01 +0000 UTC", |
||||
"closed", milestone) |
||||
case "1.6.0": |
||||
assertMilestoneEqual(t, "1.6.0", "2018-09-25 07:00:00 +0000 UTC", |
||||
"2018-05-11 05:37:01 +0000 UTC", |
||||
"2019-01-27 19:21:22 +0000 UTC", |
||||
"2018-11-23 13:23:16 +0000 UTC", |
||||
"closed", milestone) |
||||
case "1.7.0": |
||||
assertMilestoneEqual(t, "1.7.0", "2018-12-25 08:00:00 +0000 UTC", |
||||
"2018-08-28 14:20:14 +0000 UTC", |
||||
"2019-01-27 11:30:24 +0000 UTC", |
||||
"2019-01-23 08:58:23 +0000 UTC", |
||||
"closed", milestone) |
||||
} |
||||
} |
||||
|
||||
labels, err := downloader.GetLabels() |
||||
assert.NoError(t, err) |
||||
assert.True(t, len(labels) >= 48) |
||||
for _, l := range labels { |
||||
switch l.Name { |
||||
case "backport/v1.7": |
||||
assertLabelEqual(t, "backport/v1.7", "fbca04", l) |
||||
case "backport/v1.8": |
||||
assertLabelEqual(t, "backport/v1.8", "fbca04", l) |
||||
case "kind/api": |
||||
assertLabelEqual(t, "kind/api", "5319e7", l) |
||||
case "kind/breaking": |
||||
assertLabelEqual(t, "kind/breaking", "fbca04", l) |
||||
case "kind/bug": |
||||
assertLabelEqual(t, "kind/bug", "ee0701", l) |
||||
case "kind/docs": |
||||
assertLabelEqual(t, "kind/docs", "c2e0c6", l) |
||||
case "kind/enhancement": |
||||
assertLabelEqual(t, "kind/enhancement", "84b6eb", l) |
||||
case "kind/feature": |
||||
assertLabelEqual(t, "kind/feature", "006b75", l) |
||||
} |
||||
} |
||||
|
||||
releases, err := downloader.GetReleases() |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, []*base.Release{ |
||||
{ |
||||
TagName: "v0.9.99", |
||||
TargetCommitish: "master", |
||||
Name: "fork", |
||||
Body: "Forked source from Gogs into Gitea\n", |
||||
Created: time.Date(2016, 10, 17, 02, 17, 59, 0, time.UTC), |
||||
Published: time.Date(2016, 11, 17, 15, 37, 0, 0, time.UTC), |
||||
}, |
||||
}, releases[len(releases)-1:]) |
||||
|
||||
// downloader.GetIssues()
|
||||
issues, err := downloader.GetIssues(0, 3) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 3, len(issues)) |
||||
var ( |
||||
closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC) |
||||
) |
||||
assert.EqualValues(t, []*base.Issue{ |
||||
{ |
||||
Number: 6, |
||||
Title: "Contribution system: History heatmap for user", |
||||
Content: "Hi guys,\r\n\r\nI think that is a possible feature, a history heatmap similar to github or gitlab.\r\nActually exists a plugin called Calendar HeatMap. I used this on mine project to heat application log and worked fine here.\r\nThen, is only a idea, what you think? :)\r\n\r\nhttp://cal-heatmap.com/\r\nhttps://github.com/wa0x6e/cal-heatmap\r\n\r\nReference: https://github.com/gogits/gogs/issues/1640", |
||||
Milestone: "1.7.0", |
||||
PosterName: "joubertredrat", |
||||
State: "closed", |
||||
Created: time.Date(2016, 11, 02, 18, 51, 55, 0, time.UTC), |
||||
Labels: []*base.Label{ |
||||
{ |
||||
Name: "kind/feature", |
||||
Color: "006b75", |
||||
}, |
||||
{ |
||||
Name: "kind/ui", |
||||
Color: "fef2c0", |
||||
}, |
||||
}, |
||||
Reactions: &base.Reactions{ |
||||
TotalCount: 0, |
||||
PlusOne: 0, |
||||
MinusOne: 0, |
||||
Laugh: 0, |
||||
Confused: 0, |
||||
Heart: 0, |
||||
Hooray: 0, |
||||
}, |
||||
Closed: &closed1, |
||||
}, |
||||
{ |
||||
Number: 7, |
||||
Title: "display page revisions on wiki", |
||||
Content: "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991", |
||||
Milestone: "1.x.x", |
||||
PosterName: "joubertredrat", |
||||
State: "open", |
||||
Created: time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC), |
||||
Labels: []*base.Label{ |
||||
{ |
||||
Name: "kind/feature", |
||||
Color: "006b75", |
||||
}, |
||||
{ |
||||
Name: "reviewed/confirmed", |
||||
Color: "8d9b12", |
||||
Description: "Issue has been reviewed and confirmed to be present or accepted to be implemented", |
||||
}, |
||||
}, |
||||
Reactions: &base.Reactions{ |
||||
TotalCount: 6, |
||||
PlusOne: 5, |
||||
MinusOne: 0, |
||||
Laugh: 0, |
||||
Confused: 1, |
||||
Heart: 0, |
||||
Hooray: 0, |
||||
}, |
||||
}, |
||||
{ |
||||
Number: 8, |
||||
Title: "audit logs", |
||||
Content: "Hi,\r\n\r\nI think that is good idea to have user operation log to admin see what the user is doing at Gogs. Similar to example below\r\n\r\n| user | operation | information |\r\n| --- | --- | --- |\r\n| joubertredrat | repo.create | Create repo MyProjectData |\r\n| joubertredrat | user.settings | Edit settings |\r\n| tboerger | repo.fork | Create Fork from MyProjectData to ForkMyProjectData |\r\n| bkcsoft | repo.remove | Remove repo MySource |\r\n| tboerger | admin.auth | Edit auth LDAP org-connection |\r\n\r\nThis resource can be used on user page too, as user activity, set that log row is public (repo._) or private (user._, admin.*) and display only public activity.\r\n\r\nWhat you think?\r\n\r\n[Chat summary from March 14, 2017](https://github.com/go-gitea/gitea/issues/8#issuecomment-286463807)\r\n\r\nReferences:\r\nhttps://github.com/gogits/gogs/issues/3016", |
||||
Milestone: "1.x.x", |
||||
PosterName: "joubertredrat", |
||||
State: "open", |
||||
Created: time.Date(2016, 11, 02, 18, 59, 20, 0, time.UTC), |
||||
Labels: []*base.Label{ |
||||
{ |
||||
Name: "kind/feature", |
||||
Color: "006b75", |
||||
}, |
||||
{ |
||||
Name: "kind/proposal", |
||||
Color: "5319e7", |
||||
}, |
||||
}, |
||||
Reactions: &base.Reactions{ |
||||
TotalCount: 9, |
||||
PlusOne: 8, |
||||
MinusOne: 0, |
||||
Laugh: 0, |
||||
Confused: 0, |
||||
Heart: 1, |
||||
Hooray: 0, |
||||
}, |
||||
}, |
||||
}, issues) |
||||
|
||||
// downloader.GetComments()
|
||||
comments, err := downloader.GetComments(6) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 35, len(comments)) |
||||
assert.EqualValues(t, []*base.Comment{ |
||||
{ |
||||
PosterName: "bkcsoft", |
||||
Created: time.Date(2016, 11, 02, 18, 59, 48, 0, time.UTC), |
||||
Content: `I would prefer a solution that is in the backend, unless it's required to have it update without reloading. Unfortunately I can't seem to find anything that does that :unamused:
|
||||
|
||||
Also this would _require_ caching, since it will fetch huge amounts of data from disk... |
||||
`, |
||||
Reactions: &base.Reactions{ |
||||
TotalCount: 2, |
||||
PlusOne: 2, |
||||
MinusOne: 0, |
||||
Laugh: 0, |
||||
Confused: 0, |
||||
Heart: 0, |
||||
Hooray: 0, |
||||
}, |
||||
}, |
||||
{ |
||||
PosterName: "joubertredrat", |
||||
Created: time.Date(2016, 11, 02, 19, 16, 56, 0, time.UTC), |
||||
Content: `Yes, this plugin build on front-end, with backend I don't know too, but we can consider make component for this. |
||||
|
||||
In my case I use ajax to get data, but build on frontend anyway |
||||
`, |
||||
Reactions: &base.Reactions{ |
||||
TotalCount: 0, |
||||
PlusOne: 0, |
||||
MinusOne: 0, |
||||
Laugh: 0, |
||||
Confused: 0, |
||||
Heart: 0, |
||||
Hooray: 0, |
||||
}, |
||||
}, |
||||
{ |
||||
PosterName: "xinity", |
||||
Created: time.Date(2016, 11, 03, 13, 04, 56, 0, time.UTC), |
||||
Content: `following @bkcsoft retention strategy in cache is a must if we don't want gitea to waste ressources. |
||||
something like in the latest 15days could be enough don't you think ? |
||||
`, |
||||
Reactions: &base.Reactions{ |
||||
TotalCount: 2, |
||||
PlusOne: 2, |
||||
MinusOne: 0, |
||||
Laugh: 0, |
||||
Confused: 0, |
||||
Heart: 0, |
||||
Hooray: 0, |
||||
}, |
||||
}, |
||||
}, comments[:3]) |
||||
|
||||
// downloader.GetPullRequests()
|
||||
prs, err := downloader.GetPullRequests(0, 3) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 3, len(prs)) |
||||
|
||||
closed1 = time.Date(2016, 11, 02, 18, 22, 21, 0, time.UTC) |
||||
var ( |
||||
closed2 = time.Date(2016, 11, 03, 8, 06, 27, 0, time.UTC) |
||||
closed3 = time.Date(2016, 11, 02, 18, 22, 31, 0, time.UTC) |
||||
) |
||||
|
||||
var ( |
||||
merged1 = time.Date(2016, 11, 02, 18, 22, 21, 0, time.UTC) |
||||
merged2 = time.Date(2016, 11, 03, 8, 06, 27, 0, time.UTC) |
||||
merged3 = time.Date(2016, 11, 02, 18, 22, 31, 0, time.UTC) |
||||
) |
||||
assert.EqualValues(t, []*base.PullRequest{ |
||||
{ |
||||
Number: 1, |
||||
Title: "Rename import paths: \"github.com/gogits/gogs\" -> \"github.com/go-gitea/gitea\"", |
||||
Content: "", |
||||
Milestone: "1.0.0", |
||||
PosterName: "andreynering", |
||||
State: "closed", |
||||
Created: time.Date(2016, 11, 02, 17, 01, 19, 0, time.UTC), |
||||
Labels: []*base.Label{ |
||||
{ |
||||
Name: "kind/enhancement", |
||||
Color: "84b6eb", |
||||
}, |
||||
{ |
||||
Name: "lgtm/done", |
||||
Color: "0e8a16", |
||||
}, |
||||
}, |
||||
PatchURL: "https://github.com/go-gitea/gitea/pull/1.patch", |
||||
Head: base.PullRequestBranch{ |
||||
Ref: "import-paths", |
||||
SHA: "1b0ec3208db8501acba44a137c009a5a126ebaa9", |
||||
OwnerName: "andreynering", |
||||
}, |
||||
Base: base.PullRequestBranch{ |
||||
Ref: "master", |
||||
SHA: "6bcff7828f117af8d51285ce3acba01a7e40a867", |
||||
OwnerName: "go-gitea", |
||||
RepoName: "gitea", |
||||
}, |
||||
Closed: &closed1, |
||||
Merged: true, |
||||
MergedTime: &merged1, |
||||
MergeCommitSHA: "142d35e8d2baec230ddb565d1265940d59141fab", |
||||
}, |
||||
{ |
||||
Number: 2, |
||||
Title: "Fix sender of issue notifications", |
||||
Content: "It is the FROM field in mailer configuration that needs be used,\r\nnot the USER field, which is for authentication.\r\n\r\nMigrated from https://github.com/gogits/gogs/pull/3616\r\n", |
||||
Milestone: "1.0.0", |
||||
PosterName: "strk", |
||||
State: "closed", |
||||
Created: time.Date(2016, 11, 02, 17, 24, 19, 0, time.UTC), |
||||
Labels: []*base.Label{ |
||||
{ |
||||
Name: "kind/bug", |
||||
Color: "ee0701", |
||||
}, |
||||
{ |
||||
Name: "lgtm/done", |
||||
Color: "0e8a16", |
||||
}, |
||||
}, |
||||
PatchURL: "https://github.com/go-gitea/gitea/pull/2.patch", |
||||
Head: base.PullRequestBranch{ |
||||
Ref: "proper-from-on-issue-mail", |
||||
SHA: "af03d00780a6ee70c58e135c6679542cde4f8d50", |
||||
RepoName: "gogs", |
||||
OwnerName: "strk", |
||||
CloneURL: "https://github.com/strk/gogs.git", |
||||
}, |
||||
Base: base.PullRequestBranch{ |
||||
Ref: "develop", |
||||
SHA: "5c5424301443ffa3659737d12de48ab1dfe39a00", |
||||
OwnerName: "go-gitea", |
||||
RepoName: "gitea", |
||||
}, |
||||
Closed: &closed2, |
||||
Merged: true, |
||||
MergedTime: &merged2, |
||||
MergeCommitSHA: "d8de2beb5b92d02a0597ba7c7803839380666653", |
||||
}, |
||||
{ |
||||
Number: 3, |
||||
Title: "Use proper url for libravatar dep", |
||||
Content: "Fetch go-libravatar from its official source, rather than from an unmaintained fork\r\n", |
||||
Milestone: "1.0.0", |
||||
PosterName: "strk", |
||||
State: "closed", |
||||
Created: time.Date(2016, 11, 02, 17, 34, 31, 0, time.UTC), |
||||
Labels: []*base.Label{ |
||||
{ |
||||
Name: "kind/enhancement", |
||||
Color: "84b6eb", |
||||
}, |
||||
{ |
||||
Name: "lgtm/done", |
||||
Color: "0e8a16", |
||||
}, |
||||
}, |
||||
PatchURL: "https://github.com/go-gitea/gitea/pull/3.patch", |
||||
Head: base.PullRequestBranch{ |
||||
Ref: "libravatar-proper-url", |
||||
SHA: "d59a48a2550abd4129b96d38473941b895a4859b", |
||||
RepoName: "gogs", |
||||
OwnerName: "strk", |
||||
CloneURL: "https://github.com/strk/gogs.git", |
||||
}, |
||||
Base: base.PullRequestBranch{ |
||||
Ref: "develop", |
||||
SHA: "6bcff7828f117af8d51285ce3acba01a7e40a867", |
||||
OwnerName: "go-gitea", |
||||
RepoName: "gitea", |
||||
}, |
||||
Closed: &closed3, |
||||
Merged: true, |
||||
MergedTime: &merged3, |
||||
MergeCommitSHA: "5c5424301443ffa3659737d12de48ab1dfe39a00", |
||||
}, |
||||
}, prs) |
||||
} |
@ -0,0 +1,17 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"path/filepath" |
||||
"testing" |
||||
|
||||
"code.gitea.io/gitea/models" |
||||
) |
||||
|
||||
func TestMain(m *testing.M) { |
||||
models.MainTest(m, filepath.Join("..", "..")) |
||||
} |
@ -0,0 +1,205 @@ |
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 Jonas Franz. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"code.gitea.io/gitea/models" |
||||
"code.gitea.io/gitea/modules/log" |
||||
"code.gitea.io/gitea/modules/migrations/base" |
||||
) |
||||
|
||||
// MigrateOptions is equal to base.MigrateOptions
|
||||
type MigrateOptions = base.MigrateOptions |
||||
|
||||
var ( |
||||
factories []base.DownloaderFactory |
||||
) |
||||
|
||||
// RegisterDownloaderFactory registers a downloader factory
|
||||
func RegisterDownloaderFactory(factory base.DownloaderFactory) { |
||||
factories = append(factories, factory) |
||||
} |
||||
|
||||
// MigrateRepository migrate repository according MigrateOptions
|
||||
func MigrateRepository(doer *models.User, ownerName string, opts base.MigrateOptions) (*models.Repository, error) { |
||||
var ( |
||||
downloader base.Downloader |
||||
uploader = NewGiteaLocalUploader(doer, ownerName, opts.Name) |
||||
) |
||||
|
||||
for _, factory := range factories { |
||||
if match, err := factory.Match(opts); err != nil { |
||||
return nil, err |
||||
} else if match { |
||||
downloader, err = factory.New(opts) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
break |
||||
} |
||||
} |
||||
|
||||
if downloader == nil { |
||||
opts.Wiki = true |
||||
opts.Milestones = false |
||||
opts.Labels = false |
||||
opts.Releases = false |
||||
opts.Comments = false |
||||
opts.Issues = false |
||||
opts.PullRequests = false |
||||
downloader = NewPlainGitDownloader(ownerName, opts.Name, opts.RemoteURL) |
||||
log.Trace("Will migrate from git: %s", opts.RemoteURL) |
||||
} |
||||
|
||||
if err := migrateRepository(downloader, uploader, opts); err != nil { |
||||
if err1 := uploader.Rollback(); err1 != nil { |
||||
log.Error("rollback failed: %v", err1) |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
return uploader.repo, nil |
||||
} |
||||
|
||||
// migrateRepository will download informations and upload to Uploader, this is a simple
|
||||
// process for small repository. For a big repository, save all the data to disk
|
||||
// before upload is better
|
||||
func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions) error { |
||||
repo, err := downloader.GetRepoInfo() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
repo.IsPrivate = opts.Private |
||||
repo.IsMirror = opts.Mirror |
||||
log.Trace("migrating git data") |
||||
if err := uploader.CreateRepo(repo, opts.Wiki); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if opts.Milestones { |
||||
log.Trace("migrating milestones") |
||||
milestones, err := downloader.GetMilestones() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
for _, milestone := range milestones { |
||||
if err := uploader.CreateMilestone(milestone); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
} |
||||
|
||||
if opts.Labels { |
||||
log.Trace("migrating labels") |
||||
labels, err := downloader.GetLabels() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
for _, label := range labels { |
||||
if err := uploader.CreateLabel(label); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
} |
||||
|
||||
if opts.Releases { |
||||
log.Trace("migrating releases") |
||||
releases, err := downloader.GetReleases() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
for _, release := range releases { |
||||
if err := uploader.CreateRelease(release); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
} |
||||
|
||||
if opts.Issues { |
||||
log.Trace("migrating issues and comments") |
||||
for { |
||||
issues, err := downloader.GetIssues(0, 100) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
for _, issue := range issues { |
||||
if !opts.IgnoreIssueAuthor { |
||||
issue.Content = fmt.Sprintf("Author: @%s \n\n%s", issue.PosterName, issue.Content) |
||||
} |
||||
|
||||
if err := uploader.CreateIssue(issue); err != nil { |
||||
return err |
||||
} |
||||
|
||||
if !opts.Comments { |
||||
continue |
||||
} |
||||
|
||||
comments, err := downloader.GetComments(issue.Number) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
for _, comment := range comments { |
||||
if !opts.IgnoreIssueAuthor { |
||||
comment.Content = fmt.Sprintf("Author: @%s \n\n%s", comment.PosterName, comment.Content) |
||||
} |
||||
if err := uploader.CreateComment(issue.Number, comment); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
} |
||||
|
||||
if len(issues) < 100 { |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
if opts.PullRequests { |
||||
log.Trace("migrating pull requests and comments") |
||||
for { |
||||
prs, err := downloader.GetPullRequests(0, 100) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
for _, pr := range prs { |
||||
if !opts.IgnoreIssueAuthor { |
||||
pr.Content = fmt.Sprintf("Author: @%s \n\n%s", pr.PosterName, pr.Content) |
||||
} |
||||
if err := uploader.CreatePullRequest(pr); err != nil { |
||||
return err |
||||
} |
||||
if !opts.Comments { |
||||
continue |
||||
} |
||||
|
||||
comments, err := downloader.GetComments(pr.Number) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
for _, comment := range comments { |
||||
if !opts.IgnoreIssueAuthor { |
||||
comment.Content = fmt.Sprintf("Author: @%s \n\n%s", comment.PosterName, comment.Content) |
||||
} |
||||
if err := uploader.CreateComment(pr.Number, comment); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
} |
||||
if len(prs) < 100 { |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
@ -0,0 +1,229 @@ |
||||
# This is the official list of go-github authors for copyright purposes. |
||||
# |
||||
# This does not necessarily list everyone who has contributed code, since in |
||||
# some cases, their employer may be the copyright holder. To see the full list |
||||
# of contributors, see the revision history in source control or |
||||
# https://github.com/google/go-github/graphs/contributors. |
||||
# |
||||
# Authors who wish to be recognized in this file should add themselves (or |
||||
# their employer, as appropriate). |
||||
|
||||
178inaba <masahiro.furudate@gmail.com> |
||||
Abhinav Gupta <mail@abhinavg.net> |
||||
Ahmed Hagy <a.akram93@gmail.com> |
||||
Ainsley Chong <ainsley.chong@gmail.com> |
||||
Akeda Bagus <akeda@x-team.com> |
||||
Akhil Mohan <akhilerm@gmail.com> |
||||
Alec Thomas <alec@swapoff.org> |
||||
Aleks Clark <aleks.clark@gmail.com> |
||||
Alex Bramley <a.bramley@gmail.com> |
||||
Alexander Harkness <me@bearbin.net> |
||||
Allen Sun <shlallen1990@gmail.com> |
||||
Amey Sakhadeo <me@ameyms.com> |
||||
Andreas Garnæs <https://github.com/andreas> |
||||
Andrew Ryabchun <aryabchun@mail.ua> |
||||
Andy Grunwald <andygrunwald@gmail.com> |
||||
Andy Hume <andyhume@gmail.com> |
||||
Andy Lindeman <andy@lindeman.io> |
||||
Anshuman Bhartiya <anshuman.bhartiya@gmail.com> |
||||
Antoine <antoine.tu@mail.mcgill.ca> |
||||
Antoine Pelisse <apelisse@gmail.com> |
||||
Anubha Kushwaha <anubha_bt2k14@dtu.ac.in> |
||||
appilon <apilon@hashicorp.com> |
||||
Aravind <aravindkp@outlook.in> |
||||
Arda Kuyumcu <kuyumcuarda@gmail.com> |
||||
Arıl Bozoluk <arilbozoluk@hotmail.com> |
||||
Austin Dizzy <dizzy@wow.com> |
||||
Ben Batha <bhbatha@gmail.com> |
||||
Benjamen Keroack <benjamen@dollarshaveclub.com> |
||||
Beshr Kayali <beshrkayali@gmail.com> |
||||
Beyang Liu <beyang.liu@gmail.com> |
||||
Billy Lynch <wlynch92@gmail.com> |
||||
Björn Häuser <b.haeuser@rebuy.de> |
||||
Brad Harris <bmharris@gmail.com> |
||||
Brad Moylan <moylan.brad@gmail.com> |
||||
Bradley Falzon <brad@teambrad.net> |
||||
Brandon Cook <phylake@gmail.com> |
||||
Brian Egizi <brian@mojotech.com> |
||||
Bryan Boreham <bryan@weave.works> |
||||
Cami Diez <diezcami@gmail.com> |
||||
Carlos Alexandro Becker <caarlos0@gmail.com> |
||||
chandresh-pancholi <chandreshpancholi007@gmail.com> |
||||
Charles Fenwick Elliott <Charles@FenwickElliott.io> |
||||
Charlie Yan <charlieyan08@gmail.com> |
||||
Chris King <chriskingnet@gmail.com> |
||||
Chris Roche <chris@vsco.co> |
||||
Chris Schaefer <chris@dtzq.com> |
||||
Christoph Sassenberg <defsprite@gmail.com> |
||||
Colin Misare <github.com/cmisare> |
||||
Craig Peterson <cpeterson@stackoverflow.com> |
||||
Cristian Maglie <c.maglie@bug.st> |
||||
Daehyeok Mun <daehyeok@gmail.com> |
||||
Daniel Leavitt <daniel.leavitt@gmail.com> |
||||
Daniel Nilsson <daniel.nilsson1989@gmail.com> |
||||
Dave Du Cros <davidducros@gmail.com> |
||||
Dave Henderson <dhenderson@gmail.com> |
||||
David Deng <daviddengcn@gmail.com> |
||||
David Jannotta <djannotta@gmail.com> |
||||
Davide Zipeto <dawez1@gmail.com> |
||||
Dennis Webb <dennis@bluesentryit.com> |
||||
Dhi Aurrahman <diorahman@rockybars.com> |
||||
Diego Lapiduz <diego.lapiduz@cfpb.gov> |
||||
Dmitri Shuralyov <shurcooL@gmail.com> |
||||
dmnlk <seikima2demon@gmail.com> |
||||
Don Petersen <don@donpetersen.net> |
||||
Doug Turner <doug.turner@gmail.com> |
||||
Drew Fradette <drew.fradette@gmail.com> |
||||
Eli Uriegas <seemethere101@gmail.com> |
||||
Elliott Beach <elliott2.71828@gmail.com> |
||||
Emerson Wood <emersonwood94@gmail.com> |
||||
eperm <staffordworrell@gmail.com> |
||||
Erick Fejta <erick@fejta.com> |
||||
erwinvaneyk <erwinvaneyk@gmail.com> |
||||
Fabrice <fabrice.vaillant@student.ecp.fr> |
||||
Felix Geisendörfer <felix@debuggable.com> |
||||
Filippo Valsorda <hi@filippo.io> |
||||
Florian Forster <ff@octo.it> |
||||
Francesc Gil <xescugil@gmail.com> |
||||
Francis <hello@francismakes.com> |
||||
Fredrik Jönsson <fredrik.jonsson@izettle.com> |
||||
Garrett Squire <garrettsquire@gmail.com> |
||||
George Kontridze <george.kontridze@gmail.com> |
||||
Georgy Buranov <gburanov@gmail.com> |
||||
Gnahz <p@oath.pl> |
||||
Google Inc. |
||||
Grachev Mikhail <work@mgrachev.com> |
||||
griffin_stewie <panterathefamilyguy@gmail.com> |
||||
Guillaume Jacquet <guillaume.jacquet@gmail.com> |
||||
Guz Alexander <kalimatas@gmail.com> |
||||
Guðmundur Bjarni Ólafsson <gudmundur@github.com> |
||||
Hanno Hecker <hanno.hecker@zalando.de> |
||||
Hari haran <hariharan.uno@gmail.com> |
||||
haya14busa <hayabusa1419@gmail.com> |
||||
Huy Tr <kingbazoka@gmail.com> |
||||
huydx <doxuanhuy@gmail.com> |
||||
i2bskn <i2bskn@gmail.com> |
||||
Isao Jonas <isao.jonas@gmail.com> |
||||
isqua <isqua@isqua.ru> |
||||
Jameel Haffejee <RC1140@republiccommandos.co.za> |
||||
Jan Kosecki <jan.kosecki91@gmail.com> |
||||
Javier Campanini <jcampanini@palantir.com> |
||||
Jens Rantil <jens.rantil@gmail.com> |
||||
Jeremy Morris <jeremylevanmorris@gmail.com> |
||||
Jesse Newland <jesse@jnewland.com> |
||||
Jihoon Chung <j.c@navercorp.com> |
||||
Jimmi Dyson <jimmidyson@gmail.com> |
||||
Joan Saum <joan.saum@epitech.eu> |
||||
Joe Tsai <joetsai@digital-static.net> |
||||
John Barton <jrbarton@gmail.com> |
||||
John Engelman <john.r.engelman@gmail.com> |
||||
Jordan Sussman <jordansail22@gmail.com> |
||||
Joshua Bezaleel Abednego <joshua.bezaleel@gmail.com> |
||||
JP Phillips <jonphill9@gmail.com> |
||||
jpbelanger-mtl <jp.belanger@gmail.com> |
||||
Juan Basso <jrbasso@gmail.com> |
||||
Julien Garcia Gonzalez <garciagonzalez.julien@gmail.com> |
||||
Julien Rostand <jrostand@users.noreply.github.com> |
||||
Justin Abrahms <justin@abrah.ms> |
||||
Jusung Lee <e.jusunglee@gmail.com> |
||||
jzhoucliqr <jzhou@cliqr.com> |
||||
Katrina Owen <kytrinyx@github.com> |
||||
Kautilya Tripathi < tripathi.kautilya@gmail.com> |
||||
Kautilya Tripathi <tripathi.kautilya@gmail.com> |
||||
Keita Urashima <ursm@ursm.jp> |
||||
Kevin Burke <kev@inburke.com> |
||||
Konrad Malawski <konrad.malawski@project13.pl> |
||||
Kookheon Kwon <kucuny@gmail.com> |
||||
Krzysztof Kowalczyk <kkowalczyk@gmail.com> |
||||
Kshitij Saraogi <KshitijSaraogi@gmail.com> |
||||
kyokomi <kyoko1220adword@gmail.com> |
||||
Lovro Mažgon <lovro.mazgon@gmail.com> |
||||
Lucas Alcantara <lucasalcantaraf@gmail.com> |
||||
Luke Evers <me@lukevers.com> |
||||
Luke Kysow <lkysow@gmail.com> |
||||
Luke Roberts <email@luke-roberts.co.uk> |
||||
Luke Young <luke@hydrantlabs.org> |
||||
Maksim Zhylinski <uzzable@gmail.com> |
||||
Martin-Louis Bright <mlbright@gmail.com> |
||||
Marwan Sulaiman <marwan.sameer@gmail.com> |
||||
Mat Geist <matgeist@gmail.com> |
||||
Matt <alpmatthew@gmail.com> |
||||
Matt Brender <mjbrender@gmail.com> |
||||
Matt Gaunt <matt@gauntface.co.uk> |
||||
Matt Landis <landis.matt@gmail.com> |
||||
Maxime Bury <maxime.bury@gmail.com> |
||||
Michael Spiegel <michael.m.spiegel@gmail.com> |
||||
Michael Tiller <michael.tiller@gmail.com> |
||||
Michał Glapa <michal.glapa@gmail.com> |
||||
Nathan VanBenschoten <nvanbenschoten@gmail.com> |
||||
Navaneeth Suresh <navaneeths1998@gmail.com> |
||||
Neil O'Toole <neilotoole@apache.org> |
||||
Nick Miyake <nmiyake@palantir.com> |
||||
Nick Spragg <nick.spragg@bbc.co.uk> |
||||
Nikhita Raghunath <nikitaraghunath@gmail.com> |
||||
Noah Zoschke <noah+sso2@convox.com> |
||||
ns-cweber <cweber@narrativescience.com> |
||||
Oleg Kovalov <iamolegkovalov@gmail.com> |
||||
Ondřej Kupka <ondra.cap@gmail.com> |
||||
Palash Nigam <npalash25@gmail.com> |
||||
Panagiotis Moustafellos <pmoust@gmail.com> |
||||
Parham Alvani <parham.alvani@gmail.com> |
||||
Parker Moore <parkrmoore@gmail.com> |
||||
parkhyukjun89 <park.hyukjun89@gmail.com> |
||||
Pavel Shtanko <pavel.shtanko@gmail.com> |
||||
Pete Wagner <thepwagner@github.com> |
||||
Petr Shevtsov <petr.shevtsov@gmail.com> |
||||
Pierre Carrier <pierre@meteor.com> |
||||
Piotr Zurek <p.zurek@gmail.com> |
||||
Quinn Slack <qslack@qslack.com> |
||||
Rackspace US, Inc. |
||||
Radek Simko <radek.simko@gmail.com> |
||||
Radliński Ignacy <radlinsk@student.agh.edu.pl> |
||||
Rajendra arora <rajendraarora16@yahoo.com> |
||||
RaviTeja Pothana <ravi-teja@live.com> |
||||
rc1140 <jameel@republiccommandos.co.za> |
||||
Red Hat, Inc. |
||||
Rob Figueiredo <robfig@yext.com> |
||||
Rohit Upadhyay <urohit011@gmail.com> |
||||
Ronak Jain <ronakjain@outlook.in> |
||||
Ruben Vereecken <rubenvereecken@gmail.com> |
||||
Ryan Leung <rleungx@gmail.com> |
||||
Ryan Lower <rpjlower@gmail.com> |
||||
Sahil Dua <sahildua2305@gmail.com> |
||||
saisi <saisi@users.noreply.github.com> |
||||
Sam Minnée <sam@silverstripe.com> |
||||
Sandeep Sukhani <sandeep.d.sukhani@gmail.com> |
||||
Sander van Harmelen <svanharmelen@schubergphilis.com> |
||||
Sanket Payghan <sanket.payghan8@gmail.com> |
||||
Sarasa Kisaragi <lingsamuelgrace@gmail.com> |
||||
Sean Wang <sean@decrypted.org> |
||||
Sebastian Mandrean <sebastian.mandrean@gmail.com> |
||||
Sebastian Mæland Pedersen <sem.pedersen@stud.uis.no> |
||||
Sergey Romanov <xxsmotur@gmail.com> |
||||
Sevki <s@sevki.org> |
||||
Shagun Khemka <shagun.khemka60@gmail.com> |
||||
shakeelrao <shakeelrao79@gmail.com> |
||||
Shawn Catanzarite <me@shawncatz.com> |
||||
Shawn Smith <shawnpsmith@gmail.com> |
||||
sona-tar <sona.zip@gmail.com> |
||||
SoundCloud, Ltd. |
||||
Sridhar Mocherla <srmocher@microsoft.com> |
||||
Stian Eikeland <stian@eikeland.se> |
||||
Tasya Aditya Rukmana <tadityar@gmail.com> |
||||
Thomas Bruyelle <thomas.bruyelle@gmail.com> |
||||
Timothée Peignier <timothee.peignier@tryphon.org> |
||||
Trey Tacon <ttacon@gmail.com> |
||||
ttacon <ttacon@gmail.com> |
||||
Varadarajan Aravamudhan <varadaraajan@gmail.com> |
||||
Victor Castell <victor@victorcastell.com> |
||||
Victor Vrantchan <vrancean+github@gmail.com> |
||||
Vlad Ungureanu <vladu@palantir.com> |
||||
Wasim Thabraze <wasim@thabraze.me> |
||||
Will Maier <wcmaier@gmail.com> |
||||
William Bailey <mail@williambailey.org.uk> |
||||
xibz <impactbchang@gmail.com> |
||||
Yann Malet <yann.malet@gmail.com> |
||||
Yannick Utard <yannickutard@gmail.com> |
||||
Yicheng Qin <qycqycqycqycqyc@gmail.com> |
||||
Yumikiyo Osanai <yumios.art@gmail.com> |
||||
Zach Latta <zach@zachlatta.com> |
@ -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,215 @@ |
||||
// 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" |
||||
) |
||||
|
||||
// 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,137 @@ |
||||
// 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" |
||||
) |
||||
|
||||
// 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 APIs fully launch
|
||||
acceptHeaders := []string{mediaTypeStarringPreview, mediaTypeTopicsPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var repos []*StarredRepository |
||||
resp, err := s.client.Do(ctx, req, &repos) |
||||
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,230 @@ |
||||
// 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"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
Owner *User `json:"owner,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
ExternalURL *string `json:"external_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
} |
||||
|
||||
// InstallationToken represents an installation token.
|
||||
type InstallationToken struct { |
||||
Token *string `json:"token,omitempty"` |
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"` |
||||
} |
||||
|
||||
// InstallationPermissions lists the permissions for metadata, contents, issues and single file for an installation.
|
||||
type InstallationPermissions struct { |
||||
Metadata *string `json:"metadata,omitempty"` |
||||
Contents *string `json:"contents,omitempty"` |
||||
Issues *string `json:"issues,omitempty"` |
||||
SingleFile *string `json:"single_file,omitempty"` |
||||
} |
||||
|
||||
// Installation represents a GitHub Apps installation.
|
||||
type Installation struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
AppID *int64 `json:"app_id,omitempty"` |
||||
TargetID *int64 `json:"target_id,omitempty"` |
||||
Account *User `json:"account,omitempty"` |
||||
AccessTokensURL *string `json:"access_tokens_url,omitempty"` |
||||
RepositoriesURL *string `json:"repositories_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
TargetType *string `json:"target_type,omitempty"` |
||||
SingleFileName *string `json:"single_file_name,omitempty"` |
||||
RepositorySelection *string `json:"repository_selection,omitempty"` |
||||
Events []string `json:"events,omitempty"` |
||||
Permissions *InstallationPermissions `json:"permissions,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
} |
||||
|
||||
func (i Installation) String() string { |
||||
return Stringify(i) |
||||
} |
||||
|
||||
// Get a single GitHub App. Passing the empty string will get
|
||||
// the authenticated GitHub App.
|
||||
//
|
||||
// Note: appSlug is just the URL-friendly name of your GitHub App.
|
||||
// You can find this on the settings page for your GitHub App
|
||||
// (e.g., https://github.com/settings/apps/:app_slug).
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#get-a-single-github-app
|
||||
func (s *AppsService) Get(ctx context.Context, appSlug string) (*App, *Response, error) { |
||||
var u string |
||||
if appSlug != "" { |
||||
u = fmt.Sprintf("apps/%v", appSlug) |
||||
} else { |
||||
u = "app" |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
app := new(App) |
||||
resp, err := s.client.Do(ctx, req, app) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return app, resp, nil |
||||
} |
||||
|
||||
// ListInstallations lists the installations that the current GitHub App has.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#find-installations
|
||||
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) { |
||||
return s.getInstallation(ctx, fmt.Sprintf("app/installations/%v", id)) |
||||
} |
||||
|
||||
// ListUserInstallations lists installations that are accessible to the authenticated user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#list-installations-for-user
|
||||
func (s *AppsService) ListUserInstallations(ctx context.Context, opt *ListOptions) ([]*Installation, *Response, error) { |
||||
u, err := addOptions("user/installations", opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
var i struct { |
||||
Installations []*Installation `json:"installations"` |
||||
} |
||||
resp, err := s.client.Do(ctx, req, &i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i.Installations, resp, nil |
||||
} |
||||
|
||||
// CreateInstallationToken creates a new installation token.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#create-a-new-installation-token
|
||||
func (s *AppsService) CreateInstallationToken(ctx context.Context, id int64) (*InstallationToken, *Response, error) { |
||||
u := fmt.Sprintf("app/installations/%v/access_tokens", id) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
t := new(InstallationToken) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return t, resp, nil |
||||
} |
||||
|
||||
// FindOrganizationInstallation finds the organization's installation information.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#find-organization-installation
|
||||
func (s *AppsService) FindOrganizationInstallation(ctx context.Context, org string) (*Installation, *Response, error) { |
||||
return s.getInstallation(ctx, fmt.Sprintf("orgs/%v/installation", org)) |
||||
} |
||||
|
||||
// FindRepositoryInstallation finds the repository's installation information.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation
|
||||
func (s *AppsService) FindRepositoryInstallation(ctx context.Context, owner, repo string) (*Installation, *Response, error) { |
||||
return s.getInstallation(ctx, fmt.Sprintf("repos/%v/%v/installation", owner, repo)) |
||||
} |
||||
|
||||
// FindRepositoryInstallationByID finds the repository's installation information.
|
||||
//
|
||||
// Note: FindRepositoryInstallationByID uses the undocumented GitHub API endpoint /repositories/:id/installation.
|
||||
func (s *AppsService) FindRepositoryInstallationByID(ctx context.Context, id int64) (*Installation, *Response, error) { |
||||
return s.getInstallation(ctx, fmt.Sprintf("repositories/%d/installation", id)) |
||||
} |
||||
|
||||
// FindUserInstallation finds the user's installation information.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/#find-repository-installation
|
||||
func (s *AppsService) FindUserInstallation(ctx context.Context, user string) (*Installation, *Response, error) { |
||||
return s.getInstallation(ctx, fmt.Sprintf("users/%v/installation", user)) |
||||
} |
||||
|
||||
func (s *AppsService) getInstallation(ctx context.Context, url string) (*Installation, *Response, error) { |
||||
req, err := s.client.NewRequest("GET", url, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
i := new(Installation) |
||||
resp, err := s.client.Do(ctx, req, i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i, resp, nil |
||||
} |
@ -0,0 +1,103 @@ |
||||
// 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("user/installations/%v/repositories/%v", instID, repoID) |
||||
req, err := s.client.NewRequest("PUT", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
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("user/installations/%v/repositories/%v", instID, repoID) |
||||
req, err := s.client.NewRequest("DELETE", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
req.Header.Set("Accept", mediaTypeIntegrationPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,183 @@ |
||||
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
) |
||||
|
||||
// MarketplaceService handles communication with the marketplace related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
|
||||
type MarketplaceService struct { |
||||
client *Client |
||||
// Stubbed controls whether endpoints that return stubbed data are used
|
||||
// instead of production endpoints. Stubbed data is fake data that's useful
|
||||
// for testing your GitHub Apps. Stubbed data is hard-coded and will not
|
||||
// change based on actual subscriptions.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
|
||||
Stubbed bool |
||||
} |
||||
|
||||
// MarketplacePlan represents a GitHub Apps Marketplace Listing Plan.
|
||||
type MarketplacePlan struct { |
||||
URL *string `json:"url,omitempty"` |
||||
AccountsURL *string `json:"accounts_url,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
MonthlyPriceInCents *int `json:"monthly_price_in_cents,omitempty"` |
||||
YearlyPriceInCents *int `json:"yearly_price_in_cents,omitempty"` |
||||
// The pricing model for this listing. Can be one of "flat-rate", "per-unit", or "free".
|
||||
PriceModel *string `json:"price_model,omitempty"` |
||||
UnitName *string `json:"unit_name,omitempty"` |
||||
Bullets *[]string `json:"bullets,omitempty"` |
||||
// State can be one of the values "draft" or "published".
|
||||
State *string `json:"state,omitempty"` |
||||
HasFreeTrial *bool `json:"has_free_trial,omitempty"` |
||||
} |
||||
|
||||
// MarketplacePurchase represents a GitHub Apps Marketplace Purchase.
|
||||
type MarketplacePurchase struct { |
||||
// BillingCycle can be one of the values "yearly", "monthly" or nil.
|
||||
BillingCycle *string `json:"billing_cycle,omitempty"` |
||||
NextBillingDate *Timestamp `json:"next_billing_date,omitempty"` |
||||
UnitCount *int `json:"unit_count,omitempty"` |
||||
Plan *MarketplacePlan `json:"plan,omitempty"` |
||||
Account *MarketplacePlanAccount `json:"account,omitempty"` |
||||
OnFreeTrial *bool `json:"on_free_trial,omitempty"` |
||||
FreeTrialEndsOn *Timestamp `json:"free_trial_ends_on,omitempty"` |
||||
} |
||||
|
||||
// MarketplacePendingChange represents a pending change to a GitHub Apps Marketplace Plan.
|
||||
type MarketplacePendingChange struct { |
||||
EffectiveDate *Timestamp `json:"effective_date,omitempty"` |
||||
UnitCount *int `json:"unit_count,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
Plan *MarketplacePlan `json:"plan,omitempty"` |
||||
} |
||||
|
||||
// MarketplacePlanAccount represents a GitHub Account (user or organization) on a specific plan.
|
||||
type MarketplacePlanAccount struct { |
||||
URL *string `json:"url,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
Login *string `json:"login,omitempty"` |
||||
Email *string `json:"email,omitempty"` |
||||
OrganizationBillingEmail *string `json:"organization_billing_email,omitempty"` |
||||
MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` |
||||
MarketplacePendingChange *MarketplacePendingChange `json:"marketplace_pending_change,omitempty"` |
||||
} |
||||
|
||||
// ListPlans lists all plans for your Marketplace listing.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-plans-for-your-marketplace-listing
|
||||
func (s *MarketplaceService) ListPlans(ctx context.Context, opt *ListOptions) ([]*MarketplacePlan, *Response, error) { |
||||
uri := s.marketplaceURI("plans") |
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var plans []*MarketplacePlan |
||||
resp, err := s.client.Do(ctx, req, &plans) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return plans, resp, nil |
||||
} |
||||
|
||||
// ListPlanAccountsForPlan lists all GitHub accounts (user or organization) on a specific plan.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-github-accounts-user-or-organization-on-a-specific-plan
|
||||
func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { |
||||
uri := s.marketplaceURI(fmt.Sprintf("plans/%v/accounts", planID)) |
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var accounts []*MarketplacePlanAccount |
||||
resp, err := s.client.Do(ctx, req, &accounts) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return accounts, resp, nil |
||||
} |
||||
|
||||
// ListPlanAccountsForAccount lists all GitHub accounts (user or organization) associated with an account.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#check-if-a-github-account-is-associated-with-any-marketplace-listing
|
||||
func (s *MarketplaceService) ListPlanAccountsForAccount(ctx context.Context, accountID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) { |
||||
uri := s.marketplaceURI(fmt.Sprintf("accounts/%v", accountID)) |
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var accounts []*MarketplacePlanAccount |
||||
resp, err := s.client.Do(ctx, req, &accounts) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return accounts, resp, nil |
||||
} |
||||
|
||||
// ListMarketplacePurchasesForUser lists all GitHub marketplace purchases made by a user.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#get-a-users-marketplace-purchases
|
||||
func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context, opt *ListOptions) ([]*MarketplacePurchase, *Response, error) { |
||||
uri := "user/marketplace_purchases" |
||||
if s.Stubbed { |
||||
uri = "user/marketplace_purchases/stubbed" |
||||
} |
||||
|
||||
u, err := addOptions(uri, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
var purchases []*MarketplacePurchase |
||||
resp, err := s.client.Do(ctx, req, &purchases) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return purchases, resp, nil |
||||
} |
||||
|
||||
func (s *MarketplaceService) marketplaceURI(endpoint string) string { |
||||
url := "marketplace_listing" |
||||
if s.Stubbed { |
||||
url = "marketplace_listing/stubbed" |
||||
} |
||||
return url + "/" + endpoint |
||||
} |
@ -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/v3/enterprise-admin/users/#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/v3/enterprise-admin/users/#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,432 @@ |
||||
// Copyright 2018 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"net/url" |
||||
) |
||||
|
||||
// ChecksService provides access to the Checks API in the
|
||||
// GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/
|
||||
type ChecksService service |
||||
|
||||
// CheckRun represents a GitHub check run on a repository associated with a GitHub app.
|
||||
type CheckRun struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
HeadSHA *string `json:"head_sha,omitempty"` |
||||
ExternalID *string `json:"external_id,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
DetailsURL *string `json:"details_url,omitempty"` |
||||
Status *string `json:"status,omitempty"` |
||||
Conclusion *string `json:"conclusion,omitempty"` |
||||
StartedAt *Timestamp `json:"started_at,omitempty"` |
||||
CompletedAt *Timestamp `json:"completed_at,omitempty"` |
||||
Output *CheckRunOutput `json:"output,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
CheckSuite *CheckSuite `json:"check_suite,omitempty"` |
||||
App *App `json:"app,omitempty"` |
||||
PullRequests []*PullRequest `json:"pull_requests,omitempty"` |
||||
} |
||||
|
||||
// CheckRunOutput represents the output of a CheckRun.
|
||||
type CheckRunOutput struct { |
||||
Title *string `json:"title,omitempty"` |
||||
Summary *string `json:"summary,omitempty"` |
||||
Text *string `json:"text,omitempty"` |
||||
AnnotationsCount *int `json:"annotations_count,omitempty"` |
||||
AnnotationsURL *string `json:"annotations_url,omitempty"` |
||||
Annotations []*CheckRunAnnotation `json:"annotations,omitempty"` |
||||
Images []*CheckRunImage `json:"images,omitempty"` |
||||
} |
||||
|
||||
// CheckRunAnnotation represents an annotation object for a CheckRun output.
|
||||
type CheckRunAnnotation struct { |
||||
Path *string `json:"path,omitempty"` |
||||
BlobHRef *string `json:"blob_href,omitempty"` |
||||
StartLine *int `json:"start_line,omitempty"` |
||||
EndLine *int `json:"end_line,omitempty"` |
||||
AnnotationLevel *string `json:"annotation_level,omitempty"` |
||||
Message *string `json:"message,omitempty"` |
||||
Title *string `json:"title,omitempty"` |
||||
RawDetails *string `json:"raw_details,omitempty"` |
||||
} |
||||
|
||||
// CheckRunImage represents an image object for a CheckRun output.
|
||||
type CheckRunImage struct { |
||||
Alt *string `json:"alt,omitempty"` |
||||
ImageURL *string `json:"image_url,omitempty"` |
||||
Caption *string `json:"caption,omitempty"` |
||||
} |
||||
|
||||
// CheckSuite represents a suite of check runs.
|
||||
type CheckSuite struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
HeadBranch *string `json:"head_branch,omitempty"` |
||||
HeadSHA *string `json:"head_sha,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
BeforeSHA *string `json:"before,omitempty"` |
||||
AfterSHA *string `json:"after,omitempty"` |
||||
Status *string `json:"status,omitempty"` |
||||
Conclusion *string `json:"conclusion,omitempty"` |
||||
App *App `json:"app,omitempty"` |
||||
Repository *Repository `json:"repository,omitempty"` |
||||
PullRequests []*PullRequest `json:"pull_requests,omitempty"` |
||||
} |
||||
|
||||
func (c CheckRun) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
func (c CheckSuite) String() string { |
||||
return Stringify(c) |
||||
} |
||||
|
||||
// GetCheckRun gets a check-run for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/runs/#get-a-single-check-run
|
||||
func (s *ChecksService) GetCheckRun(ctx context.Context, owner, repo string, checkRunID int64) (*CheckRun, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
checkRun := new(CheckRun) |
||||
resp, err := s.client.Do(ctx, req, checkRun) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkRun, resp, nil |
||||
} |
||||
|
||||
// GetCheckSuite gets a single check suite.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/suites/#get-a-single-check-suite
|
||||
func (s *ChecksService) GetCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*CheckSuite, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/%v", owner, repo, checkSuiteID) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
checkSuite := new(CheckSuite) |
||||
resp, err := s.client.Do(ctx, req, checkSuite) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkSuite, resp, nil |
||||
} |
||||
|
||||
// CreateCheckRunOptions sets up parameters needed to create a CheckRun.
|
||||
type CreateCheckRunOptions struct { |
||||
Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.)
|
||||
HeadBranch string `json:"head_branch"` // The name of the branch to perform a check against. (Required.)
|
||||
HeadSHA string `json:"head_sha"` // The SHA of the commit. (Required.)
|
||||
DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.)
|
||||
ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.)
|
||||
Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.)
|
||||
Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".)
|
||||
StartedAt *Timestamp `json:"started_at,omitempty"` // The time that the check run began. (Optional.)
|
||||
CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.)
|
||||
Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional)
|
||||
Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.)
|
||||
} |
||||
|
||||
// CheckRunAction exposes further actions the integrator can perform, which a user may trigger.
|
||||
type CheckRunAction struct { |
||||
Label string `json:"label"` // The text to be displayed on a button in the web UI. The maximum size is 20 characters. (Required.)
|
||||
Description string `json:"description"` // A short explanation of what this action would do. The maximum size is 40 characters. (Required.)
|
||||
Identifier string `json:"identifier"` // A reference for the action on the integrator's system. The maximum size is 20 characters. (Required.)
|
||||
} |
||||
|
||||
// CreateCheckRun creates a check run for repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/runs/#create-a-check-run
|
||||
func (s *ChecksService) CreateCheckRun(ctx context.Context, owner, repo string, opt CreateCheckRunOptions) (*CheckRun, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-runs", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
checkRun := new(CheckRun) |
||||
resp, err := s.client.Do(ctx, req, checkRun) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkRun, resp, nil |
||||
} |
||||
|
||||
// UpdateCheckRunOptions sets up parameters needed to update a CheckRun.
|
||||
type UpdateCheckRunOptions struct { |
||||
Name string `json:"name"` // The name of the check (e.g., "code-coverage"). (Required.)
|
||||
HeadBranch *string `json:"head_branch,omitempty"` // The name of the branch to perform a check against. (Optional.)
|
||||
HeadSHA *string `json:"head_sha,omitempty"` // The SHA of the commit. (Optional.)
|
||||
DetailsURL *string `json:"details_url,omitempty"` // The URL of the integrator's site that has the full details of the check. (Optional.)
|
||||
ExternalID *string `json:"external_id,omitempty"` // A reference for the run on the integrator's system. (Optional.)
|
||||
Status *string `json:"status,omitempty"` // The current status. Can be one of "queued", "in_progress", or "completed". Default: "queued". (Optional.)
|
||||
Conclusion *string `json:"conclusion,omitempty"` // Can be one of "success", "failure", "neutral", "cancelled", "timed_out", or "action_required". (Optional. Required if you provide a status of "completed".)
|
||||
CompletedAt *Timestamp `json:"completed_at,omitempty"` // The time the check completed. (Optional. Required if you provide conclusion.)
|
||||
Output *CheckRunOutput `json:"output,omitempty"` // Provide descriptive details about the run. (Optional)
|
||||
Actions []*CheckRunAction `json:"actions,omitempty"` // Possible further actions the integrator can perform, which a user may trigger. (Optional.)
|
||||
} |
||||
|
||||
// UpdateCheckRun updates a check run for a specific commit in a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/runs/#update-a-check-run
|
||||
func (s *ChecksService) UpdateCheckRun(ctx context.Context, owner, repo string, checkRunID int64, opt UpdateCheckRunOptions) (*CheckRun, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-runs/%v", owner, repo, checkRunID) |
||||
req, err := s.client.NewRequest("PATCH", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
checkRun := new(CheckRun) |
||||
resp, err := s.client.Do(ctx, req, checkRun) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkRun, resp, nil |
||||
} |
||||
|
||||
// ListCheckRunAnnotations lists the annotations for a check run.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-annotations-for-a-check-run
|
||||
func (s *ChecksService) ListCheckRunAnnotations(ctx context.Context, owner, repo string, checkRunID int64, opt *ListOptions) ([]*CheckRunAnnotation, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-runs/%v/annotations", owner, repo, checkRunID) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
var checkRunAnnotations []*CheckRunAnnotation |
||||
resp, err := s.client.Do(ctx, req, &checkRunAnnotations) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkRunAnnotations, resp, nil |
||||
} |
||||
|
||||
// ListCheckRunsOptions represents parameters to list check runs.
|
||||
type ListCheckRunsOptions struct { |
||||
CheckName *string `url:"check_name,omitempty"` // Returns check runs with the specified name.
|
||||
Status *string `url:"status,omitempty"` // Returns check runs with the specified status. Can be one of "queued", "in_progress", or "completed".
|
||||
Filter *string `url:"filter,omitempty"` // Filters check runs by their completed_at timestamp. Can be one of "latest" (returning the most recent check runs) or "all". Default: "latest"
|
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListCheckRunsResults represents the result of a check run list.
|
||||
type ListCheckRunsResults struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
CheckRuns []*CheckRun `json:"check_runs,omitempty"` |
||||
} |
||||
|
||||
// ListCheckRunsForRef lists check runs for a specific ref.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref
|
||||
func (s *ChecksService) ListCheckRunsForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-runs", owner, repo, url.QueryEscape(ref)) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
var checkRunResults *ListCheckRunsResults |
||||
resp, err := s.client.Do(ctx, req, &checkRunResults) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkRunResults, resp, nil |
||||
} |
||||
|
||||
// ListCheckRunsCheckSuite lists check runs for a check suite.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/runs/#list-check-runs-in-a-check-suite
|
||||
func (s *ChecksService) ListCheckRunsCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64, opt *ListCheckRunsOptions) (*ListCheckRunsResults, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/check-runs", owner, repo, checkSuiteID) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
var checkRunResults *ListCheckRunsResults |
||||
resp, err := s.client.Do(ctx, req, &checkRunResults) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkRunResults, resp, nil |
||||
} |
||||
|
||||
// ListCheckSuiteOptions represents parameters to list check suites.
|
||||
type ListCheckSuiteOptions struct { |
||||
CheckName *string `url:"check_name,omitempty"` // Filters checks suites by the name of the check run.
|
||||
AppID *int `url:"app_id,omitempty"` // Filters check suites by GitHub App id.
|
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListCheckSuiteResults represents the result of a check run list.
|
||||
type ListCheckSuiteResults struct { |
||||
Total *int `json:"total_count,omitempty"` |
||||
CheckSuites []*CheckSuite `json:"check_suites,omitempty"` |
||||
} |
||||
|
||||
// ListCheckSuitesForRef lists check suite for a specific ref.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/suites/#list-check-suites-for-a-specific-ref
|
||||
func (s *ChecksService) ListCheckSuitesForRef(ctx context.Context, owner, repo, ref string, opt *ListCheckSuiteOptions) (*ListCheckSuiteResults, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/commits/%v/check-suites", owner, repo, url.QueryEscape(ref)) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
var checkSuiteResults *ListCheckSuiteResults |
||||
resp, err := s.client.Do(ctx, req, &checkSuiteResults) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkSuiteResults, resp, nil |
||||
} |
||||
|
||||
// AutoTriggerCheck enables or disables automatic creation of CheckSuite events upon pushes to the repository.
|
||||
type AutoTriggerCheck struct { |
||||
AppID *int64 `json:"app_id,omitempty"` // The id of the GitHub App. (Required.)
|
||||
Setting *bool `json:"setting,omitempty"` // Set to "true" to enable automatic creation of CheckSuite events upon pushes to the repository, or "false" to disable them. Default: "true" (Required.)
|
||||
} |
||||
|
||||
// CheckSuitePreferenceOptions set options for check suite preferences for a repository.
|
||||
type CheckSuitePreferenceOptions struct { |
||||
PreferenceList *PreferenceList `json:"auto_trigger_checks,omitempty"` // A list of auto trigger checks that can be set for a check suite in a repository.
|
||||
} |
||||
|
||||
// CheckSuitePreferenceResults represents the results of the preference set operation.
|
||||
type CheckSuitePreferenceResults struct { |
||||
Preferences *PreferenceList `json:"preferences,omitempty"` |
||||
Repository *Repository `json:"repository,omitempty"` |
||||
} |
||||
|
||||
// PreferenceList represents a list of auto trigger checks for repository
|
||||
type PreferenceList struct { |
||||
AutoTriggerChecks []*AutoTriggerCheck `json:"auto_trigger_checks,omitempty"` // A slice of auto trigger checks that can be set for a check suite in a repository.
|
||||
} |
||||
|
||||
// SetCheckSuitePreferences changes the default automatic flow when creating check suites.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/suites/#set-preferences-for-check-suites-on-a-repository
|
||||
func (s *ChecksService) SetCheckSuitePreferences(ctx context.Context, owner, repo string, opt CheckSuitePreferenceOptions) (*CheckSuitePreferenceResults, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/preferences", owner, repo) |
||||
req, err := s.client.NewRequest("PATCH", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
var checkSuitePrefResults *CheckSuitePreferenceResults |
||||
resp, err := s.client.Do(ctx, req, &checkSuitePrefResults) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkSuitePrefResults, resp, nil |
||||
} |
||||
|
||||
// CreateCheckSuiteOptions sets up parameters to manually create a check suites
|
||||
type CreateCheckSuiteOptions struct { |
||||
HeadSHA string `json:"head_sha"` // The sha of the head commit. (Required.)
|
||||
HeadBranch *string `json:"head_branch,omitempty"` // The name of the head branch where the code changes are implemented.
|
||||
} |
||||
|
||||
// CreateCheckSuite manually creates a check suite for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/suites/#create-a-check-suite
|
||||
func (s *ChecksService) CreateCheckSuite(ctx context.Context, owner, repo string, opt CreateCheckSuiteOptions) (*CheckSuite, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-suites", owner, repo) |
||||
req, err := s.client.NewRequest("POST", u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
checkSuite := new(CheckSuite) |
||||
resp, err := s.client.Do(ctx, req, checkSuite) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return checkSuite, resp, nil |
||||
} |
||||
|
||||
// ReRequestCheckSuite triggers GitHub to rerequest an existing check suite, without pushing new code to a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/checks/suites/#rerequest-check-suite
|
||||
func (s *ChecksService) ReRequestCheckSuite(ctx context.Context, owner, repo string, checkSuiteID int64) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/check-suites/%v/rerequest", owner, repo, checkSuiteID) |
||||
|
||||
req, err := s.client.NewRequest("POST", u, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeCheckRunsPreview) |
||||
|
||||
resp, err := s.client.Do(ctx, req, nil) |
||||
return resp, err |
||||
} |
@ -0,0 +1,188 @@ |
||||
// 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/v24/github" // with go modules enabled (GO111MODULE=on or outside GOPATH)
|
||||
import "github.com/google/go-github/github" // with go modules disabled
|
||||
|
||||
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,126 @@ |
||||
// Copyright 2018 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"time" |
||||
) |
||||
|
||||
// Event represents a GitHub event.
|
||||
type Event struct { |
||||
Type *string `json:"type,omitempty"` |
||||
Public *bool `json:"public,omitempty"` |
||||
RawPayload *json.RawMessage `json:"payload,omitempty"` |
||||
Repo *Repository `json:"repo,omitempty"` |
||||
Actor *User `json:"actor,omitempty"` |
||||
Org *Organization `json:"org,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
ID *string `json:"id,omitempty"` |
||||
} |
||||
|
||||
func (e Event) String() string { |
||||
return Stringify(e) |
||||
} |
||||
|
||||
// ParsePayload parses the event payload. For recognized event types,
|
||||
// a value of the corresponding struct type will be returned.
|
||||
func (e *Event) ParsePayload() (payload interface{}, err error) { |
||||
switch *e.Type { |
||||
case "CheckRunEvent": |
||||
payload = &CheckRunEvent{} |
||||
case "CheckSuiteEvent": |
||||
payload = &CheckSuiteEvent{} |
||||
case "CommitCommentEvent": |
||||
payload = &CommitCommentEvent{} |
||||
case "CreateEvent": |
||||
payload = &CreateEvent{} |
||||
case "DeleteEvent": |
||||
payload = &DeleteEvent{} |
||||
case "DeploymentEvent": |
||||
payload = &DeploymentEvent{} |
||||
case "DeploymentStatusEvent": |
||||
payload = &DeploymentStatusEvent{} |
||||
case "ForkEvent": |
||||
payload = &ForkEvent{} |
||||
case "GitHubAppAuthorizationEvent": |
||||
payload = &GitHubAppAuthorizationEvent{} |
||||
case "GollumEvent": |
||||
payload = &GollumEvent{} |
||||
case "InstallationEvent": |
||||
payload = &InstallationEvent{} |
||||
case "InstallationRepositoriesEvent": |
||||
payload = &InstallationRepositoriesEvent{} |
||||
case "IssueCommentEvent": |
||||
payload = &IssueCommentEvent{} |
||||
case "IssuesEvent": |
||||
payload = &IssuesEvent{} |
||||
case "LabelEvent": |
||||
payload = &LabelEvent{} |
||||
case "MarketplacePurchaseEvent": |
||||
payload = &MarketplacePurchaseEvent{} |
||||
case "MemberEvent": |
||||
payload = &MemberEvent{} |
||||
case "MembershipEvent": |
||||
payload = &MembershipEvent{} |
||||
case "MilestoneEvent": |
||||
payload = &MilestoneEvent{} |
||||
case "OrganizationEvent": |
||||
payload = &OrganizationEvent{} |
||||
case "OrgBlockEvent": |
||||
payload = &OrgBlockEvent{} |
||||
case "PageBuildEvent": |
||||
payload = &PageBuildEvent{} |
||||
case "PingEvent": |
||||
payload = &PingEvent{} |
||||
case "ProjectEvent": |
||||
payload = &ProjectEvent{} |
||||
case "ProjectCardEvent": |
||||
payload = &ProjectCardEvent{} |
||||
case "ProjectColumnEvent": |
||||
payload = &ProjectColumnEvent{} |
||||
case "PublicEvent": |
||||
payload = &PublicEvent{} |
||||
case "PullRequestEvent": |
||||
payload = &PullRequestEvent{} |
||||
case "PullRequestReviewEvent": |
||||
payload = &PullRequestReviewEvent{} |
||||
case "PullRequestReviewCommentEvent": |
||||
payload = &PullRequestReviewCommentEvent{} |
||||
case "PushEvent": |
||||
payload = &PushEvent{} |
||||
case "ReleaseEvent": |
||||
payload = &ReleaseEvent{} |
||||
case "RepositoryEvent": |
||||
payload = &RepositoryEvent{} |
||||
case "RepositoryVulnerabilityAlertEvent": |
||||
payload = &RepositoryVulnerabilityAlertEvent{} |
||||
case "StatusEvent": |
||||
payload = &StatusEvent{} |
||||
case "TeamEvent": |
||||
payload = &TeamEvent{} |
||||
case "TeamAddEvent": |
||||
payload = &TeamAddEvent{} |
||||
case "WatchEvent": |
||||
payload = &WatchEvent{} |
||||
} |
||||
err = json.Unmarshal(*e.RawPayload, &payload) |
||||
return payload, err |
||||
} |
||||
|
||||
// Payload returns the parsed event payload. For recognized event types,
|
||||
// a value of the corresponding struct type will be returned.
|
||||
//
|
||||
// Deprecated: Use ParsePayload instead, which returns an error
|
||||
// rather than panics if JSON unmarshaling raw payload fails.
|
||||
func (e *Event) Payload() (payload interface{}) { |
||||
var err error |
||||
payload, err = e.ParsePayload() |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
return payload |
||||
} |
@ -0,0 +1,833 @@ |
||||
// 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 |
||||
|
||||
// RequestedAction is included in a CheckRunEvent when a user has invoked an action,
|
||||
// i.e. when the CheckRunEvent's Action field is "requested_action".
|
||||
type RequestedAction struct { |
||||
Identifier string `json:"identifier"` // The integrator reference of the action requested by the user.
|
||||
} |
||||
|
||||
// CheckRunEvent is triggered when a check run is "created", "updated", or "re-requested".
|
||||
// The Webhook event name is "check_run".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checkrunevent
|
||||
type CheckRunEvent struct { |
||||
CheckRun *CheckRun `json:"check_run,omitempty"` |
||||
// The action performed. Can be "created", "updated", "rerequested" or "requested_action".
|
||||
Action *string `json:"action,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Org *Organization `json:"organization,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
|
||||
// The action requested by the user. Populated when the Action is "requested_action".
|
||||
RequestedAction *RequestedAction `json:"requested_action,omitempty"` //
|
||||
} |
||||
|
||||
// CheckSuiteEvent is triggered when a check suite is "completed", "requested", or "re-requested".
|
||||
// The Webhook event name is "check_suite".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#checksuiteevent
|
||||
type CheckSuiteEvent struct { |
||||
CheckSuite *CheckSuite `json:"check_suite,omitempty"` |
||||
// The action performed. Can be "completed", "requested" or "re-requested".
|
||||
Action *string `json:"action,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Org *Organization `json:"organization,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// CommitCommentEvent is triggered when a commit comment is created.
|
||||
// The Webhook event name is "commit_comment".
|
||||
//
|
||||
// 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"` |
||||
} |
||||
|
||||
// GitHubAppAuthorizationEvent is triggered when a user's authorization for a
|
||||
// GitHub Application is revoked.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#githubappauthorizationevent
|
||||
type GitHubAppAuthorizationEvent struct { |
||||
// The action performed. Can be "revoked".
|
||||
Action *string `json:"action,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Sender *User `json:"sender,omitempty"` |
||||
} |
||||
|
||||
// Page represents a single Wiki page.
|
||||
type Page struct { |
||||
PageName *string `json:"page_name,omitempty"` |
||||
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"` |
||||
Repositories []*Repository `json:"repositories,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", "pending_change", "pending_change_cancelled", "changed".
|
||||
Action *string `json:"action,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
EffectiveDate *Timestamp `json:"effective_date,omitempty"` |
||||
MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"` |
||||
PreviousMarketplacePurchase *MarketplacePurchase `json:"previous_marketplace_purchase,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
} |
||||
|
||||
// MemberEvent is triggered when a user is added as a collaborator to a repository.
|
||||
// The Webhook event name is "member".
|
||||
//
|
||||
// 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"` |
||||
Assignee *User `json:"assignee,omitempty"` |
||||
Number *int `json:"number,omitempty"` |
||||
PullRequest *PullRequest `json:"pull_request,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
Changes *EditChange `json:"changes,omitempty"` |
||||
// RequestedReviewer is populated in "review_requested", "review_request_removed" event deliveries.
|
||||
// A request affecting multiple reviewers at once is split into multiple
|
||||
// such event deliveries, each with a single, different RequestedReviewer.
|
||||
RequestedReviewer *User `json:"requested_reviewer,omitempty"` |
||||
Repo *Repository `json:"repository,omitempty"` |
||||
Sender *User `json:"sender,omitempty"` |
||||
Installation *Installation `json:"installation,omitempty"` |
||||
Label *Label `json:"label,omitempty"` // Populated in "labeled" event deliveries.
|
||||
|
||||
// The following field is only present when the webhook is triggered on
|
||||
// a repository belonging to an organization.
|
||||
Organization *Organization `json:"organization,omitempty"` |
||||
} |
||||
|
||||
// PullRequestReviewEvent is triggered when a review is submitted on a pull
|
||||
// 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"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
FullName *string `json:"full_name,omitempty"` |
||||
Owner *User `json:"owner,omitempty"` |
||||
Private *bool `json:"private,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
Fork *bool `json:"fork,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
PushedAt *Timestamp `json:"pushed_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
Homepage *string `json:"homepage,omitempty"` |
||||
Size *int `json:"size,omitempty"` |
||||
StargazersCount *int `json:"stargazers_count,omitempty"` |
||||
WatchersCount *int `json:"watchers_count,omitempty"` |
||||
Language *string `json:"language,omitempty"` |
||||
HasIssues *bool `json:"has_issues,omitempty"` |
||||
HasDownloads *bool `json:"has_downloads,omitempty"` |
||||
HasWiki *bool `json:"has_wiki,omitempty"` |
||||
HasPages *bool `json:"has_pages,omitempty"` |
||||
ForksCount *int `json:"forks_count,omitempty"` |
||||
OpenIssuesCount *int `json:"open_issues_count,omitempty"` |
||||
DefaultBranch *string `json:"default_branch,omitempty"` |
||||
MasterBranch *string `json:"master_branch,omitempty"` |
||||
Organization *string `json:"organization,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
ArchiveURL *string `json:"archive_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
StatusesURL *string `json:"statuses_url,omitempty"` |
||||
GitURL *string `json:"git_url,omitempty"` |
||||
SSHURL *string `json:"ssh_url,omitempty"` |
||||
CloneURL *string `json:"clone_url,omitempty"` |
||||
SVNURL *string `json:"svn_url,omitempty"` |
||||
} |
||||
|
||||
// PushEventRepoOwner is a basic representation of user/org in a PushEvent payload.
|
||||
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"` |
||||
} |
||||
|
||||
// RepositoryVulnerabilityAlertEvent is triggered when a security alert is created, dismissed, or resolved.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/activity/events/types/#repositoryvulnerabilityalertevent
|
||||
type RepositoryVulnerabilityAlertEvent struct { |
||||
// Action is the action that was performed. This can be: "create", "dismiss", "resolve".
|
||||
Action *string `json:"action,omitempty"` |
||||
|
||||
//The security alert of the vulnerable dependency.
|
||||
Alert *struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
AffectedRange *string `json:"affected_range,omitempty"` |
||||
AffectedPackageName *string `json:"affected_package_name,omitempty"` |
||||
ExternalReference *string `json:"external_reference,omitempty"` |
||||
ExternalIdentifier *string `json:"external_identifier,omitempty"` |
||||
FixedIn *string `json:"fixed_in,omitempty"` |
||||
Dismisser *User `json:"dismisser,omitempty"` |
||||
DismissReason *string `json:"dismiss_reason,omitempty"` |
||||
DismissedAt *Timestamp `json:"dismissed_at,omitempty"` |
||||
} `json:"alert,omitempty"` |
||||
} |
||||
|
||||
// StatusEvent is triggered when the status of a Git commit changes.
|
||||
// The Webhook event name is "status".
|
||||
//
|
||||
// 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,358 @@ |
||||
// 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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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,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 ( |
||||
"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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
t := new(Blob) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
return t, resp, err |
||||
} |
@ -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" |
||||
"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 fetches the Commit object for a given SHA.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/commits/#get-a-commit
|
||||
func (s *GitService) GetCommit(ctx context.Context, owner string, repo string, sha string) (*Commit, *Response, error) { |
||||
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 |
||||
} |
||||
|
||||
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"` |
||||
Signature *string `json:"signature,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 |
||||
} |
||||
if commit.Verification != nil { |
||||
body.Signature = commit.Verification.Signature |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
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,219 @@ |
||||
// 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" |
||||
"net/url" |
||||
"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, url.QueryEscape(ref)) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
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, url.QueryEscape(ref)) |
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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, url.QueryEscape(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,76 @@ |
||||
// 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" |
||||
) |
||||
|
||||
// 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 fetches a tag from a repo given a SHA.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/git/tags/#get-a-tag
|
||||
func (s *GitService) GetTag(ctx context.Context, owner string, repo string, sha string) (*Tag, *Response, error) { |
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
t := new(Tag) |
||||
resp, err := s.client.Do(ctx, req, t) |
||||
return t, resp, err |
||||
} |
@ -0,0 +1,99 @@ |
||||
// 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"` |
||||
|
||||
// Truncated is true if the number of items in the tree
|
||||
// exceeded GitHub's maximum limit and the Entries were truncated
|
||||
// in the response. Only populated for requests that fetch
|
||||
// trees like Git.GetTree.
|
||||
Truncated *bool `json:"truncated,omitempty"` |
||||
} |
||||
|
||||
func (t Tree) String() string { |
||||
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
File diff suppressed because it is too large
Load Diff
@ -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,28 @@ |
||||
// 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 |
||||
|
||||
// InteractionsService handles communication with the repository and organization related
|
||||
// methods of the GitHub API.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/interactions/
|
||||
type InteractionsService service |
||||
|
||||
// InteractionRestriction represents the interaction restrictions for repository and organization.
|
||||
type InteractionRestriction struct { |
||||
// Specifies the group of GitHub users who can
|
||||
// comment, open issues, or create pull requests for the given repository.
|
||||
// Possible values are: "existing_users", "contributors_only" and "collaborators_only".
|
||||
Limit *string `json:"limit,omitempty"` |
||||
|
||||
// Origin specifies the type of the resource to interact with.
|
||||
// Possible values are: "repository" and "organization".
|
||||
Origin *string `json:"origin,omitempty"` |
||||
|
||||
// ExpiresAt specifies the time after which the interaction restrictions expire.
|
||||
// The default expiry time is 24 hours from the time restriction is created.
|
||||
ExpiresAt *Timestamp `json:"expires_at,omitempty"` |
||||
} |
@ -0,0 +1,80 @@ |
||||
// Copyright 2019 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" |
||||
) |
||||
|
||||
// GetRestrictionsForOrg fetches the interaction restrictions for an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#get-interaction-restrictions-for-an-organization
|
||||
func (s *InteractionsService) GetRestrictionsForOrg(ctx context.Context, organization string) (*InteractionRestriction, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/interaction-limits", organization) |
||||
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", mediaTypeInteractionRestrictionsPreview) |
||||
|
||||
organizationInteractions := new(InteractionRestriction) |
||||
|
||||
resp, err := s.client.Do(ctx, req, organizationInteractions) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return organizationInteractions, resp, nil |
||||
} |
||||
|
||||
// UpdateRestrictionsForOrg adds or updates the interaction restrictions for an organization.
|
||||
//
|
||||
// limit specifies the group of GitHub users who can comment, open issues, or create pull requests
|
||||
// in public repositories for the given organization.
|
||||
// Possible values are: "existing_users", "contributors_only", "collaborators_only".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#add-or-update-interaction-restrictions-for-an-organization
|
||||
func (s *InteractionsService) UpdateRestrictionsForOrg(ctx context.Context, organization, limit string) (*InteractionRestriction, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/interaction-limits", organization) |
||||
|
||||
interaction := &InteractionRestriction{Limit: String(limit)} |
||||
|
||||
req, err := s.client.NewRequest("PUT", u, interaction) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) |
||||
|
||||
organizationInteractions := new(InteractionRestriction) |
||||
|
||||
resp, err := s.client.Do(ctx, req, organizationInteractions) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return organizationInteractions, resp, nil |
||||
} |
||||
|
||||
// RemoveRestrictionsFromOrg removes the interaction restrictions for an organization.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/interactions/orgs/#remove-interaction-restrictions-for-an-organization
|
||||
func (s *InteractionsService) RemoveRestrictionsFromOrg(ctx context.Context, organization string) (*Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/interaction-limits", organization) |
||||
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", mediaTypeInteractionRestrictionsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,80 @@ |
||||
// 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" |
||||
) |
||||
|
||||
// GetRestrictionsForRepo fetches the interaction restrictions for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/interactions/repos/#get-interaction-restrictions-for-a-repository
|
||||
func (s *InteractionsService) GetRestrictionsForRepo(ctx context.Context, owner, repo string) (*InteractionRestriction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/interaction-limits", 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", mediaTypeInteractionRestrictionsPreview) |
||||
|
||||
repositoryInteractions := new(InteractionRestriction) |
||||
|
||||
resp, err := s.client.Do(ctx, req, repositoryInteractions) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return repositoryInteractions, resp, nil |
||||
} |
||||
|
||||
// UpdateRestrictionsForRepo adds or updates the interaction restrictions for a repository.
|
||||
//
|
||||
// limit specifies the group of GitHub users who can comment, open issues, or create pull requests
|
||||
// for the given repository.
|
||||
// Possible values are: "existing_users", "contributors_only", "collaborators_only".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/interactions/repos/#add-or-update-interaction-restrictions-for-a-repository
|
||||
func (s *InteractionsService) UpdateRestrictionsForRepo(ctx context.Context, owner, repo, limit string) (*InteractionRestriction, *Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/interaction-limits", owner, repo) |
||||
|
||||
interaction := &InteractionRestriction{Limit: String(limit)} |
||||
|
||||
req, err := s.client.NewRequest("PUT", u, interaction) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeInteractionRestrictionsPreview) |
||||
|
||||
repositoryInteractions := new(InteractionRestriction) |
||||
|
||||
resp, err := s.client.Do(ctx, req, repositoryInteractions) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return repositoryInteractions, resp, nil |
||||
} |
||||
|
||||
// RemoveRestrictionsFromRepo removes the interaction restrictions for a repository.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/interactions/repos/#remove-interaction-restrictions-for-a-repository
|
||||
func (s *InteractionsService) RemoveRestrictionsFromRepo(ctx context.Context, owner, repo string) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/interaction-limits", 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", mediaTypeInteractionRestrictionsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -0,0 +1,347 @@ |
||||
// 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"` |
||||
|
||||
// ActiveLockReason is populated only when LockReason is provided while locking the issue.
|
||||
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
|
||||
ActiveLockReason *string `json:"active_lock_reason,omitempty"` |
||||
} |
||||
|
||||
func (i Issue) String() string { |
||||
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, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview} |
||||
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, mediaTypeLabelDescriptionSearchPreview, mediaTypeIntegrationPreview} |
||||
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, mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview} |
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
i := new(Issue) |
||||
resp, err := s.client.Do(ctx, req, i) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return i, resp, nil |
||||
} |
||||
|
||||
// LockIssueOptions specifies the optional parameters to the
|
||||
// IssuesService.Lock method.
|
||||
type LockIssueOptions struct { |
||||
// LockReason specifies the reason to lock this issue.
|
||||
// Providing a lock reason can help make it clearer to contributors why an issue
|
||||
// was locked. Possible values are: "off-topic", "too heated", "resolved", and "spam".
|
||||
LockReason string `json:"lock_reason,omitempty"` |
||||
} |
||||
|
||||
// Lock an issue's conversation.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/issues/#lock-an-issue
|
||||
func (s *IssuesService) Lock(ctx context.Context, owner string, repo string, number int, opt *LockIssueOptions) (*Response, error) { |
||||
u := fmt.Sprintf("repos/%v/%v/issues/%d/lock", owner, repo, number) |
||||
req, err := s.client.NewRequest("PUT", u, opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if opt != nil { |
||||
req.Header.Set("Accept", mediaTypeLockReasonPreview) |
||||
} |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// 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,153 @@ |
||||
// 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"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
Reactions *Reactions `json:"reactions,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
// 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,161 @@ |
||||
// 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" |
||||
"strings" |
||||
"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, unlocked
|
||||
// The Actor did that to the issue.
|
||||
//
|
||||
// locked
|
||||
// The Actor locked the issue.
|
||||
// LockReason holds the reason of locking the issue (if provided while locking).
|
||||
//
|
||||
// renamed
|
||||
// The Actor changed the issue title from Rename.From to Rename.To.
|
||||
//
|
||||
// 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"` |
||||
LockReason *string `json:"lock_reason,omitempty"` |
||||
ProjectCard *ProjectCard `json:"project_card,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 |
||||
} |
||||
|
||||
acceptHeaders := []string{mediaTypeLockReasonPreview, mediaTypeProjectCardDetailsPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var events []*IssueEvent |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
if err != nil { |
||||
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,261 @@ |
||||
// 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" |
||||
) |
||||
|
||||
// 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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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,148 @@ |
||||
// 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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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,154 @@ |
||||
// 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" |
||||
"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"` |
||||
ProjectCard *ProjectCard `json:"project_card,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"` |
||||
Type *string `json:"type,omitempty"` |
||||
Issue *Issue `json:"issue,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.
|
||||
acceptHeaders := []string{mediaTypeTimelinePreview, mediaTypeProjectCardDetailsPreview} |
||||
req.Header.Set("Accept", strings.Join(acceptHeaders, ", ")) |
||||
|
||||
var events []*Timeline |
||||
resp, err := s.client.Do(ctx, req, &events) |
||||
return events, resp, err |
||||
} |
@ -0,0 +1,97 @@ |
||||
// 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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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,248 @@ |
||||
// 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{ |
||||
"check_run": "CheckRunEvent", |
||||
"check_suite": "CheckSuiteEvent", |
||||
"commit_comment": "CommitCommentEvent", |
||||
"create": "CreateEvent", |
||||
"delete": "DeleteEvent", |
||||
"deployment": "DeploymentEvent", |
||||
"deployment_status": "DeploymentStatusEvent", |
||||
"fork": "ForkEvent", |
||||
"gollum": "GollumEvent", |
||||
"installation": "InstallationEvent", |
||||
"installation_repositories": "InstallationRepositoriesEvent", |
||||
"issue_comment": "IssueCommentEvent", |
||||
"issues": "IssuesEvent", |
||||
"label": "LabelEvent", |
||||
"marketplace_purchase": "MarketplacePurchaseEvent", |
||||
"member": "MemberEvent", |
||||
"membership": "MembershipEvent", |
||||
"milestone": "MilestoneEvent", |
||||
"organization": "OrganizationEvent", |
||||
"org_block": "OrgBlockEvent", |
||||
"page_build": "PageBuildEvent", |
||||
"ping": "PingEvent", |
||||
"project": "ProjectEvent", |
||||
"project_card": "ProjectCardEvent", |
||||
"project_column": "ProjectColumnEvent", |
||||
"public": "PublicEvent", |
||||
"pull_request_review": "PullRequestReviewEvent", |
||||
"pull_request_review_comment": "PullRequestReviewCommentEvent", |
||||
"pull_request": "PullRequestEvent", |
||||
"push": "PushEvent", |
||||
"repository": "RepositoryEvent", |
||||
"repository_vulnerability_alert": "RepositoryVulnerabilityAlertEvent", |
||||
"release": "ReleaseEvent", |
||||
"status": "StatusEvent", |
||||
"team": "TeamEvent", |
||||
"team_add": "TeamAddEvent", |
||||
"watch": "WatchEvent", |
||||
} |
||||
) |
||||
|
||||
// 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,214 @@ |
||||
// Copyright 2018 The go-github AUTHORS. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package github |
||||
|
||||
import ( |
||||
"context" |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
) |
||||
|
||||
// UserMigration represents a GitHub migration (archival).
|
||||
type UserMigration struct { |
||||
ID *int64 `json:"id,omitempty"` |
||||
GUID *string `json:"guid,omitempty"` |
||||
// State is the current state of a migration.
|
||||
// Possible values are:
|
||||
// "pending" which means the migration hasn't started yet,
|
||||
// "exporting" which means the migration is in progress,
|
||||
// "exported" which means the migration finished successfully, or
|
||||
// "failed" which means the migration failed.
|
||||
State *string `json:"state,omitempty"` |
||||
// LockRepositories indicates whether repositories are locked (to prevent
|
||||
// manipulation) while migrating data.
|
||||
LockRepositories *bool `json:"lock_repositories,omitempty"` |
||||
// ExcludeAttachments indicates whether attachments should be excluded from
|
||||
// the migration (to reduce migration archive file size).
|
||||
ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
CreatedAt *string `json:"created_at,omitempty"` |
||||
UpdatedAt *string `json:"updated_at,omitempty"` |
||||
Repositories []*Repository `json:"repositories,omitempty"` |
||||
} |
||||
|
||||
func (m UserMigration) String() string { |
||||
return Stringify(m) |
||||
} |
||||
|
||||
// UserMigrationOptions specifies the optional parameters to Migration methods.
|
||||
type UserMigrationOptions struct { |
||||
// LockRepositories indicates whether repositories should be locked (to prevent
|
||||
// manipulation) while migrating data.
|
||||
LockRepositories bool |
||||
|
||||
// ExcludeAttachments indicates whether attachments should be excluded from
|
||||
// the migration (to reduce migration archive file size).
|
||||
ExcludeAttachments bool |
||||
} |
||||
|
||||
// startUserMigration represents the body of a StartMigration request.
|
||||
type startUserMigration struct { |
||||
// Repositories is a slice of repository names to migrate.
|
||||
Repositories []string `json:"repositories,omitempty"` |
||||
|
||||
// LockRepositories indicates whether repositories should be locked (to prevent
|
||||
// manipulation) while migrating data.
|
||||
LockRepositories *bool `json:"lock_repositories,omitempty"` |
||||
|
||||
// ExcludeAttachments indicates whether attachments should be excluded from
|
||||
// the migration (to reduce migration archive file size).
|
||||
ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` |
||||
} |
||||
|
||||
// StartUserMigration starts the generation of a migration archive.
|
||||
// repos is a slice of repository names to migrate.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/migrations/users/#start-a-user-migration
|
||||
func (s *MigrationService) StartUserMigration(ctx context.Context, repos []string, opt *UserMigrationOptions) (*UserMigration, *Response, error) { |
||||
u := "user/migrations" |
||||
|
||||
body := &startUserMigration{Repositories: repos} |
||||
if opt != nil { |
||||
body.LockRepositories = Bool(opt.LockRepositories) |
||||
body.ExcludeAttachments = Bool(opt.ExcludeAttachments) |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
m := &UserMigration{} |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// ListUserMigrations lists the most recent migrations.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-a-list-of-user-migrations
|
||||
func (s *MigrationService) ListUserMigrations(ctx context.Context) ([]*UserMigration, *Response, error) { |
||||
u := "user/migrations" |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
var m []*UserMigration |
||||
resp, err := s.client.Do(ctx, req, &m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// UserMigrationStatus gets the status of a specific migration archive.
|
||||
// id is the migration ID.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-the-status-of-a-user-migration
|
||||
func (s *MigrationService) UserMigrationStatus(ctx context.Context, id int64) (*UserMigration, *Response, error) { |
||||
u := fmt.Sprintf("user/migrations/%v", id) |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
m := &UserMigration{} |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// UserMigrationArchiveURL gets the URL for a specific migration archive.
|
||||
// id is the migration ID.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/migrations/users/#download-a-user-migration-archive
|
||||
func (s *MigrationService) UserMigrationArchiveURL(ctx context.Context, id int64) (string, error) { |
||||
url := fmt.Sprintf("user/migrations/%v/archive", id) |
||||
|
||||
req, err := s.client.NewRequest("GET", url, nil) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
m := &UserMigration{} |
||||
|
||||
var loc string |
||||
originalRedirect := s.client.client.CheckRedirect |
||||
s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { |
||||
loc = req.URL.String() |
||||
return http.ErrUseLastResponse |
||||
} |
||||
defer func() { |
||||
s.client.client.CheckRedirect = originalRedirect |
||||
}() |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err == nil { |
||||
return "", errors.New("expected redirect, none provided") |
||||
} |
||||
loc = resp.Header.Get("Location") |
||||
return loc, nil |
||||
} |
||||
|
||||
// DeleteUserMigration will delete a previous migration archive.
|
||||
// id is the migration ID.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/migrations/users/#delete-a-user-migration-archive
|
||||
func (s *MigrationService) DeleteUserMigration(ctx context.Context, id int64) (*Response, error) { |
||||
url := fmt.Sprintf("user/migrations/%v/archive", id) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", url, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// UnlockUserRepo will unlock a repo that was locked for migration.
|
||||
// id is migration ID.
|
||||
// You should unlock each migrated repository and delete them when the migration
|
||||
// is complete and you no longer need the source data.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/migrations/users/#unlock-a-user-repository
|
||||
func (s *MigrationService) UnlockUserRepo(ctx context.Context, id int64, repo string) (*Response, error) { |
||||
url := fmt.Sprintf("user/migrations/%v/repos/%v/lock", id, repo) |
||||
|
||||
req, err := s.client.NewRequest("DELETE", url, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// TODO: remove custom Accept header when this API fully launches.
|
||||
req.Header.Set("Accept", mediaTypeMigrationsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
@ -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,208 @@ |
||||
// 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"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
AvatarURL *string `json:"avatar_url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Company *string `json:"company,omitempty"` |
||||
Blog *string `json:"blog,omitempty"` |
||||
Location *string `json:"location,omitempty"` |
||||
Email *string `json:"email,omitempty"` |
||||
Description *string `json:"description,omitempty"` |
||||
PublicRepos *int `json:"public_repos,omitempty"` |
||||
PublicGists *int `json:"public_gists,omitempty"` |
||||
Followers *int `json:"followers,omitempty"` |
||||
Following *int `json:"following,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
TotalPrivateRepos *int `json:"total_private_repos,omitempty"` |
||||
OwnedPrivateRepos *int `json:"owned_private_repos,omitempty"` |
||||
PrivateGists *int `json:"private_gists,omitempty"` |
||||
DiskUsage *int `json:"disk_usage,omitempty"` |
||||
Collaborators *int `json:"collaborators,omitempty"` |
||||
BillingEmail *string `json:"billing_email,omitempty"` |
||||
Type *string `json:"type,omitempty"` |
||||
Plan *Plan `json:"plan,omitempty"` |
||||
TwoFactorRequirementEnabled *bool `json:"two_factor_requirement_enabled,omitempty"` |
||||
|
||||
// DefaultRepoPermission can be one of: "read", "write", "admin", or "none". (Default: "read").
|
||||
// It is only used in OrganizationsService.Edit.
|
||||
DefaultRepoPermission *string `json:"default_repository_permission,omitempty"` |
||||
// DefaultRepoSettings can be one of: "read", "write", "admin", or "none". (Default: "read").
|
||||
// It is only used in OrganizationsService.Get.
|
||||
DefaultRepoSettings *string `json:"default_repository_settings,omitempty"` |
||||
|
||||
// MembersCanCreateRepos default value is true and is only used in Organizations.Edit.
|
||||
MembersCanCreateRepos *bool `json:"members_can_create_repositories,omitempty"` |
||||
|
||||
// API URLs
|
||||
URL *string `json:"url,omitempty"` |
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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,117 @@ |
||||
// 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.
|
||||
// Config is a required field.
|
||||
//
|
||||
// Note that only a subset of the hook fields are used and hook must
|
||||
// not be nil.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook
|
||||
func (s *OrganizationsService) CreateHook(ctx context.Context, org string, hook *Hook) (*Hook, *Response, error) { |
||||
u := fmt.Sprintf("orgs/%v/hooks", org) |
||||
|
||||
hookReq := &createHookRequest{ |
||||
Events: hook.Events, |
||||
Active: hook.Active, |
||||
Config: hook.Config, |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("POST", u, hookReq) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
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-owner 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,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,594 @@ |
||||
// 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" |
||||
) |
||||
|
||||
// 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"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
ColumnsURL *string `json:"columns_url,omitempty"` |
||||
OwnerURL *string `json:"owner_url,omitempty"` |
||||
Name *string `json:"name,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Number *int `json:"number,omitempty"` |
||||
State *string `json:"state,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
|
||||
// The User object that generated the project.
|
||||
Creator *User `json:"creator,omitempty"` |
||||
} |
||||
|
||||
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.
|
||||
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 |
||||
} |
||||
|
||||
// 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"` |
||||
// The permission level that all members of the project's organization
|
||||
// will have on this project.
|
||||
// Setting the organization permission is only available
|
||||
// for organization projects. (Optional.)
|
||||
OrganizationPermission *string `json:"organization_permission,omitempty"` |
||||
// Sets visibility of the project within the organization.
|
||||
// Setting visibility is only available
|
||||
// for organization projects.(Optional.)
|
||||
Public *bool `json:"public,omitempty"` |
||||
} |
||||
|
||||
// UpdateProject updates a repository project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/#update-a-project
|
||||
func (s *ProjectsService) UpdateProject(ctx context.Context, id 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.
|
||||
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 |
||||
} |
||||
|
||||
// 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"` |
||||
URL *string `json:"url,omitempty"` |
||||
ProjectURL *string `json:"project_url,omitempty"` |
||||
CardsURL *string `json:"cards_url,omitempty"` |
||||
CreatedAt *Timestamp `json:"created_at,omitempty"` |
||||
UpdatedAt *Timestamp `json:"updated_at,omitempty"` |
||||
NodeID *string `json:"node_id,omitempty"` |
||||
} |
||||
|
||||
// ListProjectColumns lists the columns of a GitHub Project for a repo.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/columns/#list-project-columns
|
||||
func (s *ProjectsService) ListProjectColumns(ctx context.Context, projectID 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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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"` |
||||
Archived *bool `json:"archived,omitempty"` |
||||
|
||||
// The following fields are only populated by Webhook events.
|
||||
ColumnID *int64 `json:"column_id,omitempty"` |
||||
|
||||
// The following fields are only populated by Events API.
|
||||
ProjectID *int64 `json:"project_id,omitempty"` |
||||
ProjectURL *string `json:"project_url,omitempty"` |
||||
ColumnName *string `json:"column_name,omitempty"` |
||||
PreviousColumnName *string `json:"previous_column_name,omitempty"` // Populated in "moved_columns_in_project" event deliveries.
|
||||
} |
||||
|
||||
// ProjectCardListOptions specifies the optional parameters to the
|
||||
// ProjectsService.ListProjectCards method.
|
||||
type ProjectCardListOptions struct { |
||||
// ArchivedState is used to list all, archived, or not_archived project cards.
|
||||
// Defaults to not_archived when you omit this parameter.
|
||||
ArchivedState *string `url:"archived_state,omitempty"` |
||||
|
||||
ListOptions |
||||
} |
||||
|
||||
// ListProjectCards lists the cards in a column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#list-project-cards
|
||||
func (s *ProjectsService) ListProjectCards(ctx context.Context, columnID int64, opt *ProjectCardListOptions) ([]*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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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" and "PullRequest".
|
||||
ContentType string `json:"content_type,omitempty"` |
||||
// Use true to archive a project card.
|
||||
// Specify false if you need to restore a previously archived project card.
|
||||
Archived *bool `json:"archived,omitempty"` |
||||
} |
||||
|
||||
// CreateProjectCard creates a card in the specified column of a GitHub Project.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/cards/#create-a-project-card
|
||||
func (s *ProjectsService) CreateProjectCard(ctx context.Context, columnID 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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeProjectsPreview) |
||||
|
||||
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) |
||||
} |
||||
|
||||
// ProjectCollaboratorOptions specifies the optional parameters to the
|
||||
// ProjectsService.AddProjectCollaborator method.
|
||||
type ProjectCollaboratorOptions struct { |
||||
// Permission specifies the permission to grant to the collaborator.
|
||||
// Possible values are:
|
||||
// "read" - can read, but not write to or administer this project.
|
||||
// "write" - can read and write, but not administer this project.
|
||||
// "admin" - can read, write and administer this project.
|
||||
//
|
||||
// Default value is "write"
|
||||
Permission *string `json:"permission,omitempty"` |
||||
} |
||||
|
||||
// AddProjectCollaborator adds a collaborator to an organization project and sets
|
||||
// their permission level. You must be an organization owner or a project admin to add a collaborator.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#add-user-as-a-collaborator
|
||||
func (s *ProjectsService) AddProjectCollaborator(ctx context.Context, id int64, username string, opt *ProjectCollaboratorOptions) (*Response, error) { |
||||
u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) |
||||
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", mediaTypeProjectsPreview) |
||||
|
||||
return s.client.Do(ctx, req, nil) |
||||
} |
||||
|
||||
// RemoveProjectCollaborator removes a collaborator from an organization project.
|
||||
// You must be an organization owner or a project admin to remove a collaborator.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#remove-user-as-a-collaborator
|
||||
func (s *ProjectsService) RemoveProjectCollaborator(ctx context.Context, id int64, username string) (*Response, error) { |
||||
u := fmt.Sprintf("projects/%v/collaborators/%v", id, username) |
||||
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) |
||||
} |
||||
|
||||
// ListCollaboratorOptions specifies the optional parameters to the
|
||||
// ProjectsService.ListProjectCollaborators method.
|
||||
type ListCollaboratorOptions 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 |
||||
} |
||||
|
||||
// ListProjectCollaborators lists the collaborators for an organization project. For a project,
|
||||
// the list of collaborators includes outside collaborators, organization members that are direct
|
||||
// collaborators, organization members with access through team memberships, organization members
|
||||
// with access through default organization permissions, and organization owners. You must be an
|
||||
// organization owner or a project admin to list collaborators.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#list-collaborators
|
||||
func (s *ProjectsService) ListProjectCollaborators(ctx context.Context, id int64, opt *ListCollaboratorOptions) ([]*User, *Response, error) { |
||||
u := fmt.Sprintf("projects/%v/collaborators", 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", mediaTypeProjectsPreview) |
||||
|
||||
var users []*User |
||||
resp, err := s.client.Do(ctx, req, &users) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return users, resp, nil |
||||
} |
||||
|
||||
// ProjectPermissionLevel represents the permission level an organization
|
||||
// member has for a given project.
|
||||
type ProjectPermissionLevel struct { |
||||
// Possible values: "admin", "write", "read", "none"
|
||||
Permission *string `json:"permission,omitempty"` |
||||
|
||||
User *User `json:"user,omitempty"` |
||||
} |
||||
|
||||
// ReviewProjectCollaboratorPermission returns the collaborator's permission level for an organization
|
||||
// project. Possible values for the permission key: "admin", "write", "read", "none".
|
||||
// You must be an organization owner or a project admin to review a user's permission level.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/projects/collaborators/#review-a-users-permission-level
|
||||
func (s *ProjectsService) ReviewProjectCollaboratorPermission(ctx context.Context, id int64, username string) (*ProjectPermissionLevel, *Response, error) { |
||||
u := fmt.Sprintf("projects/%v/collaborators/%v/permission", id, username) |
||||
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) |
||||
|
||||
ppl := new(ProjectPermissionLevel) |
||||
resp, err := s.client.Do(ctx, req, ppl) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
return ppl, resp, nil |
||||
} |
@ -0,0 +1,404 @@ |
||||
// 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"` |
||||
Draft *bool `json:"draft,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"` |
||||
ReviewComments *int `json:"review_comments,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"` |
||||
|
||||
// RequestedTeams is populated as part of the PullRequestEvent.
|
||||
// See, https://developer.github.com/v3/activity/events/types/#pullrequestevent for an example.
|
||||
RequestedTeams []*Team `json:"requested_teams,omitempty"` |
||||
|
||||
Links *PRLinks `json:"_links,omitempty"` |
||||
Head *PullRequestBranch `json:"head,omitempty"` |
||||
Base *PullRequestBranch `json:"base,omitempty"` |
||||
|
||||
// ActiveLockReason is populated only when LockReason is provided while locking the pull request.
|
||||
// Possible values are: "off-topic", "too heated", "resolved", and "spam".
|
||||
ActiveLockReason *string `json:"active_lock_reason,omitempty"` |
||||
} |
||||
|
||||
func (p PullRequest) String() string { |
||||
return Stringify(p) |
||||
} |
||||
|
||||
// PRLink represents a single link object from Github pull request _links.
|
||||
type PRLink struct { |
||||
HRef *string `json:"href,omitempty"` |
||||
} |
||||
|
||||
// PRLinks represents the "_links" object in a Github pull request.
|
||||
type PRLinks struct { |
||||
Self *PRLink `json:"self,omitempty"` |
||||
HTML *PRLink `json:"html,omitempty"` |
||||
Issue *PRLink `json:"issue,omitempty"` |
||||
Comments *PRLink `json:"comments,omitempty"` |
||||
ReviewComments *PRLink `json:"review_comments,omitempty"` |
||||
ReviewComment *PRLink `json:"review_comment,omitempty"` |
||||
Commits *PRLink `json:"commits,omitempty"` |
||||
Statuses *PRLink `json:"statuses,omitempty"` |
||||
} |
||||
|
||||
// PullRequestBranch represents a base or head branch in a GitHub pull request.
|
||||
type PullRequestBranch struct { |
||||
Label *string `json:"label,omitempty"` |
||||
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, all. 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{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview, mediaTypeDraftPreview} |
||||
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{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview, mediaTypeDraftPreview} |
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeLabelDescriptionSearchPreview) |
||||
|
||||
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{mediaTypeLabelDescriptionSearchPreview, mediaTypeLockReasonPreview} |
||||
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 |
||||
} |
||||
|
||||
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,188 @@ |
||||
// 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_id,omitempty"` |
||||
Body *string `json:"body,omitempty"` |
||||
Path *string `json:"path,omitempty"` |
||||
DiffHunk *string `json:"diff_hunk,omitempty"` |
||||
PullRequestReviewID *int64 `json:"pull_request_review_id,omitempty"` |
||||
Position *int `json:"position,omitempty"` |
||||
OriginalPosition *int `json:"original_position,omitempty"` |
||||
CommitID *string `json:"commit_id,omitempty"` |
||||
OriginalCommitID *string `json:"original_commit_id,omitempty"` |
||||
User *User `json:"user,omitempty"` |
||||
Reactions *Reactions `json:"reactions,omitempty"` |
||||
CreatedAt *time.Time `json:"created_at,omitempty"` |
||||
UpdatedAt *time.Time `json:"updated_at,omitempty"` |
||||
// AuthorAssociation is the comment author's relationship to the pull request's repository.
|
||||
// Possible values are "COLLABORATOR", "CONTRIBUTOR", "FIRST_TIMER", "FIRST_TIME_CONTRIBUTOR", "MEMBER", "OWNER", or "NONE".
|
||||
AuthorAssociation *string `json:"author_association,omitempty"` |
||||
URL *string `json:"url,omitempty"` |
||||
HTMLURL *string `json:"html_url,omitempty"` |
||||
PullRequestURL *string `json:"pull_request_url,omitempty"` |
||||
} |
||||
|
||||
func (p PullRequestComment) String() string { |
||||
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 |
||||
} |
||||
|
||||
// CreateCommentInReplyTo creates a new comment as a reply to an existing pull request comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#alternative-input
|
||||
func (s *PullRequestsService) CreateCommentInReplyTo(ctx context.Context, owner string, repo string, number int, body string, commentID int64) (*PullRequestComment, *Response, error) { |
||||
comment := &struct { |
||||
Body string `json:"body,omitempty"` |
||||
InReplyTo int64 `json:"in_reply_to,omitempty"` |
||||
}{ |
||||
Body: body, |
||||
InReplyTo: commentID, |
||||
} |
||||
u := fmt.Sprintf("repos/%v/%v/pulls/%d/comments", owner, repo, number) |
||||
req, err := s.client.NewRequest("POST", u, comment) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
c := new(PullRequestComment) |
||||
resp, err := s.client.Do(ctx, req, c) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return c, resp, nil |
||||
} |
||||
|
||||
// EditComment updates a pull request comment.
|
||||
// A non-nil comment.Body must be provided. Other comment fields should be left nil.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/pulls/comments/#edit-a-comment
|
||||
func (s *PullRequestsService) EditComment(ctx context.Context, owner string, repo string, 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,377 @@ |
||||
// 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" |
||||
) |
||||
|
||||
// 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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, req, &m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// CreateCommentReaction creates a reaction for a commit comment.
|
||||
// Note that if you have already created a reaction of type content, the
|
||||
// previously created reaction will be returned with Status: 200 OK.
|
||||
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
|
||||
func (s ReactionsService) CreateCommentReaction(ctx context.Context, owner, repo string, id 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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// 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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, req, &m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// CreateIssueReaction creates a reaction for an issue.
|
||||
// Note that if you have already created a reaction of type content, the
|
||||
// previously created reaction will be returned with Status: 200 OK.
|
||||
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
|
||||
func (s ReactionsService) CreateIssueReaction(ctx context.Context, owner, repo string, number int, content string) (*Reaction, *Response, error) { |
||||
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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// 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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, req, &m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// CreateIssueCommentReaction creates a reaction for an issue comment.
|
||||
// Note that if you have already created a reaction of type content, the
|
||||
// previously created reaction will be returned with Status: 200 OK.
|
||||
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
|
||||
func (s ReactionsService) CreateIssueCommentReaction(ctx context.Context, owner, repo string, id 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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// 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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, req, &m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
|
||||
// Note that if you have already created a reaction of type content, the
|
||||
// previously created reaction will be returned with Status: 200 OK.
|
||||
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
|
||||
func (s ReactionsService) CreatePullRequestCommentReaction(ctx context.Context, owner, repo string, id 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.
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// ListTeamDiscussionReactions lists the reactions for a team discussion.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion
|
||||
func (s *ReactionsService) ListTeamDiscussionReactions(ctx context.Context, teamID int64, discussionNumber int, opt *ListOptions) ([]*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, req, &m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// CreateTeamDiscussionReaction creates a reaction for a team discussion.
|
||||
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion
|
||||
func (s *ReactionsService) CreateTeamDiscussionReaction(ctx context.Context, teamID int64, discussionNumber int, content string) (*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/reactions", teamID, discussionNumber) |
||||
|
||||
body := &Reaction{Content: String(content)} |
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
m := &Reaction{} |
||||
resp, err := s.client.Do(ctx, req, m) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return m, resp, nil |
||||
} |
||||
|
||||
// ListTeamDiscussionCommentReactions lists the reactions for a team discussion comment.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-team-discussion-comment
|
||||
func (s *ReactionsService) ListTeamDiscussionCommentReactions(ctx context.Context, teamID int64, discussionNumber, commentNumber int, opt *ListOptions) ([]*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber) |
||||
u, err := addOptions(u, opt) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("GET", u, nil) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
var m []*Reaction |
||||
resp, err := s.client.Do(ctx, req, &m) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
return m, resp, nil |
||||
} |
||||
|
||||
// CreateTeamDiscussionCommentReaction creates a reaction for a team discussion comment.
|
||||
// The content should have one of the following values: "+1", "-1", "laugh", "confused", "heart", "hooray".
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-team-discussion-comment
|
||||
func (s *ReactionsService) CreateTeamDiscussionCommentReaction(ctx context.Context, teamID int64, discussionNumber, commentNumber int, content string) (*Reaction, *Response, error) { |
||||
u := fmt.Sprintf("teams/%v/discussions/%v/comments/%v/reactions", teamID, discussionNumber, commentNumber) |
||||
|
||||
body := &Reaction{Content: String(content)} |
||||
req, err := s.client.NewRequest("POST", u, body) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
|
||||
req.Header.Set("Accept", mediaTypeReactionsPreview) |
||||
|
||||
m := &Reaction{} |
||||
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,137 @@ |
||||
// 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 |
||||
} |
||||
|
||||
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,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 ( |
||||
"bytes" |
||||
"context" |
||||
"fmt" |
||||
"net/url" |
||||
"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"` |
||||
PreviousFilename *string `json:"previous_filename,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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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, url.QueryEscape(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/#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,59 @@ |
||||
// 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"` |
||||
IssueTemplate *Metric `json:"issue_template"` |
||||
PullRequestTemplate *Metric `json:"pull_request_template"` |
||||
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,269 @@ |
||||
// 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"` |
||||
// Target is only set if the type is "symlink" and the target is not a normal file.
|
||||
// If Target is set, Path will be the symlink path.
|
||||
Target *string `json:"target,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,229 @@ |
||||
// 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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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, mediaTypeExpandDeploymentStatusPreview} |
||||
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"` |
||||
Environment *string `json:"environment,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 |
||||
} |
||||
|
||||
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, mediaTypeExpandDeploymentStatusPreview} |
||||
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, mediaTypeExpandDeploymentStatusPreview} |
||||
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,96 @@ |
||||
// 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" |
||||
|
||||
"encoding/json" |
||||
) |
||||
|
||||
// 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 err != nil { |
||||
// Persist AcceptedError's metadata to the Repository object.
|
||||
if aerr, ok := err.(*AcceptedError); ok { |
||||
if err := json.Unmarshal(aerr.Raw, fork); err != nil { |
||||
return fork, resp, err |
||||
} |
||||
|
||||
return fork, resp, err |
||||
} |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return fork, resp, nil |
||||
} |
@ -0,0 +1,226 @@ |
||||
// 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"` |
||||
URL *string `json:"url,omitempty"` |
||||
ID *int64 `json:"id,omitempty"` |
||||
|
||||
// Only the following fields are used when creating a hook.
|
||||
// Config is required.
|
||||
Config map[string]interface{} `json:"config,omitempty"` |
||||
Events []string `json:"events,omitempty"` |
||||
Active *bool `json:"active,omitempty"` |
||||
} |
||||
|
||||
func (h Hook) String() string { |
||||
return Stringify(h) |
||||
} |
||||
|
||||
// createHookRequest is a subset of Hook and is used internally
|
||||
// by CreateHook to pass only the known fields for the endpoint.
|
||||
//
|
||||
// See https://github.com/google/go-github/issues/1015 for more
|
||||
// information.
|
||||
type createHookRequest struct { |
||||
// Config is required.
|
||||
Name string `json:"name"` |
||||
Config map[string]interface{} `json:"config,omitempty"` |
||||
Events []string `json:"events,omitempty"` |
||||
Active *bool `json:"active,omitempty"` |
||||
} |
||||
|
||||
// CreateHook creates a Hook for the specified repository.
|
||||
// Config is a required field.
|
||||
//
|
||||
// Note that only a subset of the hook fields are used and hook must
|
||||
// not be nil.
|
||||
//
|
||||
// GitHub API docs: https://developer.github.com/v3/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) |
||||
|
||||
hookReq := &createHookRequest{ |
||||
Name: "web", |
||||
Events: hook.Events, |
||||
Active: hook.Active, |
||||
Config: hook.Config, |
||||
} |
||||
|
||||
req, err := s.client.NewRequest("POST", u, hookReq) |
||||
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 |
||||
} |
||||
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/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) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return h, resp, nil |
||||
} |
||||
|
||||
// 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,89 @@ |
||||
// 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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 |
||||
} |
||||
|
||||
invite := &RepositoryInvitation{} |
||||
resp, err := s.client.Do(ctx, req, invite) |
||||
if err != nil { |
||||
return nil, resp, err |
||||
} |
||||
|
||||
return invite, resp, nil |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue