mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-08-01 12:26:36 +00:00
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>
39 lines
929 B
Go
39 lines
929 B
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package lock
|
|
|
|
import "sync"
|
|
|
|
// Keyed serializes the work done under one key while letting different keys run in
|
|
// parallel. Its zero value is ready to use, and it keeps one mutex per key it has seen.
|
|
type Keyed[K comparable] struct {
|
|
mu sync.Mutex
|
|
mutexes map[K]*sync.Mutex
|
|
}
|
|
|
|
// Lock locks the mutex for key and returns its unlock function.
|
|
func (kl *Keyed[K]) Lock(key K) func() {
|
|
kl.mu.Lock()
|
|
if kl.mutexes == nil {
|
|
kl.mutexes = map[K]*sync.Mutex{}
|
|
}
|
|
lock := kl.mutexes[key]
|
|
if lock == nil {
|
|
lock = &sync.Mutex{}
|
|
kl.mutexes[key] = lock
|
|
}
|
|
kl.mu.Unlock()
|
|
|
|
lock.Lock()
|
|
return lock.Unlock
|
|
}
|
|
|
|
// Delete drops the mutex for key. Holders of it keep working, they just no longer share it
|
|
// with a later Lock of the same key.
|
|
func (kl *Keyed[K]) Delete(key K) {
|
|
kl.mu.Lock()
|
|
delete(kl.mutexes, key)
|
|
kl.mu.Unlock()
|
|
}
|