enhancement: add signoff option in commit form (#14516)
Signed-off-by: a1012112796 <1012112796@qq.com>
This commit is contained in:
		
							parent
							
								
									f761c82c94
								
							
						
					
					
						commit
						f19da14c34
					
				
					 11 changed files with 51 additions and 8 deletions
				
			
		|  | @ -698,6 +698,7 @@ type EditRepoFileForm struct { | ||||||
| 	CommitChoice  string `binding:"Required;MaxSize(50)"` | 	CommitChoice  string `binding:"Required;MaxSize(50)"` | ||||||
| 	NewBranchName string `binding:"GitRefName;MaxSize(100)"` | 	NewBranchName string `binding:"GitRefName;MaxSize(100)"` | ||||||
| 	LastCommit    string | 	LastCommit    string | ||||||
|  | 	Signoff       bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Validate validates the fields
 | // Validate validates the fields
 | ||||||
|  | @ -733,6 +734,7 @@ type UploadRepoFileForm struct { | ||||||
| 	CommitChoice  string `binding:"Required;MaxSize(50)"` | 	CommitChoice  string `binding:"Required;MaxSize(50)"` | ||||||
| 	NewBranchName string `binding:"GitRefName;MaxSize(100)"` | 	NewBranchName string `binding:"GitRefName;MaxSize(100)"` | ||||||
| 	Files         []string | 	Files         []string | ||||||
|  | 	Signoff       bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Validate validates the fields
 | // Validate validates the fields
 | ||||||
|  | @ -766,6 +768,7 @@ type DeleteRepoFileForm struct { | ||||||
| 	CommitChoice  string `binding:"Required;MaxSize(50)"` | 	CommitChoice  string `binding:"Required;MaxSize(50)"` | ||||||
| 	NewBranchName string `binding:"GitRefName;MaxSize(100)"` | 	NewBranchName string `binding:"GitRefName;MaxSize(100)"` | ||||||
| 	LastCommit    string | 	LastCommit    string | ||||||
|  | 	Signoff       bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Validate validates the fields
 | // Validate validates the fields
 | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ type DeleteRepoFileOptions struct { | ||||||
| 	Author       *IdentityOptions | 	Author       *IdentityOptions | ||||||
| 	Committer    *IdentityOptions | 	Committer    *IdentityOptions | ||||||
| 	Dates        *CommitDateOptions | 	Dates        *CommitDateOptions | ||||||
|  | 	Signoff      bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DeleteRepoFile deletes a file in the given repository
 | // DeleteRepoFile deletes a file in the given repository
 | ||||||
|  | @ -199,9 +200,9 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo | ||||||
| 	// Now commit the tree
 | 	// Now commit the tree
 | ||||||
| 	var commitHash string | 	var commitHash string | ||||||
| 	if opts.Dates != nil { | 	if opts.Dates != nil { | ||||||
| 		commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Dates.Author, opts.Dates.Committer) | 		commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Signoff, opts.Dates.Author, opts.Dates.Committer) | ||||||
| 	} else { | 	} else { | ||||||
| 		commitHash, err = t.CommitTree(author, committer, treeHash, message) | 		commitHash, err = t.CommitTree(author, committer, treeHash, message, opts.Signoff) | ||||||
| 	} | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
|  |  | ||||||
|  | @ -185,12 +185,12 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, erro | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CommitTree creates a commit from a given tree for the user with provided message
 | // CommitTree creates a commit from a given tree for the user with provided message
 | ||||||
| func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, treeHash string, message string) (string, error) { | func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, treeHash string, message string, signoff bool) (string, error) { | ||||||
| 	return t.CommitTreeWithDate(author, committer, treeHash, message, time.Now(), time.Now()) | 	return t.CommitTreeWithDate(author, committer, treeHash, message, signoff, time.Now(), time.Now()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CommitTreeWithDate creates a commit from a given tree for the user with provided message
 | // CommitTreeWithDate creates a commit from a given tree for the user with provided message
 | ||||||
| func (t *TemporaryUploadRepository) CommitTreeWithDate(author, committer *models.User, treeHash string, message string, authorDate, committerDate time.Time) (string, error) { | func (t *TemporaryUploadRepository) CommitTreeWithDate(author, committer *models.User, treeHash string, message string, signoff bool, authorDate, committerDate time.Time) (string, error) { | ||||||
| 	authorSig := author.NewGitSig() | 	authorSig := author.NewGitSig() | ||||||
| 	committerSig := committer.NewGitSig() | 	committerSig := committer.NewGitSig() | ||||||
| 
 | 
 | ||||||
|  | @ -236,6 +236,13 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(author, committer *models | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if signoff { | ||||||
|  | 		// Signed-off-by
 | ||||||
|  | 		_, _ = messageBytes.WriteString("\n") | ||||||
|  | 		_, _ = messageBytes.WriteString("Signed-off-by: ") | ||||||
|  | 		_, _ = messageBytes.WriteString(committerSig.String()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	env = append(env, | 	env = append(env, | ||||||
| 		"GIT_COMMITTER_NAME="+committerSig.Name, | 		"GIT_COMMITTER_NAME="+committerSig.Name, | ||||||
| 		"GIT_COMMITTER_EMAIL="+committerSig.Email, | 		"GIT_COMMITTER_EMAIL="+committerSig.Email, | ||||||
|  |  | ||||||
|  | @ -51,6 +51,7 @@ type UpdateRepoFileOptions struct { | ||||||
| 	Author       *IdentityOptions | 	Author       *IdentityOptions | ||||||
| 	Committer    *IdentityOptions | 	Committer    *IdentityOptions | ||||||
| 	Dates        *CommitDateOptions | 	Dates        *CommitDateOptions | ||||||
|  | 	Signoff      bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string, bool) { | func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string, bool) { | ||||||
|  | @ -417,9 +418,9 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up | ||||||
| 	// Now commit the tree
 | 	// Now commit the tree
 | ||||||
| 	var commitHash string | 	var commitHash string | ||||||
| 	if opts.Dates != nil { | 	if opts.Dates != nil { | ||||||
| 		commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Dates.Author, opts.Dates.Committer) | 		commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Signoff, opts.Dates.Author, opts.Dates.Committer) | ||||||
| 	} else { | 	} else { | ||||||
| 		commitHash, err = t.CommitTree(author, committer, treeHash, message) | 		commitHash, err = t.CommitTree(author, committer, treeHash, message, opts.Signoff) | ||||||
| 	} | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
|  |  | ||||||
|  | @ -24,6 +24,7 @@ type UploadRepoFileOptions struct { | ||||||
| 	TreePath     string | 	TreePath     string | ||||||
| 	Message      string | 	Message      string | ||||||
| 	Files        []string // In UUID format.
 | 	Files        []string // In UUID format.
 | ||||||
|  | 	Signoff      bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type uploadInfo struct { | type uploadInfo struct { | ||||||
|  | @ -143,7 +144,7 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep | ||||||
| 	committer := doer | 	committer := doer | ||||||
| 
 | 
 | ||||||
| 	// Now commit the tree
 | 	// Now commit the tree
 | ||||||
| 	commitHash, err := t.CommitTree(author, committer, treeHash, opts.Message) | 	commitHash, err := t.CommitTree(author, committer, treeHash, opts.Message, opts.Signoff) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -17,6 +17,8 @@ type FileOptions struct { | ||||||
| 	Author    Identity          `json:"author"` | 	Author    Identity          `json:"author"` | ||||||
| 	Committer Identity          `json:"committer"` | 	Committer Identity          `json:"committer"` | ||||||
| 	Dates     CommitDateOptions `json:"dates"` | 	Dates     CommitDateOptions `json:"dates"` | ||||||
|  | 	// Add a Signed-off-by trailer by the committer at the end of the commit log message.
 | ||||||
|  | 	Signoff bool `json:"signoff"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CreateFileOptions options for creating files
 | // CreateFileOptions options for creating files
 | ||||||
|  |  | ||||||
|  | @ -874,6 +874,7 @@ editor.add = Add '%s' | ||||||
| editor.update = Update '%s' | editor.update = Update '%s' | ||||||
| editor.delete = Delete '%s' | editor.delete = Delete '%s' | ||||||
| editor.commit_message_desc = Add an optional extended description… | editor.commit_message_desc = Add an optional extended description… | ||||||
|  | editor.signoff_desc = Add a Signed-off-by trailer by the committer at the end of the commit log message. | ||||||
| editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch. | editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch. | ||||||
| editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request. | editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request. | ||||||
| editor.create_new_branch_np = Create a <strong>new branch</strong> for this commit. | editor.create_new_branch_np = Create a <strong>new branch</strong> for this commit. | ||||||
|  |  | ||||||
|  | @ -235,6 +235,7 @@ func CreateFile(ctx *context.APIContext) { | ||||||
| 			Author:    apiOpts.Dates.Author, | 			Author:    apiOpts.Dates.Author, | ||||||
| 			Committer: apiOpts.Dates.Committer, | 			Committer: apiOpts.Dates.Committer, | ||||||
| 		}, | 		}, | ||||||
|  | 		Signoff: apiOpts.Signoff, | ||||||
| 	} | 	} | ||||||
| 	if opts.Dates.Author.IsZero() { | 	if opts.Dates.Author.IsZero() { | ||||||
| 		opts.Dates.Author = time.Now() | 		opts.Dates.Author = time.Now() | ||||||
|  | @ -323,6 +324,7 @@ func UpdateFile(ctx *context.APIContext) { | ||||||
| 			Author:    apiOpts.Dates.Author, | 			Author:    apiOpts.Dates.Author, | ||||||
| 			Committer: apiOpts.Dates.Committer, | 			Committer: apiOpts.Dates.Committer, | ||||||
| 		}, | 		}, | ||||||
|  | 		Signoff: apiOpts.Signoff, | ||||||
| 	} | 	} | ||||||
| 	if opts.Dates.Author.IsZero() { | 	if opts.Dates.Author.IsZero() { | ||||||
| 		opts.Dates.Author = time.Now() | 		opts.Dates.Author = time.Now() | ||||||
|  | @ -449,6 +451,7 @@ func DeleteFile(ctx *context.APIContext) { | ||||||
| 			Author:    apiOpts.Dates.Author, | 			Author:    apiOpts.Dates.Author, | ||||||
| 			Committer: apiOpts.Dates.Committer, | 			Committer: apiOpts.Dates.Committer, | ||||||
| 		}, | 		}, | ||||||
|  | 		Signoff: apiOpts.Signoff, | ||||||
| 	} | 	} | ||||||
| 	if opts.Dates.Author.IsZero() { | 	if opts.Dates.Author.IsZero() { | ||||||
| 		opts.Dates.Author = time.Now() | 		opts.Dates.Author = time.Now() | ||||||
|  |  | ||||||
|  | @ -240,6 +240,7 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo | ||||||
| 		Message:      message, | 		Message:      message, | ||||||
| 		Content:      strings.ReplaceAll(form.Content, "\r", ""), | 		Content:      strings.ReplaceAll(form.Content, "\r", ""), | ||||||
| 		IsNewFile:    isNewFile, | 		IsNewFile:    isNewFile, | ||||||
|  | 		Signoff:      form.Signoff, | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| 		// This is where we handle all the errors thrown by repofiles.CreateOrUpdateRepoFile
 | 		// This is where we handle all the errors thrown by repofiles.CreateOrUpdateRepoFile
 | ||||||
| 		if git.IsErrNotExist(err) { | 		if git.IsErrNotExist(err) { | ||||||
|  | @ -442,6 +443,7 @@ func DeleteFilePost(ctx *context.Context) { | ||||||
| 		NewBranch:    branchName, | 		NewBranch:    branchName, | ||||||
| 		TreePath:     ctx.Repo.TreePath, | 		TreePath:     ctx.Repo.TreePath, | ||||||
| 		Message:      message, | 		Message:      message, | ||||||
|  | 		Signoff:      form.Signoff, | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| 		// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
 | 		// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
 | ||||||
| 		if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) { | 		if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) { | ||||||
|  | @ -650,6 +652,7 @@ func UploadFilePost(ctx *context.Context) { | ||||||
| 		TreePath:     form.TreePath, | 		TreePath:     form.TreePath, | ||||||
| 		Message:      message, | 		Message:      message, | ||||||
| 		Files:        form.Files, | 		Files:        form.Files, | ||||||
|  | 		Signoff:      form.Signoff, | ||||||
| 	}); err != nil { | 	}); err != nil { | ||||||
| 		if models.IsErrLFSFileLocked(err) { | 		if models.IsErrLFSFileLocked(err) { | ||||||
| 			ctx.Data["Err_TreePath"] = true | 			ctx.Data["Err_TreePath"] = true | ||||||
|  |  | ||||||
|  | @ -14,6 +14,12 @@ | ||||||
| 		<div class="field"> | 		<div class="field"> | ||||||
| 			<textarea name="commit_message" placeholder="{{.i18n.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea> | 			<textarea name="commit_message" placeholder="{{.i18n.Tr "repo.editor.commit_message_desc"}}" rows="5">{{.commit_message}}</textarea> | ||||||
| 		</div> | 		</div> | ||||||
|  | 		<div class="inline field"> | ||||||
|  | 			<div class="ui checkbox"> | ||||||
|  | 				<input name="signoff" type="checkbox" tabindex="0" class="hidden"> | ||||||
|  | 				<label>{{.i18n.Tr "repo.editor.signoff_desc"}}</label> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
| 		<div class="quick-pull-choice js-quick-pull-choice"> | 		<div class="quick-pull-choice js-quick-pull-choice"> | ||||||
| 			<div class="field"> | 			<div class="field"> | ||||||
| 				<div class="ui radio checkbox {{if not .CanCommitToBranch.CanCommitToBranch}}disabled{{end}}"> | 				<div class="ui radio checkbox {{if not .CanCommitToBranch.CanCommitToBranch}}disabled{{end}}"> | ||||||
|  |  | ||||||
|  | @ -12023,6 +12023,11 @@ | ||||||
|           "description": "new_branch (optional) will make a new branch from `branch` before creating the file", |           "description": "new_branch (optional) will make a new branch from `branch` before creating the file", | ||||||
|           "type": "string", |           "type": "string", | ||||||
|           "x-go-name": "NewBranchName" |           "x-go-name": "NewBranchName" | ||||||
|  |         }, | ||||||
|  |         "signoff": { | ||||||
|  |           "description": "Add a Signed-off-by trailer by the committer at the end of the commit log message.", | ||||||
|  |           "type": "boolean", | ||||||
|  |           "x-go-name": "Signoff" | ||||||
|         } |         } | ||||||
|       }, |       }, | ||||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" |       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||||
|  | @ -12731,6 +12736,11 @@ | ||||||
|           "description": "sha is the SHA for the file that already exists", |           "description": "sha is the SHA for the file that already exists", | ||||||
|           "type": "string", |           "type": "string", | ||||||
|           "x-go-name": "SHA" |           "x-go-name": "SHA" | ||||||
|  |         }, | ||||||
|  |         "signoff": { | ||||||
|  |           "description": "Add a Signed-off-by trailer by the committer at the end of the commit log message.", | ||||||
|  |           "type": "boolean", | ||||||
|  |           "x-go-name": "Signoff" | ||||||
|         } |         } | ||||||
|       }, |       }, | ||||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" |       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||||
|  | @ -15762,6 +15772,11 @@ | ||||||
|           "description": "sha is the SHA for the file that already exists", |           "description": "sha is the SHA for the file that already exists", | ||||||
|           "type": "string", |           "type": "string", | ||||||
|           "x-go-name": "SHA" |           "x-go-name": "SHA" | ||||||
|  |         }, | ||||||
|  |         "signoff": { | ||||||
|  |           "description": "Add a Signed-off-by trailer by the committer at the end of the commit log message.", | ||||||
|  |           "type": "boolean", | ||||||
|  |           "x-go-name": "Signoff" | ||||||
|         } |         } | ||||||
|       }, |       }, | ||||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" |       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue