Skip to content

Commit 675192f

Browse files
RothAndrewzachariahmillerRacer159
authored
feat: add support for --with CLI flag for task inputs (#184)
## Description Re-introduced the `--with` command line flag to allow passing task inputs directly via the CLI. Updated the runner logic, tests, and documentation to ensure proper handling and validation of inputs provided through this flag. This enhances flexibility when defining and running tasks. ... ## Related Issue Fixes #17 ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [X] New feature (non-breaking change which adds functionality) - [ ] Other (security config, docs update, etc) ## Checklist before merging - [X] Test, docs, adr added or updated as needed - [X] [Contributor Guide Steps](https://github.com/defenseunicorns/maru-runner/blob/main/CONTRIBUTING.md) followed --------- Co-authored-by: zamaz <[email protected]> Co-authored-by: Wayne Starr <[email protected]>
1 parent 5026635 commit 675192f

File tree

7 files changed

+66
-11
lines changed

7 files changed

+66
-11
lines changed

README.md

+18-1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ Variables can be defined in several ways:
217217
setVariables:
218218
- name: FOO
219219
- cmd: echo ${FOO}
220+
# Or drop the curly brackets
221+
- cmd: echo $FOO
222+
# Or use template syntax
223+
- cmd: echo ${{ .variables.FOO }}
220224
```
221225

222226
1. As an environment variable prefixed with `MARU_`. In the example above, if you create an env var `MARU_FOO=bar`, then the`FOO` variable would be set to `bar`.
@@ -374,6 +378,8 @@ tasks:
374378
actions:
375379
# to use the input, reference it using INPUT_<INPUT_NAME> in all caps
376380
- cmd: echo $INPUT_HELLO_INPUT
381+
# or use template syntax
382+
- cmd: echo ${{ .inputs.hello-input }}
377383
378384
- name: use-echo-var
379385
actions:
@@ -412,4 +418,15 @@ tasks:
412418
hello-input: hello unicorn
413419
```
414420

415-
Running `run len` will print the length of the inputs to `hello-input` and `another-input` to the console.
421+
Running `maru run len` will print the length of the inputs to `hello-input` and `another-input` to the console.
422+
423+
#### Command Line Flags
424+
425+
> [!NOTE]
426+
> The `--with` command line flag is experimental and likely to change as part of a comprehensive overhaul of the inputs/variables design.
427+
428+
When creating a task with `inputs` you can also use the `--with` command line flag. Given the `length-of-inputs` task documented above, you can also run:
429+
430+
```shell
431+
maru run length-of-inputs --with hello-input="hello unicorn"
432+
```

src/cmd/run.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ var dryRun bool
5858
// setRunnerVariables provides a map of set variables from the command line
5959
var setRunnerVariables map[string]string
6060

61+
// withRunnerInputs provides a map of --with inputs from the command line
62+
var withRunnerInputs map[string]string
63+
6164
var runCmd = &cobra.Command{
6265
Use: "run",
6366
PersistentPreRun: func(_ *cobra.Command, _ []string) {
@@ -136,7 +139,7 @@ var runCmd = &cobra.Command{
136139
if len(args) > 0 {
137140
taskName = args[0]
138141
}
139-
if err := runner.Run(tasksFile, taskName, setRunnerVariables, dryRun, auth); err != nil {
142+
if err := runner.Run(tasksFile, taskName, setRunnerVariables, withRunnerInputs, dryRun, auth); err != nil {
140143
message.Fatalf(err, "Failed to run action: %s", err.Error())
141144
}
142145
},
@@ -213,4 +216,6 @@ func init() {
213216
runFlags.AddFlag(listAllPFlag)
214217

215218
runFlags.StringToStringVar(&setRunnerVariables, "set", nil, lang.CmdRunSetVarFlag)
219+
220+
runFlags.StringToStringVar(&withRunnerInputs, "with", nil, lang.CmdRunWithVarFlag)
216221
}

src/config/lang/english.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const (
4949
CmdRunShort = "Runs a specified task from a task file"
5050
CmdRunFlag = "Name and location of task file to run"
5151
CmdRunSetVarFlag = "Set a runner variable from the command line (KEY=value)"
52-
CmdRunWithVarFlag = "Set the inputs for a task from the command line (KEY=value)"
52+
CmdRunWithVarFlag = "(experimental) Set the inputs for a task from the command line (KEY=value)"
5353
CmdRunList = "List available tasks in a task file"
5454
CmdRunListAll = "List all available tasks in a task file, including tasks from included files"
5555
CmdRunDryRun = "Validate the task without actually running any commands"

src/pkg/runner/runner.go

+15-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type Runner struct {
3030
}
3131

3232
// Run runs a task from tasks file
33-
func Run(tasksFile types.TasksFile, taskName string, setVariables map[string]string, dryRun bool, auth map[string]string) error {
33+
func Run(tasksFile types.TasksFile, taskName string, setVariables map[string]string, withInputs map[string]string, dryRun bool, auth map[string]string) error {
3434
if dryRun {
3535
message.SLog.Info("Dry-run has been set - only printing the commands that would run:")
3636
}
@@ -73,16 +73,16 @@ func Run(tasksFile types.TasksFile, taskName string, setVariables map[string]str
7373
return err
7474
}
7575

76-
// Check that this task is a valid task we can call (i.e. has defaults for any inputs since those cannot be set on the CLI)
77-
if err := validateActionableTaskCall(task.Name, task.Inputs, nil); err != nil {
76+
// Check that this task is a valid task we can call (i.e. has defaults for any unset inputs)
77+
if err := validateActionableTaskCall(task.Name, task.Inputs, withInputs); err != nil {
7878
return err
7979
}
8080

8181
if err = runner.processTaskReferences(task, runner.tasksFile, setVariables); err != nil {
8282
return err
8383
}
8484

85-
err = runner.executeTask(task, nil)
85+
err = runner.executeTask(task, withInputs)
8686
return err
8787
}
8888

@@ -278,13 +278,21 @@ func (r *Runner) executeTask(task types.Task, withs map[string]string) error {
278278
r.currStackSize--
279279
}()
280280

281-
defaultEnv := []string{}
281+
env := []string{}
282+
// Load the withs
283+
for name, value := range withs {
284+
env = append(env, utils.FormatEnvVar(name, value))
285+
}
286+
// load the default for each input if it has one and it isn't already set from withs
282287
for name, inputParam := range task.Inputs {
288+
if _, ok := withs[name]; ok {
289+
continue
290+
}
283291
d := inputParam.Default
284292
if d == "" {
285293
continue
286294
}
287-
defaultEnv = append(defaultEnv, utils.FormatEnvVar(name, d))
295+
env = append(env, utils.FormatEnvVar(name, d))
288296
}
289297

290298
// load the tasks env file into the runner, can override previous task's env files
@@ -293,7 +301,7 @@ func (r *Runner) executeTask(task types.Task, withs map[string]string) error {
293301
}
294302

295303
for _, action := range task.Actions {
296-
action.Env = utils.MergeEnv(action.Env, defaultEnv)
304+
action.Env = utils.MergeEnv(action.Env, env)
297305
if err := r.performAction(action, withs, task.Inputs); err != nil {
298306
return err
299307
}

src/test/e2e/runner_inputs_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,10 @@ func TestRunnerInputs(t *testing.T) {
152152
require.NoError(t, err, stdOut, stdErr)
153153
require.Contains(t, stdErr, "default-value")
154154
})
155+
156+
t.Run("test that using the --with command line flag works", func(t *testing.T) {
157+
stdOut, stdErr, err := e2e.Maru("run", "with:command-line-with", "--file", "src/test/tasks/inputs/tasks.yaml", "--with", "input1=input1", "--with", "input3=notthedefault", "--set", "FOO=baz")
158+
require.NoError(t, err, stdOut, stdErr)
159+
require.Contains(t, stdErr, "Input1Tmpl: input1 Input1Env: input1 Input2Tmpl: input2 Input2Env: input2 Input3Tmpl: notthedefault Input3Env: notthedefault Var: baz")
160+
})
155161
}

src/test/tasks/inputs/tasks-with-inputs.yaml

+18
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,21 @@ tasks:
5959
- name: echo-bar
6060
actions:
6161
- cmd: echo $BAR
62+
63+
- name: command-line-with
64+
description: Test task that uses the --with flag on the command line
65+
inputs:
66+
input1:
67+
description: some input
68+
required: true
69+
input2:
70+
description: some input
71+
required: false
72+
default: input2
73+
input3:
74+
description: some input
75+
required: false
76+
default: input3
77+
actions:
78+
- cmd: |
79+
echo "Input1Tmpl: ${{ .inputs.input1 }} Input1Env: $INPUT_INPUT1 Input2Tmpl: ${{ .inputs.input2 }} Input2Env: ${INPUT_INPUT2} Input3Tmpl: ${{ .inputs.input3 }} Input3Env: $INPUT_INPUT3 Var: $FOO"

src/test/tasks/tasks.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
# yaml-language-server: $schema=../../../tasks.schema.json
12
includes:
23
- foo: ./more-tasks/foo.yaml
34
- intentional: ./loop-task.yaml
45
- remote: https://raw.githubusercontent.com/defenseunicorns/maru-runner/${GIT_REVISION}/src/test/tasks/remote-import-tasks.yaml
56
# This tests that Maru uses the correct Accept Header for the GitHub API when that is used
67
- remote-api: https://api.github.com/repos/defenseunicorns/maru-runner/contents/src/test/tasks/tasks-no-default.yaml?ref=${GIT_REVISION}
7-
# This tests that Maru properly handles authenitcation and GitLab paths (which are URL encoded)
8+
# This tests that Maru properly handles authentication and GitLab paths (which are URL encoded)
89
- remote-gitlab: https://gitlab.com/api/v4/projects/66014760/repository/files/tasks%2Eyaml/raw
910

1011
variables:

0 commit comments

Comments
 (0)