diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index 9d3599102a3..c8afa73ae68 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -316,10 +316,10 @@ func TestAPIRepoMigrate(t *testing.T) { user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) - req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOption{ - CloneAddr: testCase.cloneURL, - UID: int(testCase.userID), - RepoName: testCase.repoName, + req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOptions{ + CloneAddr: testCase.cloneURL, + RepoOwnerID: testCase.userID, + RepoName: testCase.repoName, }) resp := MakeRequest(t, req, NoExpectedStatus) 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" req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+httpContext.Token, - &api.MigrateRepoOption{ - CloneAddr: cloneURL, - UID: int(userID), - RepoName: httpContext.Reponame, + &api.MigrateRepoOptions{ + CloneAddr: cloneURL, + RepoOwnerID: userID, + RepoName: httpContext.Reponame, }) resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict) respJSON := map[string]string{} diff --git a/models/task.go b/models/task.go index f4fce058c05..43cb2d4d9a6 100644 --- a/models/task.go +++ b/models/task.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" + migration "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -101,9 +102,9 @@ func (task *Task) UpdateCols(cols ...string) error { } // 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 { - var opts structs.MigrateRepoOption + var opts migration.MigrateOptions err := json.Unmarshal([]byte(task.PayloadContent), &opts) if err != nil { return nil, err diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index b3fead7da97..3ad57085b05 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -53,6 +53,7 @@ func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bin } // MigrateRepoForm form for migrating repository +// this is used to interact with web ui type MigrateRepoForm struct { // required: true 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. // It also checks if given user has permission when remote address // is actually a local path. -func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) { - remoteAddr := strings.TrimSpace(f.CloneAddr) - +func ParseRemoteAddr(remoteAddr, authUsername, authPassword string, user *models.User) (string, error) { + remoteAddr = strings.TrimSpace(remoteAddr) // Remote address can be HTTP/HTTPS/Git URL or local path. if strings.HasPrefix(remoteAddr, "http://") || strings.HasPrefix(remoteAddr, "https://") || @@ -95,8 +95,8 @@ func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) { if err != nil { return "", models.ErrInvalidCloneAddr{IsURLError: true} } - if len(f.AuthUsername)+len(f.AuthPassword) > 0 { - u.User = url.UserPassword(f.AuthUsername, f.AuthPassword) + if len(authUsername)+len(authPassword) > 0 { + u.User = url.UserPassword(authUsername, authPassword) } remoteAddr = u.String() } else if !user.CanImportLocal() { diff --git a/modules/convert/utils.go b/modules/convert/utils.go index ddb8a8820d4..69de306689e 100644 --- a/modules/convert/utils.go +++ b/modules/convert/utils.go @@ -1,3 +1,4 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. // Copyright 2016 The Gogs Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. @@ -5,7 +6,10 @@ package convert import ( + "strings" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" ) // ToCorrectPageSize makes sure page size is in allowed range. @@ -17,3 +21,19 @@ func ToCorrectPageSize(size int) int { } 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 + } +} diff --git a/modules/migrations/base/options.go b/modules/migrations/base/options.go index 2d180b61d95..dbc40b138aa 100644 --- a/modules/migrations/base/options.go +++ b/modules/migrations/base/options.go @@ -8,4 +8,28 @@ package base import "code.gitea.io/gitea/modules/structs" // 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 +} diff --git a/modules/migrations/gitea.go b/modules/migrations/gitea.go index 082ddcd5fb0..b70ad7b0ce0 100644 --- a/modules/migrations/gitea.go +++ b/modules/migrations/gitea.go @@ -123,7 +123,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate 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, Description: repo.Description, OriginalURL: repo.OriginalURL, diff --git a/modules/migrations/gitea_test.go b/modules/migrations/gitea_test.go index 62c8f713226..2dbd8ffd446 100644 --- a/modules/migrations/gitea_test.go +++ b/modules/migrations/gitea_test.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -32,7 +33,7 @@ func TestGiteaUploadRepo(t *testing.T) { 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", RepoName: repoName, AuthUsername: "", diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 2d5551d9875..36e9ed49c16 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -13,8 +13,8 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + migration "code.gitea.io/gitea/modules/migrations/base" "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "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 -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) if u.IsOrganization() { diff --git a/modules/structs/repo.go b/modules/structs/repo.go index f751c00789b..c57702b2821 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -226,6 +226,35 @@ func (gt GitServiceType) Title() string { 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 func (gt GitServiceType) TokenAuth() bool { switch gt { @@ -243,29 +272,3 @@ var ( 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 -} diff --git a/modules/task/migrate.go b/modules/task/migrate.go index d3b4fa45f01..9d6c8bf7332 100644 --- a/modules/task/migrate.go +++ b/modules/task/migrate.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "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/structs" "code.gitea.io/gitea/modules/timeutil" @@ -89,7 +90,7 @@ func runMigrateTask(t *models.Task) (err error) { return err } - var opts *structs.MigrateRepoOption + var opts *migration.MigrateOptions opts, err = t.MigrateConfig() if err != nil { return err diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 5f472f35188..9e856257705 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -636,7 +636,7 @@ func RegisterRoutes(m *macaron.Macaron) { 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.Combo("").Get(reqAnyRepoReader(), repo.Get). diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index fa4b7366e89..019d82031cb 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -9,12 +9,12 @@ import ( "errors" "fmt" "net/http" - "net/url" "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/migrations" @@ -26,7 +26,7 @@ import ( ) // 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 // --- // summary: Migrate a remote git repository @@ -38,7 +38,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { // - name: body // in: body // schema: - // "$ref": "#/definitions/MigrateRepoForm" + // "$ref": "#/definitions/MigrateRepoOptions" // responses: // "201": // "$ref": "#/responses/Repository" @@ -47,20 +47,25 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { // "422": // "$ref": "#/responses/validationError" - ctxUser := ctx.User - // Not equal means context user is an organization, - // or is another user/organization if current user is admin. - if form.UID != ctxUser.ID { - org, err := models.GetUserByID(form.UID) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.Error(http.StatusUnprocessableEntity, "", err) - } else { - ctx.Error(http.StatusInternalServerError, "GetUserByID", err) - } - return + //get repoOwner + var ( + repoOwner *models.User + err error + ) + if len(form.RepoOwner) != 0 { + repoOwner, err = models.GetUserByName(form.RepoOwner) + } else if form.RepoOwnerID != 0 { + repoOwner, err = models.GetUserByID(form.RepoOwnerID) + } else { + repoOwner = ctx.User + } + 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() { @@ -69,14 +74,14 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { } 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.") return } - if ctxUser.IsOrganization() { + if repoOwner.IsOrganization() { // Check ownership of organization. - isOwner, err := ctxUser.IsOwnedBy(ctx.User.ID) + isOwner, err := repoOwner.IsOwnedBy(ctx.User.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOwnedBy", err) 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 models.IsErrInvalidCloneAddr(err) { addrErr := err.(models.ErrInvalidCloneAddr) @@ -107,11 +112,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { return } - var gitServiceType = api.PlainGitService - u, err := url.Parse(remoteAddr) - if err == nil && strings.EqualFold(u.Host, "github.com") { - gitServiceType = api.GithubService - } + gitServiceType := convert.ToGitServiceType(form.Service) if form.Mirror && setting.Repository.DisableMirrors { 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, AuthUsername: form.AuthUsername, AuthPassword: form.AuthPassword, + AuthToken: form.AuthToken, Wiki: form.Wiki, Issues: form.Issues, Milestones: form.Milestones, @@ -144,7 +146,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { 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, Description: opts.Description, OriginalURL: form.CloneAddr, @@ -154,7 +156,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { Status: models.RepositoryBeingMigrated, }) if err != nil { - handleMigrateError(ctx, ctxUser, remoteAddr, err) + handleMigrateError(ctx, repoOwner, remoteAddr, err) return } @@ -171,24 +173,24 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) { if err == nil { repo.Status = models.RepositoryReady if err := models.UpdateRepositoryCols(repo, "status"); err == nil { - notification.NotifyMigrateRepository(ctx.User, ctxUser, repo) + notification.NotifyMigrateRepository(ctx.User, repoOwner, repo) return } } 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) } } }() - if _, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.User, ctxUser.Name, opts); err != nil { - handleMigrateError(ctx, ctxUser, remoteAddr, err) + if _, err = migrations.MigrateRepository(graceful.GetManager().HammerContext(), ctx.User, repoOwner.Name, opts); err != nil { + handleMigrateError(ctx, repoOwner, remoteAddr, err) 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)) } diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index d9ef05c3359..ced6589e48b 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -149,4 +149,7 @@ type swaggerParameterBodies struct { // in:body SubmitPullReviewOptions api.SubmitPullReviewOptions + + // in:body + MigrateRepoOptions api.MigrateRepoOptions } diff --git a/routers/repo/migrate.go b/routers/repo/migrate.go index 497f2ce36f8..34060aabde5 100644 --- a/routers/repo/migrate.go +++ b/routers/repo/migrate.go @@ -74,7 +74,7 @@ func handleMigrateError(ctx *context.Context, owner *models.User, err error, nam ctx.Data["Err_RepoName"] = true ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form) default: - remoteAddr, _ := form.ParseRemoteAddr(owner) + remoteAddr, _ := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, owner) err = util.URLSanitizedError(err, remoteAddr) if strings.Contains(err.Error(), "Authentication failed") || strings.Contains(err.Error(), "Bad credentials") || @@ -108,7 +108,7 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { return } - remoteAddr, err := form.ParseRemoteAddr(ctx.User) + remoteAddr, err := auth.ParseRemoteAddr(form.CloneAddr, form.AuthUsername, form.AuthPassword, ctx.User) if err != nil { if models.IsErrInvalidCloneAddr(err) { ctx.Data["Err_CloneAddr"] = true diff --git a/services/mirror/mirror_test.go b/services/mirror/mirror_test.go index 25e499ad788..79e18885b33 100644 --- a/services/mirror/mirror_test.go +++ b/services/mirror/mirror_test.go @@ -10,8 +10,8 @@ import ( "code.gitea.io/gitea/models" "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/structs" release_service "code.gitea.io/gitea/services/release" "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) repoPath := models.RepoPath(user.Name, repo.Name) - opts := structs.MigrateRepoOption{ + opts := migration.MigrateOptions{ RepoName: "test_mirror", Description: "Test mirror", Private: false, diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 661005be245..ac65b3ce17b 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -1798,7 +1798,7 @@ "name": "body", "in": "body", "schema": { - "$ref": "#/definitions/MigrateRepoForm" + "$ref": "#/definitions/MigrateRepoOptions" } } ], @@ -13522,7 +13522,7 @@ "x-go-package": "code.gitea.io/gitea/modules/auth" }, "MigrateRepoForm": { - "description": "MigrateRepoForm form for migrating repository", + "description": "MigrateRepoForm form for migrating repository\nthis is used to interact with web ui", "type": "object", "required": [ "clone_addr", @@ -13599,6 +13599,94 @@ }, "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": { "description": "Milestone milestone is a collection of issues on one repository", "type": "object", @@ -15795,7 +15883,7 @@ "parameterBodies": { "description": "parameterBodies", "schema": { - "$ref": "#/definitions/SubmitPullReviewOptions" + "$ref": "#/definitions/MigrateRepoOptions" } }, "redirect": {