diff options
Diffstat (limited to 'models/git')
-rw-r--r-- | models/git/branch.go | 2 | ||||
-rw-r--r-- | models/git/commit_status.go | 42 | ||||
-rw-r--r-- | models/git/commit_status_summary.go | 8 | ||||
-rw-r--r-- | models/git/commit_status_test.go | 25 |
4 files changed, 60 insertions, 17 deletions
diff --git a/models/git/branch.go b/models/git/branch.go index beeb7c0689..07c94a8ba5 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -487,7 +487,7 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o ForkFrom: opts.BaseRepo.ID, Archived: optional.Some(false), } - repoCond := repo_model.SearchRepositoryCondition(&repoOpts).And(repo_model.AccessibleRepositoryCondition(doer, unit.TypeCode)) + repoCond := repo_model.SearchRepositoryCondition(repoOpts).And(repo_model.AccessibleRepositoryCondition(doer, unit.TypeCode)) if opts.Repo.ID == opts.BaseRepo.ID { // should also include the base repo's branches repoCond = repoCond.Or(builder.Eq{"id": opts.BaseRepo.ID}) diff --git a/models/git/commit_status.go b/models/git/commit_status.go index b978476c4b..2e765391b8 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -230,18 +230,24 @@ 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 { + // This function is widely used, but it is not quite right. + // Ideally it should return something like "CommitStatusSummary" with properly aggregated state. + // GitHub's behavior: if all statuses are "skipped", GitHub will return "success" as the combined status. var lastStatus *CommitStatus state := api.CommitStatusSuccess for _, status := range statuses { - if status.State.NoBetterThan(state) { + if state == status.State || status.State.HasHigherPriorityThan(state) { state = status.State lastStatus = status } } if lastStatus == nil { if len(statuses) > 0 { + // FIXME: a bad case: Gitea just returns the first commit status, its status is "skipped" in this case. lastStatus = statuses[0] } else { + // FIXME: another bad case: if the "statuses" slice is empty, the returned value is an invalid CommitStatus, all its fields are empty. + // Frontend code (tmpl&vue) sometimes depend on the empty fields to skip rendering commit status elements (need to double check in the future) lastStatus = &CommitStatus{} } } @@ -298,27 +304,37 @@ type CommitStatusIndex struct { MaxIndex int64 `xorm:"index"` } +func makeRepoCommitQuery(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 := makeRepoCommitQuery(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) + err := makeRepoCommitQuery(ctx, repoID, sha).And(builder.In("`index`", indices)).Find(&statuses) + return statuses, err +} + +func CountLatestCommitStatus(ctx context.Context, repoID int64, sha string) (int64, error) { + return makeRepoCommitQuery(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_summary.go b/models/git/commit_status_summary.go index 7603e7aa65..774e49bb98 100644 --- a/models/git/commit_status_summary.go +++ b/models/git/commit_status_summary.go @@ -55,11 +55,15 @@ func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA } func UpdateCommitStatusSummary(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 } - state := CalcCommitStatus(commitStatuses) + // it guarantees that commitStatuses is not empty because this function is always called after a commit status is created + if len(commitStatuses) == 0 { + setting.PanicInDevOrTesting("no commit statuses found for repo %d and sha %s", repoID, sha) + } + state := CalcCommitStatus(commitStatuses) // non-empty commitStatuses is guaranteed // 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() { diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index 37d785e938..a01d030e71 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -26,7 +26,7 @@ func TestGetCommitStatuses(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - sha1 := "1234123412341234123412341234123412341234" + sha1 := "1234123412341234123412341234123412341234" // the mocked commit ID in test fixtures statuses, maxResults, err := db.FindAndCount[git_model.CommitStatus](db.DefaultContext, &git_model.CommitStatusOptions{ ListOptions: db.ListOptions{Page: 1, PageSize: 50}, @@ -256,3 +256,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" // the mocked commit ID in test fixtures + + 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, structs.CommitStatusFailure, commitStatuses[0].State) + assert.Equal(t, "ci/awesomeness", commitStatuses[0].Context) + assert.Equal(t, structs.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) +} |