Skip to content

Support choose email when creating a commit via web UI (more) #33445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions models/fixtures/repository.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion models/fixtures/user.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions routers/web/repo/cherry_pick.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
51 changes: 25 additions & 26 deletions routers/web/repo/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
11 changes: 10 additions & 1 deletion routers/web/repo/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand Down
40 changes: 40 additions & 0 deletions routers/web/repo/webgit.go
Original file line number Diff line number Diff line change
@@ -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
}
7 changes: 3 additions & 4 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions services/forms/repo_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ type CherryPickForm struct {
LastCommit string
Revert bool
Signoff bool
CommitEmail string
}

// Validate validates the fields
Expand All @@ -781,6 +782,7 @@ type UploadRepoFileForm struct {
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
Files []string
Signoff bool
CommitEmail string
}

// Validate validates the fields
Expand Down Expand Up @@ -815,6 +817,7 @@ type DeleteRepoFileForm struct {
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
LastCommit string
Signoff bool
CommitEmail string
}

// Validate validates the fields
Expand Down
14 changes: 9 additions & 5 deletions services/repository/files/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type UploadRepoFileOptions struct {
Message string
Files []string // In UUID format.
Signoff bool
Author *IdentityOptions
Committer *IdentityOptions
}

type uploadInfo struct {
Expand Down Expand Up @@ -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 {
Expand Down

This file was deleted.

This file was deleted.

Binary file not shown.
Binary file not shown.

This file was deleted.

This file was deleted.

Loading