mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-10 02:31:39 +02:00
Merge branch 'limit-repo-size' of https://github.com/DmitryFrolovTri/gitea into limit-repo-size
This commit is contained in:
commit
fd73aceaf6
229 files changed
+6151
-5929
No files matched your search
@@ -92,7 +92,7 @@ func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore
|
||||
middleware.SetLocaleCookie(resp, user.Language, 0)
|
||||
|
||||
// Clear whatever CSRF has right now, force to generate a new one
|
||||
if ctx := gitea_context.GetContext(req); ctx != nil {
|
||||
if ctx := gitea_context.GetWebContext(req); ctx != nil {
|
||||
ctx.Csrf.DeleteCookie(ctx)
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
type PackageCleanupRuleForm struct {
|
||||
ID int64
|
||||
Enabled bool
|
||||
Type string `binding:"Required;In(alpine,cargo,chef,composer,conan,conda,container,debian,generic,go,helm,maven,npm,nuget,pub,pypi,rpm,rubygems,swift,vagrant)"`
|
||||
Type string `binding:"Required;In(alpine,cargo,chef,composer,conan,conda,container,cran,debian,generic,go,helm,maven,npm,nuget,pub,pypi,rpm,rubygems,swift,vagrant)"`
|
||||
KeepCount int `binding:"In(0,1,5,10,25,50,100)"`
|
||||
KeepPattern string `binding:"RegexPattern"`
|
||||
RemoveDays int `binding:"In(0,7,14,30,60,90,180)"`
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
|
||||
"gitea.com/go-chi/binding"
|
||||
"github.com/gobwas/glob"
|
||||
)
|
||||
|
||||
// InstallForm form for installation page
|
||||
@@ -105,8 +106,8 @@ func (f *RegisterForm) Validate(req *http.Request, errs binding.Errors) binding.
|
||||
|
||||
// IsEmailDomainListed checks whether the domain of an email address
|
||||
// matches a list of domains
|
||||
func IsEmailDomainListed(list []string, email string) bool {
|
||||
if len(list) == 0 {
|
||||
func IsEmailDomainListed(globs []glob.Glob, email string) bool {
|
||||
if len(globs) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -117,8 +118,8 @@ func IsEmailDomainListed(list []string, email string) bool {
|
||||
|
||||
domain := strings.ToLower(email[n+1:])
|
||||
|
||||
for _, v := range list {
|
||||
if strings.ToLower(v) == domain {
|
||||
for _, g := range globs {
|
||||
if g.Match(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -131,12 +132,12 @@ func IsEmailDomainListed(list []string, email string) bool {
|
||||
// The email is marked as allowed if it matches any of the
|
||||
// domains in the whitelist or if it doesn't match any of
|
||||
// domains in the blocklist, if any such list is not empty.
|
||||
func (f RegisterForm) IsEmailDomainAllowed() bool {
|
||||
if len(setting.Service.EmailDomainWhitelist) == 0 {
|
||||
return !IsEmailDomainListed(setting.Service.EmailDomainBlocklist, f.Email)
|
||||
func (f *RegisterForm) IsEmailDomainAllowed() bool {
|
||||
if len(setting.Service.EmailDomainAllowList) == 0 {
|
||||
return !IsEmailDomainListed(setting.Service.EmailDomainBlockList, f.Email)
|
||||
}
|
||||
|
||||
return IsEmailDomainListed(setting.Service.EmailDomainWhitelist, f.Email)
|
||||
return IsEmailDomainListed(setting.Service.EmailDomainAllowList, f.Email)
|
||||
}
|
||||
|
||||
// MustChangePasswordForm form for updating your password after account creation
|
||||
|
||||
@@ -10,13 +10,17 @@ import (
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRegisterForm_IsDomainAllowed_Empty(t *testing.T) {
|
||||
_ = setting.Service
|
||||
oldService := setting.Service
|
||||
defer func() {
|
||||
setting.Service = oldService
|
||||
}()
|
||||
|
||||
setting.Service.EmailDomainWhitelist = []string{}
|
||||
setting.Service.EmailDomainAllowList = nil
|
||||
|
||||
form := RegisterForm{}
|
||||
|
||||
@@ -24,15 +28,18 @@ func TestRegisterForm_IsDomainAllowed_Empty(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRegisterForm_IsDomainAllowed_InvalidEmail(t *testing.T) {
|
||||
_ = setting.Service
|
||||
oldService := setting.Service
|
||||
defer func() {
|
||||
setting.Service = oldService
|
||||
}()
|
||||
|
||||
setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
|
||||
setting.Service.EmailDomainAllowList = []glob.Glob{glob.MustCompile("gitea.io")}
|
||||
|
||||
tt := []struct {
|
||||
email string
|
||||
}{
|
||||
{"securitygieqqq"},
|
||||
{"hdudhdd"},
|
||||
{"invalid-email"},
|
||||
{"gitea.io"},
|
||||
}
|
||||
|
||||
for _, v := range tt {
|
||||
@@ -42,10 +49,13 @@ func TestRegisterForm_IsDomainAllowed_InvalidEmail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) {
|
||||
_ = setting.Service
|
||||
func TestRegisterForm_IsDomainAllowed_AllowedEmail(t *testing.T) {
|
||||
oldService := setting.Service
|
||||
defer func() {
|
||||
setting.Service = oldService
|
||||
}()
|
||||
|
||||
setting.Service.EmailDomainWhitelist = []string{"gitea.io"}
|
||||
setting.Service.EmailDomainAllowList = []glob.Glob{glob.MustCompile("gitea.io"), glob.MustCompile("*.allow")}
|
||||
|
||||
tt := []struct {
|
||||
email string
|
||||
@@ -53,8 +63,11 @@ func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) {
|
||||
}{
|
||||
{"security@gitea.io", true},
|
||||
{"security@gITea.io", true},
|
||||
{"hdudhdd", false},
|
||||
{"invalid", false},
|
||||
{"seee@example.com", false},
|
||||
|
||||
{"user@my.allow", true},
|
||||
{"user@my.allow1", false},
|
||||
}
|
||||
|
||||
for _, v := range tt {
|
||||
@@ -64,11 +77,14 @@ func TestRegisterForm_IsDomainAllowed_WhitelistedEmail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterForm_IsDomainAllowed_BlocklistedEmail(t *testing.T) {
|
||||
_ = setting.Service
|
||||
func TestRegisterForm_IsDomainAllowed_BlockedEmail(t *testing.T) {
|
||||
oldService := setting.Service
|
||||
defer func() {
|
||||
setting.Service = oldService
|
||||
}()
|
||||
|
||||
setting.Service.EmailDomainWhitelist = []string{}
|
||||
setting.Service.EmailDomainBlocklist = []string{"gitea.io"}
|
||||
setting.Service.EmailDomainAllowList = nil
|
||||
setting.Service.EmailDomainBlockList = []glob.Glob{glob.MustCompile("gitea.io"), glob.MustCompile("*.block")}
|
||||
|
||||
tt := []struct {
|
||||
email string
|
||||
@@ -76,7 +92,10 @@ func TestRegisterForm_IsDomainAllowed_BlocklistedEmail(t *testing.T) {
|
||||
}{
|
||||
{"security@gitea.io", false},
|
||||
{"security@gitea.example", true},
|
||||
{"hdudhdd", true},
|
||||
{"invalid", true},
|
||||
|
||||
{"user@my.block", false},
|
||||
{"user@my.block1", true},
|
||||
}
|
||||
|
||||
for _, v := range tt {
|
||||
|
||||
@@ -115,13 +115,11 @@ func (d *CodebaseDownloader) String() string {
|
||||
return fmt.Sprintf("migration from codebase server %s %s/%s", d.baseURL, d.project, d.repoName)
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a GogsDownloader
|
||||
func (d *CodebaseDownloader) ColorFormat(s fmt.State) {
|
||||
func (d *CodebaseDownloader) LogString() string {
|
||||
if d == nil {
|
||||
log.ColorFprintf(s, "<nil: CodebaseDownloader>")
|
||||
return
|
||||
return "<CodebaseDownloader nil>"
|
||||
}
|
||||
log.ColorFprintf(s, "migration from codebase server %s %s/%s", d.baseURL, d.project, d.repoName)
|
||||
return fmt.Sprintf("<CodebaseDownloader %s %s/%s>", d.baseURL, d.project, d.repoName)
|
||||
}
|
||||
|
||||
// FormatCloneURL add authentication into remote URLs
|
||||
|
||||
@@ -62,13 +62,11 @@ func (g *GitBucketDownloader) String() string {
|
||||
return fmt.Sprintf("migration from gitbucket server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a GitBucketDownloader
|
||||
func (g *GitBucketDownloader) ColorFormat(s fmt.State) {
|
||||
func (g *GitBucketDownloader) LogString() string {
|
||||
if g == nil {
|
||||
log.ColorFprintf(s, "<nil: GitBucketDownloader>")
|
||||
return
|
||||
return "<GitBucketDownloader nil>"
|
||||
}
|
||||
log.ColorFprintf(s, "migration from gitbucket server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
return fmt.Sprintf("<GitBucketDownloader %s %s/%s>", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
// NewGitBucketDownloader creates a GitBucket downloader
|
||||
|
||||
@@ -134,13 +134,11 @@ func (g *GiteaDownloader) String() string {
|
||||
return fmt.Sprintf("migration from gitea server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a GiteaDownloader
|
||||
func (g *GiteaDownloader) ColorFormat(s fmt.State) {
|
||||
func (g *GiteaDownloader) LogString() string {
|
||||
if g == nil {
|
||||
log.ColorFprintf(s, "<nil: GiteaDownloader>")
|
||||
return
|
||||
return "<GiteaDownloader nil>"
|
||||
}
|
||||
log.ColorFprintf(s, "migration from gitea server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
return fmt.Sprintf("<GiteaDownloader %s %s/%s>", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
// GetRepoInfo returns a repository information
|
||||
|
||||
@@ -125,13 +125,11 @@ func (g *GithubDownloaderV3) String() string {
|
||||
return fmt.Sprintf("migration from github server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a GithubDownloader
|
||||
func (g *GithubDownloaderV3) ColorFormat(s fmt.State) {
|
||||
func (g *GithubDownloaderV3) LogString() string {
|
||||
if g == nil {
|
||||
log.ColorFprintf(s, "<nil: GithubDownloaderV3>")
|
||||
return
|
||||
return "<GithubDownloaderV3 nil>"
|
||||
}
|
||||
log.ColorFprintf(s, "migration from github server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
return fmt.Sprintf("<GithubDownloaderV3 %s %s/%s>", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
func (g *GithubDownloaderV3) addClient(client *http.Client, baseURL string) {
|
||||
|
||||
@@ -137,13 +137,11 @@ func (g *GitlabDownloader) String() string {
|
||||
return fmt.Sprintf("migration from gitlab server %s [%d]/%s", g.baseURL, g.repoID, g.repoName)
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a GitlabDownloader
|
||||
func (g *GitlabDownloader) ColorFormat(s fmt.State) {
|
||||
func (g *GitlabDownloader) LogString() string {
|
||||
if g == nil {
|
||||
log.ColorFprintf(s, "<nil: GitlabDownloader>")
|
||||
return
|
||||
return "<GitlabDownloader nil>"
|
||||
}
|
||||
log.ColorFprintf(s, "migration from gitlab server %s [%d]/%s", g.baseURL, g.repoID, g.repoName)
|
||||
return fmt.Sprintf("<GitlabDownloader %s [%d]/%s>", g.baseURL, g.repoID, g.repoName)
|
||||
}
|
||||
|
||||
// SetContext set context
|
||||
|
||||
@@ -77,13 +77,11 @@ func (g *GogsDownloader) String() string {
|
||||
return fmt.Sprintf("migration from gogs server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a GogsDownloader
|
||||
func (g *GogsDownloader) ColorFormat(s fmt.State) {
|
||||
func (g *GogsDownloader) LogString() string {
|
||||
if g == nil {
|
||||
log.ColorFprintf(s, "<nil: GogsDownloader>")
|
||||
return
|
||||
return "<GogsDownloader nil>"
|
||||
}
|
||||
log.ColorFprintf(s, "migration from gogs server %s %s/%s", g.baseURL, g.repoOwner, g.repoName)
|
||||
return fmt.Sprintf("<GogsDownloader %s %s/%s>", g.baseURL, g.repoOwner, g.repoName)
|
||||
}
|
||||
|
||||
// SetContext set context
|
||||
|
||||
@@ -114,13 +114,11 @@ func (d *OneDevDownloader) String() string {
|
||||
return fmt.Sprintf("migration from oneDev server %s [%d]/%s", d.baseURL, d.repoID, d.repoName)
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a OneDevDownloader
|
||||
func (d *OneDevDownloader) ColorFormat(s fmt.State) {
|
||||
func (d *OneDevDownloader) LogString() string {
|
||||
if d == nil {
|
||||
log.ColorFprintf(s, "<nil: OneDevDownloader>")
|
||||
return
|
||||
return "<OneDevDownloader nil>"
|
||||
}
|
||||
log.ColorFprintf(s, "migration from oneDev server %s [%d]/%s", d.baseURL, d.repoID, d.repoName)
|
||||
return fmt.Sprintf("<OneDevDownloader %s [%d]/%s>", d.baseURL, d.repoID, d.repoName)
|
||||
}
|
||||
|
||||
func (d *OneDevDownloader) callAPI(endpoint string, parameter map[string]string, result interface{}) error {
|
||||
|
||||
+12
-5
@@ -4,20 +4,22 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
org_model "code.gitea.io/gitea/models/organization"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
user_service "code.gitea.io/gitea/services/user"
|
||||
)
|
||||
|
||||
// DeleteOrganization completely and permanently deletes everything of organization.
|
||||
func DeleteOrganization(org *organization.Organization) error {
|
||||
func DeleteOrganization(org *org_model.Organization) error {
|
||||
ctx, commiter, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -39,7 +41,7 @@ func DeleteOrganization(org *organization.Organization) error {
|
||||
return models.ErrUserOwnPackages{UID: org.ID}
|
||||
}
|
||||
|
||||
if err := organization.DeleteOrganization(ctx, org); err != nil {
|
||||
if err := org_model.DeleteOrganization(ctx, org); err != nil {
|
||||
return fmt.Errorf("DeleteOrganization: %w", err)
|
||||
}
|
||||
|
||||
@@ -53,15 +55,20 @@ func DeleteOrganization(org *organization.Organization) error {
|
||||
path := user_model.UserPath(org.Name)
|
||||
|
||||
if err := util.RemoveAll(path); err != nil {
|
||||
return fmt.Errorf("Failed to RemoveAll %s: %w", path, err)
|
||||
return fmt.Errorf("failed to RemoveAll %s: %w", path, err)
|
||||
}
|
||||
|
||||
if len(org.Avatar) > 0 {
|
||||
avatarPath := org.CustomAvatarRelativePath()
|
||||
if err := storage.Avatars.Delete(avatarPath); err != nil {
|
||||
return fmt.Errorf("Failed to remove %s: %w", avatarPath, err)
|
||||
return fmt.Errorf("failed to remove %s: %w", avatarPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RenameOrganization renames an organization.
|
||||
func RenameOrganization(ctx context.Context, org *org_model.Organization, newName string) error {
|
||||
return user_service.RenameUser(ctx, org.AsUser(), newName)
|
||||
}
|
||||
@@ -365,6 +365,8 @@ func CheckSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, p
|
||||
typeSpecificSize = setting.Packages.LimitSizeConda
|
||||
case packages_model.TypeContainer:
|
||||
typeSpecificSize = setting.Packages.LimitSizeContainer
|
||||
case packages_model.TypeCran:
|
||||
typeSpecificSize = setting.Packages.LimitSizeCran
|
||||
case packages_model.TypeDebian:
|
||||
typeSpecificSize = setting.Packages.LimitSizeDebian
|
||||
case packages_model.TypeGeneric:
|
||||
|
||||
+10
-2
@@ -34,8 +34,8 @@ import (
|
||||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
)
|
||||
|
||||
// GetDefaultMergeMessage returns default message used when merging pull request
|
||||
func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issues_model.PullRequest, mergeStyle repo_model.MergeStyle) (message, body string, err error) {
|
||||
// getMergeMessage composes the message used when merging a pull request.
|
||||
func getMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issues_model.PullRequest, mergeStyle repo_model.MergeStyle, extraVars map[string]string) (message, body string, err error) {
|
||||
if err := pr.LoadBaseRepo(ctx); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@@ -81,6 +81,9 @@ func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr
|
||||
vars["HeadRepoOwnerName"] = pr.HeadRepo.OwnerName
|
||||
vars["HeadRepoName"] = pr.HeadRepo.Name
|
||||
}
|
||||
for extraKey, extraValue := range extraVars {
|
||||
vars[extraKey] = extraValue
|
||||
}
|
||||
refs, err := pr.ResolveCrossReferences(ctx)
|
||||
if err == nil {
|
||||
closeIssueIndexes := make([]string, 0, len(refs))
|
||||
@@ -133,6 +136,11 @@ func expandDefaultMergeMessage(template string, vars map[string]string) (message
|
||||
return os.Expand(message, mapping), os.Expand(body, mapping)
|
||||
}
|
||||
|
||||
// GetDefaultMergeMessage returns default message used when merging pull request
|
||||
func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issues_model.PullRequest, mergeStyle repo_model.MergeStyle) (message, body string, err error) {
|
||||
return getMergeMessage(ctx, baseGitRepo, pr, mergeStyle, nil)
|
||||
}
|
||||
|
||||
// Merge merges pull request to base repository.
|
||||
// Caller should check PR is ready to be merged (review and status checks)
|
||||
func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User, baseGitRepo *git.Repository, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string, wasAutoMerged bool) error {
|
||||
|
||||
@@ -5,13 +5,99 @@ package pull
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// doMergeStyleRebase rebaases the tracking branch on the base branch as the current HEAD with or with a merge commit to the original pr branch
|
||||
// getRebaseAmendMessage composes the message to amend commits in rebase merge of a pull request.
|
||||
func getRebaseAmendMessage(ctx *mergeContext, baseGitRepo *git.Repository) (message string, err error) {
|
||||
// Get existing commit message.
|
||||
commitMessage, _, err := git.NewCommand(ctx, "show", "--format=%B", "-s").RunStdString(&git.RunOpts{Dir: ctx.tmpBasePath})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
commitTitle, commitBody, _ := strings.Cut(commitMessage, "\n")
|
||||
extraVars := map[string]string{"CommitTitle": strings.TrimSpace(commitTitle), "CommitBody": strings.TrimSpace(commitBody)}
|
||||
|
||||
message, body, err := getMergeMessage(ctx, baseGitRepo, ctx.pr, repo_model.MergeStyleRebase, extraVars)
|
||||
if err != nil || message == "" {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(body) > 0 {
|
||||
message = message + "\n\n" + body
|
||||
}
|
||||
return message, err
|
||||
}
|
||||
|
||||
// Perform rebase merge without merge commit.
|
||||
func doMergeRebaseFastForward(ctx *mergeContext) error {
|
||||
baseHeadSHA, err := git.GetFullCommitID(ctx, ctx.tmpBasePath, "HEAD")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get full commit id for HEAD: %w", err)
|
||||
}
|
||||
|
||||
cmd := git.NewCommand(ctx, "merge", "--ff-only").AddDynamicArguments(stagingBranch)
|
||||
if err := runMergeCommand(ctx, repo_model.MergeStyleRebase, cmd); err != nil {
|
||||
log.Error("Unable to merge staging into base: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if anything actually changed before we amend the message, fast forward can skip commits.
|
||||
newMergeHeadSHA, err := git.GetFullCommitID(ctx, ctx.tmpBasePath, "HEAD")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get full commit id for HEAD: %w", err)
|
||||
}
|
||||
if baseHeadSHA == newMergeHeadSHA {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Original repo to read template from.
|
||||
baseGitRepo, err := git.OpenRepository(ctx, ctx.pr.BaseRepo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("Unable to get Git repo for rebase: %v", err)
|
||||
return err
|
||||
}
|
||||
defer baseGitRepo.Close()
|
||||
|
||||
// Amend last commit message based on template, if one exists
|
||||
newMessage, err := getRebaseAmendMessage(ctx, baseGitRepo)
|
||||
if err != nil {
|
||||
log.Error("Unable to get commit message for amend: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if newMessage != "" {
|
||||
if err := git.NewCommand(ctx, "commit", "--amend").AddOptionFormat("--message=%s", newMessage).Run(&git.RunOpts{Dir: ctx.tmpBasePath}); err != nil {
|
||||
log.Error("Unable to amend commit message: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Perform rebase merge with merge commit.
|
||||
func doMergeRebaseMergeCommit(ctx *mergeContext, message string) error {
|
||||
cmd := git.NewCommand(ctx, "merge").AddArguments("--no-ff", "--no-commit").AddDynamicArguments(stagingBranch)
|
||||
|
||||
if err := runMergeCommand(ctx, repo_model.MergeStyleRebaseMerge, cmd); err != nil {
|
||||
log.Error("Unable to merge staging into base: %v", err)
|
||||
return err
|
||||
}
|
||||
if err := commitAndSignNoAuthor(ctx, message); err != nil {
|
||||
log.Error("Unable to make final commit: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// doMergeStyleRebase rebases the tracking branch on the base branch as the current HEAD with or with a merge commit to the original pr branch
|
||||
func doMergeStyleRebase(ctx *mergeContext, mergeStyle repo_model.MergeStyle, message string) error {
|
||||
if err := rebaseTrackingOnToBase(ctx, mergeStyle); err != nil {
|
||||
return err
|
||||
@@ -26,25 +112,9 @@ func doMergeStyleRebase(ctx *mergeContext, mergeStyle repo_model.MergeStyle, mes
|
||||
ctx.outbuf.Reset()
|
||||
ctx.errbuf.Reset()
|
||||
|
||||
cmd := git.NewCommand(ctx, "merge")
|
||||
if mergeStyle == repo_model.MergeStyleRebase {
|
||||
cmd.AddArguments("--ff-only")
|
||||
} else {
|
||||
cmd.AddArguments("--no-ff", "--no-commit")
|
||||
}
|
||||
cmd.AddDynamicArguments(stagingBranch)
|
||||
|
||||
// Prepare merge with commit
|
||||
if err := runMergeCommand(ctx, mergeStyle, cmd); err != nil {
|
||||
log.Error("Unable to merge staging into base: %v", err)
|
||||
return err
|
||||
}
|
||||
if mergeStyle == repo_model.MergeStyleRebaseMerge {
|
||||
if err := commitAndSignNoAuthor(ctx, message); err != nil {
|
||||
log.Error("Unable to make final commit: %v", err)
|
||||
return err
|
||||
}
|
||||
return doMergeRebaseFastForward(ctx)
|
||||
}
|
||||
|
||||
return nil
|
||||
return doMergeRebaseMergeCommit(ctx, message)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/avatar"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
)
|
||||
|
||||
// UploadAvatar saves custom avatar for user.
|
||||
func UploadAvatar(u *user_model.User, data []byte) error {
|
||||
avatarData, err := avatar.ProcessAvatarImage(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
u.UseCustomAvatar = true
|
||||
u.Avatar = avatar.HashAvatar(u.ID, data)
|
||||
if err = user_model.UpdateUserCols(ctx, u, "use_custom_avatar", "avatar"); err != nil {
|
||||
return fmt.Errorf("updateUser: %w", err)
|
||||
}
|
||||
|
||||
if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
|
||||
_, err := w.Write(avatarData)
|
||||
return err
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Failed to create dir %s: %w", u.CustomAvatarRelativePath(), err)
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
// DeleteAvatar deletes the user's custom avatar.
|
||||
func DeleteAvatar(u *user_model.User) error {
|
||||
aPath := u.CustomAvatarRelativePath()
|
||||
log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
|
||||
if len(u.Avatar) > 0 {
|
||||
if err := storage.Avatars.Delete(aPath); err != nil {
|
||||
return fmt.Errorf("Failed to remove %s: %w", aPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
u.UseCustomAvatar = false
|
||||
u.Avatar = ""
|
||||
if _, err := db.GetEngine(db.DefaultContext).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
|
||||
return fmt.Errorf("UpdateUser: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/services/agit"
|
||||
container_service "code.gitea.io/gitea/services/packages/container"
|
||||
)
|
||||
|
||||
func renameUser(ctx context.Context, u *user_model.User, newUserName string) error {
|
||||
if u.IsOrganization() {
|
||||
return fmt.Errorf("cannot rename organization")
|
||||
}
|
||||
|
||||
if err := user_model.ChangeUserName(ctx, u, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := agit.UserNameChanged(ctx, u, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container_service.UpdateRepositoryNames(ctx, u, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u.Name = newUserName
|
||||
u.LowerName = strings.ToLower(newUserName)
|
||||
if err := user_model.UpdateUser(ctx, u, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Trace("User name changed: %s -> %s", u.Name, newUserName)
|
||||
return nil
|
||||
}
|
||||
+82
-52
@@ -6,7 +6,8 @@ package user
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
@@ -17,29 +18,105 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/avatar"
|
||||
"code.gitea.io/gitea/modules/eventsource"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/agit"
|
||||
"code.gitea.io/gitea/services/packages"
|
||||
container_service "code.gitea.io/gitea/services/packages/container"
|
||||
)
|
||||
|
||||
// RenameUser renames a user
|
||||
func RenameUser(ctx context.Context, u *user_model.User, newUserName string) error {
|
||||
// Non-local users are not allowed to change their username.
|
||||
if !u.IsOrganization() && !u.IsLocal() {
|
||||
return user_model.ErrUserIsNotLocal{
|
||||
UID: u.ID,
|
||||
Name: u.Name,
|
||||
}
|
||||
}
|
||||
|
||||
if newUserName == u.Name {
|
||||
return user_model.ErrUsernameNotChanged{
|
||||
UID: u.ID,
|
||||
Name: u.Name,
|
||||
}
|
||||
}
|
||||
|
||||
if err := user_model.IsUsableUsername(newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
onlyCapitalization := strings.EqualFold(newUserName, u.Name)
|
||||
oldUserName := u.Name
|
||||
|
||||
if onlyCapitalization {
|
||||
u.Name = newUserName
|
||||
if err := user_model.UpdateUserCols(ctx, u, "name"); err != nil {
|
||||
u.Name = oldUserName
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
if err := renameUser(ctx, u, newUserName); err != nil {
|
||||
|
||||
isExist, err := user_model.IsUserExist(ctx, u.ID, newUserName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := committer.Commit(); err != nil {
|
||||
if isExist {
|
||||
return user_model.ErrUserAlreadyExist{
|
||||
Name: newUserName,
|
||||
}
|
||||
}
|
||||
|
||||
if err = repo_model.UpdateRepositoryOwnerName(ctx, oldUserName, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
|
||||
if err = user_model.NewUserRedirect(ctx, u.ID, oldUserName, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := agit.UserNameChanged(ctx, u, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := container_service.UpdateRepositoryNames(ctx, u, newUserName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u.Name = newUserName
|
||||
u.LowerName = strings.ToLower(newUserName)
|
||||
if err := user_model.UpdateUserCols(ctx, u, "name", "lower_name"); err != nil {
|
||||
u.Name = oldUserName
|
||||
u.LowerName = strings.ToLower(oldUserName)
|
||||
return err
|
||||
}
|
||||
|
||||
// Do not fail if directory does not exist
|
||||
if err = util.Rename(user_model.UserPath(oldUserName), user_model.UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
|
||||
u.Name = oldUserName
|
||||
u.LowerName = strings.ToLower(oldUserName)
|
||||
return fmt.Errorf("rename user directory: %w", err)
|
||||
}
|
||||
|
||||
if err = committer.Commit(); err != nil {
|
||||
u.Name = oldUserName
|
||||
u.LowerName = strings.ToLower(oldUserName)
|
||||
if err2 := util.Rename(user_model.UserPath(newUserName), user_model.UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) {
|
||||
log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2)
|
||||
return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteUser completely and permanently deletes everything of a user,
|
||||
@@ -240,50 +317,3 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error {
|
||||
|
||||
return user_model.DeleteInactiveEmailAddresses(ctx)
|
||||
}
|
||||
|
||||
// UploadAvatar saves custom avatar for user.
|
||||
func UploadAvatar(u *user_model.User, data []byte) error {
|
||||
avatarData, err := avatar.ProcessAvatarImage(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext(db.DefaultContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
u.UseCustomAvatar = true
|
||||
u.Avatar = avatar.HashAvatar(u.ID, data)
|
||||
if err = user_model.UpdateUserCols(ctx, u, "use_custom_avatar", "avatar"); err != nil {
|
||||
return fmt.Errorf("updateUser: %w", err)
|
||||
}
|
||||
|
||||
if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
|
||||
_, err := w.Write(avatarData)
|
||||
return err
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Failed to create dir %s: %w", u.CustomAvatarRelativePath(), err)
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
// DeleteAvatar deletes the user's custom avatar.
|
||||
func DeleteAvatar(u *user_model.User) error {
|
||||
aPath := u.CustomAvatarRelativePath()
|
||||
log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
|
||||
if len(u.Avatar) > 0 {
|
||||
if err := storage.Avatars.Delete(aPath); err != nil {
|
||||
return fmt.Errorf("Failed to remove %s: %w", aPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
u.UseCustomAvatar = false
|
||||
u.Avatar = ""
|
||||
if _, err := db.GetEngine(db.DefaultContext).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
|
||||
return fmt.Errorf("UpdateUser: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user