From 610358e1c37630598e5d5022089bc43274ccc997 Mon Sep 17 00:00:00 2001 From: Jon Jensen Date: Sun, 12 Nov 2023 12:40:06 -0500 Subject: [PATCH] Support array expressions in runs-on (#2088) * Support array expressions in runs-on * Simplify appproach to use EvaluateYamlNode, fix case-sensitivity bug --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- cmd/platforms.go | 2 +- pkg/runner/run_context.go | 36 ++++++++++++++------------ pkg/runner/run_context_test.go | 47 ++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/cmd/platforms.go b/cmd/platforms.go index 9d7e97a8..45724d75 100644 --- a/cmd/platforms.go +++ b/cmd/platforms.go @@ -15,7 +15,7 @@ func (i *Input) newPlatforms() map[string]string { for _, p := range i.platforms { pParts := strings.Split(p, "=") if len(pParts) == 2 { - platforms[pParts[0]] = pParts[1] + platforms[strings.ToLower(pParts[0])] = pParts[1] } } return platforms diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index a69abc6e..faf64e11 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -626,14 +626,7 @@ func (rc *RunContext) containerImage(ctx context.Context) string { } func (rc *RunContext) runsOnImage(ctx context.Context) string { - job := rc.Run.Job() - - if job.RunsOn() == nil { - common.Logger(ctx).Errorf("'runs-on' key not defined in %s", rc.String()) - } - - for _, runnerLabel := range job.RunsOn() { - platformName := rc.ExprEval.Interpolate(ctx, runnerLabel) + for _, platformName := range rc.runsOnPlatformNames(ctx) { image := rc.Config.Platforms[strings.ToLower(platformName)] if image != "" { return image @@ -643,6 +636,22 @@ func (rc *RunContext) runsOnImage(ctx context.Context) string { return "" } +func (rc *RunContext) runsOnPlatformNames(ctx context.Context) []string { + job := rc.Run.Job() + + if job.RunsOn() == nil { + common.Logger(ctx).Errorf("'runs-on' key not defined in %s", rc.String()) + return []string{} + } + + if err := rc.ExprEval.EvaluateYamlNode(ctx, &job.RawRunsOn); err != nil { + common.Logger(ctx).Errorf("Error while evaluating runs-on: %v", err) + return []string{} + } + + return job.RunsOn() +} + func (rc *RunContext) platformImage(ctx context.Context) string { if containerImage := rc.containerImage(ctx); containerImage != "" { return containerImage @@ -684,12 +693,7 @@ func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) { img := rc.platformImage(ctx) if img == "" { - if job.RunsOn() == nil { - l.Errorf("'runs-on' key not defined in %s", rc.String()) - } - - for _, runnerLabel := range job.RunsOn() { - platformName := rc.ExprEval.Interpolate(ctx, runnerLabel) + for _, platformName := range rc.runsOnPlatformNames(ctx) { l.Infof("\U0001F6A7 Skipping unsupported platform -- Try running with `-P %+v=...`", platformName) } return false, nil @@ -923,9 +927,7 @@ func (rc *RunContext) withGithubEnv(ctx context.Context, github *model.GithubCon setActionRuntimeVars(rc, env) } - job := rc.Run.Job() - for _, runnerLabel := range job.RunsOn() { - platformName := rc.ExprEval.Interpolate(ctx, runnerLabel) + for _, platformName := range rc.runsOnPlatformNames(ctx) { if platformName != "" { if platformName == "ubuntu-latest" { // hardcode current ubuntu-latest since we have no way to check that 'on the fly' diff --git a/pkg/runner/run_context_test.go b/pkg/runner/run_context_test.go index 3e26a022..8ab643ec 100644 --- a/pkg/runner/run_context_test.go +++ b/pkg/runner/run_context_test.go @@ -470,6 +470,53 @@ func createJob(t *testing.T, input string, result string) *model.Job { return job } +func TestRunContextRunsOnPlatformNames(t *testing.T) { + log.SetLevel(log.DebugLevel) + assertObject := assert.New(t) + + rc := createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `runs-on: ubuntu-latest`, ""), + }) + assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background())) + + rc = createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `runs-on: ${{ 'ubuntu-latest' }}`, ""), + }) + assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background())) + + rc = createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `runs-on: [self-hosted, my-runner]`, ""), + }) + assertObject.Equal([]string{"self-hosted", "my-runner"}, rc.runsOnPlatformNames(context.Background())) + + rc = createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `runs-on: [self-hosted, "${{ 'my-runner' }}"]`, ""), + }) + assertObject.Equal([]string{"self-hosted", "my-runner"}, rc.runsOnPlatformNames(context.Background())) + + rc = createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `runs-on: ${{ fromJSON('["ubuntu-latest"]') }}`, ""), + }) + assertObject.Equal([]string{"ubuntu-latest"}, rc.runsOnPlatformNames(context.Background())) + + // test missing / invalid runs-on + rc = createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `name: something`, ""), + }) + assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background())) + + rc = createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `runs-on: + mapping: value`, ""), + }) + assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background())) + + rc = createIfTestRunContext(map[string]*model.Job{ + "job1": createJob(t, `runs-on: ${{ invalid expression }}`, ""), + }) + assertObject.Equal([]string{}, rc.runsOnPlatformNames(context.Background())) +} + func TestRunContextIsEnabled(t *testing.T) { log.SetLevel(log.DebugLevel) assertObject := assert.New(t)