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 testsrelease/v1.15
parent
1c7c739eb9
commit
08069dc465
|
@ -66,7 +66,7 @@ coverage.all
|
||||||
/integrations/mssql.ini
|
/integrations/mssql.ini
|
||||||
/node_modules
|
/node_modules
|
||||||
/modules/indexer/issues/indexers
|
/modules/indexer/issues/indexers
|
||||||
|
routers/repo/authorized_keys
|
||||||
|
|
||||||
# Snapcraft
|
# Snapcraft
|
||||||
snap/.snapcraft/
|
snap/.snapcraft/
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
3
go.mod
3
go.mod
|
@ -62,6 +62,7 @@ require (
|
||||||
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
|
github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561
|
||||||
github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183
|
github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183
|
||||||
github.com/gogo/protobuf v1.2.1 // indirect
|
github.com/gogo/protobuf v1.2.1 // indirect
|
||||||
|
github.com/google/go-github/v24 v24.0.1
|
||||||
github.com/gorilla/context v1.1.1
|
github.com/gorilla/context v1.1.1
|
||||||
github.com/issue9/assert v1.3.2 // indirect
|
github.com/issue9/assert v1.3.2 // indirect
|
||||||
github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c
|
github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c
|
||||||
|
@ -115,7 +116,7 @@ require (
|
||||||
go.etcd.io/bbolt v1.3.2 // indirect
|
go.etcd.io/bbolt v1.3.2 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519
|
||||||
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 // indirect
|
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
|
||||||
golang.org/x/text v0.3.0
|
golang.org/x/text v0.3.0
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -142,6 +142,12 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
|
github.com/google/go-github/v24 v24.0.1 h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju57UR4Q4=
|
||||||
|
github.com/google/go-github/v24 v24.0.1/go.mod h1:CRqaW1Uns1TCkP0wqTpxYyRxRjxwvKU/XSS44u6X74M=
|
||||||
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||||
|
@ -309,17 +315,21 @@ github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
|
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 h1:x6rhz8Y9CjbgQkccRGmELH6K+LJj7tOoh3XWeC1yaQM=
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 h1:x6rhz8Y9CjbgQkccRGmELH6K+LJj7tOoh3XWeC1yaQM=
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h5Hmyb5+VDjEiMufAEAM04=
|
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h5Hmyb5+VDjEiMufAEAM04=
|
||||||
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||||
|
@ -327,6 +337,7 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24=
|
google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24=
|
||||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -107,6 +107,7 @@ func TestRelease_MirrorDelete(t *testing.T) {
|
||||||
IsPrivate: false,
|
IsPrivate: false,
|
||||||
IsMirror: true,
|
IsMirror: true,
|
||||||
RemoteAddr: repoPath,
|
RemoteAddr: repoPath,
|
||||||
|
Wiki: true,
|
||||||
}
|
}
|
||||||
mirror, err := MigrateRepository(user, user, migrationOptions)
|
mirror, err := MigrateRepository(user, user, migrationOptions)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -896,6 +896,7 @@ type MigrateRepoOptions struct {
|
||||||
IsPrivate bool
|
IsPrivate bool
|
||||||
IsMirror bool
|
IsMirror bool
|
||||||
RemoteAddr string
|
RemoteAddr string
|
||||||
|
Wiki bool // include wiki repository
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -917,7 +918,7 @@ func wikiRemoteURL(remote string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// MigrateRepository migrates a existing repository from other project hosting.
|
// MigrateRepository migrates an existing repository from other project hosting.
|
||||||
func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, error) {
|
func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, error) {
|
||||||
repo, err := CreateRepository(doer, u, CreateRepoOptions{
|
repo, err := CreateRepository(doer, u, CreateRepoOptions{
|
||||||
Name: opts.Name,
|
Name: opts.Name,
|
||||||
|
@ -930,7 +931,6 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err
|
||||||
}
|
}
|
||||||
|
|
||||||
repoPath := RepoPath(u.Name, opts.Name)
|
repoPath := RepoPath(u.Name, opts.Name)
|
||||||
wikiPath := WikiPath(u.Name, opts.Name)
|
|
||||||
|
|
||||||
if u.IsOrganization() {
|
if u.IsOrganization() {
|
||||||
t, err := u.GetOwnerTeam()
|
t, err := u.GetOwnerTeam()
|
||||||
|
@ -956,22 +956,25 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err
|
||||||
return repo, fmt.Errorf("Clone: %v", err)
|
return repo, fmt.Errorf("Clone: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
|
if opts.Wiki {
|
||||||
if len(wikiRemotePath) > 0 {
|
wikiPath := WikiPath(u.Name, opts.Name)
|
||||||
if err := os.RemoveAll(wikiPath); err != nil {
|
wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
|
||||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
|
if len(wikiRemotePath) > 0 {
|
||||||
}
|
|
||||||
|
|
||||||
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
|
||||||
Mirror: true,
|
|
||||||
Quiet: true,
|
|
||||||
Timeout: migrateTimeout,
|
|
||||||
Branch: "master",
|
|
||||||
}); err != nil {
|
|
||||||
log.Warn("Clone wiki: %v", err)
|
|
||||||
if err := os.RemoveAll(wikiPath); err != nil {
|
if err := os.RemoveAll(wikiPath); err != nil {
|
||||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
|
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
||||||
|
Mirror: true,
|
||||||
|
Quiet: true,
|
||||||
|
Timeout: migrateTimeout,
|
||||||
|
Branch: "master",
|
||||||
|
}); err != nil {
|
||||||
|
log.Warn("Clone wiki: %v", err)
|
||||||
|
if err := os.RemoveAll(wikiPath); err != nil {
|
||||||
|
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,16 @@ type MigrateRepoForm struct {
|
||||||
// required: true
|
// required: true
|
||||||
UID int64 `json:"uid" binding:"Required"`
|
UID int64 `json:"uid" binding:"Required"`
|
||||||
// required: true
|
// required: true
|
||||||
RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||||
Mirror bool `json:"mirror"`
|
Mirror bool `json:"mirror"`
|
||||||
Private bool `json:"private"`
|
Private bool `json:"private"`
|
||||||
Description string `json:"description" binding:"MaxSize(255)"`
|
Description string `json:"description" binding:"MaxSize(255)"`
|
||||||
|
Wiki bool `json:"wiki"`
|
||||||
|
Milestones bool `json:"milestones"`
|
||||||
|
Labels bool `json:"labels"`
|
||||||
|
Issues bool `json:"issues"`
|
||||||
|
PullRequests bool `json:"pull_requests"`
|
||||||
|
Releases bool `json:"releases"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -301,6 +301,8 @@ password_not_match = The passwords do not match.
|
||||||
|
|
||||||
username_been_taken = The username is already taken.
|
username_been_taken = The username is already taken.
|
||||||
repo_name_been_taken = The repository name is already used.
|
repo_name_been_taken = The repository name is already used.
|
||||||
|
visit_rate_limit = Remote visit addressed rate limitation.
|
||||||
|
2fa_auth_required = Remote visit required two factors authentication.
|
||||||
org_name_been_taken = The organization name is already taken.
|
org_name_been_taken = The organization name is already taken.
|
||||||
team_name_been_taken = The team name is already taken.
|
team_name_been_taken = The team name is already taken.
|
||||||
team_no_units_error = Allow access to at least one repository section.
|
team_no_units_error = Allow access to at least one repository section.
|
||||||
|
@ -597,6 +599,13 @@ form.name_pattern_not_allowed = The pattern '%s' is not allowed in a repository
|
||||||
need_auth = Clone Authorization
|
need_auth = Clone Authorization
|
||||||
migrate_type = Migration Type
|
migrate_type = Migration Type
|
||||||
migrate_type_helper = This repository will be a <span class="text blue">mirror</span>
|
migrate_type_helper = This repository will be a <span class="text blue">mirror</span>
|
||||||
|
migrate_items = Migration Items
|
||||||
|
migrate_items_wiki = Wiki
|
||||||
|
migrate_items_milestones = Milestones
|
||||||
|
migrate_items_labels = Labels
|
||||||
|
migrate_items_issues = Issues
|
||||||
|
migrate_items_pullrequests = Pull Requests
|
||||||
|
migrate_items_releases = Releases
|
||||||
migrate_repo = Migrate Repository
|
migrate_repo = Migrate Repository
|
||||||
migrate.clone_address = Migrate / Clone From URL
|
migrate.clone_address = Migrate / Clone From URL
|
||||||
migrate.clone_address_desc = The HTTP(S) or Git 'clone' URL of an existing repository
|
migrate.clone_address_desc = The HTTP(S) or Git 'clone' URL of an existing repository
|
||||||
|
@ -605,6 +614,7 @@ migrate.permission_denied = You are not allowed to import local repositories.
|
||||||
migrate.invalid_local_path = "The local path is invalid. It does not exist or is not a directory."
|
migrate.invalid_local_path = "The local path is invalid. It does not exist or is not a directory."
|
||||||
migrate.failed = Migration failed: %v
|
migrate.failed = Migration failed: %v
|
||||||
migrate.lfs_mirror_unsupported = Mirroring LFS objects is not supported - use 'git lfs fetch --all' and 'git lfs push --all' instead.
|
migrate.lfs_mirror_unsupported = Mirroring LFS objects is not supported - use 'git lfs fetch --all' and 'git lfs push --all' instead.
|
||||||
|
migrate.migrate_items_options = When you are migrating from github and inputed username, the migration options will be display.
|
||||||
|
|
||||||
mirror_from = mirror of
|
mirror_from = mirror of
|
||||||
forked_from = forked from
|
forked_from = forked from
|
||||||
|
|
|
@ -979,6 +979,25 @@ function initRepository() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var toggleMigrations = function(){
|
||||||
|
var authUserName = $('#auth_username').val();
|
||||||
|
var cloneAddr = $('#clone_addr').val();
|
||||||
|
if (!$('#mirror').is(":checked") && (authUserName!=undefined && authUserName.length > 0)
|
||||||
|
&& (cloneAddr!=undefined && (cloneAddr.startsWith("https://github.com") || cloneAddr.startsWith("http://github.com")))) {
|
||||||
|
$('#migrate_items').show();
|
||||||
|
} else {
|
||||||
|
$('#migrate_items').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initMigration() {
|
||||||
|
toggleMigrations();
|
||||||
|
|
||||||
|
$('#clone_addr').on('input', toggleMigrations)
|
||||||
|
$('#auth_username').on('input', toggleMigrations)
|
||||||
|
$('#mirror').on('change', toggleMigrations)
|
||||||
|
}
|
||||||
|
|
||||||
function initPullRequestReview() {
|
function initPullRequestReview() {
|
||||||
$('.show-outdated').on('click', function (e) {
|
$('.show-outdated').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -2101,6 +2120,7 @@ $(document).ready(function () {
|
||||||
initCommentForm();
|
initCommentForm();
|
||||||
initInstall();
|
initInstall();
|
||||||
initRepository();
|
initRepository();
|
||||||
|
initMigration();
|
||||||
initWikiForm();
|
initWikiForm();
|
||||||
initEditForm();
|
initEditForm();
|
||||||
initEditor();
|
initEditor();
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/auth"
|
"code.gitea.io/gitea/modules/auth"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/migrations"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||||
|
@ -401,31 +402,63 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := models.MigrateRepository(ctx.User, ctxUser, models.MigrateRepoOptions{
|
var opts = migrations.MigrateOptions{
|
||||||
Name: form.RepoName,
|
RemoteURL: remoteAddr,
|
||||||
Description: form.Description,
|
Name: form.RepoName,
|
||||||
IsPrivate: form.Private || setting.Repository.ForcePrivate,
|
Description: form.Description,
|
||||||
IsMirror: form.Mirror,
|
Private: form.Private || setting.Repository.ForcePrivate,
|
||||||
RemoteAddr: remoteAddr,
|
Mirror: form.Mirror,
|
||||||
})
|
AuthUsername: form.AuthUsername,
|
||||||
if err != nil {
|
AuthPassword: form.AuthPassword,
|
||||||
if models.IsErrRepoAlreadyExist(err) {
|
Wiki: form.Wiki,
|
||||||
ctx.Error(409, "", "The repository with the same name already exists.")
|
Issues: form.Issues,
|
||||||
return
|
Milestones: form.Milestones,
|
||||||
}
|
Labels: form.Labels,
|
||||||
|
Comments: true,
|
||||||
|
PullRequests: form.PullRequests,
|
||||||
|
Releases: form.Releases,
|
||||||
|
}
|
||||||
|
if opts.Mirror {
|
||||||
|
opts.Issues = false
|
||||||
|
opts.Milestones = false
|
||||||
|
opts.Labels = false
|
||||||
|
opts.Comments = false
|
||||||
|
opts.PullRequests = false
|
||||||
|
opts.Releases = false
|
||||||
|
}
|
||||||
|
|
||||||
err = util.URLSanitizedError(err, remoteAddr)
|
repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts)
|
||||||
if repo != nil {
|
if err == nil {
|
||||||
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
|
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
|
||||||
log.Error("DeleteRepository: %v", errDelete)
|
ctx.JSON(201, repo.APIFormat(models.AccessModeAdmin))
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.Error(500, "MigrateRepository", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
|
switch {
|
||||||
ctx.JSON(201, repo.APIFormat(models.AccessModeAdmin))
|
case models.IsErrRepoAlreadyExist(err):
|
||||||
|
ctx.Error(409, "", "The repository with the same name already exists.")
|
||||||
|
case migrations.IsRateLimitError(err):
|
||||||
|
ctx.Error(422, "", "Remote visit addressed rate limitation.")
|
||||||
|
case migrations.IsTwoFactorAuthError(err):
|
||||||
|
ctx.Error(422, "", "Remote visit required two factors authentication.")
|
||||||
|
case models.IsErrReachLimitOfRepo(err):
|
||||||
|
ctx.Error(422, "", fmt.Sprintf("You have already reached your limit of %d repositories.", ctxUser.MaxCreationLimit()))
|
||||||
|
case models.IsErrNameReserved(err):
|
||||||
|
ctx.Error(422, "", fmt.Sprintf("The username '%s' is reserved.", err.(models.ErrNameReserved).Name))
|
||||||
|
case models.IsErrNamePatternNotAllowed(err):
|
||||||
|
ctx.Error(422, "", fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(models.ErrNamePatternNotAllowed).Pattern))
|
||||||
|
default:
|
||||||
|
err = util.URLSanitizedError(err, remoteAddr)
|
||||||
|
if strings.Contains(err.Error(), "Authentication failed") ||
|
||||||
|
strings.Contains(err.Error(), "Bad credentials") ||
|
||||||
|
strings.Contains(err.Error(), "could not read Username") {
|
||||||
|
ctx.Error(422, "", fmt.Sprintf("Authentication failed: %v.", err))
|
||||||
|
} else if strings.Contains(err.Error(), "fatal:") {
|
||||||
|
ctx.Error(422, "", fmt.Sprintf("Migration failed: %v.", err))
|
||||||
|
} else {
|
||||||
|
ctx.Error(500, "MigrateRepository", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get one repository
|
// Get one repository
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/migrations"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
|
@ -130,6 +131,8 @@ func Create(ctx *context.Context) {
|
||||||
|
|
||||||
func handleCreateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form interface{}) {
|
func handleCreateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form interface{}) {
|
||||||
switch {
|
switch {
|
||||||
|
case migrations.IsRateLimitError(err):
|
||||||
|
ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form)
|
||||||
case models.IsErrReachLimitOfRepo(err):
|
case models.IsErrReachLimitOfRepo(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
|
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case models.IsErrRepoAlreadyExist(err):
|
||||||
|
@ -195,6 +198,12 @@ func Migrate(ctx *context.Context) {
|
||||||
ctx.Data["private"] = getRepoPrivate(ctx)
|
ctx.Data["private"] = getRepoPrivate(ctx)
|
||||||
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
|
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
|
||||||
ctx.Data["mirror"] = ctx.Query("mirror") == "1"
|
ctx.Data["mirror"] = ctx.Query("mirror") == "1"
|
||||||
|
ctx.Data["wiki"] = ctx.Query("wiki") == "1"
|
||||||
|
ctx.Data["milestones"] = ctx.Query("milestones") == "1"
|
||||||
|
ctx.Data["labels"] = ctx.Query("labels") == "1"
|
||||||
|
ctx.Data["issues"] = ctx.Query("issues") == "1"
|
||||||
|
ctx.Data["pull_requests"] = ctx.Query("pull_requests") == "1"
|
||||||
|
ctx.Data["releases"] = ctx.Query("releases") == "1"
|
||||||
ctx.Data["LFSActive"] = setting.LFS.StartServer
|
ctx.Data["LFSActive"] = setting.LFS.StartServer
|
||||||
|
|
||||||
ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
|
ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
|
||||||
|
@ -242,45 +251,70 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := models.MigrateRepository(ctx.User, ctxUser, models.MigrateRepoOptions{
|
var opts = migrations.MigrateOptions{
|
||||||
Name: form.RepoName,
|
RemoteURL: remoteAddr,
|
||||||
Description: form.Description,
|
Name: form.RepoName,
|
||||||
IsPrivate: form.Private || setting.Repository.ForcePrivate,
|
Description: form.Description,
|
||||||
IsMirror: form.Mirror,
|
Private: form.Private || setting.Repository.ForcePrivate,
|
||||||
RemoteAddr: remoteAddr,
|
Mirror: form.Mirror,
|
||||||
})
|
AuthUsername: form.AuthUsername,
|
||||||
|
AuthPassword: form.AuthPassword,
|
||||||
|
Wiki: form.Wiki,
|
||||||
|
Issues: form.Issues,
|
||||||
|
Milestones: form.Milestones,
|
||||||
|
Labels: form.Labels,
|
||||||
|
Comments: true,
|
||||||
|
PullRequests: form.PullRequests,
|
||||||
|
Releases: form.Releases,
|
||||||
|
}
|
||||||
|
if opts.Mirror {
|
||||||
|
opts.Issues = false
|
||||||
|
opts.Milestones = false
|
||||||
|
opts.Labels = false
|
||||||
|
opts.Comments = false
|
||||||
|
opts.PullRequests = false
|
||||||
|
opts.Releases = false
|
||||||
|
}
|
||||||
|
|
||||||
|
repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Trace("Repository migrated [%d]: %s/%s", repo.ID, ctxUser.Name, form.RepoName)
|
log.Trace("Repository migrated [%d]: %s/%s successfully", repo.ID, ctxUser.Name, form.RepoName)
|
||||||
ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + form.RepoName)
|
ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + form.RepoName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if models.IsErrRepoAlreadyExist(err) {
|
switch {
|
||||||
|
case models.IsErrReachLimitOfRepo(err):
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", ctxUser.MaxCreationLimit()), tplMigrate, &form)
|
||||||
|
case models.IsErrNameReserved(err):
|
||||||
|
ctx.Data["Err_RepoName"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tplMigrate, &form)
|
||||||
|
case models.IsErrRepoAlreadyExist(err):
|
||||||
|
ctx.Data["Err_RepoName"] = true
|
||||||
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplMigrate, &form)
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplMigrate, &form)
|
||||||
return
|
case models.IsErrNamePatternNotAllowed(err):
|
||||||
}
|
ctx.Data["Err_RepoName"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplMigrate, &form)
|
||||||
// remoteAddr may contain credentials, so we sanitize it
|
case migrations.IsRateLimitError(err):
|
||||||
err = util.URLSanitizedError(err, remoteAddr)
|
ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tplMigrate, &form)
|
||||||
|
case migrations.IsTwoFactorAuthError(err):
|
||||||
if repo != nil {
|
ctx.Data["Err_Auth"] = true
|
||||||
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
|
ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tplMigrate, &form)
|
||||||
log.Error("DeleteRepository: %v", errDelete)
|
default:
|
||||||
|
// remoteAddr may contain credentials, so we sanitize it
|
||||||
|
err = util.URLSanitizedError(err, remoteAddr)
|
||||||
|
if strings.Contains(err.Error(), "Authentication failed") ||
|
||||||
|
strings.Contains(err.Error(), "Bad credentials") ||
|
||||||
|
strings.Contains(err.Error(), "could not read Username") {
|
||||||
|
ctx.Data["Err_Auth"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tplMigrate, &form)
|
||||||
|
} else if strings.Contains(err.Error(), "fatal:") {
|
||||||
|
ctx.Data["Err_CloneAddr"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tplMigrate, &form)
|
||||||
|
} else {
|
||||||
|
ctx.ServerError("MigratePost", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(err.Error(), "Authentication failed") ||
|
|
||||||
strings.Contains(err.Error(), "could not read Username") {
|
|
||||||
ctx.Data["Err_Auth"] = true
|
|
||||||
ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tplMigrate, &form)
|
|
||||||
return
|
|
||||||
} else if strings.Contains(err.Error(), "fatal:") {
|
|
||||||
ctx.Data["Err_CloneAddr"] = true
|
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tplMigrate, &form)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action response for actions to a repository
|
// Action response for actions to a repository
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
<span class="help">
|
<span class="help">
|
||||||
{{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}}
|
{{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}}
|
||||||
|
<br/>{{.i18n.Tr "repo.migrate.migrate_items_options"}}
|
||||||
{{if .LFSActive}}<br/>{{.i18n.Tr "repo.migrate.lfs_mirror_unsupported"}}{{end}}
|
{{if .LFSActive}}<br/>{{.i18n.Tr "repo.migrate.lfs_mirror_unsupported"}}{{end}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,10 +81,45 @@
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label>{{.i18n.Tr "repo.migrate_type"}}</label>
|
<label>{{.i18n.Tr "repo.migrate_type"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input name="mirror" type="checkbox" {{if .mirror}}checked{{end}}>
|
<input id="mirror" name="mirror" type="checkbox" {{if .mirror}}checked{{end}}>
|
||||||
<label>{{.i18n.Tr "repo.migrate_type_helper" | Safe}}</label>
|
<label>{{.i18n.Tr "repo.migrate_type_helper" | Safe}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="migrate_items" class="ui field">
|
||||||
|
<div class="inline field">
|
||||||
|
<label>{{.i18n.Tr "repo.migrate_items"}}</label>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input name="wiki" type="checkbox" {{if .wiki}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_wiki" | Safe}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_milestones" | Safe}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="inline field">
|
||||||
|
<label></label>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input name="labels" type="checkbox" {{if .labels}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_labels" | Safe}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input name="issues" type="checkbox" {{if .issues}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_issues" | Safe}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="inline field">
|
||||||
|
<label></label>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_pullrequests" | Safe}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input name="releases" type="checkbox" {{if .releases}}checked{{end}}>
|
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_releases" | Safe}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="inline field {{if .Err_Description}}error{{end}}">
|
<div class="inline field {{if .Err_Description}}error{{end}}">
|
||||||
<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label>
|
<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label>
|
||||||
<textarea id="description" name="description">{{.description}}</textarea>
|
<textarea id="description" name="description">{{.description}}</textarea>
|
||||||
|
|
|
@ -8479,6 +8479,18 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Description"
|
"x-go-name": "Description"
|
||||||
},
|
},
|
||||||
|
"issues": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "Issues"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "Labels"
|
||||||
|
},
|
||||||
|
"milestones": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "Milestones"
|
||||||
|
},
|
||||||
"mirror": {
|
"mirror": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "Mirror"
|
"x-go-name": "Mirror"
|
||||||
|
@ -8487,6 +8499,14 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "Private"
|
"x-go-name": "Private"
|
||||||
},
|
},
|
||||||
|
"pull_requests": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "PullRequests"
|
||||||
|
},
|
||||||
|
"releases": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "Releases"
|
||||||
|
},
|
||||||
"repo_name": {
|
"repo_name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "RepoName"
|
"x-go-name": "RepoName"
|
||||||
|
@ -8495,6 +8515,10 @@
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
"x-go-name": "UID"
|
"x-go-name": "UID"
|
||||||
|
},
|
||||||
|
"wiki": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "Wiki"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/auth"
|
"x-go-package": "code.gitea.io/gitea/modules/auth"
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
223
vendor/github.com/google/go-github/v24/github/activity_notifications.go
generated
vendored
Normal file
223
vendor/github.com/google/go-github/v24/github/activity_notifications.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
146
vendor/github.com/google/go-github/v24/github/activity_watching.go
generated
vendored
Normal file
146
vendor/github.com/google/go-github/v24/github/activity_watching.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
103
vendor/github.com/google/go-github/v24/github/apps_installation.go
generated
vendored
Normal file
103
vendor/github.com/google/go-github/v24/github/apps_installation.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
183
vendor/github.com/google/go-github/v24/github/apps_marketplace.go
generated
vendored
Normal file
183
vendor/github.com/google/go-github/v24/github/apps_marketplace.go
generated
vendored
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
// Copyright 2017 The go-github AUTHORS. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarketplaceService handles communication with the marketplace related
|
||||||
|
// methods of the GitHub API.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
|
||||||
|
type MarketplaceService struct {
|
||||||
|
client *Client
|
||||||
|
// Stubbed controls whether endpoints that return stubbed data are used
|
||||||
|
// instead of production endpoints. Stubbed data is fake data that's useful
|
||||||
|
// for testing your GitHub Apps. Stubbed data is hard-coded and will not
|
||||||
|
// change based on actual subscriptions.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/
|
||||||
|
Stubbed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarketplacePlan represents a GitHub Apps Marketplace Listing Plan.
|
||||||
|
type MarketplacePlan struct {
|
||||||
|
URL *string `json:"url,omitempty"`
|
||||||
|
AccountsURL *string `json:"accounts_url,omitempty"`
|
||||||
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
Description *string `json:"description,omitempty"`
|
||||||
|
MonthlyPriceInCents *int `json:"monthly_price_in_cents,omitempty"`
|
||||||
|
YearlyPriceInCents *int `json:"yearly_price_in_cents,omitempty"`
|
||||||
|
// The pricing model for this listing. Can be one of "flat-rate", "per-unit", or "free".
|
||||||
|
PriceModel *string `json:"price_model,omitempty"`
|
||||||
|
UnitName *string `json:"unit_name,omitempty"`
|
||||||
|
Bullets *[]string `json:"bullets,omitempty"`
|
||||||
|
// State can be one of the values "draft" or "published".
|
||||||
|
State *string `json:"state,omitempty"`
|
||||||
|
HasFreeTrial *bool `json:"has_free_trial,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarketplacePurchase represents a GitHub Apps Marketplace Purchase.
|
||||||
|
type MarketplacePurchase struct {
|
||||||
|
// BillingCycle can be one of the values "yearly", "monthly" or nil.
|
||||||
|
BillingCycle *string `json:"billing_cycle,omitempty"`
|
||||||
|
NextBillingDate *Timestamp `json:"next_billing_date,omitempty"`
|
||||||
|
UnitCount *int `json:"unit_count,omitempty"`
|
||||||
|
Plan *MarketplacePlan `json:"plan,omitempty"`
|
||||||
|
Account *MarketplacePlanAccount `json:"account,omitempty"`
|
||||||
|
OnFreeTrial *bool `json:"on_free_trial,omitempty"`
|
||||||
|
FreeTrialEndsOn *Timestamp `json:"free_trial_ends_on,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarketplacePendingChange represents a pending change to a GitHub Apps Marketplace Plan.
|
||||||
|
type MarketplacePendingChange struct {
|
||||||
|
EffectiveDate *Timestamp `json:"effective_date,omitempty"`
|
||||||
|
UnitCount *int `json:"unit_count,omitempty"`
|
||||||
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
Plan *MarketplacePlan `json:"plan,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarketplacePlanAccount represents a GitHub Account (user or organization) on a specific plan.
|
||||||
|
type MarketplacePlanAccount struct {
|
||||||
|
URL *string `json:"url,omitempty"`
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
ID *int64 `json:"id,omitempty"`
|
||||||
|
Login *string `json:"login,omitempty"`
|
||||||
|
Email *string `json:"email,omitempty"`
|
||||||
|
OrganizationBillingEmail *string `json:"organization_billing_email,omitempty"`
|
||||||
|
MarketplacePurchase *MarketplacePurchase `json:"marketplace_purchase,omitempty"`
|
||||||
|
MarketplacePendingChange *MarketplacePendingChange `json:"marketplace_pending_change,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPlans lists all plans for your Marketplace listing.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-plans-for-your-marketplace-listing
|
||||||
|
func (s *MarketplaceService) ListPlans(ctx context.Context, opt *ListOptions) ([]*MarketplacePlan, *Response, error) {
|
||||||
|
uri := s.marketplaceURI("plans")
|
||||||
|
u, err := addOptions(uri, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var plans []*MarketplacePlan
|
||||||
|
resp, err := s.client.Do(ctx, req, &plans)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return plans, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPlanAccountsForPlan lists all GitHub accounts (user or organization) on a specific plan.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#list-all-github-accounts-user-or-organization-on-a-specific-plan
|
||||||
|
func (s *MarketplaceService) ListPlanAccountsForPlan(ctx context.Context, planID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) {
|
||||||
|
uri := s.marketplaceURI(fmt.Sprintf("plans/%v/accounts", planID))
|
||||||
|
u, err := addOptions(uri, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var accounts []*MarketplacePlanAccount
|
||||||
|
resp, err := s.client.Do(ctx, req, &accounts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accounts, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPlanAccountsForAccount lists all GitHub accounts (user or organization) associated with an account.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#check-if-a-github-account-is-associated-with-any-marketplace-listing
|
||||||
|
func (s *MarketplaceService) ListPlanAccountsForAccount(ctx context.Context, accountID int64, opt *ListOptions) ([]*MarketplacePlanAccount, *Response, error) {
|
||||||
|
uri := s.marketplaceURI(fmt.Sprintf("accounts/%v", accountID))
|
||||||
|
u, err := addOptions(uri, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var accounts []*MarketplacePlanAccount
|
||||||
|
resp, err := s.client.Do(ctx, req, &accounts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accounts, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMarketplacePurchasesForUser lists all GitHub marketplace purchases made by a user.
|
||||||
|
//
|
||||||
|
// GitHub API docs: https://developer.github.com/v3/apps/marketplace/#get-a-users-marketplace-purchases
|
||||||
|
func (s *MarketplaceService) ListMarketplacePurchasesForUser(ctx context.Context, opt *ListOptions) ([]*MarketplacePurchase, *Response, error) {
|
||||||
|
uri := "user/marketplace_purchases"
|
||||||
|
if s.Stubbed {
|
||||||
|
uri = "user/marketplace_purchases/stubbed"
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := addOptions(uri, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := s.client.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var purchases []*MarketplacePurchase
|
||||||
|
resp, err := s.client.Do(ctx, req, &purchases)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
return purchases, resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MarketplaceService) marketplaceURI(endpoint string) string {
|
||||||
|
url := "marketplace_listing"
|
||||||
|
if s.Stubbed {
|
||||||
|
url = "marketplace_listing/stubbed"
|
||||||
|
}
|
||||||
|
return url + "/" + endpoint
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
12413
vendor/github.com/google/go-github/v24/github/github-accessors.go
generated
vendored
Normal file
12413
vendor/github.com/google/go-github/v24/github/github-accessors.go
generated
vendored
Normal file
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"`
|
||||||
|
}
|
80
vendor/github.com/google/go-github/v24/github/interactions_orgs.go
generated
vendored
Normal file
80
vendor/github.com/google/go-github/v24/github/interactions_orgs.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
80
vendor/github.com/google/go-github/v24/github/interactions_repos.go
generated
vendored
Normal file
80
vendor/github.com/google/go-github/v24/github/interactions_repos.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
148
vendor/github.com/google/go-github/v24/github/issues_milestones.go
generated
vendored
Normal file
148
vendor/github.com/google/go-github/v24/github/issues_milestones.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
329
vendor/github.com/google/go-github/v24/github/migrations_source_import.go
generated
vendored
Normal file
329
vendor/github.com/google/go-github/v24/github/migrations_source_import.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
81
vendor/github.com/google/go-github/v24/github/orgs_outside_collaborators.go
generated
vendored
Normal file
81
vendor/github.com/google/go-github/v24/github/orgs_outside_collaborators.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
91
vendor/github.com/google/go-github/v24/github/orgs_users_blocking.go
generated
vendored
Normal file
91
vendor/github.com/google/go-github/v24/github/orgs_users_blocking.go
generated
vendored
Normal file
|
@ -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
137
vendor/github.com/google/go-github/v24/github/repos_collaborators.go
generated
vendored
Normal file
137
vendor/github.com/google/go-github/v24/github/repos_collaborators.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
59
vendor/github.com/google/go-github/v24/github/repos_community_health.go
generated
vendored
Normal file
59
vendor/github.com/google/go-github/v24/github/repos_community_health.go
generated
vendored
Normal file
|
@ -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
|
||||||
|
}
|
229
vendor/github.com/google/go-github/v24/github/repos_deployments.go
generated
vendored
Normal file
229
vendor/github.com/google/go-github/v24/github/repos_deployments.go
generated
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
89
vendor/github.com/google/go-github/v24/github/repos_invitations.go
generated
vendored
Normal file
89
vendor/github.com/google/go-github/v24/github/repos_invitations.go
generated
vendored
Normal file
|
@ -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