summaryrefslogtreecommitdiffstats
path: root/internal/pkg/labels
diff options
context:
space:
mode:
Diffstat (limited to 'internal/pkg/labels')
-rw-r--r--internal/pkg/labels/labels.go109
-rw-r--r--internal/pkg/labels/labels_test.go63
2 files changed, 172 insertions, 0 deletions
diff --git a/internal/pkg/labels/labels.go b/internal/pkg/labels/labels.go
new file mode 100644
index 0000000..f448fdf
--- /dev/null
+++ b/internal/pkg/labels/labels.go
@@ -0,0 +1,109 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package labels
+
+import (
+ "fmt"
+ "strings"
+)
+
+const (
+ SchemeHost = "host"
+ SchemeDocker = "docker"
+ SchemeLXC = "lxc"
+)
+
+type Label struct {
+ Name string
+ Schema string
+ Arg string
+}
+
+func Parse(str string) (*Label, error) {
+ splits := strings.SplitN(str, ":", 3)
+ label := &Label{
+ Name: splits[0],
+ Schema: "host",
+ Arg: "",
+ }
+ if len(splits) >= 2 {
+ label.Schema = splits[1]
+ }
+ if len(splits) >= 3 {
+ label.Arg = splits[2]
+ }
+ if label.Schema != SchemeHost && label.Schema != SchemeDocker && label.Schema != SchemeLXC {
+ return nil, fmt.Errorf("unsupported schema: %s", label.Schema)
+ }
+ return label, nil
+}
+
+type Labels []*Label
+
+func (l Labels) RequireDocker() bool {
+ for _, label := range l {
+ if label.Schema == SchemeDocker {
+ return true
+ }
+ }
+ return false
+}
+
+func (l Labels) PickPlatform(runsOn []string) string {
+ platforms := make(map[string]string, len(l))
+ for _, label := range l {
+ switch label.Schema {
+ case SchemeDocker:
+ // "//" will be ignored
+ platforms[label.Name] = strings.TrimPrefix(label.Arg, "//")
+ case SchemeHost:
+ platforms[label.Name] = "-self-hosted"
+ case SchemeLXC:
+ platforms[label.Name] = "lxc:" + strings.TrimPrefix(label.Arg, "//")
+ default:
+ // It should not happen, because Parse has checked it.
+ continue
+ }
+ }
+ for _, v := range runsOn {
+ if v, ok := platforms[v]; ok {
+ return v
+ }
+ }
+
+ // 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 "node:20-bullseye"
+}
+
+func (l Labels) Names() []string {
+ names := make([]string, 0, len(l))
+ for _, label := range l {
+ names = append(names, label.Name)
+ }
+ return names
+}
+
+func (l Labels) ToStrings() []string {
+ ls := make([]string, 0, len(l))
+ for _, label := range l {
+ lbl := label.Name
+ if label.Schema != "" {
+ lbl += ":" + label.Schema
+ if label.Arg != "" {
+ lbl += ":" + label.Arg
+ }
+ }
+ ls = append(ls, lbl)
+ }
+ return ls
+}
diff --git a/internal/pkg/labels/labels_test.go b/internal/pkg/labels/labels_test.go
new file mode 100644
index 0000000..e46a27b
--- /dev/null
+++ b/internal/pkg/labels/labels_test.go
@@ -0,0 +1,63 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package labels
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "gotest.tools/v3/assert"
+)
+
+func TestParse(t *testing.T) {
+ tests := []struct {
+ args string
+ want *Label
+ wantErr bool
+ }{
+ {
+ args: "ubuntu:docker://node:18",
+ want: &Label{
+ Name: "ubuntu",
+ Schema: "docker",
+ Arg: "//node:18",
+ },
+ wantErr: false,
+ },
+ {
+ args: "ubuntu:host",
+ want: &Label{
+ Name: "ubuntu",
+ Schema: "host",
+ Arg: "",
+ },
+ wantErr: false,
+ },
+ {
+ args: "ubuntu",
+ want: &Label{
+ Name: "ubuntu",
+ Schema: "host",
+ Arg: "",
+ },
+ wantErr: false,
+ },
+ {
+ args: "ubuntu:vm:ubuntu-18.04",
+ want: nil,
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.args, func(t *testing.T) {
+ got, err := Parse(tt.args)
+ if tt.wantErr {
+ require.Error(t, err)
+ return
+ }
+ require.NoError(t, err)
+ assert.DeepEqual(t, got, tt.want)
+ })
+ }
+}