From 5a7b42dac7aa073de2d8665c1ced429cf52e3213 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 31 Jan 2025 10:36:18 +0800 Subject: [PATCH] Support choose email when creating a commit via web UI (more) (#33445) Follow #33432 --- models/fixtures/repository.yml | 13 -- models/fixtures/user.yml | 2 +- routers/web/repo/cherry_pick.go | 8 + routers/web/repo/editor.go | 51 +++-- routers/web/repo/patch.go | 11 +- routers/web/repo/webgit.go | 40 ++++ routers/web/web.go | 7 +- services/forms/repo_form.go | 3 + services/repository/files/upload.go | 14 +- .../user2/test_commit_revert.git/HEAD | 1 - .../user2/test_commit_revert.git/config | 8 - ...200c8e6707636a6cc3e0d8101fba08b19dcb91.idx | Bin 1268 -> 0 bytes ...00c8e6707636a6cc3e0d8101fba08b19dcb91.pack | Bin 609 -> 0 bytes .../user2/test_commit_revert.git/packed-refs | 3 - .../test_commit_revert.git/refs/heads/main | 1 - tests/integration/editor_test.go | 201 +++++++++++------- tests/integration/oauth_test.go | 4 - .../repo_mergecommit_revert_test.go | 37 ---- 18 files changed, 228 insertions(+), 176 deletions(-) create mode 100644 routers/web/repo/webgit.go delete mode 100644 tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD delete mode 100644 tests/gitea-repositories-meta/user2/test_commit_revert.git/config delete mode 100644 tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.idx delete mode 100644 tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.pack delete mode 100644 tests/gitea-repositories-meta/user2/test_commit_revert.git/packed-refs delete mode 100644 tests/gitea-repositories-meta/user2/test_commit_revert.git/refs/heads/main delete mode 100644 tests/integration/repo_mergecommit_revert_test.go diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index bbb028eb7b..552a78cbd2 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -1694,19 +1694,6 @@ is_fsck_enabled: true close_issues_via_commit_in_any_branch: false -- - id: 59 - owner_id: 2 - owner_name: user2 - lower_name: test_commit_revert - name: test_commit_revert - default_branch: main - is_empty: false - is_archived: false - is_private: true - status: 0 - num_issues: 0 - - id: 60 owner_id: 40 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index b3bece5589..976a236011 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -67,7 +67,7 @@ num_followers: 2 num_following: 1 num_stars: 2 - num_repos: 15 + num_repos: 14 num_teams: 0 num_members: 0 visibility: 0 diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go index 33d941c9d8..616bb8c6cb 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -114,11 +114,19 @@ func CherryPickPost(ctx *context.Context) { message += "\n\n" + form.CommitMessage } + gitCommitter, valid := WebGitOperationGetCommitChosenEmailIdentity(ctx, form.CommitEmail) + if !valid { + ctx.Data["Err_CommitEmail"] = true + ctx.RenderWithErr(ctx.Tr("repo.editor.invalid_commit_email"), tplCherryPick, &form) + return + } opts := &files.ApplyDiffPatchOptions{ LastCommitID: form.LastCommit, OldBranch: ctx.Repo.BranchName, NewBranch: branchName, Message: message, + Author: gitCommitter, + Committer: gitCommitter, } // First lets try the simple plain read-tree -m approach diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 48e041fb1d..cc4ffc698d 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -13,7 +13,6 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" @@ -103,18 +102,6 @@ func getParentTreeFields(treePath string) (treeNames, treePaths []string) { return treeNames, treePaths } -func getCandidateEmailAddresses(ctx *context.Context) []string { - emails, err := user_model.GetActivatedEmailAddresses(ctx, ctx.Doer.ID) - if err != nil { - log.Error("getCandidateEmailAddresses: GetActivatedEmailAddresses: %v", err) - } - - if ctx.Doer.KeepEmailPrivate { - emails = append([]string{ctx.Doer.GetPlaceholderEmail()}, emails...) - } - return emails -} - func editFileCommon(ctx *context.Context, isNewFile bool) { ctx.Data["PageIsEdit"] = true ctx.Data["IsNewFile"] = isNewFile @@ -123,8 +110,6 @@ func editFileCommon(ctx *context.Context, isNewFile bool) { ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") ctx.Data["IsEditingFileOnly"] = ctx.FormString("return_uri") != "" ctx.Data["ReturnURI"] = ctx.FormString("return_uri") - ctx.Data["CommitCandidateEmails"] = getCandidateEmailAddresses(ctx) - ctx.Data["CommitDefaultEmail"] = ctx.Doer.GetEmail() } func editFile(ctx *context.Context, isNewFile bool) { @@ -287,15 +272,11 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b message += "\n\n" + form.CommitMessage } - gitCommitter := &files_service.IdentityOptions{} - if form.CommitEmail != "" { - if util.SliceContainsString(getCandidateEmailAddresses(ctx), form.CommitEmail, true) { - gitCommitter.GitUserEmail = form.CommitEmail - } else { - ctx.Data["Err_CommitEmail"] = true - ctx.RenderWithErr(ctx.Tr("repo.editor.invalid_commit_email"), tplEditFile, &form) - return - } + gitCommitter, valid := WebGitOperationGetCommitChosenEmailIdentity(ctx, form.CommitEmail) + if !valid { + ctx.Data["Err_CommitEmail"] = true + ctx.RenderWithErr(ctx.Tr("repo.editor.invalid_commit_email"), tplEditFile, &form) + return } operation := "update" @@ -515,6 +496,13 @@ func DeleteFilePost(ctx *context.Context) { message += "\n\n" + form.CommitMessage } + gitCommitter, valid := WebGitOperationGetCommitChosenEmailIdentity(ctx, form.CommitEmail) + if !valid { + ctx.Data["Err_CommitEmail"] = true + ctx.RenderWithErr(ctx.Tr("repo.editor.invalid_commit_email"), tplDeleteFile, &form) + return + } + if _, err := files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.ChangeRepoFilesOptions{ LastCommitID: form.LastCommit, OldBranch: ctx.Repo.BranchName, @@ -525,8 +513,10 @@ func DeleteFilePost(ctx *context.Context) { TreePath: ctx.Repo.TreePath, }, }, - Message: message, - Signoff: form.Signoff, + Message: message, + Signoff: form.Signoff, + Author: gitCommitter, + Committer: gitCommitter, }); err != nil { // This is where we handle all the errors thrown by repofiles.DeleteRepoFile if git.IsErrNotExist(err) || files_service.IsErrRepoFileDoesNotExist(err) { @@ -726,6 +716,13 @@ func UploadFilePost(ctx *context.Context) { message += "\n\n" + form.CommitMessage } + gitCommitter, valid := WebGitOperationGetCommitChosenEmailIdentity(ctx, form.CommitEmail) + if !valid { + ctx.Data["Err_CommitEmail"] = true + ctx.RenderWithErr(ctx.Tr("repo.editor.invalid_commit_email"), tplUploadFile, &form) + return + } + if err := files_service.UploadRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, &files_service.UploadRepoFileOptions{ LastCommitID: ctx.Repo.CommitID, OldBranch: oldBranchName, @@ -734,6 +731,8 @@ func UploadFilePost(ctx *context.Context) { Message: message, Files: form.Files, Signoff: form.Signoff, + Author: gitCommitter, + Committer: gitCommitter, }); err != nil { if git_model.IsErrLFSFileLocked(err) { ctx.Data["Err_TreePath"] = true diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go index 4d47a705d6..120b3469f6 100644 --- a/routers/web/repo/patch.go +++ b/routers/web/repo/patch.go @@ -66,7 +66,7 @@ func NewDiffPatchPost(ctx *context.Context) { return } - // Cannot commit to a an existing branch if user doesn't have rights + // Cannot commit to an existing branch if user doesn't have rights if branchName == ctx.Repo.BranchName && !canCommit { ctx.Data["Err_NewBranchName"] = true ctx.Data["commit_choice"] = frmCommitChoiceNewBranch @@ -86,12 +86,21 @@ func NewDiffPatchPost(ctx *context.Context) { message += "\n\n" + form.CommitMessage } + gitCommitter, valid := WebGitOperationGetCommitChosenEmailIdentity(ctx, form.CommitEmail) + if !valid { + ctx.Data["Err_CommitEmail"] = true + ctx.RenderWithErr(ctx.Tr("repo.editor.invalid_commit_email"), tplPatchFile, &form) + return + } + fileResponse, err := files.ApplyDiffPatch(ctx, ctx.Repo.Repository, ctx.Doer, &files.ApplyDiffPatchOptions{ LastCommitID: form.LastCommit, OldBranch: ctx.Repo.BranchName, NewBranch: branchName, Message: message, Content: strings.ReplaceAll(form.Content, "\r", ""), + Author: gitCommitter, + Committer: gitCommitter, }) if err != nil { if git_model.IsErrBranchAlreadyExists(err) { diff --git a/routers/web/repo/webgit.go b/routers/web/repo/webgit.go new file mode 100644 index 0000000000..5f390197e7 --- /dev/null +++ b/routers/web/repo/webgit.go @@ -0,0 +1,40 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" + files_service "code.gitea.io/gitea/services/repository/files" +) + +func WebGitOperationCommonData(ctx *context.Context) { + // TODO: more places like "wiki page" and "merging a pull request or creating an auto merge merging task" + emails, err := user_model.GetActivatedEmailAddresses(ctx, ctx.Doer.ID) + if err != nil { + log.Error("WebGitOperationCommonData: GetActivatedEmailAddresses: %v", err) + } + if ctx.Doer.KeepEmailPrivate { + emails = append([]string{ctx.Doer.GetPlaceholderEmail()}, emails...) + } + ctx.Data["CommitCandidateEmails"] = emails + ctx.Data["CommitDefaultEmail"] = ctx.Doer.GetEmail() +} + +func WebGitOperationGetCommitChosenEmailIdentity(ctx *context.Context, email string) (_ *files_service.IdentityOptions, valid bool) { + if ctx.Data["CommitCandidateEmails"] == nil { + setting.PanicInDevOrTesting("no CommitCandidateEmails in context data") + } + emails, _ := ctx.Data["CommitCandidateEmails"].([]string) + if email == "" { + return nil, true + } + if util.SliceContainsString(emails, email, true) { + return &files_service.IdentityOptions{GitUserEmail: email}, true + } + return nil, false +} diff --git a/routers/web/web.go b/routers/web/web.go index b02bbe037f..bbf257a493 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1294,21 +1294,20 @@ func registerRoutes(m *web.Router) { m.Group("/{username}/{reponame}", func() { // repo code m.Group("", func() { m.Group("", func() { + m.Post("/_preview/*", web.Bind(forms.EditPreviewDiffForm{}), repo.DiffPreviewPost) m.Combo("/_edit/*").Get(repo.EditFile). Post(web.Bind(forms.EditRepoFileForm{}), repo.EditFilePost) m.Combo("/_new/*").Get(repo.NewFile). Post(web.Bind(forms.EditRepoFileForm{}), repo.NewFilePost) - m.Post("/_preview/*", web.Bind(forms.EditPreviewDiffForm{}), repo.DiffPreviewPost) m.Combo("/_delete/*").Get(repo.DeleteFile). Post(web.Bind(forms.DeleteRepoFileForm{}), repo.DeleteFilePost) - m.Combo("/_upload/*", repo.MustBeAbleToUpload). - Get(repo.UploadFile). + m.Combo("/_upload/*", repo.MustBeAbleToUpload).Get(repo.UploadFile). Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost) m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch). Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost) m.Combo("/_cherrypick/{sha:([a-f0-9]{7,64})}/*").Get(repo.CherryPick). Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost) - }, context.RepoRefByType(git.RefTypeBranch), context.CanWriteToBranch()) + }, context.RepoRefByType(git.RefTypeBranch), context.CanWriteToBranch(), repo.WebGitOperationCommonData) m.Group("", func() { m.Post("/upload-file", repo.UploadFileToServer) m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer) diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 40e15f2d5c..2c6373e03c 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -756,6 +756,7 @@ type CherryPickForm struct { LastCommit string Revert bool Signoff bool + CommitEmail string } // Validate validates the fields @@ -781,6 +782,7 @@ type UploadRepoFileForm struct { NewBranchName string `binding:"GitRefName;MaxSize(100)"` Files []string Signoff bool + CommitEmail string } // Validate validates the fields @@ -815,6 +817,7 @@ type DeleteRepoFileForm struct { NewBranchName string `binding:"GitRefName;MaxSize(100)"` LastCommit string Signoff bool + CommitEmail string } // Validate validates the fields diff --git a/services/repository/files/upload.go b/services/repository/files/upload.go index af32bc4c85..3c58598427 100644 --- a/services/repository/files/upload.go +++ b/services/repository/files/upload.go @@ -27,6 +27,8 @@ type UploadRepoFileOptions struct { Message string Files []string // In UUID format. Signoff bool + Author *IdentityOptions + Committer *IdentityOptions } type uploadInfo struct { @@ -130,11 +132,13 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use // Now commit the tree commitOpts := &CommitTreeUserOptions{ - ParentCommitID: opts.LastCommitID, - TreeHash: treeHash, - CommitMessage: opts.Message, - SignOff: opts.Signoff, - DoerUser: doer, + ParentCommitID: opts.LastCommitID, + TreeHash: treeHash, + CommitMessage: opts.Message, + SignOff: opts.Signoff, + DoerUser: doer, + AuthorIdentity: opts.Author, + CommitterIdentity: opts.Committer, } commitHash, err := t.CommitTree(commitOpts) if err != nil { diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD b/tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD deleted file mode 100644 index b870d82622..0000000000 --- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/heads/main diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/config b/tests/gitea-repositories-meta/user2/test_commit_revert.git/config deleted file mode 100644 index 57bbcba5be..0000000000 --- a/tests/gitea-repositories-meta/user2/test_commit_revert.git/config +++ /dev/null @@ -1,8 +0,0 @@ -[core] - repositoryformatversion = 0 - filemode = true - bare = true - ignorecase = true - precomposeunicode = true -[remote "origin"] - url = https://try.gitea.io/me-heer/test_commit_revert.git diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.idx b/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.idx deleted file mode 100644 index 77bcbe7fb4caeaf783d375068e6ffad1a61ed6f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1268 zcmexg;-AdGz`z8=v<8eo3&_PF_YD+g2HH(a%mOrj6c0=oumZz=pfMZJ4dh~WpkAtA ziT!>0sdIKX`Q+r7_O6Ur@4djIQr(9k=xzwdk9FE7To^R}r(d6a^sw8itW75x*G+gB zJLmjK_lrp}ojOnB{w=l+mP?F$x@Cip-r*TtF8d5W?KM9hE4Ed{`{q?8<@3(p#qS*Z z6?X6S>El699d>OwXZKwA@}K@YrklRMmHNzh>-92&^UoPf=J!P_8Ex$p5RAF4$7r)< z|M#umx9-w6^fNoBCjH=l=F9XikL7_y$T?t9-~gm0f!H62{{h2*2Ph^mQGur~ojo}# m=kS9Y0`j{!HqJdgaY~07L(uVgcZ<)l8XQVHe#P^wn?3-RA9Cve diff --git a/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.pack b/tests/gitea-repositories-meta/user2/test_commit_revert.git/objects/pack/pack-91200c8e6707636a6cc3e0d8101fba08b19dcb91.pack deleted file mode 100644 index 7271cdaeb87741f0ed005bdae83367b7e3dd76ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 609 zcmWG=boORoU|<4b_8F2DbLRH>`W-e9Y58t>baI49%d8{yD`ORpu-;JE=(f!`Pg%9F zAf9`#t*c0&blku9iJsbyWO}4;yFP z%7iHn>OIYzR$HvRT%NA^8pWv~9j*;B@8BN$p*G1 z_wCH-hqq<^duMh%m^c1IzWwt1r&vRF{EV|RS@eskb64Y;*G!GP6?0}E{4=r8>CO>5 zV>RZ(oyTRC@bZXm;caN>*50C^x=|%mQP)`gYQXv>i(0rD^doqK=5Ygq@QfqhAq5fF ziJvnG&>DY92Q5*&f8<>p`?>?xR*O$FPdH&E=56J^q+*+ic!g3mS89{@ zv53icL`*t=JX*?svmmBHQQ!W~yxN55@}tS&{iixseOrBH-khy&zZLku_@3Fj^;FM) z{zvmR>y);J{Ym@CsKRK~v6QJ|jfw5tr$LTYkrdPCAY9!vsuCoctS>5sd>}s!5 z&*$#%zHj+Wn}^}W1io*UAmv784~*?~gJPg+!^9h?kOkiYS{K0T~q5@A}I(u?f&fy0)1mt&dY@B;~A^`875