[API] Migration: Change ServiceType String (#12672)

* use different structs for MigrateRepoOptions on UI and API

* Fix TokenAuth and rename UID to an understandable Name

* fix swagger doc

* simplify & mk redable

* R E F A C T O R:
migration has now internal 3 structs to store its options:
 * the Options for WebUI: modules/auth/repo_form.go
 * the Options for API: modules/structs/repo.go
 * the option struct with after validation for internal prossessing: modules/migrations/base/options.go

* Copyright Header

* Deprecate UID - add RepoOwner

* adopt repo.go -> migrate.go

* add comment about each struct purpose

* lint
This commit is contained in:
6543 2020-09-11 00:29:19 +02:00 committed by GitHub
parent daefdd1385
commit fd60ebfe14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 230 additions and 87 deletions

View file

@ -316,10 +316,10 @@ func TestAPIRepoMigrate(t *testing.T) {
user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User) user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
session := loginUser(t, user.Name) session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session) token := getTokenForLoggedInUser(t, session)
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOption{ req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOptions{
CloneAddr: testCase.cloneURL, CloneAddr: testCase.cloneURL,
UID: int(testCase.userID), RepoOwnerID: testCase.userID,
RepoName: testCase.repoName, RepoName: testCase.repoName,
}) })
resp := MakeRequest(t, req, NoExpectedStatus) resp := MakeRequest(t, req, NoExpectedStatus)
if resp.Code == http.StatusUnprocessableEntity { if resp.Code == http.StatusUnprocessableEntity {
@ -360,10 +360,10 @@ func testAPIRepoMigrateConflict(t *testing.T, u *url.URL) {
cloneURL := "https://github.com/go-gitea/test_repo.git" cloneURL := "https://github.com/go-gitea/test_repo.git"
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+httpContext.Token, req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+httpContext.Token,
&api.MigrateRepoOption{ &api.MigrateRepoOptions{
CloneAddr: cloneURL, CloneAddr: cloneURL,
UID: int(userID), RepoOwnerID: userID,
RepoName: httpContext.Reponame, RepoName: httpContext.Reponame,
}) })
resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict) resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict)
respJSON := map[string]string{} respJSON := map[string]string{}

View file

@ -8,6 +8,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
migration "code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
@ -101,9 +102,9 @@ func (task *Task) UpdateCols(cols ...string) error {
} }
// MigrateConfig returns task config when migrate repository // MigrateConfig returns task config when migrate repository
func (task *Task) MigrateConfig() (*structs.MigrateRepoOption, error) { func (task *Task) MigrateConfig() (*migration.MigrateOptions, error) {
if task.Type == structs.TaskTypeMigrateRepo { if task.Type == structs.TaskTypeMigrateRepo {
var opts structs.MigrateRepoOption var opts migration.MigrateOptions
err := json.Unmarshal([]byte(task.PayloadContent), &opts) err := json.Unmarshal([]byte(task.PayloadContent), &opts)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -53,6 +53,7 @@ func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
} }
// MigrateRepoForm form for migrating repository // MigrateRepoForm form for migrating repository
// this is used to interact with web ui
type MigrateRepoForm struct { type MigrateRepoForm struct {
// required: true // required: true
CloneAddr string `json:"clone_addr" binding:"Required"` CloneAddr string `json:"clone_addr" binding:"Required"`
@ -84,9 +85,8 @@ func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
// and returns composed URL with needed username and password. // and returns composed URL with needed username and password.
// It also checks if given user has permission when remote address // It also checks if given user has permission when remote address
// is actually a local path. // is actually a local path.
func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) { func ParseRemoteAddr(remoteAddr, authUsername, authPassword string, user *models.User) (string, error) {
remoteAddr := strings.TrimSpace(f.CloneAddr) remoteAddr = strings.TrimSpace(remoteAddr)
// Remote address can be HTTP/HTTPS/Git URL or local path. // Remote address can be HTTP/HTTPS/Git URL or local path.
if strings.HasPrefix(remoteAddr, "http://") || if strings.HasPrefix(remoteAddr, "http://") ||
strings.HasPrefix(remoteAddr, "https://") || strings.HasPrefix(remoteAddr, "https://") ||
@ -95,8 +95,8 @@ func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
if err != nil { if err != nil {
return "", models.ErrInvalidCloneAddr{IsURLError: true} return "", models.ErrInvalidCloneAddr{IsURLError: true}
} }
if len(f.AuthUsername)+len(f.AuthPassword) > 0 { if len(authUsername)+len(authPassword) > 0 {
u.User = url.UserPassword(f.AuthUsername, f.AuthPassword) u.User = url.UserPassword(authUsername, authPassword)
} }
remoteAddr = u.String() remoteAddr = u.String()
} else if !user.CanImportLocal() { } else if !user.CanImportLocal() {

View file

@ -1,3 +1,4 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Copyright 2016 The Gogs Authors. All rights reserved. // Copyright 2016 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -5,7 +6,10 @@
package convert package convert
import ( import (
"strings"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
) )
// ToCorrectPageSize makes sure page size is in allowed range. // ToCorrectPageSize makes sure page size is in allowed range.
@ -17,3 +21,19 @@ func ToCorrectPageSize(size int) int {
} }
return size return size
} }
// ToGitServiceType return GitServiceType based on string
func ToGitServiceType(value string) structs.GitServiceType {
switch strings.ToLower(value) {
case "github":
return structs.GithubService
case "gitea":
return structs.GiteaService
case "gitlab":
return structs.GitlabService
case "gogs":
return structs.GogsService
default:
return structs.PlainGitService
}
}

View file

@ -8,4 +8,28 @@ package base
import "code.gitea.io/gitea/modules/structs" import "code.gitea.io/gitea/modules/structs"
// MigrateOptions defines the way a repository gets migrated // MigrateOptions defines the way a repository gets migrated
type MigrateOptions = structs.MigrateRepoOption // this is for internal usage by migrations module and func who interact with it
type MigrateOptions struct {
// required: true
CloneAddr string `json:"clone_addr" binding:"Required"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
AuthToken string `json:"auth_token"`
// required: true
UID int `json:"uid" binding:"Required"`
// required: true
RepoName string `json:"repo_name" binding:"Required"`
Mirror bool `json:"mirror"`
Private bool `json:"private"`
Description string `json:"description"`
OriginalURL string
GitServiceType structs.GitServiceType
Wiki bool
Issues bool
Milestones bool
Labels bool
Releases bool
Comments bool
PullRequests bool
MigrateToRepoID int64
}

View file

@ -123,7 +123,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
return err return err
} }
r, err = repository.MigrateRepositoryGitData(g.doer, owner, r, structs.MigrateRepoOption{ r, err = repository.MigrateRepositoryGitData(g.doer, owner, r, base.MigrateOptions{
RepoName: g.repoName, RepoName: g.repoName,
Description: repo.Description, Description: repo.Description,
OriginalURL: repo.OriginalURL, OriginalURL: repo.OriginalURL,

View file

@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -32,7 +33,7 @@ func TestGiteaUploadRepo(t *testing.T) {
uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName) uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName)
) )
err := migrateRepository(downloader, uploader, structs.MigrateRepoOption{ err := migrateRepository(downloader, uploader, base.MigrateOptions{
CloneAddr: "https://github.com/go-xorm/builder", CloneAddr: "https://github.com/go-xorm/builder",
RepoName: repoName, RepoName: repoName,
AuthUsername: "", AuthUsername: "",

View file

@ -13,8 +13,8 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
migration "code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -41,7 +41,7 @@ func WikiRemoteURL(remote string) string {
} }
// MigrateRepositoryGitData starts migrating git related data after created migrating repository // MigrateRepositoryGitData starts migrating git related data after created migrating repository
func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opts api.MigrateRepoOption) (*models.Repository, error) { func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opts migration.MigrateOptions) (*models.Repository, error) {
repoPath := models.RepoPath(u.Name, opts.RepoName) repoPath := models.RepoPath(u.Name, opts.RepoName)
if u.IsOrganization() { if u.IsOrganization() {

View file

@ -226,6 +226,35 @@ func (gt GitServiceType) Title() string {
return "" return ""
} }
// MigrateRepoOptions options for migrating repository's
// this is used to interact with api v1
type MigrateRepoOptions struct {
// required: true
CloneAddr string `json:"clone_addr" binding:"Required"`
// deprecated (only for backwards compatibility)
RepoOwnerID int64 `json:"uid"`
// Name of User or Organisation who will own Repo after migration
RepoOwner string `json:"repo_owner"`
// required: true
RepoName string `json:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
// enum: git,github,gitea,gitlab
Service string `json:"service"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
AuthToken string `json:"auth_token"`
Mirror bool `json:"mirror"`
Private bool `json:"private"`
Description string `json:"description" binding:"MaxSize(255)"`
Wiki bool `json:"wiki"`
Milestones bool `json:"milestones"`
Labels bool `json:"labels"`
Issues bool `json:"issues"`
PullRequests bool `json:"pull_requests"`
Releases bool `json:"releases"`
}
// TokenAuth represents whether a service type supports token-based auth // TokenAuth represents whether a service type supports token-based auth
func (gt GitServiceType) TokenAuth() bool { func (gt GitServiceType) TokenAuth() bool {
switch gt { switch gt {
@ -243,29 +272,3 @@ var (
GitlabService, GitlabService,
} }
) )
// MigrateRepoOption options for migrating a repository from an external service
type MigrateRepoOption struct {
// required: true
CloneAddr string `json:"clone_addr" binding:"Required"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
AuthToken string `json:"auth_token"`
// required: true
UID int `json:"uid" binding:"Required"`
// required: true
RepoName string `json:"repo_name" binding:"Required"`
Mirror bool `json:"mirror"`
Private bool `json:"private"`
Description string `json:"description"`
OriginalURL string
GitServiceType GitServiceType
Wiki bool
Issues bool
Milestones bool
Labels bool
Releases bool
Comments bool
PullRequests bool
MigrateToRepoID int64
}

View file

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/migrations"
migration "code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
@ -89,7 +90,7 @@ func runMigrateTask(t *models.Task) (err error) {
return err return err
} }
var opts *structs.MigrateRepoOption var opts *migration.MigrateOptions
opts, err = t.MigrateConfig() opts, err = t.MigrateConfig()
if err != nil { if err != nil {
return err return err

View file

@ -636,7 +636,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/issues/search", repo.SearchIssues) m.Get("/issues/search", repo.SearchIssues)
m.Post("/migrate", reqToken(), bind(auth.MigrateRepoForm{}), repo.Migrate) m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate)
m.Group("/:username/:reponame", func() { m.Group("/:username/:reponame", func() {
m.Combo("").Get(reqAnyRepoReader(), repo.Get). m.Combo("").Get(reqAnyRepoReader(), repo.Get).

View file

@ -9,12 +9,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/migrations" "code.gitea.io/gitea/modules/migrations"
@ -26,7 +26,7 @@ import (
) )
// Migrate migrate remote git repository to gitea // Migrate migrate remote git repository to gitea
func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { func Migrate(ctx *context.APIContext, form api.MigrateRepoOptions) {
// swagger:operation POST /repos/migrate repository repoMigrate // swagger:operation POST /repos/migrate repository repoMigrate
// --- // ---
// summary: Migrate a remote git repository // summary: Migrate a remote git repository
@ -38,7 +38,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
// - name: body // - name: body
// in: body // in: body
// schema: // schema:
// "$ref": "#/definitions/MigrateRepoForm" // "$ref": "#/definitions/MigrateRepoOptions"
// responses: // responses:
// "201": // "201":
// "$ref": "#/responses/Repository" // "$ref": "#/responses/Repository"
@ -47,20 +47,25 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
// "422": // "422":
// "$ref": "#/responses/validationError" // "$ref": "#/responses/validationError"
ctxUser := ctx.User //get repoOwner
// Not equal means context user is an organization, var (
// or is another user/organization if current user is admin. repoOwner *models.User
if form.UID != ctxUser.ID { err error
org, err := models.GetUserByID(form.UID) )
if err != nil { if len(form.RepoOwner) != 0 {
if models.IsErrUserNotExist(err) { repoOwner, err = models.GetUserByName(form.RepoOwner)
ctx.Error(http.StatusUnprocessableEntity, "", err) } else if form.RepoOwnerID != 0 {
} else { repoOwner, err = models.GetUserByID(form.RepoOwnerID)
ctx.Error(http.StatusInternalServerError, "GetUserByID", err) } else {
} repoOwner = ctx.User
return }
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(http.StatusInternalServerError, "GetUser", err)
} }
ctxUser = org return
} }
if ctx.HasError() { if ctx.HasError() {
@ -69,14 +74,14 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
} }
if !ctx.User.IsAdmin { if !ctx.User.IsAdmin {
if !ctxUser.IsOrganization() && ctx.User.ID != ctxUser.ID { if !repoOwner.IsOrganization() && ctx.User.ID != repoOwner.ID {
ctx.Error(http.StatusForbidden, "", "Given user is not an organization.") ctx.Error(http.StatusForbidden, "", "Given user is not an organization.")
return return
} }
if ctxUser.IsOrganization() { if repoOwner.IsOrganization() {
// Check ownership of organization. // Check ownership of organization.
isOwner, err := ctxUser.IsOwnedBy(ctx.User.ID) isOwner, err := repoOwner.IsOwnedBy(ctx.User.ID)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "IsOwnedBy", err) ctx.Error(http.StatusInternalServerError, "IsOwnedBy", err)
return return
@ -87,7 +92,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
} }
} }
remoteAddr, err := form.ParseRemoteAddr(ctx.User) remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, ctx.User)
if err != nil { if err != nil {
if models.IsErrInvalidCloneAddr(err) { if models.IsErrInvalidCloneAddr(err) {
addrErr := err.(models.ErrInvalidCloneAddr) addrErr := err.(models.ErrInvalidCloneAddr)
@ -107,11 +112,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
return return
} }
var gitServiceType = api.PlainGitService gitServiceType := convert.ToGitServiceType(form.Service)
u, err := url.Parse(remoteAddr)
if err == nil && strings.EqualFold(u.Host, "github.com") {
gitServiceType = api.GithubService
}
if form.Mirror && setting.Repository.DisableMirrors { if form.Mirror && setting.Repository.DisableMirrors {
ctx.Error(http.StatusForbidden, "MirrorsGlobalDisabled", fmt.Errorf("the site administrator has disabled mirrors")) ctx.Error(http.StatusForbidden, "MirrorsGlobalDisabled", fmt.Errorf("the site administrator has disabled mirrors"))
@ -126,6 +127,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
Mirror: form.Mirror, Mirror: form.Mirror,
AuthUsername: form.AuthUsername, AuthUsername: form.AuthUsername,
AuthPassword: form.AuthPassword, AuthPassword: form.AuthPassword,
AuthToken: form.AuthToken,
Wiki: form.Wiki, Wiki: form.Wiki,
Issues: form.Issues, Issues: form.Issues,
Milestones: form.Milestones, Milestones: form.Milestones,
@ -144,7 +146,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
opts.Releases = false opts.Releases = false
} }
repo, err := repo_module.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{ repo, err := repo_module.CreateRepository(ctx.User, repoOwner, models.CreateRepoOptions{
Name: opts.RepoName, Name: opts.RepoName,
Description: opts.Description, Description: opts.Description,
OriginalURL: form.CloneAddr, OriginalURL: form.CloneAddr,
@ -154,7 +156,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
Status: models.RepositoryBeingMigrated, Status: models.RepositoryBeingMigrated,
}) })
if err != nil { if err != nil {
handleMigrateError(ctx, ctxUser, remoteAddr, err) handleMigrateError(ctx, repoOwner, remoteAddr, err)
return return
} }
@ -171,24 +173,24 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
if err == nil { if err == nil {
repo.Status = models.RepositoryReady repo.Status = models.RepositoryReady
if err := models.UpdateRepositoryCols(repo, "status"); err == nil { if err := models.UpdateRepositoryCols(repo, "status"); err == nil {
notification.NotifyMigrateRepository(ctx.User, ctxUser, repo) notification.NotifyMigrateRepository(ctx.User, repoOwner, repo)
return return
} }
} }
if repo != nil { if repo != nil {
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil { if errDelete := models.DeleteRepository(ctx.User, repoOwner.ID, repo.ID); errDelete != nil {
log.Error("DeleteRepository: %v", errDelete) log.Error("DeleteRepository: %v", errDelete)
} }
} }
}() }()
if _, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.User, ctxUser.Name, opts); err != nil { if _, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.User, repoOwner.Name, opts); err != nil {
handleMigrateError(ctx, ctxUser, remoteAddr, err) handleMigrateError(ctx, repoOwner, remoteAddr, err)
return return
} }
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) log.Trace("Repository migrated: %s/%s", repoOwner.Name, form.RepoName)
ctx.JSON(http.StatusCreated, repo.APIFormat(models.AccessModeAdmin)) ctx.JSON(http.StatusCreated, repo.APIFormat(models.AccessModeAdmin))
} }

View file

@ -149,4 +149,7 @@ type swaggerParameterBodies struct {
// in:body // in:body
SubmitPullReviewOptions api.SubmitPullReviewOptions SubmitPullReviewOptions api.SubmitPullReviewOptions
// in:body
MigrateRepoOptions api.MigrateRepoOptions
} }

View file

@ -74,7 +74,7 @@ func handleMigrateError(ctx *context.Context, owner *models.User, err error, nam
ctx.Data["Err_RepoName"] = true ctx.Data["Err_RepoName"] = true
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form) ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form)
default: default:
remoteAddr, _ := form.ParseRemoteAddr(owner) remoteAddr, _ := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, owner)
err = util.URLSanitizedError(err, remoteAddr) err = util.URLSanitizedError(err, remoteAddr)
if strings.Contains(err.Error(), "Authentication failed") || if strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "Bad credentials") || strings.Contains(err.Error(), "Bad credentials") ||
@ -108,7 +108,7 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
return return
} }
remoteAddr, err := form.ParseRemoteAddr(ctx.User) remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, ctx.User)
if err != nil { if err != nil {
if models.IsErrInvalidCloneAddr(err) { if models.IsErrInvalidCloneAddr(err) {
ctx.Data["Err_CloneAddr"] = true ctx.Data["Err_CloneAddr"] = true

View file

@ -10,8 +10,8 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
migration "code.gitea.io/gitea/modules/migrations/base"
"code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/structs"
release_service "code.gitea.io/gitea/services/release" release_service "code.gitea.io/gitea/services/release"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -28,7 +28,7 @@ func TestRelease_MirrorDelete(t *testing.T) {
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository) repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
repoPath := models.RepoPath(user.Name, repo.Name) repoPath := models.RepoPath(user.Name, repo.Name)
opts := structs.MigrateRepoOption{ opts := migration.MigrateOptions{
RepoName: "test_mirror", RepoName: "test_mirror",
Description: "Test mirror", Description: "Test mirror",
Private: false, Private: false,

View file

@ -1798,7 +1798,7 @@
"name": "body", "name": "body",
"in": "body", "in": "body",
"schema": { "schema": {
"$ref": "#/definitions/MigrateRepoForm" "$ref": "#/definitions/MigrateRepoOptions"
} }
} }
], ],
@ -13522,7 +13522,7 @@
"x-go-package": "code.gitea.io/gitea/modules/auth" "x-go-package": "code.gitea.io/gitea/modules/auth"
}, },
"MigrateRepoForm": { "MigrateRepoForm": {
"description": "MigrateRepoForm form for migrating repository", "description": "MigrateRepoForm form for migrating repository\nthis is used to interact with web ui",
"type": "object", "type": "object",
"required": [ "required": [
"clone_addr", "clone_addr",
@ -13599,6 +13599,94 @@
}, },
"x-go-package": "code.gitea.io/gitea/modules/auth" "x-go-package": "code.gitea.io/gitea/modules/auth"
}, },
"MigrateRepoOptions": {
"description": "MigrateRepoOptions options for migrating repository's\nthis is used to interact with api v1",
"type": "object",
"required": [
"clone_addr",
"repo_name"
],
"properties": {
"auth_password": {
"type": "string",
"x-go-name": "AuthPassword"
},
"auth_token": {
"type": "string",
"x-go-name": "AuthToken"
},
"auth_username": {
"type": "string",
"x-go-name": "AuthUsername"
},
"clone_addr": {
"type": "string",
"x-go-name": "CloneAddr"
},
"description": {
"type": "string",
"x-go-name": "Description"
},
"issues": {
"type": "boolean",
"x-go-name": "Issues"
},
"labels": {
"type": "boolean",
"x-go-name": "Labels"
},
"milestones": {
"type": "boolean",
"x-go-name": "Milestones"
},
"mirror": {
"type": "boolean",
"x-go-name": "Mirror"
},
"private": {
"type": "boolean",
"x-go-name": "Private"
},
"pull_requests": {
"type": "boolean",
"x-go-name": "PullRequests"
},
"releases": {
"type": "boolean",
"x-go-name": "Releases"
},
"repo_name": {
"type": "string",
"x-go-name": "RepoName"
},
"repo_owner": {
"description": "Name of User or Organisation who will own Repo after migration",
"type": "string",
"x-go-name": "RepoOwner"
},
"service": {
"type": "string",
"enum": [
"git",
"github",
"gitea",
"gitlab"
],
"x-go-name": "Service"
},
"uid": {
"description": "deprecated (only for backwards compatibility)",
"type": "integer",
"format": "int64",
"x-go-name": "RepoOwnerID"
},
"wiki": {
"type": "boolean",
"x-go-name": "Wiki"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"Milestone": { "Milestone": {
"description": "Milestone milestone is a collection of issues on one repository", "description": "Milestone milestone is a collection of issues on one repository",
"type": "object", "type": "object",
@ -15795,7 +15883,7 @@
"parameterBodies": { "parameterBodies": {
"description": "parameterBodies", "description": "parameterBodies",
"schema": { "schema": {
"$ref": "#/definitions/SubmitPullReviewOptions" "$ref": "#/definitions/MigrateRepoOptions"
} }
}, },
"redirect": { "redirect": {