From 5f3196f0520734c2d680f10e4959f59540461208 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 11 Jun 2019 17:13:35 +0800 Subject: [PATCH 01/32] add support to migrate from gogs --- go.mod | 4 +- go.sum | 14 +- modules/migrations/base/comment.go | 1 + modules/migrations/base/milestone.go | 2 +- modules/migrations/gogs.go | 254 +++++++++++++ modules/migrations/gogs_test.go | 104 ++++++ .../github.com/gogs/go-gogs-client/.gitignore | 25 ++ vendor/github.com/gogs/go-gogs-client/LICENSE | 22 ++ .../github.com/gogs/go-gogs-client/README.md | 8 + .../gogs/go-gogs-client/admin_org.go | 43 +++ .../gogs/go-gogs-client/admin_repo.go | 21 ++ .../gogs/go-gogs-client/admin_user.go | 68 ++++ vendor/github.com/gogs/go-gogs-client/gogs.go | 90 +++++ .../github.com/gogs/go-gogs-client/issue.go | 103 ++++++ .../gogs/go-gogs-client/issue_comment.go | 70 ++++ .../gogs/go-gogs-client/issue_label.go | 99 +++++ .../gogs/go-gogs-client/issue_milestone.go | 69 ++++ .../gogs/go-gogs-client/media_types.go | 9 + .../gogs/go-gogs-client/miscellaneous.go | 11 + vendor/github.com/gogs/go-gogs-client/org.go | 69 ++++ .../gogs/go-gogs-client/org_member.go | 24 ++ .../gogs/go-gogs-client/org_team.go | 25 ++ vendor/github.com/gogs/go-gogs-client/pull.go | 37 ++ .../github.com/gogs/go-gogs-client/release.go | 22 ++ vendor/github.com/gogs/go-gogs-client/repo.go | 152 ++++++++ .../gogs/go-gogs-client/repo_branch.go | 25 ++ .../gogs/go-gogs-client/repo_collaborator.go | 44 +++ .../gogs/go-gogs-client/repo_commit.go | 53 +++ .../gogs/go-gogs-client/repo_file.go | 23 ++ .../gogs/go-gogs-client/repo_hook.go | 345 ++++++++++++++++++ .../gogs/go-gogs-client/repo_key.go | 50 +++ vendor/github.com/gogs/go-gogs-client/user.go | 25 ++ .../gogs/go-gogs-client/user_app.go | 46 +++ .../gogs/go-gogs-client/user_email.go | 43 +++ .../gogs/go-gogs-client/user_follow.go | 47 +++ .../gogs/go-gogs-client/user_key.go | 49 +++ .../github.com/gogs/go-gogs-client/utils.go | 23 ++ vendor/modules.txt | 2 + 38 files changed, 2109 insertions(+), 12 deletions(-) create mode 100644 modules/migrations/gogs.go create mode 100644 modules/migrations/gogs_test.go create mode 100644 vendor/github.com/gogs/go-gogs-client/.gitignore create mode 100644 vendor/github.com/gogs/go-gogs-client/LICENSE create mode 100644 vendor/github.com/gogs/go-gogs-client/README.md create mode 100644 vendor/github.com/gogs/go-gogs-client/admin_org.go create mode 100644 vendor/github.com/gogs/go-gogs-client/admin_repo.go create mode 100644 vendor/github.com/gogs/go-gogs-client/admin_user.go create mode 100644 vendor/github.com/gogs/go-gogs-client/gogs.go create mode 100644 vendor/github.com/gogs/go-gogs-client/issue.go create mode 100644 vendor/github.com/gogs/go-gogs-client/issue_comment.go create mode 100644 vendor/github.com/gogs/go-gogs-client/issue_label.go create mode 100644 vendor/github.com/gogs/go-gogs-client/issue_milestone.go create mode 100644 vendor/github.com/gogs/go-gogs-client/media_types.go create mode 100644 vendor/github.com/gogs/go-gogs-client/miscellaneous.go create mode 100644 vendor/github.com/gogs/go-gogs-client/org.go create mode 100644 vendor/github.com/gogs/go-gogs-client/org_member.go create mode 100644 vendor/github.com/gogs/go-gogs-client/org_team.go create mode 100644 vendor/github.com/gogs/go-gogs-client/pull.go create mode 100644 vendor/github.com/gogs/go-gogs-client/release.go create mode 100644 vendor/github.com/gogs/go-gogs-client/repo.go create mode 100644 vendor/github.com/gogs/go-gogs-client/repo_branch.go create mode 100644 vendor/github.com/gogs/go-gogs-client/repo_collaborator.go create mode 100644 vendor/github.com/gogs/go-gogs-client/repo_commit.go create mode 100644 vendor/github.com/gogs/go-gogs-client/repo_file.go create mode 100644 vendor/github.com/gogs/go-gogs-client/repo_hook.go create mode 100644 vendor/github.com/gogs/go-gogs-client/repo_key.go create mode 100644 vendor/github.com/gogs/go-gogs-client/user.go create mode 100644 vendor/github.com/gogs/go-gogs-client/user_app.go create mode 100644 vendor/github.com/gogs/go-gogs-client/user_email.go create mode 100644 vendor/github.com/gogs/go-gogs-client/user_follow.go create mode 100644 vendor/github.com/gogs/go-gogs-client/user_key.go create mode 100644 vendor/github.com/gogs/go-gogs-client/utils.go diff --git a/go.mod b/go.mod index 7e920ac03208e..9111d46ce9570 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,7 @@ require ( github.com/gobwas/glob v0.2.3 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 + github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15 github.com/google/go-github/v24 v24.0.1 github.com/gorilla/context v1.1.1 github.com/issue9/assert v1.3.2 // indirect @@ -69,8 +70,6 @@ require ( github.com/mattn/go-sqlite3 v1.11.0 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 @@ -82,7 +81,6 @@ require ( github.com/prometheus/client_golang v1.1.0 github.com/prometheus/procfs v0.0.4 // indirect github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect - github.com/russross/blackfriday v2.0.0+incompatible // indirect github.com/russross/blackfriday/v2 v2.0.1 github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect github.com/satori/go.uuid v1.2.0 diff --git a/go.sum b/go.sum index 7445469d7ed94..32121e94efc03 100644 --- a/go.sum +++ b/go.sum @@ -243,9 +243,13 @@ github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04Pgtpy github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk= +github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15 h1:tgEyCCe4+o8A2K/PEi9lF0QMA6XK+Y/j/WN01LnNbbo= +github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -254,6 +258,7 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -423,8 +428,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/niklasfasching/go-org v0.1.6 h1:F521WcqRNl8OJumlgAnekZgERaTA2HpfOYYfVEKOeI8= -github.com/niklasfasching/go-org v0.1.6/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU= github.com/niklasfasching/go-org v0.1.7 h1:t3V+3XnS/7BhKv/7SlMUa8FvAiq577/a1T3D7mLIRXE= github.com/niklasfasching/go-org v0.1.7/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -489,8 +492,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qq github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk= -github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= @@ -501,8 +502,6 @@ github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b h1:4kg1wyftSKxLtnPAvcRWakIPpokB9w780/KwrNLnfPA= github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc h1:3wIrJvFb3Pf6B/2mDBnN1G5IfUVev4X5apadQlWOczE= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= @@ -654,8 +653,6 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc= -golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -702,6 +699,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/modules/migrations/base/comment.go b/modules/migrations/base/comment.go index 38c544d6e04f3..94cbabaae62f3 100644 --- a/modules/migrations/base/comment.go +++ b/modules/migrations/base/comment.go @@ -14,6 +14,7 @@ type Comment struct { PosterName string PosterEmail string Created time.Time + Updated time.Time Content string Reactions *Reactions } diff --git a/modules/migrations/base/milestone.go b/modules/migrations/base/milestone.go index 8736aa6cfdd56..921968fcb5b97 100644 --- a/modules/migrations/base/milestone.go +++ b/modules/migrations/base/milestone.go @@ -15,5 +15,5 @@ type Milestone struct { Created time.Time Updated *time.Time Closed *time.Time - State string + State string // open, closed } diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go new file mode 100644 index 0000000000000..4b231c22abc4b --- /dev/null +++ b/modules/migrations/gogs.go @@ -0,0 +1,254 @@ +// 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 ( + "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 { +} + +// Match returns ture if the migration remote URL matched this downloader factory +func (f *GogsDownloaderFactory) Match(opts base.MigrateOptions) (bool, error) { + if opts.GitServiceType == structs.GogsService { + return true, nil + } + return false, nil +} + +// New returns a Downloader related to this factory according MigrateOptions +func (f *GogsDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader, error) { + u, err := url.Parse(opts.CloneAddr) + if err != nil { + return nil, err + } + + baseURL := u.Scheme + "://" + u.Host + fields := strings.Split(u.Path, "/") + oldOwner := fields[1] + oldName := strings.TrimSuffix(fields[2], ".git") + + log.Trace("Create gogs downloader: %s/%s", oldOwner, oldName) + + return NewGogsDownloader(baseURL, opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), 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 { + client *gogs.Client + baseURL string + repoOwner string + repoName string + userName string + password string +} + +// NewGogsDownloader creates a gogs Downloader via gogs API +func NewGogsDownloader(baseURL, userName, password, repoOwner, repoName string) *GogsDownloader { + var downloader = GogsDownloader{ + baseURL: baseURL, + userName: userName, + password: password, + repoOwner: repoOwner, + repoName: repoName, + } + + var client *gogs.Client + if userName != "" { + if password == "" { + client = gogs.NewClient(baseURL, userName) + } else { + client = gogs.NewClient(baseURL, "") + client.SetHTTPClient(&http.Client{ + Transport: &http.Transport{ + Proxy: func(req *http.Request) (*url.URL, error) { + req.SetBasicAuth(userName, password) + return nil, nil + }, + }, + }) + } + } + downloader.client = client + return &downloader +} + +// 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 github repo to stand Repo + return &base.Repository{ + Owner: g.repoOwner, + Name: g.repoName, + IsPrivate: gr.Private, + Description: gr.Description, + CloneURL: gr.CloneURL, + }, nil +} + +// GetTopics return github topics +func (g *GogsDownloader) GetTopics() ([]string, error) { + return []string{}, 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 +} + +func convertGogsLabel(label *gogs.Label) *base.Label { + return &base.Label{ + Name: label.Name, + Color: label.Color, + } +} + +// 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 +} + +// GetReleases returns releases +// FIXME: gogs API haven't support get releases +func (g *GogsDownloader) GetReleases() ([]*base.Release, error) { + return nil, ErrNotSupported +} + +// GetIssues returns issues according start and limit, perPage is not supported +func (g *GogsDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { + var allIssues = make([]*base.Issue, 0, perPage) + + issues, err := g.client.ListRepoIssues(g.repoOwner, g.repoName, gogs.ListIssueOption{ + Page: page, + }) + if err != nil { + return nil, false, fmt.Errorf("error while listing repos: %v", err) + } + for _, issue := range issues { + if issue.PullRequest != nil { + continue + } + + 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 + } + + allIssues = append(allIssues, &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, + }) + } + + 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 { + allComments = append(allComments, &base.Comment{ + PosterName: comment.Poster.Login, + PosterEmail: comment.Poster.Email, + Content: comment.Body, + Created: comment.Created, + Updated: comment.Updated, + }) + } + + return allComments, nil +} + +// GetPullRequests returns pull requests according page and perPage +func (g *GogsDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, error) { + return nil, ErrNotSupported +} diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go new file mode 100644 index 0000000000000..2e9a3f05e43db --- /dev/null +++ b/modules/migrations/gogs_test.go @@ -0,0 +1,104 @@ +// 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 ( + "testing" + "time" + + "code.gitea.io/gitea/modules/migrations/base" + "github.com/stretchr/testify/assert" +) + +func TestGogsDownloadRepo(t *testing.T) { + downloader := NewGogsDownloader("https://try.gogs.io", "c109b3c905eb57951cfdea270cfcfdc297a74500", "", "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.True(t, len(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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/.gitignore b/vendor/github.com/gogs/go-gogs-client/.gitignore new file mode 100644 index 0000000000000..25e241ae48140 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/.gitignore @@ -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 diff --git a/vendor/github.com/gogs/go-gogs-client/LICENSE b/vendor/github.com/gogs/go-gogs-client/LICENSE new file mode 100644 index 0000000000000..18b264d6046c6 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/LICENSE @@ -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. + diff --git a/vendor/github.com/gogs/go-gogs-client/README.md b/vendor/github.com/gogs/go-gogs-client/README.md new file mode 100644 index 0000000000000..ae33bc06f8ab7 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/README.md @@ -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. \ No newline at end of file diff --git a/vendor/github.com/gogs/go-gogs-client/admin_org.go b/vendor/github.com/gogs/go-gogs-client/admin_org.go new file mode 100644 index 0000000000000..28ba8f105cc90 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/admin_org.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/admin_repo.go b/vendor/github.com/gogs/go-gogs-client/admin_repo.go new file mode 100644 index 0000000000000..50ba2be47d368 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/admin_repo.go @@ -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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/admin_user.go b/vendor/github.com/gogs/go-gogs-client/admin_user.go new file mode 100644 index 0000000000000..459031d71d51a --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/admin_user.go @@ -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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/gogs.go b/vendor/github.com/gogs/go-gogs-client/gogs.go new file mode 100644 index 0000000000000..83ab8d71c57b7 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/gogs.go @@ -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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/issue.go b/vendor/github.com/gogs/go-gogs-client/issue.go new file mode 100644 index 0000000000000..aa2f0d8eebfe9 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/issue.go @@ -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", opt.Page), 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", opt.Page), 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", owner, repo, opt.Page), 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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/issue_comment.go b/vendor/github.com/gogs/go-gogs-client/issue_comment.go new file mode 100644 index 0000000000000..246af0d93ecf7 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/issue_comment.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/issue_label.go b/vendor/github.com/gogs/go-gogs-client/issue_label.go new file mode 100644 index 0000000000000..b8ff3009b48be --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/issue_label.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/issue_milestone.go b/vendor/github.com/gogs/go-gogs-client/issue_milestone.go new file mode 100644 index 0000000000000..ad27a15ef1bb6 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/issue_milestone.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/media_types.go b/vendor/github.com/gogs/go-gogs-client/media_types.go new file mode 100644 index 0000000000000..884a8a7405a0f --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/media_types.go @@ -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" +) diff --git a/vendor/github.com/gogs/go-gogs-client/miscellaneous.go b/vendor/github.com/gogs/go-gogs-client/miscellaneous.go new file mode 100644 index 0000000000000..fcf362ceb831f --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/miscellaneous.go @@ -0,0 +1,11 @@ +// 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 + Mode string + Context string +} diff --git a/vendor/github.com/gogs/go-gogs-client/org.go b/vendor/github.com/gogs/go-gogs-client/org.go new file mode 100644 index 0000000000000..10d22b50cbc28 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/org.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/org_member.go b/vendor/github.com/gogs/go-gogs-client/org_member.go new file mode 100644 index 0000000000000..d9cdadabd8846 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/org_member.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/org_team.go b/vendor/github.com/gogs/go-gogs-client/org_team.go new file mode 100644 index 0000000000000..e47f6447b03e2 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/org_team.go @@ -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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/pull.go b/vendor/github.com/gogs/go-gogs-client/pull.go new file mode 100644 index 0000000000000..be93b269d8154 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/pull.go @@ -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"` +} diff --git a/vendor/github.com/gogs/go-gogs-client/release.go b/vendor/github.com/gogs/go-gogs-client/release.go new file mode 100644 index 0000000000000..69c7f3b9baca5 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/release.go @@ -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"` +} diff --git a/vendor/github.com/gogs/go-gogs-client/repo.go b/vendor/github.com/gogs/go-gogs-client/repo.go new file mode 100644 index 0000000000000..38e5c159b1f4f --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/repo.go @@ -0,0 +1,152 @@ +// 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"` + 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"` + 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"` + 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 +} + +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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/repo_branch.go b/vendor/github.com/gogs/go-gogs-client/repo_branch.go new file mode 100644 index 0000000000000..1e5811212c5c2 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/repo_branch.go @@ -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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/repo_collaborator.go b/vendor/github.com/gogs/go-gogs-client/repo_collaborator.go new file mode 100644 index 0000000000000..6030850e6a653 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/repo_collaborator.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/repo_commit.go b/vendor/github.com/gogs/go-gogs-client/repo_commit.go new file mode 100644 index 0000000000000..b415962a2e8b3 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/repo_commit.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/repo_file.go b/vendor/github.com/gogs/go-gogs-client/repo_file.go new file mode 100644 index 0000000000000..d766fb6d8a246 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/repo_file.go @@ -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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/repo_hook.go b/vendor/github.com/gogs/go-gogs-client/repo_hook.go new file mode 100644 index 0000000000000..7f878915218dd --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/repo_hook.go @@ -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, "", " ") +} diff --git a/vendor/github.com/gogs/go-gogs-client/repo_key.go b/vendor/github.com/gogs/go-gogs-client/repo_key.go new file mode 100644 index 0000000000000..2201602c1f641 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/repo_key.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/user.go b/vendor/github.com/gogs/go-gogs-client/user.go new file mode 100644 index 0000000000000..bbe0ca9fdb9db --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/user.go @@ -0,0 +1,25 @@ +// 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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/user_app.go b/vendor/github.com/gogs/go-gogs-client/user_app.go new file mode 100644 index 0000000000000..965ed6ebfd048 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/user_app.go @@ -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) +} diff --git a/vendor/github.com/gogs/go-gogs-client/user_email.go b/vendor/github.com/gogs/go-gogs-client/user_email.go new file mode 100644 index 0000000000000..02dd402315087 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/user_email.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/user_follow.go b/vendor/github.com/gogs/go-gogs-client/user_follow.go new file mode 100644 index 0000000000000..5ba20cc084a9f --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/user_follow.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/user_key.go b/vendor/github.com/gogs/go-gogs-client/user_key.go new file mode 100644 index 0000000000000..c0278e0e9c7d2 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/user_key.go @@ -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 +} diff --git a/vendor/github.com/gogs/go-gogs-client/utils.go b/vendor/github.com/gogs/go-gogs-client/utils.go new file mode 100644 index 0000000000000..a4d673e0f7803 --- /dev/null +++ b/vendor/github.com/gogs/go-gogs-client/utils.go @@ -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 +} diff --git a/vendor/modules.txt b/vendor/modules.txt index dabd3995e9c36..80638dc906a71 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -202,6 +202,8 @@ github.com/gobwas/glob/util/strings github.com/gogits/chardet # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/cron +# github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15 +github.com/gogs/go-gogs-client # github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe github.com/golang-sql/civil # github.com/golang/protobuf v1.3.2 From 21533a4208b5cfbbf20cddfca4d906100946c671 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 8 Jul 2019 16:58:13 +0800 Subject: [PATCH 02/32] remove test since it depends on try.gogs.io --- modules/migrations/gogs_test.go | 104 -------------------------------- 1 file changed, 104 deletions(-) delete mode 100644 modules/migrations/gogs_test.go diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go deleted file mode 100644 index 2e9a3f05e43db..0000000000000 --- a/modules/migrations/gogs_test.go +++ /dev/null @@ -1,104 +0,0 @@ -// 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 ( - "testing" - "time" - - "code.gitea.io/gitea/modules/migrations/base" - "github.com/stretchr/testify/assert" -) - -func TestGogsDownloadRepo(t *testing.T) { - downloader := NewGogsDownloader("https://try.gogs.io", "c109b3c905eb57951cfdea270cfcfdc297a74500", "", "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.True(t, len(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) -} From 78d75c5644265b6e328f47ae7f2a194e542d88d4 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 8 Jul 2019 17:21:31 +0800 Subject: [PATCH 03/32] handle unsupported error --- modules/migrations/migrate.go | 36 +++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index bbc1dc2d56107..7cdb68f5416c9 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -110,7 +110,10 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating milestones") milestones, err := downloader.GetMilestones() if err != nil { - return err + if err != ErrNotSupported { + return err + } + log.Warn("migrating milestones is not supported, ignored") } msBatchSize := uploader.MaxBatchInsertSize("milestone") @@ -130,7 +133,11 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating labels") labels, err := downloader.GetLabels() if err != nil { - return err + if err != ErrNotSupported { + return err + } + + log.Warn("migrating labels is not supported, ignored") } lbBatchSize := uploader.MaxBatchInsertSize("label") @@ -150,7 +157,11 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating releases") releases, err := downloader.GetReleases() if err != nil { - return err + if err != ErrNotSupported { + return err + } + + log.Warn("migrating releases is not supported, ignored") } relBatchSize := uploader.MaxBatchInsertSize("release") @@ -175,7 +186,12 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts for i := 1; ; i++ { issues, isEnd, err := downloader.GetIssues(i, issueBatchSize) if err != nil { - return err + if err != ErrNotSupported { + return err + } + + log.Warn("migrating issues is not supported, ignored") + break } if err := uploader.CreateIssues(issues...); err != nil { @@ -190,7 +206,11 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts for _, issue := range issues { comments, err := downloader.GetComments(issue.Number) if err != nil { - return err + if err != ErrNotSupported { + return err + } + log.Warn("migrating comments is not supported, ignored") + break } allComments = append(allComments, comments...) @@ -222,7 +242,11 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts for i := 1; ; i++ { prs, err := downloader.GetPullRequests(i, prBatchSize) if err != nil { - return err + if err != ErrNotSupported { + return err + } + log.Warn("migrating pull requests is not supported, ignored") + break } if err := uploader.CreatePullRequests(prs...); err != nil { From 7417afdabbdfda2cb0408fdb2b5816136c3a016d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 9 Jul 2019 14:04:45 +0800 Subject: [PATCH 04/32] fix vendor --- modules/migrations/gogs_test.go | 114 ++++++++++++++++++++++++++++++++ vendor/modules.txt | 12 ++++ 2 files changed, 126 insertions(+) create mode 100644 modules/migrations/gogs_test.go diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go new file mode 100644 index 0000000000000..57c3467e902e6 --- /dev/null +++ b/modules/migrations/gogs_test.go @@ -0,0 +1,114 @@ +// 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 ( + "net/http" + "testing" + "time" + + "code.gitea.io/gitea/modules/migrations/base" + + "github.com/stretchr/testify/assert" +) + +func TestGogsDownloadRepo(t *testing.T) { + 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("https://try.gogs.io", "c109b3c905eb57951cfdea270cfcfdc297a74500", "", "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.True(t, len(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) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 80638dc906a71..e5eac6f3e62f5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -110,7 +110,11 @@ github.com/couchbase/vellum/utf8 github.com/couchbaselabs/go-couchbase # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew +<<<<<<< HEAD # github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 +======= +# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 +>>>>>>> fix vendor github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp github.com/denisenkom/go-mssqldb/internal/decimal @@ -200,6 +204,7 @@ github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings # github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/chardet +<<<<<<< HEAD # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/cron # github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15 @@ -207,6 +212,13 @@ github.com/gogs/go-gogs-client # github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe github.com/golang-sql/civil # github.com/golang/protobuf v1.3.2 +======= +# github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 +github.com/gogits/cron +# github.com/gogs/go-gogs-client v0.0.0-20181217004319-1cd0db3113de +github.com/gogs/go-gogs-client +# github.com/golang/protobuf v1.3.1 +>>>>>>> fix vendor github.com/golang/protobuf/proto # github.com/golang/snappy v0.0.1 github.com/golang/snappy From efcf78da67f26ea2bd2f355296d0f5a5b2b2df7c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 3 Nov 2019 12:11:32 +0800 Subject: [PATCH 05/32] fix go.sum --- vendor/modules.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/vendor/modules.txt b/vendor/modules.txt index e5eac6f3e62f5..80638dc906a71 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -110,11 +110,7 @@ github.com/couchbase/vellum/utf8 github.com/couchbaselabs/go-couchbase # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -<<<<<<< HEAD # github.com/denisenkom/go-mssqldb v0.0.0-20190924004331-208c0a498538 -======= -# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 ->>>>>>> fix vendor github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp github.com/denisenkom/go-mssqldb/internal/decimal @@ -204,7 +200,6 @@ github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings # github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/chardet -<<<<<<< HEAD # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/cron # github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15 @@ -212,13 +207,6 @@ github.com/gogs/go-gogs-client # github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe github.com/golang-sql/civil # github.com/golang/protobuf v1.3.2 -======= -# github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 -github.com/gogits/cron -# github.com/gogs/go-gogs-client v0.0.0-20181217004319-1cd0db3113de -github.com/gogs/go-gogs-client -# github.com/golang/protobuf v1.3.1 ->>>>>>> fix vendor github.com/golang/protobuf/proto # github.com/golang/snappy v0.0.1 github.com/golang/snappy From 9fe0b4a36801e54279d16673d0075917cc95a571 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 3 Nov 2019 13:52:25 +0800 Subject: [PATCH 06/32] ignore gogs test since it depends on try.gogs.io --- modules/migrations/gogs_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go index 57c3467e902e6..e7e0b73e97a6b 100644 --- a/modules/migrations/gogs_test.go +++ b/modules/migrations/gogs_test.go @@ -15,6 +15,8 @@ import ( ) func TestGogsDownloadRepo(t *testing.T) { + t.Skip() + resp, err := http.Get("https://try.gogs.io/lunnytest/TESTREPO") if err != nil || resp.StatusCode/100 != 2 { // skip and don't run test From 93a97ad7d0836ec807e945b13080050e8988aa46 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 14 Jan 2021 21:52:27 +0100 Subject: [PATCH 07/32] adapt: 'migrate service type switch page' --- options/locale/locale_en-US.ini | 1 + public/img/svg/gitea-gogs.svg | 1 + templates/repo/migrate/gogs.tmpl | 137 +++++++++++++++++++++++++++++++ web_src/svg/gitea-gogs.svg | 1 + 4 files changed, 140 insertions(+) create mode 100644 public/img/svg/gitea-gogs.svg create mode 100644 templates/repo/migrate/gogs.tmpl create mode 100644 web_src/svg/gitea-gogs.svg diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 48a43aa90113b..d3a93adfd3f3a 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -773,6 +773,7 @@ migrate.github.description = Migrating data from Github.com or Github Enterprise migrate.git.description = Migrating or Mirroring git data from Git services migrate.gitlab.description = Migrating data from GitLab.com or Self-Hosted gitlab server. migrate.gitea.description = Migrating data from Gitea.com or Self-Hosted Gitea server. +migrate.gogs.description = Migrating data from notabug.org or other Self-Hosted Gogs server. mirror_from = mirror of forked_from = forked from diff --git a/public/img/svg/gitea-gogs.svg b/public/img/svg/gitea-gogs.svg new file mode 100644 index 0000000000000..54d77be53aacf --- /dev/null +++ b/public/img/svg/gitea-gogs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/repo/migrate/gogs.tmpl b/templates/repo/migrate/gogs.tmpl new file mode 100644 index 0000000000000..4ad6e6024fae5 --- /dev/null +++ b/templates/repo/migrate/gogs.tmpl @@ -0,0 +1,137 @@ +{{template "base/head" .}} +
+
+
+
+ {{.CsrfTokenHtml}} +

+ {{.i18n.Tr "repo.migrate.migrate" .service.Title}} + +

+
+ {{template "base/alert" .}} +
+ + + + {{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}} + {{if .LFSActive}}
{{.i18n.Tr "repo.migrate.lfs_mirror_unsupported"}}{{end}} +
+
+ +
+ + + {{svg "octicon-question"}} +
+ +
+ +
+ {{if .DisableMirrors}} + + + {{else}} + + + {{end}} +
+
+ + {{.i18n.Tr "repo.migrate.migrate_items_options"}} +
+
+ +
+ + +
+
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+ +
+ + +
+
+ + +
+
+
+ +
+ +
+ + +
+ +
+ + +
+
+ +
+ {{if .IsForcedPrivate}} + + + {{else}} + + + {{end}} +
+
+
+ + +
+ +
+ + + {{.i18n.Tr "cancel"}} +
+
+
+
+
+
+{{template "base/footer" .}} diff --git a/web_src/svg/gitea-gogs.svg b/web_src/svg/gitea-gogs.svg new file mode 100644 index 0000000000000..6381d535b2a1c --- /dev/null +++ b/web_src/svg/gitea-gogs.svg @@ -0,0 +1 @@ + \ No newline at end of file From e34e6c2a8abd45c5354a9f2e75b15c5400a14e8b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 14 Jan 2021 22:27:42 +0100 Subject: [PATCH 08/32] refactor & fix & update --- modules/migrations/gogs.go | 121 ++++++++++++++++++-------------- modules/migrations/gogs_test.go | 28 +++++--- 2 files changed, 86 insertions(+), 63 deletions(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 4b231c22abc4b..108ab43133bf8 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -5,6 +5,7 @@ package migrations import ( + "context" "fmt" "net/http" "net/url" @@ -40,7 +41,7 @@ func (f *GogsDownloaderFactory) Match(opts base.MigrateOptions) (bool, error) { } // New returns a Downloader related to this factory according MigrateOptions -func (f *GogsDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader, error) { +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 @@ -53,7 +54,7 @@ func (f *GogsDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader, log.Trace("Create gogs downloader: %s/%s", oldOwner, oldName) - return NewGogsDownloader(baseURL, opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil + return NewGogsDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil } // GitServiceType returns the type of git service @@ -64,6 +65,7 @@ func (f *GogsDownloaderFactory) GitServiceType() structs.GitServiceType { // GogsDownloader implements a Downloader interface to get repository informations // from gogs via API type GogsDownloader struct { + ctx context.Context client *gogs.Client baseURL string repoOwner string @@ -72,9 +74,14 @@ type GogsDownloader struct { password string } +func (g *GogsDownloader) SetContext(ctx context.Context) { + g.ctx = ctx +} + // NewGogsDownloader creates a gogs Downloader via gogs API -func NewGogsDownloader(baseURL, userName, password, repoOwner, repoName string) *GogsDownloader { +func NewGogsDownloader(ctx context.Context, baseURL, userName, password, repoOwner, repoName string) *GogsDownloader { var downloader = GogsDownloader{ + ctx: ctx, baseURL: baseURL, userName: userName, password: password, @@ -109,19 +116,21 @@ func (g *GogsDownloader) GetRepoInfo() (*base.Repository, error) { return nil, err } - // convert github repo to stand Repo + // convert gogs repo to stand Repo return &base.Repository{ - Owner: g.repoOwner, - Name: g.repoName, - IsPrivate: gr.Private, - Description: gr.Description, - CloneURL: gr.CloneURL, + Owner: g.repoOwner, + Name: g.repoName, + IsPrivate: gr.Private, + Description: gr.Description, + CloneURL: gr.CloneURL, + OriginalURL: gr.HTMLURL, + DefaultBranch: gr.DefaultBranch, }, nil } -// GetTopics return github topics +// GetTopics return gogs topics func (g *GogsDownloader) GetTopics() ([]string, error) { - return []string{}, nil + return nil, ErrNotSupported } // GetMilestones returns milestones @@ -151,13 +160,6 @@ func (g *GogsDownloader) GetMilestones() ([]*base.Milestone, error) { return milestones, nil } -func convertGogsLabel(label *gogs.Label) *base.Label { - return &base.Label{ - Name: label.Name, - Color: label.Color, - } -} - // GetLabels returns labels func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { var perPage = 100 @@ -174,12 +176,6 @@ func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { return labels, nil } -// GetReleases returns releases -// FIXME: gogs API haven't support get releases -func (g *GogsDownloader) GetReleases() ([]*base.Release, error) { - return nil, ErrNotSupported -} - // GetIssues returns issues according start and limit, perPage is not supported func (g *GogsDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { var allIssues = make([]*base.Issue, 0, perPage) @@ -195,33 +191,7 @@ func (g *GogsDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, erro continue } - 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 - } - - allIssues = append(allIssues, &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, - }) + allIssues = append(allIssues, convertGogsIssue(issue)) } return allIssues, len(issues) == 0, nil @@ -248,7 +218,54 @@ func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) return allComments, 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, + } +} + +// GetReleases returns releases +// FIXME: gogs API haven't support get releases +func (g *GogsDownloader) GetReleases() ([]*base.Release, error) { + return nil, ErrNotSupported +} + // GetPullRequests returns pull requests according page and perPage -func (g *GogsDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, error) { +func (g *GogsDownloader) GetPullRequests(_, _ int) ([]*base.PullRequest, bool, error) { + return nil, false, ErrNotSupported +} + +func (g *GogsDownloader) GetReviews(_ int64) ([]*base.Review, error) { return nil, ErrNotSupported } diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go index e7e0b73e97a6b..ddc8cd74fce33 100644 --- a/modules/migrations/gogs_test.go +++ b/modules/migrations/gogs_test.go @@ -5,7 +5,9 @@ package migrations import ( + "context" "net/http" + "os" "testing" "time" @@ -15,7 +17,11 @@ import ( ) func TestGogsDownloadRepo(t *testing.T) { - t.Skip() + // Skip tests if Gitlab 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 { @@ -24,7 +30,7 @@ func TestGogsDownloadRepo(t *testing.T) { return } - downloader := NewGogsDownloader("https://try.gogs.io", "c109b3c905eb57951cfdea270cfcfdc297a74500", "", "lunnytest", "TESTREPO") + downloader := NewGogsDownloader(context.Background(), "https://try.gogs.io", gogsPersonalAccessToken, "", "lunnytest", "TESTREPO") repo, err := downloader.GetRepoInfo() assert.NoError(t, err) @@ -48,23 +54,23 @@ func TestGogsDownloadRepo(t *testing.T) { labels, err := downloader.GetLabels() assert.NoError(t, err) - assert.True(t, len(labels) == 7) + assert.Len(t, labels, 7) for _, l := range labels { switch l.Name { case "bug": - assertLabelEqual(t, "bug", "ee0701", l) + assertLabelEqual(t, "bug", "ee0701", "", l) case "duplicated": - assertLabelEqual(t, "duplicated", "cccccc", l) + assertLabelEqual(t, "duplicated", "cccccc", "", l) case "enhancement": - assertLabelEqual(t, "enhancement", "84b6eb", l) + assertLabelEqual(t, "enhancement", "84b6eb", "", l) case "help wanted": - assertLabelEqual(t, "help wanted", "128a0c", l) + assertLabelEqual(t, "help wanted", "128a0c", "", l) case "invalid": - assertLabelEqual(t, "invalid", "e6e6e6", l) + assertLabelEqual(t, "invalid", "e6e6e6", "", l) case "question": - assertLabelEqual(t, "question", "cc317c", l) + assertLabelEqual(t, "question", "cc317c", "", l) case "wontfix": - assertLabelEqual(t, "wontfix", "ffffff", l) + assertLabelEqual(t, "wontfix", "ffffff", "", l) } } @@ -111,6 +117,6 @@ func TestGogsDownloadRepo(t *testing.T) { }, comments) // downloader.GetPullRequests() - _, err = downloader.GetPullRequests(1, 3) + _, _, err = downloader.GetPullRequests(1, 3) assert.Error(t, err) } From 2da5710b9072963d21fb69ae63533f187c0ff814 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 14 Jan 2021 23:03:41 +0100 Subject: [PATCH 09/32] fix --- modules/migrations/gogs.go | 18 +++------ modules/structs/repo.go | 1 + public/img/svg/gitea-gogs.svg | 2 +- templates/repo/migrate/gogs.tmpl | 4 +- web_src/svg/gitea-gogs.svg | 65 +++++++++++++++++++++++++++++++- 5 files changed, 74 insertions(+), 16 deletions(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 108ab43133bf8..659ce9967ca89 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -32,14 +32,6 @@ func init() { type GogsDownloaderFactory struct { } -// Match returns ture if the migration remote URL matched this downloader factory -func (f *GogsDownloaderFactory) Match(opts base.MigrateOptions) (bool, error) { - if opts.GitServiceType == structs.GogsService { - return true, nil - } - return false, nil -} - // 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) @@ -128,11 +120,6 @@ func (g *GogsDownloader) GetRepoInfo() (*base.Repository, error) { }, nil } -// GetTopics return gogs topics -func (g *GogsDownloader) GetTopics() ([]string, error) { - return nil, ErrNotSupported -} - // GetMilestones returns milestones func (g *GogsDownloader) GetMilestones() ([]*base.Milestone, error) { var perPage = 100 @@ -261,6 +248,11 @@ func (g *GogsDownloader) GetReleases() ([]*base.Release, error) { return nil, ErrNotSupported } +// GetTopics return gogs topics +func (g *GogsDownloader) GetTopics() ([]string, error) { + return nil, ErrNotSupported +} + // GetPullRequests returns pull requests according page and perPage func (g *GogsDownloader) GetPullRequests(_, _ int) ([]*base.PullRequest, bool, error) { return nil, false, ErrNotSupported diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 309273d2fa337..0f0d834282b5b 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -280,5 +280,6 @@ var ( GithubService, GitlabService, GiteaService, + GogsService, } ) diff --git a/public/img/svg/gitea-gogs.svg b/public/img/svg/gitea-gogs.svg index 54d77be53aacf..606bcac58fa9f 100644 --- a/public/img/svg/gitea-gogs.svg +++ b/public/img/svg/gitea-gogs.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/templates/repo/migrate/gogs.tmpl b/templates/repo/migrate/gogs.tmpl index 4ad6e6024fae5..dd33fd0138930 100644 --- a/templates/repo/migrate/gogs.tmpl +++ b/templates/repo/migrate/gogs.tmpl @@ -22,7 +22,7 @@
- {{svg "octicon-question"}} +
@@ -62,6 +62,7 @@
+
diff --git a/web_src/svg/gitea-gogs.svg b/web_src/svg/gitea-gogs.svg index 6381d535b2a1c..a992f4a3e088f 100644 --- a/web_src/svg/gitea-gogs.svg +++ b/web_src/svg/gitea-gogs.svg @@ -1 +1,64 @@ - \ No newline at end of file + + + + + + image/svg+xml + + + + + + + + + + + + From 2b890ff4a632071306cb1ed5e99305d78e3907d8 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 14 Jan 2021 23:09:41 +0100 Subject: [PATCH 10/32] optimize svg --- public/img/svg/gitea-gogs.svg | 2 +- web_src/svg/gitea-gogs.svg | 65 +---------------------------------- 2 files changed, 2 insertions(+), 65 deletions(-) diff --git a/public/img/svg/gitea-gogs.svg b/public/img/svg/gitea-gogs.svg index 606bcac58fa9f..e34e81a523daa 100644 --- a/public/img/svg/gitea-gogs.svg +++ b/public/img/svg/gitea-gogs.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/web_src/svg/gitea-gogs.svg b/web_src/svg/gitea-gogs.svg index a992f4a3e088f..b1ff153b94123 100644 --- a/web_src/svg/gitea-gogs.svg +++ b/web_src/svg/gitea-gogs.svg @@ -1,64 +1 @@ - - - - - - image/svg+xml - - - - - - - - - - - - + From dc5e3baaf65c6907ba276c94a610632f258327f8 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 14 Jan 2021 23:24:16 +0100 Subject: [PATCH 11/32] refactor IsErrNotSupported --- modules/migrations/error.go | 5 +++++ modules/migrations/migrate.go | 7 +++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/migrations/error.go b/modules/migrations/error.go index 462ba29026664..a5651a4da90a4 100644 --- a/modules/migrations/error.go +++ b/modules/migrations/error.go @@ -19,6 +19,11 @@ var ( ErrRepoNotCreated = errors.New("repository is not created yet") ) +// IsErrNotSupported returns true if the err is ErrNotSupported +func IsErrNotSupported(err error) bool { + return err == ErrNotSupported +} + // IsRateLimitError returns true if the err is github.RateLimitError func IsRateLimitError(err error) bool { _, ok := err.(*github.RateLimitError) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index fd097cf92beb7..5cce77d420ec3 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -149,7 +149,10 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating topics") topics, err := downloader.GetTopics() if err != nil { - return err + if !IsErrNotSupported(err) { + return err + } + log.Warn("migrating topics is not supported, ignored") } if len(topics) > 0 { if err := uploader.CreateTopics(topics...); err != nil { @@ -161,7 +164,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating milestones") milestones, err := downloader.GetMilestones() if err != nil { - if err != ErrNotSupported { + if !IsErrNotSupported(err) { return err } log.Warn("migrating milestones is not supported, ignored") From f509a1dc0532d7916c07af4712131260d90cb113 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 00:29:47 +0100 Subject: [PATCH 12/32] gogs dont support oauth2 --- modules/migrations/gitea_uploader.go | 11 ++++++---- modules/migrations/gogs.go | 30 ++++++++++++++-------------- modules/migrations/gogs_test.go | 2 +- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/modules/migrations/gitea_uploader.go b/modules/migrations/gitea_uploader.go index 2c79bd4b0f660..99b232ff3f502 100644 --- a/modules/migrations/gitea_uploader.go +++ b/modules/migrations/gitea_uploader.go @@ -87,7 +87,6 @@ func (g *GiteaLocalUploader) MaxBatchInsertSize(tp string) int { } func fullURL(opts base.MigrateOptions, remoteAddr string) (string, error) { - var fullRemoteAddr = remoteAddr if len(opts.AuthToken) > 0 || len(opts.AuthUsername) > 0 { u, err := url.Parse(remoteAddr) if err != nil { @@ -95,11 +94,15 @@ func fullURL(opts base.MigrateOptions, remoteAddr string) (string, error) { } u.User = url.UserPassword(opts.AuthUsername, opts.AuthPassword) if len(opts.AuthToken) > 0 { - u.User = url.UserPassword("oauth2", opts.AuthToken) + if opts.GitServiceType == structs.GogsService { + u.User = url.UserPassword(opts.AuthToken, "") + } else { + u.User = url.UserPassword("oauth2", opts.AuthToken) + } } - fullRemoteAddr = u.String() + return u.String(), nil } - return fullRemoteAddr, nil + return remoteAddr, nil } // CreateRepo creates a repository diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 659ce9967ca89..79bba14ca9b2d 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -46,7 +46,7 @@ func (f *GogsDownloaderFactory) New(ctx context.Context, opts base.MigrateOption log.Trace("Create gogs downloader: %s/%s", oldOwner, oldName) - return NewGogsDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil + return NewGogsDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil } // GitServiceType returns the type of git service @@ -71,7 +71,7 @@ func (g *GogsDownloader) SetContext(ctx context.Context) { } // NewGogsDownloader creates a gogs Downloader via gogs API -func NewGogsDownloader(ctx context.Context, baseURL, userName, password, repoOwner, repoName string) *GogsDownloader { +func NewGogsDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GogsDownloader { var downloader = GogsDownloader{ ctx: ctx, baseURL: baseURL, @@ -82,21 +82,21 @@ func NewGogsDownloader(ctx context.Context, baseURL, userName, password, repoOwn } var client *gogs.Client - if userName != "" { - if password == "" { - client = gogs.NewClient(baseURL, userName) - } else { - client = gogs.NewClient(baseURL, "") - client.SetHTTPClient(&http.Client{ - Transport: &http.Transport{ - Proxy: func(req *http.Request) (*url.URL, error) { - req.SetBasicAuth(userName, password) - return nil, nil - }, + if len(token) != 0 { + client = gogs.NewClient(baseURL, token) + downloader.userName = token + } else { + client = gogs.NewClient(baseURL, "") + client.SetHTTPClient(&http.Client{ + Transport: &http.Transport{ + Proxy: func(req *http.Request) (*url.URL, error) { + req.SetBasicAuth(userName, password) + return nil, nil }, - }) - } + }, + }) } + downloader.client = client return &downloader } diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go index ddc8cd74fce33..b308f460db71b 100644 --- a/modules/migrations/gogs_test.go +++ b/modules/migrations/gogs_test.go @@ -17,7 +17,7 @@ import ( ) func TestGogsDownloadRepo(t *testing.T) { - // Skip tests if Gitlab token is not found + // 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") From 0dda8a9ccc8a528181cb2acaa55af5a08ee8cafd Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 00:33:31 +0100 Subject: [PATCH 13/32] Update modules/migrations/migrate.go --- modules/migrations/migrate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 5cce77d420ec3..8ea2c1cc6b3ed 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -190,7 +190,6 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if err != ErrNotSupported { return err } - log.Warn("migrating labels is not supported, ignored") } From 9225b0baea025e0ad3b47b32da2535b9be73d894 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 00:38:04 +0100 Subject: [PATCH 14/32] fix lint --- modules/migrations/gogs_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/migrations/gogs_test.go b/modules/migrations/gogs_test.go index b308f460db71b..c240ae6432acc 100644 --- a/modules/migrations/gogs_test.go +++ b/modules/migrations/gogs_test.go @@ -30,7 +30,7 @@ func TestGogsDownloadRepo(t *testing.T) { return } - downloader := NewGogsDownloader(context.Background(), "https://try.gogs.io", gogsPersonalAccessToken, "", "lunnytest", "TESTREPO") + downloader := NewGogsDownloader(context.Background(), "https://try.gogs.io", "", "", gogsPersonalAccessToken, "lunnytest", "TESTREPO") repo, err := downloader.GetRepoInfo() assert.NoError(t, err) From f8635eb24984f07022ad1705e0d1edd8c333c30f Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 01:22:17 +0100 Subject: [PATCH 15/32] refactor migrations downloader interface implementation(s) --- modules/migrations/base/downloader.go | 212 +------------------ modules/migrations/base/error.go | 26 +++ modules/migrations/base/null_downloader.go | 75 +++++++ modules/migrations/base/retry_downloader.go | 220 ++++++++++++++++++++ modules/migrations/error.go | 8 - modules/migrations/git.go | 41 +--- modules/migrations/gitea_downloader.go | 1 + modules/migrations/gitea_uploader.go | 26 +-- modules/migrations/github.go | 1 + modules/migrations/gitlab.go | 1 + modules/migrations/gogs.go | 40 ++-- modules/migrations/migrate.go | 16 +- modules/migrations/restore.go | 1 + 13 files changed, 358 insertions(+), 310 deletions(-) create mode 100644 modules/migrations/base/error.go create mode 100644 modules/migrations/base/null_downloader.go create mode 100644 modules/migrations/base/retry_downloader.go diff --git a/modules/migrations/base/downloader.go b/modules/migrations/base/downloader.go index afa99105c9e6c..de93f3aebab0c 100644 --- a/modules/migrations/base/downloader.go +++ b/modules/migrations/base/downloader.go @@ -7,7 +7,6 @@ package base import ( "context" - "time" "code.gitea.io/gitea/modules/structs" ) @@ -24,6 +23,7 @@ type Downloader interface { GetComments(issueNumber int64) ([]*Comment, error) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) GetReviews(pullRequestNumber int64) ([]*Review, error) + FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) } // DownloaderFactory defines an interface to match a downloader implementation and create a downloader @@ -31,213 +31,3 @@ type DownloaderFactory interface { New(ctx context.Context, opts MigrateOptions) (Downloader, error) GitServiceType() structs.GitServiceType } - -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 - } - 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 - } - 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 - } - 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 - } - 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 - } - 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 - } - 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 - } - 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 - } - 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 - } - select { - case <-d.ctx.Done(): - return nil, d.ctx.Err() - case <-time.After(time.Second * time.Duration(d.RetryDelay)): - } - } - return nil, err -} diff --git a/modules/migrations/base/error.go b/modules/migrations/base/error.go new file mode 100644 index 0000000000000..c255d28b31788 --- /dev/null +++ b/modules/migrations/base/error.go @@ -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 "errors" + +var ( + // ErrRepoNotCreated returns the error that repository not created + ErrRepoNotCreated = errors.New("repository is not created yet") +) + +// ErrNotSupported represents status if a downloader do not supported something. +type ErrNotSupported struct { +} + +// ErrNotSupported checks if an error is an ErrNotSupported +func IsErrNotSupported(err error) bool { + _, ok := err.(ErrNotSupported) + return ok +} + +func (err ErrNotSupported) Error() string { + return "not supported" +} diff --git a/modules/migrations/base/null_downloader.go b/modules/migrations/base/null_downloader.go new file mode 100644 index 0000000000000..6a34c0b00f364 --- /dev/null +++ b/modules/migrations/base/null_downloader.go @@ -0,0 +1,75 @@ +// 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" +) + +// NullNotifier implements a blank downloader +type NullDownloader struct { +} + +var ( + _ Downloader = &NullDownloader{} +) + +func (n NullDownloader) SetContext(_ context.Context) { + return +} + +func (n NullDownloader) GetRepoInfo() (*Repository, error) { + return nil, &ErrNotSupported{} +} + +func (n NullDownloader) GetTopics() ([]string, error) { + return nil, &ErrNotSupported{} +} + +func (n NullDownloader) GetMilestones() ([]*Milestone, error) { + return nil, &ErrNotSupported{} +} + +func (n NullDownloader) GetReleases() ([]*Release, error) { + return nil, &ErrNotSupported{} +} + +func (n NullDownloader) GetLabels() ([]*Label, error) { + return nil, &ErrNotSupported{} +} + +func (n NullDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { + return nil, false, &ErrNotSupported{} +} + +func (n NullDownloader) GetComments(issueNumber int64) ([]*Comment, error) { + return nil, &ErrNotSupported{} +} + +func (n NullDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) { + return nil, false, &ErrNotSupported{} +} + +func (n NullDownloader) GetReviews(pullRequestNumber int64) ([]*Review, error) { + return nil, &ErrNotSupported{} +} + +func (n NullDownloader) FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) { + return func(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 + } +} diff --git a/modules/migrations/base/retry_downloader.go b/modules/migrations/base/retry_downloader.go new file mode 100644 index 0000000000000..a47aebc1278ed --- /dev/null +++ b/modules/migrations/base/retry_downloader.go @@ -0,0 +1,220 @@ +// 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 + } + 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 + } + 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 + } + 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 + } + 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 + } + 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 + } + 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 + } + 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 + } + 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 + } + select { + case <-d.ctx.Done(): + return nil, d.ctx.Err() + case <-time.After(time.Second * time.Duration(d.RetryDelay)): + } + } + return nil, err +} diff --git a/modules/migrations/error.go b/modules/migrations/error.go index a5651a4da90a4..1c77fa9f2f288 100644 --- a/modules/migrations/error.go +++ b/modules/migrations/error.go @@ -12,18 +12,10 @@ import ( ) var ( - // ErrNotSupported returns the error not supported - ErrNotSupported = errors.New("not supported") - // ErrRepoNotCreated returns the error that repository not created ErrRepoNotCreated = errors.New("repository is not created yet") ) -// IsErrNotSupported returns true if the err is ErrNotSupported -func IsErrNotSupported(err error) bool { - return err == ErrNotSupported -} - // IsRateLimitError returns true if the err is github.RateLimitError func IsRateLimitError(err error) bool { _, ok := err.(*github.RateLimitError) diff --git a/modules/migrations/git.go b/modules/migrations/git.go index 88222086e4a8e..a7960b6651791 100644 --- a/modules/migrations/git.go +++ b/modules/migrations/git.go @@ -16,6 +16,7 @@ var ( // PlainGitDownloader implements a Downloader interface to clone git from a http/https URL type PlainGitDownloader struct { + base.NullDownloader ownerName string repoName string remoteURL string @@ -43,43 +44,3 @@ func (g *PlainGitDownloader) GetRepoInfo() (*base.Repository, error) { CloneURL: g.remoteURL, }, nil } - -// GetTopics returns empty list for plain git repo -func (g *PlainGitDownloader) GetTopics() ([]string, error) { - return []string{}, nil -} - -// GetMilestones returns milestones -func (g *PlainGitDownloader) GetMilestones() ([]*base.Milestone, error) { - return nil, ErrNotSupported -} - -// GetLabels returns labels -func (g *PlainGitDownloader) GetLabels() ([]*base.Label, error) { - return nil, ErrNotSupported -} - -// GetReleases returns releases -func (g *PlainGitDownloader) GetReleases() ([]*base.Release, error) { - return nil, ErrNotSupported -} - -// GetIssues returns issues according page and perPage -func (g *PlainGitDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { - return nil, false, ErrNotSupported -} - -// GetComments returns comments according issueNumber -func (g *PlainGitDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) { - return nil, ErrNotSupported -} - -// GetPullRequests returns pull requests according page and perPage -func (g *PlainGitDownloader) GetPullRequests(start, limit int) ([]*base.PullRequest, bool, error) { - return nil, false, ErrNotSupported -} - -// GetReviews returns reviews according issue number -func (g *PlainGitDownloader) GetReviews(issueNumber int64) ([]*base.Review, error) { - return nil, ErrNotSupported -} diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 0c690464fa96e..50fe261e5f2a9 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -69,6 +69,7 @@ func (f *GiteaDownloaderFactory) GitServiceType() structs.GitServiceType { // GiteaDownloader implements a Downloader interface to get repository information's type GiteaDownloader struct { + base.NullDownloader ctx context.Context client *gitea_sdk.Client repoOwner string diff --git a/modules/migrations/gitea_uploader.go b/modules/migrations/gitea_uploader.go index 99b232ff3f502..3be49b5c6cedb 100644 --- a/modules/migrations/gitea_uploader.go +++ b/modules/migrations/gitea_uploader.go @@ -10,7 +10,6 @@ import ( "context" "fmt" "io" - "net/url" "os" "path/filepath" "strings" @@ -86,25 +85,6 @@ func (g *GiteaLocalUploader) MaxBatchInsertSize(tp string) int { return 10 } -func fullURL(opts base.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 { - if opts.GitServiceType == structs.GogsService { - u.User = url.UserPassword(opts.AuthToken, "") - } else { - u.User = url.UserPassword("oauth2", opts.AuthToken) - } - } - return u.String(), nil - } - return remoteAddr, nil -} - // CreateRepo creates a repository func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.MigrateOptions) error { owner, err := models.GetUserByName(g.repoOwner) @@ -112,10 +92,6 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate return err } - remoteAddr, err := fullURL(opts, repo.CloneURL) - if err != nil { - return err - } var r *models.Repository if opts.MigrateToRepoID <= 0 { r, err = repo_module.CreateRepository(g.doer, owner, models.CreateRepoOptions{ @@ -141,7 +117,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate OriginalURL: repo.OriginalURL, GitServiceType: opts.GitServiceType, Mirror: repo.IsMirror, - CloneAddr: remoteAddr, + CloneAddr: repo.CloneURL, Private: repo.IsPrivate, Wiki: opts.Wiki, Releases: opts.Releases, // if didn't get releases, then sync them from tags diff --git a/modules/migrations/github.go b/modules/migrations/github.go index 178517ba42f2e..4d832387ba30e 100644 --- a/modules/migrations/github.go +++ b/modules/migrations/github.go @@ -65,6 +65,7 @@ func (f *GithubDownloaderV3Factory) GitServiceType() structs.GitServiceType { // GithubDownloaderV3 implements a Downloader interface to get repository informations // from github via APIv3 type GithubDownloaderV3 struct { + base.NullDownloader ctx context.Context client *github.Client repoOwner string diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go index e3fa956758d38..a697075ff892b 100644 --- a/modules/migrations/gitlab.go +++ b/modules/migrations/gitlab.go @@ -63,6 +63,7 @@ func (f *GitlabDownloaderFactory) GitServiceType() structs.GitServiceType { // - issueSeen, working alongside issueCount, is checked in GetComments() to see whether we // need to fetch the Issue or PR comments, as Gitlab stores them separately. type GitlabDownloader struct { + base.NullDownloader ctx context.Context client *gitlab.Client repoID int diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 79bba14ca9b2d..5b04e3e0ca310 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -57,6 +57,7 @@ func (f *GogsDownloaderFactory) GitServiceType() structs.GitServiceType { // 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 @@ -205,6 +206,25 @@ func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) return allComments, nil } +func (n GogsDownloader) FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) { + return func(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 { @@ -241,23 +261,3 @@ func convertGogsLabel(label *gogs.Label) *base.Label { Color: label.Color, } } - -// GetReleases returns releases -// FIXME: gogs API haven't support get releases -func (g *GogsDownloader) GetReleases() ([]*base.Release, error) { - return nil, ErrNotSupported -} - -// GetTopics return gogs topics -func (g *GogsDownloader) GetTopics() ([]string, error) { - return nil, ErrNotSupported -} - -// GetPullRequests returns pull requests according page and perPage -func (g *GogsDownloader) GetPullRequests(_, _ int) ([]*base.PullRequest, bool, error) { - return nil, false, ErrNotSupported -} - -func (g *GogsDownloader) GetReviews(_ int64) ([]*base.Review, error) { - return nil, ErrNotSupported -} diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 8ea2c1cc6b3ed..c0315a81361f4 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -141,6 +141,10 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts repo.Description = opts.Description } log.Trace("migrating git data") + + if opts.OriginalURL, err = downloader.FormatGitURL()(opts, opts.OriginalURL); err != nil { + return err + } if err := uploader.CreateRepo(repo, opts); err != nil { return err } @@ -149,7 +153,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating topics") topics, err := downloader.GetTopics() if err != nil { - if !IsErrNotSupported(err) { + if !base.IsErrNotSupported(err) { return err } log.Warn("migrating topics is not supported, ignored") @@ -164,7 +168,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating milestones") milestones, err := downloader.GetMilestones() if err != nil { - if !IsErrNotSupported(err) { + if !base.IsErrNotSupported(err) { return err } log.Warn("migrating milestones is not supported, ignored") @@ -187,7 +191,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating labels") labels, err := downloader.GetLabels() if err != nil { - if err != ErrNotSupported { + if !base.IsErrNotSupported(err) { return err } log.Warn("migrating labels is not supported, ignored") @@ -210,7 +214,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating releases") releases, err := downloader.GetReleases() if err != nil { - if err != ErrNotSupported { + if !base.IsErrNotSupported(err) { return err } @@ -247,7 +251,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts for i := 1; ; i++ { issues, isEnd, err := downloader.GetIssues(i, issueBatchSize) if err != nil { - if err != ErrNotSupported { + if !base.IsErrNotSupported(err) { return err } @@ -298,7 +302,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts for i := 1; ; i++ { prs, isEnd, err := downloader.GetPullRequests(i, prBatchSize) if err != nil { - if err != ErrNotSupported { + if !base.IsErrNotSupported(err) { return err } log.Warn("migrating pull requests is not supported, ignored") diff --git a/modules/migrations/restore.go b/modules/migrations/restore.go index 5550aaeb03a31..e1ab408e41c43 100644 --- a/modules/migrations/restore.go +++ b/modules/migrations/restore.go @@ -19,6 +19,7 @@ import ( // RepositoryRestorer implements an Downloader from the local directory type RepositoryRestorer struct { + base.NullDownloader ctx context.Context baseDir string repoOwner string From 7518582ef0f03b3d5284f4c979243bcd746e7c07 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 01:28:06 +0100 Subject: [PATCH 16/32] fix lint --- modules/migrations/base/error.go | 10 ++-------- modules/migrations/base/null_downloader.go | 17 +++++++++++++---- modules/migrations/gogs.go | 4 +++- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/modules/migrations/base/error.go b/modules/migrations/base/error.go index c255d28b31788..3adc968a5216f 100644 --- a/modules/migrations/base/error.go +++ b/modules/migrations/base/error.go @@ -4,23 +4,17 @@ package base -import "errors" - -var ( - // ErrRepoNotCreated returns the error that repository not created - ErrRepoNotCreated = errors.New("repository is not created yet") -) - // ErrNotSupported represents status if a downloader do not supported something. type ErrNotSupported struct { } -// ErrNotSupported checks if an error is an ErrNotSupported +// 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 { return "not supported" } diff --git a/modules/migrations/base/null_downloader.go b/modules/migrations/base/null_downloader.go index 6a34c0b00f364..80990022b1b37 100644 --- a/modules/migrations/base/null_downloader.go +++ b/modules/migrations/base/null_downloader.go @@ -9,7 +9,7 @@ import ( "net/url" ) -// NullNotifier implements a blank downloader +// NullDownloader implements a blank downloader type NullDownloader struct { } @@ -17,46 +17,55 @@ var ( _ Downloader = &NullDownloader{} ) -func (n NullDownloader) SetContext(_ context.Context) { - return -} +// SetContext set context +func (n NullDownloader) SetContext(_ context.Context) {} +// GetRepoInfo returns a repository information func (n NullDownloader) GetRepoInfo() (*Repository, error) { return nil, &ErrNotSupported{} } +// GetTopics return gitlab topics func (n NullDownloader) GetTopics() ([]string, error) { return nil, &ErrNotSupported{} } +// GetMilestones returns milestones func (n NullDownloader) GetMilestones() ([]*Milestone, error) { return nil, &ErrNotSupported{} } +// GetReleases returns releases func (n NullDownloader) GetReleases() ([]*Release, error) { return nil, &ErrNotSupported{} } +// GetLabels returns labels func (n NullDownloader) GetLabels() ([]*Label, error) { return nil, &ErrNotSupported{} } +// GetIssues returns issues according start and limit func (n NullDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { return nil, false, &ErrNotSupported{} } +// GetComments returns comments according issueNumber func (n NullDownloader) GetComments(issueNumber int64) ([]*Comment, error) { return nil, &ErrNotSupported{} } +// GetPullRequests returns pull requests according page and perPage func (n NullDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) { return nil, false, &ErrNotSupported{} } +// GetReviews returns pull requests review func (n NullDownloader) GetReviews(pullRequestNumber int64) ([]*Review, error) { return nil, &ErrNotSupported{} } +// FormatGitURL return func to add authentification into remote URLs func (n NullDownloader) FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) { return func(opts MigrateOptions, remoteAddr string) (string, error) { if len(opts.AuthToken) > 0 || len(opts.AuthUsername) > 0 { diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 5b04e3e0ca310..819615b80b85f 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -67,6 +67,7 @@ type GogsDownloader struct { password string } +// SetContext set context func (g *GogsDownloader) SetContext(ctx context.Context) { g.ctx = ctx } @@ -206,7 +207,8 @@ func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) return allComments, nil } -func (n GogsDownloader) FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) { +// FormatGitURL return func to add authentification into remote URLs +func (g GogsDownloader) FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) { return func(opts MigrateOptions, remoteAddr string) (string, error) { if len(opts.AuthToken) > 0 || len(opts.AuthUsername) > 0 { u, err := url.Parse(remoteAddr) From bce51d171c7751bbcd4ce4635c6a5600c2e45e42 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 14:13:16 +0100 Subject: [PATCH 17/32] handle ErrNotSupported on all downloader functions ... --- modules/migrations/migrate.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index c0315a81361f4..e1c7cddc549b8 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -133,15 +133,18 @@ func newDownloader(ctx context.Context, ownerName string, opts base.MigrateOptio func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions) error { repo, err := downloader.GetRepoInfo() if err != nil { - return err + if !base.IsErrNotSupported(err) { + return err + } + log.Info("migrating repo infos is not supported, ignored") } repo.IsPrivate = opts.Private repo.IsMirror = opts.Mirror if opts.Description != "" { repo.Description = opts.Description } - log.Trace("migrating git data") + log.Trace("migrating git data") if opts.OriginalURL, err = downloader.FormatGitURL()(opts, opts.OriginalURL); err != nil { return err } @@ -217,7 +220,6 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if !base.IsErrNotSupported(err) { return err } - log.Warn("migrating releases is not supported, ignored") } @@ -254,7 +256,6 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if !base.IsErrNotSupported(err) { return err } - log.Warn("migrating issues is not supported, ignored") break } @@ -269,7 +270,10 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating issue %d's comments", issue.Number) comments, err := downloader.GetComments(issue.Number) if err != nil { - return err + if !base.IsErrNotSupported(err) { + return err + } + log.Warn("migrating comments is not supported, ignored") } allComments = append(allComments, comments...) @@ -320,7 +324,10 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Trace("migrating pull request %d's comments", pr.Number) comments, err := downloader.GetComments(pr.Number) if err != nil { - return err + if !base.IsErrNotSupported(err) { + return err + } + log.Warn("migrating comments is not supported, ignored") } allComments = append(allComments, comments...) @@ -349,14 +356,18 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } reviews, err := downloader.GetReviews(number) + if err != nil { + if !base.IsErrNotSupported(err) { + return err + } + log.Warn("migrating reviews is not supported, ignored") + break + } if pr.OriginalNumber > 0 { for i := range reviews { reviews[i].IssueIndex = pr.Number } } - if err != nil { - return err - } allReviews = append(allReviews, reviews...) From cf30f4fd604643b13e78560063d55663d48fcf67 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 14:18:50 +0100 Subject: [PATCH 18/32] more specific error messages --- modules/migrations/base/error.go | 6 ++++++ modules/migrations/base/null_downloader.go | 18 +++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/modules/migrations/base/error.go b/modules/migrations/base/error.go index 3adc968a5216f..40ddcf4b75e92 100644 --- a/modules/migrations/base/error.go +++ b/modules/migrations/base/error.go @@ -4,8 +4,11 @@ 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 @@ -16,5 +19,8 @@ func IsErrNotSupported(err error) bool { // 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" } diff --git a/modules/migrations/base/null_downloader.go b/modules/migrations/base/null_downloader.go index 80990022b1b37..1de6317446fda 100644 --- a/modules/migrations/base/null_downloader.go +++ b/modules/migrations/base/null_downloader.go @@ -22,47 +22,47 @@ func (n NullDownloader) SetContext(_ context.Context) {} // GetRepoInfo returns a repository information func (n NullDownloader) GetRepoInfo() (*Repository, error) { - return nil, &ErrNotSupported{} + return nil, &ErrNotSupported{Entity: "RepoInfo"} } // GetTopics return gitlab topics func (n NullDownloader) GetTopics() ([]string, error) { - return nil, &ErrNotSupported{} + return nil, &ErrNotSupported{Entity: "Topics"} } // GetMilestones returns milestones func (n NullDownloader) GetMilestones() ([]*Milestone, error) { - return nil, &ErrNotSupported{} + return nil, &ErrNotSupported{Entity: "Milestones"} } // GetReleases returns releases func (n NullDownloader) GetReleases() ([]*Release, error) { - return nil, &ErrNotSupported{} + return nil, &ErrNotSupported{Entity: "Releases"} } // GetLabels returns labels func (n NullDownloader) GetLabels() ([]*Label, error) { - return nil, &ErrNotSupported{} + 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{} + return nil, false, &ErrNotSupported{Entity: "Issues"} } // GetComments returns comments according issueNumber func (n NullDownloader) GetComments(issueNumber int64) ([]*Comment, error) { - return nil, &ErrNotSupported{} + 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{} + return nil, false, &ErrNotSupported{Entity: "PullRequests"} } // GetReviews returns pull requests review func (n NullDownloader) GetReviews(pullRequestNumber int64) ([]*Review, error) { - return nil, &ErrNotSupported{} + return nil, &ErrNotSupported{Entity: "Reviews"} } // FormatGitURL return func to add authentification into remote URLs From 07d36912a3c81fc631860bac5452162f4ae48b71 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jan 2021 14:35:14 +0100 Subject: [PATCH 19/32] RetryDownloader: dont retry if not supported & fix test by adding a TODO :/ --- modules/migrations/base/null_downloader.go | 3 ++- modules/migrations/base/retry_downloader.go | 27 +++++++++++++++++++++ modules/migrations/migrate.go | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/migrations/base/null_downloader.go b/modules/migrations/base/null_downloader.go index 1de6317446fda..ed7c485fcc045 100644 --- a/modules/migrations/base/null_downloader.go +++ b/modules/migrations/base/null_downloader.go @@ -27,7 +27,8 @@ func (n NullDownloader) GetRepoInfo() (*Repository, error) { // GetTopics return gitlab topics func (n NullDownloader) GetTopics() ([]string, error) { - return nil, &ErrNotSupported{Entity: "Topics"} + //TODO: return nil, &ErrNotSupported{Entity: "Topics"} + return []string{}, nil } // GetMilestones returns milestones diff --git a/modules/migrations/base/retry_downloader.go b/modules/migrations/base/retry_downloader.go index a47aebc1278ed..eeb3cabbc18fb 100644 --- a/modules/migrations/base/retry_downloader.go +++ b/modules/migrations/base/retry_downloader.go @@ -48,6 +48,9 @@ func (d *RetryDownloader) GetRepoInfo() (*Repository, error) { 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() @@ -68,6 +71,9 @@ func (d *RetryDownloader) GetTopics() ([]string, error) { 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() @@ -88,6 +94,9 @@ func (d *RetryDownloader) GetMilestones() ([]*Milestone, error) { 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() @@ -108,6 +117,9 @@ func (d *RetryDownloader) GetReleases() ([]*Release, error) { 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() @@ -128,6 +140,9 @@ func (d *RetryDownloader) GetLabels() ([]*Label, error) { 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() @@ -149,6 +164,9 @@ func (d *RetryDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) { 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() @@ -169,6 +187,9 @@ func (d *RetryDownloader) GetComments(issueNumber int64) ([]*Comment, error) { 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() @@ -190,6 +211,9 @@ func (d *RetryDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bo 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() @@ -210,6 +234,9 @@ func (d *RetryDownloader) GetReviews(pullRequestNumber int64) ([]*Review, error) 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() diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index e1c7cddc549b8..bb9a214abc652 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -161,7 +161,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } log.Warn("migrating topics is not supported, ignored") } - if len(topics) > 0 { + if len(topics) != 0 { if err := uploader.CreateTopics(topics...); err != nil { return err } From 98fa1525b5bbcc81a3fae0ecbdefc74c111d0feb Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 16 Jan 2021 18:36:08 +0100 Subject: [PATCH 20/32] fix generate CloneURL --- modules/migrations/migrate.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index bb9a214abc652..5b54c50f926b8 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -143,12 +143,12 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if opts.Description != "" { repo.Description = opts.Description } - - log.Trace("migrating git data") - if opts.OriginalURL, err = downloader.FormatGitURL()(opts, opts.OriginalURL); err != nil { + if repo.CloneURL, err = downloader.FormatGitURL()(opts, repo.CloneURL); err != nil { return err } - if err := uploader.CreateRepo(repo, opts); err != nil { + + log.Trace("migrating git data") + if err = uploader.CreateRepo(repo, opts); err != nil { return err } defer uploader.Close() @@ -162,7 +162,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts log.Warn("migrating topics is not supported, ignored") } if len(topics) != 0 { - if err := uploader.CreateTopics(topics...); err != nil { + if err = uploader.CreateTopics(topics...); err != nil { return err } } @@ -229,14 +229,14 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts relBatchSize = len(releases) } - if err := uploader.CreateReleases(releases[:relBatchSize]...); err != nil { + if err = uploader.CreateReleases(releases[:relBatchSize]...); err != nil { return err } releases = releases[relBatchSize:] } // Once all releases (if any) are inserted, sync any remaining non-release tags - if err := uploader.SyncTags(); err != nil { + if err = uploader.SyncTags(); err != nil { return err } } @@ -279,7 +279,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts allComments = append(allComments, comments...) if len(allComments) >= commentBatchSize { - if err := uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { + if err = uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { return err } @@ -288,7 +288,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts } if len(allComments) > 0 { - if err := uploader.CreateComments(allComments...); err != nil { + if err = uploader.CreateComments(allComments...); err != nil { return err } } @@ -333,14 +333,14 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts allComments = append(allComments, comments...) if len(allComments) >= commentBatchSize { - if err := uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { + if err = uploader.CreateComments(allComments[:commentBatchSize]...); err != nil { return err } allComments = allComments[commentBatchSize:] } } if len(allComments) > 0 { - if err := uploader.CreateComments(allComments...); err != nil { + if err = uploader.CreateComments(allComments...); err != nil { return err } } @@ -372,14 +372,14 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts allReviews = append(allReviews, reviews...) if len(allReviews) >= reviewBatchSize { - if err := uploader.CreateReviews(allReviews[:reviewBatchSize]...); err != nil { + if err = uploader.CreateReviews(allReviews[:reviewBatchSize]...); err != nil { return err } allReviews = allReviews[reviewBatchSize:] } } if len(allReviews) > 0 { - if err := uploader.CreateReviews(allReviews...); err != nil { + if err = uploader.CreateReviews(allReviews...); err != nil { return err } } From 53f40f99c5e8ee6082ed8bf8f6bccfa04f806f25 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 16 Jan 2021 19:00:44 +0100 Subject: [PATCH 21/32] gogs: migrate closed issues too --- modules/migrations/gogs.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 819615b80b85f..9306edd121767 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -166,20 +166,34 @@ func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { } // GetIssues returns issues according start and limit, perPage is not supported -func (g *GogsDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { - var allIssues = make([]*base.Issue, 0, perPage) +func (g *GogsDownloader) GetIssues(page, _ int) ([]*base.Issue, bool, error) { + issuesOpen, isEndOpen, err := g.getIssues(page, "open") + if err != nil { + return nil, false, err + } + issuesClosed, isEndClosed, err := g.getIssues(page, "closed") + if err != nil { + return nil, false, err + } + + return append(issuesOpen, issuesClosed...), isEndOpen && isEndClosed, 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, + 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)) } From 67f93447940d10e04bb37ef3e4f7e6ba81616001 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 16 Jan 2021 19:13:55 +0100 Subject: [PATCH 22/32] optimize --- modules/migrations/gogs.go | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 9306edd121767..beaebe027d5e4 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -58,13 +58,14 @@ func (f *GogsDownloaderFactory) GitServiceType() structs.GitServiceType { // 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 + ctx context.Context + client *gogs.Client + baseURL string + repoOwner string + repoName string + userName string + password string + openIssuesFinished bool } // SetContext set context @@ -167,16 +168,24 @@ func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { // GetIssues returns issues according start and limit, perPage is not supported func (g *GogsDownloader) GetIssues(page, _ int) ([]*base.Issue, bool, error) { - issuesOpen, isEndOpen, err := g.getIssues(page, "open") - if err != nil { - return nil, false, err + state := "open" + if g.openIssuesFinished { + state = "closed" } - issuesClosed, isEndClosed, err := g.getIssues(page, "closed") + + issues, isEnd, err := g.getIssues(page, state) if err != nil { return nil, false, err } - return append(issuesOpen, issuesClosed...), isEndOpen && isEndClosed, nil + 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) { From 9a3e37d78c9d6f82aebb4b717e0a0ae1074948b1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 16 Jan 2021 19:18:56 +0100 Subject: [PATCH 23/32] sdk bug detected :/ --- modules/migrations/gogs.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index beaebe027d5e4..a8a587130bd4e 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -168,9 +168,9 @@ func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { // GetIssues returns issues according start and limit, perPage is not supported func (g *GogsDownloader) GetIssues(page, _ int) ([]*base.Issue, bool, error) { - state := "open" + state := string(gogs.STATE_OPEN) if g.openIssuesFinished { - state = "closed" + state = string(gogs.STATE_CLOSED) } issues, isEnd, err := g.getIssues(page, state) @@ -193,7 +193,7 @@ func (g *GogsDownloader) getIssues(page int, state string) ([]*base.Issue, bool, issues, err := g.client.ListRepoIssues(g.repoOwner, g.repoName, gogs.ListIssueOption{ Page: page, - State: state, + State: state, // TODO: fix SDK to respect this param!!! }) if err != nil { return nil, false, fmt.Errorf("error while listing repos: %v", err) From d70c62e352b6709061c58f94692c57393c214276 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 16 Jan 2021 22:18:56 +0100 Subject: [PATCH 24/32] resolve TODO --- go.mod | 2 ++ go.sum | 4 ++-- modules/migrations/gogs.go | 2 +- vendor/github.com/gogs/go-gogs-client/issue.go | 6 +++--- vendor/modules.txt | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 782ad71626958..a2b2c1ff8797d 100644 --- a/go.mod +++ b/go.mod @@ -129,3 +129,5 @@ require ( replace github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4 replace github.com/microcosm-cc/bluemonday => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 + +replace github.com/gogs/go-gogs-client => github.com/6543-forks/go-gogs-client v0.0.0-20210116182316-f2f8bc0ea9cc diff --git a/go.sum b/go.sum index 258906142d92f..1b238a9918351 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,8 @@ gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7 h1:N9QFoeNsUXLhl14m gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7/go.mod h1:kgsbFPPS4P+acDYDOPDa3N4IWWOuDJt5/INKRUz7aks= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= +github.com/6543-forks/go-gogs-client v0.0.0-20210116182316-f2f8bc0ea9cc h1:FLylYVXDwK+YtrmXYnv2Q1Y5lQ9TU1Xp5F2vndIOTb4= +github.com/6543-forks/go-gogs-client v0.0.0-20210116182316-f2f8bc0ea9cc/go.mod h1:1Jj2LLcHcL+RHIT1IOaEsnoawRw+sjZYoiAjFWKJN/o= github.com/6543/go-version v1.2.4 h1:MPsSnqNrM0HwA9tnmWNnsMdQMg4/u4fflARjwomoof4= github.com/6543/go-version v1.2.4/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= @@ -481,8 +483,6 @@ github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0 github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8= github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk= -github.com/gogs/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355 h1:xk0ImJ2ofG4iVcC57zoqPgqMhn65fyT/xWop8idRyCI= -github.com/gogs/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index a8a587130bd4e..7a1d594e30631 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -193,7 +193,7 @@ func (g *GogsDownloader) getIssues(page int, state string) ([]*base.Issue, bool, issues, err := g.client.ListRepoIssues(g.repoOwner, g.repoName, gogs.ListIssueOption{ Page: page, - State: state, // TODO: fix SDK to respect this param!!! + State: state, }) if err != nil { return nil, false, fmt.Errorf("error while listing repos: %v", err) diff --git a/vendor/github.com/gogs/go-gogs-client/issue.go b/vendor/github.com/gogs/go-gogs-client/issue.go index aa2f0d8eebfe9..ec69a35b1e615 100644 --- a/vendor/github.com/gogs/go-gogs-client/issue.go +++ b/vendor/github.com/gogs/go-gogs-client/issue.go @@ -47,17 +47,17 @@ type ListIssueOption struct { func (c *Client) ListIssues(opt ListIssueOption) ([]*Issue, error) { issues := make([]*Issue, 0, 10) - return issues, c.getParsedResponse("GET", fmt.Sprintf("/issues?page=%d", opt.Page), nil, nil, &issues) + 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", opt.Page), nil, nil, &issues) + 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", owner, repo, opt.Page), nil, nil, &issues) + 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) { diff --git a/vendor/modules.txt b/vendor/modules.txt index 45b036d0aea3d..ffeecc4ea9c1f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -412,7 +412,7 @@ github.com/gogs/chardet # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 ## explicit github.com/gogs/cron -# github.com/gogs/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355 +# github.com/gogs/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355 => github.com/6543-forks/go-gogs-client v0.0.0-20210116182316-f2f8bc0ea9cc ## explicit github.com/gogs/go-gogs-client # github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe @@ -1009,3 +1009,4 @@ xorm.io/xorm/schemas xorm.io/xorm/tags # github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4 # github.com/microcosm-cc/bluemonday => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 +# github.com/gogs/go-gogs-client => github.com/6543-forks/go-gogs-client v0.0.0-20210116182316-f2f8bc0ea9cc From 15f3307a6851cfc4c6a5a12e8c359abe433c3124 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 17 Jan 2021 15:37:37 +0100 Subject: [PATCH 25/32] fix out of slice issue --- modules/migrations/gitea_downloader.go | 2 +- modules/migrations/gogs.go | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go index 50fe261e5f2a9..70daf8d5a3209 100644 --- a/modules/migrations/gitea_downloader.go +++ b/modules/migrations/gitea_downloader.go @@ -96,7 +96,7 @@ func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, passwo path := strings.Split(repoPath, "/") paginationSupport := true - if err := giteaClient.CheckServerVersionConstraint(">=1.12"); err != nil { + if err = giteaClient.CheckServerVersionConstraint(">=1.12"); err != nil { paginationSupport = false } diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 7a1d594e30631..6b28307c2a5fb 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -40,13 +40,16 @@ func (f *GogsDownloaderFactory) New(ctx context.Context, opts base.MigrateOption } baseURL := u.Scheme + "://" + u.Host - fields := strings.Split(u.Path, "/") - oldOwner := fields[1] - oldName := strings.TrimSuffix(fields[2], ".git") + repoNameSpace := strings.TrimSuffix(u.Path, ".git") + repoNameSpace = strings.Trim(repoNameSpace, "/") - log.Trace("Create gogs downloader: %s/%s", oldOwner, oldName) + fields := strings.Split(repoNameSpace, "/") + if len(fields) < 2 { + return nil, fmt.Errorf("invalid path: %s", repoNameSpace) + } - return NewGogsDownloader(ctx, baseURL, opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil + 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 From 4099e1733a1a997a51ae9aad6e4df0afce0810c0 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 17 Jan 2021 16:40:27 +0100 Subject: [PATCH 26/32] fix pagination --- modules/migrations/gogs.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 6b28307c2a5fb..65c7357c85b2d 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -69,6 +69,7 @@ type GogsDownloader struct { userName string password string openIssuesFinished bool + openIssuesPages int } // SetContext set context @@ -171,9 +172,13 @@ func (g *GogsDownloader) GetLabels() ([]*base.Label, error) { // GetIssues returns issues according start and limit, perPage is not supported func (g *GogsDownloader) GetIssues(page, _ int) ([]*base.Issue, bool, error) { - state := string(gogs.STATE_OPEN) + 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) From 08b9e417394236ada3261e2b7a6a5213568567f4 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 17 Jan 2021 18:41:14 +0100 Subject: [PATCH 27/32] Resolve GetTopics() TODO --- modules/migrations/base/null_downloader.go | 5 ++--- modules/migrations/git.go | 5 +++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/migrations/base/null_downloader.go b/modules/migrations/base/null_downloader.go index ed7c485fcc045..789cfc469f021 100644 --- a/modules/migrations/base/null_downloader.go +++ b/modules/migrations/base/null_downloader.go @@ -25,10 +25,9 @@ func (n NullDownloader) GetRepoInfo() (*Repository, error) { return nil, &ErrNotSupported{Entity: "RepoInfo"} } -// GetTopics return gitlab topics +// GetTopics return repository topics func (n NullDownloader) GetTopics() ([]string, error) { - //TODO: return nil, &ErrNotSupported{Entity: "Topics"} - return []string{}, nil + return nil, &ErrNotSupported{Entity: "Topics"} } // GetMilestones returns milestones diff --git a/modules/migrations/git.go b/modules/migrations/git.go index a7960b6651791..7e4194547499b 100644 --- a/modules/migrations/git.go +++ b/modules/migrations/git.go @@ -44,3 +44,8 @@ func (g *PlainGitDownloader) GetRepoInfo() (*base.Repository, error) { CloneURL: g.remoteURL, }, nil } + +// GetTopics return empty string slice +func (g PlainGitDownloader) GetTopics() ([]string, error) { + return []string{}, nil +} From 72bd6de5cbea2221926bd7e091175f790ed7d52b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sun, 17 Jan 2021 19:20:11 +0100 Subject: [PATCH 28/32] impruve more --- modules/migrations/base/downloader.go | 2 +- modules/migrations/base/null_downloader.go | 26 +++++++++---------- modules/migrations/gogs.go | 29 ++++++++++------------ modules/migrations/migrate.go | 2 +- routers/api/v1/repo/migrate.go | 3 +++ 5 files changed, 30 insertions(+), 32 deletions(-) diff --git a/modules/migrations/base/downloader.go b/modules/migrations/base/downloader.go index de93f3aebab0c..919f4b52a05f1 100644 --- a/modules/migrations/base/downloader.go +++ b/modules/migrations/base/downloader.go @@ -23,7 +23,7 @@ type Downloader interface { GetComments(issueNumber int64) ([]*Comment, error) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) GetReviews(pullRequestNumber int64) ([]*Review, error) - FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) + FormatCloneURL(opts MigrateOptions, remoteAddr string) (string, error) } // DownloaderFactory defines an interface to match a downloader implementation and create a downloader diff --git a/modules/migrations/base/null_downloader.go b/modules/migrations/base/null_downloader.go index 789cfc469f021..a93c20339b60d 100644 --- a/modules/migrations/base/null_downloader.go +++ b/modules/migrations/base/null_downloader.go @@ -65,20 +65,18 @@ func (n NullDownloader) GetReviews(pullRequestNumber int64) ([]*Review, error) { return nil, &ErrNotSupported{Entity: "Reviews"} } -// FormatGitURL return func to add authentification into remote URLs -func (n NullDownloader) FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) { - return func(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 +// 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 } - return remoteAddr, nil + 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 } diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 65c7357c85b2d..fa509ed5ce1c7 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -238,24 +238,21 @@ func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) return allComments, nil } -// FormatGitURL return func to add authentification into remote URLs -func (g GogsDownloader) FormatGitURL() func(opts MigrateOptions, remoteAddr string) (string, error) { - return func(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 +// 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 } - return remoteAddr, nil + 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 { diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go index 5b54c50f926b8..b9c17478a9982 100644 --- a/modules/migrations/migrate.go +++ b/modules/migrations/migrate.go @@ -143,7 +143,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts if opts.Description != "" { repo.Description = opts.Description } - if repo.CloneURL, err = downloader.FormatGitURL()(opts, repo.CloneURL); err != nil { + if repo.CloneURL, err = downloader.FormatCloneURL(opts, repo.CloneURL); err != nil { return err } diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index f07599399c7b0..0b829c9dfba84 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations" + "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/notification" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" @@ -217,6 +218,8 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteA ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(models.ErrNamePatternNotAllowed).Pattern)) case models.IsErrMigrationNotAllowed(err): ctx.Error(http.StatusUnprocessableEntity, "", err) + case base.IsErrNotSupported(err): + ctx.Error(http.StatusUnprocessableEntity, "", err) default: err = util.URLSanitizedError(err, remoteAddr) if strings.Contains(err.Error(), "Authentication failed") || From 16dc498d4357c8e0e3566a615b91fc852e4974b4 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 19 Jan 2021 01:32:08 +0100 Subject: [PATCH 29/32] nits --- modules/migrations/gogs.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index fa509ed5ce1c7..fe38c9d59c1c2 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -238,8 +238,13 @@ func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) 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) { +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 { From 802b5322ab492e97b2d1b0f2cfb247350de755d1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 19 Jan 2021 02:07:42 +0100 Subject: [PATCH 30/32] fix get Comments --- modules/migrations/gogs.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index fe38c9d59c1c2..8cb5d1941c396 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -226,7 +226,12 @@ func (g *GogsDownloader) GetComments(issueNumber int64) ([]*base.Comment, error) 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, From e9109dda1c98a566a1f55cba21966e633ad749f6 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Thu, 21 Jan 2021 18:15:21 +0000 Subject: [PATCH 31/32] Retrofit context cancellation Signed-off-by: Andrew Thornton --- modules/migrations/gogs.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 8cb5d1941c396..6da9708ee7774 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -70,6 +70,7 @@ type GogsDownloader struct { password string openIssuesFinished bool openIssuesPages int + transport http.RoundTripper } // SetContext set context @@ -93,14 +94,16 @@ func NewGogsDownloader(ctx context.Context, baseURL, userName, password, token, 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: &http.Transport{ - Proxy: func(req *http.Request) (*url.URL, error) { - req.SetBasicAuth(userName, password) - return nil, nil - }, - }, + Transport: &downloader, }) } @@ -108,6 +111,12 @@ func NewGogsDownloader(ctx context.Context, baseURL, userName, password, token, return &downloader } +// RoundTrip wraps the provided request within this downloaders 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) From 19e2ed8aeebc316dac6e32f47c09ce9b286afdae Mon Sep 17 00:00:00 2001 From: zeripath Date: Thu, 21 Jan 2021 18:38:54 +0000 Subject: [PATCH 32/32] Update modules/migrations/gogs.go --- modules/migrations/gogs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/migrations/gogs.go b/modules/migrations/gogs.go index 6da9708ee7774..b616907938ff4 100644 --- a/modules/migrations/gogs.go +++ b/modules/migrations/gogs.go @@ -111,7 +111,7 @@ func NewGogsDownloader(ctx context.Context, baseURL, userName, password, token, return &downloader } -// RoundTrip wraps the provided request within this downloaders context and passes it to our internal http.Transport. +// 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))