[API] Extend contents with dates (#9464)
* extend CommitTree func * make sure Date NOT nil * spell corection Co-Authored-By: zeripath <art27@cantab.net> * add TEST Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
		
							parent
							
								
									017f314b5a
								
							
						
					
					
						commit
						40e99ea010
					
				
					 9 changed files with 114 additions and 7 deletions
				
			
		|  | @ -11,6 +11,7 @@ import ( | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"testing" | 	"testing" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
|  | @ -37,6 +38,10 @@ func getCreateFileOptions() api.CreateFileOptions { | ||||||
| 				Name:  "John Doe", | 				Name:  "John Doe", | ||||||
| 				Email: "johndoe@example.com", | 				Email: "johndoe@example.com", | ||||||
| 			}, | 			}, | ||||||
|  | 			Dates: api.CommitDateOptions{ | ||||||
|  | 				Author:    time.Unix(946684810, 0), | ||||||
|  | 				Committer: time.Unix(978307190, 0), | ||||||
|  | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Content: contentEncoded, | 		Content: contentEncoded, | ||||||
| 	} | 	} | ||||||
|  | @ -80,12 +85,14 @@ func getExpectedFileResponseForCreate(commitID, treePath string) *api.FileRespon | ||||||
| 					Name:  "Anne Doe", | 					Name:  "Anne Doe", | ||||||
| 					Email: "annedoe@example.com", | 					Email: "annedoe@example.com", | ||||||
| 				}, | 				}, | ||||||
|  | 				Date: "2000-01-01T00:00:10Z", | ||||||
| 			}, | 			}, | ||||||
| 			Committer: &api.CommitUser{ | 			Committer: &api.CommitUser{ | ||||||
| 				Identity: api.Identity{ | 				Identity: api.Identity{ | ||||||
| 					Name:  "John Doe", | 					Name:  "John Doe", | ||||||
| 					Email: "johndoe@example.com", | 					Email: "johndoe@example.com", | ||||||
| 				}, | 				}, | ||||||
|  | 				Date: "2000-12-31T23:59:50Z", | ||||||
| 			}, | 			}, | ||||||
| 			Message: "Updates README.md\n", | 			Message: "Updates README.md\n", | ||||||
| 		}, | 		}, | ||||||
|  | @ -139,6 +146,10 @@ func TestAPICreateFile(t *testing.T) { | ||||||
| 			assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL) | 			assert.EqualValues(t, expectedFileResponse.Commit.HTMLURL, fileResponse.Commit.HTMLURL) | ||||||
| 			assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email) | 			assert.EqualValues(t, expectedFileResponse.Commit.Author.Email, fileResponse.Commit.Author.Email) | ||||||
| 			assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name) | 			assert.EqualValues(t, expectedFileResponse.Commit.Author.Name, fileResponse.Commit.Author.Name) | ||||||
|  | 			assert.EqualValues(t, expectedFileResponse.Commit.Author.Date, fileResponse.Commit.Author.Date) | ||||||
|  | 			assert.EqualValues(t, expectedFileResponse.Commit.Committer.Email, fileResponse.Commit.Committer.Email) | ||||||
|  | 			assert.EqualValues(t, expectedFileResponse.Commit.Committer.Name, fileResponse.Commit.Committer.Name) | ||||||
|  | 			assert.EqualValues(t, expectedFileResponse.Commit.Committer.Date, fileResponse.Commit.Committer.Date) | ||||||
| 			gitRepo.Close() | 			gitRepo.Close() | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ type DeleteRepoFileOptions struct { | ||||||
| 	SHA          string | 	SHA          string | ||||||
| 	Author       *IdentityOptions | 	Author       *IdentityOptions | ||||||
| 	Committer    *IdentityOptions | 	Committer    *IdentityOptions | ||||||
|  | 	Dates        *CommitDateOptions | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DeleteRepoFile deletes a file in the given repository
 | // DeleteRepoFile deletes a file in the given repository
 | ||||||
|  | @ -168,7 +169,12 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Now commit the tree
 | 	// Now commit the tree
 | ||||||
| 	commitHash, err := t.CommitTree(author, committer, treeHash, message) | 	var commitHash string | ||||||
|  | 	if opts.Dates != nil { | ||||||
|  | 		commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Dates.Author, opts.Dates.Committer) | ||||||
|  | 	} else { | ||||||
|  | 		commitHash, err = t.CommitTree(author, committer, treeHash, message) | ||||||
|  | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -188,7 +188,11 @@ 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) (string, error) { | ||||||
| 	commitTimeStr := time.Now().Format(time.RFC3339) | 	return t.CommitTreeWithDate(author, committer, treeHash, message, time.Now(), time.Now()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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) { | ||||||
| 	authorSig := author.NewGitSig() | 	authorSig := author.NewGitSig() | ||||||
| 	committerSig := committer.NewGitSig() | 	committerSig := committer.NewGitSig() | ||||||
| 
 | 
 | ||||||
|  | @ -201,10 +205,10 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t | ||||||
| 	env := append(os.Environ(), | 	env := append(os.Environ(), | ||||||
| 		"GIT_AUTHOR_NAME="+authorSig.Name, | 		"GIT_AUTHOR_NAME="+authorSig.Name, | ||||||
| 		"GIT_AUTHOR_EMAIL="+authorSig.Email, | 		"GIT_AUTHOR_EMAIL="+authorSig.Email, | ||||||
| 		"GIT_AUTHOR_DATE="+commitTimeStr, | 		"GIT_AUTHOR_DATE="+authorDate.Format(time.RFC3339), | ||||||
| 		"GIT_COMMITTER_NAME="+committerSig.Name, | 		"GIT_COMMITTER_NAME="+committerSig.Name, | ||||||
| 		"GIT_COMMITTER_EMAIL="+committerSig.Email, | 		"GIT_COMMITTER_EMAIL="+committerSig.Email, | ||||||
| 		"GIT_COMMITTER_DATE="+commitTimeStr, | 		"GIT_COMMITTER_DATE="+committerDate.Format(time.RFC3339), | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	messageBytes := new(bytes.Buffer) | 	messageBytes := new(bytes.Buffer) | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"path" | 	"path" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/cache" | 	"code.gitea.io/gitea/modules/cache" | ||||||
|  | @ -31,6 +32,12 @@ type IdentityOptions struct { | ||||||
| 	Email string | 	Email string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE
 | ||||||
|  | type CommitDateOptions struct { | ||||||
|  | 	Author    time.Time | ||||||
|  | 	Committer time.Time | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // UpdateRepoFileOptions holds the repository file update options
 | // UpdateRepoFileOptions holds the repository file update options
 | ||||||
| type UpdateRepoFileOptions struct { | type UpdateRepoFileOptions struct { | ||||||
| 	LastCommitID string | 	LastCommitID string | ||||||
|  | @ -44,6 +51,7 @@ type UpdateRepoFileOptions struct { | ||||||
| 	IsNewFile    bool | 	IsNewFile    bool | ||||||
| 	Author       *IdentityOptions | 	Author       *IdentityOptions | ||||||
| 	Committer    *IdentityOptions | 	Committer    *IdentityOptions | ||||||
|  | 	Dates        *CommitDateOptions | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string, bool) { | func detectEncodingAndBOM(entry *git.TreeEntry, repo *models.Repository) (string, bool) { | ||||||
|  | @ -371,7 +379,12 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Now commit the tree
 | 	// Now commit the tree
 | ||||||
| 	commitHash, err := t.CommitTree(author, committer, treeHash, message) | 	var commitHash string | ||||||
|  | 	if opts.Dates != nil { | ||||||
|  | 		commitHash, err = t.CommitTreeWithDate(author, committer, treeHash, message, opts.Dates.Author, opts.Dates.Committer) | ||||||
|  | 	} else { | ||||||
|  | 		commitHash, err = t.CommitTree(author, committer, treeHash, message) | ||||||
|  | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -5,6 +5,10 @@ | ||||||
| 
 | 
 | ||||||
| package structs | package structs | ||||||
| 
 | 
 | ||||||
|  | import ( | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| // Identity for a person's identity like an author or committer
 | // Identity for a person's identity like an author or committer
 | ||||||
| type Identity struct { | type Identity struct { | ||||||
| 	Name string `json:"name" binding:"MaxSize(100)"` | 	Name string `json:"name" binding:"MaxSize(100)"` | ||||||
|  | @ -42,3 +46,11 @@ type Commit struct { | ||||||
| 	Committer  *User         `json:"committer"` | 	Committer  *User         `json:"committer"` | ||||||
| 	Parents    []*CommitMeta `json:"parents"` | 	Parents    []*CommitMeta `json:"parents"` | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE
 | ||||||
|  | type CommitDateOptions struct { | ||||||
|  | 	// swagger:strfmt date-time
 | ||||||
|  | 	Author time.Time `json:"author"` | ||||||
|  | 	// swagger:strfmt date-time
 | ||||||
|  | 	Committer time.Time `json:"committer"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -14,8 +14,9 @@ type FileOptions struct { | ||||||
| 	// new_branch (optional) will make a new branch from `branch` before creating the file
 | 	// new_branch (optional) will make a new branch from `branch` before creating the file
 | ||||||
| 	NewBranchName string `json:"new_branch" binding:"GitRefName;MaxSize(100)"` | 	NewBranchName string `json:"new_branch" binding:"GitRefName;MaxSize(100)"` | ||||||
| 	// `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
 | 	// `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
 | ||||||
| 	Author    Identity `json:"author"` | 	Author    Identity          `json:"author"` | ||||||
| 	Committer Identity `json:"committer"` | 	Committer Identity          `json:"committer"` | ||||||
|  | 	Dates     CommitDateOptions `json:"dates"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CreateFileOptions options for creating files
 | // CreateFileOptions options for creating files
 | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ package repo | ||||||
| import ( | import ( | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
|  | @ -213,6 +214,16 @@ func CreateFile(ctx *context.APIContext, apiOpts api.CreateFileOptions) { | ||||||
| 			Name:  apiOpts.Author.Name, | 			Name:  apiOpts.Author.Name, | ||||||
| 			Email: apiOpts.Author.Email, | 			Email: apiOpts.Author.Email, | ||||||
| 		}, | 		}, | ||||||
|  | 		Dates: &repofiles.CommitDateOptions{ | ||||||
|  | 			Author:    apiOpts.Dates.Author, | ||||||
|  | 			Committer: apiOpts.Dates.Committer, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	if opts.Dates.Author.IsZero() { | ||||||
|  | 		opts.Dates.Author = time.Now() | ||||||
|  | 	} | ||||||
|  | 	if opts.Dates.Committer.IsZero() { | ||||||
|  | 		opts.Dates.Committer = time.Now() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if opts.Message == "" { | 	if opts.Message == "" { | ||||||
|  | @ -277,6 +288,16 @@ func UpdateFile(ctx *context.APIContext, apiOpts api.UpdateFileOptions) { | ||||||
| 			Name:  apiOpts.Author.Name, | 			Name:  apiOpts.Author.Name, | ||||||
| 			Email: apiOpts.Author.Email, | 			Email: apiOpts.Author.Email, | ||||||
| 		}, | 		}, | ||||||
|  | 		Dates: &repofiles.CommitDateOptions{ | ||||||
|  | 			Author:    apiOpts.Dates.Author, | ||||||
|  | 			Committer: apiOpts.Dates.Committer, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	if opts.Dates.Author.IsZero() { | ||||||
|  | 		opts.Dates.Author = time.Now() | ||||||
|  | 	} | ||||||
|  | 	if opts.Dates.Committer.IsZero() { | ||||||
|  | 		opts.Dates.Committer = time.Now() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if opts.Message == "" { | 	if opts.Message == "" { | ||||||
|  | @ -364,6 +385,16 @@ func DeleteFile(ctx *context.APIContext, apiOpts api.DeleteFileOptions) { | ||||||
| 			Name:  apiOpts.Author.Name, | 			Name:  apiOpts.Author.Name, | ||||||
| 			Email: apiOpts.Author.Email, | 			Email: apiOpts.Author.Email, | ||||||
| 		}, | 		}, | ||||||
|  | 		Dates: &repofiles.CommitDateOptions{ | ||||||
|  | 			Author:    apiOpts.Dates.Author, | ||||||
|  | 			Committer: apiOpts.Dates.Committer, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	if opts.Dates.Author.IsZero() { | ||||||
|  | 		opts.Dates.Author = time.Now() | ||||||
|  | 	} | ||||||
|  | 	if opts.Dates.Committer.IsZero() { | ||||||
|  | 		opts.Dates.Committer = time.Now() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if opts.Message == "" { | 	if opts.Message == "" { | ||||||
|  |  | ||||||
|  | @ -118,6 +118,9 @@ type swaggerParameterBodies struct { | ||||||
| 	// in:body
 | 	// in:body
 | ||||||
| 	DeleteFileOptions api.DeleteFileOptions | 	DeleteFileOptions api.DeleteFileOptions | ||||||
| 
 | 
 | ||||||
|  | 	// in:body
 | ||||||
|  | 	CommitDateOptions api.CommitDateOptions | ||||||
|  | 
 | ||||||
| 	// in:body
 | 	// in:body
 | ||||||
| 	RepoTopicOptions api.RepoTopicOptions | 	RepoTopicOptions api.RepoTopicOptions | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8273,6 +8273,23 @@ | ||||||
|       }, |       }, | ||||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" |       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||||
|     }, |     }, | ||||||
|  |     "CommitDateOptions": { | ||||||
|  |       "description": "CommitDateOptions store dates for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE", | ||||||
|  |       "type": "object", | ||||||
|  |       "properties": { | ||||||
|  |         "author": { | ||||||
|  |           "type": "string", | ||||||
|  |           "format": "date-time", | ||||||
|  |           "x-go-name": "Author" | ||||||
|  |         }, | ||||||
|  |         "committer": { | ||||||
|  |           "type": "string", | ||||||
|  |           "format": "date-time", | ||||||
|  |           "x-go-name": "Committer" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||||
|  |     }, | ||||||
|     "CommitMeta": { |     "CommitMeta": { | ||||||
|       "type": "object", |       "type": "object", | ||||||
|       "title": "CommitMeta contains meta information of a commit in terms of API.", |       "title": "CommitMeta contains meta information of a commit in terms of API.", | ||||||
|  | @ -8414,6 +8431,9 @@ | ||||||
|           "type": "string", |           "type": "string", | ||||||
|           "x-go-name": "Content" |           "x-go-name": "Content" | ||||||
|         }, |         }, | ||||||
|  |         "dates": { | ||||||
|  |           "$ref": "#/definitions/CommitDateOptions" | ||||||
|  |         }, | ||||||
|         "message": { |         "message": { | ||||||
|           "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", |           "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", | ||||||
|           "type": "string", |           "type": "string", | ||||||
|  | @ -8972,6 +8992,9 @@ | ||||||
|         "committer": { |         "committer": { | ||||||
|           "$ref": "#/definitions/Identity" |           "$ref": "#/definitions/Identity" | ||||||
|         }, |         }, | ||||||
|  |         "dates": { | ||||||
|  |           "$ref": "#/definitions/CommitDateOptions" | ||||||
|  |         }, | ||||||
|         "message": { |         "message": { | ||||||
|           "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", |           "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", | ||||||
|           "type": "string", |           "type": "string", | ||||||
|  | @ -11303,6 +11326,9 @@ | ||||||
|           "type": "string", |           "type": "string", | ||||||
|           "x-go-name": "Content" |           "x-go-name": "Content" | ||||||
|         }, |         }, | ||||||
|  |         "dates": { | ||||||
|  |           "$ref": "#/definitions/CommitDateOptions" | ||||||
|  |         }, | ||||||
|         "from_path": { |         "from_path": { | ||||||
|           "description": "from_path (optional) is the path of the original file which will be moved/renamed to the path in the URL", |           "description": "from_path (optional) is the path of the original file which will be moved/renamed to the path in the URL", | ||||||
|           "type": "string", |           "type": "string", | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue