* 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>tags/v1.21.12.1
| @@ -11,6 +11,7 @@ import ( | |||
| "net/url" | |||
| "path/filepath" | |||
| "testing" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| @@ -37,6 +38,10 @@ func getCreateFileOptions() api.CreateFileOptions { | |||
| Name: "John Doe", | |||
| Email: "johndoe@example.com", | |||
| }, | |||
| Dates: api.CommitDateOptions{ | |||
| Author: time.Unix(946684810, 0), | |||
| Committer: time.Unix(978307190, 0), | |||
| }, | |||
| }, | |||
| Content: contentEncoded, | |||
| } | |||
| @@ -80,12 +85,14 @@ func getExpectedFileResponseForCreate(commitID, treePath string) *api.FileRespon | |||
| Name: "Anne Doe", | |||
| Email: "annedoe@example.com", | |||
| }, | |||
| Date: "2000-01-01T00:00:10Z", | |||
| }, | |||
| Committer: &api.CommitUser{ | |||
| Identity: api.Identity{ | |||
| Name: "John Doe", | |||
| Email: "johndoe@example.com", | |||
| }, | |||
| Date: "2000-12-31T23:59:50Z", | |||
| }, | |||
| 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.Author.Email, fileResponse.Commit.Author.Email) | |||
| 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() | |||
| } | |||
| @@ -23,6 +23,7 @@ type DeleteRepoFileOptions struct { | |||
| SHA string | |||
| Author *IdentityOptions | |||
| Committer *IdentityOptions | |||
| Dates *CommitDateOptions | |||
| } | |||
| // 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 | |||
| 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 { | |||
| 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 | |||
| 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() | |||
| committerSig := committer.NewGitSig() | |||
| @@ -201,10 +205,10 @@ func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, t | |||
| env := append(os.Environ(), | |||
| "GIT_AUTHOR_NAME="+authorSig.Name, | |||
| "GIT_AUTHOR_EMAIL="+authorSig.Email, | |||
| "GIT_AUTHOR_DATE="+commitTimeStr, | |||
| "GIT_AUTHOR_DATE="+authorDate.Format(time.RFC3339), | |||
| "GIT_COMMITTER_NAME="+committerSig.Name, | |||
| "GIT_COMMITTER_EMAIL="+committerSig.Email, | |||
| "GIT_COMMITTER_DATE="+commitTimeStr, | |||
| "GIT_COMMITTER_DATE="+committerDate.Format(time.RFC3339), | |||
| ) | |||
| messageBytes := new(bytes.Buffer) | |||
| @@ -10,6 +10,7 @@ import ( | |||
| "fmt" | |||
| "path" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/cache" | |||
| @@ -31,6 +32,12 @@ type IdentityOptions struct { | |||
| 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 | |||
| type UpdateRepoFileOptions struct { | |||
| LastCommitID string | |||
| @@ -44,6 +51,7 @@ type UpdateRepoFileOptions struct { | |||
| IsNewFile bool | |||
| Author *IdentityOptions | |||
| Committer *IdentityOptions | |||
| Dates *CommitDateOptions | |||
| } | |||
| 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 | |||
| 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 { | |||
| return nil, err | |||
| } | |||
| @@ -5,6 +5,10 @@ | |||
| package structs | |||
| import ( | |||
| "time" | |||
| ) | |||
| // Identity for a person's identity like an author or committer | |||
| type Identity struct { | |||
| Name string `json:"name" binding:"MaxSize(100)"` | |||
| @@ -42,3 +46,11 @@ type Commit struct { | |||
| Committer *User `json:"committer"` | |||
| 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 | |||
| 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 Identity `json:"author"` | |||
| Committer Identity `json:"committer"` | |||
| Author Identity `json:"author"` | |||
| Committer Identity `json:"committer"` | |||
| Dates CommitDateOptions `json:"dates"` | |||
| } | |||
| // CreateFileOptions options for creating files | |||
| @@ -8,6 +8,7 @@ package repo | |||
| import ( | |||
| "encoding/base64" | |||
| "net/http" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| @@ -213,6 +214,16 @@ func CreateFile(ctx *context.APIContext, apiOpts api.CreateFileOptions) { | |||
| Name: apiOpts.Author.Name, | |||
| 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 == "" { | |||
| @@ -277,6 +288,16 @@ func UpdateFile(ctx *context.APIContext, apiOpts api.UpdateFileOptions) { | |||
| Name: apiOpts.Author.Name, | |||
| 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 == "" { | |||
| @@ -364,6 +385,16 @@ func DeleteFile(ctx *context.APIContext, apiOpts api.DeleteFileOptions) { | |||
| Name: apiOpts.Author.Name, | |||
| 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 == "" { | |||
| @@ -118,6 +118,9 @@ type swaggerParameterBodies struct { | |||
| // in:body | |||
| DeleteFileOptions api.DeleteFileOptions | |||
| // in:body | |||
| CommitDateOptions api.CommitDateOptions | |||
| // in:body | |||
| RepoTopicOptions api.RepoTopicOptions | |||
| } | |||
| @@ -8273,6 +8273,23 @@ | |||
| }, | |||
| "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": { | |||
| "type": "object", | |||
| "title": "CommitMeta contains meta information of a commit in terms of API.", | |||
| @@ -8414,6 +8431,9 @@ | |||
| "type": "string", | |||
| "x-go-name": "Content" | |||
| }, | |||
| "dates": { | |||
| "$ref": "#/definitions/CommitDateOptions" | |||
| }, | |||
| "message": { | |||
| "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", | |||
| "type": "string", | |||
| @@ -8972,6 +8992,9 @@ | |||
| "committer": { | |||
| "$ref": "#/definitions/Identity" | |||
| }, | |||
| "dates": { | |||
| "$ref": "#/definitions/CommitDateOptions" | |||
| }, | |||
| "message": { | |||
| "description": "message (optional) for the commit of this file. if not supplied, a default message will be used", | |||
| "type": "string", | |||
| @@ -11303,6 +11326,9 @@ | |||
| "type": "string", | |||
| "x-go-name": "Content" | |||
| }, | |||
| "dates": { | |||
| "$ref": "#/definitions/CommitDateOptions" | |||
| }, | |||
| "from_path": { | |||
| "description": "from_path (optional) is the path of the original file which will be moved/renamed to the path in the URL", | |||
| "type": "string", | |||