mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	Fix actions skipped commit status indicator (#34507)
Addresses https://github.com/go-gitea/gitea/issues/34500 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -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 | // 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. | ||||||
|  | 	// 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 | 	var lastStatus *CommitStatus | ||||||
| 	state := api.CommitStatusSuccess | 	state := api.CommitStatusSuccess | ||||||
| 	for _, status := range statuses { | 	for _, status := range statuses { | ||||||
| 		if status.State.NoBetterThan(state) { | 		if state == status.State || status.State.HasHigherPriorityThan(state) { | ||||||
| 			state = status.State | 			state = status.State | ||||||
| 			lastStatus = status | 			lastStatus = status | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if lastStatus == nil { | 	if lastStatus == nil { | ||||||
| 		if len(statuses) > 0 { | 		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] | 			lastStatus = statuses[0] | ||||||
| 		} else { | 		} 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{} | 			lastStatus = &CommitStatus{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -59,7 +59,11 @@ func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) er | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		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, | 	// 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 | 	// so we need to use insert in on duplicate | ||||||
| 	if setting.Database.Type.IsMySQL() { | 	if setting.Database.Type.IsMySQL() { | ||||||
|   | |||||||
| @@ -18,6 +18,8 @@ const ( | |||||||
| 	CommitStatusFailure CommitStatusState = "failure" | 	CommitStatusFailure CommitStatusState = "failure" | ||||||
| 	// CommitStatusWarning is for when the CommitStatus is Warning | 	// CommitStatusWarning is for when the CommitStatus is Warning | ||||||
| 	CommitStatusWarning CommitStatusState = "warning" | 	CommitStatusWarning CommitStatusState = "warning" | ||||||
|  | 	// CommitStatusSkipped is for when CommitStatus is Skipped | ||||||
|  | 	CommitStatusSkipped CommitStatusState = "skipped" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var commitStatusPriorities = map[CommitStatusState]int{ | var commitStatusPriorities = map[CommitStatusState]int{ | ||||||
| @@ -26,25 +28,17 @@ var commitStatusPriorities = map[CommitStatusState]int{ | |||||||
| 	CommitStatusWarning: 2, | 	CommitStatusWarning: 2, | ||||||
| 	CommitStatusPending: 3, | 	CommitStatusPending: 3, | ||||||
| 	CommitStatusSuccess: 4, | 	CommitStatusSuccess: 4, | ||||||
|  | 	CommitStatusSkipped: 5, | ||||||
| } | } | ||||||
|  |  | ||||||
| func (css CommitStatusState) String() string { | func (css CommitStatusState) String() string { | ||||||
| 	return string(css) | 	return string(css) | ||||||
| } | } | ||||||
|  |  | ||||||
| // NoBetterThan returns true if this State is no better than the given State | // HasHigherPriorityThan returns true if this state has higher priority than the other | ||||||
| // This function only handles the states defined in CommitStatusPriorities | // Undefined states are considered to have the highest priority like CommitStatusError(0) | ||||||
| func (css CommitStatusState) NoBetterThan(css2 CommitStatusState) bool { | func (css CommitStatusState) HasHigherPriorityThan(other CommitStatusState) bool { | ||||||
| 	// NoBetterThan only handles the 5 states above | 	return commitStatusPriorities[css] < commitStatusPriorities[other] | ||||||
| 	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 | // IsPending represents if commit status state is pending | ||||||
|   | |||||||
| @@ -10,165 +10,21 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestNoBetterThan(t *testing.T) { | func TestNoBetterThan(t *testing.T) { | ||||||
| 	type args struct { |  | ||||||
| 		css  CommitStatusState |  | ||||||
| 		css2 CommitStatusState |  | ||||||
| 	} |  | ||||||
| 	var unExpectedState CommitStatusState |  | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| 		name string | 		s1, s2 CommitStatusState | ||||||
| 		args args | 		higher bool | ||||||
| 		want bool |  | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{CommitStatusError, CommitStatusFailure, true}, | ||||||
| 			name: "success is no better than success", | 		{CommitStatusFailure, CommitStatusWarning, true}, | ||||||
| 			args: args{ | 		{CommitStatusWarning, CommitStatusPending, true}, | ||||||
| 				css:  CommitStatusSuccess, | 		{CommitStatusPending, CommitStatusSuccess, true}, | ||||||
| 				css2: CommitStatusSuccess, | 		{CommitStatusSuccess, CommitStatusSkipped, true}, | ||||||
| 			}, |  | ||||||
| 			want: true, | 		{CommitStatusError, "unknown-xxx", false}, | ||||||
| 		}, | 		{"unknown-xxx", CommitStatusFailure, 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 { | 	for _, tt := range tests { | ||||||
| 		t.Run(tt.name, func(t *testing.T) { | 		assert.Equal(t, tt.higher, tt.s1.HasHigherPriorityThan(tt.s2), "s1=%s, s2=%s, expected=%v", tt.s1, tt.s2, tt.higher) | ||||||
| 			result := tt.args.css.NoBetterThan(tt.args.css2) |  | ||||||
| 			assert.Equal(t, tt.want, result) |  | ||||||
| 		}) |  | ||||||
| 	} | 	} | ||||||
|  | 	assert.False(t, CommitStatusError.HasHigherPriorityThan(CommitStatusError)) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -149,12 +149,14 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er | |||||||
|  |  | ||||||
| func toCommitStatus(status actions_model.Status) api.CommitStatusState { | func toCommitStatus(status actions_model.Status) api.CommitStatusState { | ||||||
| 	switch status { | 	switch status { | ||||||
| 	case actions_model.StatusSuccess, actions_model.StatusSkipped: | 	case actions_model.StatusSuccess: | ||||||
| 		return api.CommitStatusSuccess | 		return api.CommitStatusSuccess | ||||||
| 	case actions_model.StatusFailure, actions_model.StatusCancelled: | 	case actions_model.StatusFailure, actions_model.StatusCancelled: | ||||||
| 		return api.CommitStatusFailure | 		return api.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 api.CommitStatusPending | ||||||
|  | 	case actions_model.StatusSkipped: | ||||||
|  | 		return api.CommitStatusSkipped | ||||||
| 	default: | 	default: | ||||||
| 		return api.CommitStatusError | 		return api.CommitStatusError | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -42,13 +42,14 @@ func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, r | |||||||
| 		SHA:        statuses[0].SHA, | 		SHA:        statuses[0].SHA, | ||||||
| 		TotalCount: len(statuses), | 		TotalCount: len(statuses), | ||||||
| 		Repository: repo, | 		Repository: repo, | ||||||
| 		URL:        "", | 		URL:        "", // never set or used? | ||||||
|  | 		State:      api.CommitStatusSuccess, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	retStatus.Statuses = make([]*api.CommitStatus, 0, len(statuses)) | 	retStatus.Statuses = make([]*api.CommitStatus, 0, len(statuses)) | ||||||
| 	for _, status := range statuses { | 	for _, status := range statuses { | ||||||
| 		retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status)) | 		retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status)) | ||||||
| 		if retStatus.State == "" || status.State.NoBetterThan(retStatus.State) { | 		if status.State.HasHigherPriorityThan(retStatus.State) { | ||||||
| 			retStatus.State = status.State | 			retStatus.State = status.State | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -57,9 +58,13 @@ func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, r | |||||||
| 	// > failure if any of the contexts report as error or failure | 	// > failure if any of the contexts report as error or failure | ||||||
| 	// > pending if there are no statuses or a context is pending | 	// > pending if there are no statuses or a context is pending | ||||||
| 	// > success if the latest status for all contexts is success | 	// > success if the latest status for all contexts is success | ||||||
| 	if retStatus.State.IsError() { | 	switch retStatus.State { | ||||||
| 		retStatus.State = api.CommitStatusFailure | 	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 | 	return retStatus | ||||||
| } | } | ||||||
|   | |||||||
| @@ -46,59 +46,33 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus, | |||||||
|  |  | ||||||
| 			// If required rule not match any action, then it is pending | 			// If required rule not match any action, then it is pending | ||||||
| 			if targetStatus == "" { | 			if targetStatus == "" { | ||||||
| 				if structs.CommitStatusPending.NoBetterThan(returnedStatus) { | 				if structs.CommitStatusPending.HasHigherPriorityThan(returnedStatus) { | ||||||
| 					returnedStatus = structs.CommitStatusPending | 					returnedStatus = structs.CommitStatusPending | ||||||
| 				} | 				} | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if targetStatus.NoBetterThan(returnedStatus) { | 			if targetStatus.HasHigherPriorityThan(returnedStatus) { | ||||||
| 				returnedStatus = targetStatus | 				returnedStatus = targetStatus | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if matchedCount == 0 && returnedStatus == structs.CommitStatusSuccess { | 	if matchedCount == 0 && returnedStatus == structs.CommitStatusSuccess { | ||||||
| 		status := git_model.CalcCommitStatus(commitStatuses) | 		if len(commitStatuses) == 0 { | ||||||
| 		if status != nil { | 			// "no statuses" should mean "pending" | ||||||
| 			return status.State | 			return structs.CommitStatusPending | ||||||
| 		} | 		} | ||||||
| 		return structs.CommitStatusSuccess | 		status := git_model.CalcCommitStatus(commitStatuses) | ||||||
|  | 		if status.State == structs.CommitStatusSkipped { | ||||||
|  | 			return structs.CommitStatusSuccess // if all statuses are skipped, return success | ||||||
|  | 		} | ||||||
|  | 		return status.State | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return returnedStatus | 	return returnedStatus | ||||||
| } | } | ||||||
|  |  | ||||||
| // 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 |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, ctx := range requiredContexts { |  | ||||||
| 		var found bool |  | ||||||
| 		for _, commitStatus := range commitStatuses { |  | ||||||
| 			if commitStatus.Context == ctx { |  | ||||||
| 				if commitStatus.State != structs.CommitStatusSuccess { |  | ||||||
| 					return false |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				found = true |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if !found { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // IsPullCommitStatusPass returns if all required status checks PASS | // IsPullCommitStatusPass returns if all required status checks PASS | ||||||
| func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) (bool, error) { | func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) (bool, error) { | ||||||
| 	pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) | 	pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) | ||||||
|   | |||||||
| @@ -14,52 +14,70 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestMergeRequiredContextsCommitStatus(t *testing.T) { | func TestMergeRequiredContextsCommitStatus(t *testing.T) { | ||||||
| 	testCases := [][]*git_model.CommitStatus{ | 	cases := []struct { | ||||||
|  | 		commitStatuses   []*git_model.CommitStatus | ||||||
|  | 		requiredContexts []string | ||||||
|  | 		expected         structs.CommitStatusState | ||||||
|  | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			{Context: "Build 1", State: structs.CommitStatusSuccess}, | 			commitStatuses:   []*git_model.CommitStatus{}, | ||||||
| 			{Context: "Build 2", State: structs.CommitStatusSuccess}, | 			requiredContexts: []string{}, | ||||||
| 			{Context: "Build 3", State: structs.CommitStatusSuccess}, | 			expected:         structs.CommitStatusPending, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			{Context: "Build 1", State: structs.CommitStatusSuccess}, | 			commitStatuses: []*git_model.CommitStatus{ | ||||||
| 			{Context: "Build 2", State: structs.CommitStatusSuccess}, | 				{Context: "Build xxx", State: structs.CommitStatusSkipped}, | ||||||
| 			{Context: "Build 2t", State: structs.CommitStatusPending}, | 			}, | ||||||
|  | 			requiredContexts: []string{"Build*"}, | ||||||
|  | 			expected:         structs.CommitStatusSuccess, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			{Context: "Build 1", State: structs.CommitStatusSuccess}, | 			commitStatuses: []*git_model.CommitStatus{ | ||||||
| 			{Context: "Build 2", State: structs.CommitStatusSuccess}, | 				{Context: "Build 1", State: structs.CommitStatusSkipped}, | ||||||
| 			{Context: "Build 2t", State: structs.CommitStatusFailure}, | 				{Context: "Build 2", State: structs.CommitStatusSuccess}, | ||||||
|  | 				{Context: "Build 3", State: structs.CommitStatusSuccess}, | ||||||
|  | 			}, | ||||||
|  | 			requiredContexts: []string{"Build*"}, | ||||||
|  | 			expected:         structs.CommitStatusSuccess, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			{Context: "Build 1", State: structs.CommitStatusSuccess}, | 			commitStatuses: []*git_model.CommitStatus{ | ||||||
| 			{Context: "Build 2", State: structs.CommitStatusSuccess}, | 				{Context: "Build 1", State: structs.CommitStatusSuccess}, | ||||||
| 			{Context: "Build 2t", State: structs.CommitStatusSuccess}, | 				{Context: "Build 2", State: structs.CommitStatusSuccess}, | ||||||
|  | 				{Context: "Build 2t", State: structs.CommitStatusPending}, | ||||||
|  | 			}, | ||||||
|  | 			requiredContexts: []string{"Build*", "Build 2t*"}, | ||||||
|  | 			expected:         structs.CommitStatusPending, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			{Context: "Build 1", State: structs.CommitStatusSuccess}, | 			commitStatuses: []*git_model.CommitStatus{ | ||||||
| 			{Context: "Build 2", State: structs.CommitStatusSuccess}, | 				{Context: "Build 1", State: structs.CommitStatusSuccess}, | ||||||
| 			{Context: "Build 2t", State: structs.CommitStatusSuccess}, | 				{Context: "Build 2", State: structs.CommitStatusSuccess}, | ||||||
|  | 				{Context: "Build 2t", State: structs.CommitStatusFailure}, | ||||||
|  | 			}, | ||||||
|  | 			requiredContexts: []string{"Build*", "Build 2t*"}, | ||||||
|  | 			expected:         structs.CommitStatusFailure, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			commitStatuses: []*git_model.CommitStatus{ | ||||||
|  | 				{Context: "Build 1", State: structs.CommitStatusSuccess}, | ||||||
|  | 				{Context: "Build 2", State: structs.CommitStatusSuccess}, | ||||||
|  | 				{Context: "Build 2t", State: structs.CommitStatusSuccess}, | ||||||
|  | 			}, | ||||||
|  | 			requiredContexts: []string{"Build*", "Build 2t*", "Build 3*"}, | ||||||
|  | 			expected:         structs.CommitStatusPending, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			commitStatuses: []*git_model.CommitStatus{ | ||||||
|  | 				{Context: "Build 1", State: structs.CommitStatusSuccess}, | ||||||
|  | 				{Context: "Build 2", State: structs.CommitStatusSuccess}, | ||||||
|  | 				{Context: "Build 2t", State: structs.CommitStatusSuccess}, | ||||||
|  | 			}, | ||||||
|  | 			requiredContexts: []string{"Build*", "Build *", "Build 2t*", "Build 1*"}, | ||||||
|  | 			expected:         structs.CommitStatusSuccess, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	testCasesRequiredContexts := [][]string{ | 	for i, c := range cases { | ||||||
| 		{"Build*"}, | 		assert.Equal(t, c.expected, MergeRequiredContextsCommitStatus(c.commitStatuses, c.requiredContexts), "case %d", i) | ||||||
| 		{"Build*", "Build 2t*"}, |  | ||||||
| 		{"Build*", "Build 2t*"}, |  | ||||||
| 		{"Build*", "Build 2t*", "Build 3*"}, |  | ||||||
| 		{"Build*", "Build *", "Build 2t*", "Build 1*"}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	testCasesExpected := []structs.CommitStatusState{ |  | ||||||
| 		structs.CommitStatusSuccess, |  | ||||||
| 		structs.CommitStatusPending, |  | ||||||
| 		structs.CommitStatusFailure, |  | ||||||
| 		structs.CommitStatusPending, |  | ||||||
| 		structs.CommitStatusSuccess, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for i, commitStatuses := range testCases { |  | ||||||
| 		if MergeRequiredContextsCommitStatus(commitStatuses, testCasesRequiredContexts[i]) != testCasesExpected[i] { |  | ||||||
| 			assert.Fail(t, "Test case failed", "Test case %d failed", i+1) |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -14,3 +14,6 @@ | |||||||
| {{if eq .State "warning"}} | {{if eq .State "warning"}} | ||||||
| 	{{svg "gitea-exclamation" 18 "commit-status icon text yellow"}} | 	{{svg "gitea-exclamation" 18 "commit-status icon text yellow"}} | ||||||
| {{end}} | {{end}} | ||||||
|  | {{if eq .State "skipped"}} | ||||||
|  | 	{{svg "octicon-skip" 18 "commit-status icon text grey"}} | ||||||
|  | {{end}} | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import {fomanticQuery} from '../modules/fomantic/base.ts'; | |||||||
|  |  | ||||||
| const {appSubUrl, assetUrlPrefix, pageData} = window.config; | const {appSubUrl, assetUrlPrefix, pageData} = window.config; | ||||||
|  |  | ||||||
| type CommitStatus = 'pending' | 'success' | 'error' | 'failure' | 'warning'; | type CommitStatus = 'pending' | 'success' | 'error' | 'failure' | 'warning' | 'skipped'; | ||||||
|  |  | ||||||
| type CommitStatusMap = { | type CommitStatusMap = { | ||||||
|   [status in CommitStatus]: { |   [status in CommitStatus]: { | ||||||
| @@ -22,6 +22,7 @@ const commitStatus: CommitStatusMap = { | |||||||
|   error: {name: 'gitea-exclamation', color: 'red'}, |   error: {name: 'gitea-exclamation', color: 'red'}, | ||||||
|   failure: {name: 'octicon-x', color: 'red'}, |   failure: {name: 'octicon-x', color: 'red'}, | ||||||
|   warning: {name: 'gitea-exclamation', color: 'yellow'}, |   warning: {name: 'gitea-exclamation', color: 'yellow'}, | ||||||
|  |   skipped: {name: 'octicon-skip', color: 'grey'}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user