0
0
mirror of https://github.com/go-gitea/gitea.git synced 2025-07-21 16:45:03 +02:00

Add running with falure status

This commit is contained in:
Lunny Xiao 2025-07-09 15:37:17 -07:00
parent 1e86b7dad0
commit 4350e0d51e
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
12 changed files with 68 additions and 22 deletions

View File

@ -186,6 +186,9 @@ func AggregateJobStatus(jobs []*ActionRunJob) Status {
case hasCancelled: case hasCancelled:
return StatusCancelled return StatusCancelled
case hasRunning: case hasRunning:
if hasFailure {
return StatusRunningWithFailure
}
return StatusRunning return StatusRunning
case hasFailure: case hasFailure:
return StatusFailure return StatusFailure

View File

@ -65,7 +65,7 @@ func TestAggregateJobStatus(t *testing.T) {
{[]Status{StatusFailure, StatusSkipped}, StatusFailure}, {[]Status{StatusFailure, StatusSkipped}, StatusFailure},
{[]Status{StatusFailure, StatusCancelled}, StatusCancelled}, {[]Status{StatusFailure, StatusCancelled}, StatusCancelled},
{[]Status{StatusFailure, StatusWaiting}, StatusFailure}, {[]Status{StatusFailure, StatusWaiting}, StatusFailure},
{[]Status{StatusFailure, StatusRunning}, StatusRunning}, {[]Status{StatusFailure, StatusRunning}, StatusRunningWithFailure},
{[]Status{StatusFailure, StatusBlocked}, StatusFailure}, {[]Status{StatusFailure, StatusBlocked}, StatusFailure},
// skipped with other status // skipped with other status

View File

@ -23,6 +23,7 @@ const (
StatusWaiting // 5, isn't a runnerv1.Result StatusWaiting // 5, isn't a runnerv1.Result
StatusRunning // 6, isn't a runnerv1.Result StatusRunning // 6, isn't a runnerv1.Result
StatusBlocked // 7, isn't a runnerv1.Result StatusBlocked // 7, isn't a runnerv1.Result
StatusRunningWithFailure // 8, isn't a runnerv1.Result, used for aggregated status
) )
var statusNames = map[Status]string{ var statusNames = map[Status]string{
@ -34,6 +35,7 @@ var statusNames = map[Status]string{
StatusCancelled: "cancelled", StatusCancelled: "cancelled",
StatusSkipped: "skipped", StatusSkipped: "skipped",
StatusBlocked: "blocked", StatusBlocked: "blocked",
StatusRunningWithFailure: "running_with_failure",
} }
// String returns the string name of the Status // String returns the string name of the Status
@ -88,6 +90,10 @@ func (s Status) IsBlocked() bool {
return s == StatusBlocked return s == StatusBlocked
} }
func (s Status) IsRunningWithFailure() bool {
return s == StatusRunningWithFailure
}
// In returns whether s is one of the given statuses // In returns whether s is one of the given statuses
func (s Status) In(statuses ...Status) bool { func (s Status) In(statuses ...Status) bool {
return slices.Contains(statuses, s) return slices.Contains(statuses, s)

View File

@ -20,6 +20,8 @@ const (
CommitStatusWarning CommitStatusState = "warning" CommitStatusWarning CommitStatusState = "warning"
// CommitStatusSkipped is for when CommitStatus is Skipped // CommitStatusSkipped is for when CommitStatus is Skipped
CommitStatusSkipped CommitStatusState = "skipped" CommitStatusSkipped CommitStatusState = "skipped"
// CommitStatusRunningWithFailure is for only aggregated commit status
CommitStatusRunningWithFailure CommitStatusState = "running_with_failure"
) )
func (css CommitStatusState) String() string { func (css CommitStatusState) String() string {
@ -56,20 +58,28 @@ func (css CommitStatusState) IsSkipped() bool {
return css == CommitStatusSkipped return css == CommitStatusSkipped
} }
// IsRunningWithFailure represents if commit status state is running with failure
func (css CommitStatusState) IsRunningWithFailure() bool {
return css == CommitStatusRunningWithFailure
}
type CommitStatusStates []CommitStatusState //nolint:revive // export stutter type CommitStatusStates []CommitStatusState //nolint:revive // export stutter
// According to https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference // 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: // > Additionally, a combined state is returned. The state is one of:
// > failure if any of the contexts report as error or failure // > failure if any of the contexts report as error or failure and no contexts are pending
// > pending if there are no statuses or a context is pending // > pending if there are no statuses or a context is pending with no failure
// > running_with_failure if there are contexts that are pending and at least one context is failure
// > success if the latest status for all contexts is success // > success if the latest status for all contexts is success
func (css CommitStatusStates) Combine() CommitStatusState { func (css CommitStatusStates) Combine() CommitStatusState {
successCnt := 0 successCnt := 0
hasRunning, hasFailure := false, false
for _, state := range css { for _, state := range css {
switch { switch {
case state.IsError() || state.IsFailure(): case state.IsError() || state.IsFailure():
return CommitStatusFailure hasFailure = true
case state.IsPending(): case state.IsPending():
hasRunning = true
case state.IsSuccess() || state.IsWarning() || state.IsSkipped(): case state.IsSuccess() || state.IsWarning() || state.IsSkipped():
successCnt++ successCnt++
} }
@ -77,5 +87,11 @@ func (css CommitStatusStates) Combine() CommitStatusState {
if successCnt > 0 && successCnt == len(css) { if successCnt > 0 && successCnt == len(css) {
return CommitStatusSuccess return CommitStatusSuccess
} }
if hasFailure {
if hasRunning {
return CommitStatusRunningWithFailure
}
return CommitStatusFailure
}
return CommitStatusPending return CommitStatusPending
} }

View File

@ -3787,6 +3787,7 @@ status.failure = "Failure"
status.cancelled = "Canceled" status.cancelled = "Canceled"
status.skipped = "Skipped" status.skipped = "Skipped"
status.blocked = "Blocked" status.blocked = "Blocked"
status.running_with_failure = "Running with failure"
runners = Runners runners = Runners
runners.runner_manage_panel = Runners Management runners.runner_manage_panel = Runners Management

View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<!-- Orange dot -->
<circle cx="7" cy="8" r="5" fill="#f1c40f"/>
<!-- Red X (two crossing rectangles) -->
<g transform="translate(6, 5)" fill="#e74c3c">
<rect x="0" y="2" width="8" height="2" transform="rotate(45 4 3)"/>
<rect x="0" y="2" width="8" height="2" transform="rotate(-45 4 3)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 404 B

View File

@ -17,6 +17,8 @@
{{svg "octicon-blocked" $size (printf "text yellow %s" $className)}} {{svg "octicon-blocked" $size (printf "text yellow %s" $className)}}
{{else if eq .status "running"}} {{else if eq .status "running"}}
{{svg "octicon-meter" $size (printf "text yellow circular-spin %s" $className)}} {{svg "octicon-meter" $size (printf "text yellow circular-spin %s" $className)}}
{{else if eq .status "running_with_failure"}}
{{svg "gitea-running-with-failure" $size (printf "text yellow circular-spin %s" $className)}}
{{else}}{{/*failure, unknown*/}} {{else}}{{/*failure, unknown*/}}
{{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}} {{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}}
{{end}} {{end}}

View File

@ -18,6 +18,7 @@
data-locale-status-cancelled="{{ctx.Locale.Tr "actions.status.cancelled"}}" data-locale-status-cancelled="{{ctx.Locale.Tr "actions.status.cancelled"}}"
data-locale-status-skipped="{{ctx.Locale.Tr "actions.status.skipped"}}" data-locale-status-skipped="{{ctx.Locale.Tr "actions.status.skipped"}}"
data-locale-status-blocked="{{ctx.Locale.Tr "actions.status.blocked"}}" data-locale-status-blocked="{{ctx.Locale.Tr "actions.status.blocked"}}"
data-locale-status-running-with-failure="{{ctx.Locale.Tr "actions.status.running_with_failure"}}"
data-locale-artifacts-title="{{ctx.Locale.Tr "artifacts"}}" data-locale-artifacts-title="{{ctx.Locale.Tr "artifacts"}}"
data-locale-artifact-expired="{{ctx.Locale.Tr "expired"}}" data-locale-artifact-expired="{{ctx.Locale.Tr "expired"}}"
data-locale-confirm-delete-artifact="{{ctx.Locale.Tr "confirm_delete_artifact"}}" data-locale-confirm-delete-artifact="{{ctx.Locale.Tr "confirm_delete_artifact"}}"

View File

@ -17,3 +17,6 @@
{{if eq .State "skipped"}} {{if eq .State "skipped"}}
{{svg "octicon-skip" 18 "commit-status icon text grey"}} {{svg "octicon-skip" 18 "commit-status icon text grey"}}
{{end}} {{end}}
{{if eq .State "running_with_failure"}}
{{svg "gitea-running-with-failure" 18 "commit-status icon text red"}}
{{end}}

View File

@ -1,12 +1,12 @@
<!-- This vue should be kept the same as templates/repo/actions/status.tmpl <!-- This vue should be kept the same as templates/repo/actions/status.tmpl
Please also update the template file above if this vue is modified. Please also update the template file above if this vue is modified.
action status accepted: success, skipped, waiting, blocked, running, failure, cancelled, unknown action status accepted: success, skipped, waiting, blocked, running, running_with_failure, failure, cancelled, unknown
--> -->
<script lang="ts" setup> <script lang="ts" setup>
import {SvgIcon} from '../svg.ts'; import {SvgIcon} from '../svg.ts';
withDefaults(defineProps<{ withDefaults(defineProps<{
status: 'success' | 'skipped' | 'waiting' | 'blocked' | 'running' | 'failure' | 'cancelled' | 'unknown', status: 'success' | 'skipped' | 'waiting' | 'blocked' | 'running' | 'running_with_failure' | 'failure' | 'cancelled' | 'unknown',
size?: number, size?: number,
className?: string, className?: string,
localeStatus?: string, localeStatus?: string,
@ -25,6 +25,7 @@ withDefaults(defineProps<{
<SvgIcon name="octicon-clock" class="text yellow" :size="size" :class="className" v-else-if="status === 'waiting'"/> <SvgIcon name="octicon-clock" class="text yellow" :size="size" :class="className" v-else-if="status === 'waiting'"/>
<SvgIcon name="octicon-blocked" class="text yellow" :size="size" :class="className" v-else-if="status === 'blocked'"/> <SvgIcon name="octicon-blocked" class="text yellow" :size="size" :class="className" v-else-if="status === 'blocked'"/>
<SvgIcon name="octicon-meter" class="text yellow" :size="size" :class="'circular-spin ' + className" v-else-if="status === 'running'"/> <SvgIcon name="octicon-meter" class="text yellow" :size="size" :class="'circular-spin ' + className" v-else-if="status === 'running'"/>
<SvgIcon name="gitea-running-with-failure" class="text yellow" :size="size" :class="'circular-spin ' + className" v-else-if="status === 'running_with_failure'"/>
<SvgIcon name="octicon-x-circle-fill" class="text red" :size="size" v-else/><!-- failure, unknown --> <SvgIcon name="octicon-x-circle-fill" class="text red" :size="size" v-else/><!-- failure, unknown -->
</span> </span>
</template> </template>

View File

@ -39,6 +39,7 @@ export function initRepositoryActionView() {
cancelled: el.getAttribute('data-locale-status-cancelled'), cancelled: el.getAttribute('data-locale-status-cancelled'),
skipped: el.getAttribute('data-locale-status-skipped'), skipped: el.getAttribute('data-locale-status-skipped'),
blocked: el.getAttribute('data-locale-status-blocked'), blocked: el.getAttribute('data-locale-status-blocked'),
running_with_failure: el.getAttribute('data-locale-status-running-with-failure'),
}, },
logsAlwaysAutoScroll: el.getAttribute('data-locale-logs-always-auto-scroll'), logsAlwaysAutoScroll: el.getAttribute('data-locale-logs-always-auto-scroll'),
logsAlwaysExpandRunning: el.getAttribute('data-locale-logs-always-expand-running'), logsAlwaysExpandRunning: el.getAttribute('data-locale-logs-always-expand-running'),

View File

@ -78,12 +78,14 @@ import octiconTrash from '../../public/assets/img/svg/octicon-trash.svg';
import octiconTriangleDown from '../../public/assets/img/svg/octicon-triangle-down.svg'; import octiconTriangleDown from '../../public/assets/img/svg/octicon-triangle-down.svg';
import octiconX from '../../public/assets/img/svg/octicon-x.svg'; import octiconX from '../../public/assets/img/svg/octicon-x.svg';
import octiconXCircleFill from '../../public/assets/img/svg/octicon-x-circle-fill.svg'; import octiconXCircleFill from '../../public/assets/img/svg/octicon-x-circle-fill.svg';
import giteaRunningWithFailure from '../../public/assets/img/svg/gitea-running-with-failure.svg';
const svgs = { const svgs = {
'gitea-double-chevron-left': giteaDoubleChevronLeft, 'gitea-double-chevron-left': giteaDoubleChevronLeft,
'gitea-double-chevron-right': giteaDoubleChevronRight, 'gitea-double-chevron-right': giteaDoubleChevronRight,
'gitea-empty-checkbox': giteaEmptyCheckbox, 'gitea-empty-checkbox': giteaEmptyCheckbox,
'gitea-exclamation': giteaExclamation, 'gitea-exclamation': giteaExclamation,
'gitea-running-with-failure': giteaRunningWithFailure,
'octicon-archive': octiconArchive, 'octicon-archive': octiconArchive,
'octicon-arrow-switch': octiconArrowSwitch, 'octicon-arrow-switch': octiconArrowSwitch,
'octicon-blocked': octiconBlocked, 'octicon-blocked': octiconBlocked,