mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-08-02 12:53:08 +00:00
fix: fix panics, enable the forcetypeassert lint (#1123)
An unchecked type assertion panics on input it did not expect, as a missing `tool_cache` key did in https://gitea.com/gitea/runner/pulls/1122.
Every flagged site is now handled where it can fail, or typed so it cannot: a `lock.Keyed` replaces the two `sync.Map` mutex registries, and the reporter's outputs carry an explicit sent flag. Mocks keep their assertions, a mismatch there is a setup error the panic names.
Bugs it turned up (only the first is reachable from workflows):
1. A scalar `matrix.include` or `matrix.exclude`, e.g. `include: foo` or `include: [1, 2]`, panicked the runner with `interface conversion: interface {} is string, not map[string]interface {}`. Verified against `main`, it is now a workflow error. `OnSchedule` panicked the same way on a malformed `on.schedule` entry.
1. `ExternalURL()` panicked on the nil listener after `Close()`, the port is now resolved once at startup.
1. `errors.Is(err, git.ErrShortRef)` followed by `err.(*git.Error)` panics as soon as anything wraps that error, so it is `errors.As` now.
1. An output name the server acknowledged without ever being sent one was recorded as sent forever, which silently dropped a later value for that name.
48576ab3e5 fixes one discovered issue: a matrix key holding a nested object was logged and then run as if the job had no matrix, so it now fails like an unknown `exclude` key.
Reviewed-on: https://gitea.com/gitea/runner/pulls/1123
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -86,11 +86,12 @@ func (w *Workflow) OnSchedule() []string {
|
||||
case []any:
|
||||
allSchedules := []string{}
|
||||
for _, v := range val {
|
||||
for k, cron := range v.(map[string]any) {
|
||||
if k != "cron" {
|
||||
continue
|
||||
}
|
||||
allSchedules = append(allSchedules, cron.(string))
|
||||
entry, ok := v.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if cron, ok := entry["cron"].(string); ok {
|
||||
allSchedules = append(allSchedules, cron)
|
||||
}
|
||||
}
|
||||
return allSchedules
|
||||
@@ -443,9 +444,9 @@ func normalizeMatrixValue(key string, val any) ([]any, error) {
|
||||
// Scalar values are wrapped into single-element arrays automatically.
|
||||
// Template expressions are resolved by EvaluateYamlNode before this method is
|
||||
// called; if unresolved, the literal string is wrapped as a one-element fallback.
|
||||
func (j *Job) Matrix() map[string][]any {
|
||||
func (j *Job) Matrix() (map[string][]any, error) {
|
||||
if j.Strategy == nil || j.Strategy.RawMatrix.Kind != yaml.MappingNode {
|
||||
return nil
|
||||
return map[string][]any{}, nil
|
||||
}
|
||||
|
||||
// Decode to flexible map first so that scalar values don't cause a type error.
|
||||
@@ -455,9 +456,9 @@ func (j *Job) Matrix() map[string][]any {
|
||||
// Fall back to the strict array-only format for backward compatibility.
|
||||
var val map[string][]any
|
||||
if !decodeNode(j.Strategy.RawMatrix, &val) {
|
||||
return nil
|
||||
return map[string][]any{}, nil
|
||||
}
|
||||
return val
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// Convert flexible format to expected format with validation
|
||||
@@ -465,12 +466,11 @@ func (j *Job) Matrix() map[string][]any {
|
||||
for k, v := range flexVal {
|
||||
normalized, err := normalizeMatrixValue(k, v)
|
||||
if err != nil {
|
||||
log.Errorf("matrix validation error: %v", err)
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
val[k] = normalized
|
||||
}
|
||||
return val
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// GetMatrixes returns the matrix cross product
|
||||
@@ -482,38 +482,38 @@ func (j *Job) GetMatrixes() ([]map[string]any, error) {
|
||||
j.Strategy.FailFast = j.Strategy.GetFailFast()
|
||||
j.Strategy.MaxParallel = j.Strategy.GetMaxParallel()
|
||||
|
||||
if m := j.Matrix(); m != nil {
|
||||
m, err := j.Matrix()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(m) > 0 {
|
||||
includes := make([]map[string]any, 0)
|
||||
extraIncludes := make([]map[string]any, 0)
|
||||
addInclude := func(raw any) error {
|
||||
include, ok := raw.(map[string]any)
|
||||
if !ok {
|
||||
return fmt.Errorf("the workflow is not valid. Matrix include %v is not a map of matrix keys to values", raw)
|
||||
}
|
||||
for k := range include {
|
||||
if _, ok := m[k]; ok {
|
||||
includes = append(includes, include)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
extraIncludes = append(extraIncludes, include)
|
||||
return nil
|
||||
}
|
||||
for _, v := range m["include"] {
|
||||
switch t := v.(type) {
|
||||
case []any:
|
||||
for _, i := range t {
|
||||
i := i.(map[string]any)
|
||||
extraInclude := true
|
||||
for k := range i {
|
||||
if _, ok := m[k]; ok {
|
||||
includes = append(includes, i)
|
||||
extraInclude = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if extraInclude {
|
||||
extraIncludes = append(extraIncludes, i)
|
||||
if err := addInclude(i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case any:
|
||||
v := v.(map[string]any)
|
||||
extraInclude := true
|
||||
for k := range v {
|
||||
if _, ok := m[k]; ok {
|
||||
includes = append(includes, v)
|
||||
extraInclude = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if extraInclude {
|
||||
extraIncludes = append(extraIncludes, v)
|
||||
if err := addInclude(t); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,10 +521,13 @@ func (j *Job) GetMatrixes() ([]map[string]any, error) {
|
||||
|
||||
excludes := make([]map[string]any, 0)
|
||||
for _, e := range m["exclude"] {
|
||||
e := e.(map[string]any)
|
||||
for k := range e {
|
||||
exclude, ok := e.(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the workflow is not valid. Matrix exclude %v is not a map of matrix keys to values", e)
|
||||
}
|
||||
for k := range exclude {
|
||||
if _, ok := m[k]; ok {
|
||||
excludes = append(excludes, e)
|
||||
excludes = append(excludes, exclude)
|
||||
} else {
|
||||
// We fail completely here because that's what GitHub does for non-existing matrix keys, fail on exclude, silent skip on include
|
||||
return nil, fmt.Errorf("the workflow is not valid. Matrix exclude key %q does not match any key within the matrix", k)
|
||||
|
||||
Reference in New Issue
Block a user