feat: update gitea vendor
runner nix smoke / nix label and flake smoke (push) Failing after 1m28s

This commit is contained in:
2026-09-26 21:18:24 +00:00
parent c439c1b948
commit d9b2a4e787
3538 changed files with 116131 additions and 44340 deletions
@@ -7,15 +7,15 @@ import (
"errors"
"net/http"
"code.gitea.io/gitea/models/actions"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
shared_actions "code.gitea.io/gitea/routers/web/shared/actions"
"code.gitea.io/gitea/services/context"
repo_service "code.gitea.io/gitea/services/repository"
"gitea.dev/models/actions"
repo_model "gitea.dev/models/repo"
unit_model "gitea.dev/models/unit"
user_model "gitea.dev/models/user"
"gitea.dev/modules/templates"
"gitea.dev/modules/util"
shared_actions "gitea.dev/routers/web/shared/actions"
"gitea.dev/services/context"
repo_service "gitea.dev/services/repository"
)
const tplRepoActionsGeneralSettings templates.TplName = "repo/settings/actions"
@@ -8,13 +8,13 @@ import (
"fmt"
"io"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
repo_service "code.gitea.io/gitea/services/repository"
"gitea.dev/modules/log"
"gitea.dev/modules/setting"
"gitea.dev/modules/typesniffer"
"gitea.dev/modules/web"
"gitea.dev/services/context"
"gitea.dev/services/forms"
repo_service "gitea.dev/services/repository"
)
// UpdateAvatarSetting update repo's avatar
@@ -8,16 +8,16 @@ import (
"net/http"
"strings"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/mailer"
repo_service "code.gitea.io/gitea/services/repository"
"gitea.dev/models/organization"
"gitea.dev/models/perm"
repo_model "gitea.dev/models/repo"
unit_model "gitea.dev/models/unit"
user_model "gitea.dev/models/user"
"gitea.dev/modules/log"
"gitea.dev/modules/setting"
"gitea.dev/services/context"
"gitea.dev/services/mailer"
repo_service "gitea.dev/services/repository"
)
// Collaboration render a repository's collaboration page
@@ -43,6 +43,13 @@ func Collaboration(ctx *context.Context) {
ctx.Data["OrgName"] = ctx.Repo.Repository.OwnerName
ctx.Data["Org"] = ctx.Repo.Repository.Owner
ctx.Data["Units"] = unit_model.Units
if ctx.Repo.Owner.IsOrganization() {
ctx.Data["CanChangeRepoTeamAccess"], err = organization.OrgFromUser(ctx.Repo.Owner).CanChangeRepoTeamAccess(ctx, ctx.Doer)
if err != nil {
ctx.ServerError("CanChangeRepoTeamAccess", err)
return
}
}
ctx.HTML(http.StatusOK, tplCollaboration)
}
@@ -118,13 +125,19 @@ func CollaborationPost(ctx *context.Context) {
// ChangeCollaborationAccessMode response for changing access of a collaboration
func ChangeCollaborationAccessMode(ctx *context.Context) {
if err := repo_model.ChangeCollaborationAccessMode(
ctx,
ctx.Repo.Repository,
ctx.FormInt64("uid"),
perm.AccessMode(ctx.FormInt("mode"))); err != nil {
log.Error("ChangeCollaborationAccessMode: %v", err)
// the frontend initRepoSettingsCollaboration logic: it only checks "resp.ok"
u, err := user_model.GetUserByID(ctx, ctx.FormInt64("uid"))
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
mode := perm.AccessMode(ctx.FormInt("mode"))
if err := repo_service.AddOrUpdateCollaborator(ctx, ctx.Repo.Repository, u, mode); err != nil {
ctx.Status(http.StatusBadRequest)
log.Error("AddOrUpdateCollaborator: %v", err)
return
}
ctx.JSONOK()
}
// DeleteCollaboration delete a collaboration for a repository
@@ -149,9 +162,7 @@ func DeleteCollaboration(ctx *context.Context) {
// AddTeamPost response for adding a team to a repository
func AddTeamPost(ctx *context.Context) {
if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() {
ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
if !canChangeRepoTeamAccess(ctx) {
return
}
@@ -195,9 +206,7 @@ func AddTeamPost(ctx *context.Context) {
// DeleteTeam response for deleting a team from a repository
func DeleteTeam(ctx *context.Context) {
if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() {
ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
if !canChangeRepoTeamAccess(ctx) {
return
}
@@ -215,3 +224,16 @@ func DeleteTeam(ctx *context.Context) {
ctx.Flash.Success(ctx.Tr("repo.settings.remove_team_success"))
ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/collaboration")
}
func canChangeRepoTeamAccess(ctx *context.Context) bool {
canChange, err := organization.OrgFromUser(ctx.Repo.Owner).CanChangeRepoTeamAccess(ctx, ctx.Doer)
if err != nil {
ctx.ServerError("CanChangeRepoTeamAccess", err)
return false
}
if !canChange {
ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
}
return canChange
}
@@ -6,12 +6,12 @@ package setting
import (
"net/http"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/services/context"
repo_service "code.gitea.io/gitea/services/repository"
git_model "gitea.dev/models/git"
"gitea.dev/modules/log"
"gitea.dev/modules/setting"
"gitea.dev/routers/web/repo"
"gitea.dev/services/context"
repo_service "gitea.dev/services/repository"
)
// SetDefaultBranchPost set default branch
@@ -6,14 +6,14 @@ package setting
import (
"net/http"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
asymkey_model "gitea.dev/models/asymkey"
"gitea.dev/models/db"
"gitea.dev/modules/log"
"gitea.dev/modules/setting"
"gitea.dev/modules/web"
asymkey_service "gitea.dev/services/asymkey"
"gitea.dev/services/context"
"gitea.dev/services/forms"
)
// DeployKeys render the deploy keys list of a repository page
@@ -6,9 +6,9 @@ package setting
import (
"net/http"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/services/context"
"gitea.dev/modules/git"
"gitea.dev/routers/web/repo"
"gitea.dev/services/context"
)
// GitHooks hooks of a repository
@@ -14,22 +14,22 @@ import (
"strconv"
"strings"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/attribute"
"code.gitea.io/gitea/modules/git/pipeline"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
git_model "gitea.dev/models/git"
"gitea.dev/modules/charset"
"gitea.dev/modules/container"
"gitea.dev/modules/git"
"gitea.dev/modules/git/attribute"
"gitea.dev/modules/git/pipeline"
"gitea.dev/modules/gitrepo"
"gitea.dev/modules/lfs"
"gitea.dev/modules/log"
repo_module "gitea.dev/modules/repository"
"gitea.dev/modules/setting"
"gitea.dev/modules/storage"
"gitea.dev/modules/templates"
"gitea.dev/modules/typesniffer"
"gitea.dev/modules/util"
"gitea.dev/services/context"
)
const (
@@ -6,7 +6,7 @@ package setting
import (
"testing"
"code.gitea.io/gitea/models/unittest"
"gitea.dev/models/unittest"
)
func TestMain(m *testing.M) {
@@ -12,22 +12,22 @@ import (
"strings"
"time"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/glob"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
pull_service "code.gitea.io/gitea/services/pull"
"code.gitea.io/gitea/services/repository"
git_model "gitea.dev/models/git"
"gitea.dev/models/organization"
"gitea.dev/models/perm"
access_model "gitea.dev/models/perm/access"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
"gitea.dev/modules/base"
"gitea.dev/modules/glob"
"gitea.dev/modules/json"
"gitea.dev/modules/templates"
"gitea.dev/modules/web"
"gitea.dev/routers/web/repo"
"gitea.dev/services/context"
"gitea.dev/services/forms"
pull_service "gitea.dev/services/pull"
"gitea.dev/services/repository"
)
const (
@@ -74,7 +74,7 @@ func SettingsProtectedBranch(c *context.Context) {
c.Data["PageIsSettingsBranches"] = true
c.Data["Title"] = c.Locale.TrString("repo.settings.protected_branch") + " - " + rule.RuleName
users, err := access_model.GetUsersWithUnitAccess(c, c.Repo.Repository, perm.AccessModeRead, unit.TypePullRequests)
users, err := access_model.GetUsersWithAnyUnitAccess(c, c.Repo.Repository, perm.AccessModeRead, unit.TypeCode, unit.TypePullRequests)
if err != nil {
c.ServerError("GetUsersWithUnitAccess", err)
return
@@ -83,6 +83,7 @@ func SettingsProtectedBranch(c *context.Context) {
c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(rule.WhitelistUserIDs), ",")
c.Data["force_push_allowlist_users"] = strings.Join(base.Int64sToStrings(rule.ForcePushAllowlistUserIDs), ",")
c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.MergeWhitelistUserIDs), ",")
c.Data["bypass_allowlist_users"] = strings.Join(base.Int64sToStrings(rule.BypassAllowlistUserIDs), ",")
c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(rule.ApprovalsWhitelistUserIDs), ",")
c.Data["status_check_contexts"] = strings.Join(rule.StatusCheckContexts, "\n")
contexts, _ := git_model.FindRepoRecentCommitStatusContexts(c, c.Repo.Repository.ID, 7*24*time.Hour) // Find last week status check contexts
@@ -98,6 +99,7 @@ func SettingsProtectedBranch(c *context.Context) {
c.Data["whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.WhitelistTeamIDs), ",")
c.Data["force_push_allowlist_teams"] = strings.Join(base.Int64sToStrings(rule.ForcePushAllowlistTeamIDs), ",")
c.Data["merge_whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.MergeWhitelistTeamIDs), ",")
c.Data["bypass_allowlist_teams"] = strings.Join(base.Int64sToStrings(rule.BypassAllowlistTeamIDs), ",")
c.Data["approvals_whitelist_teams"] = strings.Join(base.Int64sToStrings(rule.ApprovalsWhitelistTeamIDs), ",")
}
@@ -155,7 +157,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
}
}
var whitelistUsers, whitelistTeams, forcePushAllowlistUsers, forcePushAllowlistTeams, mergeWhitelistUsers, mergeWhitelistTeams, approvalsWhitelistUsers, approvalsWhitelistTeams []int64
var whitelistUsers, whitelistTeams, forcePushAllowlistUsers, forcePushAllowlistTeams, mergeWhitelistUsers, mergeWhitelistTeams, approvalsWhitelistUsers, approvalsWhitelistTeams, bypassAllowlistUsers, bypassAllowlistTeams []int64
protectBranch.RuleName = f.RuleName
if f.RequiredApprovals < 0 {
ctx.Flash.Error(ctx.Tr("repo.settings.protected_branch_required_approvals_min"))
@@ -215,6 +217,16 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
}
}
protectBranch.EnableBypassAllowlist = f.EnableBypassAllowlist
if f.EnableBypassAllowlist {
if strings.TrimSpace(f.BypassAllowlistUsers) != "" {
bypassAllowlistUsers, _ = base.StringsToInt64s(strings.Split(f.BypassAllowlistUsers, ","))
}
if strings.TrimSpace(f.BypassAllowlistTeams) != "" {
bypassAllowlistTeams, _ = base.StringsToInt64s(strings.Split(f.BypassAllowlistTeams, ","))
}
}
protectBranch.EnableStatusCheck = f.EnableStatusCheck
if f.EnableStatusCheck {
patterns := strings.Split(strings.ReplaceAll(f.StatusCheckContexts, "\r", "\n"), "\n")
@@ -271,6 +283,8 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
MergeTeamIDs: mergeWhitelistTeams,
ApprovalsUserIDs: approvalsWhitelistUsers,
ApprovalsTeamIDs: approvalsWhitelistTeams,
BypassUserIDs: bypassAllowlistUsers,
BypassTeamIDs: bypassAllowlistTeams,
}); err != nil {
ctx.ServerError("CreateOrUpdateProtectedBranch", err)
return
@@ -8,17 +8,17 @@ import (
"net/http"
"strings"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
git_model "gitea.dev/models/git"
"gitea.dev/models/organization"
"gitea.dev/models/perm"
access_model "gitea.dev/models/perm/access"
"gitea.dev/models/unit"
"gitea.dev/modules/base"
"gitea.dev/modules/setting"
"gitea.dev/modules/templates"
"gitea.dev/modules/web"
"gitea.dev/services/context"
"gitea.dev/services/forms"
)
const (
@@ -149,7 +149,7 @@ func setTagsContext(ctx *context.Context) error {
}
ctx.Data["ProtectedTags"] = protectedTags
users, err := access_model.GetUsersWithUnitAccess(ctx, ctx.Repo.Repository, perm.AccessModeRead, unit.TypePullRequests)
users, err := access_model.GetUsersWithAnyUnitAccess(ctx, ctx.Repo.Repository, perm.AccessModeRead, unit.TypeCode, unit.TypePullRequests)
if err != nil {
ctx.ServerError("GetUsersWithUnitAccess", err)
return err
@@ -8,12 +8,12 @@ import (
"slices"
"strconv"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
"gitea.dev/models/perm"
"gitea.dev/models/repo"
"gitea.dev/models/unit"
"gitea.dev/modules/setting"
"gitea.dev/modules/templates"
"gitea.dev/services/context"
)
const tplRepoSettingsPublicAccess templates.TplName = "repo/settings/public_access"
@@ -7,11 +7,11 @@ import (
"errors"
"net/http"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
shared "code.gitea.io/gitea/routers/web/shared/secrets"
shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
"gitea.dev/modules/setting"
"gitea.dev/modules/templates"
shared "gitea.dev/routers/web/shared/secrets"
shared_user "gitea.dev/routers/web/shared/user"
"gitea.dev/services/context"
)
const (
@@ -6,36 +6,37 @@ package setting
import (
"errors"
"html/template"
"net/http"
"strings"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/indexer/code"
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
"code.gitea.io/gitea/modules/indexer/stats"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/validation"
"code.gitea.io/gitea/modules/web"
repo_router "code.gitea.io/gitea/routers/web/repo"
actions_service "code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/migrations"
mirror_service "code.gitea.io/gitea/services/mirror"
repo_service "code.gitea.io/gitea/services/repository"
wiki_service "code.gitea.io/gitea/services/wiki"
"gitea.dev/models/db"
"gitea.dev/models/organization"
repo_model "gitea.dev/models/repo"
unit_model "gitea.dev/models/unit"
user_model "gitea.dev/models/user"
"gitea.dev/modules/git"
"gitea.dev/modules/gitrepo"
"gitea.dev/modules/indexer/code"
issue_indexer "gitea.dev/modules/indexer/issues"
"gitea.dev/modules/indexer/stats"
"gitea.dev/modules/lfs"
"gitea.dev/modules/log"
"gitea.dev/modules/setting"
"gitea.dev/modules/structs"
"gitea.dev/modules/templates"
"gitea.dev/modules/util"
"gitea.dev/modules/validation"
"gitea.dev/modules/web"
repo_router "gitea.dev/routers/web/repo"
actions_service "gitea.dev/services/actions"
"gitea.dev/services/context"
"gitea.dev/services/forms"
"gitea.dev/services/migrations"
mirror_service "gitea.dev/services/mirror"
repo_service "gitea.dev/services/repository"
wiki_service "gitea.dev/services/wiki"
"xorm.io/xorm/convert"
)
@@ -49,6 +50,12 @@ const (
tplDeployKeys templates.TplName = "repo/settings/deploy_keys"
)
type selectOption struct {
Value string
Text template.HTML
Selected bool
}
// SettingsCtxData is a middleware that sets all the general context data for the
// settings template.
func SettingsCtxData(ctx *context.Context) {
@@ -66,6 +73,7 @@ func SettingsCtxData(ctx *context.Context) {
ctx.Data["SigningKeyAvailable"] = signing != nil
ctx.Data["SigningSettings"] = setting.Repository.Signing
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
preparePullRequestSettings(ctx)
if ctx.Doer.IsAdmin {
if setting.Indexer.RepoIndexerEnabled {
@@ -96,6 +104,35 @@ func SettingsCtxData(ctx *context.Context) {
}
}
func preparePullRequestSettings(ctx *context.Context) {
defaultUpdateStyle := repo_model.UpdateStyleMerge
if ctx.Repo.Repository.UnitEnabled(ctx, unit_model.TypePullRequests) {
prUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit_model.TypePullRequests)
defaultUpdateStyle = util.IfZero(prUnit.PullRequestsConfig().DefaultUpdateStyle, repo_model.UpdateStyleMerge)
}
updateBranchText := ctx.Tr("repo.pulls.update_branch")
rebaseUpdateText := ctx.Tr("repo.pulls.update_branch_rebase")
defaultUpdateStyleText := updateBranchText
if defaultUpdateStyle == repo_model.UpdateStyleRebase {
defaultUpdateStyleText = rebaseUpdateText
}
ctx.Data["PullsDefaultUpdateStyleText"] = defaultUpdateStyleText
ctx.Data["PullsDefaultUpdateStyleOptions"] = []selectOption{
{
Value: string(repo_model.UpdateStyleMerge),
Text: updateBranchText,
Selected: defaultUpdateStyle == repo_model.UpdateStyleMerge,
},
{
Value: string(repo_model.UpdateStyleRebase),
Text: rebaseUpdateText,
Selected: defaultUpdateStyle == repo_model.UpdateStyleRebase,
},
}
}
// Settings show a repository's settings page
func Settings(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplSettingsOptions)
@@ -265,8 +302,13 @@ func handleSettingsPostMirror(ctx *context.Context) {
handleSettingRemoteAddrError(ctx, err, form)
return
}
if u.User != nil && form.MirrorPassword == "" && form.MirrorUsername == u.User.Username() {
form.MirrorPassword, _ = u.User.Password()
if u.User != nil {
if form.MirrorUsername == "" {
form.MirrorUsername = u.User.Username()
}
if form.MirrorPassword == "" && form.MirrorUsername == u.User.Username() {
form.MirrorPassword, _ = u.User.Password()
}
}
address, err := git.ParseRemoteAddr(form.MirrorAddress, form.MirrorUsername, form.MirrorPassword)
@@ -459,11 +501,7 @@ func handleSettingsPostPushMirrorAdd(ctx *context.Context) {
return
}
remoteSuffix, err := util.CryptoRandomString(10)
if err != nil {
ctx.ServerError("RandomString", err)
return
}
remoteSuffix := util.CryptoRandomString(10)
remoteAddress, err := util.SanitizeURL(form.PushMirrorAddress)
if err != nil {
@@ -531,7 +569,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
}
if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
if !validation.IsValidExternalURL(form.ExternalWikiURL) {
if !validation.IsValidURL(form.ExternalWikiURL) {
ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
ctx.Redirect(repo.Link() + "/settings")
return
@@ -561,7 +599,7 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
}
if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
if !validation.IsValidExternalURL(form.ExternalTrackerURL) {
if !validation.IsValidURL(form.ExternalTrackerURL) {
ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
ctx.Redirect(repo.Link() + "/settings")
return
@@ -615,7 +653,8 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
}
if form.EnablePulls && !unit_model.TypePullRequests.UnitGlobalDisabled() {
units = append(units, newRepoUnit(repo, unit_model.TypePullRequests, &repo_model.PullRequestsConfig{
defaultUpdateStyle := util.IfZero(repo_model.UpdateStyle(form.PullsDefaultUpdateStyle), repo_model.UpdateStyleMerge)
prConfig := &repo_model.PullRequestsConfig{
IgnoreWhitespaceConflicts: form.PullsIgnoreWhitespace,
AllowMerge: form.PullsAllowMerge,
AllowRebase: form.PullsAllowRebase,
@@ -624,12 +663,20 @@ func handleSettingsPostAdvanced(ctx *context.Context) {
AllowFastForwardOnly: form.PullsAllowFastForwardOnly,
AllowManualMerge: form.PullsAllowManualMerge,
AutodetectManualMerge: form.EnableAutodetectManualMerge,
AllowMergeUpdate: form.PullsAllowMergeUpdate,
AllowRebaseUpdate: form.PullsAllowRebaseUpdate,
DefaultUpdateStyle: defaultUpdateStyle,
DefaultDeleteBranchAfterMerge: form.DefaultDeleteBranchAfterMerge,
DefaultMergeStyle: repo_model.MergeStyle(form.PullsDefaultMergeStyle),
DefaultAllowMaintainerEdit: form.DefaultAllowMaintainerEdit,
DefaultTargetBranch: strings.TrimSpace(form.DefaultTargetBranch),
}))
}
if err := prConfig.ValidateUpdateSettings(); err != nil {
ctx.Flash.Error(err.Error())
ctx.Redirect(repo.Link() + "/settings")
return
}
units = append(units, newRepoUnit(repo, unit_model.TypePullRequests, prConfig))
} else if !unit_model.TypePullRequests.UnitGlobalDisabled() {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
}
@@ -728,17 +775,17 @@ func handleSettingsPostAdminIndex(ctx *context.Context) {
func handleSettingsPostConvert(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RepoSettingForm)
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
ctx.HTTPError(http.StatusNotFound)
if !ctx.Repo.Permission.IsOwner() {
ctx.JSONErrorNotFound()
return
}
if repo.Name != form.RepoName {
ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return
}
if !repo.IsMirror {
ctx.HTTPError(http.StatusNotFound)
ctx.JSONErrorNotFound()
return
}
repo.IsMirror = false
@@ -752,14 +799,14 @@ func handleSettingsPostConvert(ctx *context.Context) {
}
log.Trace("Repository converted from mirror to regular: %s", repo.FullName())
ctx.Flash.Success(ctx.Tr("repo.settings.convert_succeed"))
ctx.Redirect(repo.Link())
ctx.JSONRedirect(repo.Link())
}
func handleSettingsPostConvertFork(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RepoSettingForm)
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
ctx.HTTPError(http.StatusNotFound)
if !ctx.Repo.Permission.IsOwner() {
ctx.JSONErrorNotFound()
return
}
if err := repo.LoadOwner(ctx); err != nil {
@@ -767,12 +814,12 @@ func handleSettingsPostConvertFork(ctx *context.Context) {
return
}
if repo.Name != form.RepoName {
ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return
}
if !repo.IsFork {
ctx.HTTPError(http.StatusNotFound)
ctx.JSONErrorNotFound()
return
}
@@ -780,7 +827,7 @@ func handleSettingsPostConvertFork(ctx *context.Context) {
maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit()
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
ctx.Flash.Error(msg)
ctx.Redirect(repo.Link() + "/settings")
ctx.JSONRedirect(repo.Link() + "/settings")
return
}
@@ -792,25 +839,25 @@ func handleSettingsPostConvertFork(ctx *context.Context) {
log.Trace("Repository converted from fork to regular: %s", repo.FullName())
ctx.Flash.Success(ctx.Tr("repo.settings.convert_fork_succeed"))
ctx.Redirect(repo.Link())
ctx.JSONRedirect(repo.Link())
}
func handleSettingsPostTransfer(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RepoSettingForm)
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
ctx.HTTPError(http.StatusNotFound)
if !ctx.Repo.Permission.IsOwner() {
ctx.JSONErrorNotFound()
return
}
if repo.Name != form.RepoName {
ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return
}
newOwner, err := user_model.GetUserByName(ctx, ctx.FormString("new_owner_name"))
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("form.enterred_invalid_owner_name"))
return
}
ctx.ServerError("IsUserExist", err)
@@ -820,7 +867,7 @@ func handleSettingsPostTransfer(ctx *context.Context) {
if newOwner.Type == user_model.UserTypeOrganization {
if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) {
// The user shouldn't know about this organization
ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("form.enterred_invalid_owner_name"))
return
}
}
@@ -834,14 +881,14 @@ func handleSettingsPostTransfer(ctx *context.Context) {
oldFullname := repo.FullName()
if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil {
if repo_model.IsErrRepoAlreadyExist(err) {
ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("repo.settings.new_owner_has_same_repo"))
} else if repo_model.IsErrRepoTransferInProgress(err) {
ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("repo.settings.transfer_in_progress"))
} else if repo_service.IsRepositoryLimitReached(err) {
limit := err.(repo_service.LimitReachedError).Limit
ctx.RenderWithErrDeprecated(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit), tplSettingsOptions, nil)
ctx.JSONError(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit))
} else if errors.Is(err, user_model.ErrBlockedUser) {
ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("repo.settings.transfer.blocked_user"))
} else {
ctx.ServerError("TransferOwnership", err)
}
@@ -856,12 +903,12 @@ func handleSettingsPostTransfer(ctx *context.Context) {
log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName())
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
}
ctx.Redirect(repo.Link() + "/settings")
ctx.JSONRedirect(repo.Link() + "/settings")
}
func handleSettingsPostCancelTransfer(ctx *context.Context) {
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
if !ctx.Repo.Permission.IsOwner() {
ctx.HTTPError(http.StatusNotFound)
return
}
@@ -890,12 +937,12 @@ func handleSettingsPostCancelTransfer(ctx *context.Context) {
func handleSettingsPostDelete(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RepoSettingForm)
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
ctx.HTTPError(http.StatusNotFound)
if !ctx.Repo.Permission.IsOwner() {
ctx.JSONErrorNotFound()
return
}
if repo.Name != form.RepoName {
ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return
}
@@ -911,18 +958,18 @@ func handleSettingsPostDelete(ctx *context.Context) {
log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
ctx.Redirect(ctx.Repo.Owner.DashboardLink())
ctx.JSONRedirect(ctx.Repo.Owner.DashboardLink())
}
func handleSettingsPostDeleteWiki(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.RepoSettingForm)
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
ctx.HTTPError(http.StatusNotFound)
if !ctx.Repo.Permission.IsOwner() {
ctx.JSONErrorNotFound()
return
}
if repo.Name != form.RepoName {
ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil)
ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name"))
return
}
@@ -933,12 +980,12 @@ func handleSettingsPostDeleteWiki(ctx *context.Context) {
log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings")
}
func handleSettingsPostArchive(ctx *context.Context) {
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
if !ctx.Repo.Permission.IsOwner() {
ctx.HTTPError(http.StatusForbidden)
return
}
@@ -971,7 +1018,7 @@ func handleSettingsPostArchive(ctx *context.Context) {
func handleSettingsPostUnarchive(ctx *context.Context) {
repo := ctx.Repo.Repository
if !ctx.Repo.IsOwner() {
if !ctx.Repo.Permission.IsOwner() {
ctx.HTTPError(http.StatusForbidden)
return
}
@@ -7,21 +7,24 @@ import (
"net/http"
"testing"
asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/contexttest"
"code.gitea.io/gitea/services/forms"
repo_service "code.gitea.io/gitea/services/repository"
asymkey_model "gitea.dev/models/asymkey"
"gitea.dev/models/organization"
"gitea.dev/models/perm"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unittest"
user_model "gitea.dev/models/user"
"gitea.dev/modules/gitrepo"
"gitea.dev/modules/setting"
"gitea.dev/modules/test"
"gitea.dev/modules/web"
"gitea.dev/services/context"
"gitea.dev/services/contexttest"
"gitea.dev/services/forms"
mirror_service "gitea.dev/services/mirror"
repo_service "gitea.dev/services/repository"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAddReadOnlyDeployKey(t *testing.T) {
@@ -237,40 +240,27 @@ func TestAddTeamPost(t *testing.T) {
func TestAddTeamPost_NotAllowed(t *testing.T) {
unittest.PrepareTestEnv(t)
ctx, _ := contexttest.MockContext(t, "org26/repo43")
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32})
require.NoError(t, repo.LoadOwner(t.Context()))
adminTeam := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 12})
targetTeam := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
require.NoError(t, repo_service.TeamAddRepository(t.Context(), adminTeam, repo))
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 28})
repoContext := &context.Repository{Owner: repo.Owner, Repository: repo}
renderCtx, _ := contexttest.MockContext(t, repo.Link()+"/settings/collaboration")
renderCtx.Repo = repoContext
renderCtx.Doer = doer
Collaboration(renderCtx)
assert.Equal(t, false, renderCtx.Data["CanChangeRepoTeamAccess"])
ctx.Req.Form.Set("team", "team11")
org := &user_model.User{
LowerName: "org26",
Type: user_model.UserTypeOrganization,
}
team := &organization.Team{
ID: 11,
OrgID: 26,
}
re := &repo_model.Repository{
ID: 43,
Owner: org,
OwnerID: 26,
}
repo := &context.Repository{
Owner: &user_model.User{
ID: 26,
LowerName: "org26",
RepoAdminChangeTeamAccess: false,
},
Repository: re,
}
ctx.Repo = repo
ctx, _ := contexttest.MockContext(t, repo.Link()+"/settings/collaboration")
ctx.Req.Form.Set("team", targetTeam.Name)
ctx.Repo = repoContext
ctx.Doer = doer
AddTeamPost(ctx)
assert.False(t, repo_service.HasRepository(t.Context(), team, re.ID))
assert.False(t, repo_service.HasRepository(t.Context(), targetTeam, repo.ID))
assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
}
@@ -386,3 +376,45 @@ func TestDeleteTeam(t *testing.T) {
assert.False(t, repo_service.HasRepository(t.Context(), team, re.ID))
}
func TestHandleSettingsPostMirrorPreservesExistingUsername(t *testing.T) {
defer test.MockVariableValue(&setting.Mirror.Enabled, true)()
unittest.PrepareTestEnv(t)
// Use the existing fixture mirror repo (org3/repo5) which has a git repo on disk.
mirrorRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
mirror := unittest.AssertExistsAndLoadBean(t, &repo_model.Mirror{RepoID: 5})
require.NoError(t, mirror_service.UpdateAddress(t.Context(), mirror, "https://existing-user:existing-password@example.com/user2/repo1.git"))
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
ctx, _ := contexttest.MockContext(t, mirrorRepo.Link()+"/settings")
contexttest.LoadUser(t, ctx, user.ID)
contexttest.LoadRepo(t, ctx, mirrorRepo.ID)
web.SetForm(ctx, &forms.RepoSettingForm{
Interval: "8h",
MirrorAddress: "https://example.com/user2/repo1.git",
MirrorPassword: "updated-password",
})
handleSettingsPostMirror(ctx)
assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
updatedMirror := unittest.AssertExistsAndLoadBean(t, &repo_model.Mirror{RepoID: mirrorRepo.ID})
assert.Equal(t, "https://example.com/user2/repo1.git", updatedMirror.RemoteAddress)
updatedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: mirrorRepo.ID})
assert.Equal(t, "https://example.com/user2/repo1.git", updatedRepo.OriginalURL)
remoteURL, err := gitrepo.GitRemoteGetURL(t.Context(), updatedRepo, updatedMirror.GetRemoteName())
require.NoError(t, err)
require.NotNil(t, remoteURL.User)
assert.Equal(t, "existing-user", remoteURL.User.Username())
password, ok := remoteURL.User.Password()
require.True(t, ok)
assert.Equal(t, "updated-password", password)
}
@@ -12,23 +12,23 @@ import (
"path"
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
webhook_module "code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
"code.gitea.io/gitea/services/forms"
webhook_service "code.gitea.io/gitea/services/webhook"
"gitea.dev/models/db"
"gitea.dev/models/perm"
access_model "gitea.dev/models/perm/access"
user_model "gitea.dev/models/user"
"gitea.dev/models/webhook"
"gitea.dev/modules/git"
"gitea.dev/modules/json"
"gitea.dev/modules/setting"
api "gitea.dev/modules/structs"
"gitea.dev/modules/templates"
"gitea.dev/modules/util"
"gitea.dev/modules/web"
webhook_module "gitea.dev/modules/webhook"
"gitea.dev/services/context"
"gitea.dev/services/convert"
"gitea.dev/services/forms"
webhook_service "gitea.dev/services/webhook"
)
const (
@@ -664,26 +664,21 @@ func TestWebhook(ctx *context.Context) {
return
}
// Grab latest commit or fake one if it's empty repository.
// Note: in old code, the "ctx.Repo.Commit" is the last commit of the default branch.
// New code doesn't set that commit, so it always uses the fake commit to test webhook.
commit := ctx.Repo.Commit
if commit == nil {
ghost := user_model.NewGhostUser()
objectFormat := git.ObjectFormatFromName(ctx.Repo.Repository.ObjectFormatName)
commit = &git.Commit{
ID: objectFormat.EmptyObjectID(),
Author: ghost.NewGitSig(),
Committer: ghost.NewGitSig(),
CommitMessage: "This is a fake commit",
}
// use a fake commit to test webhook
ghostUser := user_model.NewGhostUser()
objectFormat := git.ObjectFormatFromName(ctx.Repo.Repository.ObjectFormatName)
commit := &git.Commit{
ID: objectFormat.EmptyObjectID(),
Author: ghostUser.NewGitSig(),
Committer: ghostUser.NewGitSig(),
CommitMessage: git.CommitMessage{MessageRaw: "This is a fake commit for webhook push test"},
}
apiUser := convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone)
apiCommit := &api.PayloadCommit{
ID: commit.ID.String(),
Message: commit.Message(),
Message: commit.MessageUTF8(),
URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()),
Author: &api.PayloadUser{
Name: commit.Author.Name,
@@ -697,7 +692,7 @@ func TestWebhook(ctx *context.Context) {
commitID := commit.ID.String()
p := &api.PushPayload{
Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch,
Ref: git.RefNameFromBranch(ctx.Repo.Repository.DefaultBranch).String(),
Before: commitID,
After: commitID,
CompareURL: setting.AppURL + ctx.Repo.Repository.ComposeCompareURL(commitID, commitID),
@@ -708,8 +703,8 @@ func TestWebhook(ctx *context.Context) {
Pusher: apiUser,
Sender: apiUser,
}
if err := webhook_service.PrepareWebhook(ctx, w, webhook_module.HookEventPush, p); err != nil {
ctx.Flash.Error("PrepareWebhook: " + err.Error())
if err := webhook_service.PrepareTestWebhook(ctx, w, webhook_module.HookEventPush, p); err != nil {
ctx.Flash.Error("PrepareTestWebhook: " + err.Error())
ctx.Status(http.StatusInternalServerError)
} else {
ctx.Flash.Info(ctx.Tr("repo.settings.webhook.delivery.success"))