mirror of
https://github.com/go-gitea/gitea.git
synced 2025-01-31 09:41:28 +02:00
Support choose email when creating a commit via web UI (#33432)
Initial PR for #24469
This commit is contained in:
parent
ac2d97cb61
commit
256b94e9e9
@ -542,3 +542,13 @@ func IsEmailDomainAllowed(email string) bool {
|
|||||||
|
|
||||||
return validation.IsEmailDomainListed(setting.Service.EmailDomainAllowList, email)
|
return validation.IsEmailDomainListed(setting.Service.EmailDomainAllowList, email)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetActivatedEmailAddresses(ctx context.Context, uid int64) ([]string, error) {
|
||||||
|
emails := make([]string, 0, 2)
|
||||||
|
if err := db.GetEngine(ctx).Table("email_address").Select("email").
|
||||||
|
Where("uid=? AND is_activated=?", uid, true).Asc("id").
|
||||||
|
Find(&emails); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return emails, nil
|
||||||
|
}
|
||||||
|
@ -214,7 +214,7 @@ func (u *User) GetPlaceholderEmail() string {
|
|||||||
return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
|
return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmail returns an noreply email, if the user has set to keep his
|
// GetEmail returns a noreply email, if the user has set to keep his
|
||||||
// email address private, otherwise the primary email address.
|
// email address private, otherwise the primary email address.
|
||||||
func (u *User) GetEmail() string {
|
func (u *User) GetEmail() string {
|
||||||
if u.KeepEmailPrivate {
|
if u.KeepEmailPrivate {
|
||||||
|
@ -1345,6 +1345,8 @@ editor.new_branch_name_desc = New branch name…
|
|||||||
editor.cancel = Cancel
|
editor.cancel = Cancel
|
||||||
editor.filename_cannot_be_empty = The filename cannot be empty.
|
editor.filename_cannot_be_empty = The filename cannot be empty.
|
||||||
editor.filename_is_invalid = The filename is invalid: "%s".
|
editor.filename_is_invalid = The filename is invalid: "%s".
|
||||||
|
editor.commit_email = Commit email
|
||||||
|
editor.invalid_commit_email = The email for the commit is invalid.
|
||||||
editor.branch_does_not_exist = Branch "%s" does not exist in this repository.
|
editor.branch_does_not_exist = Branch "%s" does not exist in this repository.
|
||||||
editor.branch_already_exists = Branch "%s" already exists in this repository.
|
editor.branch_already_exists = Branch "%s" already exists in this repository.
|
||||||
editor.directory_is_a_file = Directory name "%s" is already used as a filename in this repository.
|
editor.directory_is_a_file = Directory name "%s" is already used as a filename in this repository.
|
||||||
|
@ -489,12 +489,12 @@ func ChangeFiles(ctx *context.APIContext) {
|
|||||||
OldBranch: apiOpts.BranchName,
|
OldBranch: apiOpts.BranchName,
|
||||||
NewBranch: apiOpts.NewBranchName,
|
NewBranch: apiOpts.NewBranchName,
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Committer.Name,
|
GitUserName: apiOpts.Committer.Name,
|
||||||
Email: apiOpts.Committer.Email,
|
GitUserEmail: apiOpts.Committer.Email,
|
||||||
},
|
},
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Author.Name,
|
GitUserName: apiOpts.Author.Name,
|
||||||
Email: apiOpts.Author.Email,
|
GitUserEmail: apiOpts.Author.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: apiOpts.Dates.Author,
|
Author: apiOpts.Dates.Author,
|
||||||
@ -586,12 +586,12 @@ func CreateFile(ctx *context.APIContext) {
|
|||||||
OldBranch: apiOpts.BranchName,
|
OldBranch: apiOpts.BranchName,
|
||||||
NewBranch: apiOpts.NewBranchName,
|
NewBranch: apiOpts.NewBranchName,
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Committer.Name,
|
GitUserName: apiOpts.Committer.Name,
|
||||||
Email: apiOpts.Committer.Email,
|
GitUserEmail: apiOpts.Committer.Email,
|
||||||
},
|
},
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Author.Name,
|
GitUserName: apiOpts.Author.Name,
|
||||||
Email: apiOpts.Author.Email,
|
GitUserEmail: apiOpts.Author.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: apiOpts.Dates.Author,
|
Author: apiOpts.Dates.Author,
|
||||||
@ -689,12 +689,12 @@ func UpdateFile(ctx *context.APIContext) {
|
|||||||
OldBranch: apiOpts.BranchName,
|
OldBranch: apiOpts.BranchName,
|
||||||
NewBranch: apiOpts.NewBranchName,
|
NewBranch: apiOpts.NewBranchName,
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Committer.Name,
|
GitUserName: apiOpts.Committer.Name,
|
||||||
Email: apiOpts.Committer.Email,
|
GitUserEmail: apiOpts.Committer.Email,
|
||||||
},
|
},
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Author.Name,
|
GitUserName: apiOpts.Author.Name,
|
||||||
Email: apiOpts.Author.Email,
|
GitUserEmail: apiOpts.Author.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: apiOpts.Dates.Author,
|
Author: apiOpts.Dates.Author,
|
||||||
@ -848,12 +848,12 @@ func DeleteFile(ctx *context.APIContext) {
|
|||||||
OldBranch: apiOpts.BranchName,
|
OldBranch: apiOpts.BranchName,
|
||||||
NewBranch: apiOpts.NewBranchName,
|
NewBranch: apiOpts.NewBranchName,
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Committer.Name,
|
GitUserName: apiOpts.Committer.Name,
|
||||||
Email: apiOpts.Committer.Email,
|
GitUserEmail: apiOpts.Committer.Email,
|
||||||
},
|
},
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: apiOpts.Author.Name,
|
GitUserName: apiOpts.Author.Name,
|
||||||
Email: apiOpts.Author.Email,
|
GitUserEmail: apiOpts.Author.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: apiOpts.Dates.Author,
|
Author: apiOpts.Dates.Author,
|
||||||
|
@ -58,12 +58,12 @@ func ApplyDiffPatch(ctx *context.APIContext) {
|
|||||||
OldBranch: apiOpts.BranchName,
|
OldBranch: apiOpts.BranchName,
|
||||||
NewBranch: apiOpts.NewBranchName,
|
NewBranch: apiOpts.NewBranchName,
|
||||||
Committer: &files.IdentityOptions{
|
Committer: &files.IdentityOptions{
|
||||||
Name: apiOpts.Committer.Name,
|
GitUserName: apiOpts.Committer.Name,
|
||||||
Email: apiOpts.Committer.Email,
|
GitUserEmail: apiOpts.Committer.Email,
|
||||||
},
|
},
|
||||||
Author: &files.IdentityOptions{
|
Author: &files.IdentityOptions{
|
||||||
Name: apiOpts.Author.Name,
|
GitUserName: apiOpts.Author.Name,
|
||||||
Email: apiOpts.Author.Email,
|
GitUserEmail: apiOpts.Author.Email,
|
||||||
},
|
},
|
||||||
Dates: &files.CommitDateOptions{
|
Dates: &files.CommitDateOptions{
|
||||||
Author: apiOpts.Dates.Author,
|
Author: apiOpts.Dates.Author,
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"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/charset"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
@ -102,10 +103,32 @@ func getParentTreeFields(treePath string) (treeNames, treePaths []string) {
|
|||||||
return treeNames, treePaths
|
return treeNames, treePaths
|
||||||
}
|
}
|
||||||
|
|
||||||
func editFile(ctx *context.Context, isNewFile bool) {
|
func getCandidateEmailAddresses(ctx *context.Context) []string {
|
||||||
ctx.Data["PageIsViewCode"] = true
|
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["PageIsEdit"] = true
|
||||||
ctx.Data["IsNewFile"] = isNewFile
|
ctx.Data["IsNewFile"] = isNewFile
|
||||||
|
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()
|
||||||
|
ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",")
|
||||||
|
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) {
|
||||||
|
editFileCommon(ctx, isNewFile)
|
||||||
canCommit := renderCommitRights(ctx)
|
canCommit := renderCommitRights(ctx)
|
||||||
|
|
||||||
treePath := cleanUploadFileName(ctx.Repo.TreePath)
|
treePath := cleanUploadFileName(ctx.Repo.TreePath)
|
||||||
@ -180,22 +203,13 @@ func editFile(ctx *context.Context, isNewFile bool) {
|
|||||||
|
|
||||||
ctx.Data["TreeNames"] = treeNames
|
ctx.Data["TreeNames"] = treeNames
|
||||||
ctx.Data["TreePaths"] = treePaths
|
ctx.Data["TreePaths"] = treePaths
|
||||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL()
|
|
||||||
ctx.Data["commit_summary"] = ""
|
ctx.Data["commit_summary"] = ""
|
||||||
ctx.Data["commit_message"] = ""
|
ctx.Data["commit_message"] = ""
|
||||||
if canCommit {
|
ctx.Data["commit_choice"] = util.Iif(canCommit, frmCommitChoiceDirect, frmCommitChoiceNewBranch)
|
||||||
ctx.Data["commit_choice"] = frmCommitChoiceDirect
|
|
||||||
} else {
|
|
||||||
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
|
|
||||||
}
|
|
||||||
ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
|
ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
|
||||||
ctx.Data["last_commit"] = ctx.Repo.CommitID
|
ctx.Data["last_commit"] = ctx.Repo.CommitID
|
||||||
ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",")
|
|
||||||
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
|
|
||||||
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, treePath)
|
|
||||||
|
|
||||||
ctx.Data["IsEditingFileOnly"] = ctx.FormString("return_uri") != ""
|
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, treePath)
|
||||||
ctx.Data["ReturnURI"] = ctx.FormString("return_uri")
|
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplEditFile)
|
ctx.HTML(http.StatusOK, tplEditFile)
|
||||||
}
|
}
|
||||||
@ -224,6 +238,9 @@ func NewFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile bool) {
|
func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile bool) {
|
||||||
|
editFileCommon(ctx, isNewFile)
|
||||||
|
ctx.Data["PageHasPosted"] = true
|
||||||
|
|
||||||
canCommit := renderCommitRights(ctx)
|
canCommit := renderCommitRights(ctx)
|
||||||
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
||||||
branchName := ctx.Repo.BranchName
|
branchName := ctx.Repo.BranchName
|
||||||
@ -231,21 +248,15 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||||||
branchName = form.NewBranchName
|
branchName = form.NewBranchName
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["PageIsEdit"] = true
|
|
||||||
ctx.Data["PageHasPosted"] = true
|
|
||||||
ctx.Data["IsNewFile"] = isNewFile
|
|
||||||
ctx.Data["TreePath"] = form.TreePath
|
ctx.Data["TreePath"] = form.TreePath
|
||||||
ctx.Data["TreeNames"] = treeNames
|
ctx.Data["TreeNames"] = treeNames
|
||||||
ctx.Data["TreePaths"] = treePaths
|
ctx.Data["TreePaths"] = treePaths
|
||||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName)
|
|
||||||
ctx.Data["FileContent"] = form.Content
|
ctx.Data["FileContent"] = form.Content
|
||||||
ctx.Data["commit_summary"] = form.CommitSummary
|
ctx.Data["commit_summary"] = form.CommitSummary
|
||||||
ctx.Data["commit_message"] = form.CommitMessage
|
ctx.Data["commit_message"] = form.CommitMessage
|
||||||
ctx.Data["commit_choice"] = form.CommitChoice
|
ctx.Data["commit_choice"] = form.CommitChoice
|
||||||
ctx.Data["new_branch_name"] = form.NewBranchName
|
ctx.Data["new_branch_name"] = form.NewBranchName
|
||||||
ctx.Data["last_commit"] = ctx.Repo.CommitID
|
ctx.Data["last_commit"] = ctx.Repo.CommitID
|
||||||
ctx.Data["PreviewableExtensions"] = strings.Join(markup.PreviewableExtensions(), ",")
|
|
||||||
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
|
|
||||||
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, form.TreePath)
|
ctx.Data["EditorconfigJson"] = GetEditorConfig(ctx, form.TreePath)
|
||||||
|
|
||||||
if ctx.HasError() {
|
if ctx.HasError() {
|
||||||
@ -253,7 +264,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||||||
return
|
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 {
|
if branchName == ctx.Repo.BranchName && !canCommit {
|
||||||
ctx.Data["Err_NewBranchName"] = true
|
ctx.Data["Err_NewBranchName"] = true
|
||||||
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
|
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
|
||||||
@ -276,6 +287,17 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||||||
message += "\n\n" + form.CommitMessage
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
operation := "update"
|
operation := "update"
|
||||||
if isNewFile {
|
if isNewFile {
|
||||||
operation = "create"
|
operation = "create"
|
||||||
@ -295,6 +317,8 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Signoff: form.Signoff,
|
Signoff: form.Signoff,
|
||||||
|
Author: gitCommitter,
|
||||||
|
Committer: gitCommitter,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
// This is where we handle all the errors thrown by files_service.ChangeRepoFiles
|
// This is where we handle all the errors thrown by files_service.ChangeRepoFiles
|
||||||
if git.IsErrNotExist(err) {
|
if git.IsErrNotExist(err) {
|
||||||
|
@ -720,6 +720,7 @@ type EditRepoFileForm struct {
|
|||||||
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
|
NewBranchName string `binding:"GitRefName;MaxSize(100)"`
|
||||||
LastCommit string
|
LastCommit string
|
||||||
Signoff bool
|
Signoff bool
|
||||||
|
CommitEmail string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
@ -296,8 +295,13 @@ func alterRepositoryContent(ctx context.Context, doer *user_model.User, repo *re
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
commitOpts := &files_service.CommitTreeUserOptions{
|
||||||
commitHash, err := t.CommitTreeWithDate(lastCommitID, doer, doer, treeHash, commitMessage, false, now, now)
|
ParentCommitID: lastCommitID,
|
||||||
|
TreeHash: treeHash,
|
||||||
|
CommitMessage: commitMessage,
|
||||||
|
DoerUser: doer,
|
||||||
|
}
|
||||||
|
commitHash, err := t.CommitTree(commitOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -32,15 +32,13 @@ func (err ErrCommitIDDoesNotMatch) Error() string {
|
|||||||
return fmt.Sprintf("file CommitID does not match [given: %s, expected: %s]", err.GivenCommitID, err.CurrentCommitID)
|
return fmt.Sprintf("file CommitID does not match [given: %s, expected: %s]", err.GivenCommitID, err.CurrentCommitID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CherryPick cherrypicks or reverts a commit to the given repository
|
// CherryPick cherry-picks or reverts a commit to the given repository
|
||||||
func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, revert bool, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) {
|
func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, revert bool, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) {
|
||||||
if err := opts.Validate(ctx, repo, doer); err != nil {
|
if err := opts.Validate(ctx, repo, doer); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
message := strings.TrimSpace(opts.Message)
|
message := strings.TrimSpace(opts.Message)
|
||||||
|
|
||||||
author, committer := GetAuthorAndCommitterUsers(opts.Author, opts.Committer, doer)
|
|
||||||
|
|
||||||
t, err := NewTemporaryUploadRepository(ctx, repo)
|
t, err := NewTemporaryUploadRepository(ctx, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("NewTemporaryUploadRepository failed: %v", err)
|
log.Error("NewTemporaryUploadRepository failed: %v", err)
|
||||||
@ -112,12 +110,21 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now commit the tree
|
// Now commit the tree
|
||||||
var commitHash string
|
commitOpts := &CommitTreeUserOptions{
|
||||||
if opts.Dates != nil {
|
ParentCommitID: "HEAD",
|
||||||
commitHash, err = t.CommitTreeWithDate("HEAD", author, committer, treeHash, message, opts.Signoff, opts.Dates.Author, opts.Dates.Committer)
|
TreeHash: treeHash,
|
||||||
} else {
|
CommitMessage: message,
|
||||||
commitHash, err = t.CommitTree("HEAD", author, committer, treeHash, message, opts.Signoff)
|
SignOff: opts.Signoff,
|
||||||
|
DoerUser: doer,
|
||||||
|
AuthorIdentity: opts.Author,
|
||||||
|
AuthorTime: nil,
|
||||||
|
CommitterIdentity: opts.Committer,
|
||||||
|
CommitterTime: nil,
|
||||||
}
|
}
|
||||||
|
if opts.Dates != nil {
|
||||||
|
commitOpts.AuthorTime, commitOpts.CommitterTime = &opts.Dates.Author, &opts.Dates.Committer
|
||||||
|
}
|
||||||
|
commitHash, err := t.CommitTree(commitOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@ -111,51 +110,6 @@ func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*ap
|
|||||||
return fileCommit, nil
|
return fileCommit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAuthorAndCommitterUsers Gets the author and committer user objects from the IdentityOptions
|
|
||||||
func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_model.User) (authorUser, committerUser *user_model.User) {
|
|
||||||
// Committer and author are optional. If they are not the doer (not same email address)
|
|
||||||
// then we use bogus User objects for them to store their FullName and Email.
|
|
||||||
// If only one of the two are provided, we set both of them to it.
|
|
||||||
// If neither are provided, both are the doer.
|
|
||||||
if committer != nil && committer.Email != "" {
|
|
||||||
if doer != nil && strings.EqualFold(doer.Email, committer.Email) {
|
|
||||||
committerUser = doer // the committer is the doer, so will use their user object
|
|
||||||
if committer.Name != "" {
|
|
||||||
committerUser.FullName = committer.Name
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
committerUser = &user_model.User{
|
|
||||||
FullName: committer.Name,
|
|
||||||
Email: committer.Email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if author != nil && author.Email != "" {
|
|
||||||
if doer != nil && strings.EqualFold(doer.Email, author.Email) {
|
|
||||||
authorUser = doer // the author is the doer, so will use their user object
|
|
||||||
if authorUser.Name != "" {
|
|
||||||
authorUser.FullName = author.Name
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
authorUser = &user_model.User{
|
|
||||||
FullName: author.Name,
|
|
||||||
Email: author.Email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if authorUser == nil {
|
|
||||||
if committerUser != nil {
|
|
||||||
authorUser = committerUser // No valid author was given so use the committer
|
|
||||||
} else if doer != nil {
|
|
||||||
authorUser = doer // No valid author was given and no valid committer so use the doer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if committerUser == nil {
|
|
||||||
committerUser = authorUser // No valid committer so use the author as the committer (was set to a valid user above)
|
|
||||||
}
|
|
||||||
return authorUser, committerUser
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrFilenameInvalid represents a "FilenameInvalid" kind of error.
|
// ErrFilenameInvalid represents a "FilenameInvalid" kind of error.
|
||||||
type ErrFilenameInvalid struct {
|
type ErrFilenameInvalid struct {
|
||||||
Path string
|
Path string
|
||||||
|
@ -126,8 +126,6 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
|
|||||||
|
|
||||||
message := strings.TrimSpace(opts.Message)
|
message := strings.TrimSpace(opts.Message)
|
||||||
|
|
||||||
author, committer := GetAuthorAndCommitterUsers(opts.Author, opts.Committer, doer)
|
|
||||||
|
|
||||||
t, err := NewTemporaryUploadRepository(ctx, repo)
|
t, err := NewTemporaryUploadRepository(ctx, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("NewTemporaryUploadRepository failed: %v", err)
|
log.Error("NewTemporaryUploadRepository failed: %v", err)
|
||||||
@ -187,12 +185,21 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now commit the tree
|
// Now commit the tree
|
||||||
var commitHash string
|
commitOpts := &CommitTreeUserOptions{
|
||||||
if opts.Dates != nil {
|
ParentCommitID: "HEAD",
|
||||||
commitHash, err = t.CommitTreeWithDate("HEAD", author, committer, treeHash, message, opts.Signoff, opts.Dates.Author, opts.Dates.Committer)
|
TreeHash: treeHash,
|
||||||
} else {
|
CommitMessage: message,
|
||||||
commitHash, err = t.CommitTree("HEAD", author, committer, treeHash, message, opts.Signoff)
|
SignOff: opts.Signoff,
|
||||||
|
DoerUser: doer,
|
||||||
|
AuthorIdentity: opts.Author,
|
||||||
|
AuthorTime: nil,
|
||||||
|
CommitterIdentity: opts.Committer,
|
||||||
|
CommitterTime: nil,
|
||||||
}
|
}
|
||||||
|
if opts.Dates != nil {
|
||||||
|
commitOpts.AuthorTime, commitOpts.CommitterTime = &opts.Dates.Author, &opts.Dates.Committer
|
||||||
|
}
|
||||||
|
commitHash, err := t.CommitTree(commitOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||||
"code.gitea.io/gitea/services/gitdiff"
|
"code.gitea.io/gitea/services/gitdiff"
|
||||||
)
|
)
|
||||||
@ -225,15 +226,53 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, erro
|
|||||||
return strings.TrimSpace(stdout), nil
|
return strings.TrimSpace(stdout), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitTree creates a commit from a given tree for the user with provided message
|
type CommitTreeUserOptions struct {
|
||||||
func (t *TemporaryUploadRepository) CommitTree(parent string, author, committer *user_model.User, treeHash, message string, signoff bool) (string, error) {
|
ParentCommitID string
|
||||||
return t.CommitTreeWithDate(parent, author, committer, treeHash, message, signoff, time.Now(), time.Now())
|
TreeHash string
|
||||||
|
CommitMessage string
|
||||||
|
SignOff bool
|
||||||
|
|
||||||
|
DoerUser *user_model.User
|
||||||
|
|
||||||
|
AuthorIdentity *IdentityOptions // if nil, use doer
|
||||||
|
AuthorTime *time.Time // if nil, use now
|
||||||
|
CommitterIdentity *IdentityOptions
|
||||||
|
CommitterTime *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitTreeWithDate creates a commit from a given tree for the user with provided message
|
func makeGitUserSignature(doer *user_model.User, identity, other *IdentityOptions) *git.Signature {
|
||||||
func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, committer *user_model.User, treeHash, message string, signoff bool, authorDate, committerDate time.Time) (string, error) {
|
gitSig := &git.Signature{}
|
||||||
authorSig := author.NewGitSig()
|
if identity != nil {
|
||||||
committerSig := committer.NewGitSig()
|
gitSig.Name, gitSig.Email = identity.GitUserName, identity.GitUserEmail
|
||||||
|
}
|
||||||
|
if other != nil {
|
||||||
|
gitSig.Name = util.IfZero(gitSig.Name, other.GitUserName)
|
||||||
|
gitSig.Email = util.IfZero(gitSig.Email, other.GitUserEmail)
|
||||||
|
}
|
||||||
|
if gitSig.Name == "" {
|
||||||
|
gitSig.Name = doer.GitName()
|
||||||
|
}
|
||||||
|
if gitSig.Email == "" {
|
||||||
|
gitSig.Email = doer.GetEmail()
|
||||||
|
}
|
||||||
|
return gitSig
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitTree creates a commit from a given tree for the user with provided message
|
||||||
|
func (t *TemporaryUploadRepository) CommitTree(opts *CommitTreeUserOptions) (string, error) {
|
||||||
|
authorSig := makeGitUserSignature(opts.DoerUser, opts.AuthorIdentity, opts.CommitterIdentity)
|
||||||
|
committerSig := makeGitUserSignature(opts.DoerUser, opts.CommitterIdentity, opts.AuthorIdentity)
|
||||||
|
|
||||||
|
authorDate := opts.AuthorTime
|
||||||
|
committerDate := opts.CommitterTime
|
||||||
|
if authorDate == nil && committerDate == nil {
|
||||||
|
authorDate = util.ToPointer(time.Now())
|
||||||
|
committerDate = authorDate
|
||||||
|
} else if authorDate == nil {
|
||||||
|
authorDate = committerDate
|
||||||
|
} else if committerDate == nil {
|
||||||
|
committerDate = authorDate
|
||||||
|
}
|
||||||
|
|
||||||
// Because this may call hooks we should pass in the environment
|
// Because this may call hooks we should pass in the environment
|
||||||
env := append(os.Environ(),
|
env := append(os.Environ(),
|
||||||
@ -244,21 +283,21 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, co
|
|||||||
)
|
)
|
||||||
|
|
||||||
messageBytes := new(bytes.Buffer)
|
messageBytes := new(bytes.Buffer)
|
||||||
_, _ = messageBytes.WriteString(message)
|
_, _ = messageBytes.WriteString(opts.CommitMessage)
|
||||||
_, _ = messageBytes.WriteString("\n")
|
_, _ = messageBytes.WriteString("\n")
|
||||||
|
|
||||||
cmdCommitTree := git.NewCommand(t.ctx, "commit-tree").AddDynamicArguments(treeHash)
|
cmdCommitTree := git.NewCommand(t.ctx, "commit-tree").AddDynamicArguments(opts.TreeHash)
|
||||||
if parent != "" {
|
if opts.ParentCommitID != "" {
|
||||||
cmdCommitTree.AddOptionValues("-p", parent)
|
cmdCommitTree.AddOptionValues("-p", opts.ParentCommitID)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sign bool
|
var sign bool
|
||||||
var keyID string
|
var keyID string
|
||||||
var signer *git.Signature
|
var signer *git.Signature
|
||||||
if parent != "" {
|
if opts.ParentCommitID != "" {
|
||||||
sign, keyID, signer, _ = asymkey_service.SignCRUDAction(t.ctx, t.repo.RepoPath(), author, t.basePath, parent)
|
sign, keyID, signer, _ = asymkey_service.SignCRUDAction(t.ctx, t.repo.RepoPath(), opts.DoerUser, t.basePath, opts.ParentCommitID)
|
||||||
} else {
|
} else {
|
||||||
sign, keyID, signer, _ = asymkey_service.SignInitialCommit(t.ctx, t.repo.RepoPath(), author)
|
sign, keyID, signer, _ = asymkey_service.SignInitialCommit(t.ctx, t.repo.RepoPath(), opts.DoerUser)
|
||||||
}
|
}
|
||||||
if sign {
|
if sign {
|
||||||
cmdCommitTree.AddOptionFormat("-S%s", keyID)
|
cmdCommitTree.AddOptionFormat("-S%s", keyID)
|
||||||
@ -279,7 +318,7 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, co
|
|||||||
cmdCommitTree.AddArguments("--no-gpg-sign")
|
cmdCommitTree.AddArguments("--no-gpg-sign")
|
||||||
}
|
}
|
||||||
|
|
||||||
if signoff {
|
if opts.SignOff {
|
||||||
// Signed-off-by
|
// Signed-off-by
|
||||||
_, _ = messageBytes.WriteString("\n")
|
_, _ = messageBytes.WriteString("\n")
|
||||||
_, _ = messageBytes.WriteString("Signed-off-by: ")
|
_, _ = messageBytes.WriteString("Signed-off-by: ")
|
||||||
|
@ -27,8 +27,8 @@ import (
|
|||||||
|
|
||||||
// IdentityOptions for a person's identity like an author or committer
|
// IdentityOptions for a person's identity like an author or committer
|
||||||
type IdentityOptions struct {
|
type IdentityOptions struct {
|
||||||
Name string
|
GitUserName string // to match "git config user.name"
|
||||||
Email string
|
GitUserEmail string // to match "git config user.email"
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE
|
// CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE
|
||||||
@ -160,8 +160,6 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
|
|||||||
|
|
||||||
message := strings.TrimSpace(opts.Message)
|
message := strings.TrimSpace(opts.Message)
|
||||||
|
|
||||||
author, committer := GetAuthorAndCommitterUsers(opts.Author, opts.Committer, doer)
|
|
||||||
|
|
||||||
t, err := NewTemporaryUploadRepository(ctx, repo)
|
t, err := NewTemporaryUploadRepository(ctx, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("NewTemporaryUploadRepository failed: %v", err)
|
log.Error("NewTemporaryUploadRepository failed: %v", err)
|
||||||
@ -262,12 +260,21 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now commit the tree
|
// Now commit the tree
|
||||||
var commitHash string
|
commitOpts := &CommitTreeUserOptions{
|
||||||
if opts.Dates != nil {
|
ParentCommitID: opts.LastCommitID,
|
||||||
commitHash, err = t.CommitTreeWithDate(opts.LastCommitID, author, committer, treeHash, message, opts.Signoff, opts.Dates.Author, opts.Dates.Committer)
|
TreeHash: treeHash,
|
||||||
} else {
|
CommitMessage: message,
|
||||||
commitHash, err = t.CommitTree(opts.LastCommitID, author, committer, treeHash, message, opts.Signoff)
|
SignOff: opts.Signoff,
|
||||||
|
DoerUser: doer,
|
||||||
|
AuthorIdentity: opts.Author,
|
||||||
|
AuthorTime: nil,
|
||||||
|
CommitterIdentity: opts.Committer,
|
||||||
|
CommitterTime: nil,
|
||||||
}
|
}
|
||||||
|
if opts.Dates != nil {
|
||||||
|
commitOpts.AuthorTime, commitOpts.CommitterTime = &opts.Dates.Author, &opts.Dates.Committer
|
||||||
|
}
|
||||||
|
commitHash, err := t.CommitTree(commitOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -128,12 +128,15 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// make author and committer the doer
|
|
||||||
author := doer
|
|
||||||
committer := doer
|
|
||||||
|
|
||||||
// Now commit the tree
|
// Now commit the tree
|
||||||
commitHash, err := t.CommitTree(opts.LastCommitID, author, committer, treeHash, opts.Message, opts.Signoff)
|
commitOpts := &CommitTreeUserOptions{
|
||||||
|
ParentCommitID: opts.LastCommitID,
|
||||||
|
TreeHash: treeHash,
|
||||||
|
CommitMessage: opts.Message,
|
||||||
|
SignOff: opts.Signoff,
|
||||||
|
DoerUser: doer,
|
||||||
|
}
|
||||||
|
commitHash, err := t.CommitTree(commitOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,16 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
{{if and .CommitCandidateEmails (gt (len .CommitCandidateEmails) 1)}}
|
||||||
|
<div class="field {{if .Err_CommitEmail}}error{{end}}">
|
||||||
|
<label>{{ctx.Locale.Tr "repo.editor.commit_email"}}</label>
|
||||||
|
<select class="ui selection dropdown" name="commit_email">
|
||||||
|
{{- range $email := .CommitCandidateEmails -}}
|
||||||
|
<option {{if eq $email $.CommitDefaultEmail}}selected{{end}} value="{{$email}}">{{$email}}</option>
|
||||||
|
{{- end -}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<button id="commit-button" type="submit" class="ui primary button">
|
<button id="commit-button" type="submit" class="ui primary button">
|
||||||
{{if eq .commit_choice "commit-to-new-branch"}}{{ctx.Locale.Tr "repo.editor.propose_file_change"}}{{else}}{{ctx.Locale.Tr "repo.editor.commit_changes"}}{{end}}
|
{{if eq .commit_choice "commit-to-new-branch"}}{{ctx.Locale.Tr "repo.editor.propose_file_change"}}{{else}}{{ctx.Locale.Tr "repo.editor.commit_changes"}}{{end}}
|
||||||
|
@ -81,12 +81,12 @@ func TestPullRequestTargetEvent(t *testing.T) {
|
|||||||
OldBranch: "main",
|
OldBranch: "main",
|
||||||
NewBranch: "main",
|
NewBranch: "main",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -109,12 +109,12 @@ func TestPullRequestTargetEvent(t *testing.T) {
|
|||||||
OldBranch: "main",
|
OldBranch: "main",
|
||||||
NewBranch: "fork-branch-1",
|
NewBranch: "fork-branch-1",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user4.Name,
|
GitUserName: user4.Name,
|
||||||
Email: user4.Email,
|
GitUserEmail: user4.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user4.Name,
|
GitUserName: user4.Name,
|
||||||
Email: user4.Email,
|
GitUserEmail: user4.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -164,12 +164,12 @@ func TestPullRequestTargetEvent(t *testing.T) {
|
|||||||
OldBranch: "main",
|
OldBranch: "main",
|
||||||
NewBranch: "fork-branch-2",
|
NewBranch: "fork-branch-2",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user4.Name,
|
GitUserName: user4.Name,
|
||||||
Email: user4.Email,
|
GitUserEmail: user4.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user4.Name,
|
GitUserName: user4.Name,
|
||||||
Email: user4.Email,
|
GitUserEmail: user4.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -237,12 +237,12 @@ func TestSkipCI(t *testing.T) {
|
|||||||
OldBranch: "master",
|
OldBranch: "master",
|
||||||
NewBranch: "master",
|
NewBranch: "master",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -268,12 +268,12 @@ func TestSkipCI(t *testing.T) {
|
|||||||
OldBranch: "master",
|
OldBranch: "master",
|
||||||
NewBranch: "master",
|
NewBranch: "master",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -299,12 +299,12 @@ func TestSkipCI(t *testing.T) {
|
|||||||
OldBranch: "master",
|
OldBranch: "master",
|
||||||
NewBranch: "test-skip-ci",
|
NewBranch: "test-skip-ci",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -356,12 +356,12 @@ func TestCreateDeleteRefEvent(t *testing.T) {
|
|||||||
OldBranch: "main",
|
OldBranch: "main",
|
||||||
NewBranch: "main",
|
NewBranch: "main",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -470,12 +470,12 @@ func TestPullRequestCommitStatusEvent(t *testing.T) {
|
|||||||
OldBranch: "main",
|
OldBranch: "main",
|
||||||
NewBranch: "main",
|
NewBranch: "main",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -576,12 +576,12 @@ func TestPullRequestCommitStatusEvent(t *testing.T) {
|
|||||||
OldBranch: testBranch,
|
OldBranch: testBranch,
|
||||||
NewBranch: testBranch,
|
NewBranch: testBranch,
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: user2.Name,
|
GitUserName: user2.Name,
|
||||||
Email: user2.Email,
|
GitUserEmail: user2.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
|
@ -11,9 +11,16 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
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/git"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
"code.gitea.io/gitea/modules/translation"
|
||||||
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateFile(t *testing.T) {
|
func TestCreateFile(t *testing.T) {
|
||||||
@ -173,3 +180,102 @@ func TestEditFileToNewBranch(t *testing.T) {
|
|||||||
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
|
testEditFileToNewBranch(t, session, "user2", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited)\n")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEditFileCommitEmail(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
assert.True(t, user.KeepEmailPrivate)
|
||||||
|
|
||||||
|
session := loginUser(t, user.Name)
|
||||||
|
link := "/user2/repo1/_edit/master/README.md"
|
||||||
|
|
||||||
|
getLastCommitID := func(t *testing.T) string {
|
||||||
|
req := NewRequest(t, "GET", link)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
lastCommit := htmlDoc.GetInputValueByName("last_commit")
|
||||||
|
require.NotEmpty(t, lastCommit)
|
||||||
|
return lastCommit
|
||||||
|
}
|
||||||
|
|
||||||
|
newReq := func(t *testing.T, session *TestSession, email, content string) *RequestWrapper {
|
||||||
|
req := NewRequestWithValues(t, "POST", link, map[string]string{
|
||||||
|
"_csrf": GetUserCSRFToken(t, session),
|
||||||
|
"last_commit": getLastCommitID(t),
|
||||||
|
"tree_path": "README.md",
|
||||||
|
"content": content,
|
||||||
|
"commit_choice": "direct",
|
||||||
|
"commit_email": email,
|
||||||
|
})
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("EmailInactive", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 35, UID: user.ID})
|
||||||
|
assert.False(t, email.IsActivated)
|
||||||
|
|
||||||
|
req := newReq(t, session, email.Email, "test content")
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
assert.Contains(t,
|
||||||
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||||
|
translation.NewLocale("en-US").Tr("repo.editor.invalid_commit_email"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("EmailInvalid", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 1, IsActivated: true})
|
||||||
|
assert.NotEqualValues(t, email.UID, user.ID)
|
||||||
|
|
||||||
|
req := newReq(t, session, email.Email, "test content")
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
|
assert.Contains(t,
|
||||||
|
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||||
|
translation.NewLocale("en-US").Tr("repo.editor.invalid_commit_email"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
|
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo1.RepoPath())
|
||||||
|
defer gitRepo.Close()
|
||||||
|
|
||||||
|
t.Run("DefaultEmailKeepPrivate", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
req := newReq(t, session, "", "privacy email")
|
||||||
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
|
commit, err := gitRepo.GetCommitByPath("README.md")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
fileContent, err := commit.GetFileContent("README.md", 64)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, "privacy email", fileContent)
|
||||||
|
assert.EqualValues(t, "User Two", commit.Author.Name)
|
||||||
|
assert.EqualValues(t, "user2@noreply.example.org", commit.Author.Email)
|
||||||
|
assert.EqualValues(t, "User Two", commit.Committer.Name)
|
||||||
|
assert.EqualValues(t, "user2@noreply.example.org", commit.Committer.Email)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ChooseEmail", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
email := unittest.AssertExistsAndLoadBean(t, &user_model.EmailAddress{ID: 3, UID: user.ID, IsActivated: true})
|
||||||
|
req := newReq(t, session, email.Email, "chosen email")
|
||||||
|
session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
|
commit, err := gitRepo.GetCommitByPath("README.md")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
fileContent, err := commit.GetFileContent("README.md", 64)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, "chosen email", fileContent)
|
||||||
|
assert.EqualValues(t, "User Two", commit.Author.Name)
|
||||||
|
assert.EqualValues(t, email.Email, commit.Author.Email)
|
||||||
|
assert.EqualValues(t, "User Two", commit.Committer.Name)
|
||||||
|
assert.EqualValues(t, email.Email, commit.Committer.Email)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -115,12 +115,12 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
|
|||||||
OldBranch: "master",
|
OldBranch: "master",
|
||||||
NewBranch: "master",
|
NewBranch: "master",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: actor.Name,
|
GitUserName: actor.Name,
|
||||||
Email: actor.Email,
|
GitUserEmail: actor.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: actor.Name,
|
GitUserName: actor.Name,
|
||||||
Email: actor.Email,
|
GitUserEmail: actor.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
@ -142,12 +142,12 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod
|
|||||||
OldBranch: "master",
|
OldBranch: "master",
|
||||||
NewBranch: "newBranch",
|
NewBranch: "newBranch",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: actor.Name,
|
GitUserName: actor.Name,
|
||||||
Email: actor.Email,
|
GitUserEmail: actor.Email,
|
||||||
},
|
},
|
||||||
Committer: &files_service.IdentityOptions{
|
Committer: &files_service.IdentityOptions{
|
||||||
Name: actor.Name,
|
GitUserName: actor.Name,
|
||||||
Email: actor.Email,
|
GitUserEmail: actor.Email,
|
||||||
},
|
},
|
||||||
Dates: &files_service.CommitDateOptions{
|
Dates: &files_service.CommitDateOptions{
|
||||||
Author: time.Now(),
|
Author: time.Now(),
|
||||||
|
@ -71,8 +71,8 @@ func getDeleteRepoFilesOptions(repo *repo_model.Repository) *files_service.Chang
|
|||||||
NewBranch: repo.DefaultBranch,
|
NewBranch: repo.DefaultBranch,
|
||||||
Message: "Deletes README.md",
|
Message: "Deletes README.md",
|
||||||
Author: &files_service.IdentityOptions{
|
Author: &files_service.IdentityOptions{
|
||||||
Name: "Bob Smith",
|
GitUserName: "Bob Smith",
|
||||||
Email: "bob@smith.com",
|
GitUserEmail: "bob@smith.com",
|
||||||
},
|
},
|
||||||
Committer: nil,
|
Committer: nil,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user