mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
i18n: translate Actions PreExecutionError for viewer (#10267)
Identified in code review https://codeberg.org/forgejo/forgejo/pulls/10244#issuecomment-8576643, the `PreExecutionError` field in `ActionRun` isn't well implemented as it translates the error at action runtime rather than later when the action is viewed in the UI. This PR adds an error code and error details column that can be more correctly translated. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10267 Reviewed-by: 0ko <0ko@noreply.codeberg.org> Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net> Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
This commit is contained in:
parent
6edfeb60f9
commit
993da59ad4
10 changed files with 165 additions and 28 deletions
41
models/actions/pre_execution_errors.go
Normal file
41
models/actions/pre_execution_errors.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"forgejo.org/modules/translation"
|
||||
)
|
||||
|
||||
type PreExecutionError int64
|
||||
|
||||
// PreExecutionError values are stored in the database in ActionRun.PreExecutionError and therefore values can't be
|
||||
// reordered or changed without a database migration. Translation arguments are stored in the database in
|
||||
// PreExecutionErrorDetails, and so they can't be changed or reordered without creating a migration or a new error code
|
||||
// to represent the new argument details.
|
||||
const (
|
||||
ErrorCodeEventDetectionError PreExecutionError = iota + 1
|
||||
ErrorCodeJobParsingError
|
||||
ErrorCodePersistentIncompleteMatrix
|
||||
)
|
||||
|
||||
func TranslatePreExecutionError(lang translation.Locale, run *ActionRun) string {
|
||||
if run.PreExecutionError != "" {
|
||||
// legacy: Forgejo v13 stored value pre-translated, preventing correct translation to active user
|
||||
return run.PreExecutionError
|
||||
}
|
||||
|
||||
switch run.PreExecutionErrorCode {
|
||||
case 0:
|
||||
return ""
|
||||
case ErrorCodeEventDetectionError:
|
||||
return lang.TrString("actions.workflow.event_detection_error", run.PreExecutionErrorDetails...)
|
||||
case ErrorCodeJobParsingError:
|
||||
return lang.TrString("actions.workflow.job_parsing_error", run.PreExecutionErrorDetails...)
|
||||
case ErrorCodePersistentIncompleteMatrix:
|
||||
return lang.TrString("actions.workflow.persistent_incomplete_matrix", run.PreExecutionErrorDetails...)
|
||||
}
|
||||
return fmt.Sprintf("<unsupported error: code=%v details=%#v", run.PreExecutionErrorCode, run.PreExecutionErrorDetails)
|
||||
}
|
||||
64
models/actions/pre_execution_errors_test.go
Normal file
64
models/actions/pre_execution_errors_test.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"forgejo.org/modules/translation"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTranslatePreExecutionError(t *testing.T) {
|
||||
translation.InitLocales(t.Context())
|
||||
lang := translation.NewLocale("en-US")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
run *ActionRun
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "legacy",
|
||||
run: &ActionRun{PreExecutionError: "legacy message"},
|
||||
expected: "legacy message",
|
||||
},
|
||||
{
|
||||
name: "no error",
|
||||
run: &ActionRun{},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "ErrorCodeEventDetectionError",
|
||||
run: &ActionRun{
|
||||
PreExecutionErrorCode: ErrorCodeEventDetectionError,
|
||||
PreExecutionErrorDetails: []any{"inner error message"},
|
||||
},
|
||||
expected: "Unable to parse supported events in workflow: inner error message",
|
||||
},
|
||||
{
|
||||
name: "ErrorCodeJobParsingError",
|
||||
run: &ActionRun{
|
||||
PreExecutionErrorCode: ErrorCodeJobParsingError,
|
||||
PreExecutionErrorDetails: []any{"inner error message"},
|
||||
},
|
||||
expected: "Unable to parse jobs in workflow: inner error message",
|
||||
},
|
||||
{
|
||||
name: "ErrorCodePersistentIncompleteMatrix",
|
||||
run: &ActionRun{
|
||||
PreExecutionErrorCode: ErrorCodePersistentIncompleteMatrix,
|
||||
PreExecutionErrorDetails: []any{"blocked_job", "needs-1, needs-2"},
|
||||
},
|
||||
expected: "Unable to evaluate `strategy.matrix` of job blocked_job due to a `needs` expression that was invalid. It may reference a job that is not in it's 'needs' list (needs-1, needs-2), or an output that doesn't exist on one of those jobs.",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := TranslatePreExecutionError(lang, tt.run)
|
||||
assert.Equal(t, tt.expected, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +78,10 @@ type ActionRun struct {
|
|||
ConcurrencyGroup string `xorm:"'concurrency_group' index(concurrency)"`
|
||||
ConcurrencyType ConcurrencyMode
|
||||
|
||||
PreExecutionError string `xorm:"LONGTEXT"` // used to report errors that blocked execution of a workflow
|
||||
// used to report errors that blocked execution of a workflow
|
||||
PreExecutionError string `xorm:"LONGTEXT"` // deprecated: replaced with PreExecutionErrorCode and PreExecutionErrorDetails for better i18n
|
||||
PreExecutionErrorCode PreExecutionError
|
||||
PreExecutionErrorDetails []any `xorm:"JSON LONGTEXT"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue