From 85b62cf5068338df586b4a6c1d29f52b637f4506 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Mon, 16 Mar 2026 13:37:01 +0100 Subject: [PATCH 1/5] Scale set add multi-label support --- .../v1alpha1/autoscalingrunnerset_types.go | 3 ++ .../v1alpha1/zz_generated.deepcopy.go | 5 +++ ...ions.github.com_autoscalingrunnersets.yaml | 4 +++ ...ions.github.com_autoscalingrunnersets.yaml | 4 +++ .../templates/autoscalingrunnserset.yaml | 4 +++ ...ling_runner_set_scale_set_labels_test.yaml | 24 ++++++++++++++ .../values.yaml | 4 +++ .../templates/autoscalingrunnerset.yaml | 4 +++ .../tests/template_test.go | 31 +++++++++++++++++++ charts/gha-runner-scale-set/values.yaml | 2 ++ ...ions.github.com_autoscalingrunnersets.yaml | 4 +++ .../autoscalingrunnerset_controller.go | 30 ++++++++++++++---- 12 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml diff --git a/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go b/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go index 90049d27bc..5338453978 100644 --- a/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go +++ b/apis/actions.github.com/v1alpha1/autoscalingrunnerset_types.go @@ -66,6 +66,9 @@ type AutoscalingRunnerSetSpec struct { // +optional RunnerScaleSetName string `json:"runnerScaleSetName,omitempty"` + // +optional + RunnerScaleSetLabels []string `json:"runnerScaleSetLabels,omitempty"` + // +optional Proxy *ProxyConfig `json:"proxy,omitempty"` diff --git a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go index 232d6f8647..df2dabc81a 100644 --- a/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go +++ b/apis/actions.github.com/v1alpha1/zz_generated.deepcopy.go @@ -227,6 +227,11 @@ func (in *AutoscalingRunnerSetList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AutoscalingRunnerSetSpec) DeepCopyInto(out *AutoscalingRunnerSetSpec) { *out = *in + if in.RunnerScaleSetLabels != nil { + in, out := &in.RunnerScaleSetLabels, &out.RunnerScaleSetLabels + *out = make([]string, len(*in)) + copy(*out, *in) + } if in.Proxy != nil { in, out := &in.Proxy, &out.Proxy *out = new(ProxyConfig) diff --git a/charts/gha-runner-scale-set-controller-experimental/crds/actions.github.com_autoscalingrunnersets.yaml b/charts/gha-runner-scale-set-controller-experimental/crds/actions.github.com_autoscalingrunnersets.yaml index 1b18467f7e..17adca1ef9 100644 --- a/charts/gha-runner-scale-set-controller-experimental/crds/actions.github.com_autoscalingrunnersets.yaml +++ b/charts/gha-runner-scale-set-controller-experimental/crds/actions.github.com_autoscalingrunnersets.yaml @@ -8385,6 +8385,10 @@ spec: type: object runnerGroup: type: string + runnerScaleSetLabels: + items: + type: string + type: array runnerScaleSetName: type: string template: diff --git a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml index 1b18467f7e..17adca1ef9 100644 --- a/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml +++ b/charts/gha-runner-scale-set-controller/crds/actions.github.com_autoscalingrunnersets.yaml @@ -8385,6 +8385,10 @@ spec: type: object runnerGroup: type: string + runnerScaleSetLabels: + items: + type: string + type: array runnerScaleSetName: type: string template: diff --git a/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml b/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml index a97caf4df1..f0d2c8a43c 100644 --- a/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml +++ b/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml @@ -83,6 +83,10 @@ spec: githubConfigSecret: {{ include "github-secret.name" . | quote }} runnerGroup: {{ .Values.scaleset.runnerGroup | quote }} runnerScaleSetName: {{ .Values.scaleset.name | quote }} + {{- if and .Values.scaleset.labels (kindIs "slice" .Values.scaleset.labels) }} + runnerScaleSetLabels: + {{- toYaml .Values.scaleset.labels | nindent 4 }} + {{- end }} {{- if .Values.githubServerTLS }} githubServerTLS: diff --git a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml new file mode 100644 index 0000000000..6176694bc1 --- /dev/null +++ b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml @@ -0,0 +1,24 @@ +suite: "AutoscalingRunnerSet scale set labels" +templates: + - autoscalingrunnserset.yaml +tests: + - it: should apply scaleset labels slice as runnerScaleSetLabels + set: + scaleset.name: "test" + scaleset.labels: + - "linux" + - "x64" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - equal: + path: spec.runnerScaleSetLabels[0] + value: "linux" + - equal: + path: spec.runnerScaleSetLabels[1] + value: "x64" \ No newline at end of file diff --git a/charts/gha-runner-scale-set-experimental/values.yaml b/charts/gha-runner-scale-set-experimental/values.yaml index eced4064e6..19444b59e4 100644 --- a/charts/gha-runner-scale-set-experimental/values.yaml +++ b/charts/gha-runner-scale-set-experimental/values.yaml @@ -5,6 +5,10 @@ scaleset: # Name of the scaleset name: "" runnerGroup: "default" + # Labels are optional list of strings that will be applied to the scaleset + # allowing scaleset to be selected by the listener based on the labels specified in the workflow. + # https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/apply-labels + labels: [] ## minRunners is the min number of idle runners. The target number of runners created will be ## calculated as a sum of minRunners and the number of jobs assigned to the scale set. # minRunners: 0 diff --git a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml index db6ba9d0ab..0771e9c9a6 100644 --- a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml +++ b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml @@ -74,6 +74,10 @@ spec: {{- with .Values.runnerScaleSetName }} runnerScaleSetName: {{ . }} {{- end }} + {{- if and .Values.scaleSetLabels (kindIs "slice" .Values.scaleSetLabels) }} + runnerScaleSetLabels: + {{- toYaml .Values.scaleSetLabels | nindent 4 }} + {{- end }} {{- if .Values.githubServerTLS }} githubServerTLS: diff --git a/charts/gha-runner-scale-set/tests/template_test.go b/charts/gha-runner-scale-set/tests/template_test.go index 7a65747572..9d6c2e9203 100644 --- a/charts/gha-runner-scale-set/tests/template_test.go +++ b/charts/gha-runner-scale-set/tests/template_test.go @@ -474,6 +474,37 @@ func TestTemplateRenderedAutoScalingRunnerSet_RunnerScaleSetName(t *testing.T) { assert.Equal(t, "ghcr.io/actions/actions-runner:latest", ars.Spec.Template.Spec.Containers[0].Image) } +func TestTemplateRenderedAutoScalingRunnerSet_ScaleSetLabels(t *testing.T) { + t.Parallel() + + // Path to the helm chart we will test + helmChartPath, err := filepath.Abs("../../gha-runner-scale-set") + require.NoError(t, err) + + releaseName := "test-runners" + namespaceName := "test-" + strings.ToLower(random.UniqueId()) + + options := &helm.Options{ + Logger: logger.Discard, + SetValues: map[string]string{ + "githubConfigUrl": "https://github.com/actions", + "githubConfigSecret.github_token": "gh_token12345", + "scaleSetLabels[0]": "linux", + "scaleSetLabels[1]": "x64", + "controllerServiceAccount.name": "arc", + "controllerServiceAccount.namespace": "arc-system", + }, + KubectlOptions: k8s.NewKubectlOptions("", "", namespaceName), + } + + output := helm.RenderTemplate(t, options, helmChartPath, releaseName, []string{"templates/autoscalingrunnerset.yaml"}) + + var ars v1alpha1.AutoscalingRunnerSet + helm.UnmarshalK8SYaml(t, output, &ars) + + assert.Equal(t, []string{"linux", "x64"}, ars.Spec.RunnerScaleSetLabels) +} + func TestTemplateRenderedAutoScalingRunnerSet_ProvideMetadata(t *testing.T) { t.Parallel() diff --git a/charts/gha-runner-scale-set/values.yaml b/charts/gha-runner-scale-set/values.yaml index 8a9b64e997..b8d754f373 100644 --- a/charts/gha-runner-scale-set/values.yaml +++ b/charts/gha-runner-scale-set/values.yaml @@ -2,6 +2,8 @@ ## ex: https://github.com/myorg/myrepo or https://github.com/myorg or https://github.com/enterprises/myenterprise githubConfigUrl: "" +scaleSetLabels: [] + ## githubConfigSecret is the k8s secret information to use when authenticating via the GitHub API. ## You can choose to supply: ## A) a PAT token, diff --git a/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml b/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml index 1b18467f7e..17adca1ef9 100644 --- a/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml +++ b/config/crd/bases/actions.github.com_autoscalingrunnersets.yaml @@ -8385,6 +8385,10 @@ spec: type: object runnerGroup: type: string + runnerScaleSetLabels: + items: + type: string + type: array runnerScaleSetName: type: string template: diff --git a/controllers/actions.github.com/autoscalingrunnerset_controller.go b/controllers/actions.github.com/autoscalingrunnerset_controller.go index c2d48d1614..9494fd41b8 100644 --- a/controllers/actions.github.com/autoscalingrunnerset_controller.go +++ b/controllers/actions.github.com/autoscalingrunnerset_controller.go @@ -424,17 +424,35 @@ func (r *AutoscalingRunnerSetReconciler) createRunnerScaleSet(ctx context.Contex } if runnerScaleSet == nil { + labels := []scaleset.Label{ + { + Name: autoscalingRunnerSet.Spec.RunnerScaleSetName, + Type: "System", + }, + } + + if labelCount := len(autoscalingRunnerSet.Spec.RunnerScaleSetLabels); labelCount > 0 { + unique := make(map[string]bool, labelCount+1) + unique[autoscalingRunnerSet.Spec.RunnerScaleSetName] = true + + for _, label := range autoscalingRunnerSet.Spec.RunnerScaleSetLabels { + if _, exists := unique[label]; exists { + logger.Info("Duplicate label found. Skipping adding duplicate label to runner scale set", "label", label) + continue + } + labels = append(labels, scaleset.Label{ + Name: label, + Type: "System", + }) + unique[label] = true + } + } runnerScaleSet, err = actionsClient.CreateRunnerScaleSet( ctx, &scaleset.RunnerScaleSet{ Name: autoscalingRunnerSet.Spec.RunnerScaleSetName, RunnerGroupID: runnerGroupID, - Labels: []scaleset.Label{ - { - Name: autoscalingRunnerSet.Spec.RunnerScaleSetName, - Type: "System", - }, - }, + Labels: labels, RunnerSetting: scaleset.RunnerSetting{ DisableUpdate: true, }, From 7561b07453f88ce50c2647f7f6af2e1f3827a230 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Mon, 16 Mar 2026 15:15:42 +0100 Subject: [PATCH 2/5] Add e2e test --- .../custom-label-setup-v2.test.sh | 118 ++++++++++++++++++ .../custom-label-setup.test.sh | 117 +++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 test/actions.github.com/custom-label-setup-v2.test.sh create mode 100644 test/actions.github.com/custom-label-setup.test.sh diff --git a/test/actions.github.com/custom-label-setup-v2.test.sh b/test/actions.github.com/custom-label-setup-v2.test.sh new file mode 100644 index 0000000000..467986cb4d --- /dev/null +++ b/test/actions.github.com/custom-label-setup-v2.test.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +set -euo pipefail + +DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +ROOT_DIR="$(realpath "${DIR}/../..")" + +source "${DIR}/helper.sh" + +VERSION="$(chart_version "${ROOT_DIR}/charts/gha-runner-scale-set-controller-experimental/Chart.yaml")" || exit 1 +export VERSION + +SCALE_SET_NAME="custom-label-$(date +'%M%S')$(((RANDOM + 100) % 100 + 1))" +SCALE_SET_NAMESPACE="arc-runners" +SCALE_SET_LABEL="custom-$(date +'%s')${RANDOM}" +WORKFLOW_FILE="arc-custom-label.yaml" +WORKFLOW_REF="${WORKFLOW_REF:-nikola-jokic-patch-1}" +ARC_NAME="arc" +ARC_NAMESPACE="arc-systems" + +function install_arc() { + echo "Creating namespace ${ARC_NAMESPACE}" + kubectl create namespace "${SCALE_SET_NAMESPACE}" + + echo "Installing ARC" + helm install "${ARC_NAME}" \ + --namespace "${ARC_NAMESPACE}" \ + --create-namespace \ + --set controller.manager.container.image="${IMAGE_NAME}:${IMAGE_TAG}" \ + "${ROOT_DIR}/charts/gha-runner-scale-set-controller-experimental" \ + --debug + + if ! NAME="${ARC_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_arc; then + NAMESPACE="${ARC_NAMESPACE}" log_arc + return 1 + fi +} + +function install_scale_set() { + echo "Installing scale set ${SCALE_SET_NAMESPACE}/${SCALE_SET_NAME} with label ${SCALE_SET_LABEL}" + helm install "${SCALE_SET_NAME}" \ + --namespace "${SCALE_SET_NAMESPACE}" \ + --create-namespace \ + --set controllerServiceAccount.name="${ARC_NAME}-gha-rs-controller" \ + --set controllerServiceAccount.namespace="${ARC_NAMESPACE}" \ + --set auth.url="https://github.com/${TARGET_ORG}/${TARGET_REPO}" \ + --set auth.githubToken="${GITHUB_TOKEN}" \ + --set scaleset.labels[0]="${SCALE_SET_LABEL}" \ + "${ROOT_DIR}/charts/gha-runner-scale-set-experimental" \ + --version="${VERSION}" + + if ! NAME="${SCALE_SET_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_scale_set; then + NAMESPACE="${ARC_NAMESPACE}" log_arc + return 1 + fi +} + +function verify_scale_set_label() { + local actual_label + actual_label="$(kubectl get autoscalingrunnersets.actions.github.com -n "${SCALE_SET_NAMESPACE}" -l app.kubernetes.io/instance="${SCALE_SET_NAME}" -o jsonpath='{.items[0].spec.runnerScaleSetLabels[0]}')" + if [[ "${actual_label}" != "${SCALE_SET_LABEL}" ]]; then + echo "Expected scale set label '${SCALE_SET_LABEL}', got '${actual_label}'" >&2 + return 1 + fi +} + +function run_custom_label_workflow() { + local repo="${TARGET_ORG}/${TARGET_REPO}" + local queue_time + queue_time="$(date -u +%FT%TZ)" + + gh workflow run -R "${repo}" "${WORKFLOW_FILE}" \ + --ref "${WORKFLOW_REF}" \ + -f scaleset-label="${SCALE_SET_LABEL}" || return 1 + + local count=0 + local run_id= + while true; do + if [[ "${count}" -ge 12 ]]; then + echo "Timeout waiting for custom label workflow to start" >&2 + return 1 + fi + + run_id="$(gh run list -R "${repo}" --workflow "${WORKFLOW_FILE}" --branch "${WORKFLOW_REF}" --created ">${queue_time}" --json databaseId --jq '.[0].databaseId' | head -n1)" + if [[ -n "${run_id}" ]]; then + break + fi + + sleep 5 + count=$((count + 1)) + done + + gh run watch "${run_id}" -R "${repo}" --exit-status +} + +function main() { + local failed=() + + build_image + create_cluster + + install_arc + install_scale_set + verify_scale_set_label || failed+=("verify_scale_set_label") + + run_custom_label_workflow || failed+=("run_custom_label_workflow") + + INSTALLATION_NAME="${SCALE_SET_NAME}" NAMESPACE="${SCALE_SET_NAMESPACE}" cleanup_scale_set || failed+=("cleanup_scale_set") + + NAMESPACE="${ARC_NAMESPACE}" log_arc || failed+=("log_arc") + + delete_cluster + + print_results "${failed[@]}" +} + +main diff --git a/test/actions.github.com/custom-label-setup.test.sh b/test/actions.github.com/custom-label-setup.test.sh new file mode 100644 index 0000000000..06e35c7cd0 --- /dev/null +++ b/test/actions.github.com/custom-label-setup.test.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +set -euo pipefail + +DIR="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" + +ROOT_DIR="$(realpath "${DIR}/../..")" + +source "${DIR}/helper.sh" + +export VERSION="$(chart_version "${ROOT_DIR}/charts/gha-runner-scale-set-controller/Chart.yaml")" + +SCALE_SET_NAME="custom-label-$(date +'%M%S')$(((RANDOM + 100) % 100 + 1))" +SCALE_SET_NAMESPACE="arc-runners" +SCALE_SET_LABEL="custom-$(date +'%s')${RANDOM}" +WORKFLOW_FILE="arc-custom-label.yaml" +WORKFLOW_REF="${WORKFLOW_REF:-nikola-jokic-patch-1}" +ARC_NAME="arc" +ARC_NAMESPACE="arc-systems" + +function install_arc() { + echo "Creating namespace ${ARC_NAMESPACE}" + kubectl create namespace "${SCALE_SET_NAMESPACE}" + + echo "Installing ARC" + helm install "${ARC_NAME}" \ + --namespace "${ARC_NAMESPACE}" \ + --create-namespace \ + --set image.repository="${IMAGE_NAME}" \ + --set image.tag="${IMAGE_TAG}" \ + "${ROOT_DIR}/charts/gha-runner-scale-set-controller" \ + --debug + + if ! NAME="${ARC_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_arc; then + NAMESPACE="${ARC_NAMESPACE}" log_arc + return 1 + fi +} + +function install_scale_set() { + echo "Installing scale set ${SCALE_SET_NAMESPACE}/${SCALE_SET_NAME} with label ${SCALE_SET_LABEL}" + helm install "${SCALE_SET_NAME}" \ + --namespace "${SCALE_SET_NAMESPACE}" \ + --create-namespace \ + --set githubConfigUrl="https://github.com/${TARGET_ORG}/${TARGET_REPO}" \ + --set githubConfigSecret.github_token="${GITHUB_TOKEN}" \ + --set scaleSetLabels[0]="${SCALE_SET_LABEL}" \ + "${ROOT_DIR}/charts/gha-runner-scale-set" \ + --version="${VERSION}" \ + --debug + + if ! NAME="${SCALE_SET_NAME}" NAMESPACE="${ARC_NAMESPACE}" wait_for_scale_set; then + NAMESPACE="${ARC_NAMESPACE}" log_arc + return 1 + fi +} + +function verify_scale_set_label() { + local actual_label + actual_label="$(kubectl get autoscalingrunnersets.actions.github.com -n "${SCALE_SET_NAMESPACE}" -l app.kubernetes.io/instance="${SCALE_SET_NAME}" -o jsonpath='{.items[0].spec.runnerScaleSetLabels[0]}')" + if [[ "${actual_label}" != "${SCALE_SET_LABEL}" ]]; then + echo "Expected scale set label '${SCALE_SET_LABEL}', got '${actual_label}'" >&2 + return 1 + fi +} + +function run_custom_label_workflow() { + local repo="${TARGET_ORG}/${TARGET_REPO}" + local queue_time + queue_time="$(date -u +%FT%TZ)" + + gh workflow run -R "${repo}" "${WORKFLOW_FILE}" \ + --ref "${WORKFLOW_REF}" \ + -f scaleset-label="${SCALE_SET_LABEL}" || return 1 + + local count=0 + local run_id= + while true; do + if [[ "${count}" -ge 12 ]]; then + echo "Timeout waiting for custom label workflow to start" >&2 + return 1 + fi + + run_id="$(gh run list -R "${repo}" --workflow "${WORKFLOW_FILE}" --branch "${WORKFLOW_REF}" --created ">${queue_time}" --json databaseId --jq '.[0].databaseId' | head -n1)" + if [[ -n "${run_id}" ]]; then + break + fi + + sleep 5 + count=$((count + 1)) + done + + gh run watch "${run_id}" -R "${repo}" --exit-status +} + +function main() { + local failed=() + + build_image + create_cluster + + install_arc + install_scale_set + verify_scale_set_label || failed+=("verify_scale_set_label") + + run_custom_label_workflow || failed+=("run_custom_label_workflow") + + INSTALLATION_NAME="${SCALE_SET_NAME}" NAMESPACE="${SCALE_SET_NAMESPACE}" cleanup_scale_set || failed+=("cleanup_scale_set") + + NAMESPACE="${ARC_NAMESPACE}" log_arc || failed+=("log_arc") + + delete_cluster + + print_results "${failed[@]}" +} + +main \ No newline at end of file From 94092e96beb7c604f6eac021d637d3adee10e753 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Tue, 17 Mar 2026 00:16:58 +0100 Subject: [PATCH 3/5] fix perm --- test/actions.github.com/custom-label-setup-v2.test.sh | 4 +--- test/actions.github.com/custom-label-setup.test.sh | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) mode change 100644 => 100755 test/actions.github.com/custom-label-setup-v2.test.sh mode change 100644 => 100755 test/actions.github.com/custom-label-setup.test.sh diff --git a/test/actions.github.com/custom-label-setup-v2.test.sh b/test/actions.github.com/custom-label-setup-v2.test.sh old mode 100644 new mode 100755 index 467986cb4d..6235a78b24 --- a/test/actions.github.com/custom-label-setup-v2.test.sh +++ b/test/actions.github.com/custom-label-setup-v2.test.sh @@ -15,7 +15,6 @@ SCALE_SET_NAME="custom-label-$(date +'%M%S')$(((RANDOM + 100) % 100 + 1))" SCALE_SET_NAMESPACE="arc-runners" SCALE_SET_LABEL="custom-$(date +'%s')${RANDOM}" WORKFLOW_FILE="arc-custom-label.yaml" -WORKFLOW_REF="${WORKFLOW_REF:-nikola-jokic-patch-1}" ARC_NAME="arc" ARC_NAMESPACE="arc-systems" @@ -71,7 +70,6 @@ function run_custom_label_workflow() { queue_time="$(date -u +%FT%TZ)" gh workflow run -R "${repo}" "${WORKFLOW_FILE}" \ - --ref "${WORKFLOW_REF}" \ -f scaleset-label="${SCALE_SET_LABEL}" || return 1 local count=0 @@ -82,7 +80,7 @@ function run_custom_label_workflow() { return 1 fi - run_id="$(gh run list -R "${repo}" --workflow "${WORKFLOW_FILE}" --branch "${WORKFLOW_REF}" --created ">${queue_time}" --json databaseId --jq '.[0].databaseId' | head -n1)" + run_id="$(gh run list -R "${repo}" --workflow "${WORKFLOW_FILE}" --created ">${queue_time}" --json databaseId --jq '.[0].databaseId' | head -n1)" if [[ -n "${run_id}" ]]; then break fi diff --git a/test/actions.github.com/custom-label-setup.test.sh b/test/actions.github.com/custom-label-setup.test.sh old mode 100644 new mode 100755 index 06e35c7cd0..084365354d --- a/test/actions.github.com/custom-label-setup.test.sh +++ b/test/actions.github.com/custom-label-setup.test.sh @@ -14,7 +14,6 @@ SCALE_SET_NAME="custom-label-$(date +'%M%S')$(((RANDOM + 100) % 100 + 1))" SCALE_SET_NAMESPACE="arc-runners" SCALE_SET_LABEL="custom-$(date +'%s')${RANDOM}" WORKFLOW_FILE="arc-custom-label.yaml" -WORKFLOW_REF="${WORKFLOW_REF:-nikola-jokic-patch-1}" ARC_NAME="arc" ARC_NAMESPACE="arc-systems" @@ -70,7 +69,6 @@ function run_custom_label_workflow() { queue_time="$(date -u +%FT%TZ)" gh workflow run -R "${repo}" "${WORKFLOW_FILE}" \ - --ref "${WORKFLOW_REF}" \ -f scaleset-label="${SCALE_SET_LABEL}" || return 1 local count=0 @@ -81,7 +79,7 @@ function run_custom_label_workflow() { return 1 fi - run_id="$(gh run list -R "${repo}" --workflow "${WORKFLOW_FILE}" --branch "${WORKFLOW_REF}" --created ">${queue_time}" --json databaseId --jq '.[0].databaseId' | head -n1)" + run_id="$(gh run list -R "${repo}" --workflow "${WORKFLOW_FILE}" --created ">${queue_time}" --json databaseId --jq '.[0].databaseId' | head -n1)" if [[ -n "${run_id}" ]]; then break fi @@ -114,4 +112,4 @@ function main() { print_results "${failed[@]}" } -main \ No newline at end of file +main From ba73e39fa95ec23e618ba646148cae8d810440f2 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Tue, 17 Mar 2026 10:13:38 +0100 Subject: [PATCH 4/5] fix create ns --- test/actions.github.com/anonymous-proxy-setup-v2.test.sh | 3 --- test/actions.github.com/anonymous-proxy-setup.test.sh | 3 --- test/actions.github.com/auth-proxy-setup-v2.test.sh | 3 --- test/actions.github.com/auth-proxy-setup.test.sh | 3 --- test/actions.github.com/custom-label-setup-v2.test.sh | 3 --- test/actions.github.com/custom-label-setup.test.sh | 3 --- test/actions.github.com/default-setup-v2.test.sh | 3 --- test/actions.github.com/default-setup.test.sh | 3 --- test/actions.github.com/dind-mode-setup-v2.test.sh | 3 --- test/actions.github.com/dind-mode-setup.test.sh | 3 --- test/actions.github.com/kubernetes-mode-setup-v2.test.sh | 3 --- test/actions.github.com/kubernetes-mode-setup.test.sh | 3 --- test/actions.github.com/single-namespace-setup-v2.test.sh | 3 --- test/actions.github.com/single-namespace-setup.test.sh | 3 --- test/actions.github.com/update-strategy-v2.test.sh | 1 - test/actions.github.com/update-strategy.test.sh | 1 - 16 files changed, 44 deletions(-) diff --git a/test/actions.github.com/anonymous-proxy-setup-v2.test.sh b/test/actions.github.com/anonymous-proxy-setup-v2.test.sh index d8516ce410..696e1017d6 100755 --- a/test/actions.github.com/anonymous-proxy-setup-v2.test.sh +++ b/test/actions.github.com/anonymous-proxy-setup-v2.test.sh @@ -17,9 +17,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/anonymous-proxy-setup.test.sh b/test/actions.github.com/anonymous-proxy-setup.test.sh index 5c5cce3450..ff45710c0c 100755 --- a/test/actions.github.com/anonymous-proxy-setup.test.sh +++ b/test/actions.github.com/anonymous-proxy-setup.test.sh @@ -17,9 +17,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/auth-proxy-setup-v2.test.sh b/test/actions.github.com/auth-proxy-setup-v2.test.sh index 2c8b0e7d5a..630c59543f 100755 --- a/test/actions.github.com/auth-proxy-setup-v2.test.sh +++ b/test/actions.github.com/auth-proxy-setup-v2.test.sh @@ -22,9 +22,6 @@ function install_arc() { return 1 } - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/auth-proxy-setup.test.sh b/test/actions.github.com/auth-proxy-setup.test.sh index f52a065d79..179748de69 100755 --- a/test/actions.github.com/auth-proxy-setup.test.sh +++ b/test/actions.github.com/auth-proxy-setup.test.sh @@ -22,9 +22,6 @@ function install_arc() { return 1 } - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/custom-label-setup-v2.test.sh b/test/actions.github.com/custom-label-setup-v2.test.sh index 6235a78b24..c64855205f 100755 --- a/test/actions.github.com/custom-label-setup-v2.test.sh +++ b/test/actions.github.com/custom-label-setup-v2.test.sh @@ -19,9 +19,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/custom-label-setup.test.sh b/test/actions.github.com/custom-label-setup.test.sh index 084365354d..8295ec3e03 100755 --- a/test/actions.github.com/custom-label-setup.test.sh +++ b/test/actions.github.com/custom-label-setup.test.sh @@ -18,9 +18,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/default-setup-v2.test.sh b/test/actions.github.com/default-setup-v2.test.sh index a07dfd9344..921165fd4b 100755 --- a/test/actions.github.com/default-setup-v2.test.sh +++ b/test/actions.github.com/default-setup-v2.test.sh @@ -18,9 +18,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/default-setup.test.sh b/test/actions.github.com/default-setup.test.sh index 7d8b24e3cc..9a92a26069 100755 --- a/test/actions.github.com/default-setup.test.sh +++ b/test/actions.github.com/default-setup.test.sh @@ -17,9 +17,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/dind-mode-setup-v2.test.sh b/test/actions.github.com/dind-mode-setup-v2.test.sh index 7b2b800ff2..0e1a9ff680 100755 --- a/test/actions.github.com/dind-mode-setup-v2.test.sh +++ b/test/actions.github.com/dind-mode-setup-v2.test.sh @@ -17,9 +17,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/dind-mode-setup.test.sh b/test/actions.github.com/dind-mode-setup.test.sh index 19cf04a724..deb9b75d8d 100755 --- a/test/actions.github.com/dind-mode-setup.test.sh +++ b/test/actions.github.com/dind-mode-setup.test.sh @@ -17,9 +17,6 @@ ARC_NAME="arc" ARC_NAMESPACE="arc-systems" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/kubernetes-mode-setup-v2.test.sh b/test/actions.github.com/kubernetes-mode-setup-v2.test.sh index 0fa2a3c703..7a388296af 100755 --- a/test/actions.github.com/kubernetes-mode-setup-v2.test.sh +++ b/test/actions.github.com/kubernetes-mode-setup-v2.test.sh @@ -22,9 +22,6 @@ function install_arc() { return 1 } - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/kubernetes-mode-setup.test.sh b/test/actions.github.com/kubernetes-mode-setup.test.sh index 42697156c8..aa9b52b334 100755 --- a/test/actions.github.com/kubernetes-mode-setup.test.sh +++ b/test/actions.github.com/kubernetes-mode-setup.test.sh @@ -22,9 +22,6 @@ function install_arc() { return 1 } - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/single-namespace-setup-v2.test.sh b/test/actions.github.com/single-namespace-setup-v2.test.sh index bdd8aa6550..382953bddb 100755 --- a/test/actions.github.com/single-namespace-setup-v2.test.sh +++ b/test/actions.github.com/single-namespace-setup-v2.test.sh @@ -17,9 +17,6 @@ ARC_NAME="arc" ARC_NAMESPACE="${SCALE_SET_NAMESPACE}" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/single-namespace-setup.test.sh b/test/actions.github.com/single-namespace-setup.test.sh index 0a28f525f2..836dfe7446 100755 --- a/test/actions.github.com/single-namespace-setup.test.sh +++ b/test/actions.github.com/single-namespace-setup.test.sh @@ -17,9 +17,6 @@ ARC_NAME="arc" ARC_NAMESPACE="${SCALE_SET_NAMESPACE}" function install_arc() { - echo "Creating namespace ${ARC_NAMESPACE}" - kubectl create namespace "${SCALE_SET_NAMESPACE}" - echo "Installing ARC" helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ diff --git a/test/actions.github.com/update-strategy-v2.test.sh b/test/actions.github.com/update-strategy-v2.test.sh index 2ac2f2ada0..8d27a64509 100755 --- a/test/actions.github.com/update-strategy-v2.test.sh +++ b/test/actions.github.com/update-strategy-v2.test.sh @@ -21,7 +21,6 @@ ARC_NAMESPACE="arc-systems" function install_arc() { echo "Installing ARC" - helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ --create-namespace \ diff --git a/test/actions.github.com/update-strategy.test.sh b/test/actions.github.com/update-strategy.test.sh index 2e966a6736..7ddff6e9ee 100755 --- a/test/actions.github.com/update-strategy.test.sh +++ b/test/actions.github.com/update-strategy.test.sh @@ -21,7 +21,6 @@ ARC_NAMESPACE="arc-systems" function install_arc() { echo "Installing ARC" - helm install "${ARC_NAME}" \ --namespace "${ARC_NAMESPACE}" \ --create-namespace \ From d479af7342eaedbd0c76df67b3531267b8c54471 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Thu, 19 Mar 2026 12:48:11 +0100 Subject: [PATCH 5/5] Add helm checks for label constraints --- .../templates/autoscalingrunnserset.yaml | 8 +++++ ...ling_runner_set_scale_set_labels_test.yaml | 36 ++++++++++++++++++- .../templates/autoscalingrunnerset.yaml | 8 +++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml b/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml index f0d2c8a43c..b0e60c1ffd 100644 --- a/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml +++ b/charts/gha-runner-scale-set-experimental/templates/autoscalingrunnserset.yaml @@ -84,6 +84,14 @@ spec: runnerGroup: {{ .Values.scaleset.runnerGroup | quote }} runnerScaleSetName: {{ .Values.scaleset.name | quote }} {{- if and .Values.scaleset.labels (kindIs "slice" .Values.scaleset.labels) }} + {{- range .Values.scaleset.labels }} + {{- if empty . }} + {{- fail "scaleset.labels contains an empty string, each label must be a non-empty string of less than 256 characters" }} + {{- end }} + {{- if ge (len .) 256 }} + {{- fail "scaleset.labels contains a label that is 256 characters or more, each label must be a non-empty string of less than 256 characters" }} + {{- end }} + {{- end }} runnerScaleSetLabels: {{- toYaml .Values.scaleset.labels | nindent 4 }} {{- end }} diff --git a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml index 6176694bc1..b8fb8d9ecd 100644 --- a/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml +++ b/charts/gha-runner-scale-set-experimental/tests/autoscaling_runner_set_scale_set_labels_test.yaml @@ -21,4 +21,38 @@ tests: value: "linux" - equal: path: spec.runnerScaleSetLabels[1] - value: "x64" \ No newline at end of file + value: "x64" + + - it: should fail when a scaleset label is empty + set: + scaleset.name: "test" + scaleset.labels: + - "linux" + - "" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: "scaleset.labels contains an empty string, each label must be a non-empty string of less than 256 characters" + + - it: should fail when a scaleset label is 256 characters or more + set: + scaleset.name: "test" + scaleset.labels: + - "linux" + - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + auth.url: "https://github.com/org" + auth.githubToken: "gh_token12345" + controllerServiceAccount.name: "arc" + controllerServiceAccount.namespace: "arc-system" + release: + name: "test-name" + namespace: "test-namespace" + asserts: + - failedTemplate: + errorMessage: "scaleset.labels contains a label that is 256 characters or more, each label must be a non-empty string of less than 256 characters" \ No newline at end of file diff --git a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml index 0771e9c9a6..384395b896 100644 --- a/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml +++ b/charts/gha-runner-scale-set/templates/autoscalingrunnerset.yaml @@ -75,6 +75,14 @@ spec: runnerScaleSetName: {{ . }} {{- end }} {{- if and .Values.scaleSetLabels (kindIs "slice" .Values.scaleSetLabels) }} + {{- range .Values.scaleSetLabels }} + {{- if empty . }} + {{- fail "scaleSetLabels contains an empty string, each label must be a non-empty string of less than 256 characters" }} + {{- end }} + {{- if ge (len .) 256 }} + {{- fail "scaleSetLabels contains a label that is 256 characters or more, each label must be a non-empty string of less than 256 characters" }} + {{- end }} + {{- end }} runnerScaleSetLabels: {{- toYaml .Values.scaleSetLabels | nindent 4 }} {{- end }}