Skip to content
43 changes: 23 additions & 20 deletions models/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,29 @@ type ActionType int

// Possible action types.
const (
ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2
ActionStarRepo // 3
ActionWatchRepo // 4
ActionCommitRepo // 5
ActionCreateIssue // 6
ActionCreatePullRequest // 7
ActionTransferRepo // 8
ActionPushTag // 9
ActionCommentIssue // 10
ActionMergePullRequest // 11
ActionCloseIssue // 12
ActionReopenIssue // 13
ActionClosePullRequest // 14
ActionReopenPullRequest // 15
ActionDeleteTag // 16
ActionDeleteBranch // 17
ActionMirrorSyncPush // 18
ActionMirrorSyncCreate // 19
ActionMirrorSyncDelete // 20
ActionCreateRepo ActionType = iota + 1 // 1
ActionRenameRepo // 2
ActionStarRepo // 3
ActionWatchRepo // 4
ActionCommitRepo // 5
ActionCreateIssue // 6
ActionCreatePullRequest // 7
ActionTransferRepo // 8
ActionPushTag // 9
ActionCommentIssue // 10
ActionMergePullRequest // 11
ActionCloseIssue // 12
ActionReopenIssue // 13
ActionClosePullRequest // 14
ActionReopenPullRequest // 15
ActionDeleteTag // 16
ActionDeleteBranch // 17
ActionMirrorSyncPush // 18
ActionMirrorSyncCreate // 19
ActionMirrorSyncDelete // 20
ActionMigrationStarted // 21
ActionMigrationSuccessful // 22
ActionMigrationFailure // 23
)

var (
Expand Down
18 changes: 17 additions & 1 deletion models/release_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,25 @@ func TestRelease_MirrorDelete(t *testing.T) {
IsMirror: true,
RemoteAddr: repoPath,
}
mirror, err := MigrateRepository(user, user, migrationOptions)

out := make(chan bool)
defer close(out)

mirror, err := MigrateRepository(user, user, migrationOptions, func(err error) string {
if err != nil {
out <- false
return err.Error()
}
out <- true
return repoPath
})

assert.NoError(t, err)

// Now we have to wait til the migration is reported.
success := <-out
assert.True(t, success)

gitRepo, err := git.OpenRepository(repoPath)
assert.NoError(t, err)

Expand Down
196 changes: 9 additions & 187 deletions models/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (
"github.com/go-xorm/builder"
"github.com/go-xorm/xorm"
version "github.com/mcuadros/go-version"
ini "gopkg.in/ini.v1"
)

var repoWorkingPool = sync.NewExclusivePool()
Expand Down Expand Up @@ -868,162 +867,6 @@ func (repo *Repository) CloneLink() (cl *CloneLink) {
return repo.cloneLink(x, false)
}

// MigrateRepoOptions contains the repository migrate options
type MigrateRepoOptions struct {
Name string
Description string
IsPrivate bool
IsMirror bool
RemoteAddr string
}

/*
GitHub, GitLab, Gogs: *.wiki.git
BitBucket: *.git/wiki
*/
var commonWikiURLSuffixes = []string{".wiki.git", ".git/wiki"}

// wikiRemoteURL returns accessible repository URL for wiki if exists.
// Otherwise, it returns an empty string.
func wikiRemoteURL(remote string) string {
remote = strings.TrimSuffix(remote, ".git")
for _, suffix := range commonWikiURLSuffixes {
wikiURL := remote + suffix
if git.IsRepoURLAccessible(wikiURL) {
return wikiURL
}
}
return ""
}

// MigrateRepository migrates a existing repository from other project hosting.
func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, error) {
repo, err := CreateRepository(doer, u, CreateRepoOptions{
Name: opts.Name,
Description: opts.Description,
IsPrivate: opts.IsPrivate,
IsMirror: opts.IsMirror,
})
if err != nil {
return nil, err
}

repoPath := RepoPath(u.Name, opts.Name)
wikiPath := WikiPath(u.Name, opts.Name)

if u.IsOrganization() {
t, err := u.GetOwnerTeam()
if err != nil {
return nil, err
}
repo.NumWatches = t.NumMembers
} else {
repo.NumWatches = 1
}

migrateTimeout := time.Duration(setting.Git.Timeout.Migrate) * time.Second

if err := os.RemoveAll(repoPath); err != nil {
return repo, fmt.Errorf("Failed to remove %s: %v", repoPath, err)
}

if err = git.Clone(opts.RemoteAddr, repoPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
}); err != nil {
return repo, fmt.Errorf("Clone: %v", err)
}

wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
if len(wikiRemotePath) > 0 {
if err := os.RemoveAll(wikiPath); err != nil {
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
}

if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
Mirror: true,
Quiet: true,
Timeout: migrateTimeout,
Branch: "master",
}); err != nil {
log.Warn("Clone wiki: %v", err)
if err := os.RemoveAll(wikiPath); err != nil {
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
}
}
}

// Check if repository is empty.
_, stderr, err := com.ExecCmdDir(repoPath, "git", "log", "-1")
if err != nil {
if strings.Contains(stderr, "fatal: bad default revision 'HEAD'") {
repo.IsEmpty = true
} else {
return repo, fmt.Errorf("check empty: %v - %s", err, stderr)
}
}

if !repo.IsEmpty {
// Try to get HEAD branch and set it as default branch.
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
return repo, fmt.Errorf("OpenRepository: %v", err)
}
headBranch, err := gitRepo.GetHEADBranch()
if err != nil {
return repo, fmt.Errorf("GetHEADBranch: %v", err)
}
if headBranch != nil {
repo.DefaultBranch = headBranch.Name
}

if err = SyncReleasesWithTags(repo, gitRepo); err != nil {
log.Error(4, "Failed to synchronize tags to releases for repository: %v", err)
}
}

if err = repo.UpdateSize(); err != nil {
log.Error(4, "Failed to update size for repository: %v", err)
}

if opts.IsMirror {
if _, err = x.InsertOne(&Mirror{
RepoID: repo.ID,
Interval: setting.Mirror.DefaultInterval,
EnablePrune: true,
NextUpdateUnix: util.TimeStampNow().AddDuration(setting.Mirror.DefaultInterval),
}); err != nil {
return repo, fmt.Errorf("InsertOne: %v", err)
}

repo.IsMirror = true
err = UpdateRepository(repo, false)
} else {
repo, err = CleanUpMigrateInfo(repo)
}

if err != nil && !repo.IsEmpty {
UpdateRepoIndexer(repo)
}

return repo, err
}

// cleanUpMigrateGitConfig removes mirror info which prevents "push --all".
// This also removes possible user credentials.
func cleanUpMigrateGitConfig(configPath string) error {
cfg, err := ini.Load(configPath)
if err != nil {
return fmt.Errorf("open config file: %v", err)
}
cfg.DeleteSection("remote \"origin\"")
if err = cfg.SaveToIndent(configPath, "\t"); err != nil {
return fmt.Errorf("save config file: %v", err)
}
return nil
}

// createDelegateHooks creates all the hooks scripts for the repo
func createDelegateHooks(repoPath string) (err error) {
var (
Expand Down Expand Up @@ -1063,30 +906,6 @@ func createDelegateHooks(repoPath string) (err error) {
return nil
}

// CleanUpMigrateInfo finishes migrating repository and/or wiki with things that don't need to be done for mirrors.
func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
repoPath := repo.RepoPath()
if err := createDelegateHooks(repoPath); err != nil {
return repo, fmt.Errorf("createDelegateHooks: %v", err)
}
if repo.HasWiki() {
if err := createDelegateHooks(repo.WikiPath()); err != nil {
return repo, fmt.Errorf("createDelegateHooks.(wiki): %v", err)
}
}

if err := cleanUpMigrateGitConfig(repo.GitConfigPath()); err != nil {
return repo, fmt.Errorf("cleanUpMigrateGitConfig: %v", err)
}
if repo.HasWiki() {
if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil {
return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err)
}
}

return repo, UpdateRepository(repo, false)
}

// initRepoCommit temporarily changes with work directory.
func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
var stderr string
Expand Down Expand Up @@ -1121,6 +940,7 @@ type CreateRepoOptions struct {
IsPrivate bool
IsMirror bool
AutoInit bool
NoWatchers bool
}

func getRepoInitFile(tp, name string) ([]byte, error) {
Expand Down Expand Up @@ -1274,7 +1094,7 @@ func IsUsableRepoName(name string) error {
return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
}

func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err error) {
func createRepository(e *xorm.Session, doer, u *User, repo *Repository, noWatchers bool) (err error) {
if err = IsUsableRepoName(repo.Name); err != nil {
return err
}
Expand Down Expand Up @@ -1360,10 +1180,12 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
return fmt.Errorf("watchRepo: %v", err)
}
}
if err = newRepoAction(e, doer, repo); err != nil {
return fmt.Errorf("newRepoAction: %v", err)
}

if !noWatchers {
if err = newRepoAction(e, doer, repo); err != nil {
return fmt.Errorf("newRepoAction: %v", err)
}
}
return nil
}

Expand All @@ -1390,7 +1212,7 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
return nil, err
}

if err = createRepository(sess, doer, u, repo); err != nil {
if err = createRepository(sess, doer, u, repo, opts.NoWatchers); err != nil {
return nil, err
}

Expand Down Expand Up @@ -2422,7 +2244,7 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
return nil, err
}

if err = createRepository(sess, doer, u, repo); err != nil {
if err = createRepository(sess, doer, u, repo, true); err != nil {
return nil, err
}

Expand Down
Loading