feat: vendor gitea 1.16.2

This commit is contained in:
2026-06-02 08:36:01 +00:00
parent 247cd60f69
commit 54798b4615
2145 changed files with 162965 additions and 126447 deletions
@@ -54,12 +54,12 @@ func TestCodebaseDownloadRepo(t *testing.T) {
assertMilestonesEqual(t, []*base.Milestone{
{
Title: "Milestone1",
Deadline: timePtr(time.Date(2021, time.September, 16, 0, 0, 0, 0, time.UTC)),
Deadline: new(time.Date(2021, time.September, 16, 0, 0, 0, 0, time.UTC)),
},
{
Title: "Milestone2",
Deadline: timePtr(time.Date(2021, time.September, 17, 0, 0, 0, 0, time.UTC)),
Closed: timePtr(time.Date(2021, time.September, 17, 0, 0, 0, 0, time.UTC)),
Deadline: new(time.Date(2021, time.September, 17, 0, 0, 0, 0, time.UTC)),
Closed: new(time.Date(2021, time.September, 17, 0, 0, 0, 0, time.UTC)),
State: "closed",
},
}, milestones)
@@ -14,7 +14,6 @@ import (
"code.gitea.io/gitea/modules/log"
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/codecommit"
@@ -87,7 +86,7 @@ type CodeCommitDownloader struct {
// GetRepoInfo returns a repository information
func (c *CodeCommitDownloader) GetRepoInfo(ctx context.Context) (*base.Repository, error) {
output, err := c.codeCommitClient.GetRepository(ctx, &codecommit.GetRepositoryInput{
RepositoryName: util.ToPointer(c.repoName),
RepositoryName: new(c.repoName),
})
if err != nil {
return nil, err
@@ -119,7 +118,7 @@ func (c *CodeCommitDownloader) GetComments(ctx context.Context, commentable base
for {
resp, err := c.codeCommitClient.GetCommentsForPullRequest(ctx, &codecommit.GetCommentsForPullRequestInput{
NextToken: nextToken,
PullRequestId: util.ToPointer(strconv.FormatInt(commentable.GetForeignIndex(), 10)),
PullRequestId: new(strconv.FormatInt(commentable.GetForeignIndex(), 10)),
})
if err != nil {
return nil, false, err
@@ -161,7 +160,7 @@ func (c *CodeCommitDownloader) GetPullRequests(ctx context.Context, page, perPag
prs := make([]*base.PullRequest, 0, len(batch))
for _, id := range batch {
output, err := c.codeCommitClient.GetPullRequest(ctx, &codecommit.GetPullRequestInput{
PullRequestId: util.ToPointer(id),
PullRequestId: new(id),
})
if err != nil {
return nil, false, err
@@ -241,7 +240,7 @@ func (c *CodeCommitDownloader) getAllPullRequestIDs(ctx context.Context) ([]stri
for {
output, err := c.codeCommitClient.ListPullRequests(ctx, &codecommit.ListPullRequestsInput{
RepositoryName: util.ToPointer(c.repoName),
RepositoryName: new(c.repoName),
NextToken: nextToken,
})
if err != nil {
@@ -288,12 +288,13 @@ func (g *RepositoryDumper) CreateLabels(_ context.Context, labels ...*base.Label
func (g *RepositoryDumper) CreateReleases(_ context.Context, releases ...*base.Release) error {
if g.opts.ReleaseAssets {
for _, release := range releases {
attachDir := filepath.Join("release_assets", release.TagName)
attachDir := filepath.Join("release_assets", uuid.New().String())
if err := os.MkdirAll(filepath.Join(g.baseDir, attachDir), os.ModePerm); err != nil {
return err
}
for _, asset := range release.Assets {
attachLocalPath := filepath.Join(attachDir, asset.Name)
// we cannot use asset.Name because it might contains special characters.
attachLocalPath := filepath.Join(attachDir, uuid.New().String())
// SECURITY: We cannot check the DownloadURL and DownloadFunc are safe here
// ... we must assume that they are safe and simply download the attachment
@@ -306,14 +307,15 @@ func (g *RepositoryDumper) CreateReleases(_ context.Context, releases ...*base.R
if err != nil {
return err
}
defer rc.Close()
} else {
resp, err := http.Get(*asset.DownloadURL)
if err != nil {
return err
}
defer resp.Body.Close()
rc = resp.Body
}
defer rc.Close()
fw, err := os.Create(attachPath)
if err != nil {
@@ -357,6 +359,11 @@ func (g *RepositoryDumper) SyncTags(ctx context.Context) error {
return nil
}
// SyncBranches syncs branches in the database
func (g *RepositoryDumper) SyncBranches(ctx context.Context) error {
return nil
}
// CreateIssues creates issues
func (g *RepositoryDumper) CreateIssues(_ context.Context, issues ...*base.Issue) error {
var err error
@@ -489,7 +496,7 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR
if pr.Head.CloneURL == "" || pr.Head.Ref == "" {
// Set head information if pr.Head.SHA is available
if pr.Head.SHA != "" {
_, _, err = gitcmd.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &gitcmd.RunOpts{Dir: g.gitPath()})
_, _, err = gitcmd.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).WithDir(g.gitPath()).RunStdString(ctx)
if err != nil {
log.Error("PR #%d in %s/%s unable to update-ref for pr HEAD: %v", pr.Number, g.repoOwner, g.repoName, err)
}
@@ -519,7 +526,7 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR
if !ok {
// Set head information if pr.Head.SHA is available
if pr.Head.SHA != "" {
_, _, err = gitcmd.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &gitcmd.RunOpts{Dir: g.gitPath()})
_, _, err = gitcmd.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).WithDir(g.gitPath()).RunStdString(ctx)
if err != nil {
log.Error("PR #%d in %s/%s unable to update-ref for pr HEAD: %v", pr.Number, g.repoOwner, g.repoName, err)
}
@@ -554,7 +561,7 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR
fetchArg = git.BranchPrefix + fetchArg
}
_, _, err = gitcmd.NewCommand("fetch", "--no-tags").AddDashesAndList(remote, fetchArg).RunStdString(ctx, &gitcmd.RunOpts{Dir: g.gitPath()})
_, _, err = gitcmd.NewCommand("fetch", "--no-tags").AddDashesAndList(remote, fetchArg).WithDir(g.gitPath()).RunStdString(ctx)
if err != nil {
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err)
// We need to continue here so that the Head.Ref is reset and we attempt to set the gitref for the PR
@@ -578,7 +585,7 @@ func (g *RepositoryDumper) handlePullRequest(ctx context.Context, pr *base.PullR
pr.Head.SHA = headSha
}
if pr.Head.SHA != "" {
_, _, err = gitcmd.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).RunStdString(ctx, &gitcmd.RunOpts{Dir: g.gitPath()})
_, _, err = gitcmd.NewCommand("update-ref", "--no-deref").AddDynamicArguments(pr.GetGitHeadRefName(), pr.Head.SHA).WithDir(g.gitPath()).RunStdString(ctx)
if err != nil {
log.Error("unable to set %s as the local head for PR #%d from %s in %s/%s. Error: %v", pr.Head.SHA, pr.Number, pr.Head.Ref, g.repoOwner, g.repoName, err)
}
@@ -7,7 +7,7 @@ package migrations
import (
"errors"
"github.com/google/go-github/v74/github"
"github.com/google/go-github/v84/github"
)
// ErrRepoNotCreated returns the error that repository not created
@@ -186,7 +186,7 @@ func (g *GiteaDownloader) GetMilestones(ctx context.Context) ([]*base.Milestone,
}
for i := range ms {
// old gitea instances dont have this information
// old gitea instances don't have this information
createdAT := time.Time{}
var updatedAT *time.Time
if ms[i].Closed != nil {
@@ -345,25 +345,43 @@ func (g *GiteaDownloader) GetReleases(ctx context.Context) ([]*base.Release, err
return releases, nil
}
func (g *GiteaDownloader) getIssueReactions(index int64) ([]*base.Reaction, error) {
var reactions []*base.Reaction
func (g *GiteaDownloader) getIssueReactions(ctx context.Context, index int64) ([]*base.Reaction, error) {
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
return nil, nil
}
for _, reaction := range rl {
reactions = append(reactions, &base.Reaction{
UserID: reaction.User.ID,
UserName: reaction.User.UserName,
Content: reaction.Reaction,
})
allReactions := make([]*base.Reaction, 0, g.maxPerPage)
for i := 1; ; i++ {
// make sure gitea can shutdown gracefully
select {
case <-ctx.Done():
return nil, nil
default:
}
reactions, _, err := g.client.ListIssueReactions(g.repoOwner, g.repoName, index, gitea_sdk.ListIssueReactionsOptions{ListOptions: gitea_sdk.ListOptions{
PageSize: g.maxPerPage,
Page: i,
}})
if err != nil {
return nil, err
}
for _, reaction := range reactions {
allReactions = append(allReactions, &base.Reaction{
UserID: reaction.User.ID,
UserName: reaction.User.UserName,
Content: reaction.Reaction,
})
}
if !g.pagination || len(reactions) < g.maxPerPage {
break
}
}
return reactions, nil
return allReactions, nil
}
func (g *GiteaDownloader) getCommentReactions(commentID int64) ([]*base.Reaction, error) {
@@ -388,7 +406,7 @@ func (g *GiteaDownloader) getCommentReactions(commentID int64) ([]*base.Reaction
}
// GetIssues returns issues according start and limit
func (g *GiteaDownloader) GetIssues(_ context.Context, page, perPage int) ([]*base.Issue, bool, error) {
func (g *GiteaDownloader) GetIssues(ctx context.Context, page, perPage int) ([]*base.Issue, bool, error) {
if perPage > g.maxPerPage {
perPage = g.maxPerPage
}
@@ -413,7 +431,7 @@ func (g *GiteaDownloader) GetIssues(_ context.Context, page, perPage int) ([]*ba
milestone = issue.Milestone.Title
}
reactions, err := g.getIssueReactions(issue.Index)
reactions, err := g.getIssueReactions(ctx, issue.Index)
if err != nil {
WarnAndNotice("Unable to load reactions during migrating issue #%d in %s. Error: %v", issue.Index, g, err)
}
@@ -497,7 +515,7 @@ func (g *GiteaDownloader) GetComments(ctx context.Context, commentable base.Comm
}
// GetPullRequests returns pull requests according page and perPage
func (g *GiteaDownloader) GetPullRequests(_ context.Context, page, perPage int) ([]*base.PullRequest, bool, error) {
func (g *GiteaDownloader) GetPullRequests(ctx context.Context, page, perPage int) ([]*base.PullRequest, bool, error) {
if perPage > g.maxPerPage {
perPage = g.maxPerPage
}
@@ -546,7 +564,7 @@ func (g *GiteaDownloader) GetPullRequests(_ context.Context, page, perPage int)
mergeCommitSHA = *pr.MergedCommitID
}
reactions, err := g.getIssueReactions(pr.Index)
reactions, err := g.getIssueReactions(ctx, pr.Index)
if err != nil {
WarnAndNotice("Unable to load reactions during migrating pull #%d in %s. Error: %v", pr.Index, g, err)
}
@@ -17,16 +17,17 @@ import (
)
func TestGiteaDownloadRepo(t *testing.T) {
// Skip tests if Gitea token is not found
giteaToken := os.Getenv("GITEA_TOKEN")
// Skip tests if Gitea token is not found (TODO: this test seems stopped for long time because there is no token in CI secrets)
giteaToken := os.Getenv("GITEA_TEST_OFFICIAL_SITE_TOKEN")
if giteaToken == "" {
t.Skip("skipped test because GITEA_TOKEN was not in the environment")
t.Skip("skipped test because GITEA_TEST_OFFICIAL_SITE_TOKEN was not in the environment")
}
resp, err := http.Get("https://gitea.com/gitea")
if err != nil || resp.StatusCode != http.StatusOK {
t.Skipf("Can't reach https://gitea.com, skipping %s", t.Name())
}
defer resp.Body.Close()
ctx := t.Context()
downloader, err := NewGiteaDownloader(ctx, "https://gitea.com", "gitea/test_repo", "", "", giteaToken)
require.NoError(t, err, "NewGiteaDownloader error occur")
@@ -85,16 +86,16 @@ func TestGiteaDownloadRepo(t *testing.T) {
{
Title: "V2 Finalize",
Created: time.Unix(0, 0),
Deadline: timePtr(time.Unix(1599263999, 0)),
Updated: timePtr(time.Unix(0, 0)),
Deadline: new(time.Unix(1599263999, 0)),
Updated: new(time.Unix(0, 0)),
State: "open",
},
{
Title: "V1",
Description: "Generate Content",
Created: time.Unix(0, 0),
Updated: timePtr(time.Unix(0, 0)),
Closed: timePtr(time.Unix(1598985406, 0)),
Updated: new(time.Unix(0, 0)),
Closed: new(time.Unix(1598985406, 0)),
State: "closed",
},
}, milestones)
@@ -170,7 +171,7 @@ func TestGiteaDownloadRepo(t *testing.T) {
Content: "laugh",
},
},
Closed: timePtr(time.Date(2020, 9, 1, 15, 49, 34, 0, time.UTC)),
Closed: new(time.Date(2020, 9, 1, 15, 49, 34, 0, time.UTC)),
},
{
Number: 2,
@@ -189,7 +190,7 @@ func TestGiteaDownloadRepo(t *testing.T) {
Color: "d4c5f9",
Description: "",
}},
Closed: timePtr(time.Unix(1598969497, 0)),
Closed: new(time.Unix(1598969497, 0)),
},
}, issues)
@@ -236,7 +237,7 @@ func TestGiteaDownloadRepo(t *testing.T) {
IsLocked: false,
Created: time.Unix(1598982759, 0),
Updated: time.Unix(1599023425, 0),
Closed: timePtr(time.Unix(1598982934, 0)),
Closed: new(time.Unix(1598982934, 0)),
Assignees: []string{"techknowlogick"},
Base: base.PullRequestBranch{
CloneURL: "",
@@ -253,7 +254,7 @@ func TestGiteaDownloadRepo(t *testing.T) {
OwnerName: "6543-forks",
},
Merged: true,
MergedTime: timePtr(time.Unix(1598982934, 0)),
MergedTime: new(time.Unix(1598982934, 0)),
MergeCommitSHA: "827aa28a907853e5ddfa40c8f9bc52471a2685fd",
PatchURL: "https://gitea.com/gitea/test_repo/pulls/12.patch",
}, prs[1])
@@ -6,10 +6,9 @@ package migrations
import (
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"time"
@@ -303,7 +302,7 @@ func (g *GiteaLocalUploader) CreateReleases(ctx context.Context, releases ...*ba
return fmt.Errorf("GetTagCommit[%v]: %w", rel.TagName, err)
}
rel.Sha1 = commit.ID.String()
rel.NumCommits, err = commit.CommitsCount()
rel.NumCommits, err = gitrepo.CommitsCountOfCommit(ctx, g.repo, commit.ID.String())
if err != nil {
return fmt.Errorf("CommitsCount: %w", err)
}
@@ -366,7 +365,13 @@ func (g *GiteaLocalUploader) CreateReleases(ctx context.Context, releases ...*ba
// SyncTags syncs releases with tags in the database
func (g *GiteaLocalUploader) SyncTags(ctx context.Context) error {
return repo_module.SyncReleasesWithTags(ctx, g.repo, g.gitRepo)
_, err := repo_module.SyncReleasesWithTags(ctx, g.repo, g.gitRepo)
return err
}
func (g *GiteaLocalUploader) SyncBranches(ctx context.Context) error {
_, _, err := repo_module.SyncRepoBranchesWithRepo(ctx, g.repo, g.gitRepo, g.doer.ID)
return err
}
// CreateIssues creates issues
@@ -585,12 +590,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(ctx context.Context, pr *ba
}
defer ret.Close()
pullDir := filepath.Join(g.repo.RepoPath(), "pulls")
if err = os.MkdirAll(pullDir, os.ModePerm); err != nil {
return err
}
f, err := os.Create(filepath.Join(pullDir, fmt.Sprintf("%d.patch", pr.Number)))
f, err := gitrepo.CreateRepoFile(ctx, g.repo, fmt.Sprintf("pulls/%d.patch", pr.Number))
if err != nil {
return err
}
@@ -664,7 +664,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(ctx context.Context, pr *ba
fetchArg = git.BranchPrefix + fetchArg
}
_, _, err = gitcmd.NewCommand("fetch", "--no-tags").AddDashesAndList(remote, fetchArg).RunStdString(ctx, &gitcmd.RunOpts{Dir: g.repo.RepoPath()})
_, _, err = gitrepo.RunCmdString(ctx, g.repo, gitcmd.NewCommand("fetch", "--no-tags").AddDashesAndList(remote, fetchArg))
if err != nil {
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err)
return head, nil
@@ -699,7 +699,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(ctx context.Context, pr *ba
// The SHA is empty
log.Warn("Empty reference, no pull head for PR #%d in %s/%s", pr.Number, g.repoOwner, g.repoName)
} else {
_, _, err = gitcmd.NewCommand("rev-list", "--quiet", "-1").AddDynamicArguments(pr.Head.SHA).RunStdString(ctx, &gitcmd.RunOpts{Dir: g.repo.RepoPath()})
_, _, err = gitrepo.RunCmdString(ctx, g.repo, gitcmd.NewCommand("rev-list", "--quiet", "-1").AddDynamicArguments(pr.Head.SHA))
if err != nil {
// Git update-ref remove bad references with a relative path
log.Warn("Deprecated local head %s for PR #%d in %s/%s, removing %s", pr.Head.SHA, pr.Number, g.repoOwner, g.repoName, pr.GetGitHeadRefName())
@@ -735,7 +735,7 @@ func (g *GiteaLocalUploader) newPullRequest(ctx context.Context, pr *base.PullRe
if pr.Base.Ref != "" && pr.Head.SHA != "" {
// A PR against a tag base does not make sense - therefore pr.Base.Ref must be a branch
// TODO: should we be checking for the refs/heads/ prefix on the pr.Base.Ref? (i.e. are these actually branches or refs)
pr.Base.SHA, _, err = g.gitRepo.GetMergeBase("", git.BranchPrefix+pr.Base.Ref, pr.Head.SHA)
pr.Base.SHA, err = gitrepo.MergeBase(ctx, g.repo, git.BranchPrefix+pr.Base.Ref, pr.Head.SHA)
if err != nil {
log.Error("Cannot determine the merge base for PR #%d in %s/%s. Error: %v", pr.Number, g.repoOwner, g.repoName, err)
}
@@ -897,21 +897,10 @@ func (g *GiteaLocalUploader) CreateReviews(ctx context.Context, reviews ...*base
// SECURITY: The TreePath must be cleaned! use relative path
comment.TreePath = util.PathJoinRel(comment.TreePath)
var patch string
reader, writer := io.Pipe()
defer func() {
_ = reader.Close()
_ = writer.Close()
}()
go func(comment *base.ReviewComment) {
if err := git.GetRepoRawDiffForFile(g.gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, comment.TreePath, writer); err != nil {
// We should ignore the error since the commit maybe removed when force push to the pull request
log.Warn("GetRepoRawDiffForFile failed when migrating [%s, %s, %s, %s]: %v", g.gitRepo.Path, pr.MergeBase, headCommitID, comment.TreePath, err)
}
_ = writer.Close()
}(comment)
patch, _ = git.CutDiffAroundLine(reader, int64((&issues_model.Comment{Line: int64(line + comment.Position - 1)}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines)
patch, _ := git.GetFileDiffCutAroundLine(
g.gitRepo, pr.MergeBase, headCommitID, comment.TreePath,
int64((&issues_model.Comment{Line: int64(line + comment.Position - 1)}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines,
)
if comment.CreatedAt.IsZero() {
comment.CreatedAt = review.CreatedAt
@@ -999,12 +988,15 @@ func (g *GiteaLocalUploader) remapUser(ctx context.Context, source user_model.Ex
func (g *GiteaLocalUploader) remapLocalUser(ctx context.Context, source user_model.ExternalUserMigrated) (int64, error) {
userid, ok := g.userMap[source.GetExternalID()]
if !ok {
name, err := user_model.GetUserNameByID(ctx, source.GetExternalID())
if err != nil {
user, err := user_model.GetUserByID(ctx, source.GetExternalID())
if errors.Is(err, util.ErrNotExist) {
g.userMap[source.GetExternalID()] = userid
return 0, nil
} else if err != nil {
return 0, err
}
// let's not reuse an ID when the user was deleted or has a different user name
if name != source.GetExternalName() {
// let's not reuse an ID when the user was deleted or has a different username
if !util.AsciiEqualFold(user.Name, source.GetExternalName()) {
userid = 0
} else {
userid = source.GetExternalID()
@@ -5,9 +5,6 @@
package migrations
import (
"fmt"
"os"
"path/filepath"
"strconv"
"testing"
"time"
@@ -17,15 +14,10 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
base "code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
repo_service "code.gitea.io/gitea/services/repository"
"github.com/stretchr/testify/assert"
@@ -228,297 +220,3 @@ func TestGiteaUploadRemapExternalUser(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, linkedUser.ID, target.GetUserID())
}
func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
unittest.PrepareTestEnv(t)
//
// fromRepo master
//
fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
baseRef := "master"
// this is very different from the real situation. It should be a bare repository for all the Gitea managed repositories
assert.NoError(t, git.InitRepository(t.Context(), fromRepo.RepoPath(), false, fromRepo.ObjectFormatName))
err := gitcmd.NewCommand("symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(t.Context(), &gitcmd.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte("# Testing Repository\n\nOriginally created in: "+fromRepo.RepoPath()), 0o644))
assert.NoError(t, git.AddChanges(t.Context(), fromRepo.RepoPath(), true))
signature := git.Signature{
Email: "test@example.com",
Name: "test",
When: time.Now(),
}
assert.NoError(t, git.CommitChanges(t.Context(), fromRepo.RepoPath(), git.CommitChangesOptions{
Committer: &signature,
Author: &signature,
Message: "Initial Commit",
}))
fromGitRepo, err := gitrepo.OpenRepository(t.Context(), fromRepo)
assert.NoError(t, err)
defer fromGitRepo.Close()
baseSHA, err := fromGitRepo.GetBranchCommitID(baseRef)
assert.NoError(t, err)
//
// fromRepo branch1
//
headRef := "branch1"
_, _, err = gitcmd.NewCommand("checkout", "-b").AddDynamicArguments(headRef).RunStdString(t.Context(), &gitcmd.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte("SOMETHING"), 0o644))
assert.NoError(t, git.AddChanges(t.Context(), fromRepo.RepoPath(), true))
signature.When = time.Now()
assert.NoError(t, git.CommitChanges(t.Context(), fromRepo.RepoPath(), git.CommitChangesOptions{
Committer: &signature,
Author: &signature,
Message: "Pull request",
}))
assert.NoError(t, err)
headSHA, err := fromGitRepo.GetBranchCommitID(headRef)
assert.NoError(t, err)
fromRepoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: fromRepo.OwnerID})
//
// forkRepo branch2
//
forkHeadRef := "branch2"
forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8})
assert.NoError(t, git.Clone(t.Context(), fromRepo.RepoPath(), forkRepo.RepoPath(), git.CloneRepoOptions{
Branch: headRef,
}))
_, _, err = gitcmd.NewCommand("checkout", "-b").AddDynamicArguments(forkHeadRef).RunStdString(t.Context(), &gitcmd.RunOpts{Dir: forkRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(forkRepo.RepoPath(), "README.md"), []byte("# branch2 "+forkRepo.RepoPath()), 0o644))
assert.NoError(t, git.AddChanges(t.Context(), forkRepo.RepoPath(), true))
assert.NoError(t, git.CommitChanges(t.Context(), forkRepo.RepoPath(), git.CommitChangesOptions{
Committer: &signature,
Author: &signature,
Message: "branch2 commit",
}))
forkGitRepo, err := gitrepo.OpenRepository(t.Context(), forkRepo)
assert.NoError(t, err)
defer forkGitRepo.Close()
forkHeadSHA, err := forkGitRepo.GetBranchCommitID(forkHeadRef)
assert.NoError(t, err)
toRepoName := "migrated"
ctx := t.Context()
uploader := NewGiteaLocalUploader(ctx, fromRepoOwner, fromRepoOwner.Name, toRepoName)
uploader.gitServiceType = structs.GiteaService
assert.NoError(t, repo_service.Init(t.Context()))
assert.NoError(t, uploader.CreateRepo(ctx, &base.Repository{
Description: "description",
OriginalURL: fromRepo.RepoPath(),
CloneURL: fromRepo.RepoPath(),
IsPrivate: false,
IsMirror: true,
}, base.MigrateOptions{
GitServiceType: structs.GiteaService,
Private: false,
Mirror: true,
}))
for _, testCase := range []struct {
name string
head string
logFilter []string
logFiltered []bool
pr base.PullRequest
}{
{
name: "fork, good Head.SHA",
head: fmt.Sprintf("%s/%s", forkRepo.OwnerName, forkHeadRef),
pr: base.PullRequest{
PatchURL: "",
Number: 1,
State: "open",
Base: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: baseRef,
SHA: baseSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
Head: base.PullRequestBranch{
CloneURL: forkRepo.RepoPath(),
Ref: forkHeadRef,
SHA: forkHeadSHA,
RepoName: forkRepo.Name,
OwnerName: forkRepo.OwnerName,
},
},
},
{
name: "fork, invalid Head.Ref",
head: "unknown repository",
pr: base.PullRequest{
PatchURL: "",
Number: 1,
State: "open",
Base: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: baseRef,
SHA: baseSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
Head: base.PullRequestBranch{
CloneURL: forkRepo.RepoPath(),
Ref: "INVALID",
SHA: forkHeadSHA,
RepoName: forkRepo.Name,
OwnerName: forkRepo.OwnerName,
},
},
logFilter: []string{"Fetch branch from"},
logFiltered: []bool{true},
},
{
name: "invalid fork CloneURL",
head: "unknown repository",
pr: base.PullRequest{
PatchURL: "",
Number: 1,
State: "open",
Base: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: baseRef,
SHA: baseSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
Head: base.PullRequestBranch{
CloneURL: "UNLIKELY",
Ref: forkHeadRef,
SHA: forkHeadSHA,
RepoName: forkRepo.Name,
OwnerName: "WRONG",
},
},
logFilter: []string{"AddRemote"},
logFiltered: []bool{true},
},
{
name: "no fork, good Head.SHA",
head: headRef,
pr: base.PullRequest{
PatchURL: "",
Number: 1,
State: "open",
Base: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: baseRef,
SHA: baseSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
Head: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: headRef,
SHA: headSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
},
},
{
name: "no fork, empty Head.SHA",
head: headRef,
pr: base.PullRequest{
PatchURL: "",
Number: 1,
State: "open",
Base: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: baseRef,
SHA: baseSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
Head: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: headRef,
SHA: "",
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
},
logFilter: []string{"Empty reference", "Cannot remove local head"},
logFiltered: []bool{true, false},
},
{
name: "no fork, invalid Head.SHA",
head: headRef,
pr: base.PullRequest{
PatchURL: "",
Number: 1,
State: "open",
Base: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: baseRef,
SHA: baseSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
Head: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: headRef,
SHA: "brokenSHA",
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
},
logFilter: []string{"Deprecated local head"},
logFiltered: []bool{true},
},
{
name: "no fork, not found Head.SHA",
head: headRef,
pr: base.PullRequest{
PatchURL: "",
Number: 1,
State: "open",
Base: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: baseRef,
SHA: baseSHA,
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
Head: base.PullRequestBranch{
CloneURL: fromRepo.RepoPath(),
Ref: headRef,
SHA: "2697b352310fcd01cbd1f3dbd43b894080027f68",
RepoName: fromRepo.Name,
OwnerName: fromRepo.OwnerName,
},
},
logFilter: []string{"Deprecated local head", "Cannot remove local head"},
logFiltered: []bool{true, false},
},
} {
t.Run(testCase.name, func(t *testing.T) {
stopMark := fmt.Sprintf(">>>>>>>>>>>>>STOP: %s<<<<<<<<<<<<<<<", testCase.name)
logChecker, cleanup := test.NewLogChecker(log.DEFAULT)
logChecker.Filter(testCase.logFilter...).StopMark(stopMark)
defer cleanup()
testCase.pr.EnsuredSafe = true
head, err := uploader.updateGitForPullRequest(ctx, &testCase.pr)
assert.NoError(t, err)
assert.Equal(t, testCase.head, head)
log.Info(stopMark)
logFiltered, logStopped := logChecker.Check(5 * time.Second)
assert.True(t, logStopped)
if len(testCase.logFilter) > 0 {
assert.Equal(t, testCase.logFiltered, logFiltered, "for log message filters: %v", testCase.logFilter)
}
})
}
}
@@ -20,7 +20,7 @@ import (
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/structs"
"github.com/google/go-github/v74/github"
"github.com/google/go-github/v84/github"
"golang.org/x/oauth2"
)
@@ -861,28 +861,22 @@ func (g *GithubDownloaderV3) GetReviews(ctx context.Context, reviewable base.Rev
opt.Page = resp.NextPage
}
// Get requested reviews
for {
g.waitAndPickClient(ctx)
reviewers, resp, err := g.getClient().PullRequests.ListReviewers(ctx, g.repoOwner, g.repoName, int(reviewable.GetForeignIndex()), opt)
if err != nil {
return nil, fmt.Errorf("error while listing repos: %w", err)
}
g.setRate(&resp.Rate)
for _, user := range reviewers.Users {
r := &base.Review{
ReviewerID: user.GetID(),
ReviewerName: user.GetLogin(),
State: base.ReviewStateRequestReview,
IssueIndex: reviewable.GetLocalIndex(),
}
allReviews = append(allReviews, r)
}
// TODO: Handle Team requests
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
g.waitAndPickClient(ctx)
reviewers, resp, err := g.getClient().PullRequests.ListReviewers(ctx, g.repoOwner, g.repoName, int(reviewable.GetForeignIndex()))
if err != nil {
return nil, fmt.Errorf("error while listing repos: %w", err)
}
g.setRate(&resp.Rate)
for _, user := range reviewers.Users {
r := &base.Review{
ReviewerID: user.GetID(),
ReviewerName: user.GetLogin(),
State: base.ReviewStateRequestReview,
IssueIndex: reviewable.GetLocalIndex(),
}
allReviews = append(allReviews, r)
}
// TODO: Handle Team requests
return allReviews, nil
}
@@ -47,19 +47,19 @@ func TestGitHubDownloadRepo(t *testing.T) {
{
Title: "1.0.0",
Description: "Milestone 1.0.0",
Deadline: timePtr(time.Date(2019, 11, 11, 8, 0, 0, 0, time.UTC)),
Deadline: new(time.Date(2019, 11, 11, 8, 0, 0, 0, time.UTC)),
Created: time.Date(2019, 11, 12, 19, 37, 8, 0, time.UTC),
Updated: timePtr(time.Date(2019, 11, 12, 21, 56, 17, 0, time.UTC)),
Closed: timePtr(time.Date(2019, 11, 12, 19, 45, 49, 0, time.UTC)),
Updated: new(time.Date(2019, 11, 12, 21, 56, 17, 0, time.UTC)),
Closed: new(time.Date(2019, 11, 12, 19, 45, 49, 0, time.UTC)),
State: "closed",
},
{
Title: "1.1.0",
Description: "Milestone 1.1.0",
Deadline: timePtr(time.Date(2019, 11, 12, 8, 0, 0, 0, time.UTC)),
Deadline: new(time.Date(2019, 11, 12, 8, 0, 0, 0, time.UTC)),
Created: time.Date(2019, 11, 12, 19, 37, 25, 0, time.UTC),
Updated: timePtr(time.Date(2019, 11, 12, 21, 39, 27, 0, time.UTC)),
Closed: timePtr(time.Date(2019, 11, 12, 19, 45, 46, 0, time.UTC)),
Updated: new(time.Date(2019, 11, 12, 21, 39, 27, 0, time.UTC)),
Closed: new(time.Date(2019, 11, 12, 19, 45, 46, 0, time.UTC)),
State: "closed",
},
}, milestones)
@@ -163,7 +163,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
Content: "+1",
},
},
Closed: timePtr(time.Date(2019, 11, 12, 20, 22, 22, 0, time.UTC)),
Closed: new(time.Date(2019, 11, 12, 20, 22, 22, 0, time.UTC)),
},
{
Number: 2,
@@ -214,7 +214,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
Content: "+1",
},
},
Closed: timePtr(time.Date(2019, 11, 12, 21, 1, 31, 0, time.UTC)),
Closed: new(time.Date(2019, 11, 12, 21, 1, 31, 0, time.UTC)),
},
}, issues)
@@ -284,9 +284,9 @@ func TestGitHubDownloadRepo(t *testing.T) {
OwnerName: "go-gitea",
RepoName: "test_repo",
},
Closed: timePtr(time.Date(2019, 11, 12, 21, 39, 27, 0, time.UTC)),
Closed: new(time.Date(2019, 11, 12, 21, 39, 27, 0, time.UTC)),
Merged: true,
MergedTime: timePtr(time.Date(2019, 11, 12, 21, 39, 27, 0, time.UTC)),
MergedTime: new(time.Date(2019, 11, 12, 21, 39, 27, 0, time.UTC)),
MergeCommitSHA: "f32b0a9dfd09a60f616f29158f772cedd89942d2",
ForeignIndex: 3,
},
@@ -63,16 +63,16 @@ type gitlabIIDResolver struct {
frozen bool
}
func (r *gitlabIIDResolver) recordIssueIID(issueIID int) {
func (r *gitlabIIDResolver) recordIssueIID(issueIID int64) {
if r.frozen {
panic("cannot record issue IID after pull request IID generation has started")
}
r.maxIssueIID = max(r.maxIssueIID, int64(issueIID))
r.maxIssueIID = max(r.maxIssueIID, issueIID)
}
func (r *gitlabIIDResolver) generatePullRequestNumber(mrIID int) int64 {
func (r *gitlabIIDResolver) generatePullRequestNumber(mrIID int64) int64 {
r.frozen = true
return r.maxIssueIID + int64(mrIID)
return r.maxIssueIID + mrIID
}
// GitlabDownloader implements a Downloader interface to get repository information
@@ -83,7 +83,7 @@ type GitlabDownloader struct {
base.NullDownloader
client *gitlab.Client
baseURL string
repoID int
repoID int64
repoName string
iidResolver gitlabIIDResolver
maxPerPage int
@@ -212,8 +212,8 @@ func (g *GitlabDownloader) GetMilestones(ctx context.Context) ([]*base.Milestone
ms, _, err := g.client.Milestones.ListMilestones(g.repoID, &gitlab.ListMilestonesOptions{
State: &state,
ListOptions: gitlab.ListOptions{
Page: i,
PerPage: perPage,
Page: int64(i),
PerPage: int64(perPage),
},
}, nil, gitlab.WithContext(ctx))
if err != nil {
@@ -281,8 +281,8 @@ func (g *GitlabDownloader) GetLabels(ctx context.Context) ([]*base.Label, error)
labels := make([]*base.Label, 0, perPage)
for i := 1; ; i++ {
ls, _, err := g.client.Labels.ListLabels(g.repoID, &gitlab.ListLabelsOptions{ListOptions: gitlab.ListOptions{
Page: i,
PerPage: perPage,
Page: int64(i),
PerPage: int64(perPage),
}}, nil, gitlab.WithContext(ctx))
if err != nil {
return nil, err
@@ -310,7 +310,7 @@ func (g *GitlabDownloader) convertGitlabRelease(ctx context.Context, rel *gitlab
Name: rel.Name,
Body: rel.Description,
Created: *rel.CreatedAt,
PublisherID: int64(rel.Author.ID),
PublisherID: rel.Author.ID,
PublisherName: rel.Author.Username,
}
@@ -319,7 +319,7 @@ func (g *GitlabDownloader) convertGitlabRelease(ctx context.Context, rel *gitlab
for _, asset := range rel.Assets.Links {
assetID := asset.ID // Don't optimize this, for closure we need a local variable
r.Assets = append(r.Assets, &base.ReleaseAsset{
ID: int64(asset.ID),
ID: asset.ID,
Name: asset.Name,
Size: &zero,
DownloadCount: &zero,
@@ -359,8 +359,8 @@ func (g *GitlabDownloader) GetReleases(ctx context.Context) ([]*base.Release, er
for i := 1; ; i++ {
ls, _, err := g.client.Releases.ListReleases(g.repoID, &gitlab.ListReleasesOptions{
ListOptions: gitlab.ListOptions{
Page: i,
PerPage: perPage,
Page: int64(i),
PerPage: int64(perPage),
},
}, nil, gitlab.WithContext(ctx))
if err != nil {
@@ -396,8 +396,8 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
State: &state,
Sort: &sort,
ListOptions: gitlab.ListOptions{
PerPage: perPage,
Page: page,
PerPage: int64(perPage),
Page: int64(page),
},
}
@@ -423,7 +423,7 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
var reactions []*gitlab.AwardEmoji
awardPage := 1
for {
awards, _, err := g.client.AwardEmoji.ListIssueAwardEmoji(g.repoID, issue.IID, &gitlab.ListAwardEmojiOptions{Page: awardPage, PerPage: perPage}, gitlab.WithContext(ctx))
awards, _, err := g.client.AwardEmoji.ListIssueAwardEmoji(g.repoID, issue.IID, &gitlab.ListAwardEmojiOptions{ListOptions: gitlab.ListOptions{Page: int64(awardPage), PerPage: int64(perPage)}}, gitlab.WithContext(ctx))
if err != nil {
return nil, false, fmt.Errorf("error while listing issue awards: %w", err)
}
@@ -439,8 +439,8 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
allIssues = append(allIssues, &base.Issue{
Title: issue.Title,
Number: int64(issue.IID),
PosterID: int64(issue.Author.ID),
Number: issue.IID,
PosterID: issue.Author.ID,
PosterName: issue.Author.Username,
Content: issue.Description,
Milestone: milestone,
@@ -451,7 +451,7 @@ func (g *GitlabDownloader) GetIssues(ctx context.Context, page, perPage int) ([]
Closed: issue.ClosedAt,
IsLocked: issue.DiscussionLocked,
Updated: *issue.UpdatedAt,
ForeignIndex: int64(issue.IID),
ForeignIndex: issue.IID,
Context: gitlabIssueContext{IsMergeRequest: false},
})
@@ -472,21 +472,25 @@ func (g *GitlabDownloader) GetComments(ctx context.Context, commentable base.Com
allComments := make([]*base.Comment, 0, g.maxPerPage)
page := 1
var page int64 = 1
for {
var comments []*gitlab.Discussion
var resp *gitlab.Response
var err error
if !context.IsMergeRequest {
comments, resp, err = g.client.Discussions.ListIssueDiscussions(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListIssueDiscussionsOptions{
Page: page,
PerPage: g.maxPerPage,
comments, resp, err = g.client.Discussions.ListIssueDiscussions(g.repoID, commentable.GetForeignIndex(), &gitlab.ListIssueDiscussionsOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: int64(g.maxPerPage),
},
}, nil, gitlab.WithContext(ctx))
} else {
comments, resp, err = g.client.Discussions.ListMergeRequestDiscussions(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListMergeRequestDiscussionsOptions{
Page: page,
PerPage: g.maxPerPage,
comments, resp, err = g.client.Discussions.ListMergeRequestDiscussions(g.repoID, commentable.GetForeignIndex(), &gitlab.ListMergeRequestDiscussionsOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: int64(g.maxPerPage),
},
}, nil, gitlab.WithContext(ctx))
}
@@ -510,17 +514,17 @@ func (g *GitlabDownloader) GetComments(ctx context.Context, commentable base.Com
var resp *gitlab.Response
var err error
if context.IsMergeRequest {
stateEvents, resp, err = g.client.ResourceStateEvents.ListMergeStateEvents(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListStateEventsOptions{
stateEvents, resp, err = g.client.ResourceStateEvents.ListMergeStateEvents(g.repoID, commentable.GetForeignIndex(), &gitlab.ListStateEventsOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: g.maxPerPage,
PerPage: int64(g.maxPerPage),
},
}, nil, gitlab.WithContext(ctx))
} else {
stateEvents, resp, err = g.client.ResourceStateEvents.ListIssueStateEvents(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListStateEventsOptions{
stateEvents, resp, err = g.client.ResourceStateEvents.ListIssueStateEvents(g.repoID, commentable.GetForeignIndex(), &gitlab.ListStateEventsOptions{
ListOptions: gitlab.ListOptions{
Page: page,
PerPage: g.maxPerPage,
PerPage: int64(g.maxPerPage),
},
}, nil, gitlab.WithContext(ctx))
}
@@ -531,11 +535,11 @@ func (g *GitlabDownloader) GetComments(ctx context.Context, commentable base.Com
for _, stateEvent := range stateEvents {
posterUserID, posterUsername := user.GhostUserID, user.GhostUserName
if stateEvent.User != nil {
posterUserID, posterUsername = int64(stateEvent.User.ID), stateEvent.User.Username
posterUserID, posterUsername = stateEvent.User.ID, stateEvent.User.Username
}
comment := &base.Comment{
IssueIndex: commentable.GetLocalIndex(),
Index: int64(stateEvent.ID),
Index: stateEvent.ID,
PosterID: posterUserID,
PosterName: posterUsername,
Content: "",
@@ -569,8 +573,8 @@ var targetBranchChangeRegexp = regexp.MustCompile("^changed target branch from `
func (g *GitlabDownloader) convertNoteToComment(localIndex int64, note *gitlab.Note) *base.Comment {
comment := &base.Comment{
IssueIndex: localIndex,
Index: int64(note.ID),
PosterID: int64(note.Author.ID),
Index: note.ID,
PosterID: note.Author.ID,
PosterName: note.Author.Username,
PosterEmail: note.Author.Email,
Content: note.Body,
@@ -603,8 +607,8 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
view := "simple"
opt := &gitlab.ListProjectMergeRequestsOptions{
ListOptions: gitlab.ListOptions{
PerPage: perPage,
Page: page,
PerPage: int64(perPage),
Page: int64(page),
},
View: &view,
}
@@ -664,7 +668,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
var reactions []*gitlab.AwardEmoji
awardPage := 1
for {
awards, _, err := g.client.AwardEmoji.ListMergeRequestAwardEmoji(g.repoID, pr.IID, &gitlab.ListAwardEmojiOptions{Page: awardPage, PerPage: perPage}, gitlab.WithContext(ctx))
awards, _, err := g.client.AwardEmoji.ListMergeRequestAwardEmoji(g.repoID, pr.IID, &gitlab.ListAwardEmojiOptions{ListOptions: gitlab.ListOptions{Page: int64(awardPage), PerPage: int64(perPage)}}, gitlab.WithContext(ctx))
if err != nil {
return nil, false, fmt.Errorf("error while listing merge requests awards: %w", err)
}
@@ -685,7 +689,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
Title: pr.Title,
Number: newPRNumber,
PosterName: pr.Author.Username,
PosterID: int64(pr.Author.ID),
PosterID: pr.Author.ID,
Content: pr.Description,
Milestone: milestone,
State: pr.State,
@@ -711,7 +715,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
OwnerName: pr.Author.Username,
},
PatchURL: pr.WebURL + ".patch",
ForeignIndex: int64(pr.IID),
ForeignIndex: pr.IID,
Context: gitlabIssueContext{IsMergeRequest: true},
IsDraft: pr.Draft,
})
@@ -725,7 +729,7 @@ func (g *GitlabDownloader) GetPullRequests(ctx context.Context, page, perPage in
// GetReviews returns pull requests review
func (g *GitlabDownloader) GetReviews(ctx context.Context, reviewable base.Reviewable) ([]*base.Review, error) {
approvals, resp, err := g.client.MergeRequestApprovals.GetConfiguration(g.repoID, int(reviewable.GetForeignIndex()), gitlab.WithContext(ctx))
approvals, resp, err := g.client.MergeRequestApprovals.GetConfiguration(g.repoID, reviewable.GetForeignIndex(), gitlab.WithContext(ctx))
if err != nil {
if resp != nil && resp.StatusCode == http.StatusNotFound {
log.Error(fmt.Sprintf("GitlabDownloader: while migrating a error occurred: '%s'", err.Error()))
@@ -747,7 +751,7 @@ func (g *GitlabDownloader) GetReviews(ctx context.Context, reviewable base.Revie
for _, user := range approvals.ApprovedBy {
reviews = append(reviews, &base.Review{
IssueIndex: reviewable.GetLocalIndex(),
ReviewerID: int64(user.User.ID),
ReviewerID: user.User.ID,
ReviewerName: user.User.Username,
CreatedAt: createdAt,
// All we get are approvals
@@ -765,7 +769,7 @@ func (g *GitlabDownloader) awardsToReactions(awards []*gitlab.AwardEmoji) []*bas
uid := fmt.Sprintf("%s%d", award.Name, award.User.ID)
if uniqCheck.Add(uid) {
result = append(result, &base.Reaction{
UserID: int64(award.User.ID),
UserID: award.User.ID,
UserName: award.User.Username,
Content: award.Name,
})
@@ -30,6 +30,7 @@ func TestGitlabDownloadRepo(t *testing.T) {
if err != nil || resp.StatusCode != http.StatusOK {
t.Skipf("Can't access test repo, skipping %s", t.Name())
}
defer resp.Body.Close()
ctx := t.Context()
downloader, err := NewGitlabDownloader(ctx, "https://gitlab.com", "gitea/test_repo", gitlabPersonalAccessToken)
if err != nil {
@@ -58,14 +59,14 @@ func TestGitlabDownloadRepo(t *testing.T) {
{
Title: "1.1.0",
Created: time.Date(2019, 11, 28, 8, 42, 44, 575000000, time.UTC),
Updated: timePtr(time.Date(2019, 11, 28, 8, 42, 44, 575000000, time.UTC)),
Updated: new(time.Date(2019, 11, 28, 8, 42, 44, 575000000, time.UTC)),
State: "active",
},
{
Title: "1.0.0",
Created: time.Date(2019, 11, 28, 8, 42, 30, 301000000, time.UTC),
Updated: timePtr(time.Date(2019, 11, 28, 15, 57, 52, 401000000, time.UTC)),
Closed: timePtr(time.Date(2019, 11, 28, 15, 57, 52, 401000000, time.UTC)),
Updated: new(time.Date(2019, 11, 28, 15, 57, 52, 401000000, time.UTC)),
Closed: new(time.Date(2019, 11, 28, 15, 57, 52, 401000000, time.UTC)),
State: "closed",
},
}, milestones)
@@ -160,7 +161,7 @@ func TestGitlabDownloadRepo(t *testing.T) {
Content: "open_mouth",
},
},
Closed: timePtr(time.Date(2019, 11, 28, 8, 46, 23, 275000000, time.UTC)),
Closed: new(time.Date(2019, 11, 28, 8, 46, 23, 275000000, time.UTC)),
},
{
Number: 2,
@@ -209,7 +210,7 @@ func TestGitlabDownloadRepo(t *testing.T) {
Content: "hearts",
},
},
Closed: timePtr(time.Date(2019, 11, 28, 8, 45, 44, 959000000, time.UTC)),
Closed: new(time.Date(2019, 11, 28, 8, 45, 44, 959000000, time.UTC)),
},
}, issues)
@@ -357,7 +358,7 @@ func gitlabClientMockTeardown(server *httptest.Server) {
}
type reviewTestCase struct {
repoID, prID, reviewerID int
repoID, prID, reviewerID int64
reviewerName string
createdAt, updatedAt *time.Time
expectedCreatedAt time.Time
@@ -382,8 +383,8 @@ func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Requ
fmt.Fprint(w, `
{
"id": 5,
"iid": `+strconv.Itoa(t.prID)+`,
"project_id": `+strconv.Itoa(t.repoID)+`,
"iid": `+strconv.FormatInt(t.prID, 10)+`,
"project_id": `+strconv.FormatInt(t.repoID, 10)+`,
"title": "Approvals API",
"description": "Test",
"state": "opened",
@@ -397,7 +398,7 @@ func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Requ
"user": {
"name": "Administrator",
"username": "`+t.reviewerName+`",
"id": `+strconv.Itoa(t.reviewerID)+`,
"id": `+strconv.FormatInt(t.reviewerID, 10)+`,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
"web_url": "http://localhost:3000/root"
@@ -407,8 +408,8 @@ func convertTestCase(t reviewTestCase) (func(w http.ResponseWriter, r *http.Requ
}`)
}
review := base.Review{
IssueIndex: int64(t.prID),
ReviewerID: int64(t.reviewerID),
IssueIndex: t.prID,
ReviewerID: t.reviewerID,
ReviewerName: t.reviewerName,
CreatedAt: t.expectedCreatedAt,
State: "APPROVED",
@@ -421,7 +422,7 @@ func TestGitlabGetReviews(t *testing.T) {
mux, server, client := gitlabClientMockSetup(t)
defer gitlabClientMockTeardown(server)
repoID := 1324
var repoID int64 = 1324
ctx := t.Context()
downloader := &GitlabDownloader{
client: client,
@@ -462,8 +463,7 @@ func TestGitlabGetReviews(t *testing.T) {
mock, review := convertTestCase(testCase)
mux.HandleFunc(fmt.Sprintf("/api/v4/projects/%d/merge_requests/%d/approvals", testCase.repoID, testCase.prID), mock)
id := int64(testCase.prID)
rvs, err := downloader.GetReviews(ctx, &base.Issue{Number: id, ForeignIndex: id})
rvs, err := downloader.GetReviews(ctx, &base.Issue{Number: testCase.prID, ForeignIndex: testCase.prID})
assert.NoError(t, err)
assertReviewsEqual(t, []*base.Review{&review}, rvs)
}
@@ -519,18 +519,10 @@ func TestNoteToComment(t *testing.T) {
downloader := &GitlabDownloader{}
now := time.Now()
makeTestNote := func(id int, body string, system bool) gitlab.Note {
makeTestNote := func(id int64, body string, system bool) gitlab.Note {
return gitlab.Note{
ID: id,
Author: struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Name string `json:"name"`
State string `json:"state"`
AvatarURL string `json:"avatar_url"`
WebURL string `json:"web_url"`
}{
Author: gitlab.NoteAuthor{
ID: 72,
Email: "test@example.com",
Username: "test",
@@ -27,6 +27,7 @@ func TestGogsDownloadRepo(t *testing.T) {
t.Skipf("visit test repo failed, ignored")
return
}
defer resp.Body.Close()
ctx := t.Context()
downloader := NewGogsDownloader(ctx, "https://try.gogs.io", "", "", gogsPersonalAccessToken, "lunnytest", "TESTREPO")
repo, err := downloader.GetRepoInfo(ctx)
@@ -18,10 +18,6 @@ func TestMain(m *testing.M) {
unittest.MainTest(m)
}
func timePtr(t time.Time) *time.Time {
return &t
}
func assertTimeEqual(t *testing.T, expected, actual time.Time) {
assert.Equal(t, expected.UTC(), actual.UTC())
}
@@ -222,7 +218,7 @@ func assertRepositoryEqual(t *testing.T, expected, actual *base.Repository) {
func assertReviewEqual(t *testing.T, expected, actual *base.Review) {
assert.Equal(t, expected.ID, actual.ID, "ID")
assert.Equal(t, expected.IssueIndex, actual.IssueIndex, "IsssueIndex")
assert.Equal(t, expected.IssueIndex, actual.IssueIndex, "IssueIndex")
assert.Equal(t, expected.ReviewerID, actual.ReviewerID, "ReviewerID")
assert.Equal(t, expected.ReviewerName, actual.ReviewerName, "ReviewerName")
assert.Equal(t, expected.Official, actual.Official, "Official")
@@ -16,6 +16,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/hostmatcher"
"code.gitea.io/gitea/modules/log"
@@ -130,8 +131,8 @@ func MigrateRepository(ctx context.Context, doer *user_model.User, ownerName str
if err1 := uploader.Rollback(); err1 != nil {
log.Error("rollback failed: %v", err1)
}
if err2 := system_model.CreateRepositoryNotice(fmt.Sprintf("Migrate repository from %s failed: %v", opts.OriginalURL, err)); err2 != nil {
log.Error("create respotiry notice failed: ", err2)
if err2 := system_model.CreateRepositoryNotice(fmt.Sprintf("Migrate repository (%s/%s) from %s failed: %v", ownerName, opts.RepoName, opts.OriginalURL, err)); err2 != nil {
log.Error("create repository notice failed: ", err2)
}
return nil, err
}
@@ -217,7 +218,7 @@ func migrateRepository(ctx context.Context, doer *user_model.User, downloader ba
// We don't actually need to check the OriginalURL as it isn't used anywhere
}
log.Trace("migrating git data from %s", repo.CloneURL)
log.Trace("migrating git data from %s", util.SanitizeCredentialURLs(repo.CloneURL))
messenger("repo.migrate.migrating_git")
if err = uploader.CreateRepo(ctx, repo, opts); err != nil {
return err
@@ -327,6 +328,9 @@ func migrateRepository(ctx context.Context, doer *user_model.User, downloader ba
messenger("repo.migrate.migrating_issues")
issueBatchSize := uploader.MaxBatchInsertSize("issue")
// because when the migrating is running, some issues maybe removed, so after the next page
// some of issue maybe duplicated, so we need to record the inserted issue indexes
mapInsertedIssueIndexes := container.Set[int64]{}
for i := 1; ; i++ {
issues, isEnd, err := downloader.GetIssues(ctx, i, issueBatchSize)
if err != nil {
@@ -336,6 +340,14 @@ func migrateRepository(ctx context.Context, doer *user_model.User, downloader ba
log.Warn("migrating issues is not supported, ignored")
break
}
for i := 0; i < len(issues); i++ {
if mapInsertedIssueIndexes.Contains(issues[i].Number) {
issues = append(issues[:i], issues[i+1:]...)
i--
continue
}
mapInsertedIssueIndexes.Add(issues[i].Number)
}
if err := uploader.CreateIssues(ctx, issues...); err != nil {
return err
@@ -381,6 +393,7 @@ func migrateRepository(ctx context.Context, doer *user_model.User, downloader ba
log.Trace("migrating pull requests and comments")
messenger("repo.migrate.migrating_pulls")
prBatchSize := uploader.MaxBatchInsertSize("pullrequest")
mapInsertedPRIndexes := container.Set[int64]{}
for i := 1; ; i++ {
prs, isEnd, err := downloader.GetPullRequests(ctx, i, prBatchSize)
if err != nil {
@@ -390,6 +403,14 @@ func migrateRepository(ctx context.Context, doer *user_model.User, downloader ba
log.Warn("migrating pull requests is not supported, ignored")
break
}
for i := 0; i < len(prs); i++ {
if mapInsertedPRIndexes.Contains(prs[i].Number) {
prs = append(prs[:i], prs[i+1:]...)
i--
continue
}
mapInsertedPRIndexes.Add(prs[i].Number)
}
if err := uploader.CreatePullRequests(ctx, prs...); err != nil {
return err
@@ -457,6 +478,15 @@ func migrateRepository(ctx context.Context, doer *user_model.User, downloader ba
break
}
}
if len(mapInsertedPRIndexes) > 0 {
// The pull requests migrating process may created head branches in the base repository
// because head repository maybe a fork one which will not be migrated. So that we need
// to sync branches again.
log.Trace("syncing branches after migrating pull requests")
if err = uploader.SyncBranches(ctx); err != nil {
return err
}
}
}
if opts.Comments && supportAllComments {
@@ -77,19 +77,19 @@ type OneDevDownloader struct {
}
// NewOneDevDownloader creates a new downloader
func NewOneDevDownloader(_ context.Context, baseURL *url.URL, username, password, repoPath string) *OneDevDownloader {
func NewOneDevDownloader(ctx context.Context, baseURL *url.URL, username, password, repoPath string) *OneDevDownloader {
httpTransport := NewMigrationHTTPTransport()
downloader := &OneDevDownloader{
baseURL: baseURL,
repoPath: repoPath,
client: &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
if len(username) > 0 && len(password) > 0 {
Transport: roundTripperFunc(
func(req *http.Request) (*http.Response, error) {
if username != "" && password != "" {
req.SetBasicAuth(username, password)
}
return nil, nil
},
},
return httpTransport.RoundTrip(req.WithContext(ctx))
}),
},
userMap: make(map[int64]*onedevUser),
milestoneMap: make(map[int64]string),
@@ -19,13 +19,11 @@ func TestOneDevDownloadRepo(t *testing.T) {
if err != nil || resp.StatusCode != http.StatusOK {
t.Skipf("Can't access test repo, skipping %s", t.Name())
}
defer resp.Body.Close()
u, _ := url.Parse("https://code.onedev.io")
ctx := t.Context()
downloader := NewOneDevDownloader(ctx, u, "", "", "go-gitea-test_repo")
if err != nil {
t.Fatalf("NewOneDevDownloader is nil: %v", err)
}
repo, err := downloader.GetRepoInfo(ctx)
assert.NoError(t, err)
assertRepositoryEqual(t, &base.Repository{