2019-05-07 04:12:51 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Copyright 2018 Jonas Franz. 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 (
2020-09-02 20:49:25 +03:00
"context"
2022-02-25 12:20:50 +03:00
"fmt"
"os"
"path/filepath"
2022-02-01 21:20:28 +03:00
"strconv"
2022-02-25 12:20:50 +03:00
"strings"
2019-05-07 04:12:51 +03:00
"testing"
"time"
"code.gitea.io/gitea/models"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2022-04-08 12:11:15 +03:00
issues_model "code.gitea.io/gitea/models/issues"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-12 17:36:47 +03:00
"code.gitea.io/gitea/models/unittest"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2022-02-25 12:20:50 +03:00
"code.gitea.io/gitea/modules/git"
2019-12-17 07:16:54 +03:00
"code.gitea.io/gitea/modules/graceful"
2022-02-25 12:20:50 +03:00
"code.gitea.io/gitea/modules/log"
2021-11-16 18:25:33 +03:00
base "code.gitea.io/gitea/modules/migration"
2019-10-13 16:23:14 +03:00
"code.gitea.io/gitea/modules/structs"
2019-05-07 04:12:51 +03:00
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
func TestGiteaUploadRepo ( t * testing . T ) {
// FIXME: Since no accesskey or user/password will trigger rate limit of github, just skip
t . Skip ( )
2021-11-12 17:36:47 +03:00
unittest . PrepareTestEnv ( t )
2019-05-07 04:12:51 +03:00
2021-11-24 12:49:20 +03:00
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } ) . ( * user_model . User )
2019-05-07 04:12:51 +03:00
var (
2020-09-21 17:36:51 +03:00
downloader = NewGithubDownloaderV3 ( context . Background ( ) , "https://github.com" , "" , "" , "" , "go-xorm" , "builder" )
2019-05-07 04:12:51 +03:00
repoName = "builder-" + time . Now ( ) . Format ( "2006-01-02-15-04-05" )
2019-12-17 07:16:54 +03:00
uploader = NewGiteaLocalUploader ( graceful . GetManager ( ) . HammerContext ( ) , user , user . Name , repoName )
2019-05-07 04:12:51 +03:00
)
2020-09-11 01:29:19 +03:00
err := migrateRepository ( downloader , uploader , base . MigrateOptions {
2019-10-13 16:23:14 +03:00
CloneAddr : "https://github.com/go-xorm/builder" ,
RepoName : repoName ,
2019-05-07 04:12:51 +03:00
AuthUsername : "" ,
2019-07-08 05:14:12 +03:00
Wiki : true ,
Issues : true ,
Milestones : true ,
Labels : true ,
Releases : true ,
Comments : true ,
PullRequests : true ,
Private : true ,
Mirror : false ,
2021-06-17 01:02:24 +03:00
} , nil )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , err )
2021-12-10 04:27:50 +03:00
repo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { OwnerID : user . ID , Name : repoName } ) . ( * repo_model . Repository )
2019-05-07 04:12:51 +03:00
assert . True ( t , repo . HasWiki ( ) )
2021-12-10 04:27:50 +03:00
assert . EqualValues ( t , repo_model . RepositoryReady , repo . Status )
2019-05-07 04:12:51 +03:00
2022-04-08 12:11:15 +03:00
milestones , _ , err := issues_model . GetMilestones ( issues_model . GetMilestonesOption {
2020-07-28 14:30:40 +03:00
RepoID : repo . ID ,
State : structs . StateOpen ,
} )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , err )
2021-06-07 08:27:09 +03:00
assert . Len ( t , milestones , 1 )
2019-05-07 04:12:51 +03:00
2022-04-08 12:11:15 +03:00
milestones , _ , err = issues_model . GetMilestones ( issues_model . GetMilestonesOption {
2020-07-28 14:30:40 +03:00
RepoID : repo . ID ,
State : structs . StateClosed ,
} )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , err )
2021-06-07 08:27:09 +03:00
assert . Empty ( t , milestones )
2019-05-07 04:12:51 +03:00
2021-09-24 14:32:56 +03:00
labels , err := models . GetLabelsByRepoID ( repo . ID , "" , db . ListOptions { } )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , err )
2021-08-18 03:47:18 +03:00
assert . Len ( t , labels , 12 )
2019-05-07 04:12:51 +03:00
releases , err := models . GetReleasesByRepoID ( repo . ID , models . FindReleasesOptions {
2021-09-24 14:32:56 +03:00
ListOptions : db . ListOptions {
2020-01-24 22:00:29 +03:00
PageSize : 10 ,
Page : 0 ,
} ,
2019-05-07 04:12:51 +03:00
IncludeTags : true ,
2020-01-24 22:00:29 +03:00
} )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , err )
2021-06-07 08:27:09 +03:00
assert . Len ( t , releases , 8 )
2019-05-07 04:12:51 +03:00
releases , err = models . GetReleasesByRepoID ( repo . ID , models . FindReleasesOptions {
2021-09-24 14:32:56 +03:00
ListOptions : db . ListOptions {
2020-01-24 22:00:29 +03:00
PageSize : 10 ,
Page : 0 ,
} ,
2019-05-07 04:12:51 +03:00
IncludeTags : false ,
2020-01-24 22:00:29 +03:00
} )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , err )
2021-06-07 08:27:09 +03:00
assert . Len ( t , releases , 1 )
2019-05-07 04:12:51 +03:00
issues , err := models . Issues ( & models . IssuesOptions {
2022-04-25 17:06:24 +03:00
RepoID : repo . ID ,
2019-05-07 04:12:51 +03:00
IsPull : util . OptionalBoolFalse ,
SortType : "oldest" ,
} )
assert . NoError ( t , err )
2021-08-18 03:47:18 +03:00
assert . Len ( t , issues , 15 )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , issues [ 0 ] . LoadDiscussComments ( ) )
2021-06-07 08:27:09 +03:00
assert . Empty ( t , issues [ 0 ] . Comments )
2019-05-07 04:12:51 +03:00
pulls , _ , err := models . PullRequests ( repo . ID , & models . PullRequestsOptions {
SortType : "oldest" ,
} )
assert . NoError ( t , err )
2021-08-18 03:47:18 +03:00
assert . Len ( t , pulls , 30 )
2019-05-07 04:12:51 +03:00
assert . NoError ( t , pulls [ 0 ] . LoadIssue ( ) )
assert . NoError ( t , pulls [ 0 ] . Issue . LoadDiscussComments ( ) )
2021-06-07 08:27:09 +03:00
assert . Len ( t , pulls [ 0 ] . Issue . Comments , 2 )
2019-05-07 04:12:51 +03:00
}
2022-02-01 21:20:28 +03:00
2022-02-06 12:05:29 +03:00
func TestGiteaUploadRemapLocalUser ( t * testing . T ) {
unittest . PrepareTestEnv ( t )
doer := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } ) . ( * user_model . User )
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 2 } ) . ( * user_model . User )
repoName := "migrated"
uploader := NewGiteaLocalUploader ( context . Background ( ) , doer , doer . Name , repoName )
// call remapLocalUser
uploader . sameApp = true
externalID := int64 ( 1234567 )
externalName := "username"
source := base . Release {
PublisherID : externalID ,
PublisherName : externalName ,
}
//
// The externalID does not match any existing user, everything
// belongs to the doer
//
target := models . Release { }
uploader . userMap = make ( map [ int64 ] int64 )
err := uploader . remapUser ( & source , & target )
assert . NoError ( t , err )
assert . EqualValues ( t , doer . ID , target . GetUserID ( ) )
//
// The externalID matches a known user but the name does not match,
// everything belongs to the doer
//
source . PublisherID = user . ID
target = models . Release { }
uploader . userMap = make ( map [ int64 ] int64 )
err = uploader . remapUser ( & source , & target )
assert . NoError ( t , err )
assert . EqualValues ( t , doer . ID , target . GetUserID ( ) )
//
// The externalID and externalName match an existing user, everything
// belongs to the existing user
//
source . PublisherName = user . Name
target = models . Release { }
uploader . userMap = make ( map [ int64 ] int64 )
err = uploader . remapUser ( & source , & target )
assert . NoError ( t , err )
assert . EqualValues ( t , user . ID , target . GetUserID ( ) )
}
2022-02-01 21:20:28 +03:00
func TestGiteaUploadRemapExternalUser ( t * testing . T ) {
unittest . PrepareTestEnv ( t )
doer := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 1 } ) . ( * user_model . User )
repoName := "migrated"
uploader := NewGiteaLocalUploader ( context . Background ( ) , doer , doer . Name , repoName )
uploader . gitServiceType = structs . GiteaService
2022-02-06 12:05:29 +03:00
// call remapExternalUser
uploader . sameApp = false
2022-02-01 21:20:28 +03:00
externalID := int64 ( 1234567 )
2022-02-06 12:05:29 +03:00
externalName := "username"
2022-02-01 21:20:28 +03:00
source := base . Release {
PublisherID : externalID ,
PublisherName : externalName ,
}
//
// When there is no user linked to the external ID, the migrated data is authored
// by the doer
//
2022-02-06 12:05:29 +03:00
uploader . userMap = make ( map [ int64 ] int64 )
2022-02-01 21:20:28 +03:00
target := models . Release { }
2022-02-06 12:05:29 +03:00
err := uploader . remapUser ( & source , & target )
2022-02-01 21:20:28 +03:00
assert . NoError ( t , err )
assert . EqualValues ( t , doer . ID , target . GetUserID ( ) )
//
// Link the external ID to an existing user
//
linkedUser := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 2 } ) . ( * user_model . User )
externalLoginUser := & user_model . ExternalLoginUser {
ExternalID : strconv . FormatInt ( externalID , 10 ) ,
UserID : linkedUser . ID ,
LoginSourceID : 0 ,
Provider : structs . GiteaService . Name ( ) ,
}
err = user_model . LinkExternalToUser ( linkedUser , externalLoginUser )
assert . NoError ( t , err )
//
// When a user is linked to the external ID, it becomes the author of
// the migrated data
//
2022-02-06 12:05:29 +03:00
uploader . userMap = make ( map [ int64 ] int64 )
2022-02-01 21:20:28 +03:00
target = models . Release { }
2022-02-06 12:05:29 +03:00
err = uploader . remapUser ( & source , & target )
2022-02-01 21:20:28 +03:00
assert . NoError ( t , err )
2022-02-06 12:05:29 +03:00
assert . EqualValues ( t , linkedUser . ID , target . GetUserID ( ) )
2022-02-01 21:20:28 +03:00
}
2022-02-25 12:20:50 +03:00
func TestGiteaUploadUpdateGitForPullRequest ( t * testing . T ) {
unittest . PrepareTestEnv ( t )
//
// fromRepo master
//
fromRepo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 } ) . ( * repo_model . Repository )
baseRef := "master"
assert . NoError ( t , git . InitRepository ( git . DefaultContext , fromRepo . RepoPath ( ) , false ) )
2022-04-01 05:55:30 +03:00
err := git . NewCommand ( git . DefaultContext , "symbolic-ref" , "HEAD" , git . BranchPrefix + baseRef ) . Run ( & git . RunOpts { Dir : fromRepo . RepoPath ( ) } )
2022-02-25 12:20:50 +03:00
assert . NoError ( t , err )
assert . NoError ( t , os . WriteFile ( filepath . Join ( fromRepo . RepoPath ( ) , "README.md" ) , [ ] byte ( fmt . Sprintf ( "# Testing Repository\n\nOriginally created in: %s" , fromRepo . RepoPath ( ) ) ) , 0 o644 ) )
assert . NoError ( t , git . AddChanges ( fromRepo . RepoPath ( ) , true ) )
signature := git . Signature {
Email : "test@example.com" ,
Name : "test" ,
When : time . Now ( ) ,
}
assert . NoError ( t , git . CommitChanges ( fromRepo . RepoPath ( ) , git . CommitChangesOptions {
Committer : & signature ,
Author : & signature ,
Message : "Initial Commit" ,
} ) )
2022-03-29 22:13:41 +03:00
fromGitRepo , err := git . OpenRepository ( git . DefaultContext , fromRepo . RepoPath ( ) )
2022-02-25 12:20:50 +03:00
assert . NoError ( t , err )
defer fromGitRepo . Close ( )
baseSHA , err := fromGitRepo . GetBranchCommitID ( baseRef )
assert . NoError ( t , err )
//
// fromRepo branch1
//
headRef := "branch1"
2022-04-01 05:55:30 +03:00
_ , _ , err = git . NewCommand ( git . DefaultContext , "checkout" , "-b" , headRef ) . RunStdString ( & git . RunOpts { Dir : fromRepo . RepoPath ( ) } )
2022-02-25 12:20:50 +03:00
assert . NoError ( t , err )
assert . NoError ( t , os . WriteFile ( filepath . Join ( fromRepo . RepoPath ( ) , "README.md" ) , [ ] byte ( "SOMETHING" ) , 0 o644 ) )
assert . NoError ( t , git . AddChanges ( fromRepo . RepoPath ( ) , true ) )
signature . When = time . Now ( )
assert . NoError ( t , git . CommitChanges ( 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 } ) . ( * user_model . User )
//
// forkRepo branch2
//
forkHeadRef := "branch2"
forkRepo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 8 } ) . ( * repo_model . Repository )
assert . NoError ( t , git . CloneWithArgs ( git . DefaultContext , fromRepo . RepoPath ( ) , forkRepo . RepoPath ( ) , [ ] string { } , git . CloneRepoOptions {
Branch : headRef ,
} ) )
2022-04-01 05:55:30 +03:00
_ , _ , err = git . NewCommand ( git . DefaultContext , "checkout" , "-b" , forkHeadRef ) . RunStdString ( & git . RunOpts { Dir : forkRepo . RepoPath ( ) } )
2022-02-25 12:20:50 +03:00
assert . NoError ( t , err )
assert . NoError ( t , os . WriteFile ( filepath . Join ( forkRepo . RepoPath ( ) , "README.md" ) , [ ] byte ( fmt . Sprintf ( "# branch2 %s" , forkRepo . RepoPath ( ) ) ) , 0 o644 ) )
assert . NoError ( t , git . AddChanges ( forkRepo . RepoPath ( ) , true ) )
assert . NoError ( t , git . CommitChanges ( forkRepo . RepoPath ( ) , git . CommitChangesOptions {
Committer : & signature ,
Author : & signature ,
Message : "branch2 commit" ,
} ) )
2022-03-29 22:13:41 +03:00
forkGitRepo , err := git . OpenRepository ( git . DefaultContext , forkRepo . RepoPath ( ) )
2022-02-25 12:20:50 +03:00
assert . NoError ( t , err )
defer forkGitRepo . Close ( )
forkHeadSHA , err := forkGitRepo . GetBranchCommitID ( forkHeadRef )
assert . NoError ( t , err )
toRepoName := "migrated"
uploader := NewGiteaLocalUploader ( context . Background ( ) , fromRepoOwner , fromRepoOwner . Name , toRepoName )
uploader . gitServiceType = structs . GiteaService
assert . NoError ( t , uploader . CreateRepo ( & 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
assertContent func ( t * testing . T , content string )
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 ,
} ,
} ,
assertContent : func ( t * testing . T , content string ) {
assert . Contains ( t , content , "Fetch branch from" )
} ,
} ,
{
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" ,
} ,
} ,
assertContent : func ( t * testing . T , content string ) {
assert . Contains ( t , content , "AddRemote failed" )
} ,
} ,
{
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 ,
} ,
} ,
assertContent : func ( t * testing . T , content string ) {
assert . Contains ( t , content , "Empty reference, removing" )
assert . NotContains ( t , content , "Cannot remove local head" )
} ,
} ,
{
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 ,
} ,
} ,
assertContent : func ( t * testing . T , content string ) {
assert . Contains ( t , content , "Deprecated local head" )
assert . Contains ( t , content , "Cannot remove local head" )
} ,
} ,
{
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 ,
} ,
} ,
assertContent : func ( t * testing . T , content string ) {
assert . Contains ( t , content , "Deprecated local head" )
assert . NotContains ( t , content , "Cannot remove local head" )
} ,
} ,
} {
t . Run ( testCase . name , func ( t * testing . T ) {
logger , ok := log . NamedLoggers . Load ( log . DEFAULT )
assert . True ( t , ok )
logger . SetLogger ( "buffer" , "buffer" , "{}" )
defer logger . DelLogger ( "buffer" )
head , err := uploader . updateGitForPullRequest ( & testCase . pr )
assert . NoError ( t , err )
assert . EqualValues ( t , testCase . head , head )
if testCase . assertContent != nil {
fence := fmt . Sprintf ( ">>>>>>>>>>>>>FENCE %s<<<<<<<<<<<<<<<" , testCase . name )
log . Error ( fence )
var content string
for i := 0 ; i < 5000 ; i ++ {
content , err = logger . GetLoggerProviderContent ( "buffer" )
assert . NoError ( t , err )
if strings . Contains ( content , fence ) {
break
}
time . Sleep ( 1 * time . Millisecond )
}
testCase . assertContent ( t , content )
}
} )
}
}