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..e7e0b73e97a6b
--- /dev/null
+++ b/modules/migrations/gogs_test.go
@@ -0,0 +1,116 @@
+// 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) {
+	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
+		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/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 {
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