Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task semantics behaviour #276

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bob.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@ variables:

build:
build:
input: "*"
cmd: go build -tags dev -ldflags="-X 'main.Version=${VERSION}'" -o ./run
target: run
dependson:
- proto

gomodtidy:
input: "*"
cmd: go mod tidy

lint:
input: "*"
cmd: CGO_ENABLED=0 golangci-lint run --timeout=10m0s

test:
input: "*"
cmd: go test ./...

proto:
Expand Down
4 changes: 2 additions & 2 deletions bob/aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ func (b *B) Aggregate() (aggregate *bobfile.Bobfile, err error) {
aggregate.Project = aggregate.Dir()
}

err = aggregate.Verify()
err = aggregate.Verify(b.enableCaching, b.enableRedundantTargets)
errz.Fatal(err)

err = aggregate.BTasks.IgnoreChildTargets()
Expand Down Expand Up @@ -246,7 +246,7 @@ func collectDecorations(ag *bobfile.Bobfile) (_ map[string][]string, err error)
if !task.IsDecoration() {
continue
}
if !task.IsValidDecoration() {
if !task.IsCompoundTask() {
errz.Fatal(usererror.Wrap(fmt.Errorf("task `%s` modifies an imported task. It can only contain a `dependsOn` property", k)))
}
decorations[k] = task.DependsOn
Expand Down
12 changes: 6 additions & 6 deletions bob/aggregate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func benchmarkAggregate(b *testing.B, ignoredMultiplier int) {
}

// createFileSturcture creates a deep file structure.
// `multiplier`` is the number of directorys created containing the structure.
// `multiplier is the number of directorys created containing the structure.
func createFileSturcture(dir string, multiplier int) error {
for i := 0; i < multiplier; i++ {
// create parent
Expand Down Expand Up @@ -142,7 +142,7 @@ func createFileSturcture(dir string, multiplier int) error {
}

// createIgnoreFileSturcture creates a deep file structure witch must be ignored by Aggregate().
// `multiplier`` is the number of directorys created containing the structure.
// `multiplier is the number of directorys created containing the structure.
func createIgnoreFileSturcture(dir string, multiplier int) error {
for i := 0; i < multiplier; i++ {
// create parent
Expand Down Expand Up @@ -190,7 +190,7 @@ func TestEmptyProjectName(t *testing.T) {
err = os.Chdir(dir)
assert.Nil(t, err)

testBob, err := Bob(WithDir(dir))
testBob, err := Bob(WithDir(dir), WithEnableRedundantTargets())
assert.Nil(t, err)

err = CreatePlayground(PlaygroundOptions{Dir: dir})
Expand All @@ -213,7 +213,7 @@ func TestProjectName(t *testing.T) {
err = os.Chdir(dir)
assert.Nil(t, err)

testBob, err := Bob(WithDir(dir))
testBob, err := Bob(WithDir(dir), WithEnableRedundantTargets())
assert.Nil(t, err)

projectName := "example.com/test-user/test-project"
Expand All @@ -240,7 +240,7 @@ func TestInvalidProjectName(t *testing.T) {
err = os.Chdir(dir)
assert.Nil(t, err)

testBob, err := Bob(WithDir(dir))
testBob, err := Bob(WithDir(dir), WithEnableRedundantTargets())
assert.Nil(t, err)

projectName := "@"
Expand Down Expand Up @@ -333,7 +333,7 @@ func TestMultiLevelBobfileSameProjectName(t *testing.T) {
err = os.Chdir(dir)
assert.Nil(t, err)

testBob, err := Bob(WithDir(dir))
testBob, err := Bob(WithDir(dir), WithEnableRedundantTargets())
assert.Nil(t, err)

projectName := "first-level"
Expand Down
5 changes: 5 additions & 0 deletions bob/bob.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ type B struct {
// from the cache Default: true
enableCaching bool

// enableRedundantTargets option allows redundant targets on build tasks
// a task has redundant target when it has a `target` used in combination with `rebuild:always`
// by default a user error will return when a task has both `target` and `rebuild:always` defined
enableRedundantTargets bool

// allowInsecure uses http protocol for accessing the remote artifact store, if any
allowInsecure bool

Expand Down
16 changes: 7 additions & 9 deletions bob/bobfile/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@ import (
)

// Verify a bobfile before task runner.
func (b *Bobfile) Verify() error {
return b.verifyBefore()
}

// VerifyBefore a bobfile before task runner.
func (b *Bobfile) VerifyBefore() error {
return b.verifyBefore()
func (b *Bobfile) Verify(cacheEnabled, allowRedundantTargets bool) error {
return b.verifyBefore(cacheEnabled, allowRedundantTargets)
}

// VerifyAfter a bobfile after task runner.
Expand All @@ -20,14 +15,17 @@ func (b *Bobfile) VerifyAfter() error {
}

// verifyBefore verifies a Bobfile before Run() is called.
func (b *Bobfile) verifyBefore() (err error) {
func (b *Bobfile) verifyBefore(cacheEnabled, allowRedundantTargets bool) (err error) {
defer errz.Recover(&err)

err = b.BTasks.VerifyDuplicateTargets()
errz.Fatal(err)

err = b.BTasks.VerifyMandatoryInputs()
errz.Fatal(err)

for _, task := range b.BTasks {
err = task.VerifyBefore()
err = task.VerifyBefore(cacheEnabled, allowRedundantTargets)
errz.Fatal(err)
}

Expand Down
6 changes: 6 additions & 0 deletions bob/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func WithCachingEnabled(enabled bool) Option {
}
}

func WithEnableRedundantTargets() Option {
return func(b *B) {
b.enableRedundantTargets = true
}
}

func WithPushEnabled(enabled bool) Option {
return func(b *B) {
b.enablePush = enabled
Expand Down
8 changes: 6 additions & 2 deletions bob/playbook/build_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,14 @@ func (p *Playbook) build(ctx context.Context, task *bobtask.Task) (err error) {
}

if !rebuildRequired {
status := StateNoRebuildRequired
status := StateCached
t, _ := task.Target()
if t == nil {
status = StateNoRebuildRequired
}
boblog.Log.V(2).Info(fmt.Sprintf("%-*s\t%s", p.namePad, coloredName, status.Short()))
taskSuccessFul = true
return p.TaskNoRebuildRequired(task.Name())
return p.TaskNoRebuildRequired(task.Name(), status)
}

err = task.Clean()
Expand Down
8 changes: 4 additions & 4 deletions bob/playbook/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,20 @@ func (p *Playbook) play() error {
return err
}

//boblog.Log.V(3).Info(fmt.Sprintf("%-*s\t walking", p.namePad, taskname))
// boblog.Log.V(3).Info(fmt.Sprintf("%-*s\t walking", p.namePad, taskname))

switch task.State() {
case StatePending:
// Check if all dependent tasks are completed
for _, dependentTaskName := range task.Task.DependsOn {
t, ok := p.Tasks[dependentTaskName]
if !ok {
//fmt.Printf("Task %s does not exist", dependentTaskName)
// fmt.Printf("Task %s does not exist", dependentTaskName)
return usererror.Wrap(boberror.ErrTaskDoesNotExistF(dependentTaskName))
}

state := t.State()
if state != StateCompleted && state != StateNoRebuildRequired {
if state != StateCompleted && state != StateCached && state != StateNoRebuildRequired {
// A dependent task is not completed.
// So this task is not yet ready to run.
return nil
Expand All @@ -60,7 +60,7 @@ func (p *Playbook) play() error {
return taskFailed
case StateCanceled:
return nil
case StateNoRebuildRequired:
case StateCached, StateNoRebuildRequired:
return nil
case StateCompleted:
return nil
Expand Down
6 changes: 3 additions & 3 deletions bob/playbook/playbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ func (p *Playbook) TaskCompleted(taskname string) (err error) {
}

// TaskNoRebuildRequired sets a task's state to indicate that no rebuild is required
func (p *Playbook) TaskNoRebuildRequired(taskname string) (err error) {
func (p *Playbook) TaskNoRebuildRequired(taskname string, status State) (err error) {
defer errz.Recover(&err)

err = p.setTaskState(taskname, StateNoRebuildRequired, nil)
err = p.setTaskState(taskname, status, nil)
errz.Fatal(err)

err = p.play()
Expand Down Expand Up @@ -301,7 +301,7 @@ func (p *Playbook) setTaskState(taskname string, state State, taskError error) e

task.SetState(state, taskError)
switch state {
case StateCompleted, StateCanceled, StateNoRebuildRequired, StateFailed:
case StateCompleted, StateCanceled, StateCached, StateNoRebuildRequired, StateFailed:
task.SetEnd(time.Now())
}

Expand Down
2 changes: 1 addition & 1 deletion bob/playbook/rebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (p *Playbook) didChildTaskChange(taskname string, namePad int, coloredName
}

// Check if child task changed
if t.State() != StateNoRebuildRequired {
if t.State() != StateCached && t.State() != StateNoRebuildRequired {
return Done
}

Expand Down
11 changes: 8 additions & 3 deletions bob/playbook/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ func (s *State) Summary() string {
return "⌛ "
case StateCompleted:
return aurora.Green("✔").Bold().String() + " "
case StateNoRebuildRequired:
case StateCached:
return aurora.Green("cached").String() + " "
case StateNoRebuildRequired:
return aurora.Gray(10, "✔").Bold().String() + " "
case StateFailed:
return aurora.Red("failed").String() + " "
case StateCanceled:
Expand All @@ -29,8 +31,10 @@ func (s *State) Short() string {
return "pending"
case StateCompleted:
return "done"
case StateNoRebuildRequired:
case StateCached:
return "cached"
case StateNoRebuildRequired:
return "not-rebuild"
case StateFailed:
return "failed"
case StateCanceled:
Expand All @@ -43,7 +47,8 @@ func (s *State) Short() string {
const (
StatePending State = "PENDING"
StateCompleted State = "COMPLETED"
StateNoRebuildRequired State = "CACHED"
StateCached State = "CACHED"
StateNoRebuildRequired State = "NO-REBUILD"
StateFailed State = "FAILED"
StateRunning State = "RUNNING"
StateCanceled State = "CANCELED"
Expand Down
9 changes: 6 additions & 3 deletions bob/playbook/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

// summary prints the tasks processing details as a summary of the playbook.
func (p *Playbook) summary(processedTasks []*bobtask.Task) {

boblog.Log.V(1).Info("")
boblog.Log.V(1).Info(aurora.Bold("● ● ● ●").BrightGreen().String())

Expand All @@ -27,12 +26,16 @@ func (p *Playbook) summary(processedTasks []*bobtask.Task) {

execTime := ""
status := stat.State()
if status != StateNoRebuildRequired {
if status != StateCached && status != StateNoRebuildRequired {
execTime = fmt.Sprintf("\t(%s)", format.DisplayDuration(stat.ExecutionTime()))
}

taskName := t.Name()
boblog.Log.V(1).Info(fmt.Sprintf(" %-*s\t%s%s", p.namePad, taskName, status.Summary(), execTime))
if t.IsCompoundTask() {
boblog.Log.V(1).Info(fmt.Sprintf(" %-*s\t%s%s", p.namePad, taskName, "-", execTime))
} else {
boblog.Log.V(1).Info(fmt.Sprintf(" %-*s\t%s%s", p.namePad, taskName, status.Summary(), execTime))
}
}
boblog.Log.V(1).Info("")
}
15 changes: 11 additions & 4 deletions bob/playground.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ func createPlaygroundBobfile(dir string, overwrite bool, projectName string) (er
"sleep 2",
"touch slowdone",
}, "\n"),
TargetDirty: "slowdone",
RebuildDirty: string(bobtask.RebuildAlways),
TargetDirty: "slowdone",
}

// A run command to run a environment from a compose file
Expand Down Expand Up @@ -345,7 +346,8 @@ func createPlaygroundBobfile(dir string, overwrite bool, projectName string) (er
}

bobfile.BTasks["print"] = bobtask.Task{
CmdDirty: "echo ${HELLOWORLD}",
CmdDirty: "echo ${HELLOWORLD}",
RebuildDirty: string(bobtask.RebuildAlways),
}

bobfile.BTasks["multilinetouch"] = bobtask.Task{
Expand All @@ -354,6 +356,7 @@ func createPlaygroundBobfile(dir string, overwrite bool, projectName string) (er
"touch \\\n\tmultilinefile1 \\\n\tmultilinefile2 \\\n\t\tmultilinefile3 \\\n multilinefile4",
"touch \\\n multilinefile5",
}, "\n"),
RebuildDirty: string(bobtask.RebuildAlways),
}

bobfile.BTasks["ignoredInputs"] = bobtask.Task{
Expand All @@ -369,7 +372,8 @@ func createPlaygroundBobfile(dir string, overwrite bool, projectName string) (er
"touch .bbuild/dirone/dirtwo/fileone",
"touch .bbuild/dirone/dirtwo/filetwo",
}, "\n"),
TargetDirty: ".bbuild/dirone/",
RebuildDirty: string(bobtask.RebuildAlways),
TargetDirty: ".bbuild/dirone/",
}

bobfile.BTasks[SecondLevelDir+"/build2"] = bobtask.Task{
Expand All @@ -379,6 +383,7 @@ func createPlaygroundBobfile(dir string, overwrite bool, projectName string) (er
m := make(map[string]interface{})
m["image"] = BuildTargetBobTestImage
bobfile.BTasks[BuildTargetDockerImageName] = bobtask.Task{
InputDirty: "Dockerfile",
CmdDirty: strings.Join([]string{
fmt.Sprintf("docker build -t %s .", BuildTargetBobTestImage),
}, "\n"),
Expand All @@ -388,6 +393,7 @@ func createPlaygroundBobfile(dir string, overwrite bool, projectName string) (er
m = make(map[string]interface{})
m["image"] = BuildTargetBobTestImagePlus
bobfile.BTasks[BuildTargetDockerImagePlusName] = bobtask.Task{
InputDirty: "Dockerfile.plus",
CmdDirty: strings.Join([]string{
fmt.Sprintf("docker build -f Dockerfile.plus -t %s .", BuildTargetBobTestImagePlus),
}, "\n"),
Expand Down Expand Up @@ -444,7 +450,8 @@ func createPlaygroundBobfileThirdLevel(dir string, overwrite bool, projectName s
}

bobfile.BTasks["print"] = bobtask.Task{
CmdDirty: "echo hello-third-level",
CmdDirty: "echo hello-third-level",
RebuildDirty: string(bobtask.RebuildAlways),
}

bobfile.Dependencies = []string{"docker", "go_1_18", "git"}
Expand Down
17 changes: 17 additions & 0 deletions bobtask/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,20 @@ func CreateErrAmbiguousTargets(tasks []string, target string) error {
sort.Strings(tasks)
return fmt.Errorf("%w,\nmultiple tasks [%s] pointing to the same target `%s`", ErrAmbigousTargets, strings.Join(tasks, " "), target)
}

// VerifyMandatoryInputs check that build tasks have `input` field set
// input is mandatory except when task has `rebuild:always` set or is a compound task
func (tm Map) VerifyMandatoryInputs() error {
for taskName, v := range tm {
if v.InputDirty == "" {
if v.Rebuild() == RebuildAlways {
continue
}
if v.IsCompoundTask() {
continue
}
return usererror.Wrap(fmt.Errorf("no input provided for task `%s`", taskName))
}
}
return nil
}
Loading