mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-14 06:39:40 +01:00
[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"`
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ type FileOptions struct {
|
||||||
// `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