Skip to content

Commit ca6c52b

Browse files
committed
Improve migration API
1 parent 4d0535c commit ca6c52b

File tree

4 files changed

+68
-64
lines changed

4 files changed

+68
-64
lines changed

routers/api/v1/api.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,10 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
728728

729729
m.Get("/issues/search", repo.SearchIssues)
730730

731-
m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate)
731+
m.Group("/migrate", func() {
732+
m.Post("", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate)
733+
m.Get("/status", repo.GetMigratingTask)
734+
})
732735

733736
m.Group("/{username}/{reponame}", func() {
734737
m.Combo("").Get(reqAnyRepoReader(), repo.Get).

routers/api/v1/repo/migrate.go

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
package repo
66

77
import (
8-
"bytes"
9-
"errors"
108
"fmt"
119
"net/http"
1210
"strings"
@@ -18,18 +16,16 @@ import (
1816
user_model "code.gitea.io/gitea/models/user"
1917
"code.gitea.io/gitea/modules/context"
2018
"code.gitea.io/gitea/modules/convert"
21-
"code.gitea.io/gitea/modules/graceful"
2219
"code.gitea.io/gitea/modules/lfs"
2320
"code.gitea.io/gitea/modules/log"
2421
base "code.gitea.io/gitea/modules/migration"
25-
"code.gitea.io/gitea/modules/notification"
26-
repo_module "code.gitea.io/gitea/modules/repository"
2722
"code.gitea.io/gitea/modules/setting"
2823
api "code.gitea.io/gitea/modules/structs"
2924
"code.gitea.io/gitea/modules/util"
3025
"code.gitea.io/gitea/modules/web"
3126
"code.gitea.io/gitea/services/forms"
3227
"code.gitea.io/gitea/services/migrations"
28+
"code.gitea.io/gitea/services/task"
3329
)
3430

3531
// Migrate migrate remote git repository to gitea
@@ -141,6 +137,7 @@ func Migrate(ctx *context.APIContext) {
141137
CloneAddr: remoteAddr,
142138
RepoName: form.RepoName,
143139
Description: form.Description,
140+
OriginalURL: form.CloneAddr,
144141
Private: form.Private || setting.Repository.ForcePrivate,
145142
Mirror: form.Mirror,
146143
LFS: form.LFS,
@@ -149,7 +146,7 @@ func Migrate(ctx *context.APIContext) {
149146
AuthPassword: form.AuthPassword,
150147
AuthToken: form.AuthToken,
151148
Wiki: form.Wiki,
152-
Issues: form.Issues,
149+
Issues: form.Issues || form.PullRequests,
153150
Milestones: form.Milestones,
154151
Labels: form.Labels,
155152
Comments: true,
@@ -167,63 +164,33 @@ func Migrate(ctx *context.APIContext) {
167164
opts.Releases = false
168165
}
169166

170-
repo, err := repo_module.CreateRepository(ctx.User, repoOwner, models.CreateRepoOptions{
171-
Name: opts.RepoName,
172-
Description: opts.Description,
173-
OriginalURL: form.CloneAddr,
174-
GitServiceType: gitServiceType,
175-
IsPrivate: opts.Private,
176-
IsMirror: opts.Mirror,
177-
Status: repo_model.RepositoryBeingMigrated,
178-
})
179-
if err != nil {
180-
handleMigrateError(ctx, repoOwner, remoteAddr, err)
167+
if err = repo_model.CheckCreateRepository(ctx.User, repoOwner, opts.RepoName, false); err != nil {
168+
handleMigrateError(ctx, repoOwner, &opts, err)
181169
return
182170
}
183171

184-
opts.MigrateToRepoID = repo.ID
185-
186-
defer func() {
187-
if e := recover(); e != nil {
188-
var buf bytes.Buffer
189-
fmt.Fprintf(&buf, "Handler crashed with error: %v", log.Stack(2))
190-
191-
err = errors.New(buf.String())
192-
}
193-
194-
if err == nil {
195-
notification.NotifyMigrateRepository(ctx.User, repoOwner, repo)
196-
return
197-
}
198-
199-
if repo != nil {
200-
if errDelete := models.DeleteRepository(ctx.User, repoOwner.ID, repo.ID); errDelete != nil {
201-
log.Error("DeleteRepository: %v", errDelete)
202-
}
203-
}
204-
}()
205-
206-
if repo, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.User, repoOwner.Name, opts, nil); err != nil {
207-
handleMigrateError(ctx, repoOwner, remoteAddr, err)
172+
repo, err := task.MigrateRepository(ctx.User, repoOwner, opts)
173+
if err == nil {
174+
log.Trace("Repository migrated: %s/%s", repoOwner.Name, form.RepoName)
175+
ctx.JSON(http.StatusCreated, convert.ToRepo(repo, perm.AccessModeAdmin))
208176
return
209177
}
210178

211-
log.Trace("Repository migrated: %s/%s", repoOwner.Name, form.RepoName)
212-
ctx.JSON(http.StatusCreated, convert.ToRepo(repo, perm.AccessModeAdmin))
179+
handleMigrateError(ctx, repoOwner, &opts, err)
213180
}
214181

215-
func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, remoteAddr string, err error) {
182+
func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, migrationOpts *migrations.MigrateOptions, err error) {
216183
switch {
217-
case repo_model.IsErrRepoAlreadyExist(err):
218-
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
219-
case repo_model.IsErrRepoFilesAlreadyExist(err):
220-
ctx.Error(http.StatusConflict, "", "Files already exist for this repository. Adopt them or delete them.")
221184
case migrations.IsRateLimitError(err):
222185
ctx.Error(http.StatusUnprocessableEntity, "", "Remote visit addressed rate limitation.")
223186
case migrations.IsTwoFactorAuthError(err):
224187
ctx.Error(http.StatusUnprocessableEntity, "", "Remote visit required two factors authentication.")
225188
case repo_model.IsErrReachLimitOfRepo(err):
226189
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit()))
190+
case repo_model.IsErrRepoAlreadyExist(err):
191+
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
192+
case repo_model.IsErrRepoFilesAlreadyExist(err):
193+
ctx.Error(http.StatusConflict, "", "Files already exist for this repository. Adopt them or delete them.")
227194
case db.IsErrNameReserved(err):
228195
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' is reserved.", err.(db.ErrNameReserved).Name))
229196
case db.IsErrNameCharsNotAllowed(err):
@@ -235,6 +202,7 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, rem
235202
case base.IsErrNotSupported(err):
236203
ctx.Error(http.StatusUnprocessableEntity, "", err)
237204
default:
205+
remoteAddr, _ := forms.ParseRemoteAddr(migrationOpts.CloneAddr, migrationOpts.AuthUsername, migrationOpts.AuthPassword)
238206
err = util.NewStringURLSanitizedError(err, remoteAddr, true)
239207
if strings.Contains(err.Error(), "Authentication failed") ||
240208
strings.Contains(err.Error(), "Bad credentials") ||
@@ -269,3 +237,36 @@ func handleRemoteAddrError(ctx *context.APIContext, err error) {
269237
ctx.Error(http.StatusInternalServerError, "ParseRemoteAddr", err)
270238
}
271239
}
240+
241+
// GetMigratingTask returns the migrating task by repo's id
242+
func GetMigratingTask(ctx *context.APIContext) {
243+
// swagger:operation GET /repos/migrate/status task
244+
// ---
245+
// summary: Get the migration status of a repository by its id
246+
// produces:
247+
// - application/json
248+
// parameters:
249+
// - name: repo_id
250+
// in: query
251+
// description: repository id
252+
// type: int64
253+
// responses:
254+
// "200":
255+
// "$ref": "#/responses/"
256+
// "404":
257+
// "$ref": "#/response/"
258+
t, err := models.GetMigratingTask(ctx.FormInt64("repo_id"))
259+
260+
if err != nil {
261+
ctx.JSON(http.StatusNotFound, err)
262+
return
263+
}
264+
265+
ctx.JSON(200, map[string]interface{}{
266+
"status": t.Status,
267+
"err": t.Message,
268+
"repo-id": t.RepoID,
269+
"start": t.StartTime,
270+
"end": t.EndTime,
271+
})
272+
}

routers/web/repo/migrate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ func MigratePost(ctx *context.Context) {
239239
return
240240
}
241241

242-
err = task.MigrateRepository(ctx.User, ctxUser, opts)
242+
_, err = task.MigrateRepository(ctx.User, ctxUser, opts)
243243
if err == nil {
244244
ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(opts.RepoName))
245245
return

services/task/task.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,37 +60,37 @@ func handle(data ...queue.Data) []queue.Data {
6060
}
6161

6262
// MigrateRepository add migration repository to task
63-
func MigrateRepository(doer, u *user_model.User, opts base.MigrateOptions) error {
64-
task, err := CreateMigrateTask(doer, u, opts)
63+
func MigrateRepository(doer, u *user_model.User, opts base.MigrateOptions) (*repo_model.Repository, error) {
64+
task, repo, err := createMigrationTask(doer, u, opts)
6565
if err != nil {
66-
return err
66+
return repo, err
6767
}
6868

69-
return taskQueue.Push(task)
69+
return repo, taskQueue.Push(task)
7070
}
7171

72-
// CreateMigrateTask creates a migrate task
73-
func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*models.Task, error) {
72+
// createMigrationTask creates a migrate task
73+
func createMigrationTask(doer, u *user_model.User, opts base.MigrateOptions) (*models.Task, *repo_model.Repository, error) {
7474
// encrypt credentials for persistence
7575
var err error
7676
opts.CloneAddrEncrypted, err = secret.EncryptSecret(setting.SecretKey, opts.CloneAddr)
7777
if err != nil {
78-
return nil, err
78+
return nil, nil, err
7979
}
8080
opts.CloneAddr = util.NewStringURLSanitizer(opts.CloneAddr, true).Replace(opts.CloneAddr)
8181
opts.AuthPasswordEncrypted, err = secret.EncryptSecret(setting.SecretKey, opts.AuthPassword)
8282
if err != nil {
83-
return nil, err
83+
return nil, nil, err
8484
}
8585
opts.AuthPassword = ""
8686
opts.AuthTokenEncrypted, err = secret.EncryptSecret(setting.SecretKey, opts.AuthToken)
8787
if err != nil {
88-
return nil, err
88+
return nil, nil, err
8989
}
9090
opts.AuthToken = ""
9191
bs, err := json.Marshal(&opts)
9292
if err != nil {
93-
return nil, err
93+
return nil, nil, err
9494
}
9595

9696
task := &models.Task{
@@ -102,7 +102,7 @@ func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*mod
102102
}
103103

104104
if err := models.CreateTask(task); err != nil {
105-
return nil, err
105+
return nil, nil, err
106106
}
107107

108108
repo, err := repo_module.CreateRepository(doer, u, models.CreateRepoOptions{
@@ -121,13 +121,13 @@ func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*mod
121121
if err2 != nil {
122122
log.Error("UpdateCols Failed: %v", err2.Error())
123123
}
124-
return nil, err
124+
return nil, nil, err
125125
}
126126

127127
task.RepoID = repo.ID
128128
if err = task.UpdateCols("repo_id"); err != nil {
129-
return nil, err
129+
return nil, repo, err
130130
}
131131

132-
return task, nil
132+
return task, repo, nil
133133
}

0 commit comments

Comments
 (0)