From c287b1383f91024a8eba1a3f47912eecd66e19be Mon Sep 17 00:00:00 2001
From: KN4CK3R <admin@oldschoolhack.me>
Date: Mon, 15 Jan 2024 19:30:12 +0100
Subject: [PATCH] Fix `GetCommitStatuses` (#28787) (#28804)

Backport #28787

Replaces #28802

(cherry picked from commit ae99233db03ac123631d3f98eeaa4bf5c624b292)
---
 models/git/commit_status.go      | 67 +++++++++++++++-----------------
 models/git/commit_status_test.go | 15 ++++++-
 routers/api/v1/repo/status.go    |  4 +-
 3 files changed, 49 insertions(+), 37 deletions(-)

diff --git a/models/git/commit_status.go b/models/git/commit_status.go
index acb0110200..446a2ddd5b 100644
--- a/models/git/commit_status.go
+++ b/models/git/commit_status.go
@@ -25,7 +25,6 @@ import (
 	"code.gitea.io/gitea/modules/translation"
 
 	"xorm.io/builder"
-	"xorm.io/xorm"
 )
 
 // CommitStatus holds a single Status of a single Commit
@@ -220,60 +219,58 @@ func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
 // CommitStatusOptions holds the options for query commit statuses
 type CommitStatusOptions struct {
 	db.ListOptions
+	RepoID   int64
+	SHA      string
 	State    string
 	SortType string
 }
 
-// GetCommitStatuses returns all statuses for a given commit.
-func GetCommitStatuses(ctx context.Context, repo *repo_model.Repository, sha string, opts *CommitStatusOptions) ([]*CommitStatus, int64, error) {
-	if opts.Page <= 0 {
-		opts.Page = 1
-	}
-	if opts.PageSize <= 0 {
-		opts.Page = setting.ItemsPerPage
+func (opts *CommitStatusOptions) ToConds() builder.Cond {
+	var cond builder.Cond = builder.Eq{
+		"repo_id": opts.RepoID,
+		"sha":     opts.SHA,
 	}
 
-	countSession := listCommitStatusesStatement(ctx, repo, sha, opts)
-	countSession = db.SetSessionPagination(countSession, opts)
-	maxResults, err := countSession.Count(new(CommitStatus))
-	if err != nil {
-		log.Error("Count PRs: %v", err)
-		return nil, maxResults, err
-	}
-
-	statuses := make([]*CommitStatus, 0, opts.PageSize)
-	findSession := listCommitStatusesStatement(ctx, repo, sha, opts)
-	findSession = db.SetSessionPagination(findSession, opts)
-	sortCommitStatusesSession(findSession, opts.SortType)
-	return statuses, maxResults, findSession.Find(&statuses)
-}
-
-func listCommitStatusesStatement(ctx context.Context, repo *repo_model.Repository, sha string, opts *CommitStatusOptions) *xorm.Session {
-	sess := db.GetEngine(ctx).Where("repo_id = ?", repo.ID).And("sha = ?", sha)
 	switch opts.State {
 	case "pending", "success", "error", "failure", "warning":
-		sess.And("state = ?", opts.State)
+		cond = cond.And(builder.Eq{
+			"state": opts.State,
+		})
 	}
-	return sess
+
+	return cond
 }
 
-func sortCommitStatusesSession(sess *xorm.Session, sortType string) {
-	switch sortType {
+func (opts *CommitStatusOptions) ToOrders() string {
+	switch opts.SortType {
 	case "oldest":
-		sess.Asc("created_unix")
+		return "created_unix ASC"
 	case "recentupdate":
-		sess.Desc("updated_unix")
+		return "updated_unix DESC"
 	case "leastupdate":
-		sess.Asc("updated_unix")
+		return "updated_unix ASC"
 	case "leastindex":
-		sess.Desc("index")
+		return "`index` DESC"
 	case "highestindex":
-		sess.Asc("index")
+		return "`index` ASC"
 	default:
-		sess.Desc("created_unix")
+		return "created_unix DESC"
 	}
 }
 
+// GetCommitStatuses returns all statuses for a given commit.
+func GetCommitStatuses(ctx context.Context, opts *CommitStatusOptions) ([]*CommitStatus, int64, error) {
+	sess := db.GetEngine(ctx).
+		Where(opts.ToConds()).
+		OrderBy(opts.ToOrders())
+
+	db.SetSessionPagination(sess, opts)
+
+	statuses := make([]*CommitStatus, 0, opts.PageSize)
+	count, err := sess.FindAndCount(&statuses)
+	return statuses, count, err
+}
+
 // CommitStatusIndex represents a table for commit status index
 type CommitStatusIndex struct {
 	ID       int64
diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go
index 2197433b3e..d82c2bc5ea 100644
--- a/models/git/commit_status_test.go
+++ b/models/git/commit_status_test.go
@@ -22,7 +22,11 @@ func TestGetCommitStatuses(t *testing.T) {
 
 	sha1 := "1234123412341234123412341234123412341234"
 
-	statuses, maxResults, err := git_model.GetCommitStatuses(db.DefaultContext, repo1, sha1, &git_model.CommitStatusOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 50}})
+	statuses, maxResults, err := git_model.GetCommitStatuses(db.DefaultContext, &git_model.CommitStatusOptions{
+		ListOptions: db.ListOptions{Page: 1, PageSize: 50},
+		RepoID:      repo1.ID,
+		SHA:         sha1,
+	})
 	assert.NoError(t, err)
 	assert.Equal(t, int(maxResults), 5)
 	assert.Len(t, statuses, 5)
@@ -46,4 +50,13 @@ func TestGetCommitStatuses(t *testing.T) {
 	assert.Equal(t, "deploy/awesomeness", statuses[4].Context)
 	assert.Equal(t, structs.CommitStatusError, statuses[4].State)
 	assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL(db.DefaultContext))
+
+	statuses, maxResults, err = git_model.GetCommitStatuses(db.DefaultContext, &git_model.CommitStatusOptions{
+		ListOptions: db.ListOptions{Page: 2, PageSize: 50},
+		RepoID:      repo1.ID,
+		SHA:         sha1,
+	})
+	assert.NoError(t, err)
+	assert.Equal(t, int(maxResults), 5)
+	assert.Empty(t, statuses)
 }
diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go
index 926d91ca81..170d765cad 100644
--- a/routers/api/v1/repo/status.go
+++ b/routers/api/v1/repo/status.go
@@ -194,8 +194,10 @@ func getCommitStatuses(ctx *context.APIContext, sha string) {
 
 	listOptions := utils.GetListOptions(ctx)
 
-	statuses, maxResults, err := git_model.GetCommitStatuses(ctx, repo, sha, &git_model.CommitStatusOptions{
+	statuses, maxResults, err := git_model.GetCommitStatuses(ctx, &git_model.CommitStatusOptions{
 		ListOptions: listOptions,
+		RepoID:      repo.ID,
+		SHA:         sha,
 		SortType:    ctx.FormTrim("sort"),
 		State:       ctx.FormTrim("state"),
 	})