2
0

fix(labels): return empty string on label mismatch instead of fallback
Some checks failed
Release / build (amd64, darwin) (push) Successful in 53s
Release / build (amd64, linux) (push) Successful in 1m8s
Release / build (amd64, windows) (push) Successful in 50s
Release / build (arm64, darwin) (push) Successful in 1m1s
Release / build (arm64, linux) (push) Successful in 53s
Release / release (push) Successful in 21s
CI / build-and-test (push) Failing after 45s

Changes PickPlatform to return empty string when no matching label is found, causing the job to fail with a clear error rather than silently falling back to ubuntu-latest. This prevents jobs from running in incorrect environments when runner labels are edited in Gitea admin UI after registration. Adds comprehensive test coverage for label matching scenarios including exact matches, no matches, empty labels, and multiple runsOn values.
This commit is contained in:
2026-02-09 01:56:57 -05:00
parent d87b08c559
commit 522ee44718
2 changed files with 65 additions and 11 deletions

View File

@@ -56,6 +56,7 @@ func (l Labels) RequireDocker() bool {
}
// PickPlatform selects the appropriate platform based on the runsOn requirements.
// Returns empty string if no matching label is found, which will cause the job to fail.
func (l Labels) PickPlatform(runsOn []string) string {
platforms := make(map[string]string, len(l))
for _, label := range l {
@@ -76,17 +77,12 @@ func (l Labels) PickPlatform(runsOn []string) string {
}
}
// TODO: support multiple labels
// like:
// ["ubuntu-22.04"] => "ubuntu:22.04"
// ["with-gpu"] => "linux:with-gpu"
// ["ubuntu-22.04", "with-gpu"] => "ubuntu:22.04_with-gpu"
// return default.
// So the runner receives a task with a label that the runner doesn't have,
// it happens when the user have edited the label of the runner in the web UI.
// TODO: it may be not correct, what if the runner is used as host mode only?
return "docker.gitea.com/runner-images:ubuntu-latest"
// No matching label found. This indicates a mismatch between server's view
// of runner labels and the runner's local configuration (e.g., labels were
// edited in Gitea admin UI after runner registered). Return empty string
// to cause the job to fail with a clear error rather than silently running
// in the wrong environment.
return ""
}
// Names returns the names of all labels.

View File

@@ -10,6 +10,64 @@ import (
"gotest.tools/v3/assert"
)
func TestPickPlatform(t *testing.T) {
tests := []struct {
name string
labels []string
runsOn []string
want string
}{
{
name: "exact match host label",
labels: []string{"linux-latest:host", "ubuntu:host"},
runsOn: []string{"linux-latest"},
want: "-self-hosted",
},
{
name: "exact match docker label",
labels: []string{"ubuntu:docker://node:18"},
runsOn: []string{"ubuntu"},
want: "node:18",
},
{
name: "no match returns empty string to fail job",
labels: []string{"linux:host", "debian:host"},
runsOn: []string{"unknown-label"},
want: "",
},
{
name: "no match on docker runner returns empty string",
labels: []string{"ubuntu:docker://node:18", "linux:host"},
runsOn: []string{"unknown-label"},
want: "",
},
{
name: "empty labels returns empty string",
labels: []string{},
runsOn: []string{"anything"},
want: "",
},
{
name: "multiple runsOn matches first available",
labels: []string{"linux:host", "ubuntu:docker://node:18"},
runsOn: []string{"windows", "ubuntu"},
want: "node:18",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ls := Labels{}
for _, l := range tt.labels {
label, err := Parse(l)
require.NoError(t, err)
ls = append(ls, label)
}
got := ls.PickPlatform(tt.runsOn)
assert.Equal(t, got, tt.want)
})
}
}
func TestParse(t *testing.T) {
tests := []struct {
args string