From 1406b010950f538c08c5457964514b4f3be38778 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 24 May 2025 20:38:05 -0700 Subject: [PATCH 01/13] Introduce combined status --- models/git/commit_status.go | 65 ++++++----- models/git/commit_status_summary.go | 105 ++++++++++++------ models/git/commit_status_test.go | 82 ++++++-------- modules/commitstatus/combined_status.go | 35 ++++++ .../commit_status.go | 29 ++++- .../commit_status_test.go | 2 +- modules/structs/status.go | 38 ++++--- routers/web/repo/branch.go | 4 +- routers/web/repo/commit.go | 2 +- routers/web/repo/pull.go | 6 +- routers/web/repo/release.go | 3 +- routers/web/repo/repo.go | 2 +- routers/web/repo/view.go | 2 +- services/actions/commit_status.go | 12 +- services/convert/status.go | 17 +-- services/git/commit.go | 2 +- services/pull/commit_status.go | 46 ++------ services/pull/commit_status_test.go | 44 ++++---- services/pull/pull.go | 17 ++- .../repository/commitstatus/commitstatus.go | 22 ++-- services/repository/gitgraph/graph_models.go | 4 +- services/repository/repository.go | 6 +- tests/integration/actions_trigger_test.go | 7 +- tests/integration/git_general_test.go | 9 +- tests/integration/pull_merge_test.go | 7 +- tests/integration/pull_status_test.go | 27 ++--- tests/integration/repo_commits_test.go | 11 +- tests/integration/repo_webhook_test.go | 3 +- 28 files changed, 339 insertions(+), 270 deletions(-) create mode 100644 modules/commitstatus/combined_status.go rename modules/{structs => commitstatus}/commit_status.go (71%) rename modules/{structs => commitstatus}/commit_status_test.go (99%) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index b978476c4bfd2..882c18230ed35 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -17,10 +17,10 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/translation" @@ -28,19 +28,19 @@ import ( "xorm.io/xorm" ) -// CommitStatus holds a single Status of a single Commit +// CommitStatus holds a single commit status of a single Commit type CommitStatus struct { - ID int64 `xorm:"pk autoincr"` - Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` - Repo *repo_model.Repository `xorm:"-"` - State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` - SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` - TargetURL string `xorm:"TEXT"` - Description string `xorm:"TEXT"` - ContextHash string `xorm:"VARCHAR(64) index"` - Context string `xorm:"TEXT"` - Creator *user_model.User `xorm:"-"` + ID int64 `xorm:"pk autoincr"` + Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"` + Repo *repo_model.Repository `xorm:"-"` + State commitstatus.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` + SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"` + TargetURL string `xorm:"TEXT"` + Description string `xorm:"TEXT"` + ContextHash string `xorm:"VARCHAR(64) index"` + Context string `xorm:"TEXT"` + Creator *user_model.User `xorm:"-"` CreatorID int64 CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` @@ -229,23 +229,34 @@ func (status *CommitStatus) HideActionsURL(ctx context.Context) { } // CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc -func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus { - var lastStatus *CommitStatus - state := api.CommitStatusSuccess +func CalcCommitStatus(statuses []*CommitStatus) commitstatus.CombinedStatus { + states := make(commitstatus.CommitStatusStates, 0, len(statuses)) for _, status := range statuses { - if status.State.NoBetterThan(state) { - state = status.State - lastStatus = status - } + states = append(states, status.State) + } + return states.Merge() +} + +// CalcCommitStatusSummary returns commit status state via some status, the commit statues should order by id desc +func CalcCommitStatusSummary(statuses []*CommitStatus) *CommitStatusSummary { + if len(statuses) == 0 { + return nil } - if lastStatus == nil { - if len(statuses) > 0 { - lastStatus = statuses[0] - } else { - lastStatus = &CommitStatus{} + + states := make(commitstatus.CommitStatusStates, 0, len(statuses)) + targetURL := "" + for _, status := range statuses { + states = append(states, status.State) + if status.TargetURL != "" { + targetURL = status.TargetURL } } - return lastStatus + return &CommitStatusSummary{ + RepoID: statuses[0].RepoID, + SHA: statuses[0].SHA, + State: states.Merge(), + TargetURL: targetURL, + } } // CommitStatusOptions holds the options for query commit statuses @@ -490,7 +501,7 @@ func NewCommitStatus(ctx context.Context, opts NewCommitStatusOptions) error { // SignCommitWithStatuses represents a commit with validation of signature and status state. type SignCommitWithStatuses struct { - Status *CommitStatus + Status *CommitStatusSummary Statuses []*CommitStatus *asymkey_model.SignCommit } diff --git a/models/git/commit_status_summary.go b/models/git/commit_status_summary.go index 7603e7aa65415..f3f5fbdf51659 100644 --- a/models/git/commit_status_summary.go +++ b/models/git/commit_status_summary.go @@ -5,53 +5,86 @@ package git import ( "context" + "strings" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/commitstatus" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/translation" "xorm.io/builder" ) -// CommitStatusSummary holds the latest commit Status of a single Commit +// CommitStatusSummary holds the latest combined Status of a single Commit type CommitStatusSummary struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` - SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` - State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"` - TargetURL string `xorm:"TEXT"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` + Repo *repo_model.Repository `xorm:"-"` + SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` + State commitstatus.CombinedStatus `xorm:"VARCHAR(7) NOT NULL"` + TargetURL string `xorm:"TEXT"` } func init() { db.RegisterModel(new(CommitStatusSummary)) } +func (status *CommitStatusSummary) loadRepository(ctx context.Context) error { + if status.RepoID == 0 { + return nil + } + + repo, err := repo_model.GetRepositoryByID(ctx, status.RepoID) + if err != nil { + return err + } + status.Repo = repo + + return nil +} + +// LocaleString returns the locale string name of the Status +func (status *CommitStatusSummary) LocaleString(lang translation.Locale) string { + return lang.TrString("repo.commitstatus." + status.State.String()) +} + +// HideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions +func (status *CommitStatusSummary) HideActionsURL(ctx context.Context) { + if status.RepoID == 0 { + return + } + + if status.Repo == nil { + if err := status.loadRepository(ctx); err != nil { + log.Error("loadRepository: %v", err) + return + } + } + + prefix := status.Repo.Link() + "/actions" + if strings.HasPrefix(status.TargetURL, prefix) { + status.TargetURL = "" + } +} + type RepoSHA struct { RepoID int64 SHA string } -func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CommitStatus, error) { +func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CommitStatusSummary, error) { cond := builder.NewCond() for _, rs := range repoSHAs { cond = cond.Or(builder.Eq{"repo_id": rs.RepoID, "sha": rs.SHA}) } - var summaries []CommitStatusSummary + var summaries []*CommitStatusSummary if err := db.GetEngine(ctx).Where(cond).Find(&summaries); err != nil { return nil, err } - - commitStatuses := make([]*CommitStatus, 0, len(repoSHAs)) - for _, summary := range summaries { - commitStatuses = append(commitStatuses, &CommitStatus{ - RepoID: summary.RepoID, - SHA: summary.SHA, - State: summary.State, - TargetURL: summary.TargetURL, - }) - } - return commitStatuses, nil + return summaries, nil } func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) error { @@ -59,30 +92,38 @@ func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) er if err != nil { return err } - state := CalcCommitStatus(commitStatuses) + summary := CalcCommitStatusSummary(commitStatuses) + // mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database, // so we need to use insert in on duplicate if setting.Database.Type.IsMySQL() { _, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state,target_url) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE state=?", - repoID, sha, state.State, state.TargetURL, state.State) + repoID, sha, summary.State, summary.TargetURL, summary.State) return err } if cnt, err := db.GetEngine(ctx).Where("repo_id=? AND sha=?", repoID, sha). Cols("state, target_url"). - Update(&CommitStatusSummary{ - State: state.State, - TargetURL: state.TargetURL, - }); err != nil { + Update(summary); err != nil { return err } else if cnt == 0 { - _, err = db.GetEngine(ctx).Insert(&CommitStatusSummary{ - RepoID: repoID, - SHA: sha, - State: state.State, - TargetURL: state.TargetURL, - }) + _, err = db.GetEngine(ctx).Insert(summary) return err } return nil } + +func CommitStatusSummeriesHideActionsURL(ctx context.Context, statuses []*CommitStatusSummary) { + idToRepos := make(map[int64]*repo_model.Repository) + for _, status := range statuses { + if status == nil { + continue + } + + if status.Repo == nil { + status.Repo = idToRepos[status.RepoID] + } + status.HideActionsURL(ctx) + idToRepos[status.RepoID] = status.Repo + } +} diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index 37d785e938571..119711f12cd5a 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -14,9 +14,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" - "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" ) @@ -38,23 +38,23 @@ func TestGetCommitStatuses(t *testing.T) { assert.Len(t, statuses, 5) assert.Equal(t, "ci/awesomeness", statuses[0].Context) - assert.Equal(t, structs.CommitStatusPending, statuses[0].State) + assert.Equal(t, commitstatus.CommitStatusPending, statuses[0].State) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[0].APIURL(db.DefaultContext)) assert.Equal(t, "cov/awesomeness", statuses[1].Context) - assert.Equal(t, structs.CommitStatusWarning, statuses[1].State) + assert.Equal(t, commitstatus.CommitStatusWarning, statuses[1].State) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[1].APIURL(db.DefaultContext)) assert.Equal(t, "cov/awesomeness", statuses[2].Context) - assert.Equal(t, structs.CommitStatusSuccess, statuses[2].State) + assert.Equal(t, commitstatus.CommitStatusSuccess, statuses[2].State) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[2].APIURL(db.DefaultContext)) assert.Equal(t, "ci/awesomeness", statuses[3].Context) - assert.Equal(t, structs.CommitStatusFailure, statuses[3].State) + assert.Equal(t, commitstatus.CommitStatusFailure, statuses[3].State) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[3].APIURL(db.DefaultContext)) assert.Equal(t, "deploy/awesomeness", statuses[4].Context) - assert.Equal(t, structs.CommitStatusError, statuses[4].State) + assert.Equal(t, commitstatus.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 = db.FindAndCount[git_model.CommitStatus](db.DefaultContext, &git_model.CommitStatusOptions{ @@ -70,110 +70,96 @@ func TestGetCommitStatuses(t *testing.T) { func Test_CalcCommitStatus(t *testing.T) { kases := []struct { statuses []*git_model.CommitStatus - expected *git_model.CommitStatus + expected commitstatus.CombinedStatus }{ { statuses: []*git_model.CommitStatus{ { - State: structs.CommitStatusPending, + State: commitstatus.CommitStatusPending, }, }, - expected: &git_model.CommitStatus{ - State: structs.CommitStatusPending, - }, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, { - State: structs.CommitStatusPending, + State: commitstatus.CommitStatusPending, }, }, - expected: &git_model.CommitStatus{ - State: structs.CommitStatusPending, - }, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, { - State: structs.CommitStatusPending, + State: commitstatus.CommitStatusPending, }, { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, }, - expected: &git_model.CommitStatus{ - State: structs.CommitStatusPending, - }, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ { - State: structs.CommitStatusError, + State: commitstatus.CommitStatusError, }, { - State: structs.CommitStatusPending, + State: commitstatus.CommitStatusPending, }, { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, }, - expected: &git_model.CommitStatus{ - State: structs.CommitStatusError, - }, + expected: commitstatus.CombinedStatusFailure, }, { statuses: []*git_model.CommitStatus{ { - State: structs.CommitStatusWarning, + State: commitstatus.CommitStatusWarning, }, { - State: structs.CommitStatusPending, + State: commitstatus.CommitStatusPending, }, { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, }, - expected: &git_model.CommitStatus{ - State: structs.CommitStatusWarning, - }, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, { - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, }, }, - expected: &git_model.CommitStatus{ - State: structs.CommitStatusSuccess, - }, + expected: commitstatus.CombinedStatusSuccess, }, { statuses: []*git_model.CommitStatus{ { - State: structs.CommitStatusFailure, + State: commitstatus.CommitStatusFailure, }, { - State: structs.CommitStatusError, + State: commitstatus.CommitStatusError, }, { - State: structs.CommitStatusWarning, + State: commitstatus.CommitStatusWarning, }, }, - expected: &git_model.CommitStatus{ - State: structs.CommitStatusError, - }, + expected: commitstatus.CombinedStatusFailure, }, } @@ -208,7 +194,7 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) { Creator: user2, SHA: commit.ID, CommitStatus: &git_model.CommitStatus{ - State: structs.CommitStatusFailure, + State: commitstatus.CommitStatusFailure, TargetURL: "https://example.com/tests/", Context: "compliance/lint-backend", }, @@ -220,7 +206,7 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) { Creator: user2, SHA: commit.ID, CommitStatus: &git_model.CommitStatus{ - State: structs.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: "https://example.com/tests/", Context: "compliance/lint-backend", }, diff --git a/modules/commitstatus/combined_status.go b/modules/commitstatus/combined_status.go new file mode 100644 index 0000000000000..ca8b86edb94e7 --- /dev/null +++ b/modules/commitstatus/combined_status.go @@ -0,0 +1,35 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package commitstatus + +// CombinedStatus represents the combined status of a commit. +type CombinedStatus string + +const ( + // CombinedStatusPending is for when the CombinedStatus is Pending + CombinedStatusPending CombinedStatus = "pending" + // CombinedStatusSuccess is for when the CombinedStatus is Success + CombinedStatusSuccess CombinedStatus = "success" + // CombinedStatusFailure is for when the CombinedStatus is Failure + CombinedStatusFailure CombinedStatus = "failure" +) + +func (cs CombinedStatus) String() string { + return string(cs) +} + +// IsPending represents if commit status state is pending +func (cs CombinedStatus) IsPending() bool { + return cs == CombinedStatusPending +} + +// IsSuccess represents if commit status state is success +func (cs CombinedStatus) IsSuccess() bool { + return cs == CombinedStatusSuccess +} + +// IsFailure represents if commit status state is failure +func (cs CombinedStatus) IsFailure() bool { + return cs == CombinedStatusFailure +} diff --git a/modules/structs/commit_status.go b/modules/commitstatus/commit_status.go similarity index 71% rename from modules/structs/commit_status.go rename to modules/commitstatus/commit_status.go index dc880ef5eb98d..13cbf85677f7f 100644 --- a/modules/structs/commit_status.go +++ b/modules/commitstatus/commit_status.go @@ -1,11 +1,11 @@ // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package structs +package commitstatus // CommitStatusState holds the state of a CommitStatus // It can be "pending", "success", "error" and "failure" -type CommitStatusState string +type CommitStatusState string //nolint const ( // CommitStatusPending is for when the CommitStatus is Pending @@ -71,3 +71,28 @@ func (css CommitStatusState) IsFailure() bool { func (css CommitStatusState) IsWarning() bool { return css == CommitStatusWarning } + +type CommitStatusStates []CommitStatusState //nolint + +// According to https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference +// > Additionally, a combined state is returned. The state is one of: +// > failure if any of the contexts report as error or failure +// > pending if there are no statuses or a context is pending +// > success if the latest status for all contexts is success + +func (css CommitStatusStates) Merge() CombinedStatus { + successCnt := 0 + for _, state := range css { + switch { + case state.IsError() || state.IsFailure(): + return CombinedStatusFailure + case state.IsPending(): + case state.IsSuccess() || state.IsWarning(): + successCnt++ + } + } + if successCnt > 0 && successCnt == len(css) { + return CombinedStatusSuccess + } + return CombinedStatusPending +} diff --git a/modules/structs/commit_status_test.go b/modules/commitstatus/commit_status_test.go similarity index 99% rename from modules/structs/commit_status_test.go rename to modules/commitstatus/commit_status_test.go index 88e09aadc1596..ced17e11d916e 100644 --- a/modules/structs/commit_status_test.go +++ b/modules/commitstatus/commit_status_test.go @@ -1,7 +1,7 @@ // Copyright 2023 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package structs +package commitstatus import ( "testing" diff --git a/modules/structs/status.go b/modules/structs/status.go index c1d8b902ec3a7..d22ab6862cfca 100644 --- a/modules/structs/status.go +++ b/modules/structs/status.go @@ -5,17 +5,19 @@ package structs import ( "time" + + "code.gitea.io/gitea/modules/commitstatus" ) // CommitStatus holds a single status of a single Commit type CommitStatus struct { - ID int64 `json:"id"` - State CommitStatusState `json:"status"` - TargetURL string `json:"target_url"` - Description string `json:"description"` - URL string `json:"url"` - Context string `json:"context"` - Creator *User `json:"creator"` + ID int64 `json:"id"` + State commitstatus.CommitStatusState `json:"status"` + TargetURL string `json:"target_url"` + Description string `json:"description"` + URL string `json:"url"` + Context string `json:"context"` + Creator *User `json:"creator"` // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time @@ -24,19 +26,19 @@ type CommitStatus struct { // CombinedStatus holds the combined state of several statuses for a single commit type CombinedStatus struct { - State CommitStatusState `json:"state"` - SHA string `json:"sha"` - TotalCount int `json:"total_count"` - Statuses []*CommitStatus `json:"statuses"` - Repository *Repository `json:"repository"` - CommitURL string `json:"commit_url"` - URL string `json:"url"` + State commitstatus.CombinedStatus `json:"state"` + SHA string `json:"sha"` + TotalCount int `json:"total_count"` + Statuses []*CommitStatus `json:"statuses"` + Repository *Repository `json:"repository"` + CommitURL string `json:"commit_url"` + URL string `json:"url"` } // CreateStatusOption holds the information needed to create a new CommitStatus for a Commit type CreateStatusOption struct { - State CommitStatusState `json:"state"` - TargetURL string `json:"target_url"` - Description string `json:"description"` - Context string `json:"context"` + State commitstatus.CommitStatusState `json:"state"` + TargetURL string `json:"target_url"` + Description string `json:"description"` + Context string `json:"context"` } diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 5d382ebd710d2..3ef1bfbf27d73 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -75,9 +75,9 @@ func Branches(ctx *context.Context) { } } - commitStatus := make(map[string]*git_model.CommitStatus) + commitStatus := make(map[string]*git_model.CommitStatusSummary, len(commitStatuses)) for commitID, cs := range commitStatuses { - commitStatus[commitID] = git_model.CalcCommitStatus(cs) + commitStatus[commitID] = git_model.CalcCommitStatusSummary(cs) } ctx.Data["Keyword"] = kw diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 01a6cbc31947f..f9df09f4f132a 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -385,7 +385,7 @@ func Diff(ctx *context.Context) { git_model.CommitStatusesHideActionsURL(ctx, statuses) } - ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses) + ctx.Data["CommitStatus"] = git_model.CalcCommitStatusSummary(statuses) ctx.Data["CommitStatuses"] = statuses verification := asymkey_service.ParseCommitWithSignature(ctx, commit) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 43ddc265cfafb..fd0ac1df3b7a5 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -302,7 +302,7 @@ func prepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) if len(commitStatuses) != 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(commitStatuses) } } @@ -369,7 +369,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(commitStatuses) } compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), @@ -465,7 +465,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(commitStatuses) } if pb != nil && pb.EnableStatusCheck { diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 553bdbf6e5c5b..e78cda7b86c8f 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -16,6 +16,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/markup/markdown" @@ -71,7 +72,7 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model type ReleaseInfo struct { Release *repo_model.Release - CommitStatus *git_model.CommitStatus + CommitStatus commitstatus.CombinedStatus CommitStatuses []*git_model.CommitStatus } diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index ee112b83f261b..9a1f4fd8cbce1 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -560,7 +560,7 @@ func SearchRepo(ctx *context.Context) { return } if !ctx.Repo.CanRead(unit.TypeActions) { - git_model.CommitStatusesHideActionsURL(ctx, latestCommitStatuses) + git_model.CommitStatusSummeriesHideActionsURL(ctx, latestCommitStatuses) } results := make([]*repo_service.WebSearchRepository, len(repos)) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 2f014346848d1..b328e54ca0ab3 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -139,7 +139,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool { git_model.CommitStatusesHideActionsURL(ctx, statuses) } - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(statuses) ctx.Data["LatestCommitStatuses"] = statuses } diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go index eb15d16061ea2..741b3501821fa 100644 --- a/services/actions/commit_status.go +++ b/services/actions/commit_status.go @@ -14,9 +14,9 @@ import ( git_model "code.gitea.io/gitea/models/git" user_model "code.gitea.io/gitea/models/user" actions_module "code.gitea.io/gitea/modules/actions" + "code.gitea.io/gitea/modules/commitstatus" git "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" - api "code.gitea.io/gitea/modules/structs" webhook_module "code.gitea.io/gitea/modules/webhook" commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus" @@ -147,16 +147,16 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er return commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID.String(), &status) } -func toCommitStatus(status actions_model.Status) api.CommitStatusState { +func toCommitStatus(status actions_model.Status) commitstatus.CommitStatusState { switch status { case actions_model.StatusSuccess, actions_model.StatusSkipped: - return api.CommitStatusSuccess + return commitstatus.CommitStatusSuccess case actions_model.StatusFailure, actions_model.StatusCancelled: - return api.CommitStatusFailure + return commitstatus.CommitStatusFailure case actions_model.StatusWaiting, actions_model.StatusBlocked, actions_model.StatusRunning: - return api.CommitStatusPending + return commitstatus.CommitStatusPending default: - return api.CommitStatusError + return commitstatus.CommitStatusError } } diff --git a/services/convert/status.go b/services/convert/status.go index 6cef63c1cdadf..243eaf6158d52 100644 --- a/services/convert/status.go +++ b/services/convert/status.go @@ -8,6 +8,7 @@ import ( git_model "code.gitea.io/gitea/models/git" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/commitstatus" api "code.gitea.io/gitea/modules/structs" ) @@ -45,21 +46,11 @@ func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, r URL: "", } - retStatus.Statuses = make([]*api.CommitStatus, 0, len(statuses)) + states := make(commitstatus.CommitStatusStates, 0, len(statuses)) for _, status := range statuses { retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status)) - if retStatus.State == "" || status.State.NoBetterThan(retStatus.State) { - retStatus.State = status.State - } + states = append(states, status.State) } - // According to https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference - // > Additionally, a combined state is returned. The state is one of: - // > failure if any of the contexts report as error or failure - // > pending if there are no statuses or a context is pending - // > success if the latest status for all contexts is success - if retStatus.State.IsError() { - retStatus.State = api.CommitStatusFailure - } - + retStatus.State = states.Merge() return retStatus } diff --git a/services/git/commit.go b/services/git/commit.go index 3faef7678290f..a50256a42950a 100644 --- a/services/git/commit.go +++ b/services/git/commit.go @@ -90,7 +90,7 @@ func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.Sig } commit.Statuses = statuses - commit.Status = git_model.CalcCommitStatus(statuses) + commit.Status = git_model.CalcCommitStatusSummary(statuses) newCommits = append(newCommits, commit) } return newCommits, nil diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 0bfff21746fd7..62e79897924d6 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -10,20 +10,16 @@ import ( "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/structs" "github.com/gobwas/glob" "github.com/pkg/errors" ) // MergeRequiredContextsCommitStatus returns a commit status state for given required contexts -func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) structs.CommitStatusState { - // matchedCount is the number of `CommitStatus.Context` that match any context of `requiredContexts` - matchedCount := 0 - returnedStatus := structs.CommitStatusSuccess - +func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) commitstatus.CombinedStatus { if len(requiredContexts) > 0 { requiredContextsGlob := make(map[string]glob.Glob, len(requiredContexts)) for _, ctx := range requiredContexts { @@ -34,57 +30,35 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, } } + requiredCommitStatuses := make([]*git_model.CommitStatus, 0, len(commitStatuses)) for _, gp := range requiredContextsGlob { - var targetStatus structs.CommitStatusState for _, commitStatus := range commitStatuses { if gp.Match(commitStatus.Context) { - targetStatus = commitStatus.State - matchedCount++ + requiredCommitStatuses = append(requiredCommitStatuses, commitStatus) break } } - - // If required rule not match any action, then it is pending - if targetStatus == "" { - if structs.CommitStatusPending.NoBetterThan(returnedStatus) { - returnedStatus = structs.CommitStatusPending - } - break - } - - if targetStatus.NoBetterThan(returnedStatus) { - returnedStatus = targetStatus - } } - } - - if matchedCount == 0 && returnedStatus == structs.CommitStatusSuccess { - status := git_model.CalcCommitStatus(commitStatuses) - if status != nil { - return status.State + if len(requiredCommitStatuses) > 0 { + return git_model.CalcCommitStatus(requiredCommitStatuses) } - return structs.CommitStatusSuccess } - return returnedStatus + return git_model.CalcCommitStatus(commitStatuses) } // IsCommitStatusContextSuccess returns true if all required status check contexts succeed. func IsCommitStatusContextSuccess(commitStatuses []*git_model.CommitStatus, requiredContexts []string) bool { // If no specific context is required, require that last commit status is a success if len(requiredContexts) == 0 { - status := git_model.CalcCommitStatus(commitStatuses) - if status == nil || status.State != structs.CommitStatusSuccess { - return false - } - return true + return git_model.CalcCommitStatus(commitStatuses) == commitstatus.CombinedStatusSuccess } for _, ctx := range requiredContexts { var found bool for _, commitStatus := range commitStatuses { if commitStatus.Context == ctx { - if commitStatus.State != structs.CommitStatusSuccess { + if commitStatus.State != commitstatus.CommitStatusSuccess { return false } @@ -117,7 +91,7 @@ func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) ( } // GetPullRequestCommitStatusState returns pull request merged commit status state -func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullRequest) (structs.CommitStatusState, error) { +func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullRequest) (commitstatus.CombinedStatus, error) { // Ensure HeadRepo is loaded if err := pr.LoadHeadRepo(ctx); err != nil { return "", errors.Wrap(err, "LoadHeadRepo") diff --git a/services/pull/commit_status_test.go b/services/pull/commit_status_test.go index 592acdd55cd43..501d01d32bd2a 100644 --- a/services/pull/commit_status_test.go +++ b/services/pull/commit_status_test.go @@ -8,7 +8,7 @@ import ( "testing" git_model "code.gitea.io/gitea/models/git" - "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/commitstatus" "github.com/stretchr/testify/assert" ) @@ -16,29 +16,29 @@ import ( func TestMergeRequiredContextsCommitStatus(t *testing.T) { testCases := [][]*git_model.CommitStatus{ { - {Context: "Build 1", State: structs.CommitStatusSuccess}, - {Context: "Build 2", State: structs.CommitStatusSuccess}, - {Context: "Build 3", State: structs.CommitStatusSuccess}, + {Context: "Build 1", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 3", State: commitstatus.CommitStatusSuccess}, }, { - {Context: "Build 1", State: structs.CommitStatusSuccess}, - {Context: "Build 2", State: structs.CommitStatusSuccess}, - {Context: "Build 2t", State: structs.CommitStatusPending}, + {Context: "Build 1", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2t", State: commitstatus.CommitStatusPending}, }, { - {Context: "Build 1", State: structs.CommitStatusSuccess}, - {Context: "Build 2", State: structs.CommitStatusSuccess}, - {Context: "Build 2t", State: structs.CommitStatusFailure}, + {Context: "Build 1", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2t", State: commitstatus.CommitStatusFailure}, }, { - {Context: "Build 1", State: structs.CommitStatusSuccess}, - {Context: "Build 2", State: structs.CommitStatusSuccess}, - {Context: "Build 2t", State: structs.CommitStatusSuccess}, + {Context: "Build 1", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2t", State: commitstatus.CommitStatusSuccess}, }, { - {Context: "Build 1", State: structs.CommitStatusSuccess}, - {Context: "Build 2", State: structs.CommitStatusSuccess}, - {Context: "Build 2t", State: structs.CommitStatusSuccess}, + {Context: "Build 1", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2", State: commitstatus.CommitStatusSuccess}, + {Context: "Build 2t", State: commitstatus.CommitStatusSuccess}, }, } testCasesRequiredContexts := [][]string{ @@ -49,12 +49,12 @@ func TestMergeRequiredContextsCommitStatus(t *testing.T) { {"Build*", "Build *", "Build 2t*", "Build 1*"}, } - testCasesExpected := []structs.CommitStatusState{ - structs.CommitStatusSuccess, - structs.CommitStatusPending, - structs.CommitStatusFailure, - structs.CommitStatusPending, - structs.CommitStatusSuccess, + testCasesExpected := []commitstatus.CombinedStatus{ + commitstatus.CombinedStatusSuccess, + commitstatus.CombinedStatusPending, + commitstatus.CombinedStatusFailure, + commitstatus.CombinedStatusPending, + commitstatus.CombinedStatusSuccess, } for i, commitStatuses := range testCases { diff --git a/services/pull/pull.go b/services/pull/pull.go index 81be797832aa4..54375c20a92d3 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -946,13 +946,13 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ } // GetIssuesLastCommitStatus returns a map of issue ID to the most recent commit's latest status -func GetIssuesLastCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64]*git_model.CommitStatus, error) { +func GetIssuesLastCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64]*git_model.CommitStatusSummary, error) { _, lastStatus, err := GetIssuesAllCommitStatus(ctx, issues) return lastStatus, err } // GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status -func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64][]*git_model.CommitStatus, map[int64]*git_model.CommitStatus, error) { +func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64][]*git_model.CommitStatus, map[int64]*git_model.CommitStatusSummary, error) { if err := issues.LoadPullRequests(ctx); err != nil { return nil, nil, err } @@ -963,7 +963,7 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList var ( gitRepos = make(map[int64]*git.Repository) res = make(map[int64][]*git_model.CommitStatus) - lastRes = make(map[int64]*git_model.CommitStatus) + lastRes = make(map[int64]*git_model.CommitStatusSummary) err error ) defer func() { @@ -986,27 +986,26 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList gitRepos[issue.RepoID] = gitRepo } - statuses, lastStatus, err := getAllCommitStatus(ctx, gitRepo, issue.PullRequest) + statuses, err := getAllCommitStatus(ctx, gitRepo, issue.PullRequest) if err != nil { log.Error("getAllCommitStatus: cant get commit statuses of pull [%d]: %v", issue.PullRequest.ID, err) continue } res[issue.PullRequest.ID] = statuses - lastRes[issue.PullRequest.ID] = lastStatus + lastRes[issue.PullRequest.ID] = git_model.CalcCommitStatusSummary(statuses) } return res, lastRes, nil } // getAllCommitStatus get pr's commit statuses. -func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues_model.PullRequest) (statuses []*git_model.CommitStatus, lastStatus *git_model.CommitStatus, err error) { +func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues_model.PullRequest) (statuses []*git_model.CommitStatus, err error) { sha, shaErr := gitRepo.GetRefCommitID(pr.GetGitRefName()) if shaErr != nil { - return nil, nil, shaErr + return nil, shaErr } statuses, _, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) - lastStatus = git_model.CalcCommitStatus(statuses) - return statuses, lastStatus, err + return statuses, err } // IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index f369a303e6ce4..c795d7993f990 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -14,12 +14,12 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" - api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/services/notify" ) @@ -47,10 +47,10 @@ func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheVal return nil } -func updateCommitStatusCache(repoID int64, branchName string, state api.CommitStatusState, targetURL string) error { +func updateCommitStatusCache(repoID int64, branchName string, state commitstatus.CombinedStatus, targetURL string) error { c := cache.GetCache() bs, err := json.Marshal(commitStatusCacheValue{ - State: state.String(), + State: string(state), TargetURL: targetURL, }) if err != nil { @@ -121,13 +121,13 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } // FindReposLastestCommitStatuses loading repository default branch latest combinded commit status with cache -func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatus, error) { - results := make([]*git_model.CommitStatus, len(repos)) +func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatusSummary, error) { + results := make([]*git_model.CommitStatusSummary, len(repos)) allCached := true for i, repo := range repos { if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil { - results[i] = &git_model.CommitStatus{ - State: api.CommitStatusState(cv.State), + results[i] = &git_model.CommitStatusSummary{ + State: commitstatus.CombinedStatus(cv.State), TargetURL: cv.TargetURL, } } else { @@ -170,10 +170,8 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep repoSHAs = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { return repoSHA.RepoID == repo.ID }) - if results[i] != nil { - if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { - log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) - } + if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { + log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } break } @@ -191,7 +189,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep for i, repo := range repos { if results[i] == nil { - results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID]) + results[i] = git_model.CalcCommitStatusSummary(repoToItsLatestCommitStatuses[repo.ID]) if results[i] != nil { if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) diff --git a/services/repository/gitgraph/graph_models.go b/services/repository/gitgraph/graph_models.go index c45662836bcc3..07463e3f03328 100644 --- a/services/repository/gitgraph/graph_models.go +++ b/services/repository/gitgraph/graph_models.go @@ -125,7 +125,7 @@ func (graph *Graph) LoadAndProcessCommits(ctx context.Context, repository *repo_ if err != nil { log.Error("GetLatestCommitStatus: %v", err) } else { - c.Status = git_model.CalcCommitStatus(statuses) + c.Status = git_model.CalcCommitStatusSummary(statuses) } } return nil @@ -249,7 +249,7 @@ type Commit struct { Commit *git.Commit User *user_model.User Verification *asymkey_model.CommitVerification - Status *git_model.CommitStatus + Status *git_model.CommitStatusSummary Flow int64 Row int Column int diff --git a/services/repository/repository.go b/services/repository/repository.go index 739ef1ec384b9..bdff4331cfbae 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -34,9 +34,9 @@ import ( // WebSearchRepository represents a repository returned by web search type WebSearchRepository struct { - Repository *structs.Repository `json:"repository"` - LatestCommitStatus *git.CommitStatus `json:"latest_commit_status"` - LocaleLatestCommitStatus string `json:"locale_latest_commit_status"` + Repository *structs.Repository `json:"repository"` + LatestCommitStatus *git.CommitStatusSummary `json:"latest_commit_status"` + LocaleLatestCommitStatus string `json:"locale_latest_commit_status"` } // WebSearchResults results of a successful web search diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index e755481d09e68..d40da16d8d36c 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -22,6 +22,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" actions_module "code.gitea.io/gitea/modules/actions" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/json" @@ -638,7 +639,7 @@ jobs: if len(latestCommitStatuses) == 0 { return false } - if latestCommitStatuses[0].State == api.CommitStatusPending { + if latestCommitStatuses[0].State == commitstatus.CommitStatusPending { insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context) return true } @@ -679,14 +680,14 @@ func checkCommitStatusAndInsertFakeStatus(t *testing.T, repo *repo_model.Reposit latestCommitStatuses, _, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll) assert.NoError(t, err) assert.Len(t, latestCommitStatuses, 1) - assert.Equal(t, api.CommitStatusPending, latestCommitStatuses[0].State) + assert.Equal(t, commitstatus.CommitStatusPending, latestCommitStatuses[0].State) insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context) } func insertFakeStatus(t *testing.T, repo *repo_model.Repository, sha, targetURL, context string) { err := commitstatus_service.CreateCommitStatus(db.DefaultContext, repo, user_model.NewActionsUser(), sha, &git_model.CommitStatus{ - State: api.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: targetURL, Context: context, }) diff --git a/tests/integration/git_general_test.go b/tests/integration/git_general_test.go index ed60bdb58a432..3b0f9589d2c63 100644 --- a/tests/integration/git_general_test.go +++ b/tests/integration/git_general_test.go @@ -26,6 +26,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/setting" @@ -713,7 +714,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { commitID := path.Base(commitURL) - addCommitStatus := func(status api.CommitStatusState) func(*testing.T) { + addCommitStatus := func(status commitstatus.CommitStatusState) func(*testing.T) { return doAPICreateCommitStatus(ctx, commitID, api.CreateStatusOption{ State: status, TargetURL: "http://test.ci/", @@ -723,7 +724,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { } // Call API to add Pending status for commit - t.Run("CreateStatus", addCommitStatus(api.CommitStatusPending)) + t.Run("CreateStatus", addCommitStatus(commitstatus.CommitStatusPending)) // Cancel not existing auto merge ctx.ExpectedCode = http.StatusNotFound @@ -752,7 +753,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { assert.False(t, pr.HasMerged) // Call API to add Failure status for commit - t.Run("CreateStatus", addCommitStatus(api.CommitStatusFailure)) + t.Run("CreateStatus", addCommitStatus(commitstatus.CommitStatusFailure)) // Check pr status pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t) @@ -760,7 +761,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) { assert.False(t, pr.HasMerged) // Call API to add Success status for commit - t.Run("CreateStatus", addCommitStatus(api.CommitStatusSuccess)) + t.Run("CreateStatus", addCommitStatus(commitstatus.CommitStatusSuccess)) // wait to let gitea merge stuff time.Sleep(time.Second) diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index cf50d5e639e2d..5fad26f70e745 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/queue" @@ -768,7 +769,7 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) { }() err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{ - State: api.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: "https://gitea.com", Context: "gitea/actions", }) @@ -848,7 +849,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) { }() err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{ - State: api.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: "https://gitea.com", Context: "gitea/actions", }) @@ -977,7 +978,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing. }() err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{ - State: api.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: "https://gitea.com", Context: "gitea/actions", }) diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 4d43847f1bee7..00ffcfb632c0c 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" @@ -55,20 +56,20 @@ func TestPullCreate_CommitStatus(t *testing.T) { commitID := path.Base(commitURL) - statusList := []api.CommitStatusState{ - api.CommitStatusPending, - api.CommitStatusError, - api.CommitStatusFailure, - api.CommitStatusSuccess, - api.CommitStatusWarning, + statusList := []commitstatus.CommitStatusState{ + commitstatus.CommitStatusPending, + commitstatus.CommitStatusError, + commitstatus.CommitStatusFailure, + commitstatus.CommitStatusSuccess, + commitstatus.CommitStatusWarning, } - statesIcons := map[api.CommitStatusState]string{ - api.CommitStatusPending: "octicon-dot-fill", - api.CommitStatusSuccess: "octicon-check", - api.CommitStatusError: "gitea-exclamation", - api.CommitStatusFailure: "octicon-x", - api.CommitStatusWarning: "gitea-exclamation", + statesIcons := map[commitstatus.CommitStatusState]string{ + commitstatus.CommitStatusPending: "octicon-dot-fill", + commitstatus.CommitStatusSuccess: "octicon-check", + commitstatus.CommitStatusError: "gitea-exclamation", + commitstatus.CommitStatusFailure: "octicon-x", + commitstatus.CommitStatusWarning: "gitea-exclamation", } testCtx := NewAPITestContext(t, "user1", "repo1", auth_model.AccessTokenScopeWriteRepository) @@ -99,7 +100,7 @@ func TestPullCreate_CommitStatus(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"}) css := unittest.AssertExistsAndLoadBean(t, &git_model.CommitStatusSummary{RepoID: repo1.ID, SHA: commitID}) - assert.Equal(t, api.CommitStatusWarning, css.State) + assert.Equal(t, commitstatus.CommitStatusWarning, css.State) }) } diff --git a/tests/integration/repo_commits_test.go b/tests/integration/repo_commits_test.go index 504d2adaccd8f..bef957597ae62 100644 --- a/tests/integration/repo_commits_test.go +++ b/tests/integration/repo_commits_test.go @@ -12,6 +12,7 @@ import ( "testing" auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -76,7 +77,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) { // Call API to add status for commit ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository) t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{ - State: api.CommitStatusState(state), + State: commitstatus.CommitStatusState(state), TargetURL: "http://test.ci/", Description: "", Context: "testci", @@ -120,7 +121,7 @@ func testRepoCommitsWithStatus(t *testing.T, resp, respOne *httptest.ResponseRec assert.NotNil(t, status) if assert.Len(t, statuses, 1) { - assert.Equal(t, api.CommitStatusState(state), statuses[0].State) + assert.Equal(t, commitstatus.CommitStatusState(state), statuses[0].State) assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/statuses/65f1bf27bc3bf70f64657658635e66094edbcb4d", statuses[0].URL) assert.Equal(t, "http://test.ci/", statuses[0].TargetURL) assert.Empty(t, statuses[0].Description) @@ -174,7 +175,7 @@ func TestRepoCommitsStatusParallel(t *testing.T) { parentT.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) { ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository) runBody := doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{ - State: api.CommitStatusPending, + State: commitstatus.CommitStatusPending, TargetURL: "http://test.ci/", Description: "", Context: "testci", @@ -205,14 +206,14 @@ func TestRepoCommitsStatusMultiple(t *testing.T) { // Call API to add status for commit ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository) t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{ - State: api.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: "http://test.ci/", Description: "", Context: "testci", })) t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{ - State: api.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: "http://test.ci/", Description: "", Context: "other_context", diff --git a/tests/integration/repo_webhook_test.go b/tests/integration/repo_webhook_test.go index 13e3d198eadf0..c77f5c811709b 100644 --- a/tests/integration/repo_webhook_test.go +++ b/tests/integration/repo_webhook_test.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" + "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" @@ -732,7 +733,7 @@ func Test_WebhookStatus(t *testing.T) { // update a status for a commit via API doAPICreateCommitStatus(testCtx, commitID, api.CreateStatusOption{ - State: api.CommitStatusSuccess, + State: commitstatus.CommitStatusSuccess, TargetURL: "http://test.ci/", Description: "", Context: "testci", From 811e900d30d1acfbffa3d8504854490ae0ea0ec2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 24 May 2025 21:00:14 -0700 Subject: [PATCH 02/13] improvements --- models/git/commit_status.go | 4 +- modules/commitstatus/commit_status.go | 23 --- modules/commitstatus/commit_status_test.go | 174 --------------------- services/convert/status.go | 17 +- 4 files changed, 7 insertions(+), 211 deletions(-) delete mode 100644 modules/commitstatus/commit_status_test.go diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 882c18230ed35..9ff8d30195d07 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -228,7 +228,7 @@ func (status *CommitStatus) HideActionsURL(ctx context.Context) { } } -// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc +// CalcCommitStatus returns a combined status, the commit statuses should order by id desc func CalcCommitStatus(statuses []*CommitStatus) commitstatus.CombinedStatus { states := make(commitstatus.CommitStatusStates, 0, len(statuses)) for _, status := range statuses { @@ -237,7 +237,7 @@ func CalcCommitStatus(statuses []*CommitStatus) commitstatus.CombinedStatus { return states.Merge() } -// CalcCommitStatusSummary returns commit status state via some status, the commit statues should order by id desc +// CalcCommitStatusSummary returns commit status summary, the commit statuses should order by id desc func CalcCommitStatusSummary(statuses []*CommitStatus) *CommitStatusSummary { if len(statuses) == 0 { return nil diff --git a/modules/commitstatus/commit_status.go b/modules/commitstatus/commit_status.go index 13cbf85677f7f..f7d4c7d7102e5 100644 --- a/modules/commitstatus/commit_status.go +++ b/modules/commitstatus/commit_status.go @@ -20,33 +20,10 @@ const ( CommitStatusWarning CommitStatusState = "warning" ) -var commitStatusPriorities = map[CommitStatusState]int{ - CommitStatusError: 0, - CommitStatusFailure: 1, - CommitStatusWarning: 2, - CommitStatusPending: 3, - CommitStatusSuccess: 4, -} - func (css CommitStatusState) String() string { return string(css) } -// NoBetterThan returns true if this State is no better than the given State -// This function only handles the states defined in CommitStatusPriorities -func (css CommitStatusState) NoBetterThan(css2 CommitStatusState) bool { - // NoBetterThan only handles the 5 states above - if _, exist := commitStatusPriorities[css]; !exist { - return false - } - - if _, exist := commitStatusPriorities[css2]; !exist { - return false - } - - return commitStatusPriorities[css] <= commitStatusPriorities[css2] -} - // IsPending represents if commit status state is pending func (css CommitStatusState) IsPending() bool { return css == CommitStatusPending diff --git a/modules/commitstatus/commit_status_test.go b/modules/commitstatus/commit_status_test.go deleted file mode 100644 index ced17e11d916e..0000000000000 --- a/modules/commitstatus/commit_status_test.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package commitstatus - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestNoBetterThan(t *testing.T) { - type args struct { - css CommitStatusState - css2 CommitStatusState - } - var unExpectedState CommitStatusState - tests := []struct { - name string - args args - want bool - }{ - { - name: "success is no better than success", - args: args{ - css: CommitStatusSuccess, - css2: CommitStatusSuccess, - }, - want: true, - }, - { - name: "success is no better than pending", - args: args{ - css: CommitStatusSuccess, - css2: CommitStatusPending, - }, - want: false, - }, - { - name: "success is no better than failure", - args: args{ - css: CommitStatusSuccess, - css2: CommitStatusFailure, - }, - want: false, - }, - { - name: "success is no better than error", - args: args{ - css: CommitStatusSuccess, - css2: CommitStatusError, - }, - want: false, - }, - { - name: "pending is no better than success", - args: args{ - css: CommitStatusPending, - css2: CommitStatusSuccess, - }, - want: true, - }, - { - name: "pending is no better than pending", - args: args{ - css: CommitStatusPending, - css2: CommitStatusPending, - }, - want: true, - }, - { - name: "pending is no better than failure", - args: args{ - css: CommitStatusPending, - css2: CommitStatusFailure, - }, - want: false, - }, - { - name: "pending is no better than error", - args: args{ - css: CommitStatusPending, - css2: CommitStatusError, - }, - want: false, - }, - { - name: "failure is no better than success", - args: args{ - css: CommitStatusFailure, - css2: CommitStatusSuccess, - }, - want: true, - }, - { - name: "failure is no better than pending", - args: args{ - css: CommitStatusFailure, - css2: CommitStatusPending, - }, - want: true, - }, - { - name: "failure is no better than failure", - args: args{ - css: CommitStatusFailure, - css2: CommitStatusFailure, - }, - want: true, - }, - { - name: "failure is no better than error", - args: args{ - css: CommitStatusFailure, - css2: CommitStatusError, - }, - want: false, - }, - { - name: "error is no better than success", - args: args{ - css: CommitStatusError, - css2: CommitStatusSuccess, - }, - want: true, - }, - { - name: "error is no better than pending", - args: args{ - css: CommitStatusError, - css2: CommitStatusPending, - }, - want: true, - }, - { - name: "error is no better than failure", - args: args{ - css: CommitStatusError, - css2: CommitStatusFailure, - }, - want: true, - }, - { - name: "error is no better than error", - args: args{ - css: CommitStatusError, - css2: CommitStatusError, - }, - want: true, - }, - { - name: "unExpectedState is no better than success", - args: args{ - css: unExpectedState, - css2: CommitStatusSuccess, - }, - want: false, - }, - { - name: "unExpectedState is no better than unExpectedState", - args: args{ - css: unExpectedState, - css2: unExpectedState, - }, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := tt.args.css.NoBetterThan(tt.args.css2) - assert.Equal(t, tt.want, result) - }) - } -} diff --git a/services/convert/status.go b/services/convert/status.go index 243eaf6158d52..f71766a2c43c5 100644 --- a/services/convert/status.go +++ b/services/convert/status.go @@ -8,7 +8,6 @@ import ( git_model "code.gitea.io/gitea/models/git" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/commitstatus" api "code.gitea.io/gitea/modules/structs" ) @@ -39,18 +38,12 @@ func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, r return nil } - retStatus := &api.CombinedStatus{ - SHA: statuses[0].SHA, + summary := git_model.CalcCommitStatusSummary(statuses) + return &api.CombinedStatus{ + State: summary.State, + SHA: summary.SHA, TotalCount: len(statuses), Repository: repo, - URL: "", + URL: summary.TargetURL, } - - states := make(commitstatus.CommitStatusStates, 0, len(statuses)) - for _, status := range statuses { - retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status)) - states = append(states, status.State) - } - retStatus.State = states.Merge() - return retStatus } From 0915b1815746ed82ccfd3eca2ab51b633ef6bc0b Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sat, 24 May 2025 21:10:03 -0700 Subject: [PATCH 03/13] improvements --- models/git/commit_status.go | 8 +++--- models/git/commit_status_summary.go | 12 ++++----- routers/web/repo/repo.go | 2 +- .../repository/commitstatus/commitstatus.go | 26 +++++++++---------- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 9ff8d30195d07..7ab89bd63bf2c 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -215,11 +215,9 @@ func (status *CommitStatus) HideActionsURL(ctx context.Context) { return } - if status.Repo == nil { - if err := status.loadRepository(ctx); err != nil { - log.Error("loadRepository: %v", err) - return - } + if err := status.loadRepository(ctx); err != nil { + log.Error("loadRepository: %v", err) + return } prefix := status.Repo.Link() + "/actions" diff --git a/models/git/commit_status_summary.go b/models/git/commit_status_summary.go index f3f5fbdf51659..aa980baecba5e 100644 --- a/models/git/commit_status_summary.go +++ b/models/git/commit_status_summary.go @@ -32,7 +32,7 @@ func init() { } func (status *CommitStatusSummary) loadRepository(ctx context.Context) error { - if status.RepoID == 0 { + if status.RepoID == 0 || status.Repo != nil { return nil } @@ -56,11 +56,9 @@ func (status *CommitStatusSummary) HideActionsURL(ctx context.Context) { return } - if status.Repo == nil { - if err := status.loadRepository(ctx); err != nil { - log.Error("loadRepository: %v", err) - return - } + if err := status.loadRepository(ctx); err != nil { + log.Error("loadRepository: %v", err) + return } prefix := status.Repo.Link() + "/actions" @@ -74,7 +72,7 @@ type RepoSHA struct { SHA string } -func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CommitStatusSummary, error) { +func GetLatestCombinedStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CommitStatusSummary, error) { cond := builder.NewCond() for _, rs := range repoSHAs { cond = cond.Or(builder.Eq{"repo_id": rs.RepoID, "sha": rs.SHA}) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 9a1f4fd8cbce1..024fa47c3a611 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -553,7 +553,7 @@ func SearchRepo(ctx *context.Context) { ctx.SetTotalCountHeader(count) - latestCommitStatuses, err := commitstatus_service.FindReposLastestCommitStatuses(ctx, repos) + latestCommitStatuses, err := commitstatus_service.FindReposLastestCombinedStatuses(ctx, repos) if err != nil { log.Error("FindReposLastestCommitStatuses: %v", err) ctx.JSON(http.StatusInternalServerError, nil) diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index c795d7993f990..cd0f8929b5ed5 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -28,16 +28,16 @@ func getCacheKey(repoID int64, brancheName string) string { return fmt.Sprintf("commit_status:%x", hashBytes) } -type commitStatusCacheValue struct { +type combinedStatusCacheValue struct { State string `json:"state"` TargetURL string `json:"target_url"` } -func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheValue { +func getCombinedStatusCache(repoID int64, branchName string) *combinedStatusCacheValue { c := cache.GetCache() statusStr, ok := c.Get(getCacheKey(repoID, branchName)) if ok && statusStr != "" { - var cv commitStatusCacheValue + var cv combinedStatusCacheValue err := json.Unmarshal([]byte(statusStr), &cv) if err == nil { return &cv @@ -47,9 +47,9 @@ func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheVal return nil } -func updateCommitStatusCache(repoID int64, branchName string, state commitstatus.CombinedStatus, targetURL string) error { +func updateCombinedStatusCache(repoID int64, branchName string, state commitstatus.CombinedStatus, targetURL string) error { c := cache.GetCache() - bs, err := json.Marshal(commitStatusCacheValue{ + bs, err := json.Marshal(combinedStatusCacheValue{ State: string(state), TargetURL: targetURL, }) @@ -60,7 +60,7 @@ func updateCommitStatusCache(repoID int64, branchName string, state commitstatus return c.Put(getCacheKey(repoID, branchName), string(bs), 3*24*60) } -func deleteCommitStatusCache(repoID int64, branchName string) error { +func deleteCombinedStatusCache(repoID int64, branchName string) error { c := cache.GetCache() return c.Delete(getCacheKey(repoID, branchName)) } @@ -112,7 +112,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } if commit.ID.String() == defaultBranchCommit.ID.String() { // since one commit status updated, the combined commit status should be invalid - if err := deleteCommitStatusCache(repo.ID, repo.DefaultBranch); err != nil { + if err := deleteCombinedStatusCache(repo.ID, repo.DefaultBranch); err != nil { log.Error("deleteCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } } @@ -120,12 +120,12 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato return nil } -// FindReposLastestCommitStatuses loading repository default branch latest combinded commit status with cache -func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatusSummary, error) { +// FindReposLastestCombinedStatuses loading repository default branch latest combinded commit status with cache +func FindReposLastestCombinedStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatusSummary, error) { results := make([]*git_model.CommitStatusSummary, len(repos)) allCached := true for i, repo := range repos { - if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil { + if cv := getCombinedStatusCache(repo.ID, repo.DefaultBranch); cv != nil { results[i] = &git_model.CommitStatusSummary{ State: commitstatus.CombinedStatus(cv.State), TargetURL: cv.TargetURL, @@ -158,7 +158,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep repoSHAs = append(repoSHAs, git_model.RepoSHA{RepoID: id, SHA: sha}) } - summaryResults, err := git_model.GetLatestCommitStatusForRepoAndSHAs(ctx, repoSHAs) + summaryResults, err := git_model.GetLatestCombinedStatusForRepoAndSHAs(ctx, repoSHAs) if err != nil { return nil, fmt.Errorf("GetLatestCommitStatusForRepoAndSHAs: %v", err) } @@ -170,7 +170,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep repoSHAs = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { return repoSHA.RepoID == repo.ID }) - if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { + if err := updateCombinedStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } break @@ -191,7 +191,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep if results[i] == nil { results[i] = git_model.CalcCommitStatusSummary(repoToItsLatestCommitStatuses[repo.ID]) if results[i] != nil { - if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { + if err := updateCombinedStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } } From e3554b394550d5aa4c21ac065fc7c0cd74a2fc1a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 May 2025 00:21:52 -0700 Subject: [PATCH 04/13] Rename CommitStatusSummary to CombinedStatus --- ...t_status_summary.go => combined_status.go} | 36 ++++++++++--------- models/git/commit_status.go | 12 +++---- models/git/commit_status_test.go | 18 +++++----- modules/commitstatus/combined_status.go | 30 ++++++++-------- modules/commitstatus/commit_status.go | 8 ++--- modules/structs/status.go | 14 ++++---- routers/web/repo/branch.go | 4 +-- routers/web/repo/commit.go | 2 +- routers/web/repo/pull.go | 6 ++-- routers/web/repo/release.go | 4 +-- routers/web/repo/repo.go | 10 +++--- routers/web/repo/view.go | 2 +- services/convert/status.go | 8 ++--- services/git/commit.go | 2 +- services/pull/commit_status.go | 10 +++--- services/pull/commit_status_test.go | 12 +++---- services/pull/pull.go | 8 ++--- .../repository/commitstatus/commitstatus.go | 12 +++---- services/repository/gitgraph/graph_models.go | 4 +-- services/repository/repository.go | 6 ++-- tests/integration/pull_status_test.go | 2 +- 21 files changed, 107 insertions(+), 103 deletions(-) rename models/git/{commit_status_summary.go => combined_status.go} (70%) diff --git a/models/git/commit_status_summary.go b/models/git/combined_status.go similarity index 70% rename from models/git/commit_status_summary.go rename to models/git/combined_status.go index aa980baecba5e..568c8b46d7e4a 100644 --- a/models/git/commit_status_summary.go +++ b/models/git/combined_status.go @@ -17,21 +17,25 @@ import ( "xorm.io/builder" ) -// CommitStatusSummary holds the latest combined Status of a single Commit -type CommitStatusSummary struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` - Repo *repo_model.Repository `xorm:"-"` - SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` - State commitstatus.CombinedStatus `xorm:"VARCHAR(7) NOT NULL"` - TargetURL string `xorm:"TEXT"` +// CombinedStatus holds the latest combined Status of a single Commit +type CombinedStatus struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"` + Repo *repo_model.Repository `xorm:"-"` + SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"` + State commitstatus.CombinedStatusState `xorm:"VARCHAR(7) NOT NULL"` + TargetURL string `xorm:"TEXT"` +} + +func (CombinedStatus) TableName() string { + return "commit_status_summary" // legacy name for compatibility } func init() { - db.RegisterModel(new(CommitStatusSummary)) + db.RegisterModel(new(CombinedStatus)) } -func (status *CommitStatusSummary) loadRepository(ctx context.Context) error { +func (status *CombinedStatus) loadRepository(ctx context.Context) error { if status.RepoID == 0 || status.Repo != nil { return nil } @@ -46,12 +50,12 @@ func (status *CommitStatusSummary) loadRepository(ctx context.Context) error { } // LocaleString returns the locale string name of the Status -func (status *CommitStatusSummary) LocaleString(lang translation.Locale) string { +func (status *CombinedStatus) LocaleString(lang translation.Locale) string { return lang.TrString("repo.commitstatus." + status.State.String()) } // HideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions -func (status *CommitStatusSummary) HideActionsURL(ctx context.Context) { +func (status *CombinedStatus) HideActionsURL(ctx context.Context) { if status.RepoID == 0 { return } @@ -72,13 +76,13 @@ type RepoSHA struct { SHA string } -func GetLatestCombinedStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CommitStatusSummary, error) { +func GetLatestCombinedStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CombinedStatus, error) { cond := builder.NewCond() for _, rs := range repoSHAs { cond = cond.Or(builder.Eq{"repo_id": rs.RepoID, "sha": rs.SHA}) } - var summaries []*CommitStatusSummary + var summaries []*CombinedStatus if err := db.GetEngine(ctx).Where(cond).Find(&summaries); err != nil { return nil, err } @@ -90,7 +94,7 @@ func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) er if err != nil { return err } - summary := CalcCommitStatusSummary(commitStatuses) + summary := CalcCombinedStatus(commitStatuses) // mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database, // so we need to use insert in on duplicate @@ -111,7 +115,7 @@ func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) er return nil } -func CommitStatusSummeriesHideActionsURL(ctx context.Context, statuses []*CommitStatusSummary) { +func CombinedStatusesHideActionsURL(ctx context.Context, statuses []*CombinedStatus) { idToRepos := make(map[int64]*repo_model.Repository) for _, status := range statuses { if status == nil { diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 7ab89bd63bf2c..79aa0d362ee9f 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -226,8 +226,8 @@ func (status *CommitStatus) HideActionsURL(ctx context.Context) { } } -// CalcCommitStatus returns a combined status, the commit statuses should order by id desc -func CalcCommitStatus(statuses []*CommitStatus) commitstatus.CombinedStatus { +// CalcCombinedStatusState returns a combined status state, the commit statuses should order by id desc +func CalcCombinedStatusState(statuses []*CommitStatus) commitstatus.CombinedStatusState { states := make(commitstatus.CommitStatusStates, 0, len(statuses)) for _, status := range statuses { states = append(states, status.State) @@ -235,8 +235,8 @@ func CalcCommitStatus(statuses []*CommitStatus) commitstatus.CombinedStatus { return states.Merge() } -// CalcCommitStatusSummary returns commit status summary, the commit statuses should order by id desc -func CalcCommitStatusSummary(statuses []*CommitStatus) *CommitStatusSummary { +// CalcCombinedStatus returns combined status struct, the commit statuses should order by id desc +func CalcCombinedStatus(statuses []*CommitStatus) *CombinedStatus { if len(statuses) == 0 { return nil } @@ -249,7 +249,7 @@ func CalcCommitStatusSummary(statuses []*CommitStatus) *CommitStatusSummary { targetURL = status.TargetURL } } - return &CommitStatusSummary{ + return &CombinedStatus{ RepoID: statuses[0].RepoID, SHA: statuses[0].SHA, State: states.Merge(), @@ -499,7 +499,7 @@ func NewCommitStatus(ctx context.Context, opts NewCommitStatusOptions) error { // SignCommitWithStatuses represents a commit with validation of signature and status state. type SignCommitWithStatuses struct { - Status *CommitStatusSummary + Status *CombinedStatus Statuses []*CommitStatus *asymkey_model.SignCommit } diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index 119711f12cd5a..cd3b9a8dfab7c 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -70,7 +70,7 @@ func TestGetCommitStatuses(t *testing.T) { func Test_CalcCommitStatus(t *testing.T) { kases := []struct { statuses []*git_model.CommitStatus - expected commitstatus.CombinedStatus + expected commitstatus.CombinedStatusState }{ { statuses: []*git_model.CommitStatus{ @@ -78,7 +78,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusPending, }, }, - expected: commitstatus.CombinedStatusPending, + expected: commitstatus.CombinedStatusStatePending, }, { statuses: []*git_model.CommitStatus{ @@ -89,7 +89,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusPending, }, }, - expected: commitstatus.CombinedStatusPending, + expected: commitstatus.CombinedStatusStatePending, }, { statuses: []*git_model.CommitStatus{ @@ -103,7 +103,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusPending, + expected: commitstatus.CombinedStatusStatePending, }, { statuses: []*git_model.CommitStatus{ @@ -117,7 +117,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusFailure, + expected: commitstatus.CombinedStatusStateFailure, }, { statuses: []*git_model.CommitStatus{ @@ -131,7 +131,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusPending, + expected: commitstatus.CombinedStatusStatePending, }, { statuses: []*git_model.CommitStatus{ @@ -145,7 +145,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusSuccess, + expected: commitstatus.CombinedStatusStateSuccess, }, { statuses: []*git_model.CommitStatus{ @@ -159,12 +159,12 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusWarning, }, }, - expected: commitstatus.CombinedStatusFailure, + expected: commitstatus.CombinedStatusStateFailure, }, } for _, kase := range kases { - assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses)) + assert.Equal(t, kase.expected, git_model.CalcCombinedStatusState(kase.statuses)) } } diff --git a/modules/commitstatus/combined_status.go b/modules/commitstatus/combined_status.go index ca8b86edb94e7..378dd1ad7df2a 100644 --- a/modules/commitstatus/combined_status.go +++ b/modules/commitstatus/combined_status.go @@ -3,33 +3,33 @@ package commitstatus -// CombinedStatus represents the combined status of a commit. -type CombinedStatus string +// CombinedStatusState represents the combined status of a commit. +type CombinedStatusState string const ( - // CombinedStatusPending is for when the CombinedStatus is Pending - CombinedStatusPending CombinedStatus = "pending" - // CombinedStatusSuccess is for when the CombinedStatus is Success - CombinedStatusSuccess CombinedStatus = "success" - // CombinedStatusFailure is for when the CombinedStatus is Failure - CombinedStatusFailure CombinedStatus = "failure" + // CombinedStatusStatePending is for when the CombinedStatus is Pending + CombinedStatusStatePending CombinedStatusState = "pending" + // CombinedStatusStateSuccess is for when the CombinedStatus is Success + CombinedStatusStateSuccess CombinedStatusState = "success" + // CombinedStatusStateFailure is for when the CombinedStatus is Failure + CombinedStatusStateFailure CombinedStatusState = "failure" ) -func (cs CombinedStatus) String() string { +func (cs CombinedStatusState) String() string { return string(cs) } // IsPending represents if commit status state is pending -func (cs CombinedStatus) IsPending() bool { - return cs == CombinedStatusPending +func (cs CombinedStatusState) IsPending() bool { + return cs == CombinedStatusStatePending } // IsSuccess represents if commit status state is success -func (cs CombinedStatus) IsSuccess() bool { - return cs == CombinedStatusSuccess +func (cs CombinedStatusState) IsSuccess() bool { + return cs == CombinedStatusStateSuccess } // IsFailure represents if commit status state is failure -func (cs CombinedStatus) IsFailure() bool { - return cs == CombinedStatusFailure +func (cs CombinedStatusState) IsFailure() bool { + return cs == CombinedStatusStateFailure } diff --git a/modules/commitstatus/commit_status.go b/modules/commitstatus/commit_status.go index f7d4c7d7102e5..1bb979f5289a2 100644 --- a/modules/commitstatus/commit_status.go +++ b/modules/commitstatus/commit_status.go @@ -57,19 +57,19 @@ type CommitStatusStates []CommitStatusState //nolint // > pending if there are no statuses or a context is pending // > success if the latest status for all contexts is success -func (css CommitStatusStates) Merge() CombinedStatus { +func (css CommitStatusStates) Merge() CombinedStatusState { successCnt := 0 for _, state := range css { switch { case state.IsError() || state.IsFailure(): - return CombinedStatusFailure + return CombinedStatusStateFailure case state.IsPending(): case state.IsSuccess() || state.IsWarning(): successCnt++ } } if successCnt > 0 && successCnt == len(css) { - return CombinedStatusSuccess + return CombinedStatusStateSuccess } - return CombinedStatusPending + return CombinedStatusStatePending } diff --git a/modules/structs/status.go b/modules/structs/status.go index d22ab6862cfca..4fd9f774ae827 100644 --- a/modules/structs/status.go +++ b/modules/structs/status.go @@ -26,13 +26,13 @@ type CommitStatus struct { // CombinedStatus holds the combined state of several statuses for a single commit type CombinedStatus struct { - State commitstatus.CombinedStatus `json:"state"` - SHA string `json:"sha"` - TotalCount int `json:"total_count"` - Statuses []*CommitStatus `json:"statuses"` - Repository *Repository `json:"repository"` - CommitURL string `json:"commit_url"` - URL string `json:"url"` + State commitstatus.CombinedStatusState `json:"state"` + SHA string `json:"sha"` + TotalCount int `json:"total_count"` + Statuses []*CommitStatus `json:"statuses"` + Repository *Repository `json:"repository"` + CommitURL string `json:"commit_url"` + URL string `json:"url"` } // CreateStatusOption holds the information needed to create a new CommitStatus for a Commit diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 3ef1bfbf27d73..d40a69de2b687 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -75,9 +75,9 @@ func Branches(ctx *context.Context) { } } - commitStatus := make(map[string]*git_model.CommitStatusSummary, len(commitStatuses)) + commitStatus := make(map[string]*git_model.CombinedStatus, len(commitStatuses)) for commitID, cs := range commitStatuses { - commitStatus[commitID] = git_model.CalcCommitStatusSummary(cs) + commitStatus[commitID] = git_model.CalcCombinedStatus(cs) } ctx.Data["Keyword"] = kw diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index f9df09f4f132a..9cc232b669d78 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -385,7 +385,7 @@ func Diff(ctx *context.Context) { git_model.CommitStatusesHideActionsURL(ctx, statuses) } - ctx.Data["CommitStatus"] = git_model.CalcCommitStatusSummary(statuses) + ctx.Data["CommitStatus"] = git_model.CalcCombinedStatus(statuses) ctx.Data["CommitStatuses"] = statuses verification := asymkey_service.ParseCommitWithSignature(ctx, commit) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index fd0ac1df3b7a5..f5c0867d84ec2 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -302,7 +302,7 @@ func prepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) if len(commitStatuses) != 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(commitStatuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCombinedStatus(commitStatuses) } } @@ -369,7 +369,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(commitStatuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCombinedStatus(commitStatuses) } compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(), @@ -465,7 +465,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C if len(commitStatuses) > 0 { ctx.Data["LatestCommitStatuses"] = commitStatuses - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(commitStatuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCombinedStatus(commitStatuses) } if pb != nil && pb.EnableStatusCheck { diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index e78cda7b86c8f..d8f790c5e67dc 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -72,7 +72,7 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model type ReleaseInfo struct { Release *repo_model.Release - CommitStatus commitstatus.CombinedStatus + CommitStatus commitstatus.CombinedStatusState CommitStatuses []*git_model.CommitStatus } @@ -136,7 +136,7 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions) return nil, err } - info.CommitStatus = git_model.CalcCommitStatus(statuses) + info.CommitStatus = git_model.CalcCombinedStatusState(statuses) info.CommitStatuses = statuses } diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 024fa47c3a611..cc16c4b87c047 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -553,14 +553,14 @@ func SearchRepo(ctx *context.Context) { ctx.SetTotalCountHeader(count) - latestCommitStatuses, err := commitstatus_service.FindReposLastestCombinedStatuses(ctx, repos) + latestCombinedStatuses, err := commitstatus_service.FindReposLastestCombinedStatuses(ctx, repos) if err != nil { log.Error("FindReposLastestCommitStatuses: %v", err) ctx.JSON(http.StatusInternalServerError, nil) return } if !ctx.Repo.CanRead(unit.TypeActions) { - git_model.CommitStatusSummeriesHideActionsURL(ctx, latestCommitStatuses) + git_model.CombinedStatusesHideActionsURL(ctx, latestCombinedStatuses) } results := make([]*repo_service.WebSearchRepository, len(repos)) @@ -580,9 +580,9 @@ func SearchRepo(ctx *context.Context) { }, } - if latestCommitStatuses[i] != nil { - results[i].LatestCommitStatus = latestCommitStatuses[i] - results[i].LocaleLatestCommitStatus = latestCommitStatuses[i].LocaleString(ctx.Locale) + if latestCombinedStatuses[i] != nil { + results[i].LatestCombinedStatus = latestCombinedStatuses[i] + results[i].LocaleLatestCombinedStatus = latestCombinedStatuses[i].LocaleString(ctx.Locale) } } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index b328e54ca0ab3..2d67b573bdd1a 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -139,7 +139,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool { git_model.CommitStatusesHideActionsURL(ctx, statuses) } - ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatusSummary(statuses) + ctx.Data["LatestCommitStatus"] = git_model.CalcCombinedStatus(statuses) ctx.Data["LatestCommitStatuses"] = statuses } diff --git a/services/convert/status.go b/services/convert/status.go index f71766a2c43c5..997de94d3c200 100644 --- a/services/convert/status.go +++ b/services/convert/status.go @@ -38,12 +38,12 @@ func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, r return nil } - summary := git_model.CalcCommitStatusSummary(statuses) + combinedStatus := git_model.CalcCombinedStatus(statuses) return &api.CombinedStatus{ - State: summary.State, - SHA: summary.SHA, + State: combinedStatus.State, + SHA: combinedStatus.SHA, TotalCount: len(statuses), Repository: repo, - URL: summary.TargetURL, + URL: combinedStatus.TargetURL, } } diff --git a/services/git/commit.go b/services/git/commit.go index a50256a42950a..811dab7c42c8f 100644 --- a/services/git/commit.go +++ b/services/git/commit.go @@ -90,7 +90,7 @@ func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.Sig } commit.Statuses = statuses - commit.Status = git_model.CalcCommitStatusSummary(statuses) + commit.Status = git_model.CalcCombinedStatus(statuses) newCommits = append(newCommits, commit) } return newCommits, nil diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 62e79897924d6..7da02e28ab30d 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -19,7 +19,7 @@ import ( ) // MergeRequiredContextsCommitStatus returns a commit status state for given required contexts -func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) commitstatus.CombinedStatus { +func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) commitstatus.CombinedStatusState { if len(requiredContexts) > 0 { requiredContextsGlob := make(map[string]glob.Glob, len(requiredContexts)) for _, ctx := range requiredContexts { @@ -40,18 +40,18 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, } } if len(requiredCommitStatuses) > 0 { - return git_model.CalcCommitStatus(requiredCommitStatuses) + return git_model.CalcCombinedStatusState(requiredCommitStatuses) } } - return git_model.CalcCommitStatus(commitStatuses) + return git_model.CalcCombinedStatusState(commitStatuses) } // IsCommitStatusContextSuccess returns true if all required status check contexts succeed. func IsCommitStatusContextSuccess(commitStatuses []*git_model.CommitStatus, requiredContexts []string) bool { // If no specific context is required, require that last commit status is a success if len(requiredContexts) == 0 { - return git_model.CalcCommitStatus(commitStatuses) == commitstatus.CombinedStatusSuccess + return git_model.CalcCombinedStatusState(commitStatuses) == commitstatus.CombinedStatusStateSuccess } for _, ctx := range requiredContexts { @@ -91,7 +91,7 @@ func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) ( } // GetPullRequestCommitStatusState returns pull request merged commit status state -func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullRequest) (commitstatus.CombinedStatus, error) { +func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullRequest) (commitstatus.CombinedStatusState, error) { // Ensure HeadRepo is loaded if err := pr.LoadHeadRepo(ctx); err != nil { return "", errors.Wrap(err, "LoadHeadRepo") diff --git a/services/pull/commit_status_test.go b/services/pull/commit_status_test.go index 501d01d32bd2a..6ae6d20de1cb1 100644 --- a/services/pull/commit_status_test.go +++ b/services/pull/commit_status_test.go @@ -49,12 +49,12 @@ func TestMergeRequiredContextsCommitStatus(t *testing.T) { {"Build*", "Build *", "Build 2t*", "Build 1*"}, } - testCasesExpected := []commitstatus.CombinedStatus{ - commitstatus.CombinedStatusSuccess, - commitstatus.CombinedStatusPending, - commitstatus.CombinedStatusFailure, - commitstatus.CombinedStatusPending, - commitstatus.CombinedStatusSuccess, + testCasesExpected := []commitstatus.CombinedStatusState{ + commitstatus.CombinedStatusStateSuccess, + commitstatus.CombinedStatusStatePending, + commitstatus.CombinedStatusStateFailure, + commitstatus.CombinedStatusStatePending, + commitstatus.CombinedStatusStateSuccess, } for i, commitStatuses := range testCases { diff --git a/services/pull/pull.go b/services/pull/pull.go index 54375c20a92d3..c408f9a31a6c3 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -946,13 +946,13 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ } // GetIssuesLastCommitStatus returns a map of issue ID to the most recent commit's latest status -func GetIssuesLastCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64]*git_model.CommitStatusSummary, error) { +func GetIssuesLastCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64]*git_model.CombinedStatus, error) { _, lastStatus, err := GetIssuesAllCommitStatus(ctx, issues) return lastStatus, err } // GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status -func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64][]*git_model.CommitStatus, map[int64]*git_model.CommitStatusSummary, error) { +func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64][]*git_model.CommitStatus, map[int64]*git_model.CombinedStatus, error) { if err := issues.LoadPullRequests(ctx); err != nil { return nil, nil, err } @@ -963,7 +963,7 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList var ( gitRepos = make(map[int64]*git.Repository) res = make(map[int64][]*git_model.CommitStatus) - lastRes = make(map[int64]*git_model.CommitStatusSummary) + lastRes = make(map[int64]*git_model.CombinedStatus) err error ) defer func() { @@ -992,7 +992,7 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList continue } res[issue.PullRequest.ID] = statuses - lastRes[issue.PullRequest.ID] = git_model.CalcCommitStatusSummary(statuses) + lastRes[issue.PullRequest.ID] = git_model.CalcCombinedStatus(statuses) } return res, lastRes, nil } diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index cd0f8929b5ed5..3eea51513caf4 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -47,7 +47,7 @@ func getCombinedStatusCache(repoID int64, branchName string) *combinedStatusCach return nil } -func updateCombinedStatusCache(repoID int64, branchName string, state commitstatus.CombinedStatus, targetURL string) error { +func updateCombinedStatusCache(repoID int64, branchName string, state commitstatus.CombinedStatusState, targetURL string) error { c := cache.GetCache() bs, err := json.Marshal(combinedStatusCacheValue{ State: string(state), @@ -121,13 +121,13 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } // FindReposLastestCombinedStatuses loading repository default branch latest combinded commit status with cache -func FindReposLastestCombinedStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatusSummary, error) { - results := make([]*git_model.CommitStatusSummary, len(repos)) +func FindReposLastestCombinedStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CombinedStatus, error) { + results := make([]*git_model.CombinedStatus, len(repos)) allCached := true for i, repo := range repos { if cv := getCombinedStatusCache(repo.ID, repo.DefaultBranch); cv != nil { - results[i] = &git_model.CommitStatusSummary{ - State: commitstatus.CombinedStatus(cv.State), + results[i] = &git_model.CombinedStatus{ + State: commitstatus.CombinedStatusState(cv.State), TargetURL: cv.TargetURL, } } else { @@ -189,7 +189,7 @@ func FindReposLastestCombinedStatuses(ctx context.Context, repos []*repo_model.R for i, repo := range repos { if results[i] == nil { - results[i] = git_model.CalcCommitStatusSummary(repoToItsLatestCommitStatuses[repo.ID]) + results[i] = git_model.CalcCombinedStatus(repoToItsLatestCommitStatuses[repo.ID]) if results[i] != nil { if err := updateCombinedStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) diff --git a/services/repository/gitgraph/graph_models.go b/services/repository/gitgraph/graph_models.go index 07463e3f03328..ef5f864130b41 100644 --- a/services/repository/gitgraph/graph_models.go +++ b/services/repository/gitgraph/graph_models.go @@ -125,7 +125,7 @@ func (graph *Graph) LoadAndProcessCommits(ctx context.Context, repository *repo_ if err != nil { log.Error("GetLatestCommitStatus: %v", err) } else { - c.Status = git_model.CalcCommitStatusSummary(statuses) + c.Status = git_model.CalcCombinedStatus(statuses) } } return nil @@ -249,7 +249,7 @@ type Commit struct { Commit *git.Commit User *user_model.User Verification *asymkey_model.CommitVerification - Status *git_model.CommitStatusSummary + Status *git_model.CombinedStatus Flow int64 Row int Column int diff --git a/services/repository/repository.go b/services/repository/repository.go index bdff4331cfbae..5b94bd29a6fd7 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -34,9 +34,9 @@ import ( // WebSearchRepository represents a repository returned by web search type WebSearchRepository struct { - Repository *structs.Repository `json:"repository"` - LatestCommitStatus *git.CommitStatusSummary `json:"latest_commit_status"` - LocaleLatestCommitStatus string `json:"locale_latest_commit_status"` + Repository *structs.Repository `json:"repository"` + LatestCombinedStatus *git.CombinedStatus `json:"latest_commit_status"` + LocaleLatestCombinedStatus string `json:"locale_latest_commit_status"` } // WebSearchResults results of a successful web search diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 00ffcfb632c0c..c198ad8b4b71d 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -99,7 +99,7 @@ func TestPullCreate_CommitStatus(t *testing.T) { } repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"}) - css := unittest.AssertExistsAndLoadBean(t, &git_model.CommitStatusSummary{RepoID: repo1.ID, SHA: commitID}) + css := unittest.AssertExistsAndLoadBean(t, &git_model.CombinedStatus{RepoID: repo1.ID, SHA: commitID}) assert.Equal(t, commitstatus.CommitStatusWarning, css.State) }) } From 43ed1366090abbade90375f37c4c6013accb8c21 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 May 2025 11:42:59 -0700 Subject: [PATCH 05/13] generate swagger doc --- templates/swagger/v1_json.tmpl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index c97e52566050f..ba83c890fe4f4 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -21032,7 +21032,7 @@ "x-go-name": "SHA" }, "state": { - "$ref": "#/definitions/CommitStatusState" + "$ref": "#/definitions/CombinedStatusState" }, "statuses": { "type": "array", @@ -21053,6 +21053,11 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "CombinedStatusState": { + "type": "string", + "title": "CombinedStatusState represents the combined status of a commit.", + "x-go-package": "code.gitea.io/gitea/modules/commitstatus" + }, "Comment": { "description": "Comment represents a comment on a commit or issue", "type": "object", @@ -21281,7 +21286,7 @@ "CommitStatusState": { "description": "CommitStatusState holds the state of a CommitStatus\nIt can be \"pending\", \"success\", \"error\" and \"failure\"", "type": "string", - "x-go-package": "code.gitea.io/gitea/modules/structs" + "x-go-package": "code.gitea.io/gitea/modules/commitstatus" }, "CommitUser": { "type": "object", From 083e0ba97a2dca4c12bd4d30e51e9925dfa2e1ef Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 May 2025 12:39:38 -0700 Subject: [PATCH 06/13] Some improvements --- models/git/combined_status.go | 10 +++++----- models/git/commit_status.go | 4 ++-- models/git/commit_status_test.go | 14 +++++++------- modules/commitstatus/combined_status.go | 18 +++++++++--------- modules/commitstatus/commit_status.go | 8 ++++---- routers/web/repo/branch.go | 6 +++--- services/convert/status.go | 4 +++- services/pull/commit_status.go | 2 +- services/pull/commit_status_test.go | 10 +++++----- .../repository/commitstatus/commitstatus.go | 2 +- 10 files changed, 40 insertions(+), 38 deletions(-) diff --git a/models/git/combined_status.go b/models/git/combined_status.go index 568c8b46d7e4a..1caa1cba76ff3 100644 --- a/models/git/combined_status.go +++ b/models/git/combined_status.go @@ -89,27 +89,27 @@ func GetLatestCombinedStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoS return summaries, nil } -func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) error { +func InsertOrUpdateCombinedStatus(ctx context.Context, repoID int64, sha string) error { commitStatuses, _, err := GetLatestCommitStatus(ctx, repoID, sha, db.ListOptionsAll) if err != nil { return err } - summary := CalcCombinedStatus(commitStatuses) + combinedStatus := CalcCombinedStatus(commitStatuses) // mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database, // so we need to use insert in on duplicate if setting.Database.Type.IsMySQL() { _, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state,target_url) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE state=?", - repoID, sha, summary.State, summary.TargetURL, summary.State) + repoID, sha, combinedStatus.State, combinedStatus.TargetURL, combinedStatus.State) return err } if cnt, err := db.GetEngine(ctx).Where("repo_id=? AND sha=?", repoID, sha). Cols("state, target_url"). - Update(summary); err != nil { + Update(combinedStatus); err != nil { return err } else if cnt == 0 { - _, err = db.GetEngine(ctx).Insert(summary) + _, err = db.GetEngine(ctx).Insert(combinedStatus) return err } return nil diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 79aa0d362ee9f..74a625886901d 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -232,7 +232,7 @@ func CalcCombinedStatusState(statuses []*CommitStatus) commitstatus.CombinedStat for _, status := range statuses { states = append(states, status.State) } - return states.Merge() + return states.CalcAsCombinedStatusState() } // CalcCombinedStatus returns combined status struct, the commit statuses should order by id desc @@ -252,7 +252,7 @@ func CalcCombinedStatus(statuses []*CommitStatus) *CombinedStatus { return &CombinedStatus{ RepoID: statuses[0].RepoID, SHA: statuses[0].SHA, - State: states.Merge(), + State: states.CalcAsCombinedStatusState(), TargetURL: targetURL, } } diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index cd3b9a8dfab7c..a502dd1c63ec2 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -78,7 +78,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusPending, }, }, - expected: commitstatus.CombinedStatusStatePending, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ @@ -89,7 +89,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusPending, }, }, - expected: commitstatus.CombinedStatusStatePending, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ @@ -103,7 +103,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusStatePending, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ @@ -117,7 +117,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusStateFailure, + expected: commitstatus.CombinedStatusFailure, }, { statuses: []*git_model.CommitStatus{ @@ -131,7 +131,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusStatePending, + expected: commitstatus.CombinedStatusPending, }, { statuses: []*git_model.CommitStatus{ @@ -145,7 +145,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusSuccess, }, }, - expected: commitstatus.CombinedStatusStateSuccess, + expected: commitstatus.CombinedStatusSuccess, }, { statuses: []*git_model.CommitStatus{ @@ -159,7 +159,7 @@ func Test_CalcCommitStatus(t *testing.T) { State: commitstatus.CommitStatusWarning, }, }, - expected: commitstatus.CombinedStatusStateFailure, + expected: commitstatus.CombinedStatusFailure, }, } diff --git a/modules/commitstatus/combined_status.go b/modules/commitstatus/combined_status.go index 378dd1ad7df2a..f0946bf32377f 100644 --- a/modules/commitstatus/combined_status.go +++ b/modules/commitstatus/combined_status.go @@ -7,12 +7,12 @@ package commitstatus type CombinedStatusState string const ( - // CombinedStatusStatePending is for when the CombinedStatus is Pending - CombinedStatusStatePending CombinedStatusState = "pending" - // CombinedStatusStateSuccess is for when the CombinedStatus is Success - CombinedStatusStateSuccess CombinedStatusState = "success" - // CombinedStatusStateFailure is for when the CombinedStatus is Failure - CombinedStatusStateFailure CombinedStatusState = "failure" + // CombinedStatusPending is for when the CombinedStatus is Pending + CombinedStatusPending CombinedStatusState = "pending" + // CombinedStatusSuccess is for when the CombinedStatus is Success + CombinedStatusSuccess CombinedStatusState = "success" + // CombinedStatusFailure is for when the CombinedStatus is Failure + CombinedStatusFailure CombinedStatusState = "failure" ) func (cs CombinedStatusState) String() string { @@ -21,15 +21,15 @@ func (cs CombinedStatusState) String() string { // IsPending represents if commit status state is pending func (cs CombinedStatusState) IsPending() bool { - return cs == CombinedStatusStatePending + return cs == CombinedStatusPending } // IsSuccess represents if commit status state is success func (cs CombinedStatusState) IsSuccess() bool { - return cs == CombinedStatusStateSuccess + return cs == CombinedStatusSuccess } // IsFailure represents if commit status state is failure func (cs CombinedStatusState) IsFailure() bool { - return cs == CombinedStatusStateFailure + return cs == CombinedStatusFailure } diff --git a/modules/commitstatus/commit_status.go b/modules/commitstatus/commit_status.go index 1bb979f5289a2..432fe7449fc12 100644 --- a/modules/commitstatus/commit_status.go +++ b/modules/commitstatus/commit_status.go @@ -57,19 +57,19 @@ type CommitStatusStates []CommitStatusState //nolint // > pending if there are no statuses or a context is pending // > success if the latest status for all contexts is success -func (css CommitStatusStates) Merge() CombinedStatusState { +func (css CommitStatusStates) CalcAsCombinedStatusState() CombinedStatusState { successCnt := 0 for _, state := range css { switch { case state.IsError() || state.IsFailure(): - return CombinedStatusStateFailure + return CombinedStatusFailure case state.IsPending(): case state.IsSuccess() || state.IsWarning(): successCnt++ } } if successCnt > 0 && successCnt == len(css) { - return CombinedStatusStateSuccess + return CombinedStatusSuccess } - return CombinedStatusStatePending + return CombinedStatusPending } diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index d40a69de2b687..eff80eb6188a1 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -75,14 +75,14 @@ func Branches(ctx *context.Context) { } } - commitStatus := make(map[string]*git_model.CombinedStatus, len(commitStatuses)) + combinedStatuses := make(map[string]*git_model.CombinedStatus, len(commitStatuses)) for commitID, cs := range commitStatuses { - commitStatus[commitID] = git_model.CalcCombinedStatus(cs) + combinedStatuses[commitID] = git_model.CalcCombinedStatus(cs) } ctx.Data["Keyword"] = kw ctx.Data["Branches"] = branches - ctx.Data["CommitStatus"] = commitStatus + ctx.Data["CommitStatus"] = combinedStatuses ctx.Data["CommitStatuses"] = commitStatuses ctx.Data["DefaultBranchBranch"] = defaultBranch pager := context.NewPagination(int(branchesCount), pageSize, page, 5) diff --git a/services/convert/status.go b/services/convert/status.go index 997de94d3c200..469f30bee3da4 100644 --- a/services/convert/status.go +++ b/services/convert/status.go @@ -5,6 +5,7 @@ package convert import ( "context" + "net/url" git_model "code.gitea.io/gitea/models/git" user_model "code.gitea.io/gitea/models/user" @@ -44,6 +45,7 @@ func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, r SHA: combinedStatus.SHA, TotalCount: len(statuses), Repository: repo, - URL: combinedStatus.TargetURL, + CommitURL: repo.URL + "/commits/" + url.PathEscape(combinedStatus.SHA), + URL: repo.URL + "/commits/" + url.PathEscape(combinedStatus.SHA) + "/status", } } diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 7da02e28ab30d..ec52565faf054 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -51,7 +51,7 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, func IsCommitStatusContextSuccess(commitStatuses []*git_model.CommitStatus, requiredContexts []string) bool { // If no specific context is required, require that last commit status is a success if len(requiredContexts) == 0 { - return git_model.CalcCombinedStatusState(commitStatuses) == commitstatus.CombinedStatusStateSuccess + return git_model.CalcCombinedStatusState(commitStatuses) == commitstatus.CombinedStatusSuccess } for _, ctx := range requiredContexts { diff --git a/services/pull/commit_status_test.go b/services/pull/commit_status_test.go index 6ae6d20de1cb1..fdec95f43c9af 100644 --- a/services/pull/commit_status_test.go +++ b/services/pull/commit_status_test.go @@ -50,11 +50,11 @@ func TestMergeRequiredContextsCommitStatus(t *testing.T) { } testCasesExpected := []commitstatus.CombinedStatusState{ - commitstatus.CombinedStatusStateSuccess, - commitstatus.CombinedStatusStatePending, - commitstatus.CombinedStatusStateFailure, - commitstatus.CombinedStatusStatePending, - commitstatus.CombinedStatusStateSuccess, + commitstatus.CombinedStatusSuccess, + commitstatus.CombinedStatusPending, + commitstatus.CombinedStatusFailure, + commitstatus.CombinedStatusPending, + commitstatus.CombinedStatusSuccess, } for i, commitStatuses := range testCases { diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 3eea51513caf4..4bd44157752af 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -99,7 +99,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err) } - return git_model.UpdateCommitStatusSummary(ctx, repo.ID, commit.ID.String()) + return git_model.InsertOrUpdateCombinedStatus(ctx, repo.ID, commit.ID.String()) }); err != nil { return err } From 38708d4b756d3f0d939eda5e4241734e076e5eab Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 May 2025 14:34:12 -0700 Subject: [PATCH 07/13] Split GetLatestCommitStatus as two functions --- models/fixtures/commit_status.yml | 5 +++ models/git/combined_status.go | 2 +- models/git/commit_status.go | 34 +++++++++++++------- models/git/commit_status_test.go | 23 +++++++++++++ routers/api/v1/repo/status.go | 11 +++++-- routers/web/repo/commit.go | 2 +- routers/web/repo/pull.go | 6 ++-- routers/web/repo/release.go | 2 +- routers/web/repo/view.go | 2 +- services/actions/commit_status.go | 2 +- services/git/commit.go | 2 +- services/pull/commit_status.go | 2 +- services/pull/pull.go | 2 +- services/repository/gitgraph/graph_models.go | 2 +- tests/integration/actions_trigger_test.go | 4 +-- 15 files changed, 72 insertions(+), 29 deletions(-) diff --git a/models/fixtures/commit_status.yml b/models/fixtures/commit_status.yml index 20d57975ef40d..87c652e53abc8 100644 --- a/models/fixtures/commit_status.yml +++ b/models/fixtures/commit_status.yml @@ -7,6 +7,7 @@ target_url: https://example.com/builds/ description: My awesome CI-service context: ci/awesomeness + context_hash: c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7 creator_id: 2 - @@ -18,6 +19,7 @@ target_url: https://example.com/converage/ description: My awesome Coverage service context: cov/awesomeness + context_hash: 3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe creator_id: 2 - @@ -29,6 +31,7 @@ target_url: https://example.com/converage/ description: My awesome Coverage service context: cov/awesomeness + context_hash: 3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe creator_id: 2 - @@ -40,6 +43,7 @@ target_url: https://example.com/builds/ description: My awesome CI-service context: ci/awesomeness + context_hash: c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7 creator_id: 2 - @@ -51,4 +55,5 @@ target_url: https://example.com/builds/ description: My awesome deploy service context: deploy/awesomeness + context_hash: ae9547713a6665fc4261d0756904932085a41cf2 creator_id: 2 diff --git a/models/git/combined_status.go b/models/git/combined_status.go index 1caa1cba76ff3..5484d4100a5a8 100644 --- a/models/git/combined_status.go +++ b/models/git/combined_status.go @@ -90,7 +90,7 @@ func GetLatestCombinedStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoS } func InsertOrUpdateCombinedStatus(ctx context.Context, repoID int64, sha string) error { - commitStatuses, _, err := GetLatestCommitStatus(ctx, repoID, sha, db.ListOptionsAll) + commitStatuses, err := GetLatestCommitStatus(ctx, repoID, sha, db.ListOptionsAll) if err != nil { return err } diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 74a625886901d..bc18c5ac5cfd0 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -307,27 +307,37 @@ type CommitStatusIndex struct { MaxIndex int64 `xorm:"index"` } +var getBase = func(ctx context.Context, repoID int64, sha string) *xorm.Session { + return db.GetEngine(ctx).Table(&CommitStatus{}). + Where("repo_id = ?", repoID).And("sha = ?", sha) +} + // GetLatestCommitStatus returns all statuses with a unique context for a given commit. -func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) { - getBase := func() *xorm.Session { - return db.GetEngine(ctx).Table(&CommitStatus{}). - Where("repo_id = ?", repoID).And("sha = ?", sha) - } +func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, error) { indices := make([]int64, 0, 10) - sess := getBase().Select("max( `index` ) as `index`"). - GroupBy("context_hash").OrderBy("max( `index` ) desc") + sess := getBase(ctx, repoID, sha). + Select("max( `index` ) as `index`"). + GroupBy("context_hash"). + OrderBy("max( `index` ) desc") if !listOptions.IsListAll() { sess = db.SetSessionPagination(sess, &listOptions) } - count, err := sess.FindAndCount(&indices) - if err != nil { - return nil, count, err + if err := sess.Find(&indices); err != nil { + return nil, err } + statuses := make([]*CommitStatus, 0, len(indices)) if len(indices) == 0 { - return statuses, count, nil + return statuses, nil } - return statuses, count, getBase().And(builder.In("`index`", indices)).Find(&statuses) + return statuses, getBase(ctx, repoID, sha).And(builder.In("`index`", indices)).Find(&statuses) +} + +func CountLatestCommitStatus(ctx context.Context, repoID int64, sha string) (int64, error) { + return getBase(ctx, repoID, sha). + Select("count(context_hash)"). + GroupBy("context_hash"). + Count() } // GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index a502dd1c63ec2..f2618eada6a20 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -242,3 +242,26 @@ func TestCommitStatusesHideActionsURL(t *testing.T) { assert.Empty(t, statuses[0].TargetURL) assert.Equal(t, "https://mycicd.org/1", statuses[1].TargetURL) } + +func TestGetCountLatestCommitStatus(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + + sha1 := "1234123412341234123412341234123412341234" + + commitStatuses, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo1.ID, sha1, db.ListOptions{ + Page: 1, + PageSize: 2, + }) + assert.NoError(t, err) + assert.Len(t, commitStatuses, 2) + assert.Equal(t, commitstatus.CommitStatusFailure, commitStatuses[0].State) + assert.Equal(t, "ci/awesomeness", commitStatuses[0].Context) + assert.Equal(t, commitstatus.CommitStatusError, commitStatuses[1].State) + assert.Equal(t, "deploy/awesomeness", commitStatuses[1].Context) + + count, err := git_model.CountLatestCommitStatus(db.DefaultContext, repo1.ID, sha1) + assert.NoError(t, err) + assert.EqualValues(t, 3, count) +} diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index 756adcf3a380e..34fd0d0c0ad6b 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -258,19 +258,24 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) { repo := ctx.Repo.Repository - statuses, count, err := git_model.GetLatestCommitStatus(ctx, repo.ID, refCommit.Commit.ID.String(), utils.GetListOptions(ctx)) + statuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, refCommit.Commit.ID.String(), utils.GetListOptions(ctx)) if err != nil { ctx.APIErrorInternal(fmt.Errorf("GetLatestCommitStatus[%s, %s]: %w", repo.FullName(), refCommit.CommitID, err)) return } + count, err := git_model.CountLatestCommitStatus(ctx, repo.ID, refCommit.Commit.ID.String()) + if err != nil { + ctx.APIErrorInternal(fmt.Errorf("GetLatestCommitStatus[%s, %s]: %w", repo.FullName(), refCommit.CommitID, err)) + return + } + ctx.SetTotalCountHeader(count) + if len(statuses) == 0 { ctx.JSON(http.StatusOK, &api.CombinedStatus{}) return } combiStatus := convert.ToCombinedStatus(ctx, statuses, convert.ToRepo(ctx, repo, ctx.Repo.Permission)) - - ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, combiStatus) } diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 9cc232b669d78..943c84e9c05b4 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -377,7 +377,7 @@ func Diff(ctx *context.Context) { ctx.Data["FileIconPoolHTML"] = renderedIconPool.RenderToHTML() } - statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll) + statuses, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index f5c0867d84ec2..813aff527b345 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -291,7 +291,7 @@ func prepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue) if len(compareInfo.Commits) != 0 { sha := compareInfo.Commits[0].ID.String() - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptionsAll) + commitStatuses, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptionsAll) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil @@ -358,7 +358,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err) return nil } - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll) + commitStatuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil @@ -454,7 +454,7 @@ func prepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C return nil } - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll) + commitStatuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index d8f790c5e67dc..223b399b3aba1 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -131,7 +131,7 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions) } if canReadActions { - statuses, _, err := git_model.GetLatestCommitStatus(ctx, r.Repo.ID, r.Sha1, db.ListOptionsAll) + statuses, err := git_model.GetLatestCommitStatus(ctx, r.Repo.ID, r.Sha1, db.ListOptionsAll) if err != nil { return nil, err } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 2d67b573bdd1a..804d7ef77a27a 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -131,7 +131,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool { ctx.Data["LatestCommitVerification"] = verification ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(ctx, latestCommit) - statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptionsAll) + statuses, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptionsAll) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go index 741b3501821fa..a87cd4d89f221 100644 --- a/services/actions/commit_status.go +++ b/services/actions/commit_status.go @@ -92,7 +92,7 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er } ctxname := fmt.Sprintf("%s / %s (%s)", runName, job.Name, event) state := toCommitStatus(job.Status) - if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll); err == nil { + if statuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll); err == nil { for _, v := range statuses { if v.Context == ctxname { if v.State == state { diff --git a/services/git/commit.go b/services/git/commit.go index 811dab7c42c8f..a30234d239dc1 100644 --- a/services/git/commit.go +++ b/services/git/commit.go @@ -84,7 +84,7 @@ func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.Sig commit := &git_model.SignCommitWithStatuses{ SignCommit: c, } - statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, commit.ID.String(), db.ListOptions{}) + statuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, commit.ID.String(), db.ListOptions{}) if err != nil { return nil, err } diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index ec52565faf054..2e386b08a5998 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -125,7 +125,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR return "", errors.Wrap(err, "LoadBaseRepo") } - commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) + commitStatuses, err := git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) if err != nil { return "", errors.Wrap(err, "GetLatestCommitStatus") } diff --git a/services/pull/pull.go b/services/pull/pull.go index c408f9a31a6c3..55abe6fa00a6d 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -1004,7 +1004,7 @@ func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues return nil, shaErr } - statuses, _, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) + statuses, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) return statuses, err } diff --git a/services/repository/gitgraph/graph_models.go b/services/repository/gitgraph/graph_models.go index ef5f864130b41..bd0a6fbf38f99 100644 --- a/services/repository/gitgraph/graph_models.go +++ b/services/repository/gitgraph/graph_models.go @@ -121,7 +121,7 @@ func (graph *Graph) LoadAndProcessCommits(ctx context.Context, repository *repo_ return repo_model.IsOwnerMemberCollaborator(ctx, repository, user.ID) }, &keyMap) - statuses, _, err := git_model.GetLatestCommitStatus(ctx, repository.ID, c.Commit.ID.String(), db.ListOptions{}) + statuses, err := git_model.GetLatestCommitStatus(ctx, repository.ID, c.Commit.ID.String(), db.ListOptions{}) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } else { diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index d40da16d8d36c..6461fe85f4d16 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -634,7 +634,7 @@ jobs: assert.NotEmpty(t, addFileResp) sha = addFileResp.Commit.SHA assert.Eventually(t, func() bool { - latestCommitStatuses, _, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll) + latestCommitStatuses, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll) assert.NoError(t, err) if len(latestCommitStatuses) == 0 { return false @@ -677,7 +677,7 @@ jobs: } func checkCommitStatusAndInsertFakeStatus(t *testing.T, repo *repo_model.Repository, sha string) { - latestCommitStatuses, _, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll) + latestCommitStatuses, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll) assert.NoError(t, err) assert.Len(t, latestCommitStatuses, 1) assert.Equal(t, commitstatus.CommitStatusPending, latestCommitStatuses[0].State) From 4171935599e3efda1204da8b85ae7ee643df6bf2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 May 2025 14:53:42 -0700 Subject: [PATCH 08/13] Fix tests --- routers/web/repo/commit.go | 4 +++- routers/web/repo/issue_view.go | 4 +++- services/pull/commit_status.go | 9 ++++++++- services/pull/commit_status_test.go | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 943c84e9c05b4..d15e5b91c8420 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -457,7 +457,9 @@ func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) ([]*git_m } if !ctx.Repo.CanRead(unit_model.TypeActions) { for _, commit := range commits { - commit.Status.HideActionsURL(ctx) + if commit.Status != nil { + commit.Status.HideActionsURL(ctx) + } git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses) } } diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go index 13b9d83da42d0..9e39aa7163d01 100644 --- a/routers/web/repo/issue_view.go +++ b/routers/web/repo/issue_view.go @@ -757,7 +757,9 @@ func prepareIssueViewCommentsAndSidebarParticipants(ctx *context.Context, issue } if !ctx.Repo.CanRead(unit.TypeActions) { for _, commit := range comment.Commits { - commit.Status.HideActionsURL(ctx) + if commit.Status != nil { + commit.Status.HideActionsURL(ctx) + } git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses) } } diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 2e386b08a5998..64ac7eb2fb982 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -40,8 +40,15 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, } } if len(requiredCommitStatuses) > 0 { - return git_model.CalcCombinedStatusState(requiredCommitStatuses) + returnedStatus := git_model.CalcCombinedStatusState(requiredCommitStatuses) + if len(requiredCommitStatuses) == len(requiredContexts) { + return returnedStatus + } + if returnedStatus == commitstatus.CombinedStatusFailure { + return commitstatus.CombinedStatusFailure + } } + return commitstatus.CombinedStatusPending } return git_model.CalcCombinedStatusState(commitStatuses) diff --git a/services/pull/commit_status_test.go b/services/pull/commit_status_test.go index fdec95f43c9af..8d8e436bdd610 100644 --- a/services/pull/commit_status_test.go +++ b/services/pull/commit_status_test.go @@ -58,8 +58,9 @@ func TestMergeRequiredContextsCommitStatus(t *testing.T) { } for i, commitStatuses := range testCases { - if MergeRequiredContextsCommitStatus(commitStatuses, testCasesRequiredContexts[i]) != testCasesExpected[i] { - assert.Fail(t, "Test case failed", "Test case %d failed", i+1) + status := MergeRequiredContextsCommitStatus(commitStatuses, testCasesRequiredContexts[i]) + if status != testCasesExpected[i] { + assert.Fail(t, "Test case failed", "Test case %d failed: expect %s, got %s", i+1, testCasesExpected[i], status) } } } From eb9fe8723169e94d27be3309a21e6ed15a07d99e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 May 2025 16:25:50 -0700 Subject: [PATCH 09/13] Fix tests --- routers/api/v1/repo/status.go | 7 +------ services/convert/status.go | 9 +++++++++ tests/integration/pull_status_test.go | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index 34fd0d0c0ad6b..768a0652b081b 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -201,15 +201,10 @@ func getCommitStatuses(ctx *context.APIContext, commitID string) { return } - apiStatuses := make([]*api.CommitStatus, 0, len(statuses)) - for _, status := range statuses { - apiStatuses = append(apiStatuses, convert.ToCommitStatus(ctx, status)) - } - ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) ctx.SetTotalCountHeader(maxResults) - ctx.JSON(http.StatusOK, apiStatuses) + ctx.JSON(http.StatusOK, convert.ToCommitStatuses(ctx, statuses)) } // GetCombinedCommitStatusByRef returns the combined status for any given commit hash diff --git a/services/convert/status.go b/services/convert/status.go index 469f30bee3da4..a772721025cdc 100644 --- a/services/convert/status.go +++ b/services/convert/status.go @@ -33,6 +33,14 @@ func ToCommitStatus(ctx context.Context, status *git_model.CommitStatus) *api.Co return apiStatus } +func ToCommitStatuses(ctx context.Context, statuses []*git_model.CommitStatus) []*api.CommitStatus { + apiStatuses := make([]*api.CommitStatus, len(statuses)) + for i, status := range statuses { + apiStatuses[i] = ToCommitStatus(ctx, status) + } + return apiStatuses +} + // ToCombinedStatus converts List of CommitStatus to a CombinedStatus func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, repo *api.Repository) *api.CombinedStatus { if len(statuses) == 0 { @@ -42,6 +50,7 @@ func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, r combinedStatus := git_model.CalcCombinedStatus(statuses) return &api.CombinedStatus{ State: combinedStatus.State, + Statuses: ToCommitStatuses(ctx, statuses), SHA: combinedStatus.SHA, TotalCount: len(statuses), Repository: repo, diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index c198ad8b4b71d..0f02e9cc3a015 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -100,7 +100,7 @@ func TestPullCreate_CommitStatus(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"}) css := unittest.AssertExistsAndLoadBean(t, &git_model.CombinedStatus{RepoID: repo1.ID, SHA: commitID}) - assert.Equal(t, commitstatus.CommitStatusWarning, css.State) + assert.Equal(t, commitstatus.CombinedStatusSuccess, css.State) // warning will also be counted as success }) } From d77674673ab0adcebb8489b8c4c674345c4a8df6 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 25 May 2025 17:49:11 -0700 Subject: [PATCH 10/13] Use Combine as the function name to combine commit status as combined status --- models/git/commit_status.go | 4 ++-- modules/commitstatus/commit_status.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index bc18c5ac5cfd0..5eea522844480 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -232,7 +232,7 @@ func CalcCombinedStatusState(statuses []*CommitStatus) commitstatus.CombinedStat for _, status := range statuses { states = append(states, status.State) } - return states.CalcAsCombinedStatusState() + return states.Combine() } // CalcCombinedStatus returns combined status struct, the commit statuses should order by id desc @@ -252,7 +252,7 @@ func CalcCombinedStatus(statuses []*CommitStatus) *CombinedStatus { return &CombinedStatus{ RepoID: statuses[0].RepoID, SHA: statuses[0].SHA, - State: states.CalcAsCombinedStatusState(), + State: states.Combine(), TargetURL: targetURL, } } diff --git a/modules/commitstatus/commit_status.go b/modules/commitstatus/commit_status.go index 432fe7449fc12..dd2a579e9f4bb 100644 --- a/modules/commitstatus/commit_status.go +++ b/modules/commitstatus/commit_status.go @@ -56,8 +56,7 @@ type CommitStatusStates []CommitStatusState //nolint // > failure if any of the contexts report as error or failure // > pending if there are no statuses or a context is pending // > success if the latest status for all contexts is success - -func (css CommitStatusStates) CalcAsCombinedStatusState() CombinedStatusState { +func (css CommitStatusStates) Combine() CombinedStatusState { successCnt := 0 for _, state := range css { switch { From b053be0d31fb6040bf615fb667f61fc9a763d0e5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 26 May 2025 12:27:02 -0700 Subject: [PATCH 11/13] correct names --- models/git/combined_status.go | 6 +++--- services/pull/pull.go | 5 ++--- services/repository/commitstatus/commitstatus.go | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/models/git/combined_status.go b/models/git/combined_status.go index 5484d4100a5a8..8ff4201696221 100644 --- a/models/git/combined_status.go +++ b/models/git/combined_status.go @@ -82,11 +82,11 @@ func GetLatestCombinedStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoS cond = cond.Or(builder.Eq{"repo_id": rs.RepoID, "sha": rs.SHA}) } - var summaries []*CombinedStatus - if err := db.GetEngine(ctx).Where(cond).Find(&summaries); err != nil { + combinedStatuses := make([]*CombinedStatus, 0, len(repoSHAs)) + if err := db.GetEngine(ctx).Where(cond).Find(&combinedStatuses); err != nil { return nil, err } - return summaries, nil + return combinedStatuses, nil } func InsertOrUpdateCombinedStatus(ctx context.Context, repoID int64, sha string) error { diff --git a/services/pull/pull.go b/services/pull/pull.go index 55abe6fa00a6d..d36817c9b3d06 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -998,14 +998,13 @@ func GetIssuesAllCommitStatus(ctx context.Context, issues issues_model.IssueList } // getAllCommitStatus get pr's commit statuses. -func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues_model.PullRequest) (statuses []*git_model.CommitStatus, err error) { +func getAllCommitStatus(ctx context.Context, gitRepo *git.Repository, pr *issues_model.PullRequest) ([]*git_model.CommitStatus, error) { sha, shaErr := gitRepo.GetRefCommitID(pr.GetGitRefName()) if shaErr != nil { return nil, shaErr } - statuses, err = git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) - return statuses, err + return git_model.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptionsAll) } // IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 4bd44157752af..d6b4730deddfc 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -158,15 +158,15 @@ func FindReposLastestCombinedStatuses(ctx context.Context, repos []*repo_model.R repoSHAs = append(repoSHAs, git_model.RepoSHA{RepoID: id, SHA: sha}) } - summaryResults, err := git_model.GetLatestCombinedStatusForRepoAndSHAs(ctx, repoSHAs) + combinedStatuses, err := git_model.GetLatestCombinedStatusForRepoAndSHAs(ctx, repoSHAs) if err != nil { return nil, fmt.Errorf("GetLatestCommitStatusForRepoAndSHAs: %v", err) } - for _, summary := range summaryResults { + for _, combinedStatus := range combinedStatuses { for i, repo := range repos { - if repo.ID == summary.RepoID { - results[i] = summary + if repo.ID == combinedStatus.RepoID { + results[i] = combinedStatus repoSHAs = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { return repoSHA.RepoID == repo.ID }) From c9678eaafc9ba56fc4783c2bd34dc2741f472b78 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 26 May 2025 13:14:10 -0700 Subject: [PATCH 12/13] Add tests for Combine --- modules/commitstatus/commit_status_test.go | 191 +++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 modules/commitstatus/commit_status_test.go diff --git a/modules/commitstatus/commit_status_test.go b/modules/commitstatus/commit_status_test.go new file mode 100644 index 0000000000000..01d35f6eeb3a5 --- /dev/null +++ b/modules/commitstatus/commit_status_test.go @@ -0,0 +1,191 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package commitstatus + +import "testing" + +func TestCombine(t *testing.T) { + tests := []struct { + name string + states CommitStatusStates + expected CombinedStatusState + }{ + // 0 states + { + name: "empty", + states: CommitStatusStates{}, + expected: CombinedStatusPending, + }, + // 1 state + { + name: "pending", + states: CommitStatusStates{CommitStatusPending}, + expected: CombinedStatusPending, + }, + { + name: "success", + states: CommitStatusStates{CommitStatusSuccess}, + expected: CombinedStatusSuccess, + }, + { + name: "error", + states: CommitStatusStates{CommitStatusError}, + expected: CombinedStatusFailure, + }, + { + name: "failure", + states: CommitStatusStates{CommitStatusFailure}, + expected: CombinedStatusFailure, + }, + { + name: "warning", + states: CommitStatusStates{CommitStatusWarning}, + expected: CombinedStatusSuccess, + }, + // 2 states + { + name: "pending and success", + states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess}, + expected: CombinedStatusPending, + }, + { + name: "pending and error", + states: CommitStatusStates{CommitStatusPending, CommitStatusError}, + expected: CombinedStatusFailure, + }, + { + name: "pending and failure", + states: CommitStatusStates{CommitStatusPending, CommitStatusFailure}, + expected: CombinedStatusFailure, + }, + { + name: "pending and warning", + states: CommitStatusStates{CommitStatusPending, CommitStatusWarning}, + expected: CombinedStatusPending, + }, + { + name: "success and error", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusError}, + expected: CombinedStatusFailure, + }, + { + name: "success and failure", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusFailure}, + expected: CombinedStatusFailure, + }, + { + name: "success and warning", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusWarning}, + expected: CombinedStatusSuccess, + }, + { + name: "error and failure", + states: CommitStatusStates{CommitStatusError, CommitStatusFailure}, + expected: CombinedStatusFailure, + }, + { + name: "error and warning", + states: CommitStatusStates{CommitStatusError, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "failure and warning", + states: CommitStatusStates{CommitStatusFailure, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + // 3 states + { + name: "pending, success and warning", + states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusWarning}, + expected: CombinedStatusPending, + }, + { + name: "pending, success and error", + states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusError}, + expected: CombinedStatusFailure, + }, + { + name: "pending, success and failure", + states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusFailure}, + expected: CombinedStatusFailure, + }, + { + name: "pending, error and failure", + states: CommitStatusStates{CommitStatusPending, CommitStatusError, CommitStatusFailure}, + expected: CombinedStatusFailure, + }, + { + name: "success, error and warning", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusError, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "success, failure and warning", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusFailure, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "error, failure and warning", + states: CommitStatusStates{CommitStatusError, CommitStatusFailure, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + // All success + { + name: "all success", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusSuccess}, + expected: CombinedStatusSuccess, + }, + // All pending + { + name: "all pending", + states: CommitStatusStates{CommitStatusPending, CommitStatusPending, CommitStatusPending}, + expected: CombinedStatusPending, + }, + // 4 states + { + name: "pending, success, error and warning", + states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusError, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "pending, success, failure and warning", + states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusFailure, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "pending, error, failure and warning", + states: CommitStatusStates{CommitStatusPending, CommitStatusError, CommitStatusFailure, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "success, error, failure and warning", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusError, CommitStatusFailure, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "mixed states", + states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusError, CommitStatusWarning}, + expected: CombinedStatusFailure, + }, + { + name: "mixed states with all success", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusPending, CommitStatusWarning}, + expected: CombinedStatusPending, + }, + { + name: "all success with warning", + states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusSuccess, CommitStatusWarning}, + expected: CombinedStatusSuccess, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.states.Combine() + if result != tt.expected { + t.Errorf("expected %v, got %v", tt.expected, result) + } + }) + } +} From 3a2ae5cae81f2f591cba2cfd3a187f67f2a29c1c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 27 May 2025 14:17:51 -0700 Subject: [PATCH 13/13] Some changes to templates --- routers/web/repo/branch.go | 2 +- routers/web/repo/commit.go | 2 +- routers/web/repo/issue_list.go | 4 ++-- routers/web/repo/release.go | 5 ++--- routers/web/user/home.go | 4 ++-- routers/web/user/notification.go | 12 ++---------- services/pull/pull.go | 8 ++++---- templates/repo/branch/list.tmpl | 4 ++-- templates/repo/commit_page.tmpl | 2 +- templates/repo/commit_statuses.tmpl | 2 +- templates/repo/pulls/status.tmpl | 12 ++++++------ templates/repo/release/list.tmpl | 2 +- templates/shared/issuelist.tmpl | 2 +- 13 files changed, 26 insertions(+), 35 deletions(-) diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index eff80eb6188a1..1dcddb598a29a 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -82,7 +82,7 @@ func Branches(ctx *context.Context) { ctx.Data["Keyword"] = kw ctx.Data["Branches"] = branches - ctx.Data["CommitStatus"] = combinedStatuses + ctx.Data["CombinedStatuses"] = combinedStatuses ctx.Data["CommitStatuses"] = commitStatuses ctx.Data["DefaultBranchBranch"] = defaultBranch pager := context.NewPagination(int(branchesCount), pageSize, page, 5) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index d15e5b91c8420..70d919c2ab6fa 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -385,7 +385,7 @@ func Diff(ctx *context.Context) { git_model.CommitStatusesHideActionsURL(ctx, statuses) } - ctx.Data["CommitStatus"] = git_model.CalcCombinedStatus(statuses) + ctx.Data["CombinedStatus"] = git_model.CalcCombinedStatus(statuses) ctx.Data["CommitStatuses"] = statuses verification := asymkey_service.ParseCommitWithSignature(ctx, commit) diff --git a/routers/web/repo/issue_list.go b/routers/web/repo/issue_list.go index 35107bc585dfb..0027a95bc9409 100644 --- a/routers/web/repo/issue_list.go +++ b/routers/web/repo/issue_list.go @@ -665,7 +665,7 @@ func prepareIssueFilterAndList(ctx *context.Context, milestoneID, projectID int6 } } - commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues) + commitStatuses, combinedStatuses, err := pull_service.GetIssuesAllCommitStatus(ctx, issues) if err != nil { ctx.ServerError("GetIssuesAllCommitStatus", err) return @@ -682,7 +682,7 @@ func prepareIssueFilterAndList(ctx *context.Context, milestoneID, projectID int6 } ctx.Data["Issues"] = issues - ctx.Data["CommitLastStatus"] = lastStatus + ctx.Data["CombinedStatuses"] = combinedStatuses ctx.Data["CommitStatuses"] = commitStatuses // Get assignees. diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 223b399b3aba1..f5ab026d6846e 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -16,7 +16,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/commitstatus" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/markup/markdown" @@ -72,7 +71,7 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model type ReleaseInfo struct { Release *repo_model.Release - CommitStatus commitstatus.CombinedStatusState + CombinedStatus *git_model.CombinedStatus CommitStatuses []*git_model.CommitStatus } @@ -136,7 +135,7 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions) return nil, err } - info.CommitStatus = git_model.CalcCombinedStatusState(statuses) + info.CombinedStatus = git_model.CalcCombinedStatus(statuses) info.CommitStatuses = statuses } diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 77f9cb8cca84f..094f4f3f18849 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -564,7 +564,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { } } - commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues) + commitStatuses, combinedStatuses, err := pull_service.GetIssuesAllCommitStatus(ctx, issues) if err != nil { ctx.ServerError("GetIssuesLastCommitStatus", err) return @@ -630,7 +630,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { } return 0 } - ctx.Data["CommitLastStatus"] = lastStatus + ctx.Data["CombinedStatuses"] = combinedStatuses ctx.Data["CommitStatuses"] = commitStatuses ctx.Data["IssueStats"] = issueStats ctx.Data["ViewType"] = viewType diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 89f3c6956f7fa..d6eaf49aeea07 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -274,7 +274,7 @@ func NotificationSubscriptions(ctx *context.Context) { return } - commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues) + commitStatuses, combinedStatuses, err := pull_service.GetIssuesAllCommitStatus(ctx, issues) if err != nil { ctx.ServerError("GetIssuesAllCommitStatus", err) return @@ -284,19 +284,11 @@ func NotificationSubscriptions(ctx *context.Context) { git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key]) } } - ctx.Data["CommitLastStatus"] = lastStatus + ctx.Data["CombinedStatuses"] = combinedStatuses ctx.Data["CommitStatuses"] = commitStatuses ctx.Data["Issues"] = issues - ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, "") - commitStatus, err := pull_service.GetIssuesLastCommitStatus(ctx, issues) - if err != nil { - ctx.ServerError("GetIssuesLastCommitStatus", err) - return - } - ctx.Data["CommitStatus"] = commitStatus - approvalCounts, err := issues.GetApprovalCounts(ctx) if err != nil { ctx.ServerError("ApprovalCounts", err) diff --git a/services/pull/pull.go b/services/pull/pull.go index d36817c9b3d06..58195e3a4d35b 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -945,10 +945,10 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ return stringBuilder.String() } -// GetIssuesLastCommitStatus returns a map of issue ID to the most recent commit's latest status -func GetIssuesLastCommitStatus(ctx context.Context, issues issues_model.IssueList) (map[int64]*git_model.CombinedStatus, error) { - _, lastStatus, err := GetIssuesAllCommitStatus(ctx, issues) - return lastStatus, err +// GetIssuesCombinedStatuses returns a map of issue ID to the most recent commit's latest status +func GetIssuesCombinedStatuses(ctx context.Context, issues issues_model.IssueList) (map[int64]*git_model.CombinedStatus, error) { + _, combinedStatuses, err := GetIssuesAllCommitStatus(ctx, issues) + return combinedStatuses, err } // GetIssuesAllCommitStatus returns a map of issue ID to a list of all statuses for the most recent commit as well as a map of issue ID to only the commit's latest status diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index fffe3a08cc4bf..4b888a766a328 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -25,7 +25,7 @@ {{svg "octicon-shield-lock"}} {{end}} - {{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}} + {{template "repo/commit_statuses" dict "Status" (index $.CombinedStatuses .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}}

{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}} · {{ctx.RenderUtils.RenderCommitMessage .DefaultBranchBranch.DBBranch.CommitMessage .Repository}} · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DefaultBranchBranch.DBBranch.CommitTime}}{{if .DefaultBranchBranch.DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}

@@ -101,7 +101,7 @@ {{svg "octicon-shield-lock"}} {{end}} - {{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DBBranch.CommitID)}} + {{template "repo/commit_statuses" dict "Status" (index $.CombinedStatuses .DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DBBranch.CommitID)}}

{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DBBranch.CommitID}} · {{ctx.RenderUtils.RenderCommitMessage .DBBranch.CommitMessage $.Repository}} · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DBBranch.CommitTime}}{{if .DBBranch.Pusher}}  {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}}  {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}

{{end}} diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 7abd37710859f..10cac1945f9dc 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -5,7 +5,7 @@
-

{{ctx.RenderUtils.RenderCommitMessage .Commit.Message $.Repository}}{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}

+

{{ctx.RenderUtils.RenderCommitMessage .Commit.Message $.Repository}}{{template "repo/commit_statuses" dict "Status" .CombinedStatus "Statuses" .CommitStatuses}}

{{if not $.PageIsWiki}}
diff --git a/templates/repo/commit_statuses.tmpl b/templates/repo/commit_statuses.tmpl index 1bbfb331051c8..0b2db9514d6d0 100644 --- a/templates/repo/commit_statuses.tmpl +++ b/templates/repo/commit_statuses.tmpl @@ -9,6 +9,6 @@ {{end}}
- {{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CommitStatus" .Status)}} + {{template "repo/pulls/status" (dict "CommitStatuses" .Statuses "CombinedStatus" .Status)}}
{{end}} diff --git a/templates/repo/pulls/status.tmpl b/templates/repo/pulls/status.tmpl index 96030f9422d54..6c965e040cf3b 100644 --- a/templates/repo/pulls/status.tmpl +++ b/templates/repo/pulls/status.tmpl @@ -6,18 +6,18 @@ * is_context_required: Used in pull request commit status check table */}} -{{if .CommitStatus}} +{{if .CombinedStatus}}
- {{if or (eq .CommitStatus.State "pending") (.MissingRequiredChecks)}} + {{if or (eq .CombinedStatus.State "pending") (.MissingRequiredChecks)}} {{ctx.Locale.Tr "repo.pulls.status_checking"}} - {{else if eq .CommitStatus.State "success"}} + {{else if eq .CombinedStatus.State "success"}} {{ctx.Locale.Tr "repo.pulls.status_checks_success"}} - {{else if eq .CommitStatus.State "warning"}} + {{else if eq .CombinedStatus.State "warning"}} {{ctx.Locale.Tr "repo.pulls.status_checks_warning"}} - {{else if eq .CommitStatus.State "failure"}} + {{else if eq .CombinedStatus.State "failure"}} {{ctx.Locale.Tr "repo.pulls.status_checks_failure"}} - {{else if eq .CommitStatus.State "error"}} + {{else if eq .CombinedStatus.State "error"}} {{ctx.Locale.Tr "repo.pulls.status_checks_error"}} {{else}} {{ctx.Locale.Tr "repo.pulls.status_checking"}} diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 1a7d911acbdf3..bbfc30e4e2231 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -33,7 +33,7 @@

{{if $.PageIsSingleTag}}{{$release.Title}}{{else}}{{$release.Title}}{{end}} - {{template "repo/commit_statuses" dict "Status" $info.CommitStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}} + {{template "repo/commit_statuses" dict "Status" $info.CombinedStatus "Statuses" $info.CommitStatuses "AdditionalClasses" "tw-flex"}} {{template "repo/release/label" (dict "Release" $release)}}

diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index 30670c3b0fc74..df7da5e1de3ca 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -16,7 +16,7 @@ {{.Title | ctx.RenderUtils.RenderIssueSimpleTitle}} {{if .IsPull}} {{if (index $.CommitStatuses .PullRequest.ID)}} - {{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID)}} + {{template "repo/commit_statuses" dict "Status" (index $.CombinedStatuses .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID)}} {{end}} {{end}}