Skip to content

Commit e153cf0

Browse files
lunnya1012112796techknowlogick
authored
Add a migrate service type switch page (#12697)
* Add a migrat service type switch page * Improve translations * remove images * Fix images * remove extra create repo button on dashboard * Follow reviewers' opinions * Fix frontend lint * Remove wrong submit file * Fix tests * Adjust the size of image * Apply suggestions from code review Co-authored-by: 赵智超 <[email protected]> * Remove username and password from migration of github/gitlab * Improve docs * Improve interface docs Co-authored-by: 赵智超 <[email protected]> Co-authored-by: techknowlogick <[email protected]>
1 parent 6483dbc commit e153cf0

File tree

21 files changed

+481
-209
lines changed

21 files changed

+481
-209
lines changed

integrations/repo_migrate_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
package integrations
66

77
import (
8+
"fmt"
89
"net/http"
910
"net/http/httptest"
1011
"testing"
1112

13+
"code.gitea.io/gitea/modules/structs"
1214
"github.com/stretchr/testify/assert"
1315
)
1416

1517
func testRepoMigrate(t testing.TB, session *TestSession, cloneAddr, repoName string) *httptest.ResponseRecorder {
16-
req := NewRequest(t, "GET", "/repo/migrate")
18+
req := NewRequest(t, "GET", fmt.Sprintf("/repo/migrate?service_type=%d", structs.PlainGitService)) // render plain git migration page
1719
resp := session.MakeRequest(t, req, http.StatusOK)
1820
htmlDoc := NewHTMLParser(t, resp.Body)
1921

@@ -28,8 +30,8 @@ func testRepoMigrate(t testing.TB, session *TestSession, cloneAddr, repoName str
2830
"clone_addr": cloneAddr,
2931
"uid": uid,
3032
"repo_name": repoName,
31-
},
32-
)
33+
"service": fmt.Sprintf("%d", structs.PlainGitService),
34+
})
3335
resp = session.MakeRequest(t, req, http.StatusFound)
3436

3537
return resp

modules/structs/repo.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package structs
66

77
import (
8+
"strings"
89
"time"
910
)
1011

@@ -205,17 +206,7 @@ const (
205206
// Name represents the service type's name
206207
// WARNNING: the name have to be equal to that on goth's library
207208
func (gt GitServiceType) Name() string {
208-
switch gt {
209-
case GithubService:
210-
return "github"
211-
case GiteaService:
212-
return "gitea"
213-
case GitlabService:
214-
return "gitlab"
215-
case GogsService:
216-
return "gogs"
217-
}
218-
return ""
209+
return strings.ToLower(gt.Title())
219210
}
220211

221212
// Title represents the service type's proper title

options/locale/locale_en-US.ini

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ migrate_items_milestones = Milestones
720720
migrate_items_labels = Labels
721721
migrate_items_issues = Issues
722722
migrate_items_pullrequests = Pull Requests
723+
migrate_items_merge_requests = Merge Requests
723724
migrate_items_releases = Releases
724725
migrate_repo = Migrate Repository
725726
migrate.clone_address = Migrate / Clone From URL
@@ -729,11 +730,15 @@ migrate.permission_denied = You are not allowed to import local repositories.
729730
migrate.invalid_local_path = "The local path is invalid. It does not exist or is not a directory."
730731
migrate.failed = Migration failed: %v
731732
migrate.lfs_mirror_unsupported = Mirroring LFS objects is not supported - use 'git lfs fetch --all' and 'git lfs push --all' instead.
732-
migrate.migrate_items_options = Authentication is needed to migrate items from a service that supports them.
733+
migrate.migrate_items_options = Access Token is required to migrate additional items
733734
migrated_from = Migrated from <a href="%[1]s">%[2]s</a>
734735
migrated_from_fake = Migrated From %[1]s
736+
migrate.migrate = Migrate From %s
735737
migrate.migrating = Migrating from <b>%s</b> ...
736738
migrate.migrating_failed = Migrating from <b>%s</b> failed.
739+
migrate.github.description = Migrating data from Github.com or Github Enterprise.
740+
migrate.git.description = Migrating or Mirroring git data from Git services
741+
migrate.gitlab.description = Migrating data from GitLab.com or Self-Hosted gitlab server.
737742

738743
mirror_from = mirror of
739744
forked_from = forked from

public/img/svg/gitea-git.svg

Lines changed: 1 addition & 0 deletions
Loading

public/img/svg/gitea-github.svg

Lines changed: 1 addition & 0 deletions
Loading

public/img/svg/gitea-gitlab.svg

Lines changed: 1 addition & 0 deletions
Loading

routers/repo/migrate.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// Copyright 2014 The Gogs Authors. All rights reserved.
2+
// Copyright 2020 The Gitea Authors. All rights reserved.
3+
// Use of this source code is governed by a MIT-style
4+
// license that can be found in the LICENSE file.
5+
6+
package repo
7+
8+
import (
9+
"strings"
10+
11+
"code.gitea.io/gitea/models"
12+
"code.gitea.io/gitea/modules/auth"
13+
"code.gitea.io/gitea/modules/base"
14+
"code.gitea.io/gitea/modules/context"
15+
"code.gitea.io/gitea/modules/migrations"
16+
"code.gitea.io/gitea/modules/setting"
17+
"code.gitea.io/gitea/modules/structs"
18+
"code.gitea.io/gitea/modules/task"
19+
"code.gitea.io/gitea/modules/util"
20+
)
21+
22+
const (
23+
tplMigrate base.TplName = "repo/migrate/migrate"
24+
)
25+
26+
// Migrate render migration of repository page
27+
func Migrate(ctx *context.Context) {
28+
ctx.Data["Services"] = append([]structs.GitServiceType{structs.PlainGitService}, structs.SupportedFullGitService...)
29+
serviceType := ctx.QueryInt("service_type")
30+
if serviceType == 0 {
31+
ctx.HTML(200, tplMigrate)
32+
return
33+
}
34+
35+
ctx.Data["Title"] = ctx.Tr("new_migrate")
36+
ctx.Data["private"] = getRepoPrivate(ctx)
37+
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
38+
ctx.Data["DisableMirrors"] = setting.Repository.DisableMirrors
39+
ctx.Data["mirror"] = ctx.Query("mirror") == "1"
40+
ctx.Data["wiki"] = ctx.Query("wiki") == "1"
41+
ctx.Data["milestones"] = ctx.Query("milestones") == "1"
42+
ctx.Data["labels"] = ctx.Query("labels") == "1"
43+
ctx.Data["issues"] = ctx.Query("issues") == "1"
44+
ctx.Data["pull_requests"] = ctx.Query("pull_requests") == "1"
45+
ctx.Data["releases"] = ctx.Query("releases") == "1"
46+
ctx.Data["LFSActive"] = setting.LFS.StartServer
47+
// Plain git should be first
48+
ctx.Data["service"] = structs.GitServiceType(serviceType)
49+
50+
ctxUser := checkContextUser(ctx, ctx.QueryInt64("org"))
51+
if ctx.Written() {
52+
return
53+
}
54+
ctx.Data["ContextUser"] = ctxUser
55+
56+
ctx.HTML(200, base.TplName("repo/migrate/"+structs.GitServiceType(serviceType).Name()))
57+
}
58+
59+
func handleMigrateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form *auth.MigrateRepoForm) {
60+
switch {
61+
case migrations.IsRateLimitError(err):
62+
ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form)
63+
case migrations.IsTwoFactorAuthError(err):
64+
ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form)
65+
case models.IsErrReachLimitOfRepo(err):
66+
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
67+
case models.IsErrRepoAlreadyExist(err):
68+
ctx.Data["Err_RepoName"] = true
69+
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
70+
case models.IsErrNameReserved(err):
71+
ctx.Data["Err_RepoName"] = true
72+
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form)
73+
case models.IsErrNamePatternNotAllowed(err):
74+
ctx.Data["Err_RepoName"] = true
75+
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
76+
default:
77+
remoteAddr, _ := form.ParseRemoteAddr(owner)
78+
err = util.URLSanitizedError(err, remoteAddr)
79+
if strings.Contains(err.Error(), "Authentication failed") ||
80+
strings.Contains(err.Error(), "Bad credentials") ||
81+
strings.Contains(err.Error(), "could not read Username") {
82+
ctx.Data["Err_Auth"] = true
83+
ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tpl, form)
84+
} else if strings.Contains(err.Error(), "fatal:") {
85+
ctx.Data["Err_CloneAddr"] = true
86+
ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tpl, form)
87+
} else {
88+
ctx.ServerError(name, err)
89+
}
90+
}
91+
}
92+
93+
// MigratePost response for migrating from external git repository
94+
func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
95+
ctx.Data["Title"] = ctx.Tr("new_migrate")
96+
// Plain git should be first
97+
ctx.Data["service"] = form.Service
98+
ctx.Data["Services"] = append([]structs.GitServiceType{structs.PlainGitService}, structs.SupportedFullGitService...)
99+
100+
ctxUser := checkContextUser(ctx, form.UID)
101+
if ctx.Written() {
102+
return
103+
}
104+
ctx.Data["ContextUser"] = ctxUser
105+
106+
if ctx.HasError() {
107+
ctx.HTML(200, tplMigrate)
108+
return
109+
}
110+
111+
remoteAddr, err := form.ParseRemoteAddr(ctx.User)
112+
if err != nil {
113+
if models.IsErrInvalidCloneAddr(err) {
114+
ctx.Data["Err_CloneAddr"] = true
115+
addrErr := err.(models.ErrInvalidCloneAddr)
116+
switch {
117+
case addrErr.IsURLError:
118+
ctx.RenderWithErr(ctx.Tr("form.url_error"), tplMigrate, &form)
119+
case addrErr.IsPermissionDenied:
120+
ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplMigrate, &form)
121+
case addrErr.IsInvalidPath:
122+
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplMigrate, &form)
123+
default:
124+
ctx.ServerError("Unknown error", err)
125+
}
126+
} else {
127+
ctx.ServerError("ParseRemoteAddr", err)
128+
}
129+
return
130+
}
131+
132+
var opts = migrations.MigrateOptions{
133+
OriginalURL: form.CloneAddr,
134+
GitServiceType: structs.GitServiceType(form.Service),
135+
CloneAddr: remoteAddr,
136+
RepoName: form.RepoName,
137+
Description: form.Description,
138+
Private: form.Private || setting.Repository.ForcePrivate,
139+
Mirror: form.Mirror && !setting.Repository.DisableMirrors,
140+
AuthUsername: form.AuthUsername,
141+
AuthPassword: form.AuthPassword,
142+
AuthToken: form.AuthToken,
143+
Wiki: form.Wiki,
144+
Issues: form.Issues,
145+
Milestones: form.Milestones,
146+
Labels: form.Labels,
147+
Comments: form.Issues || form.PullRequests,
148+
PullRequests: form.PullRequests,
149+
Releases: form.Releases,
150+
}
151+
if opts.Mirror {
152+
opts.Issues = false
153+
opts.Milestones = false
154+
opts.Labels = false
155+
opts.Comments = false
156+
opts.PullRequests = false
157+
opts.Releases = false
158+
}
159+
160+
err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName)
161+
if err != nil {
162+
handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form)
163+
return
164+
}
165+
166+
err = task.MigrateRepository(ctx.User, ctxUser, opts)
167+
if err == nil {
168+
ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + opts.RepoName)
169+
return
170+
}
171+
172+
handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form)
173+
}

0 commit comments

Comments
 (0)