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