summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
author6543 <6543@obermui.de>2020-10-14 06:06:00 +0200
committerGitHub <noreply@github.com>2020-10-14 07:06:00 +0300
commit49b1948cb11f46b8dabc6c977079ca9a187c92e0 (patch)
tree4c582fd4a53ce6ee3d24b1ef902b3f242187eb50 /modules
parentdfa7291f8fafd2aac032ef73a78b588e4d0e9a36 (diff)
downloadgitea-49b1948cb11f46b8dabc6c977079ca9a187c92e0.tar.gz
gitea-49b1948cb11f46b8dabc6c977079ca9a187c92e0.zip
Gitea 2 Gitea migration (#12657)
* first draft * update gitea sdk to 9e280adb4da * adapt feat of updated sdk * releases now works * break the Reactions loop * use convertGiteaLabel * fix endless loop because paggination is not supported there !!! * rename gitea local uploader files * pagination can bite you in the ass * Version Checks * lint * docs * rename gitea sdk import to miss future conficts * go-swagger: dont scan the sdk structs * make sure gitea can shutdown gracefully * make GetPullRequests and GetIssues similar * rm useles * Add Test: started ... * ... add tests ... * Add tests and Fixing things * Workaround missing SHA * Adapt: Ensure that all migration requests are cancellable (714ab71ddc4260937b1480519d453d2dc4e77dd6) * LINT: fix misspells in test set * adapt ListMergeRequestAwardEmoji * update sdk * Return error when creating giteadownloader failed * update sdk * adapt new sdk * adopt new features * check version before err * adapt: 'migrate service type switch page' * optimize * Fix DefaultBranch * impruve * handle subPath * fix test * Fix ReviewCommentPosition * test GetReviews * add DefaultBranch int test set * rm unused * Update SDK to v0.13.0 * addopt sdk changes * found better link * format template * Update Docs * Update Gitea SDK (v0.13.1)
Diffstat (limited to 'modules')
-rw-r--r--modules/migrations/base/downloader.go15
-rw-r--r--modules/migrations/base/issue.go1
-rw-r--r--modules/migrations/base/pullrequest.go1
-rw-r--r--modules/migrations/base/release.go1
-rw-r--r--modules/migrations/base/repo.go2
-rw-r--r--modules/migrations/base/review.go1
-rw-r--r--modules/migrations/git.go6
-rw-r--r--modules/migrations/gitea_downloader.go671
-rw-r--r--modules/migrations/gitea_downloader_test.go365
-rw-r--r--modules/migrations/gitea_uploader.go (renamed from modules/migrations/gitea.go)23
-rw-r--r--modules/migrations/gitea_uploader_test.go (renamed from modules/migrations/gitea_test.go)0
-rw-r--r--modules/migrations/github.go10
-rw-r--r--modules/migrations/github_test.go2
-rw-r--r--modules/migrations/gitlab.go10
-rw-r--r--modules/migrations/gitlab_test.go2
-rw-r--r--modules/migrations/migrate.go4
-rw-r--r--modules/structs/repo.go1
17 files changed, 1083 insertions, 32 deletions
diff --git a/modules/migrations/base/downloader.go b/modules/migrations/base/downloader.go
index 036abf22c9..5c47ed5305 100644
--- a/modules/migrations/base/downloader.go
+++ b/modules/migrations/base/downloader.go
@@ -15,7 +15,7 @@ import (
// AssetDownloader downloads an asset (attachment) for a release
type AssetDownloader interface {
- GetAsset(tag string, id int64) (io.ReadCloser, error)
+ GetAsset(relTag string, relID, id int64) (io.ReadCloser, error)
}
// Downloader downloads the site repo informations
@@ -29,7 +29,7 @@ type Downloader interface {
GetLabels() ([]*Label, error)
GetIssues(page, perPage int) ([]*Issue, bool, error)
GetComments(issueNumber int64) ([]*Comment, error)
- GetPullRequests(page, perPage int) ([]*PullRequest, error)
+ GetPullRequests(page, perPage int) ([]*PullRequest, bool, error)
GetReviews(pullRequestNumber int64) ([]*Review, error)
}
@@ -209,23 +209,24 @@ func (d *RetryDownloader) GetComments(issueNumber int64) ([]*Comment, error) {
}
// GetPullRequests returns a repository's pull requests with retry
-func (d *RetryDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, error) {
+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, err = d.Downloader.GetPullRequests(page, perPage); err == nil {
- return prs, nil
+ if prs, isEnd, err = d.Downloader.GetPullRequests(page, perPage); err == nil {
+ return prs, isEnd, nil
}
select {
case <-d.ctx.Done():
- return nil, d.ctx.Err()
+ return nil, false, d.ctx.Err()
case <-time.After(time.Second * time.Duration(d.RetryDelay)):
}
}
- return nil, err
+ return nil, false, err
}
// GetReviews returns pull requests reviews
diff --git a/modules/migrations/base/issue.go b/modules/migrations/base/issue.go
index 4e2bf25f17..b9625a23f6 100644
--- a/modules/migrations/base/issue.go
+++ b/modules/migrations/base/issue.go
@@ -23,4 +23,5 @@ type Issue struct {
Closed *time.Time
Labels []*Label
Reactions []*Reaction
+ Assignees []string
}
diff --git a/modules/migrations/base/pullrequest.go b/modules/migrations/base/pullrequest.go
index 964512e137..ee612fbb8e 100644
--- a/modules/migrations/base/pullrequest.go
+++ b/modules/migrations/base/pullrequest.go
@@ -31,7 +31,6 @@ type PullRequest struct {
MergeCommitSHA string
Head PullRequestBranch
Base PullRequestBranch
- Assignee string
Assignees []string
IsLocked bool
Reactions []*Reaction
diff --git a/modules/migrations/base/release.go b/modules/migrations/base/release.go
index 2a223920c7..c9b26ab1da 100644
--- a/modules/migrations/base/release.go
+++ b/modules/migrations/base/release.go
@@ -15,6 +15,7 @@ type ReleaseAsset struct {
DownloadCount *int
Created time.Time
Updated time.Time
+ DownloadURL *string
}
// Release represents a release
diff --git a/modules/migrations/base/repo.go b/modules/migrations/base/repo.go
index d2052da90d..d26a911854 100644
--- a/modules/migrations/base/repo.go
+++ b/modules/migrations/base/repo.go
@@ -12,8 +12,6 @@ type Repository struct {
IsPrivate bool
IsMirror bool
Description string
- AuthUsername string
- AuthPassword string
CloneURL string
OriginalURL string
DefaultBranch string
diff --git a/modules/migrations/base/review.go b/modules/migrations/base/review.go
index 8051fed653..0a9d03dae9 100644
--- a/modules/migrations/base/review.go
+++ b/modules/migrations/base/review.go
@@ -36,6 +36,7 @@ type ReviewComment struct {
TreePath string
DiffHunk string
Position int
+ Line int
CommitID string
PosterID int64
Reactions []*Reaction
diff --git a/modules/migrations/git.go b/modules/migrations/git.go
index 5c9acb2533..0aad8dbef5 100644
--- a/modules/migrations/git.go
+++ b/modules/migrations/git.go
@@ -66,7 +66,7 @@ func (g *PlainGitDownloader) GetReleases() ([]*base.Release, error) {
}
// GetAsset returns an asset
-func (g *PlainGitDownloader) GetAsset(_ string, _ int64) (io.ReadCloser, error) {
+func (g *PlainGitDownloader) GetAsset(_ string, _, _ int64) (io.ReadCloser, error) {
return nil, ErrNotSupported
}
@@ -81,8 +81,8 @@ func (g *PlainGitDownloader) GetComments(issueNumber int64) ([]*base.Comment, er
}
// GetPullRequests returns pull requests according page and perPage
-func (g *PlainGitDownloader) GetPullRequests(start, limit int) ([]*base.PullRequest, error) {
- return nil, ErrNotSupported
+func (g *PlainGitDownloader) GetPullRequests(start, limit int) ([]*base.PullRequest, bool, error) {
+ return nil, false, ErrNotSupported
}
// GetReviews returns reviews according issue number
diff --git a/modules/migrations/gitea_downloader.go b/modules/migrations/gitea_downloader.go
new file mode 100644
index 0000000000..827cbef5c2
--- /dev/null
+++ b/modules/migrations/gitea_downloader.go
@@ -0,0 +1,671 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "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"
+
+ gitea_sdk "code.gitea.io/sdk/gitea"
+)
+
+var (
+ _ base.Downloader = &GiteaDownloader{}
+ _ base.DownloaderFactory = &GiteaDownloaderFactory{}
+)
+
+func init() {
+ RegisterDownloaderFactory(&GiteaDownloaderFactory{})
+}
+
+// GiteaDownloaderFactory defines a gitea downloader factory
+type GiteaDownloaderFactory struct {
+}
+
+// New returns a Downloader related to this factory according MigrateOptions
+func (f *GiteaDownloaderFactory) New(ctx context.Context, opts base.MigrateOptions) (base.Downloader, error) {
+ u, err := url.Parse(opts.CloneAddr)
+ if err != nil {
+ return nil, err
+ }
+
+ baseURL := u.Scheme + "://" + u.Host
+ repoNameSpace := strings.TrimPrefix(u.Path, "/")
+ repoNameSpace = strings.TrimSuffix(repoNameSpace, ".git")
+
+ path := strings.Split(repoNameSpace, "/")
+ if len(path) < 2 {
+ return nil, fmt.Errorf("invalid path")
+ }
+
+ repoPath := strings.Join(path[len(path)-2:], "/")
+ if len(path) > 2 {
+ subPath := strings.Join(path[:len(path)-2], "/")
+ baseURL += "/" + subPath
+ }
+
+ log.Trace("Create gitea downloader. BaseURL: %s RepoName: %s", baseURL, repoNameSpace)
+
+ return NewGiteaDownloader(ctx, baseURL, repoPath, opts.AuthUsername, opts.AuthPassword, opts.AuthToken)
+}
+
+// GitServiceType returns the type of git service
+func (f *GiteaDownloaderFactory) GitServiceType() structs.GitServiceType {
+ return structs.GiteaService
+}
+
+// GiteaDownloader implements a Downloader interface to get repository information's
+type GiteaDownloader struct {
+ ctx context.Context
+ client *gitea_sdk.Client
+ repoOwner string
+ repoName string
+ pagination bool
+ maxPerPage int
+}
+
+// NewGiteaDownloader creates a gitea Downloader via gitea API
+// Use either a username/password or personal token. token is preferred
+// Note: Public access only allows very basic access
+func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, password, token string) (*GiteaDownloader, error) {
+ giteaClient, err := gitea_sdk.NewClient(
+ baseURL,
+ gitea_sdk.SetToken(token),
+ gitea_sdk.SetBasicAuth(username, password),
+ gitea_sdk.SetContext(ctx),
+ )
+ if err != nil {
+ log.Error(fmt.Sprintf("NewGiteaDownloader: %s", err.Error()))
+ return nil, err
+ }
+
+ path := strings.Split(repoPath, "/")
+
+ paginationSupport := true
+ if err := giteaClient.CheckServerVersionConstraint(">=1.12"); err != nil {
+ paginationSupport = false
+ }
+
+ // set small maxPerPage since we can only guess
+ // (default would be 50 but this can differ)
+ maxPerPage := 10
+ // new gitea instances can tell us what maximum they have
+ if giteaClient.CheckServerVersionConstraint(">=1.13.0") == nil {
+ apiConf, _, err := giteaClient.GetGlobalAPISettings()
+ if err != nil {
+ return nil, err
+ }
+ maxPerPage = apiConf.MaxResponseItems
+ }
+
+ return &GiteaDownloader{
+ ctx: ctx,
+ client: giteaClient,
+ repoOwner: path[0],
+ repoName: path[1],
+ pagination: paginationSupport,
+ maxPerPage: maxPerPage,
+ }, nil
+}
+
+// SetContext set context
+func (g *GiteaDownloader) SetContext(ctx context.Context) {
+ g.ctx = ctx
+}
+
+// GetRepoInfo returns a repository information
+func (g *GiteaDownloader) GetRepoInfo() (*base.Repository, error) {
+ if g == nil {
+ return nil, errors.New("error: GiteaDownloader is nil")
+ }
+
+ repo, _, err := g.client.GetRepo(g.repoOwner, g.repoName)
+ if err != nil {
+ return nil, err
+ }
+
+ return &base.Repository{
+ Name: repo.Name,
+ Owner: repo.Owner.UserName,
+ IsPrivate: repo.Private,
+ Description: repo.Description,
+ CloneURL: repo.CloneURL,
+ OriginalURL: repo.HTMLURL,
+ DefaultBranch: repo.DefaultBranch,
+ }, nil
+}
+
+// GetTopics return gitea topics
+func (g *GiteaDownloader) GetTopics() ([]string, error) {
+ topics, _, err := g.client.ListRepoTopics(g.repoOwner, g.repoName, gitea_sdk.ListRepoTopicsOptions{})
+ return topics, err
+}
+
+// GetMilestones returns milestones
+func (g *GiteaDownloader) GetMilestones() ([]*base.Milestone, error) {
+ var milestones = make([]*base.Milestone, 0, g.maxPerPage)
+
+ for i := 1; ; i++ {
+ // make sure gitea can shutdown gracefully
+ select {
+ case <-g.ctx.Done():
+ return nil, nil
+ default:
+ }
+
+ ms, _, err := g.client.ListRepoMilestones(g.repoOwner, g.repoName, gitea_sdk.ListMilestoneOption{
+ ListOptions: gitea_sdk.ListOptions{
+ PageSize: g.maxPerPage,
+ Page: i,
+ },
+ State: gitea_sdk.StateAll,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ for i := range ms {
+ // old gitea instances dont have this information
+ createdAT := time.Now()
+ var updatedAT *time.Time
+ if ms[i].Closed != nil {
+ createdAT = *ms[i].Closed
+ updatedAT = ms[i].Closed
+ }
+
+ // new gitea instances (>=1.13) do
+ if !ms[i].Created.IsZero() {
+ createdAT = ms[i].Created
+ }
+ if ms[i].Updated != nil && !ms[i].Updated.IsZero() {
+ updatedAT = ms[i].Updated
+ }
+
+ milestones = append(milestones, &base.Milestone{
+ Title: ms[i].Title,
+ Description: ms[i].Description,
+ Deadline: ms[i].Deadline,
+ Created: createdAT,
+ Updated: updatedAT,
+ Closed: ms[i].Closed,
+ State: string(ms[i].State),
+ })
+ }
+ if !g.pagination || len(ms) < g.maxPerPage {
+ break
+ }
+ }
+ return milestones, nil
+}
+
+func (g *GiteaDownloader) convertGiteaLabel(label *gitea_sdk.Label) *base.Label {
+ return &base.Label{
+ Name: label.Name,
+ Color: label.Color,
+ Description: label.Description,
+ }
+}
+
+// GetLabels returns labels
+func (g *GiteaDownloader) GetLabels() ([]*base.Label, error) {
+ var labels = make([]*base.Label, 0, g.maxPerPage)
+
+ for i := 1; ; i++ {
+ // make sure gitea can shutdown gracefully
+ select {
+ case <-g.ctx.Done():
+ return nil, nil
+ default:
+ }
+
+ ls, _, err := g.client.ListRepoLabels(g.repoOwner, g.repoName, gitea_sdk.ListLabelsOptions{ListOptions: gitea_sdk.ListOptions{
+ PageSize: g.maxPerPage,
+ Page: i,
+ }})
+ if err != nil {
+ return nil, err
+ }
+
+ for i := range ls {
+ labels = append(labels, g.convertGiteaLabel(ls[i]))
+ }
+ if !g.pagination || len(ls) < g.maxPerPage {
+ break
+ }
+ }
+ return labels, nil
+}
+
+func (g *GiteaDownloader) convertGiteaRelease(rel *gitea_sdk.Release) *base.Release {
+ r := &base.Release{
+ TagName: rel.TagName,
+ TargetCommitish: rel.Target,
+ Name: rel.Title,
+ Body: rel.Note,
+ Draft: rel.IsDraft,
+ Prerelease: rel.IsPrerelease,
+ PublisherID: rel.Publisher.ID,
+ PublisherName: rel.Publisher.UserName,
+ PublisherEmail: rel.Publisher.Email,
+ Published: rel.PublishedAt,
+ Created: rel.CreatedAt,
+ }
+
+ for _, asset := range rel.Attachments {
+ size := int(asset.Size)
+ dlCount := int(asset.DownloadCount)
+ r.Assets = append(r.Assets, base.ReleaseAsset{
+ ID: asset.ID,
+ Name: asset.Name,
+ Size: &size,
+ DownloadCount: &dlCount,
+ Created: asset.Created,
+ DownloadURL: &asset.DownloadURL,
+ })
+ }
+ return r
+}
+
+// GetReleases returns releases
+func (g *GiteaDownloader) GetReleases() ([]*base.Release, error) {
+ var releases = make([]*base.Release, 0, g.maxPerPage)
+
+ for i := 1; ; i++ {
+ // make sure gitea can shutdown gracefully
+ select {
+ case <-g.ctx.Done():
+ return nil, nil
+ default:
+ }
+
+ rl, _, err := g.client.ListReleases(g.repoOwner, g.repoName, gitea_sdk.ListReleasesOptions{ListOptions: gitea_sdk.ListOptions{
+ PageSize: g.maxPerPage,
+ Page: i,
+ }})
+ if err != nil {
+ return nil, err
+ }
+
+ for i := range rl {
+ releases = append(releases, g.convertGiteaRelease(rl[i]))
+ }
+ if !g.pagination || len(rl) < g.maxPerPage {
+ break
+ }
+ }
+ return releases, nil
+}
+
+// GetAsset returns an asset
+func (g *GiteaDownloader) GetAsset(_ string, relID, id int64) (io.ReadCloser, error) {
+ asset, _, err := g.client.GetReleaseAttachment(g.repoOwner, g.repoName, relID, id)
+ if err != nil {
+ return nil, err
+ }
+ resp, err := http.Get(asset.DownloadURL)
+ if err != nil {
+ return nil, err
+ }
+
+ // resp.Body is closed by the uploader
+ return resp.Body, nil
+}
+
+func (g *GiteaDownloader) getIssueReactions(index int64) ([]*base.Reaction, error) {
+ var reactions []*base.Reaction
+ if err := g.client.CheckServerVersionConstraint(">=1.11"); err != nil {
+ log.Info("GiteaDownloader: instance to old, skip getIssueReactions")
+ return reactions, nil
+ }
+ rl, _, err := g.client.GetIssueReactions(g.repoOwner, g.repoName, index)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, reaction := range rl {
+ reactions = append(reactions, &base.Reaction{
+ UserID: reaction.User.ID,
+ UserName: reaction.User.UserName,
+ Content: reaction.Reaction,
+ })
+ }
+ return reactions, nil
+}
+
+func (g *GiteaDownloader) getCommentReactions(commentID int64) ([]*base.Reaction, error) {
+ var reactions []*base.Reaction
+ if err := g.client.CheckServerVersionConstraint(">=1.11"); err != nil {
+ log.Info("GiteaDownloader: instance to old, skip getCommentReactions")
+ return reactions, nil
+ }
+ rl, _, err := g.client.GetIssueCommentReactions(g.repoOwner, g.repoName, commentID)
+ if err != nil {
+ return nil, err
+ }
+
+ for i := range rl {
+ reactions = append(reactions, &base.Reaction{
+ UserID: rl[i].User.ID,
+ UserName: rl[i].User.UserName,
+ Content: rl[i].Reaction,
+ })
+ }
+ return reactions, nil
+}
+
+// GetIssues returns issues according start and limit
+func (g *GiteaDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) {
+ if perPage > g.maxPerPage {
+ perPage = g.maxPerPage
+ }
+ var allIssues = make([]*base.Issue, 0, perPage)
+
+ issues, _, err := g.client.ListRepoIssues(g.repoOwner, g.repoName, gitea_sdk.ListIssueOption{
+ ListOptions: gitea_sdk.ListOptions{Page: page, PageSize: perPage},
+ State: gitea_sdk.StateAll,
+ Type: gitea_sdk.IssueTypeIssue,
+ })
+ if err != nil {
+ return nil, false, fmt.Errorf("error while listing issues: %v", err)
+ }
+ for _, issue := range issues {
+
+ var labels = make([]*base.Label, 0, len(issue.Labels))
+ for i := range issue.Labels {
+ labels = append(labels, g.convertGiteaLabel(issue.Labels[i]))
+ }
+
+ var milestone string
+ if issue.Milestone != nil {
+ milestone = issue.Milestone.Title
+ }
+
+ reactions, err := g.getIssueReactions(issue.Index)
+ if err != nil {
+ return nil, false, fmt.Errorf("error while loading reactions: %v", err)
+ }
+
+ var assignees []string
+ for i := range issue.Assignees {
+ assignees = append(assignees, issue.Assignees[i].UserName)
+ }
+
+ allIssues = append(allIssues, &base.Issue{
+ Title: issue.Title,
+ Number: issue.Index,
+ PosterID: issue.Poster.ID,
+ PosterName: issue.Poster.UserName,
+ PosterEmail: issue.Poster.Email,
+ Content: issue.Body,
+ Milestone: milestone,
+ State: string(issue.State),
+ Created: issue.Created,
+ Updated: issue.Updated,
+ Closed: issue.Closed,
+ Reactions: reactions,
+ Labels: labels,
+ Assignees: assignees,
+ IsLocked: issue.IsLocked,
+ })
+ }
+
+ isEnd := len(issues) < perPage
+ if !g.pagination {
+ isEnd = len(issues) == 0
+ }
+ return allIssues, isEnd, nil
+}
+
+// GetComments returns comments according issueNumber
+func (g *GiteaDownloader) GetComments(index int64) ([]*base.Comment, error) {
+ var allComments = make([]*base.Comment, 0, g.maxPerPage)
+
+ // for i := 1; ; i++ {
+ // make sure gitea can shutdown gracefully
+ select {
+ case <-g.ctx.Done():
+ return nil, nil
+ default:
+ }
+
+ comments, _, err := g.client.ListIssueComments(g.repoOwner, g.repoName, index, gitea_sdk.ListIssueCommentOptions{ListOptions: gitea_sdk.ListOptions{
+ // PageSize: g.maxPerPage,
+ // Page: i,
+ }})
+ if err != nil {
+ return nil, fmt.Errorf("error while listing comments: %v", err)
+ }
+
+ for _, comment := range comments {
+ reactions, err := g.getCommentReactions(comment.ID)
+ if err != nil {
+ return nil, fmt.Errorf("error while listing comment creactions: %v", err)
+ }
+
+ allComments = append(allComments, &base.Comment{
+ IssueIndex: index,
+ PosterID: comment.Poster.ID,
+ PosterName: comment.Poster.UserName,
+ PosterEmail: comment.Poster.Email,
+ Content: comment.Body,
+ Created: comment.Created,
+ Updated: comment.Updated,
+ Reactions: reactions,
+ })
+ }
+
+ // TODO enable pagination vor (gitea >= 1.14) when it got implemented
+ // if !g.pagination || len(comments) < g.maxPerPage {
+ // break
+ // }
+ //}
+ return allComments, nil
+}
+
+// GetPullRequests returns pull requests according page and perPage
+func (g *GiteaDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) {
+ if perPage > g.maxPerPage {
+ perPage = g.maxPerPage
+ }
+ var allPRs = make([]*base.PullRequest, 0, perPage)
+
+ prs, _, err := g.client.ListRepoPullRequests(g.repoOwner, g.repoName, gitea_sdk.ListPullRequestsOptions{
+ ListOptions: gitea_sdk.ListOptions{
+ Page: page,
+ PageSize: perPage,
+ },
+ State: gitea_sdk.StateAll,
+ })
+ if err != nil {
+ return nil, false, fmt.Errorf("error while listing repos: %v", err)
+ }
+ for _, pr := range prs {
+ var milestone string
+ if pr.Milestone != nil {
+ milestone = pr.Milestone.Title
+ }
+
+ var labels = make([]*base.Label, 0, len(pr.Labels))
+ for i := range pr.Labels {
+ labels = append(labels, g.convertGiteaLabel(pr.Labels[i]))
+ }
+
+ var (
+ headUserName string
+ headRepoName string
+ headCloneURL string
+ headRef string
+ headSHA string
+ )
+ if pr.Head != nil {
+ if pr.Head.Repository != nil {
+ headUserName = pr.Head.Repository.Owner.UserName
+ headRepoName = pr.Head.Repository.Name
+ headCloneURL = pr.Head.Repository.CloneURL
+ }
+ headSHA = pr.Head.Sha
+ headRef = pr.Head.Ref
+ if headSHA == "" {
+ headCommit, _, err := g.client.GetSingleCommit(g.repoOwner, g.repoName, url.PathEscape(pr.Head.Ref))
+ if err != nil {
+ return nil, false, fmt.Errorf("error while resolving git ref: %v", err)
+ }
+ headSHA = headCommit.SHA
+ }
+ }
+
+ var mergeCommitSHA string
+ if pr.MergedCommitID != nil {
+ mergeCommitSHA = *pr.MergedCommitID
+ }
+
+ reactions, err := g.getIssueReactions(pr.Index)
+ if err != nil {
+ return nil, false, fmt.Errorf("error while loading reactions: %v", err)
+ }
+
+ var assignees []string
+ for i := range pr.Assignees {
+ assignees = append(assignees, pr.Assignees[i].UserName)
+ }
+
+ createdAt := time.Now()
+ if pr.Created != nil {
+ createdAt = *pr.Created
+ }
+ updatedAt := time.Now()
+ if pr.Created != nil {
+ updatedAt = *pr.Updated
+ }
+
+ closedAt := pr.Closed
+ if pr.Merged != nil && closedAt == nil {
+ closedAt = pr.Merged
+ }
+
+ allPRs = append(allPRs, &base.PullRequest{
+ Title: pr.Title,
+ Number: pr.Index,
+ PosterID: pr.Poster.ID,
+ PosterName: pr.Poster.UserName,
+ PosterEmail: pr.Poster.Email,
+ Content: pr.Body,
+ State: string(pr.State),
+ Created: createdAt,
+ Updated: updatedAt,
+ Closed: closedAt,
+ Labels: labels,
+ Milestone: milestone,
+ Reactions: reactions,
+ Assignees: assignees,
+ Merged: pr.HasMerged,
+ MergedTime: pr.Merged,
+ MergeCommitSHA: mergeCommitSHA,
+ IsLocked: pr.IsLocked,
+ PatchURL: pr.PatchURL,
+ Head: base.PullRequestBranch{
+ Ref: headRef,
+ SHA: headSHA,
+ RepoName: headRepoName,
+ OwnerName: headUserName,
+ CloneURL: headCloneURL,
+ },
+ Base: base.PullRequestBranch{
+ Ref: pr.Base.Ref,
+ SHA: pr.Base.Sha,
+ RepoName: g.repoName,
+ OwnerName: g.repoOwner,
+ },
+ })
+ }
+
+ isEnd := len(prs) < perPage
+ if !g.pagination {
+ isEnd = len(prs) == 0
+ }
+ return allPRs, isEnd, nil
+}
+
+// GetReviews returns pull requests review
+func (g *GiteaDownloader) GetReviews(index int64) ([]*base.Review, error) {
+ if err := g.client.CheckServerVersionConstraint(">=1.12"); err != nil {
+ log.Info("GiteaDownloader: instance to old, skip GetReviews")
+ return nil, nil
+ }
+
+ var allReviews = make([]*base.Review, 0, g.maxPerPage)
+
+ for i := 1; ; i++ {
+ // make sure gitea can shutdown gracefully
+ select {
+ case <-g.ctx.Done():
+ return nil, nil
+ default:
+ }
+
+ prl, _, err := g.client.ListPullReviews(g.repoOwner, g.repoName, index, gitea_sdk.ListPullReviewsOptions{ListOptions: gitea_sdk.ListOptions{
+ Page: i,
+ PageSize: g.maxPerPage,
+ }})
+ if err != nil {
+ return nil, err
+ }
+
+ for _, pr := range prl {
+
+ rcl, _, err := g.client.ListPullReviewComments(g.repoOwner, g.repoName, index, pr.ID)
+ if err != nil {
+ return nil, err
+ }
+ var reviewComments []*base.ReviewComment
+ for i := range rcl {
+ line := int(rcl[i].LineNum)
+ if rcl[i].OldLineNum > 0 {
+ line = int(rcl[i].OldLineNum) * -1
+ }
+
+ reviewComments = append(reviewComments, &base.ReviewComment{
+ ID: rcl[i].ID,
+ Content: rcl[i].Body,
+ TreePath: rcl[i].Path,
+ DiffHunk: rcl[i].DiffHunk,
+ Line: line,
+ CommitID: rcl[i].CommitID,
+ PosterID: rcl[i].Reviewer.ID,
+ CreatedAt: rcl[i].Created,
+ UpdatedAt: rcl[i].Updated,
+ })
+ }
+
+ allReviews = append(allReviews, &base.Review{
+ ID: pr.ID,
+ IssueIndex: index,
+ ReviewerID: pr.Reviewer.ID,
+ ReviewerName: pr.Reviewer.UserName,
+ Official: pr.Official,
+ CommitID: pr.CommitID,
+ Content: pr.Body,
+ CreatedAt: pr.Submitted,
+ State: string(pr.State),
+ Comments: reviewComments,
+ })
+ }
+
+ if len(prl) < g.maxPerPage {
+ break
+ }
+ }
+ return allReviews, nil
+}
diff --git a/modules/migrations/gitea_downloader_test.go b/modules/migrations/gitea_downloader_test.go
new file mode 100644
index 0000000000..c52c1225f4
--- /dev/null
+++ b/modules/migrations/gitea_downloader_test.go
@@ -0,0 +1,365 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package migrations
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "os"
+ "sort"
+ "testing"
+ "time"
+
+ "code.gitea.io/gitea/modules/migrations/base"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func assertEqualIssue(t *testing.T, issueExp, issueGet *base.Issue) {
+ assert.EqualValues(t, issueExp.Number, issueGet.Number)
+ assert.EqualValues(t, issueExp.Title, issueGet.Title)
+ assert.EqualValues(t, issueExp.Content, issueGet.Content)
+ assert.EqualValues(t, issueExp.Milestone, issueGet.Milestone)
+ assert.EqualValues(t, issueExp.PosterID, issueGet.PosterID)
+ assert.EqualValues(t, issueExp.PosterName, issueGet.PosterName)
+ assert.EqualValues(t, issueExp.PosterEmail, issueGet.PosterEmail)
+ assert.EqualValues(t, issueExp.IsLocked, issueGet.IsLocked)
+ assert.EqualValues(t, issueExp.Created.Unix(), issueGet.Created.Unix())
+ assert.EqualValues(t, issueExp.Updated.Unix(), issueGet.Updated.Unix())
+ if issueExp.Closed != nil {
+ assert.EqualValues(t, issueExp.Closed.Unix(), issueGet.Closed.Unix())
+ } else {
+ assert.True(t, issueGet.Closed == nil)
+ }
+ sort.Strings(issueExp.Assignees)
+ sort.Strings(issueGet.Assignees)
+ assert.EqualValues(t, issueExp.Assignees, issueGet.Assignees)
+ assert.EqualValues(t, issueExp.Labels, issueGet.Labels)
+ assert.EqualValues(t, issueExp.Reactions, issueGet.Reactions)
+}
+
+func TestGiteaDownloadRepo(t *testing.T) {
+ // Skip tests if Gitea token is not found
+ giteaToken := os.Getenv("GITEA_TOKEN")
+ if giteaToken == "" {
+ t.Skip("skipped test because GITEA_TOKEN was not in the environment")
+ }
+
+ resp, err := http.Get("https://gitea.com/gitea")
+ if err != nil || resp.StatusCode != 200 {
+ t.Skipf("Can't reach https://gitea.com, skipping %s", t.Name())
+ }
+
+ downloader, err := NewGiteaDownloader(context.Background(), "https://gitea.com", "gitea/test_repo", "", "", giteaToken)
+ if downloader == nil {
+ t.Fatal("NewGitlabDownloader is nil")
+ }
+ if !assert.NoError(t, err) {
+ t.Fatal("NewGitlabDownloader error occur")
+ }
+
+ repo, err := downloader.GetRepoInfo()
+ assert.NoError(t, err)
+ assert.EqualValues(t, &base.Repository{
+ Name: "test_repo",
+ Owner: "gitea",
+ IsPrivate: false,
+ Description: "Test repository for testing migration from gitea to gitea",
+ CloneURL: "https://gitea.com/gitea/test_repo.git",
+ OriginalURL: "https://gitea.com/gitea/test_repo",
+ DefaultBranch: "master",
+ }, repo)
+
+ topics, err := downloader.GetTopics()
+ assert.NoError(t, err)
+ sort.Strings(topics)
+ assert.EqualValues(t, []string{"ci", "gitea", "migration", "test"}, topics)
+
+ labels, err := downloader.GetLabels()
+ assert.NoError(t, err)
+ assert.Len(t, labels, 6)
+ for _, l := range labels {
+ switch l.Name {
+ case "Bug":
+ assertLabelEqual(t, "Bug", "e11d21", "", l)
+ case "documentation":
+ assertLabelEqual(t, "Enhancement", "207de5", "", l)
+ case "confirmed":
+ assertLabelEqual(t, "Feature", "0052cc", "a feature request", l)
+ case "enhancement":
+ assertLabelEqual(t, "Invalid", "d4c5f9", "", l)
+ case "critical":
+ assertLabelEqual(t, "Question", "fbca04", "", l)
+ case "discussion":
+ assertLabelEqual(t, "Valid", "53e917", "", l)
+ default:
+ assert.Error(t, fmt.Errorf("unexpected label: %s", l.Name))
+ }
+ }
+
+ milestones, err := downloader.GetMilestones()
+ assert.NoError(t, err)
+ assert.Len(t, milestones, 2)
+
+ for _, milestone := range milestones {
+ switch milestone.Title {
+ case "V1":
+ assert.EqualValues(t, "Generate Content", milestone.Description)
+ // assert.EqualValues(t, "ToDo", milestone.Created)
+ // assert.EqualValues(t, "ToDo", milestone.Updated)
+ assert.EqualValues(t, 1598985406, milestone.Closed.Unix())
+ assert.True(t, milestone.Deadline == nil)
+ assert.EqualValues(t, "closed", milestone.State)
+ case "V2 Finalize":
+ assert.EqualValues(t, "", milestone.Description)
+ // assert.EqualValues(t, "ToDo", milestone.Created)
+ // assert.EqualValues(t, "ToDo", milestone.Updated)
+ assert.True(t, milestone.Closed == nil)
+ assert.EqualValues(t, 1599263999, milestone.Deadline.Unix())
+ assert.EqualValues(t, "open", milestone.State)
+ default:
+ assert.Error(t, fmt.Errorf("unexpected milestone: %s", milestone.Title))
+ }
+ }
+
+ releases, err := downloader.GetReleases()
+ assert.NoError(t, err)
+ assert.EqualValues(t, []*base.Release{
+ {
+ Name: "Second Release",
+ TagName: "v2-rc1",
+ TargetCommitish: "master",
+ Body: "this repo has:\r\n* reactions\r\n* wiki\r\n* issues (open/closed)\r\n* pulls (open/closed/merged) (external/internal)\r\n* pull reviews\r\n* projects\r\n* milestones\r\n* labels\r\n* releases\r\n\r\nto test migration against",
+ Draft: false,
+ Prerelease: true,
+ Created: time.Date(2020, 9, 1, 18, 2, 43, 0, time.UTC),
+ Published: time.Date(2020, 9, 1, 18, 2, 43, 0, time.UTC),
+ PublisherID: 689,
+ PublisherName: "6543",
+ PublisherEmail: "6543@noreply.gitea.io",
+ },
+ {
+ Name: "First Release",
+ TagName: "V1",
+ TargetCommitish: "master",
+ Body: "as title",
+ Draft: false,
+ Prerelease: false,
+ Created: time.Date(2020, 9, 1, 17, 30, 32, 0, time.UTC),
+ Published: time.Date(2020, 9, 1, 17, 30, 32, 0, time.UTC),
+ PublisherID: 689,
+ PublisherName: "6543",
+ PublisherEmail: "6543@noreply.gitea.io",
+ },
+ }, releases)
+
+ issues, isEnd, err := downloader.GetIssues(1, 50)
+ assert.NoError(t, err)
+ assert.EqualValues(t, 7, len(issues))
+ assert.True(t, isEnd)
+ assert.EqualValues(t, "open", issues[0].State)
+
+ issues, isEnd, err = downloader.GetIssues(3, 2)
+ assert.NoError(t, err)
+ assert.EqualValues(t, 2, len(issues))
+ assert.False(t, isEnd)
+
+ var (
+ closed4 = time.Date(2020, 9, 1, 15, 49, 34, 0, time.UTC)
+ closed2 = time.Unix(1598969497, 0)
+ )
+
+ assertEqualIssue(t, &base.Issue{
+ Number: 4,
+ Title: "what is this repo about?",
+ Content: "",
+ Milestone: "V1",
+ PosterID: -1,
+ PosterName: "Ghost",
+ PosterEmail: "",
+ State: "closed",
+ IsLocked: true,
+ Created: time.Unix(1598975321, 0),
+ Updated: time.Unix(1598975400, 0),
+ Labels: []*base.Label{{
+ Name: "Question",
+ Color: "fbca04",
+ Description: "",
+ }},
+ Reactions: []*base.Reaction{
+ {
+ UserID: 689,
+ UserName: "6543",
+ Content: "gitea",
+ },
+ {
+ UserID: 689,
+ UserName: "6543",
+ Content: "laugh",
+ },
+ },
+ Closed: &closed4,
+ }, issues[0])
+ assertEqualIssue(t, &base.Issue{
+ Number: 2,
+ Title: "Spam",
+ Content: ":(",
+ Milestone: "",
+ PosterID: 689,
+ PosterName: "6543",
+ PosterEmail: "6543@noreply.gitea.io",
+ State: "closed",
+ IsLocked: false,
+ Created: time.Unix(1598919780, 0),
+ Updated: closed2,
+ Labels: []*base.Label{{
+ Name: "Invalid",
+ Color: "d4c5f9",
+ Description: "",
+ }},
+ Reactions: nil,
+ Closed: &closed2,
+ }, issues[1])
+
+ comments, err := downloader.GetComments(4)
+ assert.NoError(t, err)
+ assert.Len(t, comments, 2)
+ assert.EqualValues(t, 1598975370, comments[0].Created.Unix())
+ assert.EqualValues(t, 1599070865, comments[0].Updated.Unix())
+ assert.EqualValues(t, 1598975393, comments[1].Created.Unix())
+ assert.EqualValues(t, 1598975393, comments[1].Updated.Unix())
+ assert.EqualValues(t, []*base.Comment{
+ {
+ IssueIndex: 4,
+ PosterID: 689,
+ PosterName: "6543",
+ PosterEmail: "6543@noreply.gitea.io",
+ Created: comments[0].Created,
+ Updated: comments[0].Updated,
+ Content: "a really good question!\n\nIt is the used as TESTSET for gitea2gitea repo migration function",
+ },
+ {
+ IssueIndex: 4,
+ PosterID: -1,
+ PosterName: "Ghost",
+ PosterEmail: "",
+ Created: comments[1].Created,
+ Updated: comments[1].Updated,
+ Content: "Oh!",
+ },
+ }, comments)
+
+ prs, isEnd, err := downloader.GetPullRequests(1, 50)
+ assert.NoError(t, err)
+ assert.True(t, isEnd)
+ assert.Len(t, prs, 6)
+ prs, isEnd, err = downloader.GetPullRequests(1, 3)
+ assert.NoError(t, err)
+ assert.False(t, isEnd)
+ assert.Len(t, prs, 3)
+ merged12 := time.Unix(1598982934, 0)
+ assertEqualPulls(t, &base.PullRequest{
+ Number: 12,
+ PosterID: 689,
+ PosterName: "6543",
+ PosterEmail: "6543@noreply.gitea.io",
+ Title: "Dont Touch",
+ Content: "\r\nadd dont touch note",
+ Milestone: "V2 Finalize",
+ State: "closed",
+ IsLocked: false,
+ Created: time.Unix(1598982759, 0),
+ Updated: time.Unix(1599023425, 0),
+ Closed: &merged12,
+ Assignees: []string{"techknowlogick"},
+ Labels: []*base.Label{},
+
+ Base: base.PullRequestBranch{
+ CloneURL: "",
+ Ref: "master",
+ SHA: "827aa28a907853e5ddfa40c8f9bc52471a2685fd",
+ RepoName: "test_repo",
+ OwnerName: "gitea",
+ },
+ Head: base.PullRequestBranch{
+ CloneURL: "https://gitea.com/6543-forks/test_repo.git",
+ Ref: "refs/pull/12/head",
+ SHA: "b6ab5d9ae000b579a5fff03f92c486da4ddf48b6",
+ RepoName: "test_repo",
+ OwnerName: "6543-forks",
+ },
+ Merged: true,
+ MergedTime: &merged12,
+ MergeCommitSHA: "827aa28a907853e5ddfa40c8f9bc52471a2685fd",
+ PatchURL: "https://gitea.com/gitea/test_repo/pulls/12.patch",
+ }, prs[1])
+
+ reviews, err := downloader.GetReviews(7)
+ assert.NoError(t, err)
+ if assert.Len(t, reviews, 3) {
+ assert.EqualValues(t, 689, reviews[0].ReviewerID)
+ assert.EqualValues(t, "6543", reviews[0].ReviewerName)
+ assert.EqualValues(t, "techknowlogick", reviews[1].ReviewerName)
+ assert.EqualValues(t, "techknowlogick", reviews[2].ReviewerName)
+ assert.False(t, reviews[1].Official)
+ assert.EqualValues(t, "I think this needs some changes", reviews[1].Content)
+ assert.EqualValues(t, "REQUEST_CHANGES", reviews[1].State)
+ assert.True(t, reviews[2].Official)
+ assert.EqualValues(t, "looks good", reviews[2].Content)
+ assert.EqualValues(t, "APPROVED", reviews[2].State)
+
+ // TODO: https://github.com/go-gitea/gitea/issues/12846
+ // assert.EqualValues(t, 9, reviews[1].ReviewerID)
+ // assert.EqualValues(t, 9, reviews[2].ReviewerID)
+
+ assert.Len(t, reviews[0].Comments, 1)
+ assert.EqualValues(t, &base.ReviewComment{
+ ID: 116561,
+ InReplyTo: 0,
+ Content: "is one `\\newline` to less?",
+ TreePath: "README.md",
+ DiffHunk: "@@ -2,3 +2,3 @@\n \n-Test repository for testing migration from gitea 2 gitea\n\\ No newline at end of file\n+Test repository for testing migration from gitea 2 gitea",
+ Position: 0,
+ Line: 4,
+ CommitID: "187ece0cb6631e2858a6872e5733433bb3ca3b03",
+ PosterID: 689,
+ Reactions: nil,
+ CreatedAt: time.Date(2020, 9, 1, 16, 12, 58, 0, time.UTC),
+ UpdatedAt: time.Date(2020, 9, 1, 16, 12, 58, 0, time.UTC),
+ }, reviews[0].Comments[0])
+ }
+}
+
+func assertEqualPulls(t *testing.T, pullExp, pullGet *base.PullRequest) {
+ assertEqualIssue(t, pull2issue(pullExp), pull2issue(pullGet))
+ assert.EqualValues(t, 0, pullGet.OriginalNumber)
+ assert.EqualValues(t, pullExp.PatchURL, pullGet.PatchURL)
+ assert.EqualValues(t, pullExp.Merged, pullGet.Merged)
+ assert.EqualValues(t, pullExp.MergedTime.Unix(), pullGet.MergedTime.Unix())
+ assert.EqualValues(t, pullExp.MergeCommitSHA, pullGet.MergeCommitSHA)
+ assert.EqualValues(t, pullExp.Base, pullGet.Base)
+ assert.EqualValues(t, pullExp.Head, pullGet.Head)
+}
+
+func pull2issue(pull *base.PullRequest) *base.Issue {
+ return &base.Issue{
+ Number: pull.Number,
+ PosterID: pull.PosterID,
+ PosterName: pull.PosterName,
+ PosterEmail: pull.PosterEmail,
+ Title: pull.Title,
+ Content: pull.Content,
+ Milestone: pull.Milestone,
+ State: pull.State,
+ IsLocked: pull.IsLocked,
+ Created: pull.Created,
+ Updated: pull.Updated,
+ Closed: pull.Closed,
+ Labels: pull.Labels,
+ Reactions: pull.Reactions,
+ Assignees: pull.Assignees,
+ }
+}
diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea_uploader.go
index d4ba66fd38..cd1fd5cb8d 100644
--- a/modules/migrations/gitea.go
+++ b/modules/migrations/gitea_uploader.go
@@ -273,9 +273,18 @@ func (g *GiteaLocalUploader) CreateReleases(downloader base.Downloader, releases
// download attachment
err = func() error {
- rc, err := downloader.GetAsset(rel.TagName, asset.ID)
- if err != nil {
- return err
+ var rc io.ReadCloser
+ if asset.DownloadURL == nil {
+ rc, err = downloader.GetAsset(rel.TagName, rel.ID, asset.ID)
+ if err != nil {
+ return err
+ }
+ } else {
+ resp, err := http.Get(*asset.DownloadURL)
+ if err != nil {
+ return err
+ }
+ rc = resp.Body
}
_, err = storage.Attachments.Save(attach.RelativePath(), rc)
return err
@@ -779,8 +788,12 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
}
for _, comment := range review.Comments {
- _, _, line, _ := git.ParseDiffHunkString(comment.DiffHunk)
-
+ line := comment.Line
+ if line != 0 {
+ comment.Position = 1
+ } else {
+ _, _, line, _ = git.ParseDiffHunkString(comment.DiffHunk)
+ }
headCommitID, err := g.gitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil {
return fmt.Errorf("GetRefCommitID[%s]: %v", pr.GetGitRefName(), err)
diff --git a/modules/migrations/gitea_test.go b/modules/migrations/gitea_uploader_test.go
index 8432a1eecd..8432a1eecd 100644
--- a/modules/migrations/gitea_test.go
+++ b/modules/migrations/gitea_uploader_test.go
diff --git a/modules/migrations/github.go b/modules/migrations/github.go
index c053596c17..088e54744d 100644
--- a/modules/migrations/github.go
+++ b/modules/migrations/github.go
@@ -329,7 +329,7 @@ func (g *GithubDownloaderV3) GetReleases() ([]*base.Release, error) {
}
// GetAsset returns an asset
-func (g *GithubDownloaderV3) GetAsset(_ string, id int64) (io.ReadCloser, error) {
+func (g *GithubDownloaderV3) GetAsset(_ string, _, id int64) (io.ReadCloser, error) {
asset, redir, err := g.client.Repositories.DownloadReleaseAsset(g.ctx, g.repoOwner, g.repoName, id, http.DefaultClient)
if err != nil {
return nil, err
@@ -496,7 +496,7 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er
}
// GetPullRequests returns pull requests according page and perPage
-func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullRequest, error) {
+func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) {
opt := &github.PullRequestListOptions{
Sort: "created",
Direction: "asc",
@@ -510,7 +510,7 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq
g.sleep()
prs, resp, err := g.client.PullRequests.List(g.ctx, g.repoOwner, g.repoName, opt)
if err != nil {
- return nil, fmt.Errorf("error while listing repos: %v", err)
+ return nil, false, fmt.Errorf("error while listing repos: %v", err)
}
g.rate = &resp.Rate
for _, pr := range prs {
@@ -576,7 +576,7 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq
PerPage: perPage,
})
if err != nil {
- return nil, err
+ return nil, false, err
}
g.rate = &resp.Rate
if len(res) == 0 {
@@ -626,7 +626,7 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq
})
}
- return allPRs, nil
+ return allPRs, len(prs) < perPage, nil
}
func convertGithubReview(r *github.PullRequestReview) *base.Review {
diff --git a/modules/migrations/github_test.go b/modules/migrations/github_test.go
index 3a1affbc2f..efa8b6ba9b 100644
--- a/modules/migrations/github_test.go
+++ b/modules/migrations/github_test.go
@@ -271,7 +271,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
}, comments[:2])
// downloader.GetPullRequests()
- prs, err := downloader.GetPullRequests(1, 2)
+ prs, _, err := downloader.GetPullRequests(1, 2)
assert.NoError(t, err)
assert.EqualValues(t, 2, len(prs))
diff --git a/modules/migrations/gitlab.go b/modules/migrations/gitlab.go
index 379a2f2b60..23cd90c747 100644
--- a/modules/migrations/gitlab.go
+++ b/modules/migrations/gitlab.go
@@ -303,7 +303,7 @@ func (g *GitlabDownloader) GetReleases() ([]*base.Release, error) {
}
// GetAsset returns an asset
-func (g *GitlabDownloader) GetAsset(tag string, id int64) (io.ReadCloser, error) {
+func (g *GitlabDownloader) GetAsset(tag string, _, id int64) (io.ReadCloser, error) {
link, _, err := g.client.ReleaseLinks.GetReleaseLink(g.repoID, tag, int(id), gitlab.WithContext(g.ctx))
if err != nil {
return nil, err
@@ -464,7 +464,7 @@ func (g *GitlabDownloader) GetComments(issueNumber int64) ([]*base.Comment, erro
}
// GetPullRequests returns pull requests according page and perPage
-func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, error) {
+func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) {
opt := &gitlab.ListProjectMergeRequestsOptions{
ListOptions: gitlab.ListOptions{
PerPage: perPage,
@@ -479,7 +479,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
prs, _, err := g.client.MergeRequests.ListProjectMergeRequests(g.repoID, opt, nil, gitlab.WithContext(g.ctx))
if err != nil {
- return nil, fmt.Errorf("error while listing merge requests: %v", err)
+ return nil, false, fmt.Errorf("error while listing merge requests: %v", err)
}
for _, pr := range prs {
@@ -521,7 +521,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
for {
awards, _, err := g.client.AwardEmoji.ListMergeRequestAwardEmoji(g.repoID, pr.IID, &gitlab.ListAwardEmojiOptions{Page: awardPage, PerPage: perPage}, gitlab.WithContext(g.ctx))
if err != nil {
- return nil, fmt.Errorf("error while listing merge requests awards: %v", err)
+ return nil, false, fmt.Errorf("error while listing merge requests awards: %v", err)
}
if len(awards) < perPage {
break
@@ -569,7 +569,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
})
}
- return allPRs, nil
+ return allPRs, len(prs) < perPage, nil
}
// GetReviews returns pull requests review
diff --git a/modules/migrations/gitlab_test.go b/modules/migrations/gitlab_test.go
index 11c3aefeaf..f64d72147c 100644
--- a/modules/migrations/gitlab_test.go
+++ b/modules/migrations/gitlab_test.go
@@ -242,7 +242,7 @@ func TestGitlabDownloadRepo(t *testing.T) {
},
}, comments[:4])
- prs, err := downloader.GetPullRequests(1, 1)
+ prs, _, err := downloader.GetPullRequests(1, 1)
assert.NoError(t, err)
assert.Len(t, prs, 1)
diff --git a/modules/migrations/migrate.go b/modules/migrations/migrate.go
index 8543a3fc09..191f2a5550 100644
--- a/modules/migrations/migrate.go
+++ b/modules/migrations/migrate.go
@@ -229,7 +229,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts
log.Trace("migrating pull requests and comments")
var prBatchSize = uploader.MaxBatchInsertSize("pullrequest")
for i := 1; ; i++ {
- prs, err := downloader.GetPullRequests(i, prBatchSize)
+ prs, isEnd, err := downloader.GetPullRequests(i, prBatchSize)
if err != nil {
return err
}
@@ -300,7 +300,7 @@ func migrateRepository(downloader base.Downloader, uploader base.Uploader, opts
}
}
- if len(prs) < prBatchSize {
+ if isEnd {
break
}
}
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index a8ca823ef6..c12f8e1c18 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -275,5 +275,6 @@ var (
SupportedFullGitService = []GitServiceType{
GithubService,
GitlabService,
+ GiteaService,
}
)