mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 20:21:47 +01:00 
			
		
		
		
	feat(api): add date range filtering to commit retrieval endpoints (#34497)
- Add support for filtering commits by date range via new "since" and "until" parameters - Update API endpoints and command logic to handle the new parameters for fetching commits within given dates - Extend API documentation and Swagger specs to describe the new "since" and "until" query parameters - Refactor related function signatures and implementations to accept and pass "since" and "until" values --------- Signed-off-by: appleboy <appleboy.tw@gmail.com> Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
		
							parent
							
								
									9cfcc079c7
								
							
						
					
					
						commit
						d06eb8d801
					
				| @ -166,6 +166,8 @@ type CommitsCountOptions struct { | ||||
| 	Not      string | ||||
| 	Revision []string | ||||
| 	RelPath  []string | ||||
| 	Since    string | ||||
| 	Until    string | ||||
| } | ||||
| 
 | ||||
| // CommitsCount returns number of total commits of until given revision. | ||||
| @ -199,8 +201,8 @@ func (c *Commit) CommitsCount() (int64, error) { | ||||
| } | ||||
| 
 | ||||
| // CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize | ||||
| func (c *Commit) CommitsByRange(page, pageSize int, not string) ([]*Commit, error) { | ||||
| 	return c.repo.commitsByRange(c.ID, page, pageSize, not) | ||||
| func (c *Commit) CommitsByRange(page, pageSize int, not, since, until string) ([]*Commit, error) { | ||||
| 	return c.repo.commitsByRangeWithTime(c.ID, page, pageSize, not, since, until) | ||||
| } | ||||
| 
 | ||||
| // CommitsBefore returns all the commits before current revision | ||||
|  | ||||
| @ -89,7 +89,8 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) { | ||||
| 	return commits[0], nil | ||||
| } | ||||
| 
 | ||||
| func (repo *Repository) commitsByRange(id ObjectID, page, pageSize int, not string) ([]*Commit, error) { | ||||
| // commitsByRangeWithTime returns the specific page commits before current revision, with not, since, until support | ||||
| func (repo *Repository) commitsByRangeWithTime(id ObjectID, page, pageSize int, not, since, until string) ([]*Commit, error) { | ||||
| 	cmd := NewCommand("log"). | ||||
| 		AddOptionFormat("--skip=%d", (page-1)*pageSize). | ||||
| 		AddOptionFormat("--max-count=%d", pageSize). | ||||
| @ -99,6 +100,12 @@ func (repo *Repository) commitsByRange(id ObjectID, page, pageSize int, not stri | ||||
| 	if not != "" { | ||||
| 		cmd.AddOptionValues("--not", not) | ||||
| 	} | ||||
| 	if since != "" { | ||||
| 		cmd.AddOptionFormat("--since=%s", since) | ||||
| 	} | ||||
| 	if until != "" { | ||||
| 		cmd.AddOptionFormat("--until=%s", until) | ||||
| 	} | ||||
| 
 | ||||
| 	stdout, _, err := cmd.RunStdBytes(repo.Ctx, &RunOpts{Dir: repo.Path}) | ||||
| 	if err != nil { | ||||
| @ -212,6 +219,8 @@ type CommitsByFileAndRangeOptions struct { | ||||
| 	File     string | ||||
| 	Not      string | ||||
| 	Page     int | ||||
| 	Since    string | ||||
| 	Until    string | ||||
| } | ||||
| 
 | ||||
| // CommitsByFileAndRange return the commits according revision file and the page | ||||
| @ -231,6 +240,12 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) | ||||
| 		if opts.Not != "" { | ||||
| 			gitCmd.AddOptionValues("--not", opts.Not) | ||||
| 		} | ||||
| 		if opts.Since != "" { | ||||
| 			gitCmd.AddOptionFormat("--since=%s", opts.Since) | ||||
| 		} | ||||
| 		if opts.Until != "" { | ||||
| 			gitCmd.AddOptionFormat("--until=%s", opts.Until) | ||||
| 		} | ||||
| 
 | ||||
| 		gitCmd.AddDashesAndList(opts.File) | ||||
| 		err := gitCmd.Run(repo.Ctx, &RunOpts{ | ||||
|  | ||||
| @ -40,7 +40,9 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string) | ||||
| 
 | ||||
| 	since := fromTime.Format(time.RFC3339) | ||||
| 
 | ||||
| 	stdout, _, runErr := NewCommand("rev-list", "--count", "--no-merges", "--branches=*", "--date=iso").AddOptionFormat("--since='%s'", since).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path}) | ||||
| 	stdout, _, runErr := NewCommand("rev-list", "--count", "--no-merges", "--branches=*", "--date=iso"). | ||||
| 		AddOptionFormat("--since=%s", since). | ||||
| 		RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path}) | ||||
| 	if runErr != nil { | ||||
| 		return nil, runErr | ||||
| 	} | ||||
| @ -60,7 +62,8 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string) | ||||
| 		_ = stdoutWriter.Close() | ||||
| 	}() | ||||
| 
 | ||||
| 	gitCmd := NewCommand("log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso").AddOptionFormat("--since='%s'", since) | ||||
| 	gitCmd := NewCommand("log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso"). | ||||
| 		AddOptionFormat("--since=%s", since) | ||||
| 	if len(branch) == 0 { | ||||
| 		gitCmd.AddArguments("--branches=*") | ||||
| 	} else { | ||||
|  | ||||
| @ -200,5 +200,3 @@ func TestListToPushCommits(t *testing.T) { | ||||
| 		assert.Equal(t, now, pushCommits.Commits[1].Timestamp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // TODO TestPushUpdate | ||||
|  | ||||
| @ -8,6 +8,7 @@ import ( | ||||
| 	"math" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| 
 | ||||
| 	issues_model "code.gitea.io/gitea/models/issues" | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
| @ -116,6 +117,16 @@ func GetAllCommits(ctx *context.APIContext) { | ||||
| 	//   in: query | ||||
| 	//   description: filepath of a file/dir | ||||
| 	//   type: string | ||||
| 	// - name: since | ||||
| 	//   in: query | ||||
| 	//   description: Only commits after this date will be returned (ISO 8601 format) | ||||
| 	//   type: string | ||||
| 	//   format: date-time | ||||
| 	// - name: until | ||||
| 	//   in: query | ||||
| 	//   description: Only commits before this date will be returned (ISO 8601 format) | ||||
| 	//   type: string | ||||
| 	//   format: date-time | ||||
| 	// - name: stat | ||||
| 	//   in: query | ||||
| 	//   description: include diff stats for every commit (disable for speedup, default 'true') | ||||
| @ -148,6 +159,23 @@ func GetAllCommits(ctx *context.APIContext) { | ||||
| 	//   "409": | ||||
| 	//     "$ref": "#/responses/EmptyRepository" | ||||
| 
 | ||||
| 	since := ctx.FormString("since") | ||||
| 	until := ctx.FormString("until") | ||||
| 
 | ||||
| 	// Validate since/until as ISO 8601 (RFC3339) | ||||
| 	if since != "" { | ||||
| 		if _, err := time.Parse(time.RFC3339, since); err != nil { | ||||
| 			ctx.APIError(http.StatusUnprocessableEntity, "invalid 'since' format, expected ISO 8601 (RFC3339)") | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 	if until != "" { | ||||
| 		if _, err := time.Parse(time.RFC3339, until); err != nil { | ||||
| 			ctx.APIError(http.StatusUnprocessableEntity, "invalid 'until' format, expected ISO 8601 (RFC3339)") | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ctx.Repo.Repository.IsEmpty { | ||||
| 		ctx.JSON(http.StatusConflict, api.APIError{ | ||||
| 			Message: "Git Repository is empty.", | ||||
| @ -198,6 +226,8 @@ func GetAllCommits(ctx *context.APIContext) { | ||||
| 			RepoPath: ctx.Repo.GitRepo.Path, | ||||
| 			Not:      not, | ||||
| 			Revision: []string{baseCommit.ID.String()}, | ||||
| 			Since:    since, | ||||
| 			Until:    until, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			ctx.APIErrorInternal(err) | ||||
| @ -205,7 +235,7 @@ func GetAllCommits(ctx *context.APIContext) { | ||||
| 		} | ||||
| 
 | ||||
| 		// Query commits | ||||
| 		commits, err = baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize, not) | ||||
| 		commits, err = baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize, not, since, until) | ||||
| 		if err != nil { | ||||
| 			ctx.APIErrorInternal(err) | ||||
| 			return | ||||
| @ -221,6 +251,8 @@ func GetAllCommits(ctx *context.APIContext) { | ||||
| 				Not:      not, | ||||
| 				Revision: []string{sha}, | ||||
| 				RelPath:  []string{path}, | ||||
| 				Since:    since, | ||||
| 				Until:    until, | ||||
| 			}) | ||||
| 
 | ||||
| 		if err != nil { | ||||
| @ -237,6 +269,8 @@ func GetAllCommits(ctx *context.APIContext) { | ||||
| 				File:     path, | ||||
| 				Not:      not, | ||||
| 				Page:     listOptions.Page, | ||||
| 				Since:    since, | ||||
| 				Until:    until, | ||||
| 			}) | ||||
| 		if err != nil { | ||||
| 			ctx.APIErrorInternal(err) | ||||
|  | ||||
| @ -15,7 +15,7 @@ import ( | ||||
| 
 | ||||
| // ShowBranchFeed shows tags and/or releases on the repo as RSS / Atom feed | ||||
| func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType string) { | ||||
| 	commits, err := ctx.Repo.Commit.CommitsByRange(0, 10, "") | ||||
| 	commits, err := ctx.Repo.Commit.CommitsByRange(0, 10, "", "", "") | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("ShowBranchFeed", err) | ||||
| 		return | ||||
|  | ||||
| @ -78,7 +78,7 @@ func Commits(ctx *context.Context) { | ||||
| 	} | ||||
| 
 | ||||
| 	// Both `git log branchName` and `git log commitId` work. | ||||
| 	commits, err := ctx.Repo.Commit.CommitsByRange(page, pageSize, "") | ||||
| 	commits, err := ctx.Repo.Commit.CommitsByRange(page, pageSize, "", "", "") | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("CommitsByRange", err) | ||||
| 		return | ||||
|  | ||||
							
								
								
									
										14
									
								
								templates/swagger/v1_json.tmpl
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								templates/swagger/v1_json.tmpl
									
									
									
										generated
									
									
									
								
							| @ -6604,6 +6604,20 @@ | ||||
|             "name": "path", | ||||
|             "in": "query" | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "format": "date-time", | ||||
|             "description": "Only commits after this date will be returned (ISO 8601 format)", | ||||
|             "name": "since", | ||||
|             "in": "query" | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "format": "date-time", | ||||
|             "description": "Only commits before this date will be returned (ISO 8601 format)", | ||||
|             "name": "until", | ||||
|             "in": "query" | ||||
|           }, | ||||
|           { | ||||
|             "type": "boolean", | ||||
|             "description": "include diff stats for every commit (disable for speedup, default 'true')", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user