Add support to migrate from gogs (#14342)
Add support to migrate gogs: * issues * comments * labels * milestones * wiki Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Andrew Thornton <art27@cantab.net>tokarchuk/v1.17
parent
b5570d3e68
commit
81c833d92d
@ -0,0 +1,26 @@ |
||||
// Copyright 2021 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 "fmt" |
||||
|
||||
// ErrNotSupported represents status if a downloader do not supported something.
|
||||
type ErrNotSupported struct { |
||||
Entity string |
||||
} |
||||
|
||||
// IsErrNotSupported checks if an error is an ErrNotSupported
|
||||
func IsErrNotSupported(err error) bool { |
||||
_, ok := err.(ErrNotSupported) |
||||
return ok |
||||
} |
||||
|
||||
// Error return error message
|
||||
func (err ErrNotSupported) Error() string { |
||||
if len(err.Entity) != 0 { |
||||
return fmt.Sprintf("'%s' not supported", err.Entity) |
||||
} |
||||
return "not supported" |
||||
} |
@ -0,0 +1,82 @@ |
||||
// Copyright 2021 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 ( |
||||
"context" |
||||
"net/url" |
||||
) |
||||
|
||||
// NullDownloader implements a blank downloader
|
||||
type NullDownloader struct { |
||||
} |
||||
|
||||
var ( |
||||
_ Downloader = &NullDownloader{} |
||||
) |
||||
|
||||
// SetContext set context
|
||||
func (n NullDownloader) SetContext(_ context.Context) {} |
||||
|
||||
// GetRepoInfo returns a repository information
|
||||
func (n NullDownloader) GetRepoInfo() (*Repository, error) { |
||||
return nil, &ErrNotSupported{Entity: "RepoInfo"} |
||||
} |
||||
|
||||
// GetTopics return repository topics
|
||||
func (n NullDownloader) GetTopics() ([]string, error) { |
||||
return nil, &ErrNotSupported{Entity: "Topics"} |
||||
} |
||||
|
||||
// GetMilestones returns milestones
|
||||
func (n NullDownloader) GetMilestones() ([]*Milestone, error) { |
||||
return nil, &ErrNotSupported{Entity: "Milestones"} |
||||
} |
||||
|
||||
// GetReleases returns releases
|
||||
func (n NullDownloader) GetReleases() ([]*Release, error) { |
||||
return nil, &ErrNotSupported{Entity: "Releases"} |
||||
} |
||||
|
||||
// GetLabels returns labels
|
||||
func (n NullDownloader) GetLabels() ([]*Label, error) { |
||||
return nil, &ErrNotSupported{Entity: "Labels"} |
||||
} |
||||
|
||||
// GetIssues returns issues according start and limit
|
||||
func (n NullDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { |
||||
return nil, false, &ErrNotSupported{Entity: "Issues"} |
||||
} |
||||
|
||||
// GetComments returns comments according issueNumber
|
||||
func (n NullDownloader) GetComments(issueNumber int64) ([]*Comment, error) { |
||||
return nil, &ErrNotSupported{Entity: "Comments"} |
||||
} |
||||
|
||||
// GetPullRequests returns pull requests according page and perPage
|
||||
func (n NullDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) { |
||||
return nil, false, &ErrNotSupported{Entity: "PullRequests"} |
||||
} |
||||
|
||||
// GetReviews returns pull requests review
|
||||
func (n NullDownloader) GetReviews(pullRequestNumber int64) ([]*Review, error) { |
||||
return nil, &ErrNotSupported{Entity: "Reviews"} |
||||
} |
||||
|
||||
// FormatCloneURL add authentification into remote URLs
|
||||
func (n NullDownloader) FormatCloneURL(opts MigrateOptions, remoteAddr string) (string, error) { |
||||
if len(opts.AuthToken) > 0 || len(opts.AuthUsername) > 0 { |
||||
u, err := url.Parse(remoteAddr) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
u.User = url.UserPassword(opts.AuthUsername, opts.AuthPassword) |
||||
if len(opts.AuthToken) > 0 { |
||||
u.User = url.UserPassword("oauth2", opts.AuthToken) |
||||
} |
||||
return u.String(), nil |
||||
} |
||||
return remoteAddr, nil |
||||
} |
@ -0,0 +1,247 @@ |
||||
// Copyright 2021 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 ( |
||||
"context" |
||||
"time" |
||||
) |
||||
|
||||
var ( |
||||
_ Downloader = &RetryDownloader{} |
||||
) |
||||
|
||||
// RetryDownloader retry the downloads
|
||||
type RetryDownloader struct { |
||||
Downloader |
||||
ctx context.Context |
||||
RetryTimes int // the total execute times
|
||||
RetryDelay int // time to delay seconds
|
||||
} |
||||
|
||||
// NewRetryDownloader creates a retry downloader
|
||||
func NewRetryDownloader(ctx context.Context, downloader Downloader, retryTimes, retryDelay int) *RetryDownloader { |
||||
return &RetryDownloader{ |
||||
Downloader: downloader, |
||||
ctx: ctx, |
||||
RetryTimes: retryTimes, |
||||
RetryDelay: retryDelay, |
||||
} |
||||
} |
||||
|
||||
// SetContext set context
|
||||
func (d *RetryDownloader) SetContext(ctx context.Context) { |
||||
d.ctx = ctx |
||||
d.Downloader.SetContext(ctx) |
||||
} |
||||
|
||||
// GetRepoInfo returns a repository information with retry
|
||||
func (d *RetryDownloader) GetRepoInfo() (*Repository, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
repo *Repository |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if repo, err = d.Downloader.GetRepoInfo(); err == nil { |
||||
return repo, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetTopics returns a repository's topics with retry
|
||||
func (d *RetryDownloader) GetTopics() ([]string, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
topics []string |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if topics, err = d.Downloader.GetTopics(); err == nil { |
||||
return topics, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetMilestones returns a repository's milestones with retry
|
||||
func (d *RetryDownloader) GetMilestones() ([]*Milestone, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
milestones []*Milestone |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if milestones, err = d.Downloader.GetMilestones(); err == nil { |
||||
return milestones, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetReleases returns a repository's releases with retry
|
||||
func (d *RetryDownloader) GetReleases() ([]*Release, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
releases []*Release |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if releases, err = d.Downloader.GetReleases(); err == nil { |
||||
return releases, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetLabels returns a repository's labels with retry
|
||||
func (d *RetryDownloader) GetLabels() ([]*Label, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
labels []*Label |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if labels, err = d.Downloader.GetLabels(); err == nil { |
||||
return labels, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetIssues returns a repository's issues with retry
|
||||
func (d *RetryDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
issues []*Issue |
||||
isEnd bool |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if issues, isEnd, err = d.Downloader.GetIssues(page, perPage); err == nil { |
||||
return issues, isEnd, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, false, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, false, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, false, err |
||||
} |
||||
|
||||
// GetComments returns a repository's comments with retry
|
||||
func (d *RetryDownloader) GetComments(issueNumber int64) ([]*Comment, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
comments []*Comment |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if comments, err = d.Downloader.GetComments(issueNumber); err == nil { |
||||
return comments, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetPullRequests returns a repository's pull requests with retry
|
||||
func (d *RetryDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
prs []*PullRequest |
||||
err error |
||||
isEnd bool |
||||
) |
||||
for ; times > 0; times-- { |
||||
if prs, isEnd, err = d.Downloader.GetPullRequests(page, perPage); err == nil { |
||||
return prs, isEnd, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, false, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, false, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, false, err |
||||
} |
||||
|
||||
// GetReviews returns pull requests reviews
|
||||
func (d *RetryDownloader) GetReviews(pullRequestNumber int64) ([]*Review, error) { |
||||
var ( |
||||
times = d.RetryTimes |
||||
reviews []*Review |
||||
err error |
||||
) |
||||
for ; times > 0; times-- { |
||||
if reviews, err = d.Downloader.GetReviews(pullRequestNumber); err == nil { |
||||
return reviews, nil |
||||
} |
||||
if IsErrNotSupported(err) { |
||||
return nil, err |
||||
} |
||||
select { |
||||
case <-d.ctx.Done(): |
||||
return nil, d.ctx.Err() |
||||
case <-time.After(time.Second * time.Duration(d.RetryDelay)): |
||||
} |
||||
} |
||||
return nil, err |
||||
} |
@ -0,0 +1,312 @@ |
||||
// 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 ( |
||||
"context" |
||||
"fmt" |
||||
"net/http" |
||||
"net/url" |
||||
"strings" |
||||
"time" |
||||
|
||||
"code.gitea.io/gitea/modules/log" |
||||
"code.gitea.io/gitea/modules/migrations/base" |
||||
"code.gitea.io/gitea/modules/structs" |
||||
|
||||
"github.com/gogs/go-gogs-client" |
||||
) |
||||
|
||||
var ( |
||||
_ base.Downloader = &GogsDownloader{} |
||||
_ base.DownloaderFactory = &GogsDownloaderFactory{} |
||||
) |
||||
|
||||
func init() { |
||||
RegisterDownloaderFactory(&GogsDownloaderFactory{}) |
||||
} |
||||
|
||||
// GogsDownloaderFactory defines a gogs downloader factory
|
||||
type GogsDownloaderFactory struct { |
||||
} |
||||
|
||||
// New returns a Downloader related to this factory according MigrateOptions
|
||||
func (f *GogsDownloaderFactory) New(ctx context.Context, opts base.MigrateOptions) (base.Downloader, error) { |
||||
u, err := url.Parse(opts.CloneAddr) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
baseURL := u.Scheme + "://" + u.Host |
||||
repoNameSpace := strings.TrimSuffix(u.Path, ".git") |
||||
repoNameSpace = strings.Trim(repoNameSpace, "/") |
||||
|
||||
fields := strings.Split(repoNameSpace, "/") |
||||
if len(fields) < 2 { |
||||
return nil, fmt.Errorf("invalid path: %s", repoNameSpace) |
||||
} |
||||
|
||||
log.Trace("Create gogs downloader. BaseURL: %s RepoOwner: %s RepoName: %s", baseURL, fields[0], fields[1]) |
||||
return NewGogsDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, fields[0], fields[1]), nil |
||||
} |
||||
|
||||
// GitServiceType returns the type of git service
|
||||
func (f *GogsDownloaderFactory) GitServiceType() structs.GitServiceType { |
||||
return structs.GogsService |
||||
} |
||||
|
||||
// GogsDownloader implements a Downloader interface to get repository informations
|
||||
// from gogs via API
|
||||
type GogsDownloader struct { |
||||
base.NullDownloader |
||||
ctx context.Context |
||||
client *gogs.Client |
||||
baseURL string |
||||
repoOwner string |
||||
repoName string |
||||
userName string |
||||
password string |
||||
openIssuesFinished bool |
||||
openIssuesPages int |
||||
transport http.RoundTripper |
||||
} |
||||
|
||||
// SetContext set context
|
||||
func (g *GogsDownloader) SetContext(ctx context.Context) { |
||||
g.ctx = ctx |
||||
} |
||||
|
||||
// NewGogsDownloader creates a gogs Downloader via gogs API
|
||||
func NewGogsDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GogsDownloader { |
||||
var downloader = GogsDownloader{ |
||||
ctx: ctx, |
||||
baseURL: baseURL, |
||||
userName: userName, |
||||
password: password, |
||||
repoOwner: repoOwner, |
||||
repoName: repoName, |
||||
} |
||||
|
||||
var client *gogs.Client |
||||
if len(token) != 0 { |
||||
client = gogs.NewClient(baseURL, token) |
||||
downloader.userName = token |
||||
} else { |
||||
downloader.transport = &http.Transport{ |
||||
Proxy: func(req *http.Request) (*url.URL, error) { |
||||
req.SetBasicAuth(userName, password) |
||||
return nil, nil |
||||
}, |
||||
} |
||||
|
||||
client = gogs.NewClient(baseURL, "") |
||||
client.SetHTTPClient(&http.Client{ |
||||
Transport: &downloader, |
||||
}) |
||||
} |
||||
|
||||
downloader.client = client |
||||
return &downloader |
||||
} |
||||
|
||||
// RoundTrip wraps the provided request within this downloader's context and passes it to our internal http.Transport.
|
||||
// This implements http.RoundTripper and makes the gogs client requests cancellable even though it is not cancellable itself
|
||||
func (g *GogsDownloader) RoundTrip(req *http.Request) (*http.Response, error) { |
||||
return g.transport.RoundTrip(req.WithContext(g.ctx)) |
||||
} |
||||
|
||||
// GetRepoInfo returns a repository information
|
||||
func (g *GogsDownloader) GetRepoInfo() (*base.Repository, error) { |
||||
gr, err := g.client.GetRepo(g.repoOwner, g.repoName) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// convert gogs repo to stand Repo
|
||||
return &base.Repository{ |
||||
Owner: g.repoOwner, |
||||
Name: g.repoName, |
||||
IsPrivate: gr.Private, |
||||
Description: gr.Description, |
||||
CloneURL: gr.CloneURL, |
||||
OriginalURL: gr.HTMLURL, |
||||
DefaultBranch: gr.DefaultBranch, |
||||
}, nil |
||||
} |
||||
|
||||
// GetMilestones returns milestones
|
||||
func (g *GogsDownloader) GetMilestones() ([]*base.Milestone, error) { |
||||
var perPage = 100 |
||||
var milestones = make([]*base.Milestone, 0, perPage) |
||||
|
||||
ms, err := g.client.ListRepoMilestones(g.repoOwner, g.repoName) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
t := time.Now() |
||||
|
||||
for _, m := range ms { |
||||
milestones = append(milestones, &base.Milestone{ |
||||
Title: m.Title, |
||||
Description: m.Description, |
||||
Deadline: m.Deadline, |
||||
State: string(m.State), |
||||
Created: t, |
||||
Updated: &t, |
||||
Closed: m.Closed, |
||||
}) |
||||
} |
||||
|
||||
return milestones, nil |
||||
} |
||||
|
||||
// GetLabels returns labels
|
||||
func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { |
||||
var perPage = 100 |
||||
var labels = make([]*base.Label, 0, perPage) |
||||
ls, err := g.client.ListRepoLabels(g.repoOwner, g.repoName) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
for _, label := range ls { |
||||
labels = append(labels, convertGogsLabel(label)) |
||||
} |
||||
|
||||
return labels, nil |
||||
} |
||||
|
||||
// GetIssues returns issues according start and limit, perPage is not supported
|
||||
func (g *GogsDownloader) GetIssues(page, _ int) ([]*base.Issue, bool, error) { |
||||
var state string |
||||
if g.openIssuesFinished { |
||||
state = string(gogs.STATE_CLOSED) |
||||
page -= g.openIssuesPages |
||||
} else { |
||||
state = string(gogs.STATE_OPEN) |
||||
g.openIssuesPages = page |
||||
} |
||||
|
||||
issues, isEnd, err := g.getIssues(page, state) |
||||
if err != nil { |
||||
return nil, false, err |
||||
} |
||||
|
||||
if isEnd { |
||||
if g.openIssuesFinished { |
||||
return issues, true, nil |
||||
} |
||||
g.openIssuesFinished = true |
||||
} |
||||
|
||||
return issues, false, nil |
||||
} |
||||
|
||||
func (g *GogsDownloader) getIssues(page int, state string) ([]*base.Issue, bool, error) { |
||||
var allIssues = make([]*base.Issue, 0, 10) |
||||
|
||||
issues, err := g.client.ListRepoIssues(g.repoOwner, g.repoName, gogs.ListIssueOption{ |
||||
Page: page, |
||||
State: state, |
||||
}) |
||||
if err != nil { |
||||
return nil, false, fmt.Errorf("error while listing repos: %v", err) |
||||
} |
||||
|
||||
for _, issue := range issues { |
||||
if issue.PullRequest != nil { |
||||
continue |
||||
} |
||||
allIssues = append(allIssues, convertGogsIssue(issue)) |
||||
} |
||||
|
||||
return allIssues, len(issues) == 0, nil |
||||
} |
||||
|
||||
// GetComments returns comments according issueNumber
|
||||
func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { |
||||
var allComments = make([]*base.Comment, 0, 100) |
||||
|
||||
comments, err := g.client.ListIssueComments(g.repoOwner, g.repoName, issueNumber) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error while listing repos: %v", err) |
||||
} |
||||
for _, comment := range comments { |
||||
if len(comment.Body) == 0 || comment.Poster == nil { |
||||
continue |
||||
} |
||||
allComments = append(allComments, &base.Comment{ |
||||
IssueIndex: issueNumber, |
||||
PosterID: comment.Poster.ID, |
||||
PosterName: comment.Poster.Login, |
||||
PosterEmail: comment.Poster.Email, |
||||
Content: comment.Body, |
||||
Created: comment.Created, |
||||
Updated: comment.Updated, |
||||
}) |
||||
} |
||||
|
||||
return allComments, nil |
||||
} |
||||
|
||||
// GetTopics return repository topics
|
||||
func (g *GogsDownloader) GetTopics() ([]string, error) { |
||||
return []string{}, nil |
||||
} |
||||
|
||||
// FormatCloneURL add authentification into remote URLs
|
||||
func (g *GogsDownloader) FormatCloneURL(opts MigrateOptions, remoteAddr string) (string, error) { |
||||
if len(opts.AuthToken) > 0 || len(opts.AuthUsername) > 0 { |
||||
u, err := url.Parse(remoteAddr) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
if len(opts.AuthToken) != 0 { |
||||
u.User = url.UserPassword(opts.AuthToken, "") |
||||
} else { |
||||
u.User = url.UserPassword(opts.AuthUsername, opts.AuthPassword) |
||||
} |
||||
return u.String(), nil |
||||
} |
||||
return remoteAddr, nil |
||||
} |
||||
|
||||
func convertGogsIssue(issue *gogs.Issue) *base.Issue { |
||||
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, convertGogsLabel(l)) |
||||
} |
||||
|
||||
var closed *time.Time |
||||
if issue.State == gogs.STATE_CLOSED { |
||||
// gogs client haven't provide closed, so we use updated instead
|
||||
closed = &issue.Updated |
||||
} |
||||
|
||||
return &base.Issue{ |
||||
Title: issue.Title, |
||||
Number: issue.Index, |
||||
PosterName: issue.Poster.Login, |
||||
PosterEmail: issue.Poster.Email, |
||||
Content: issue.Body, |
||||
Milestone: milestone, |
||||
State: string(issue.State), |
||||
Created: issue.Created, |
||||
Labels: labels, |
||||
Closed: closed, |
||||
} |
||||
} |
||||
|
||||
func convertGogsLabel(label *gogs.Label) *base.Label { |
||||
return &base.Label{ |
||||
Name: label.Name, |
||||
Color: label.Color, |
||||
} |
||||
} |
@ -0,0 +1,122 @@ |
||||
// 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 ( |
||||
"context" |
||||
"net/http" |
||||
"os" |
||||
"testing" |
||||
"time" |
||||
|
||||
"code.gitea.io/gitea/modules/migrations/base" |
||||
|
||||
"github.com/stretchr/testify/assert" |
||||
) |
||||
|
||||
func TestGogsDownloadRepo(t *testing.T) { |
||||
// Skip tests if Gogs token is not found
|
||||
gogsPersonalAccessToken := os.Getenv("GOGS_READ_TOKEN") |
||||
if len(gogsPersonalAccessToken) == 0 { |
||||
t.Skip("skipped test because GOGS_READ_TOKEN was not in the environment") |
||||
} |
||||
|
||||
resp, err := http.Get("https://try.gogs.io/lunnytest/TESTREPO") |
||||
if err != nil || resp.StatusCode/100 != 2 { |
||||
// skip and don't run test
|
||||
t.Skipf("visit test repo failed, ignored") |
||||
return |
||||
} |
||||
|
||||
downloader := NewGogsDownloader(context.Background(), "https://try.gogs.io", "", "", gogsPersonalAccessToken, "lunnytest", "TESTREPO") |
||||
repo, err := downloader.GetRepoInfo() |
||||
assert.NoError(t, err) |
||||
|
||||
assert.EqualValues(t, &base.Repository{ |
||||
Name: "TESTREPO", |
||||
Owner: "lunnytest", |
||||
Description: "", |
||||
CloneURL: "https://try.gogs.io/lunnytest/TESTREPO.git", |
||||
}, repo) |
||||
|
||||
milestones, err := downloader.GetMilestones() |
||||
assert.NoError(t, err) |
||||
assert.True(t, len(milestones) == 1) |
||||
|
||||
for _, milestone := range milestones { |
||||
switch milestone.Title { |
||||
case "1.0": |
||||
assert.EqualValues(t, "open", milestone.State) |
||||
} |
||||
} |
||||
|
||||
labels, err := downloader.GetLabels() |
||||
assert.NoError(t, err) |
||||
assert.Len(t, labels, 7) |
||||
for _, l := range labels { |
||||
switch l.Name { |
||||
case "bug": |
||||
assertLabelEqual(t, "bug", "ee0701", "", l) |
||||
case "duplicated": |
||||
assertLabelEqual(t, "duplicated", "cccccc", "", l) |
||||
case "enhancement": |
||||
assertLabelEqual(t, "enhancement", "84b6eb", "", l) |
||||
case "help wanted": |
||||
assertLabelEqual(t, "help wanted", "128a0c", "", l) |
||||
case "invalid": |
||||
assertLabelEqual(t, "invalid", "e6e6e6", "", l) |
||||
case "question": |
||||
assertLabelEqual(t, "question", "cc317c", "", l) |
||||
case "wontfix": |
||||
assertLabelEqual(t, "wontfix", "ffffff", "", l) |
||||
} |
||||
} |
||||
|
||||
_, err = downloader.GetReleases() |
||||
assert.Error(t, err) |
||||
|
||||
// downloader.GetIssues()
|
||||
issues, isEnd, err := downloader.GetIssues(1, 8) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 1, len(issues)) |
||||
assert.False(t, isEnd) |
||||
|
||||
assert.EqualValues(t, []*base.Issue{ |
||||
{ |
||||
Number: 1, |
||||
Title: "test", |
||||
Content: "test", |
||||
Milestone: "", |
||||
PosterName: "lunny", |
||||
PosterEmail: "xiaolunwen@gmail.com", |
||||
State: "open", |
||||
Created: time.Date(2019, 06, 11, 8, 16, 44, 0, time.UTC), |
||||
Labels: []*base.Label{ |
||||
{ |
||||
Name: "bug", |
||||
Color: "ee0701", |
||||
}, |
||||
}, |
||||
}, |
||||
}, issues) |
||||
|
||||
// downloader.GetComments()
|
||||
comments, err := downloader.GetComments(1) |
||||
assert.NoError(t, err) |
||||
assert.EqualValues(t, 1, len(comments)) |
||||
assert.EqualValues(t, []*base.Comment{ |
||||
{ |
||||
PosterName: "lunny", |
||||
PosterEmail: "xiaolunwen@gmail.com", |
||||
Created: time.Date(2019, 06, 11, 8, 19, 50, 0, time.UTC), |
||||
Updated: time.Date(2019, 06, 11, 8, 19, 50, 0, time.UTC), |
||||
Content: `1111`, |
||||
}, |
||||
}, comments) |
||||
|
||||
// downloader.GetPullRequests()
|
||||
_, _, err = downloader.GetPullRequests(1, 3) |
||||
assert.Error(t, err) |
||||
} |
After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1,139 @@ |
||||
{{template "base/head" .}} |
||||
<div class="page-content repository new migrate"> |
||||
<div class="ui middle very relaxed page grid"> |
||||
<div class="column"> |
||||
<form class="ui form" action="{{.Link}}" method="post"> |
||||
{{.CsrfTokenHtml}} |
||||
<h3 class="ui top attached header"> |
||||
{{.i18n.Tr "repo.migrate.migrate" .service.Title}} |
||||
<input id="service_type" type="hidden" name="service" value="{{.service}}"> |
||||
</h3> |
||||
<div class="ui attached segment"> |
||||
{{template "base/alert" .}} |
||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}"> |
||||
<label for="clone_addr">{{.i18n.Tr "repo.migrate.clone_address"}}</label> |
||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required> |
||||
<span class="help"> |
||||
{{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}} |
||||
{{if .LFSActive}}<br />{{.i18n.Tr "repo.migrate.lfs_mirror_unsupported"}}{{end}} |
||||
</span> |
||||
</div> |
||||
|
||||
<div class="inline field {{if .Err_Auth}}error{{end}}"> |
||||
<label for="auth_token">{{.i18n.Tr "access_token"}}</label> |
||||
<input id="auth_token" name="auth_token" value="{{.auth_token}}" {{if not .auth_token}} data-need-clear="true" {{end}}> |
||||
<!-- <a target=”_blank” href="https://docs.gitea.io/en-us/api-usage">{{svg "octicon-question"}}</a> --> |
||||
</div> |
||||
|
||||
<div class="inline field"> |
||||
<label>{{.i18n.Tr "repo.migrate_options"}}</label> |
||||
<div class="ui checkbox"> |
||||
{{if .DisableMirrors}} |
||||
<input id="mirror" name="mirror" type="checkbox" readonly> |
||||
<label>{{.i18n.Tr "repo.migrate_options_mirror_disabled"}}</label> |
||||
{{else}} |
||||
<input id="mirror" name="mirror" type="checkbox" {{if .mirror}} checked{{end}}> |
||||
<label>{{.i18n.Tr "repo.migrate_options_mirror_helper" | Safe}}</label> |
||||
{{end}} |
||||
</div> |
||||
</div> |
||||
|
||||
<span class="help">{{.i18n.Tr "repo.migrate.migrate_items_options"}}</span> |
||||
<div id="migrate_items"> |
||||
<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> |
||||
<!-- Gogs do not support it |
||||
<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_merge_requests" | 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="ui divider"></div> |
||||
|
||||
<div class="inline required field {{if .Err_Owner}}error{{end}}"> |
||||
<label>{{.i18n.Tr "repo.owner"}}</label> |
||||
<div class="ui selection owner dropdown"> |
||||
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required> |
||||
<span class="text" title="{{.ContextUser.Name}}"> |
||||
{{avatar .ContextUser}} |
||||
{{.ContextUser.ShortName 20}} |
||||
</span> |
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}} |
||||
<div class="menu" title="{{.SignedUser.Name}}"> |
||||
<div class="item" data-value="{{.SignedUser.ID}}"> |
||||
{{avatar .SignedUser}} |
||||
{{.SignedUser.ShortName 20}} |
||||
</div> |
||||
{{range .Orgs}} |
||||
<div class="item" data-value="{{.ID}}" title="{{.Name}}"> |
||||
{{avatar .}} |
||||
{{.ShortName 20}} |
||||
</div> |
||||
{{end}} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="inline required field {{if .Err_RepoName}}error{{end}}"> |
||||
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label> |
||||
<input id="repo_name" name="repo_name" value="{{.repo_name}}" required> |
||||
</div> |
||||
<div class="inline field"> |
||||
<label>{{.i18n.Tr "repo.visibility"}}</label> |
||||
<div class="ui checkbox"> |
||||
{{if .IsForcedPrivate}} |
||||
<input name="private" type="checkbox" checked readonly> |
||||
<label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label> |
||||
{{else}} |
||||
<input name="private" type="checkbox" {{if .private}} checked{{end}}> |
||||
<label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label> |
||||
{{end}} |
||||
</div> |
||||
</div> |
||||
<div class="inline field {{if .Err_Description}}error{{end}}"> |
||||
<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> |
||||
<textarea id="description" name="description">{{.description}}</textarea> |
||||
</div> |
||||
|
||||
<div class="inline field"> |
||||
<label></label> |
||||
<button class="ui green button"> |
||||
{{.i18n.Tr "repo.migrate_repo"}} |
||||
</button> |
||||
<a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> |
||||
</div> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{{template "base/footer" .}} |
@ -0,0 +1,25 @@ |
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects) |
||||
*.o |
||||
*.a |
||||
*.so |
||||
|
||||
# Folders |
||||
_obj |
||||
_test |
||||
|
||||
# Architecture specific extensions/prefixes |
||||
*.[568vq] |
||||
[568vq].out |
||||
|
||||
*.cgo1.go |
||||
*.cgo2.c |
||||
_cgo_defun.c |
||||
_cgo_gotypes.go |
||||
_cgo_export.* |
||||
|
||||
_testmain.go |
||||
|
||||
*.exe |
||||
*.test |
||||
*.prof |
||||
.idea |
@ -0,0 +1,22 @@ |
||||
The MIT License (MIT) |
||||
|
||||
Copyright (c) 2014 Go Git Service |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
|
@ -0,0 +1,8 @@ |
||||
Gogs API client in Go |
||||
===================== |
||||
|
||||
This package is still in experiment, see [Wiki](https://github.com/gogits/go-gogs-client/wiki) for documentation. |
||||
|
||||
## License |
||||
|
||||
This project is under the MIT License. See the [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) file for the full license text. |
@ -0,0 +1,43 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
func (c *Client) AdminCreateOrg(user string, opt CreateOrgOption) (*Organization, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
org := new(Organization) |
||||
return org, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/orgs", user), |
||||
jsonHeader, bytes.NewReader(body), org) |
||||
} |
||||
|
||||
func (c *Client) AdminCreateTeam(user string, opt CreateTeamOption) (*Team, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
team := new(Team) |
||||
return team, c.getParsedResponse("POST", fmt.Sprintf("/admin/orgs/%s/teams", user), |
||||
jsonHeader, bytes.NewReader(body), team) |
||||
} |
||||
|
||||
func (c *Client) AdminAddTeamMembership(teamID int64, user string) error { |
||||
_, err := c.getResponse("PUT", fmt.Sprintf("/admin/teams/%d/members/%s", teamID, user), |
||||
jsonHeader, nil) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) AdminAddTeamRepository(teamID int64, repo string) error { |
||||
_, err := c.getResponse("PUT", fmt.Sprintf("/admin/teams/%d/repos/%s", teamID, repo), |
||||
jsonHeader, nil) |
||||
return err |
||||
} |
@ -0,0 +1,21 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
func (c *Client) AdminCreateRepo(user string, opt CreateRepoOption) (*Repository, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
repo := new(Repository) |
||||
return repo, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/repos", user), |
||||
jsonHeader, bytes.NewReader(body), repo) |
||||
} |
@ -0,0 +1,68 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
type CreateUserOption struct { |
||||
SourceID int64 `json:"source_id"` |
||||
LoginName string `json:"login_name"` |
||||
Username string `json:"username" binding:"Required;AlphaDashDot;MaxSize(35)"` |
||||
FullName string `json:"full_name" binding:"MaxSize(100)"` |
||||
Email string `json:"email" binding:"Required;Email;MaxSize(254)"` |
||||
Password string `json:"password" binding:"MaxSize(255)"` |
||||
SendNotify bool `json:"send_notify"` |
||||
} |
||||
|
||||
func (c *Client) AdminCreateUser(opt CreateUserOption) (*User, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
user := new(User) |
||||
return user, c.getParsedResponse("POST", "/admin/users", jsonHeader, bytes.NewReader(body), user) |
||||
} |
||||
|
||||
type EditUserOption struct { |
||||
SourceID int64 `json:"source_id"` |
||||
LoginName string `json:"login_name"` |
||||
FullName string `json:"full_name" binding:"MaxSize(100)"` |
||||
Email string `json:"email" binding:"Required;Email;MaxSize(254)"` |
||||
Password string `json:"password" binding:"MaxSize(255)"` |
||||
Website string `json:"website" binding:"MaxSize(50)"` |
||||
Location string `json:"location" binding:"MaxSize(50)"` |
||||
Active *bool `json:"active"` |
||||
Admin *bool `json:"admin"` |
||||
AllowGitHook *bool `json:"allow_git_hook"` |
||||
AllowImportLocal *bool `json:"allow_import_local"` |
||||
MaxRepoCreation *int `json:"max_repo_creation"` |
||||
} |
||||
|
||||
func (c *Client) AdminEditUser(user string, opt EditUserOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("PATCH", fmt.Sprintf("/admin/users/%s", user), jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) AdminDeleteUser(user string) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/admin/users/%s", user), nil, nil) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) AdminCreateUserPublicKey(user string, opt CreateKeyOption) (*PublicKey, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
key := new(PublicKey) |
||||
return key, c.getParsedResponse("POST", fmt.Sprintf("/admin/users/%s/keys", user), jsonHeader, bytes.NewReader(body), key) |
||||
} |
@ -0,0 +1,90 @@ |
||||
// Copyright 2014 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"io" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"strings" |
||||
) |
||||
|
||||
func Version() string { |
||||
return "0.13.0" |
||||
} |
||||
|
||||
// Client represents a Gogs API client.
|
||||
type Client struct { |
||||
url string |
||||
accessToken string |
||||
client *http.Client |
||||
} |
||||
|
||||
// NewClient initializes and returns an API client.
|
||||
func NewClient(url, token string) *Client { |
||||
return &Client{ |
||||
url: strings.TrimSuffix(url, "/"), |
||||
accessToken: token, |
||||
client: &http.Client{}, |
||||
} |
||||
} |
||||
|
||||
// SetHTTPClient replaces default http.Client with user given one.
|
||||
func (c *Client) SetHTTPClient(client *http.Client) { |
||||
c.client = client |
||||
} |
||||
|
||||
func (c *Client) doRequest(method, path string, header http.Header, body io.Reader) (*http.Response, error) { |
||||
req, err := http.NewRequest(method, c.url+"/api/v1"+path, body) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
req.Header.Set("Authorization", "token "+c.accessToken) |
||||
for k, v := range header { |
||||
req.Header[k] = v |
||||
} |
||||
|
||||
return c.client.Do(req) |
||||
} |
||||
|
||||
func (c *Client) getResponse(method, path string, header http.Header, body io.Reader) ([]byte, error) { |
||||
resp, err := c.doRequest(method, path, header, body) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer resp.Body.Close() |
||||
|
||||
data, err := ioutil.ReadAll(resp.Body) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
switch resp.StatusCode { |
||||
case 403: |
||||
return nil, errors.New("403 Forbidden") |
||||
case 404: |
||||
return nil, errors.New("404 Not Found") |
||||
} |
||||
|
||||
if resp.StatusCode/100 != 2 { |
||||
errMap := make(map[string]interface{}) |
||||
if err = json.Unmarshal(data, &errMap); err != nil { |
||||
return nil, err |
||||
} |
||||
return nil, errors.New(errMap["message"].(string)) |
||||
} |
||||
|
||||
return data, nil |
||||
} |
||||
|
||||
func (c *Client) getParsedResponse(method, path string, header http.Header, body io.Reader, obj interface{}) error { |
||||
data, err := c.getResponse(method, path, header, body) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return json.Unmarshal(data, obj) |
||||
} |
@ -0,0 +1,103 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
type StateType string |
||||
|
||||
const ( |
||||
STATE_OPEN StateType = "open" |
||||
STATE_CLOSED StateType = "closed" |
||||
) |
||||
|
||||
type PullRequestMeta struct { |
||||
HasMerged bool `json:"merged"` |
||||
Merged *time.Time `json:"merged_at"` |
||||
} |
||||
|
||||
type Issue struct { |
||||
ID int64 `json:"id"` |
||||
Index int64 `json:"number"` |
||||
Poster *User `json:"user"` |
||||
Title string `json:"title"` |
||||
Body string `json:"body"` |
||||
Labels []*Label `json:"labels"` |
||||
Milestone *Milestone `json:"milestone"` |
||||
Assignee *User `json:"assignee"` |
||||
State StateType `json:"state"` |
||||
Comments int `json:"comments"` |
||||
Created time.Time `json:"created_at"` |
||||
Updated time.Time `json:"updated_at"` |
||||
|
||||
PullRequest *PullRequestMeta `json:"pull_request"` |
||||
} |
||||
|
||||
type ListIssueOption struct { |
||||
Page int |
||||
State string |
||||
} |
||||
|
||||
func (c *Client) ListIssues(opt ListIssueOption) ([]*Issue, error) { |
||||
issues := make([]*Issue, 0, 10) |
||||
return issues, c.getParsedResponse("GET", fmt.Sprintf("/issues?page=%d&state=%s", opt.Page, opt.State), nil, nil, &issues) |
||||
} |
||||
|
||||
func (c *Client) ListUserIssues(opt ListIssueOption) ([]*Issue, error) { |
||||
issues := make([]*Issue, 0, 10) |
||||
return issues, c.getParsedResponse("GET", fmt.Sprintf("/user/issues?page=%d&state=%s", opt.Page, opt.State), nil, nil, &issues) |
||||
} |
||||
|
||||
func (c *Client) ListRepoIssues(owner, repo string, opt ListIssueOption) ([]*Issue, error) { |
||||
issues := make([]*Issue, 0, 10) |
||||
return issues, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues?page=%d&state=%s", owner, repo, opt.Page, opt.State), nil, nil, &issues) |
||||
} |
||||
|
||||
func (c *Client) GetIssue(owner, repo string, index int64) (*Issue, error) { |
||||
issue := new(Issue) |
||||
return issue, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), nil, nil, issue) |
||||
} |
||||
|
||||
type CreateIssueOption struct { |
||||
Title string `json:"title" binding:"Required"` |
||||
Body string `json:"body"` |
||||
Assignee string `json:"assignee"` |
||||
Milestone int64 `json:"milestone"` |
||||
Labels []int64 `json:"labels"` |
||||
Closed bool `json:"closed"` |
||||
} |
||||
|
||||
func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
issue := new(Issue) |
||||
return issue, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues", owner, repo), |
||||
jsonHeader, bytes.NewReader(body), issue) |
||||
} |
||||
|
||||
type EditIssueOption struct { |
||||
Title string `json:"title"` |
||||
Body *string `json:"body"` |
||||
Assignee *string `json:"assignee"` |
||||
Milestone *int64 `json:"milestone"` |
||||
State *string `json:"state"` |
||||
} |
||||
|
||||
func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption) (*Issue, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
issue := new(Issue) |
||||
return issue, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index), |
||||
jsonHeader, bytes.NewReader(body), issue) |
||||
} |
@ -0,0 +1,70 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// Comment represents a comment in commit and issue page.
|
||||
type Comment struct { |
||||
ID int64 `json:"id"` |
||||
HTMLURL string `json:"html_url"` |
||||
Poster *User `json:"user"` |
||||
Body string `json:"body"` |
||||
Created time.Time `json:"created_at"` |
||||
Updated time.Time `json:"updated_at"` |
||||
} |
||||
|
||||
// ListIssueComments list comments on an issue.
|
||||
func (c *Client) ListIssueComments(owner, repo string, index int64) ([]*Comment, error) { |
||||
comments := make([]*Comment, 0, 10) |
||||
return comments, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index), nil, nil, &comments) |
||||
} |
||||
|
||||
// ListRepoIssueComments list comments for a given repo.
|
||||
func (c *Client) ListRepoIssueComments(owner, repo string) ([]*Comment, error) { |
||||
comments := make([]*Comment, 0, 10) |
||||
return comments, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/comments", owner, repo), nil, nil, &comments) |
||||
} |
||||
|
||||
// CreateIssueCommentOption is option when creating an issue comment.
|
||||
type CreateIssueCommentOption struct { |
||||
Body string `json:"body" binding:"Required"` |
||||
} |
||||
|
||||
// CreateIssueComment create comment on an issue.
|
||||
func (c *Client) CreateIssueComment(owner, repo string, index int64, opt CreateIssueCommentOption) (*Comment, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
comment := new(Comment) |
||||
return comment, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/comments", owner, repo, index), jsonHeader, bytes.NewReader(body), comment) |
||||
} |
||||
|
||||
// EditIssueCommentOption is option when editing an issue comment.
|
||||
type EditIssueCommentOption struct { |
||||
Body string `json:"body" binding:"Required"` |
||||
} |
||||
|
||||
// EditIssueComment edits an issue comment.
|
||||
func (c *Client) EditIssueComment(owner, repo string, index, commentID int64, opt EditIssueCommentOption) (*Comment, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
comment := new(Comment) |
||||
return comment, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/%d/comments/%d", owner, repo, index, commentID), jsonHeader, bytes.NewReader(body), comment) |
||||
} |
||||
|
||||
// DeleteIssueComment deletes an issue comment.
|
||||
func (c *Client) DeleteIssueComment(owner, repo string, index, commentID int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/comments/%d", owner, repo, index, commentID), nil, nil) |
||||
return err |
||||
} |
@ -0,0 +1,99 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
type Label struct { |
||||
ID int64 `json:"id"` |
||||
Name string `json:"name"` |
||||
Color string `json:"color"` |
||||
URL string `json:"url"` |
||||
} |
||||
|
||||
func (c *Client) ListRepoLabels(owner, repo string) ([]*Label, error) { |
||||
labels := make([]*Label, 0, 10) |
||||
return labels, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels", owner, repo), nil, nil, &labels) |
||||
} |
||||
|
||||
func (c *Client) GetRepoLabel(owner, repo string, id int64) (*Label, error) { |
||||
label := new(Label) |
||||
return label, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil, label) |
||||
} |
||||
|
||||
type CreateLabelOption struct { |
||||
Name string `json:"name" binding:"Required"` |
||||
Color string `json:"color" binding:"Required;Size(7)"` |
||||
} |
||||
|
||||
func (c *Client) CreateLabel(owner, repo string, opt CreateLabelOption) (*Label, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
label := new(Label) |
||||
return label, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/labels", owner, repo), |
||||
jsonHeader, bytes.NewReader(body), label) |
||||
} |
||||
|
||||
type EditLabelOption struct { |
||||
Name *string `json:"name"` |
||||
Color *string `json:"color"` |
||||
} |
||||
|
||||
func (c *Client) EditLabel(owner, repo string, id int64, opt EditLabelOption) (*Label, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
label := new(Label) |
||||
return label, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), label) |
||||
} |
||||
|
||||
func (c *Client) DeleteLabel(owner, repo string, id int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/labels/%d", owner, repo, id), nil, nil) |
||||
return err |
||||
} |
||||
|
||||
type IssueLabelsOption struct { |
||||
Labels []int64 `json:"labels"` |
||||
} |
||||
|
||||
func (c *Client) GetIssueLabels(owner, repo string, index int64) ([]*Label, error) { |
||||
labels := make([]*Label, 0, 5) |
||||
return labels, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), nil, nil, &labels) |
||||
} |
||||
|
||||
func (c *Client) AddIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
labels := make([]*Label, 0) |
||||
return labels, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels) |
||||
} |
||||
|
||||
func (c *Client) ReplaceIssueLabels(owner, repo string, index int64, opt IssueLabelsOption) ([]*Label, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
labels := make([]*Label, 0) |
||||
return labels, c.getParsedResponse("PUT", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), jsonHeader, bytes.NewReader(body), &labels) |
||||
} |
||||
|
||||
func (c *Client) DeleteIssueLabel(owner, repo string, index, label int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels/%d", owner, repo, index, label), nil, nil) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) ClearIssueLabels(owner, repo string, index int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/issues/%d/labels", owner, repo, index), nil, nil) |
||||
return err |
||||
} |
@ -0,0 +1,69 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
type Milestone struct { |
||||
ID int64 `json:"id"` |
||||
Title string `json:"title"` |
||||
Description string `json:"description"` |
||||
State StateType `json:"state"` |
||||
OpenIssues int `json:"open_issues"` |
||||
ClosedIssues int `json:"closed_issues"` |
||||
Closed *time.Time `json:"closed_at"` |
||||
Deadline *time.Time `json:"due_on"` |
||||
} |
||||
|
||||
func (c *Client) ListRepoMilestones(owner, repo string) ([]*Milestone, error) { |
||||
milestones := make([]*Milestone, 0, 10) |
||||
return milestones, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones", owner, repo), nil, nil, &milestones) |
||||
} |
||||
|
||||
func (c *Client) GetMilestone(owner, repo string, id int64) (*Milestone, error) { |
||||
milestone := new(Milestone) |
||||
return milestone, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil, milestone) |
||||
} |
||||
|
||||
type CreateMilestoneOption struct { |
||||
Title string `json:"title"` |
||||
Description string `json:"description"` |
||||
Deadline *time.Time `json:"due_on"` |
||||
} |
||||
|
||||
func (c *Client) CreateMilestone(owner, repo string, opt CreateMilestoneOption) (*Milestone, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
milestone := new(Milestone) |
||||
return milestone, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/milestones", owner, repo), jsonHeader, bytes.NewReader(body), milestone) |
||||
} |
||||
|
||||
type EditMilestoneOption struct { |
||||
Title string `json:"title"` |
||||
Description *string `json:"description"` |
||||
State *string `json:"state"` |
||||
Deadline *time.Time `json:"due_on"` |
||||
} |
||||
|
||||
func (c *Client) EditMilestone(owner, repo string, id int64, opt EditMilestoneOption) (*Milestone, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
milestone := new(Milestone) |
||||
return milestone, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), jsonHeader, bytes.NewReader(body), milestone) |
||||
} |
||||
|
||||
func (c *Client) DeleteMilestone(owner, repo string, id int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/milestones/%d", owner, repo, id), nil, nil) |
||||
return err |
||||
} |
@ -0,0 +1,9 @@ |
||||
// Copyright 2018 The Gogs 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 gogs |
||||
|
||||
const ( |
||||
MediaApplicationSHA = "application/vnd.gogs.sha" |
||||
) |
@ -0,0 +1,10 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
type MarkdownOption struct { |
||||
Text string |
||||
Context string |
||||
} |
@ -0,0 +1,69 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
type Organization struct { |
||||
ID int64 `json:"id"` |
||||
UserName string `json:"username"` |
||||
FullName string `json:"full_name"` |
||||
AvatarUrl string `json:"avatar_url"` |
||||
Description string `json:"description"` |
||||
Website string `json:"website"` |
||||
Location string `json:"location"` |
||||
} |
||||
|
||||
func (c *Client) ListMyOrgs() ([]*Organization, error) { |
||||
orgs := make([]*Organization, 0, 5) |
||||
return orgs, c.getParsedResponse("GET", "/user/orgs", nil, nil, &orgs) |
||||
} |
||||
|
||||
func (c *Client) ListUserOrgs(user string) ([]*Organization, error) { |
||||
orgs := make([]*Organization, 0, 5) |
||||
return orgs, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/orgs", user), nil, nil, &orgs) |
||||
} |
||||
|
||||
func (c *Client) GetOrg(orgname string) (*Organization, error) { |
||||
org := new(Organization) |
||||
return org, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s", orgname), nil, nil, org) |
||||
} |
||||
|
||||
type CreateOrgOption struct { |
||||
UserName string `json:"username" binding:"Required"` |
||||
FullName string `json:"full_name"` |
||||
Description string `json:"description"` |
||||
Website string `json:"website"` |
||||
Location string `json:"location"` |
||||
} |
||||
|
||||
type EditOrgOption struct { |
||||
FullName string `json:"full_name"` |
||||
Description string `json:"description"` |
||||
Website string `json:"website"` |
||||
Location string `json:"location"` |
||||
} |
||||
|
||||
func (c *Client) CreateOrg(opt CreateOrgOption) (*Organization, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
org := new(Organization) |
||||
return org, c.getParsedResponse("POST", "/user/orgs", jsonHeader, bytes.NewReader(body), org) |
||||
} |
||||
|
||||
func (c *Client) EditOrg(orgname string, opt EditOrgOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("PATCH", fmt.Sprintf("/orgs/%s", orgname), jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
@ -0,0 +1,24 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
type AddOrgMembershipOption struct { |
||||
Role string `json:"role" binding:"Required"` |
||||
} |
||||
|
||||
func (c *Client) AddOrgMembership(org, user string, opt AddOrgMembershipOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("PUT", fmt.Sprintf("/orgs/%s/membership/%s", org, user), jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
@ -0,0 +1,25 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import "fmt" |
||||
|
||||
type Team struct { |
||||
ID int64 `json:"id"` |
||||
Name string `json:"name"` |
||||
Description string `json:"description"` |
||||
Permission string `json:"permission"` |
||||
} |
||||
|
||||
type CreateTeamOption struct { |
||||
Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` |
||||
Description string `json:"description" binding:"MaxSize(255)"` |
||||
Permission string `json:"permission"` |
||||
} |
||||
|
||||
func (c *Client) ListTeams(name string) ([]*Team, error) { |
||||
teams := make([]*Team, 0, 5) |
||||
return teams, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/teams", name), nil, nil, &teams) |
||||
} |
@ -0,0 +1,37 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"time" |
||||
) |
||||
|
||||
// PullRequest represents a pull reqesut API object.
|
||||
type PullRequest struct { |
||||
// Copied from issue.go
|
||||
ID int64 `json:"id"` |
||||
Index int64 `json:"number"` |
||||
Poster *User `json:"user"` |
||||
Title string `json:"title"` |
||||
Body string `json:"body"` |
||||
Labels []*Label `json:"labels"` |
||||
Milestone *Milestone `json:"milestone"` |
||||
Assignee *User `json:"assignee"` |
||||
State StateType `json:"state"` |
||||
Comments int `json:"comments"` |
||||
|
||||
HeadBranch string `json:"head_branch"` |
||||
HeadRepo *Repository `json:"head_repo"` |
||||
BaseBranch string `json:"base_branch"` |
||||
BaseRepo *Repository `json:"base_repo"` |
||||
|
||||
HTMLURL string `json:"html_url"` |
||||
|
||||
Mergeable *bool `json:"mergeable"` |
||||
HasMerged bool `json:"merged"` |
||||
Merged *time.Time `json:"merged_at"` |
||||
MergedCommitID *string `json:"merge_commit_sha"` |
||||
MergedBy *User `json:"merged_by"` |
||||
} |
@ -0,0 +1,22 @@ |
||||
// Copyright 2017 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"time" |
||||
) |
||||
|
||||
// Release represents a release API object.
|
||||
type Release struct { |
||||
ID int64 `json:"id"` |
||||
TagName string `json:"tag_name"` |
||||
TargetCommitish string `json:"target_commitish"` |
||||
Name string `json:"name"` |
||||
Body string `json:"body"` |
||||
Draft bool `json:"draft"` |
||||
Prerelease bool `json:"prerelease"` |
||||
Author *User `json:"author"` |
||||
Created time.Time `json:"created_at"` |
||||
} |
@ -0,0 +1,172 @@ |
||||
// Copyright 2014 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// Permission represents a API permission.
|
||||
type Permission struct { |
||||
Admin bool `json:"admin"` |
||||
Push bool `json:"push"` |
||||
Pull bool `json:"pull"` |
||||
} |
||||
|
||||
// Repository represents a API repository.
|
||||
type Repository struct { |
||||
ID int64 `json:"id"` |
||||
Owner *User `json:"owner"` |
||||
Name string `json:"name"` |
||||
FullName string `json:"full_name"` |
||||
Description string `json:"description"` |
||||
Private bool `json:"private"` |
||||
Unlisted bool `json:"unlisted"` |
||||
Fork bool `json:"fork"` |
||||
Parent *Repository `json:"parent"` |
||||
Empty bool `json:"empty"` |
||||
Mirror bool `json:"mirror"` |
||||
Size int64 `json:"size"` |
||||
HTMLURL string `json:"html_url"` |
||||
SSHURL string `json:"ssh_url"` |
||||
CloneURL string `json:"clone_url"` |
||||
Website string `json:"website"` |
||||
Stars int `json:"stars_count"` |
||||
Forks int `json:"forks_count"` |
||||
Watchers int `json:"watchers_count"` |
||||
OpenIssues int `json:"open_issues_count"` |
||||
DefaultBranch string `json:"default_branch"` |
||||
Created time.Time `json:"created_at"` |
||||
Updated time.Time `json:"updated_at"` |
||||
Permissions *Permission `json:"permissions,omitempty"` |
||||
} |
||||
|
||||
// ListMyRepos lists all repositories for the authenticated user that has access to.
|
||||
func (c *Client) ListMyRepos() ([]*Repository, error) { |
||||
repos := make([]*Repository, 0, 10) |
||||
return repos, c.getParsedResponse("GET", "/user/repos", nil, nil, &repos) |
||||
} |
||||
|
||||
func (c *Client) ListUserRepos(user string) ([]*Repository, error) { |
||||
repos := make([]*Repository, 0, 10) |
||||
return repos, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/repos", user), nil, nil, &repos) |
||||
} |
||||
|
||||
func (c *Client) ListOrgRepos(org string) ([]*Repository, error) { |
||||
repos := make([]*Repository, 0, 10) |
||||
return repos, c.getParsedResponse("GET", fmt.Sprintf("/orgs/%s/repos", org), nil, nil, &repos) |
||||
} |
||||
|
||||
type CreateRepoOption struct { |
||||
Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"` |
||||
Description string `json:"description" binding:"MaxSize(255)"` |
||||
Private bool `json:"private"` |
||||
Unlisted bool `json:"unlisted"` |
||||
AutoInit bool `json:"auto_init"` |
||||
Gitignores string `json:"gitignores"` |
||||
License string `json:"license"` |
||||
Readme string `json:"readme"` |
||||
} |
||||
|
||||
// CreateRepo creates a repository for authenticated user.
|
||||
func (c *Client) CreateRepo(opt CreateRepoOption) (*Repository, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
repo := new(Repository) |
||||
return repo, c.getParsedResponse("POST", "/user/repos", jsonHeader, bytes.NewReader(body), repo) |
||||
} |
||||
|
||||
// CreateOrgRepo creates an organization repository for authenticated user.
|
||||
func (c *Client) CreateOrgRepo(org string, opt CreateRepoOption) (*Repository, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
repo := new(Repository) |
||||
return repo, c.getParsedResponse("POST", fmt.Sprintf("/org/%s/repos", org), jsonHeader, bytes.NewReader(body), repo) |
||||
} |
||||
|
||||
// GetRepo returns information of a repository of given owner.
|
||||
func (c *Client) GetRepo(owner, reponame string) (*Repository, error) { |
||||
repo := new(Repository) |
||||
return repo, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s", owner, reponame), nil, nil, repo) |
||||
} |
||||
|
||||
// DeleteRepo deletes a repository of user or organization.
|
||||
func (c *Client) DeleteRepo(owner, repo string) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s", owner, repo), nil, nil) |
||||
return err |
||||
} |
||||
|
||||
type MigrateRepoOption struct { |
||||
CloneAddr string `json:"clone_addr" binding:"Required"` |
||||
AuthUsername string `json:"auth_username"` |
||||
AuthPassword string `json:"auth_password"` |
||||
UID int `json:"uid" binding:"Required"` |
||||
RepoName string `json:"repo_name" binding:"Required"` |
||||
Mirror bool `json:"mirror"` |
||||
Private bool `json:"private"` |
||||
Unlisted bool `json:"unlisted"` |
||||
Description string `json:"description"` |
||||
} |
||||
|
||||
// MigrateRepo migrates a repository from other Git hosting sources for the
|
||||
// authenticated user.
|
||||
//
|
||||
// To migrate a repository for a organization, the authenticated user must be a
|
||||
// owner of the specified organization.
|
||||
func (c *Client) MigrateRepo(opt MigrateRepoOption) (*Repository, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
repo := new(Repository) |
||||
return repo, c.getParsedResponse("POST", "/repos/migrate", jsonHeader, bytes.NewReader(body), repo) |
||||
} |
||||
|
||||
type EditIssueTrackerOption struct { |
||||
EnableIssues *bool `json:"enable_issues"` |
||||
EnableExternalTracker *bool `json:"enable_external_tracker"` |
||||
ExternalTrackerURL *string `json:"external_tracker_url"` |
||||
TrackerURLFormat *string `json:"tracker_url_format"` |
||||
TrackerIssueStyle *string `json:"tracker_issue_style"` |
||||
} |
||||
|
||||
// EditIssueTracker updates issue tracker options of the repository.
|
||||
func (c *Client) EditIssueTracker(owner, repo string, opt EditIssueTrackerOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issue-tracker", owner, repo), jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
||||
|
||||
type EditWikiOption struct { |
||||
EnableWiki *bool `json:"enable_wiki"` |
||||
AllowPublicWiki *bool `json:"allow_public_wiki"` |
||||
EnableExternalWiki *bool `json:"enable_external_wiki"` |
||||
ExternalWikiURL *string `json:"external_wiki_url"` |
||||
} |
||||
|
||||
// EditWiki updates wiki options of the repository.
|
||||
func (c *Client) EditWiki(owner, repo string, opt EditWikiOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/wiki", owner, repo), jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) MirrorSync(owner, repo string) error { |
||||
_, err := c.getResponse("POST", fmt.Sprintf("/repos/%s/%s/mirror-sync", owner, repo), jsonHeader, nil) |
||||
return err |
||||
} |
@ -0,0 +1,25 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"fmt" |
||||
) |
||||
|
||||
// Branch represents a repository branch.
|
||||
type Branch struct { |
||||
Name string `json:"name"` |
||||
Commit *PayloadCommit `json:"commit"` |
||||
} |
||||
|
||||
func (c *Client) ListRepoBranches(user, repo string) ([]*Branch, error) { |
||||
branches := make([]*Branch, 0, 10) |
||||
return branches, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches", user, repo), nil, nil, &branches) |
||||
} |
||||
|
||||
func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, error) { |
||||
b := new(Branch) |
||||
return b, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil, &b) |
||||
} |
@ -0,0 +1,44 @@ |
||||
// Copyright 2016 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
) |
||||
|
||||
type Collaborator struct { |
||||
*User |
||||
Permissions Permission `json:"permissions"` |
||||
} |
||||
|
||||
type AddCollaboratorOption struct { |
||||
Permission *string `json:"permission"` |
||||
} |
||||
|
||||
func (c *Client) ListCollaborator(user, repo string) ([]*Collaborator, error) { |
||||
collabs := make([]*Collaborator, 0, 10) |
||||
return collabs, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/collaborators", user, repo), nil, nil, &collabs) |
||||
} |
||||
|
||||
func (c *Client) AddCollaborator(user, repo, collaborator string, opt AddCollaboratorOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("PUT", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) DeleteCollaborator(user, repo, collaborator string) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) IsCollaborator(user, repo, collaborator string) error { |
||||
_, err := c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/collaborators/%s", user, repo, collaborator), nil, nil) |
||||
return err |
||||
} |
@ -0,0 +1,53 @@ |
||||
// Copyright 2018 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net/http" |
||||
) |
||||
|
||||
// CommitMeta contains meta information of a commit in terms of API.
|
||||
type CommitMeta struct { |
||||
URL string `json:"url"` |
||||
SHA string `json:"sha"` |
||||
} |
||||
|
||||
// CommitUser contains information of a user in the context of a commit.
|
||||
type CommitUser struct { |
||||
Name string `json:"name"` |
||||
Email string `json:"email"` |
||||
Date string `json:"date"` |
||||
} |
||||
|
||||
// RepoCommit contains information of a commit in the context of a repository.
|
||||
type RepoCommit struct { |
||||
URL string `json:"url"` |
||||
Author *CommitUser `json:"author"` |
||||
Committer *CommitUser `json:"committer"` |
||||
Message string `json:"message"` |
||||
Tree *CommitMeta `json:"tree"` |
||||
} |
||||
|
||||
// Commit contains information generated from a Git commit.
|
||||
type Commit struct { |
||||
*CommitMeta |
||||
HTMLURL string `json:"html_url"` |
||||
RepoCommit *RepoCommit `json:"commit"` |
||||
Author *User `json:"author"` |
||||
Committer *User `json:"committer"` |
||||
Parents []*CommitMeta `json:"parents"` |
||||
} |
||||
|
||||
func (c *Client) GetSingleCommit(user, repo, commitID string) (*Commit, error) { |
||||
commit := new(Commit) |
||||
return commit, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s", user, repo, commitID), nil, nil, &commit) |
||||
} |
||||
|
||||
func (c *Client) GetReferenceSHA(user, repo, ref string) (string, error) { |
||||
data, err := c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/commits/%s", user, repo, ref), |
||||
http.Header{"Accept": []string{MediaApplicationSHA}}, nil) |
||||
return string(data), err |
||||
} |
@ -0,0 +1,23 @@ |
||||
// Copyright 2014 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"fmt" |
||||
) |
||||
|
||||
// GetFile downloads a file of repository, ref can be branch/tag/commit.
|
||||
// e.g.: ref -> master, tree -> macaron.go(no leading slash)
|
||||
func (c *Client) GetFile(user, repo, ref, tree string) ([]byte, error) { |
||||
return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/raw/%s/%s", user, repo, ref, tree), nil, nil) |
||||
} |
||||
|
||||
// GetArchive downloads the full contents of a repository. Ref can be a branch/tag/commit.
|
||||
func (c *Client) GetArchive(user, repo, ref, format string) ([]byte, error) { |
||||
if format != ".zip" && format != ".tar.gz" { |
||||
return nil, fmt.Errorf("invalid format: %s (must be .zip or .tar.gz)", format) |
||||
} |
||||
return c.getResponse("GET", fmt.Sprintf("/repos/%s/%s/archive/%s%s", user, repo, ref, format), nil, nil) |
||||
} |
@ -0,0 +1,345 @@ |
||||
// Copyright 2014 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
var ( |
||||
ErrInvalidReceiveHook = errors.New("invalid JSON payload received over webhook") |
||||
) |
||||
|
||||
type Hook struct { |
||||
ID int64 `json:"id"` |
||||
Type string `json:"type"` |
||||
URL string `json:"-"` |
||||
Config map[string]string `json:"config"` |
||||
Events []string `json:"events"` |
||||
Active bool `json:"active"` |
||||
Updated time.Time `json:"updated_at"` |
||||
Created time.Time `json:"created_at"` |
||||
} |
||||
|
||||
func (c *Client) ListRepoHooks(user, repo string) ([]*Hook, error) { |
||||
hooks := make([]*Hook, 0, 10) |
||||
return hooks, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), nil, nil, &hooks) |
||||
} |
||||
|
||||
type CreateHookOption struct { |
||||
Type string `json:"type" binding:"Required"` |
||||
Config map[string]string `json:"config" binding:"Required"` |
||||
Events []string `json:"events"` |
||||
Active bool `json:"active"` |
||||
} |
||||
|
||||
func (c *Client) CreateRepoHook(user, repo string, opt CreateHookOption) (*Hook, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
h := new(Hook) |
||||
return h, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/hooks", user, repo), jsonHeader, bytes.NewReader(body), h) |
||||
} |
||||
|
||||
type EditHookOption struct { |
||||
Config map[string]string `json:"config"` |
||||
Events []string `json:"events"` |
||||
Active *bool `json:"active"` |
||||
} |
||||
|
||||
func (c *Client) EditRepoHook(user, repo string, id int64, opt EditHookOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("PATCH", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) DeleteRepoHook(user, repo string, id int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/hooks/%d", user, repo, id), nil, nil) |
||||
return err |
||||
} |
||||
|
||||
type Payloader interface { |
||||
JSONPayload() ([]byte, error) |
||||
} |
||||
|
||||
type PayloadUser struct { |
||||
Name string `json:"name"` |
||||
Email string `json:"email"` |
||||
UserName string `json:"username"` |
||||
} |
||||
|
||||
// FIXME: consider use same format as API when commits API are added.
|
||||
type PayloadCommit struct { |
||||
ID string `json:"id"` |
||||
Message string `json:"message"` |
||||
URL string `json:"url"` |
||||
Author *PayloadUser `json:"author"` |
||||
Committer *PayloadUser `json:"committer"` |
||||
|
||||
Added []string `json:"added"` |
||||
Removed []string `json:"removed"` |
||||
Modified []string `json:"modified"` |
||||
|
||||
Timestamp time.Time `json:"timestamp"` |
||||
} |
||||
|
||||
var ( |
||||
_ Payloader = &CreatePayload{} |
||||
_ Payloader = &DeletePayload{} |
||||
_ Payloader = &ForkPayload{} |
||||
_ Payloader = &PushPayload{} |
||||
_ Payloader = &IssuesPayload{} |
||||
_ Payloader = &IssueCommentPayload{} |
||||
_ Payloader = &PullRequestPayload{} |
||||
) |
||||
|
||||
// _________ __
|
||||
// \_ ___ \_______ ____ _____ _/ |_ ____
|
||||
// / \ \/\_ __ \_/ __ \\__ \\ __\/ __ \
|
||||
// \ \____| | \/\ ___/ / __ \| | \ ___/
|
||||
// \______ /|__| \___ >____ /__| \___ >
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type CreatePayload struct { |
||||
Ref string `json:"ref"` |
||||
RefType string `json:"ref_type"` |
||||
Sha string `json:"sha"` |
||||
DefaultBranch string `json:"default_branch"` |
||||
Repo *Repository `json:"repository"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *CreatePayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
||||
|
||||
// ParseCreateHook parses create event hook content.
|
||||
func ParseCreateHook(raw []byte) (*CreatePayload, error) { |
||||
hook := new(CreatePayload) |
||||
if err := json.Unmarshal(raw, hook); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// it is possible the JSON was parsed, however,
|
||||
// was not from Gogs (maybe was from Bitbucket)
|
||||
// So we'll check to be sure certain key fields
|
||||
// were populated
|
||||
switch { |
||||
case hook.Repo == nil: |
||||
return nil, ErrInvalidReceiveHook |
||||
case len(hook.Ref) == 0: |
||||
return nil, ErrInvalidReceiveHook |
||||
} |
||||
return hook, nil |
||||
} |
||||
|
||||
// ________ .__ __
|
||||
// \______ \ ____ | | _____/ |_ ____
|
||||
// | | \_/ __ \| | _/ __ \ __\/ __ \
|
||||
// | ` \ ___/| |_\ ___/| | \ ___/
|
||||
// /_______ /\___ >____/\___ >__| \___ >
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type PusherType string |
||||
|
||||
const ( |
||||
PUSHER_TYPE_USER PusherType = "user" |
||||
) |
||||
|
||||
type DeletePayload struct { |
||||
Ref string `json:"ref"` |
||||
RefType string `json:"ref_type"` |
||||
PusherType PusherType `json:"pusher_type"` |
||||
Repo *Repository `json:"repository"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *DeletePayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
||||
|
||||
// ___________ __
|
||||
// \_ _____/__________| | __
|
||||
// | __)/ _ \_ __ \ |/ /
|
||||
// | \( <_> ) | \/ <
|
||||
// \___ / \____/|__| |__|_ \
|
||||
// \/ \/
|
||||
|
||||
type ForkPayload struct { |
||||
Forkee *Repository `json:"forkee"` |
||||
Repo *Repository `json:"repository"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *ForkPayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
||||
|
||||
// __________ .__
|
||||
// \______ \__ __ _____| |__
|
||||
// | ___/ | \/ ___/ | \
|
||||
// | | | | /\___ \| Y \
|
||||
// |____| |____//____ >___| /
|
||||
// \/ \/
|
||||
|
||||
// PushPayload represents a payload information of push event.
|
||||
type PushPayload struct { |
||||
Ref string `json:"ref"` |
||||
Before string `json:"before"` |
||||
After string `json:"after"` |
||||
CompareURL string `json:"compare_url"` |
||||
Commits []*PayloadCommit `json:"commits"` |
||||
Repo *Repository `json:"repository"` |
||||
Pusher *User `json:"pusher"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *PushPayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
||||
|
||||
// ParsePushHook parses push event hook content.
|
||||
func ParsePushHook(raw []byte) (*PushPayload, error) { |
||||
hook := new(PushPayload) |
||||
if err := json.Unmarshal(raw, hook); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
switch { |
||||
case hook.Repo == nil: |
||||
return nil, ErrInvalidReceiveHook |
||||
case len(hook.Ref) == 0: |
||||
return nil, ErrInvalidReceiveHook |
||||
} |
||||
return hook, nil |
||||
} |
||||
|
||||
// Branch returns branch name from a payload
|
||||
func (p *PushPayload) Branch() string { |
||||
return strings.Replace(p.Ref, "refs/heads/", "", -1) |
||||
} |
||||
|
||||
// .___
|
||||
// | | ______ ________ __ ____
|
||||
// | |/ ___// ___/ | \_/ __ \
|
||||
// | |\___ \ \___ \| | /\ ___/
|
||||
// |___/____ >____ >____/ \___ >
|
||||
// \/ \/ \/
|
||||
|
||||
type HookIssueAction string |
||||
|
||||
const ( |
||||
HOOK_ISSUE_OPENED HookIssueAction = "opened" |
||||
HOOK_ISSUE_CLOSED HookIssueAction = "closed" |
||||
HOOK_ISSUE_REOPENED HookIssueAction = "reopened" |
||||
HOOK_ISSUE_EDITED HookIssueAction = "edited" |
||||
HOOK_ISSUE_ASSIGNED HookIssueAction = "assigned" |
||||
HOOK_ISSUE_UNASSIGNED HookIssueAction = "unassigned" |
||||
HOOK_ISSUE_LABEL_UPDATED HookIssueAction = "label_updated" |
||||
HOOK_ISSUE_LABEL_CLEARED HookIssueAction = "label_cleared" |
||||
HOOK_ISSUE_MILESTONED HookIssueAction = "milestoned" |
||||
HOOK_ISSUE_DEMILESTONED HookIssueAction = "demilestoned" |
||||
HOOK_ISSUE_SYNCHRONIZED HookIssueAction = "synchronized" |
||||
) |
||||
|
||||
type ChangesFromPayload struct { |
||||
From string `json:"from"` |
||||
} |
||||
|
||||
type ChangesPayload struct { |
||||
Title *ChangesFromPayload `json:"title,omitempty"` |
||||
Body *ChangesFromPayload `json:"body,omitempty"` |
||||
} |
||||
|
||||
// IssuesPayload represents a payload information of issues event.
|
||||
type IssuesPayload struct { |
||||
Action HookIssueAction `json:"action"` |
||||
Index int64 `json:"number"` |
||||
Issue *Issue `json:"issue"` |
||||
Changes *ChangesPayload `json:"changes,omitempty"` |
||||
Repository *Repository `json:"repository"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *IssuesPayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
||||
|
||||
type HookIssueCommentAction string |
||||
|
||||
const ( |
||||
HOOK_ISSUE_COMMENT_CREATED HookIssueCommentAction = "created" |
||||
HOOK_ISSUE_COMMENT_EDITED HookIssueCommentAction = "edited" |
||||
HOOK_ISSUE_COMMENT_DELETED HookIssueCommentAction = "deleted" |
||||
) |
||||
|
||||
// IssueCommentPayload represents a payload information of issue comment event.
|
||||
type IssueCommentPayload struct { |
||||
Action HookIssueCommentAction `json:"action"` |
||||
Issue *Issue `json:"issue"` |
||||
Comment *Comment `json:"comment"` |
||||
Changes *ChangesPayload `json:"changes,omitempty"` |
||||
Repository *Repository `json:"repository"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *IssueCommentPayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
||||
|
||||
// __________ .__ .__ __________ __
|
||||
// \______ \__ __| | | | \______ \ ____ ________ __ ____ _______/ |_
|
||||
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
|
||||
// | | | | / |_| |__ | | \ ___< <_| | | /\ ___/ \___ \ | |
|
||||
// |____| |____/|____/____/ |____|_ /\___ >__ |____/ \___ >____ > |__|
|
||||
// \/ \/ |__| \/ \/
|
||||
|
||||
// PullRequestPayload represents a payload information of pull request event.
|
||||
type PullRequestPayload struct { |
||||
Action HookIssueAction `json:"action"` |
||||
Index int64 `json:"number"` |
||||
PullRequest *PullRequest `json:"pull_request"` |
||||
Changes *ChangesPayload `json:"changes,omitempty"` |
||||
Repository *Repository `json:"repository"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *PullRequestPayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
||||
|
||||
// __________ .__
|
||||
// \______ \ ____ | | ____ _____ ______ ____
|
||||
// | _// __ \| | _/ __ \\__ \ / ___// __ \
|
||||
// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
|
||||
// |____|_ /\___ >____/\___ >____ /____ >\___ >
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type HookReleaseAction string |
||||
|
||||
const ( |
||||
HOOK_RELEASE_PUBLISHED HookReleaseAction = "published" |
||||
) |
||||
|
||||
// ReleasePayload represents a payload information of release event.
|
||||
type ReleasePayload struct { |
||||
Action HookReleaseAction `json:"action"` |
||||
Release *Release `json:"release"` |
||||
Repository *Repository `json:"repository"` |
||||
Sender *User `json:"sender"` |
||||
} |
||||
|
||||
func (p *ReleasePayload) JSONPayload() ([]byte, error) { |
||||
return json.MarshalIndent(p, "", " ") |
||||
} |
@ -0,0 +1,50 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
type DeployKey struct { |
||||
ID int64 `json:"id"` |
||||
Key string `json:"key"` |
||||
URL string `json:"url"` |
||||
Title string `json:"title"` |
||||
Created time.Time `json:"created_at"` |
||||
ReadOnly bool `json:"read_only"` |
||||
} |
||||
|
||||
func (c *Client) ListDeployKeys(user, repo string) ([]*DeployKey, error) { |
||||
keys := make([]*DeployKey, 0, 10) |
||||
return keys, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys", user, repo), nil, nil, &keys) |
||||
} |
||||
|
||||
func (c *Client) GetDeployKey(user, repo string, keyID int64) (*DeployKey, error) { |
||||
key := new(DeployKey) |
||||
return key, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/keys/%d", user, repo, keyID), nil, nil, &key) |
||||
} |
||||
|
||||
type CreateKeyOption struct { |
||||
Title string `json:"title" binding:"Required"` |
||||
Key string `json:"key" binding:"Required"` |
||||
} |
||||
|
||||
func (c *Client) CreateDeployKey(user, repo string, opt CreateKeyOption) (*DeployKey, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
key := new(DeployKey) |
||||
return key, c.getParsedResponse("POST", fmt.Sprintf("/repos/%s/%s/keys", user, repo), jsonHeader, bytes.NewReader(body), key) |
||||
} |
||||
|
||||
func (c *Client) DeleteDeployKey(owner, repo string, keyID int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/repos/%s/%s/keys/%d", owner, repo, keyID), nil, nil) |
||||
return err |
||||
} |
@ -0,0 +1,31 @@ |
||||
// Copyright 2014 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"fmt" |
||||
) |
||||
|
||||
// User represents a API user.
|
||||
type User struct { |
||||
ID int64 `json:"id"` |
||||
UserName string `json:"username"` // LEGACY [Gogs 1.0]: remove field(s) for backward compatibility
|
||||
Login string `json:"login"` |
||||
FullName string `json:"full_name"` |
||||
Email string `json:"email"` |
||||
AvatarUrl string `json:"avatar_url"` |
||||
} |
||||
|
||||
func (c *Client) GetUserInfo(user string) (*User, error) { |
||||
u := new(User) |
||||
err := c.getParsedResponse("GET", fmt.Sprintf("/users/%s", user), nil, nil, u) |
||||
return u, err |
||||
} |
||||
|
||||
func (c *Client) GetSelfInfo() (*User, error) { |
||||
u := new(User) |
||||
err := c.getParsedResponse("GET", "/user", nil, nil, u) |
||||
return u, err |
||||
} |
@ -0,0 +1,46 @@ |
||||
// Copyright 2014 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/base64" |
||||
"encoding/json" |
||||
"fmt" |
||||
"net/http" |
||||
) |
||||
|
||||
func BasicAuthEncode(user, pass string) string { |
||||
return base64.StdEncoding.EncodeToString([]byte(user + ":" + pass)) |
||||
} |
||||
|
||||
// AccessToken represents a API access token.
|
||||
type AccessToken struct { |
||||
Name string `json:"name"` |
||||
Sha1 string `json:"sha1"` |
||||
} |
||||
|
||||
func (c *Client) ListAccessTokens(user, pass string) ([]*AccessToken, error) { |
||||
tokens := make([]*AccessToken, 0, 10) |
||||
return tokens, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/tokens", user), |
||||
http.Header{"Authorization": []string{"Basic " + BasicAuthEncode(user, pass)}}, nil, &tokens) |
||||
} |
||||
|
||||
type CreateAccessTokenOption struct { |
||||
Name string `json:"name" binding:"Required"` |
||||
} |
||||
|
||||
func (c *Client) CreateAccessToken(user, pass string, opt CreateAccessTokenOption) (*AccessToken, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
t := new(AccessToken) |
||||
return t, c.getParsedResponse("POST", fmt.Sprintf("/users/%s/tokens", user), |
||||
http.Header{ |
||||
"content-type": []string{"application/json"}, |
||||
"Authorization": []string{"Basic " + BasicAuthEncode(user, pass)}}, |
||||
bytes.NewReader(body), t) |
||||
} |
@ -0,0 +1,43 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
) |
||||
|
||||
type Email struct { |
||||
Email string `json:"email"` |
||||
Verified bool `json:"verified"` |
||||
Primary bool `json:"primary"` |
||||
} |
||||
|
||||
func (c *Client) ListEmails() ([]*Email, error) { |
||||
emails := make([]*Email, 0, 3) |
||||
return emails, c.getParsedResponse("GET", "/user/emails", nil, nil, &emails) |
||||
} |
||||
|
||||
type CreateEmailOption struct { |
||||
Emails []string `json:"emails"` |
||||
} |
||||
|
||||
func (c *Client) AddEmail(opt CreateEmailOption) ([]*Email, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
emails := make([]*Email, 0, 3) |
||||
return emails, c.getParsedResponse("POST", "/user/emails", jsonHeader, bytes.NewReader(body), emails) |
||||
} |
||||
|
||||
func (c *Client) DeleteEmail(opt CreateEmailOption) error { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = c.getResponse("DELETE", "/user/emails", jsonHeader, bytes.NewReader(body)) |
||||
return err |
||||
} |
@ -0,0 +1,47 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import "fmt" |
||||
|
||||
func (c *Client) ListMyFollowers(page int) ([]*User, error) { |
||||
users := make([]*User, 0, 10) |
||||
return users, c.getParsedResponse("GET", fmt.Sprintf("/user/followers?page=%d", page), nil, nil, &users) |
||||
} |
||||
|
||||
func (c *Client) ListFollowers(user string, page int) ([]*User, error) { |
||||
users := make([]*User, 0, 10) |
||||
return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/followers?page=%d", user, page), nil, nil, &users) |
||||
} |
||||
|
||||
func (c *Client) ListMyFollowing(page int) ([]*User, error) { |
||||
users := make([]*User, 0, 10) |
||||
return users, c.getParsedResponse("GET", fmt.Sprintf("/user/following?page=%d", page), nil, nil, &users) |
||||
} |
||||
|
||||
func (c *Client) ListFollowing(user string, page int) ([]*User, error) { |
||||
users := make([]*User, 0, 10) |
||||
return users, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/following?page=%d", user, page), nil, nil, &users) |
||||
} |
||||
|
||||
func (c *Client) IsFollowing(target string) bool { |
||||
_, err := c.getResponse("GET", fmt.Sprintf("/user/following/%s", target), nil, nil) |
||||
return err == nil |
||||
} |
||||
|
||||
func (c *Client) IsUserFollowing(user, target string) bool { |
||||
_, err := c.getResponse("GET", fmt.Sprintf("/users/%s/following/%s", user, target), nil, nil) |
||||
return err == nil |
||||
} |
||||
|
||||
func (c *Client) Follow(target string) error { |
||||
_, err := c.getResponse("PUT", fmt.Sprintf("/user/following/%s", target), jsonHeader, nil) |
||||
return err |
||||
} |
||||
|
||||
func (c *Client) Unfollow(target string) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/user/following/%s", target), nil, nil) |
||||
return err |
||||
} |
@ -0,0 +1,49 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
type PublicKey struct { |
||||
ID int64 `json:"id"` |
||||
Key string `json:"key"` |
||||
URL string `json:"url,omitempty"` |
||||
Title string `json:"title,omitempty"` |
||||
Created time.Time `json:"created_at,omitempty"` |
||||
} |
||||
|
||||
func (c *Client) ListPublicKeys(user string) ([]*PublicKey, error) { |
||||
keys := make([]*PublicKey, 0, 10) |
||||
return keys, c.getParsedResponse("GET", fmt.Sprintf("/users/%s/keys", user), nil, nil, &keys) |
||||
} |
||||
|
||||
func (c *Client) ListMyPublicKeys() ([]*PublicKey, error) { |
||||
keys := make([]*PublicKey, 0, 10) |
||||
return keys, c.getParsedResponse("GET", "/user/keys", nil, nil, &keys) |
||||
} |
||||
|
||||
func (c *Client) GetPublicKey(keyID int64) (*PublicKey, error) { |
||||
key := new(PublicKey) |
||||
return key, c.getParsedResponse("GET", fmt.Sprintf("/user/keys/%d", keyID), nil, nil, &key) |
||||
} |
||||
|
||||
func (c *Client) CreatePublicKey(opt CreateKeyOption) (*PublicKey, error) { |
||||
body, err := json.Marshal(&opt) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
key := new(PublicKey) |
||||
return key, c.getParsedResponse("POST", "/user/keys", jsonHeader, bytes.NewReader(body), key) |
||||
} |
||||
|
||||
func (c *Client) DeletePublicKey(keyID int64) error { |
||||
_, err := c.getResponse("DELETE", fmt.Sprintf("/user/keys/%d", keyID), nil, nil) |
||||
return err |
||||
} |
@ -0,0 +1,23 @@ |
||||
// Copyright 2015 The Gogs 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 gogs |
||||
|
||||
import ( |
||||
"net/http" |
||||
) |
||||
|
||||
var jsonHeader = http.Header{"content-type": []string{"application/json"}} |
||||
|
||||
func Bool(v bool) *bool { |
||||
return &v |
||||
} |
||||
|
||||
func String(v string) *string { |
||||
return &v |
||||
} |
||||
|
||||
func Int64(v int64) *int64 { |
||||
return &v |
||||
} |
After Width: | Height: | Size: 2.6 KiB |
Loading…
Reference in new issue