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

adding the possibility to call others tasks from a task #32

Merged
merged 1 commit into from
Apr 30, 2018
Merged
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
20 changes: 14 additions & 6 deletions _tests/orbit.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
tasks:
- use: "explorer"
run:
- dep status
- echo "I am explorer task"
- use: "sputnik"
private: true
run:
- dep status
- echo "I am sputnik task"
- use: "challenger"
run:
- faildep status
- failecho "I am challenger task"
- use: "zuma"
shell: nope.sh
run:
- dep status
- echo "I am zuma task"
- use: "falcon"
shell: bash -c
run:
- dep status
- echo "I am falcon task"
- use: "ariane"
shell: ls
run:
- -l
- -l
- use: "new shepard"
run:
- echo "I am new shepard task"
- {{ run "explorer" "sputnik" }}
- use: "new glenn"
run:
- echo "I am new glenn task"
- {{ run "vulcan" }}
13 changes: 13 additions & 0 deletions app/generator/funcmap.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package generator

import (
"fmt"
"runtime"
"strings"

"github.com/gulien/orbit/app/logger"

Expand Down Expand Up @@ -37,3 +39,14 @@ a data-driven template by using "debug".
func isDebug() bool {
return logger.GetLevel() == logrus.DebugLevel
}

/*
run returns a string which will be parsed by a regex pattern
in our runner.

This function is available in
a data-driven template by using "run".
*/
func run(tasks ...string) string {
return fmt.Sprintf("run@%s", strings.Join(tasks, ","))
}
7 changes: 7 additions & 0 deletions app/generator/funcmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,10 @@ func TestIsDebug(t *testing.T) {
t.Error("Dumb test should have been successful!")
}
}

// Tests run function to check if it returns a well-formed string.
func TestRun(t *testing.T) {
if run("explorer", "falcon") != "run@explorer,falcon" {
t.Error("String returned by run function is malformated!")
}
}
1 change: 1 addition & 0 deletions app/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func NewOrbitGenerator(context *context.OrbitContext) *OrbitGenerator {
funcMap["os"] = getOS
funcMap["verbose"] = isVerbose
funcMap["debug"] = isDebug
funcMap["run"] = run

g := &OrbitGenerator{
context: context,
Expand Down
98 changes: 67 additions & 31 deletions app/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"fmt"
"os"
"os/exec"
"regexp"
"runtime"
"strings"
"text/tabwriter"
Expand Down Expand Up @@ -40,17 +41,17 @@ type (
// Use is the name of the task.
Use string `yaml:"use"`

// Shell allows to choose which binary will
// be called to run the commands.
Shell string `yaml:"shell,omitempty"`

// Short is the short description of the task.
Short string `yaml:"short,omitempty"`

// Private allows to hide the task when
// printing the available tasks.
Private bool `yaml:"private,omitempty"`

// Shell allows to choose which binary will
// be called to run the commands.
Shell string `yaml:"shell,omitempty"`

// Run is the stack of commands to execute.
Run []string `yaml:"run"`
}
Expand Down Expand Up @@ -133,47 +134,82 @@ func (r *OrbitRunner) Run(names ...string) error {
return nil
}

// getTask returns an instance of orbitTask if found or nil.
func (r *OrbitRunner) getTask(name string) *orbitTask {
for _, task := range r.config.Tasks {
if name == task.Use {
return task
}
}

return nil
}

// run executes the stack of commands from the given task.
func (r *OrbitRunner) run(task *orbitTask) error {
logger.Infof("running task %s: %s", task.Use, task.Short)
if task.Short == "" {
logger.Infof("running task %s", task.Use)
} else {
logger.Infof("running task %s: %s", task.Use, task.Short)
}

for _, cmd := range task.Run {

var e *exec.Cmd
if task.Shell != "" {
shellAndParams := strings.Fields(task.Shell)
shell := shellAndParams[0]
parameters := append(shellAndParams[1:], cmd)
e = exec.Command(shell, parameters...)
// check if the current command is calling others tasks.
tasks := r.interpret(cmd)
if tasks != nil {
if err := r.Run(tasks...); err != nil {
return err
}
} else {
if runtime.GOOS == "windows" {
e = exec.Command(os.Getenv(defaultWindowsShellEnvVariable), "/c", cmd)
} else {
e = exec.Command(os.Getenv(defaultPosixShellEnvVariable), "-c", cmd)
e := r.buildCommand(cmd, task)
e.Stdout = os.Stdout
e.Stderr = os.Stderr
e.Stdin = os.Stdin

logger.Infof("executing command %s from task %s", e.Args, task.Use)

if err := e.Run(); err != nil {
return err
}
}
}

return nil
}

logger.Infof("executing command %s", e.Args)
// compiledRegexp is a simple regex pattern used to match a string created by
// the template function run.
var compiledRegexp = regexp.MustCompile(`^run@(.+)$`)

e.Stdout = os.Stdout
e.Stderr = os.Stderr
e.Stdin = os.Stdin
// interpret checks if the command is calling others tasks.
func (r *OrbitRunner) interpret(cmd string) []string {
// let's check if the command match our pattern.
match := compiledRegexp.FindStringSubmatch(cmd)

if err := e.Run(); err != nil {
return err
}
if len(match) == 0 {
// nop, it's just a command.
return nil
}

return nil
// ok, let's retrieve the tasks from the command.
return strings.Split(match[1], ",")
}

// getTask returns an instance of orbitTask if found or nil.
func (r *OrbitRunner) getTask(name string) *orbitTask {
for _, task := range r.config.Tasks {
if name == task.Use {
return task
}
// buildCommand returns an exec.Cmd instance.
func (r *OrbitRunner) buildCommand(cmd string, task *orbitTask) *exec.Cmd {
if task.Shell != "" {
// the user has specified a custom binary to use.
shellAndParams := strings.Fields(task.Shell)
shell := shellAndParams[0]
parameters := append(shellAndParams[1:], cmd)

return exec.Command(shell, parameters...)
}

return nil
// if no custom binary specified, detects the current shell of the user.
if runtime.GOOS == "windows" {
return exec.Command(os.Getenv(defaultWindowsShellEnvVariable), "/c", cmd)
}

return exec.Command(os.Getenv(defaultPosixShellEnvVariable), "-c", cmd)
}
9 changes: 9 additions & 0 deletions app/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,13 @@ func TestRun(t *testing.T) {
t.Error("Custom shell task should have been run!")
}

// case 8: uses a task which calls others tasks
if err := r.Run("new shepard"); err != nil {
t.Error("Task calling others tasks should have been run!")
}

// case 9: uses a task which calls a non existing task.
if err := r.Run("new glenn"); err == nil {
t.Error("Task calling another task should not have been run!")
}
}