mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-08-06 00:44:22 +02:00
fix: coerce every expression value kind to a string and drop the format() panic (#1135)
`coerceToString` covered only a few kinds and returned the unconverted `reflect.Value` for the rest, so callers rendered contexts as `<*model.GithubContext Value>` and mangled sized integers and floats the same way. It now returns a string, which makes that placeholder unrepresentable, and is exported as `CoerceToString` so Gitea can drop its own diverging copy. It also takes an already reflected value, so internal callers need no conversion and no guard against the zero `Value`.
`format()` panicked whenever a lone `}` was followed by anything other than another `}`. Only a trailing `}` reached the existing unmatched-brace check, so an expression such as `format('a}b')`, which any workflow can write, took the process down instead. It now returns that same error.
Reviewed-on: https://gitea.com/gitea/runner/pulls/1135
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gitea.com/gitea/runner/act/model"
|
||||
@@ -429,41 +430,54 @@ func (impl *interperterImpl) coerceToNumber(value reflect.Value) reflect.Value {
|
||||
return reflect.ValueOf(math.NaN())
|
||||
}
|
||||
|
||||
func (impl *interperterImpl) coerceToString(value reflect.Value) reflect.Value {
|
||||
switch value.Kind() {
|
||||
case reflect.Invalid:
|
||||
return reflect.ValueOf("")
|
||||
|
||||
case reflect.Bool:
|
||||
switch value.Bool() {
|
||||
case true:
|
||||
return reflect.ValueOf("true")
|
||||
case false:
|
||||
return reflect.ValueOf("false")
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
return value
|
||||
|
||||
case reflect.Int:
|
||||
return reflect.ValueOf(fmt.Sprint(value))
|
||||
|
||||
case reflect.Float64:
|
||||
if math.IsInf(value.Float(), 1) {
|
||||
return reflect.ValueOf("Infinity")
|
||||
} else if math.IsInf(value.Float(), -1) {
|
||||
return reflect.ValueOf("-Infinity")
|
||||
}
|
||||
return reflect.ValueOf(fmt.Sprintf("%.15G", value.Float()))
|
||||
|
||||
case reflect.Slice:
|
||||
return reflect.ValueOf("Array")
|
||||
|
||||
case reflect.Map:
|
||||
return reflect.ValueOf("Object")
|
||||
// CoerceToString converts an evaluated expression value to a string the way GitHub does,
|
||||
// see https://docs.github.com/en/actions/reference/workflows-and-actions/expressions#operators
|
||||
// An already reflected value is accepted as-is, since Interface() would panic on an invalid one.
|
||||
func CoerceToString(v any) string {
|
||||
value, ok := v.(reflect.Value)
|
||||
if !ok {
|
||||
value = reflect.ValueOf(v)
|
||||
}
|
||||
|
||||
return value
|
||||
switch value.Kind() {
|
||||
case reflect.Invalid:
|
||||
return ""
|
||||
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(value.Bool())
|
||||
|
||||
case reflect.String:
|
||||
return value.String()
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(value.Int(), 10)
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(value.Uint(), 10)
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if math.IsInf(value.Float(), 1) {
|
||||
return "Infinity"
|
||||
} else if math.IsInf(value.Float(), -1) {
|
||||
return "-Infinity"
|
||||
}
|
||||
return fmt.Sprintf("%.15G", value.Float())
|
||||
|
||||
case reflect.Slice, reflect.Array:
|
||||
return "Array"
|
||||
|
||||
// contexts such as `github` are pointers to structs, so they stringify as objects too
|
||||
case reflect.Map, reflect.Struct:
|
||||
return "Object"
|
||||
|
||||
case reflect.Interface, reflect.Pointer:
|
||||
if value.IsNil() {
|
||||
return ""
|
||||
}
|
||||
return CoerceToString(value.Elem())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v", value)
|
||||
}
|
||||
|
||||
func (impl *interperterImpl) compareString(left, right string, kind actionlint.CompareOpNodeKind) (bool, error) {
|
||||
|
||||
Reference in New Issue
Block a user