diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b0b578f..7b73783 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -25,7 +25,7 @@ jobs: go-version-file: 'go.mod' - name: lint run: | - go install honnef.co/go/tools/cmd/staticcheck@latest + go install honnef.co/go/tools/cmd/staticcheck@v0.7.0 staticcheck ./... - name: vet run: | @@ -44,4 +44,3 @@ jobs: uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: push: false - tags: ${{ steps.meta.outputs.tags }} diff --git a/pkg/starter/scripts.go b/pkg/starter/scripts.go index 0ca78fd..86db9af 100644 --- a/pkg/starter/scripts.go +++ b/pkg/starter/scripts.go @@ -353,7 +353,11 @@ fi # insert anything to setup env when running as a service # run the host process which keep the listener alive -NODE_PATH="./externals/node20/bin/node" +# Prefer Node 24, retaining support for older runner distributions. +NODE_PATH="./externals/node24/bin/node" +if [ ! -e "\${NODE_PATH}" ]; then + NODE_PATH="./externals/node20/bin/node" +fi if [ ! -e "\${NODE_PATH}" ]; then NODE_PATH="./externals/node16/bin/node" fi diff --git a/pkg/starter/scripts_test.go b/pkg/starter/scripts_test.go new file mode 100644 index 0000000..ef6a585 --- /dev/null +++ b/pkg/starter/scripts_test.go @@ -0,0 +1,78 @@ +package starter + +import ( + "bytes" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "text/template" +) + +func TestRunnerServiceNodeRuntime(t *testing.T) { + var rendered bytes.Buffer + tmpl, err := template.New("setup").Parse(templateCreateLatestRunnerOnce) + if err != nil { + t.Fatal(err) + } + if err := tmpl.Execute(&rendered, templateCreateLatestRunnerOnceValue{}); err != nil { + t.Fatal(err) + } + + // Execute the actual heredoc so expansion happens at setup time, then run + // the generated service script against the runtimes bundled with a runner. + const start = "cat << EOF > ./bin/runsvc.sh\n" + _, patch, ok := strings.Cut(rendered.String(), start) + if !ok { + t.Fatal("service script heredoc not found") + } + body, _, ok := strings.Cut(patch, "\nEOF\n") + if !ok { + t.Fatal("service script heredoc terminator not found") + } + + for _, tc := range []struct { + name string + runtimes []string + want string + }{ + {"prefer node24", []string{"node24", "node20", "node16"}, "node24"}, + {"node24 only", []string{"node24"}, "node24"}, + {"fallback to node20", []string{"node20", "node16"}, "node20"}, + {"node20 only", []string{"node20"}, "node20"}, + {"fallback to node16", []string{"node16"}, "node16"}, + } { + t.Run(tc.name, func(t *testing.T) { + dir := t.TempDir() + if err := os.MkdirAll(filepath.Join(dir, "bin"), 0755); err != nil { + t.Fatal(err) + } + for _, runtime := range tc.runtimes { + path := filepath.Join(dir, "externals", runtime, "bin", "node") + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + t.Fatal(err) + } + stub := "#!/bin/bash\nprintf '%s\\n' '" + runtime + "' \"$@\"\n" + if err := os.WriteFile(path, []byte(stub), 0755); err != nil { + t.Fatal(err) + } + } + setup := exec.Command("bash", "-c", start+body+"\nEOF\n") + setup.Dir = dir + if output, err := setup.CombinedOutput(); err != nil { + t.Fatalf("generate service script: %v\n%s", err, output) + } + service := exec.Command("bash", "./bin/runsvc.sh", "--once") + service.Dir = dir + output, err := service.CombinedOutput() + if err != nil { + t.Fatalf("run service script: %v\n%s", err, output) + } + want := tc.want + "\n./bin/RunnerService.js\n--once\n" + if string(output) != want { + t.Fatalf("service invocation = %q, want %q", output, want) + } + }) + } +}