Skip to content

Commit

Permalink
run: add --fail-fast parameter
Browse files Browse the repository at this point in the history
Add a "--fail-fast" parameter to "baur run".
By default it is enabled.
If disabled and multiple tasks are run a failed task run won't cause
that further runs are skipped.
  • Loading branch information
fho committed Nov 12, 2024
1 parent 0c655e2 commit 2718dae
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 8 deletions.
16 changes: 11 additions & 5 deletions internal/command/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type runCmd struct {
// Cmdline parameters
skipUpload bool
force bool
failFast bool
inputStr []string
lookupInputStr string
taskRunnerGoRoutines uint
Expand Down Expand Up @@ -127,6 +128,8 @@ func newRunCmd() *runCmd {
"skip uploading task outputs and recording the run")
cmd.Flags().BoolVarP(&cmd.force, "force", "f", false,
"enforce running tasks independent of their status")
cmd.Flags().BoolVar(&cmd.failFast, "fail-fast", true,
"skip execution of queued tasks and terminate when a task run fails")
cmd.Flags().StringArrayVar(&cmd.inputStr, "input-str", nil,
"include a string as input, can be specified multiple times")
cmd.Flags().StringVar(&cmd.lookupInputStr, "lookup-input-str", "",
Expand Down Expand Up @@ -183,6 +186,7 @@ func (c *runCmd) run(_ *cobra.Command, args []string) {
c.taskRunnerRoutinePool = routines.NewPool(c.taskRunnerGoRoutines)
c.taskRunner = baur.NewTaskRunner(
baur.NewTaskInfoCreator(c.storage, taskStatusEvaluator),
c.failFast,
)

if c.showOutput && !verboseFlag {
Expand Down Expand Up @@ -297,13 +301,15 @@ func (c *runCmd) run(_ *cobra.Command, args []string) {
func (c *runCmd) skipAllScheduledTaskRuns() {
c.skipAllScheduledTaskRunsOnce.Do(func() {
c.taskRunner.SkipRuns(true)

c.errorHappened = true
if c.failFast {
stderr.Printf("%s, %s execution of queued task runs\n",
term.RedHighlight("terminating"),
term.YellowHighlight("skipping"),
)

stderr.Printf("%s, %s execution of queued task runs\n",
term.RedHighlight("terminating"),
term.YellowHighlight("skipping"),
)
return
}
})
}

Expand Down
54 changes: 54 additions & 0 deletions internal/command/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,57 @@ func TestRunAbortsAfterError(t *testing.T) {
assert.Contains(t, stderr.String(), "terminating, skipping execution of queued task runs")
assert.Contains(t, stderr.String(), "testapp.xbuild: execution skipped")
}

func TestRunFailFastDisabledContinuesAfterError(t *testing.T) {
initTest(t)
r := repotest.CreateBaurRepository(t, repotest.WithNewDB())

appCfg := cfg.App{
Name: "testapp",
Tasks: cfg.Tasks{
{
Name: "build",
Command: []string{"bash", "-c", "exit 1"},
Input: cfg.Input{
Files: []cfg.FileInputs{
{Paths: []string{".app.toml"}},
},
},
},
{
Name: "xbuild",
Command: []string{"bash", "-c", "exit 0"},
Input: cfg.Input{
Files: []cfg.FileInputs{
{Paths: []string{".app.toml"}},
},
},
},
},
}

err := appCfg.ToFile(filepath.Join(r.Dir, ".app.toml"))
require.NoError(t, err)

doInitDb(t)

runCmdTest := newRunCmd()
runCmdTest.SetArgs([]string{"--fail-fast=false"})
stdout, stderr := interceptCmdOutput(t)

oldExitFunc := exitFunc
var exitCode int
exitFunc = func(code int) {
exitCode = code
}
t.Cleanup(func() {
exitFunc = oldExitFunc
})

err = runCmdTest.Execute()
require.NoError(t, err)
assert.Equal(t, 1, exitCode)

assert.Regexp(t, "^testapp.build.*failed: exit status 1", stderr.String())
assert.Contains(t, stdout.String(), "testapp.xbuild: run stored in database")
}
6 changes: 4 additions & 2 deletions pkg/baur/taskrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,18 @@ type TaskInfoRetriever interface {

// TaskRunner executes the command of a task.
type TaskRunner struct {
skipAfterError bool
skipEnabled uint32 // must be accessed via atomic operations
LogFn exec.PrintfFn
GitUntrackedFilesFn func(dir string) ([]string, error)
taskInfoCreator *TaskInfoCreator
}

func NewTaskRunner(taskInfoCreator *TaskInfoCreator) *TaskRunner {
func NewTaskRunner(taskInfoCreator *TaskInfoCreator, skipAfterError bool) *TaskRunner {
return &TaskRunner{
LogFn: exec.DefaultLogFn,
taskInfoCreator: taskInfoCreator,
skipAfterError: skipAfterError,
}
}

Expand Down Expand Up @@ -90,7 +92,7 @@ func (t *TaskRunner) createTaskInfoEnv(ctx context.Context, task *Task) ([]strin
// Run executes the command of a task and returns the execution result.
// The output of the commands are logged with debug log level.
func (t *TaskRunner) Run(task *Task) (*RunResult, error) {
if t.SkipRunsIsEnabled() {
if t.skipAfterError && t.SkipRunsIsEnabled() {
return nil, ErrTaskRunSkipped
}
if t.GitUntrackedFilesFn != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/baur/taskrunner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func TestRunningTaskFailsWhenGitWorktreeIsDirty(t *testing.T) {
tr := NewTaskRunner(nil)
tr := NewTaskRunner(nil, true)
tr.GitUntrackedFilesFn = func(_ string) ([]string, error) {
return []string{"1"}, nil
}
Expand Down

0 comments on commit 2718dae

Please sign in to comment.