mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	[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:
		@@ -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{}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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: "",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -149,4 +149,7 @@ type swaggerParameterBodies struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// in:body
 | 
						// in:body
 | 
				
			||||||
	SubmitPullReviewOptions api.SubmitPullReviewOptions
 | 
						SubmitPullReviewOptions api.SubmitPullReviewOptions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// in:body
 | 
				
			||||||
 | 
						MigrateRepoOptions api.MigrateRepoOptions
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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": {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user