mirror of https://github.com/go-gitea/gitea.git
Keeping consistent between UI and API about combined commit status state and fix some bugs (#34562)
Extract from #34531 ## Move Commit status state to a standalone package Move the state from `structs` to `commitstatus` package. It also introduce `CommitStatusStates` so that the combine function could be used from UI and API logic. ## Combined commit status Changed This PR will follow Github's combined commit status. Before this PR, every commit status could be a combined one. 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 This PR will follow that rule and remove the `NoBetterThan` logic. This also fixes the inconsistent between UI and API. In the API convert package, it has implemented this which is different from the UI. It also fixed the missing `URL` and `CommitURL` in the API. ## `CalcCommitStatus` return nil if there is no commit statuses The behavior of `CalcCommitStatus` is changed. If the parameter commit statuses is empty, it will return nil. The reference places should check the returned value themselves.pull/34493/head^2
parent
f6041441ee
commit
6d0b24064a
|
@ -17,10 +17,10 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
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/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ type CommitStatus struct {
|
||||||
Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"`
|
Index int64 `xorm:"INDEX UNIQUE(repo_sha_index)"`
|
||||||
RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"`
|
RepoID int64 `xorm:"INDEX UNIQUE(repo_sha_index)"`
|
||||||
Repo *repo_model.Repository `xorm:"-"`
|
Repo *repo_model.Repository `xorm:"-"`
|
||||||
State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"`
|
State commitstatus.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"`
|
||||||
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
|
SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_sha_index)"`
|
||||||
TargetURL string `xorm:"TEXT"`
|
TargetURL string `xorm:"TEXT"`
|
||||||
Description string `xorm:"TEXT"`
|
Description string `xorm:"TEXT"`
|
||||||
|
@ -230,28 +230,25 @@ 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 commit status state via some status, the commit statues should order by id desc
|
||||||
func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
|
func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
|
||||||
// This function is widely used, but it is not quite right.
|
if len(statuses) == 0 {
|
||||||
// Ideally it should return something like "CommitStatusSummary" with properly aggregated state.
|
return nil
|
||||||
// GitHub's behavior: if all statuses are "skipped", GitHub will return "success" as the combined status.
|
}
|
||||||
var lastStatus *CommitStatus
|
|
||||||
state := api.CommitStatusSuccess
|
states := make(commitstatus.CommitStatusStates, 0, len(statuses))
|
||||||
|
targetURL := ""
|
||||||
for _, status := range statuses {
|
for _, status := range statuses {
|
||||||
if state == status.State || status.State.HasHigherPriorityThan(state) {
|
states = append(states, status.State)
|
||||||
state = status.State
|
if status.TargetURL != "" {
|
||||||
lastStatus = status
|
targetURL = status.TargetURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lastStatus == nil {
|
|
||||||
if len(statuses) > 0 {
|
return &CommitStatus{
|
||||||
// FIXME: a bad case: Gitea just returns the first commit status, its status is "skipped" in this case.
|
RepoID: statuses[0].RepoID,
|
||||||
lastStatus = statuses[0]
|
SHA: statuses[0].SHA,
|
||||||
} else {
|
State: states.Combine(),
|
||||||
// FIXME: another bad case: if the "statuses" slice is empty, the returned value is an invalid CommitStatus, all its fields are empty.
|
TargetURL: targetURL,
|
||||||
// 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{}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return lastStatus
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitStatusOptions holds the options for query commit statuses
|
// CommitStatusOptions holds the options for query commit statuses
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/commitstatus"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
@ -18,7 +18,7 @@ type CommitStatusSummary struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"`
|
RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"`
|
||||||
SHA string `xorm:"VARCHAR(64) NOT NULL 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"`
|
State commitstatus.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"`
|
||||||
TargetURL string `xorm:"TEXT"`
|
TargetURL string `xorm:"TEXT"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,9 @@ import (
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
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/git"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -38,23 +38,23 @@ func TestGetCommitStatuses(t *testing.T) {
|
||||||
assert.Len(t, statuses, 5)
|
assert.Len(t, statuses, 5)
|
||||||
|
|
||||||
assert.Equal(t, "ci/awesomeness", statuses[0].Context)
|
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, "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, "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, "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, "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, "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, "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, "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, "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))
|
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{
|
statuses, maxResults, err = db.FindAndCount[git_model.CommitStatus](db.DefaultContext, &git_model.CommitStatusOptions{
|
||||||
|
@ -75,110 +75,110 @@ func Test_CalcCommitStatus(t *testing.T) {
|
||||||
{
|
{
|
||||||
statuses: []*git_model.CommitStatus{
|
statuses: []*git_model.CommitStatus{
|
||||||
{
|
{
|
||||||
State: structs.CommitStatusPending,
|
State: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: &git_model.CommitStatus{
|
expected: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusPending,
|
State: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
statuses: []*git_model.CommitStatus{
|
statuses: []*git_model.CommitStatus{
|
||||||
{
|
{
|
||||||
State: structs.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
State: structs.CommitStatusPending,
|
State: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: &git_model.CommitStatus{
|
expected: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusPending,
|
State: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
statuses: []*git_model.CommitStatus{
|
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{
|
expected: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusPending,
|
State: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
statuses: []*git_model.CommitStatus{
|
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{
|
expected: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusError,
|
State: commitstatus.CommitStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
statuses: []*git_model.CommitStatus{
|
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{
|
expected: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusWarning,
|
State: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
statuses: []*git_model.CommitStatus{
|
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{
|
expected: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
statuses: []*git_model.CommitStatus{
|
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{
|
expected: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusError,
|
State: commitstatus.CommitStatusFailure,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, kase := range kases {
|
for _, kase := range kases {
|
||||||
assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses))
|
assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses), "statuses: %v", kase.statuses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
|
||||||
Creator: user2,
|
Creator: user2,
|
||||||
SHA: commit.ID,
|
SHA: commit.ID,
|
||||||
CommitStatus: &git_model.CommitStatus{
|
CommitStatus: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusFailure,
|
State: commitstatus.CommitStatusFailure,
|
||||||
TargetURL: "https://example.com/tests/",
|
TargetURL: "https://example.com/tests/",
|
||||||
Context: "compliance/lint-backend",
|
Context: "compliance/lint-backend",
|
||||||
},
|
},
|
||||||
|
@ -220,7 +220,7 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
|
||||||
Creator: user2,
|
Creator: user2,
|
||||||
SHA: commit.ID,
|
SHA: commit.ID,
|
||||||
CommitStatus: &git_model.CommitStatus{
|
CommitStatus: &git_model.CommitStatus{
|
||||||
State: structs.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: "https://example.com/tests/",
|
TargetURL: "https://example.com/tests/",
|
||||||
Context: "compliance/lint-backend",
|
Context: "compliance/lint-backend",
|
||||||
},
|
},
|
||||||
|
@ -270,9 +270,9 @@ func TestGetCountLatestCommitStatus(t *testing.T) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, commitStatuses, 2)
|
assert.Len(t, commitStatuses, 2)
|
||||||
assert.Equal(t, structs.CommitStatusFailure, commitStatuses[0].State)
|
assert.Equal(t, commitstatus.CommitStatusFailure, commitStatuses[0].State)
|
||||||
assert.Equal(t, "ci/awesomeness", commitStatuses[0].Context)
|
assert.Equal(t, "ci/awesomeness", commitStatuses[0].Context)
|
||||||
assert.Equal(t, structs.CommitStatusError, commitStatuses[1].State)
|
assert.Equal(t, commitstatus.CommitStatusError, commitStatuses[1].State)
|
||||||
assert.Equal(t, "deploy/awesomeness", commitStatuses[1].Context)
|
assert.Equal(t, "deploy/awesomeness", commitStatuses[1].Context)
|
||||||
|
|
||||||
count, err := git_model.CountLatestCommitStatus(db.DefaultContext, repo1.ID, sha1)
|
count, err := git_model.CountLatestCommitStatus(db.DefaultContext, repo1.ID, sha1)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package structs
|
package commitstatus
|
||||||
|
|
||||||
// CommitStatusState holds the state of a CommitStatus
|
// CommitStatusState holds the state of a CommitStatus
|
||||||
// It can be "pending", "success", "error" and "failure"
|
// swagger:enum CommitStatusState
|
||||||
type CommitStatusState string
|
type CommitStatusState string //nolint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// CommitStatusPending is for when the CommitStatus is Pending
|
// CommitStatusPending is for when the CommitStatus is Pending
|
||||||
|
@ -22,25 +22,10 @@ const (
|
||||||
CommitStatusSkipped CommitStatusState = "skipped"
|
CommitStatusSkipped CommitStatusState = "skipped"
|
||||||
)
|
)
|
||||||
|
|
||||||
var commitStatusPriorities = map[CommitStatusState]int{
|
|
||||||
CommitStatusError: 0,
|
|
||||||
CommitStatusFailure: 1,
|
|
||||||
CommitStatusWarning: 2,
|
|
||||||
CommitStatusPending: 3,
|
|
||||||
CommitStatusSuccess: 4,
|
|
||||||
CommitStatusSkipped: 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
func (css CommitStatusState) String() string {
|
func (css CommitStatusState) String() string {
|
||||||
return string(css)
|
return string(css)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasHigherPriorityThan returns true if this state has higher priority than the other
|
|
||||||
// Undefined states are considered to have the highest priority like CommitStatusError(0)
|
|
||||||
func (css CommitStatusState) HasHigherPriorityThan(other CommitStatusState) bool {
|
|
||||||
return commitStatusPriorities[css] < commitStatusPriorities[other]
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPending represents if commit status state is pending
|
// IsPending represents if commit status state is pending
|
||||||
func (css CommitStatusState) IsPending() bool {
|
func (css CommitStatusState) IsPending() bool {
|
||||||
return css == CommitStatusPending
|
return css == CommitStatusPending
|
||||||
|
@ -65,3 +50,32 @@ func (css CommitStatusState) IsFailure() bool {
|
||||||
func (css CommitStatusState) IsWarning() bool {
|
func (css CommitStatusState) IsWarning() bool {
|
||||||
return css == CommitStatusWarning
|
return css == CommitStatusWarning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSkipped represents if commit status state is skipped
|
||||||
|
func (css CommitStatusState) IsSkipped() bool {
|
||||||
|
return css == CommitStatusSkipped
|
||||||
|
}
|
||||||
|
|
||||||
|
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) Combine() CommitStatusState {
|
||||||
|
successCnt := 0
|
||||||
|
for _, state := range css {
|
||||||
|
switch {
|
||||||
|
case state.IsError() || state.IsFailure():
|
||||||
|
return CommitStatusFailure
|
||||||
|
case state.IsPending():
|
||||||
|
case state.IsSuccess() || state.IsWarning() || state.IsSkipped():
|
||||||
|
successCnt++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if successCnt > 0 && successCnt == len(css) {
|
||||||
|
return CommitStatusSuccess
|
||||||
|
}
|
||||||
|
return CommitStatusPending
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
// 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 CommitStatusState
|
||||||
|
}{
|
||||||
|
// 0 states
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
states: CommitStatusStates{},
|
||||||
|
expected: CommitStatusPending,
|
||||||
|
},
|
||||||
|
// 1 state
|
||||||
|
{
|
||||||
|
name: "pending",
|
||||||
|
states: CommitStatusStates{CommitStatusPending},
|
||||||
|
expected: CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess},
|
||||||
|
expected: CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error",
|
||||||
|
states: CommitStatusStates{CommitStatusError},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "failure",
|
||||||
|
states: CommitStatusStates{CommitStatusFailure},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "warning",
|
||||||
|
states: CommitStatusStates{CommitStatusWarning},
|
||||||
|
expected: CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
// 2 states
|
||||||
|
{
|
||||||
|
name: "pending and success",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess},
|
||||||
|
expected: CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending and error",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusError},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending and failure",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusFailure},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusWarning},
|
||||||
|
expected: CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success and error",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusError},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success and failure",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusFailure},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusWarning},
|
||||||
|
expected: CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error and failure",
|
||||||
|
states: CommitStatusStates{CommitStatusError, CommitStatusFailure},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusError, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "failure and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusFailure, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
// 3 states
|
||||||
|
{
|
||||||
|
name: "pending, success and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusWarning},
|
||||||
|
expected: CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending, success and error",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusError},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending, success and failure",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusFailure},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending, error and failure",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusError, CommitStatusFailure},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success, error and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusError, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success, failure and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusFailure, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error, failure and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusError, CommitStatusFailure, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success, warning and skipped",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusWarning, CommitStatusSkipped},
|
||||||
|
expected: CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
// All success
|
||||||
|
{
|
||||||
|
name: "all success",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusSuccess},
|
||||||
|
expected: CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
// All pending
|
||||||
|
{
|
||||||
|
name: "all pending",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusPending, CommitStatusPending},
|
||||||
|
expected: CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all skipped",
|
||||||
|
states: CommitStatusStates{CommitStatusSkipped, CommitStatusSkipped, CommitStatusSkipped},
|
||||||
|
expected: CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
// 4 states
|
||||||
|
{
|
||||||
|
name: "pending, success, error and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusError, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending, success, failure and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusFailure, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pending, error, failure and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusError, CommitStatusFailure, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "success, error, failure and warning",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusError, CommitStatusFailure, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed states",
|
||||||
|
states: CommitStatusStates{CommitStatusPending, CommitStatusSuccess, CommitStatusError, CommitStatusWarning},
|
||||||
|
expected: CommitStatusFailure,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed states with all success",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusPending, CommitStatusWarning},
|
||||||
|
expected: CommitStatusPending,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all success with warning",
|
||||||
|
states: CommitStatusStates{CommitStatusSuccess, CommitStatusSuccess, CommitStatusSuccess, CommitStatusWarning},
|
||||||
|
expected: CommitStatusSuccess,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +0,0 @@
|
||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package structs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNoBetterThan(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
s1, s2 CommitStatusState
|
|
||||||
higher bool
|
|
||||||
}{
|
|
||||||
{CommitStatusError, CommitStatusFailure, true},
|
|
||||||
{CommitStatusFailure, CommitStatusWarning, true},
|
|
||||||
{CommitStatusWarning, CommitStatusPending, true},
|
|
||||||
{CommitStatusPending, CommitStatusSuccess, true},
|
|
||||||
{CommitStatusSuccess, CommitStatusSkipped, true},
|
|
||||||
|
|
||||||
{CommitStatusError, "unknown-xxx", false},
|
|
||||||
{"unknown-xxx", CommitStatusFailure, true},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
assert.Equal(t, tt.higher, tt.s1.HasHigherPriorityThan(tt.s2), "s1=%s, s2=%s, expected=%v", tt.s1, tt.s2, tt.higher)
|
|
||||||
}
|
|
||||||
assert.False(t, CommitStatusError.HasHigherPriorityThan(CommitStatusError))
|
|
||||||
}
|
|
|
@ -5,12 +5,14 @@ package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/commitstatus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommitStatus holds a single status of a single Commit
|
// CommitStatus holds a single status of a single Commit
|
||||||
type CommitStatus struct {
|
type CommitStatus struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
State CommitStatusState `json:"status"`
|
State commitstatus.CommitStatusState `json:"status"`
|
||||||
TargetURL string `json:"target_url"`
|
TargetURL string `json:"target_url"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
|
@ -24,7 +26,7 @@ type CommitStatus struct {
|
||||||
|
|
||||||
// CombinedStatus holds the combined state of several statuses for a single commit
|
// CombinedStatus holds the combined state of several statuses for a single commit
|
||||||
type CombinedStatus struct {
|
type CombinedStatus struct {
|
||||||
State CommitStatusState `json:"state"`
|
State commitstatus.CommitStatusState `json:"state"`
|
||||||
SHA string `json:"sha"`
|
SHA string `json:"sha"`
|
||||||
TotalCount int `json:"total_count"`
|
TotalCount int `json:"total_count"`
|
||||||
Statuses []*CommitStatus `json:"statuses"`
|
Statuses []*CommitStatus `json:"statuses"`
|
||||||
|
@ -35,7 +37,7 @@ type CombinedStatus struct {
|
||||||
|
|
||||||
// CreateStatusOption holds the information needed to create a new CommitStatus for a Commit
|
// CreateStatusOption holds the information needed to create a new CommitStatus for a Commit
|
||||||
type CreateStatusOption struct {
|
type CreateStatusOption struct {
|
||||||
State CommitStatusState `json:"state"`
|
State commitstatus.CommitStatusState `json:"state"`
|
||||||
TargetURL string `json:"target_url"`
|
TargetURL string `json:"target_url"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Context string `json:"context"`
|
Context string `json:"context"`
|
||||||
|
|
|
@ -457,6 +457,9 @@ func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) ([]*git_m
|
||||||
}
|
}
|
||||||
if !ctx.Repo.CanRead(unit_model.TypeActions) {
|
if !ctx.Repo.CanRead(unit_model.TypeActions) {
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
|
if commit.Status == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
commit.Status.HideActionsURL(ctx)
|
commit.Status.HideActionsURL(ctx)
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
|
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
|
||||||
}
|
}
|
||||||
|
|
|
@ -757,6 +757,9 @@ func prepareIssueViewCommentsAndSidebarParticipants(ctx *context.Context, issue
|
||||||
}
|
}
|
||||||
if !ctx.Repo.CanRead(unit.TypeActions) {
|
if !ctx.Repo.CanRead(unit.TypeActions) {
|
||||||
for _, commit := range comment.Commits {
|
for _, commit := range comment.Commits {
|
||||||
|
if commit.Status == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
commit.Status.HideActionsURL(ctx)
|
commit.Status.HideActionsURL(ctx)
|
||||||
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
|
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ import (
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
actions_module "code.gitea.io/gitea/modules/actions"
|
actions_module "code.gitea.io/gitea/modules/actions"
|
||||||
|
"code.gitea.io/gitea/modules/commitstatus"
|
||||||
git "code.gitea.io/gitea/modules/git"
|
git "code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||||
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
|
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
|
||||||
|
|
||||||
|
@ -147,18 +147,18 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
|
||||||
return commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID.String(), &status)
|
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 {
|
switch status {
|
||||||
case actions_model.StatusSuccess:
|
case actions_model.StatusSuccess:
|
||||||
return api.CommitStatusSuccess
|
return commitstatus.CommitStatusSuccess
|
||||||
case actions_model.StatusFailure, actions_model.StatusCancelled:
|
case actions_model.StatusFailure, actions_model.StatusCancelled:
|
||||||
return api.CommitStatusFailure
|
return commitstatus.CommitStatusFailure
|
||||||
case actions_model.StatusWaiting, actions_model.StatusBlocked, actions_model.StatusRunning:
|
case actions_model.StatusWaiting, actions_model.StatusBlocked, actions_model.StatusRunning:
|
||||||
return api.CommitStatusPending
|
return commitstatus.CommitStatusPending
|
||||||
case actions_model.StatusSkipped:
|
case actions_model.StatusSkipped:
|
||||||
return api.CommitStatusSkipped
|
return commitstatus.CommitStatusSkipped
|
||||||
default:
|
default:
|
||||||
return api.CommitStatusError
|
return commitstatus.CommitStatusError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -32,39 +33,29 @@ func ToCommitStatus(ctx context.Context, status *git_model.CommitStatus) *api.Co
|
||||||
return apiStatus
|
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
|
// ToCombinedStatus converts List of CommitStatus to a CombinedStatus
|
||||||
func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, repo *api.Repository) *api.CombinedStatus {
|
func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, repo *api.Repository) *api.CombinedStatus {
|
||||||
if len(statuses) == 0 {
|
if len(statuses) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
retStatus := &api.CombinedStatus{
|
combinedStatus := git_model.CalcCommitStatus(statuses)
|
||||||
SHA: statuses[0].SHA,
|
|
||||||
|
return &api.CombinedStatus{
|
||||||
|
State: combinedStatus.State,
|
||||||
|
Statuses: ToCommitStatuses(ctx, statuses),
|
||||||
|
SHA: combinedStatus.SHA,
|
||||||
TotalCount: len(statuses),
|
TotalCount: len(statuses),
|
||||||
Repository: repo,
|
Repository: repo,
|
||||||
URL: "", // never set or used?
|
CommitURL: repo.URL + "/commits/" + url.PathEscape(combinedStatus.SHA),
|
||||||
State: api.CommitStatusSuccess,
|
URL: repo.URL + "/commits/" + url.PathEscape(combinedStatus.SHA) + "/status",
|
||||||
}
|
}
|
||||||
|
|
||||||
retStatus.Statuses = make([]*api.CommitStatus, 0, len(statuses))
|
|
||||||
for _, status := range statuses {
|
|
||||||
retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status))
|
|
||||||
if status.State.HasHigherPriorityThan(retStatus.State) {
|
|
||||||
retStatus.State = 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
|
|
||||||
switch retStatus.State {
|
|
||||||
case api.CommitStatusSkipped:
|
|
||||||
retStatus.State = api.CommitStatusSuccess // all skipped means success
|
|
||||||
case api.CommitStatusPending, api.CommitStatusSuccess:
|
|
||||||
// use the current state for pending or success
|
|
||||||
default:
|
|
||||||
retStatus.State = api.CommitStatusFailure // otherwise, it is a failure
|
|
||||||
}
|
|
||||||
return retStatus
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,21 +10,24 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
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/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MergeRequiredContextsCommitStatus returns a commit status state for given required contexts
|
// MergeRequiredContextsCommitStatus returns a commit status state for given required contexts
|
||||||
func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) structs.CommitStatusState {
|
func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, requiredContexts []string) commitstatus.CommitStatusState {
|
||||||
// matchedCount is the number of `CommitStatus.Context` that match any context of `requiredContexts`
|
if len(commitStatuses) == 0 {
|
||||||
matchedCount := 0
|
return commitstatus.CommitStatusPending
|
||||||
returnedStatus := structs.CommitStatusSuccess
|
}
|
||||||
|
|
||||||
|
if len(requiredContexts) == 0 {
|
||||||
|
return git_model.CalcCommitStatus(commitStatuses).State
|
||||||
|
}
|
||||||
|
|
||||||
if len(requiredContexts) > 0 {
|
|
||||||
requiredContextsGlob := make(map[string]glob.Glob, len(requiredContexts))
|
requiredContextsGlob := make(map[string]glob.Glob, len(requiredContexts))
|
||||||
for _, ctx := range requiredContexts {
|
for _, ctx := range requiredContexts {
|
||||||
if gp, err := glob.Compile(ctx); err != nil {
|
if gp, err := glob.Compile(ctx); err != nil {
|
||||||
|
@ -34,43 +37,29 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requiredCommitStatuses := make([]*git_model.CommitStatus, 0, len(commitStatuses))
|
||||||
for _, gp := range requiredContextsGlob {
|
for _, gp := range requiredContextsGlob {
|
||||||
var targetStatus structs.CommitStatusState
|
|
||||||
for _, commitStatus := range commitStatuses {
|
for _, commitStatus := range commitStatuses {
|
||||||
if gp.Match(commitStatus.Context) {
|
if gp.Match(commitStatus.Context) {
|
||||||
targetStatus = commitStatus.State
|
requiredCommitStatuses = append(requiredCommitStatuses, commitStatus)
|
||||||
matchedCount++
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If required rule not match any action, then it is pending
|
|
||||||
if targetStatus == "" {
|
|
||||||
if structs.CommitStatusPending.HasHigherPriorityThan(returnedStatus) {
|
|
||||||
returnedStatus = structs.CommitStatusPending
|
|
||||||
}
|
}
|
||||||
break
|
if len(requiredCommitStatuses) == 0 {
|
||||||
}
|
return commitstatus.CommitStatusPending
|
||||||
|
|
||||||
if targetStatus.HasHigherPriorityThan(returnedStatus) {
|
|
||||||
returnedStatus = targetStatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if matchedCount == 0 && returnedStatus == structs.CommitStatusSuccess {
|
|
||||||
if len(commitStatuses) == 0 {
|
|
||||||
// "no statuses" should mean "pending"
|
|
||||||
return structs.CommitStatusPending
|
|
||||||
}
|
|
||||||
status := git_model.CalcCommitStatus(commitStatuses)
|
|
||||||
if status.State == structs.CommitStatusSkipped {
|
|
||||||
return structs.CommitStatusSuccess // if all statuses are skipped, return success
|
|
||||||
}
|
|
||||||
return status.State
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
returnedStatus := git_model.CalcCommitStatus(requiredCommitStatuses).State
|
||||||
|
if len(requiredCommitStatuses) == len(requiredContexts) {
|
||||||
return returnedStatus
|
return returnedStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
if returnedStatus == commitstatus.CommitStatusFailure {
|
||||||
|
return commitstatus.CommitStatusFailure
|
||||||
|
}
|
||||||
|
// even if part of success, return pending
|
||||||
|
return commitstatus.CommitStatusPending
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPullCommitStatusPass returns if all required status checks PASS
|
// IsPullCommitStatusPass returns if all required status checks PASS
|
||||||
|
@ -91,7 +80,7 @@ func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPullRequestCommitStatusState returns pull request merged commit status state
|
// 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.CommitStatusState, error) {
|
||||||
// Ensure HeadRepo is loaded
|
// Ensure HeadRepo is loaded
|
||||||
if err := pr.LoadHeadRepo(ctx); err != nil {
|
if err := pr.LoadHeadRepo(ctx); err != nil {
|
||||||
return "", errors.Wrap(err, "LoadHeadRepo")
|
return "", errors.Wrap(err, "LoadHeadRepo")
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
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"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -17,64 +17,64 @@ func TestMergeRequiredContextsCommitStatus(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
commitStatuses []*git_model.CommitStatus
|
commitStatuses []*git_model.CommitStatus
|
||||||
requiredContexts []string
|
requiredContexts []string
|
||||||
expected structs.CommitStatusState
|
expected commitstatus.CommitStatusState
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
commitStatuses: []*git_model.CommitStatus{},
|
commitStatuses: []*git_model.CommitStatus{},
|
||||||
requiredContexts: []string{},
|
requiredContexts: []string{},
|
||||||
expected: structs.CommitStatusPending,
|
expected: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
commitStatuses: []*git_model.CommitStatus{
|
commitStatuses: []*git_model.CommitStatus{
|
||||||
{Context: "Build xxx", State: structs.CommitStatusSkipped},
|
{Context: "Build xxx", State: commitstatus.CommitStatusSkipped},
|
||||||
},
|
},
|
||||||
requiredContexts: []string{"Build*"},
|
requiredContexts: []string{"Build*"},
|
||||||
expected: structs.CommitStatusSuccess,
|
expected: commitstatus.CommitStatusSuccess,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
commitStatuses: []*git_model.CommitStatus{
|
commitStatuses: []*git_model.CommitStatus{
|
||||||
{Context: "Build 1", State: structs.CommitStatusSkipped},
|
{Context: "Build 1", State: commitstatus.CommitStatusSkipped},
|
||||||
{Context: "Build 2", State: structs.CommitStatusSuccess},
|
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 3", State: structs.CommitStatusSuccess},
|
{Context: "Build 3", State: commitstatus.CommitStatusSuccess},
|
||||||
},
|
},
|
||||||
requiredContexts: []string{"Build*"},
|
requiredContexts: []string{"Build*"},
|
||||||
expected: structs.CommitStatusSuccess,
|
expected: commitstatus.CommitStatusSuccess,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
commitStatuses: []*git_model.CommitStatus{
|
commitStatuses: []*git_model.CommitStatus{
|
||||||
{Context: "Build 1", State: structs.CommitStatusSuccess},
|
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2", State: structs.CommitStatusSuccess},
|
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2t", State: structs.CommitStatusPending},
|
{Context: "Build 2t", State: commitstatus.CommitStatusPending},
|
||||||
},
|
},
|
||||||
requiredContexts: []string{"Build*", "Build 2t*"},
|
requiredContexts: []string{"Build*", "Build 2t*"},
|
||||||
expected: structs.CommitStatusPending,
|
expected: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
commitStatuses: []*git_model.CommitStatus{
|
commitStatuses: []*git_model.CommitStatus{
|
||||||
{Context: "Build 1", State: structs.CommitStatusSuccess},
|
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2", State: structs.CommitStatusSuccess},
|
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2t", State: structs.CommitStatusFailure},
|
{Context: "Build 2t", State: commitstatus.CommitStatusFailure},
|
||||||
},
|
},
|
||||||
requiredContexts: []string{"Build*", "Build 2t*"},
|
requiredContexts: []string{"Build*", "Build 2t*"},
|
||||||
expected: structs.CommitStatusFailure,
|
expected: commitstatus.CommitStatusFailure,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
commitStatuses: []*git_model.CommitStatus{
|
commitStatuses: []*git_model.CommitStatus{
|
||||||
{Context: "Build 1", State: structs.CommitStatusSuccess},
|
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2", State: structs.CommitStatusSuccess},
|
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2t", State: structs.CommitStatusSuccess},
|
{Context: "Build 2t", State: commitstatus.CommitStatusSuccess},
|
||||||
},
|
},
|
||||||
requiredContexts: []string{"Build*", "Build 2t*", "Build 3*"},
|
requiredContexts: []string{"Build*", "Build 2t*", "Build 3*"},
|
||||||
expected: structs.CommitStatusPending,
|
expected: commitstatus.CommitStatusPending,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
commitStatuses: []*git_model.CommitStatus{
|
commitStatuses: []*git_model.CommitStatus{
|
||||||
{Context: "Build 1", State: structs.CommitStatusSuccess},
|
{Context: "Build 1", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2", State: structs.CommitStatusSuccess},
|
{Context: "Build 2", State: commitstatus.CommitStatusSuccess},
|
||||||
{Context: "Build 2t", State: structs.CommitStatusSuccess},
|
{Context: "Build 2t", State: commitstatus.CommitStatusSuccess},
|
||||||
},
|
},
|
||||||
requiredContexts: []string{"Build*", "Build *", "Build 2t*", "Build 1*"},
|
requiredContexts: []string{"Build*", "Build *", "Build 2t*", "Build 1*"},
|
||||||
expected: structs.CommitStatusSuccess,
|
expected: commitstatus.CommitStatusSuccess,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, c := range cases {
|
for i, c := range cases {
|
||||||
|
|
|
@ -14,12 +14,12 @@ import (
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
|
"code.gitea.io/gitea/modules/commitstatus"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
|
||||||
"code.gitea.io/gitea/services/notify"
|
"code.gitea.io/gitea/services/notify"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheVal
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateCommitStatusCache(repoID int64, branchName string, state api.CommitStatusState, targetURL string) error {
|
func updateCommitStatusCache(repoID int64, branchName string, state commitstatus.CommitStatusState, targetURL string) error {
|
||||||
c := cache.GetCache()
|
c := cache.GetCache()
|
||||||
bs, err := json.Marshal(commitStatusCacheValue{
|
bs, err := json.Marshal(commitStatusCacheValue{
|
||||||
State: state.String(),
|
State: state.String(),
|
||||||
|
@ -127,7 +127,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep
|
||||||
for i, repo := range repos {
|
for i, repo := range repos {
|
||||||
if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil {
|
if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil {
|
||||||
results[i] = &git_model.CommitStatus{
|
results[i] = &git_model.CommitStatus{
|
||||||
State: api.CommitStatusState(cv.State),
|
State: commitstatus.CommitStatusState(cv.State),
|
||||||
TargetURL: cv.TargetURL,
|
TargetURL: cv.TargetURL,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -21030,7 +21030,17 @@
|
||||||
"x-go-name": "SHA"
|
"x-go-name": "SHA"
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"$ref": "#/definitions/CommitStatusState"
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"pending",
|
||||||
|
"success",
|
||||||
|
"error",
|
||||||
|
"failure",
|
||||||
|
"warning",
|
||||||
|
"skipped"
|
||||||
|
],
|
||||||
|
"x-go-enum-desc": "pending CommitStatusPending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped CommitStatusSkipped is for when CommitStatus is Skipped",
|
||||||
|
"x-go-name": "State"
|
||||||
},
|
},
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -21258,7 +21268,17 @@
|
||||||
"x-go-name": "ID"
|
"x-go-name": "ID"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"$ref": "#/definitions/CommitStatusState"
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"pending",
|
||||||
|
"success",
|
||||||
|
"error",
|
||||||
|
"failure",
|
||||||
|
"warning",
|
||||||
|
"skipped"
|
||||||
|
],
|
||||||
|
"x-go-enum-desc": "pending CommitStatusPending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped CommitStatusSkipped is for when CommitStatus is Skipped",
|
||||||
|
"x-go-name": "State"
|
||||||
},
|
},
|
||||||
"target_url": {
|
"target_url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -21276,11 +21296,6 @@
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
||||||
},
|
},
|
||||||
"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"
|
|
||||||
},
|
|
||||||
"CommitUser": {
|
"CommitUser": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "CommitUser contains information of a user in the context of a commit.",
|
"title": "CommitUser contains information of a user in the context of a commit.",
|
||||||
|
@ -22329,7 +22344,17 @@
|
||||||
"x-go-name": "Description"
|
"x-go-name": "Description"
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"$ref": "#/definitions/CommitStatusState"
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"pending",
|
||||||
|
"success",
|
||||||
|
"error",
|
||||||
|
"failure",
|
||||||
|
"warning",
|
||||||
|
"skipped"
|
||||||
|
],
|
||||||
|
"x-go-enum-desc": "pending CommitStatusPending CommitStatusPending is for when the CommitStatus is Pending\nsuccess CommitStatusSuccess CommitStatusSuccess is for when the CommitStatus is Success\nerror CommitStatusError CommitStatusError is for when the CommitStatus is Error\nfailure CommitStatusFailure CommitStatusFailure is for when the CommitStatus is Failure\nwarning CommitStatusWarning CommitStatusWarning is for when the CommitStatus is Warning\nskipped CommitStatusSkipped CommitStatusSkipped is for when CommitStatus is Skipped",
|
||||||
|
"x-go-name": "State"
|
||||||
},
|
},
|
||||||
"target_url": {
|
"target_url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
actions_module "code.gitea.io/gitea/modules/actions"
|
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/git"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
@ -638,7 +639,7 @@ jobs:
|
||||||
if len(latestCommitStatuses) == 0 {
|
if len(latestCommitStatuses) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if latestCommitStatuses[0].State == api.CommitStatusPending {
|
if latestCommitStatuses[0].State == commitstatus.CommitStatusPending {
|
||||||
insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context)
|
insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context)
|
||||||
return true
|
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)
|
latestCommitStatuses, err := git_model.GetLatestCommitStatus(db.DefaultContext, repo.ID, sha, db.ListOptionsAll)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, latestCommitStatuses, 1)
|
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)
|
insertFakeStatus(t, repo, sha, latestCommitStatuses[0].TargetURL, latestCommitStatuses[0].Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertFakeStatus(t *testing.T, repo *repo_model.Repository, sha, targetURL, context string) {
|
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{
|
err := commitstatus_service.CreateCommitStatus(db.DefaultContext, repo, user_model.NewActionsUser(), sha, &git_model.CommitStatus{
|
||||||
State: api.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: targetURL,
|
TargetURL: targetURL,
|
||||||
Context: context,
|
Context: context,
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
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/git"
|
||||||
"code.gitea.io/gitea/modules/lfs"
|
"code.gitea.io/gitea/modules/lfs"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -713,7 +714,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
|
||||||
|
|
||||||
commitID := path.Base(commitURL)
|
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{
|
return doAPICreateCommitStatus(ctx, commitID, api.CreateStatusOption{
|
||||||
State: status,
|
State: status,
|
||||||
TargetURL: "http://test.ci/",
|
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
|
// 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
|
// Cancel not existing auto merge
|
||||||
ctx.ExpectedCode = http.StatusNotFound
|
ctx.ExpectedCode = http.StatusNotFound
|
||||||
|
@ -752,7 +753,7 @@ func doAutoPRMerge(baseCtx *APITestContext, dstPath string) func(t *testing.T) {
|
||||||
assert.False(t, pr.HasMerged)
|
assert.False(t, pr.HasMerged)
|
||||||
|
|
||||||
// Call API to add Failure status for commit
|
// Call API to add Failure status for commit
|
||||||
t.Run("CreateStatus", addCommitStatus(api.CommitStatusFailure))
|
t.Run("CreateStatus", addCommitStatus(commitstatus.CommitStatusFailure))
|
||||||
|
|
||||||
// Check pr status
|
// Check pr status
|
||||||
pr, err = doAPIGetPullRequest(ctx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
|
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)
|
assert.False(t, pr.HasMerged)
|
||||||
|
|
||||||
// Call API to add Success status for commit
|
// 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
|
// wait to let gitea merge stuff
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/models/webhook"
|
"code.gitea.io/gitea/models/webhook"
|
||||||
|
"code.gitea.io/gitea/modules/commitstatus"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/queue"
|
"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{
|
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
|
||||||
State: api.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: "https://gitea.com",
|
TargetURL: "https://gitea.com",
|
||||||
Context: "gitea/actions",
|
Context: "gitea/actions",
|
||||||
})
|
})
|
||||||
|
@ -848,7 +849,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
|
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
|
||||||
State: api.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: "https://gitea.com",
|
TargetURL: "https://gitea.com",
|
||||||
Context: "gitea/actions",
|
Context: "gitea/actions",
|
||||||
})
|
})
|
||||||
|
@ -977,7 +978,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
|
err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
|
||||||
State: api.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: "https://gitea.com",
|
TargetURL: "https://gitea.com",
|
||||||
Context: "gitea/actions",
|
Context: "gitea/actions",
|
||||||
})
|
})
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/issues"
|
"code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
"code.gitea.io/gitea/modules/commitstatus"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
@ -55,20 +56,20 @@ func TestPullCreate_CommitStatus(t *testing.T) {
|
||||||
|
|
||||||
commitID := path.Base(commitURL)
|
commitID := path.Base(commitURL)
|
||||||
|
|
||||||
statusList := []api.CommitStatusState{
|
statusList := []commitstatus.CommitStatusState{
|
||||||
api.CommitStatusPending,
|
commitstatus.CommitStatusPending,
|
||||||
api.CommitStatusError,
|
commitstatus.CommitStatusError,
|
||||||
api.CommitStatusFailure,
|
commitstatus.CommitStatusFailure,
|
||||||
api.CommitStatusSuccess,
|
commitstatus.CommitStatusSuccess,
|
||||||
api.CommitStatusWarning,
|
commitstatus.CommitStatusWarning,
|
||||||
}
|
}
|
||||||
|
|
||||||
statesIcons := map[api.CommitStatusState]string{
|
statesIcons := map[commitstatus.CommitStatusState]string{
|
||||||
api.CommitStatusPending: "octicon-dot-fill",
|
commitstatus.CommitStatusPending: "octicon-dot-fill",
|
||||||
api.CommitStatusSuccess: "octicon-check",
|
commitstatus.CommitStatusSuccess: "octicon-check",
|
||||||
api.CommitStatusError: "gitea-exclamation",
|
commitstatus.CommitStatusError: "gitea-exclamation",
|
||||||
api.CommitStatusFailure: "octicon-x",
|
commitstatus.CommitStatusFailure: "octicon-x",
|
||||||
api.CommitStatusWarning: "gitea-exclamation",
|
commitstatus.CommitStatusWarning: "gitea-exclamation",
|
||||||
}
|
}
|
||||||
|
|
||||||
testCtx := NewAPITestContext(t, "user1", "repo1", auth_model.AccessTokenScopeWriteRepository)
|
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"})
|
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.CommitStatusSummary{RepoID: repo1.ID, SHA: commitID})
|
||||||
assert.Equal(t, api.CommitStatusWarning, css.State)
|
assert.Equal(t, commitstatus.CommitStatusSuccess, css.State)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
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/json"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
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
|
// Call API to add status for commit
|
||||||
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
|
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
|
||||||
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
||||||
State: api.CommitStatusState(state),
|
State: commitstatus.CommitStatusState(state),
|
||||||
TargetURL: "http://test.ci/",
|
TargetURL: "http://test.ci/",
|
||||||
Description: "",
|
Description: "",
|
||||||
Context: "testci",
|
Context: "testci",
|
||||||
|
@ -120,7 +121,7 @@ func testRepoCommitsWithStatus(t *testing.T, resp, respOne *httptest.ResponseRec
|
||||||
assert.NotNil(t, status)
|
assert.NotNil(t, status)
|
||||||
|
|
||||||
if assert.Len(t, statuses, 1) {
|
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, setting.AppURL+"api/v1/repos/user2/repo1/statuses/65f1bf27bc3bf70f64657658635e66094edbcb4d", statuses[0].URL)
|
||||||
assert.Equal(t, "http://test.ci/", statuses[0].TargetURL)
|
assert.Equal(t, "http://test.ci/", statuses[0].TargetURL)
|
||||||
assert.Empty(t, statuses[0].Description)
|
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) {
|
parentT.Run(fmt.Sprintf("ParallelCreateStatus_%d", i), func(t *testing.T) {
|
||||||
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
|
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
|
||||||
runBody := doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
runBody := doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
||||||
State: api.CommitStatusPending,
|
State: commitstatus.CommitStatusPending,
|
||||||
TargetURL: "http://test.ci/",
|
TargetURL: "http://test.ci/",
|
||||||
Description: "",
|
Description: "",
|
||||||
Context: "testci",
|
Context: "testci",
|
||||||
|
@ -205,14 +206,14 @@ func TestRepoCommitsStatusMultiple(t *testing.T) {
|
||||||
// Call API to add status for commit
|
// Call API to add status for commit
|
||||||
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
|
ctx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository)
|
||||||
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
||||||
State: api.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: "http://test.ci/",
|
TargetURL: "http://test.ci/",
|
||||||
Description: "",
|
Description: "",
|
||||||
Context: "testci",
|
Context: "testci",
|
||||||
}))
|
}))
|
||||||
|
|
||||||
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
t.Run("CreateStatus", doAPICreateCommitStatus(ctx, path.Base(commitURL), api.CreateStatusOption{
|
||||||
State: api.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: "http://test.ci/",
|
TargetURL: "http://test.ci/",
|
||||||
Description: "",
|
Description: "",
|
||||||
Context: "other_context",
|
Context: "other_context",
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/models/webhook"
|
"code.gitea.io/gitea/models/webhook"
|
||||||
|
"code.gitea.io/gitea/modules/commitstatus"
|
||||||
"code.gitea.io/gitea/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -770,7 +771,7 @@ func Test_WebhookStatus(t *testing.T) {
|
||||||
|
|
||||||
// update a status for a commit via API
|
// update a status for a commit via API
|
||||||
doAPICreateCommitStatus(testCtx, commitID, api.CreateStatusOption{
|
doAPICreateCommitStatus(testCtx, commitID, api.CreateStatusOption{
|
||||||
State: api.CommitStatusSuccess,
|
State: commitstatus.CommitStatusSuccess,
|
||||||
TargetURL: "http://test.ci/",
|
TargetURL: "http://test.ci/",
|
||||||
Description: "",
|
Description: "",
|
||||||
Context: "testci",
|
Context: "testci",
|
||||||
|
|
Loading…
Reference in New Issue