0
0
mirror of https://github.com/go-gitea/gitea.git synced 2025-07-20 14:48:30 +02:00

Merge 4350e0d51ee2b325044a454dd8b5a2cd6cfe3408 into 6599efb3b1400ac06d06e1c8b68ae6037fbb7952

This commit is contained in:
Lunny Xiao 2025-07-12 10:29:43 +03:00 committed by GitHub
commit 05a31f9fa4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 68 additions and 22 deletions

View File

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

View File

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

View File

@ -15,25 +15,27 @@ import (
type Status int
const (
StatusUnknown Status = iota // 0, consistent with runnerv1.Result_RESULT_UNSPECIFIED
StatusSuccess // 1, consistent with runnerv1.Result_RESULT_SUCCESS
StatusFailure // 2, consistent with runnerv1.Result_RESULT_FAILURE
StatusCancelled // 3, consistent with runnerv1.Result_RESULT_CANCELLED
StatusSkipped // 4, consistent with runnerv1.Result_RESULT_SKIPPED
StatusWaiting // 5, isn't a runnerv1.Result
StatusRunning // 6, isn't a runnerv1.Result
StatusBlocked // 7, isn't a runnerv1.Result
StatusUnknown Status = iota // 0, consistent with runnerv1.Result_RESULT_UNSPECIFIED
StatusSuccess // 1, consistent with runnerv1.Result_RESULT_SUCCESS
StatusFailure // 2, consistent with runnerv1.Result_RESULT_FAILURE
StatusCancelled // 3, consistent with runnerv1.Result_RESULT_CANCELLED
StatusSkipped // 4, consistent with runnerv1.Result_RESULT_SKIPPED
StatusWaiting // 5, isn't a runnerv1.Result
StatusRunning // 6, 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{
StatusUnknown: "unknown",
StatusWaiting: "waiting",
StatusRunning: "running",
StatusSuccess: "success",
StatusFailure: "failure",
StatusCancelled: "cancelled",
StatusSkipped: "skipped",
StatusBlocked: "blocked",
StatusUnknown: "unknown",
StatusWaiting: "waiting",
StatusRunning: "running",
StatusSuccess: "success",
StatusFailure: "failure",
StatusCancelled: "cancelled",
StatusSkipped: "skipped",
StatusBlocked: "blocked",
StatusRunningWithFailure: "running_with_failure",
}
// String returns the string name of the Status
@ -88,6 +90,10 @@ func (s Status) IsBlocked() bool {
return s == StatusBlocked
}
func (s Status) IsRunningWithFailure() bool {
return s == StatusRunningWithFailure
}
// In returns whether s is one of the given statuses
func (s Status) In(statuses ...Status) bool {
return slices.Contains(statuses, s)

View File

@ -20,6 +20,8 @@ const (
CommitStatusWarning CommitStatusState = "warning"
// CommitStatusSkipped is for when CommitStatus is Skipped
CommitStatusSkipped CommitStatusState = "skipped"
// CommitStatusRunningWithFailure is for only aggregated commit status
CommitStatusRunningWithFailure CommitStatusState = "running_with_failure"
)
func (css CommitStatusState) String() string {
@ -56,20 +58,28 @@ func (css CommitStatusState) IsSkipped() bool {
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
// 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
// > 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 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
func (css CommitStatusStates) Combine() CommitStatusState {
successCnt := 0
hasRunning, hasFailure := false, false
for _, state := range css {
switch {
case state.IsError() || state.IsFailure():
return CommitStatusFailure
hasFailure = true
case state.IsPending():
hasRunning = true
case state.IsSuccess() || state.IsWarning() || state.IsSkipped():
successCnt++
}
@ -77,5 +87,11 @@ func (css CommitStatusStates) Combine() CommitStatusState {
if successCnt > 0 && successCnt == len(css) {
return CommitStatusSuccess
}
if hasFailure {
if hasRunning {
return CommitStatusRunningWithFailure
}
return CommitStatusFailure
}
return CommitStatusPending
}

View File

@ -3789,6 +3789,7 @@ status.failure = "Failure"
status.cancelled = "Canceled"
status.skipped = "Skipped"
status.blocked = "Blocked"
status.running_with_failure = "Running with failure"
runners = Runners
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)}}
{{else if eq .status "running"}}
{{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*/}}
{{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}}
{{end}}

View File

@ -18,6 +18,7 @@
data-locale-status-cancelled="{{ctx.Locale.Tr "actions.status.cancelled"}}"
data-locale-status-skipped="{{ctx.Locale.Tr "actions.status.skipped"}}"
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-artifact-expired="{{ctx.Locale.Tr "expired"}}"
data-locale-confirm-delete-artifact="{{ctx.Locale.Tr "confirm_delete_artifact"}}"

View File

@ -17,3 +17,6 @@
{{if eq .State "skipped"}}
{{svg "octicon-skip" 18 "commit-status icon text grey"}}
{{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
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>
import {SvgIcon} from '../svg.ts';
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,
className?: 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-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="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 -->
</span>
</template>

View File

@ -39,6 +39,7 @@ export function initRepositoryActionView() {
cancelled: el.getAttribute('data-locale-status-cancelled'),
skipped: el.getAttribute('data-locale-status-skipped'),
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'),
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 octiconX from '../../public/assets/img/svg/octicon-x.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 = {
'gitea-double-chevron-left': giteaDoubleChevronLeft,
'gitea-double-chevron-right': giteaDoubleChevronRight,
'gitea-empty-checkbox': giteaEmptyCheckbox,
'gitea-exclamation': giteaExclamation,
'gitea-running-with-failure': giteaRunningWithFailure,
'octicon-archive': octiconArchive,
'octicon-arrow-switch': octiconArrowSwitch,
'octicon-blocked': octiconBlocked,