Skip to content

Commit

Permalink
Merge pull request #943 from k1LoW/exec-background
Browse files Browse the repository at this point in the history
Add `exec.background:` for executing commands in the background.
  • Loading branch information
k1LoW committed May 30, 2024
2 parents fb1ea8b + adc720c commit 01d041d
Show file tree
Hide file tree
Showing 14 changed files with 85 additions and 29 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1585,7 +1585,7 @@ The response to the run command is always `stdout` and `stderr`.
The `exec` runner is a built-in runner, so there is no need to specify it in the `runners:` section.

It execute command using `command:` and `stdin:` and `shell:`.
It execute command using `command:`, `stdin:`, `shell:` and `background:`.

``` yaml
-
Expand All @@ -1601,6 +1601,8 @@ It execute command using `command:` and `stdin:` and `shell:`.
shell: bash
```

`background:` set to `true` to run the command in the background.

See [testdata/book/exec.yml](testdata/book/exec.yml).

#### Structure of recorded responses
Expand Down
14 changes: 9 additions & 5 deletions capture/runbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,16 +404,20 @@ func (c *cRunbook) CaptureDBResponse(name string, res *runn.DBResponse) {
r.replaceLatestStep(step)
}

func (c *cRunbook) CaptureExecCommand(command, shell string) {
func (c *cRunbook) CaptureExecCommand(command, shell string, background bool) {
r := c.currentRunbook()
if r == nil {
return
}
cmd := yaml.MapSlice{
{Key: "command", Value: command},
{Key: "shell", Value: shell},
}
if background {
cmd = append(cmd, yaml.MapItem{Key: "background", Value: true})
}
step := yaml.MapSlice{
{Key: "exec", Value: yaml.MapSlice{
{Key: "command", Value: command},
{Key: "shell", Value: shell},
}},
{Key: "exec", Value: cmd},
}
r.Steps = append(r.Steps, step)
}
Expand Down
7 changes: 5 additions & 2 deletions capture/runbook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"testing"

"github.com/k1LoW/donegroup"
"github.com/k1LoW/runn"
"github.com/k1LoW/runn/testutil"
"github.com/tenntenn/golden"
Expand All @@ -24,9 +25,10 @@ func TestRunbook(t *testing.T) {
{filepath.Join(testutil.Testdata(), "book", "exec.yml")},
{filepath.Join(testutil.Testdata(), "book", "include_main.yml")},
}
ctx := context.Background()
for _, tt := range tests {
t.Run(filepath.Base(tt.book), func(t *testing.T) {
ctx, cancel := donegroup.WithCancel(context.Background())
t.Cleanup(cancel)
dir := t.TempDir()
hs := testutil.HTTPServer(t)
gs := testutil.GRPCServer(t, false, false)
Expand Down Expand Up @@ -71,9 +73,10 @@ func TestRunnable(t *testing.T) {
{filepath.Join(testutil.Testdata(), "book", "db.yml")},
{filepath.Join(testutil.Testdata(), "book", "exec.yml")},
}
ctx := context.Background()
for _, tt := range tests {
t.Run(filepath.Base(tt.book), func(t *testing.T) {
ctx, cancel := donegroup.WithCancel(context.Background())
t.Cleanup(cancel)
dir := t.TempDir()
{
hs := testutil.HTTPServer(t)
Expand Down
6 changes: 3 additions & 3 deletions capturer.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type Capturer interface {
CaptureDBStatement(name string, stmt string)
CaptureDBResponse(name string, res *DBResponse)

CaptureExecCommand(command, shell string)
CaptureExecCommand(command, shell string, background bool)
CaptureExecStdin(stdin string)
CaptureExecStdout(stdout string)
CaptureExecStderr(stderr string)
Expand Down Expand Up @@ -193,9 +193,9 @@ func (cs capturers) captureDBResponse(name string, res *DBResponse) { //nostyle:
}
}

func (cs capturers) captureExecCommand(command, shell string) { //nostyle:recvtype
func (cs capturers) captureExecCommand(command, shell string, background bool) { //nostyle:recvtype
for _, c := range cs {
c.CaptureExecCommand(command, shell)
c.CaptureExecCommand(command, shell, background)
}
}

Expand Down
2 changes: 1 addition & 1 deletion cmdout.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (d *cmdOut) CaptureSSHStdout(stdout string)
func (d *cmdOut) CaptureSSHStderr(stderr string) {}
func (d *cmdOut) CaptureDBStatement(name string, stmt string) {}
func (d *cmdOut) CaptureDBResponse(name string, res *DBResponse) {}
func (d *cmdOut) CaptureExecCommand(command, shell string) {}
func (d *cmdOut) CaptureExecCommand(command, shell string, background bool) {}
func (d *cmdOut) CaptureExecStdin(stdin string) {}
func (d *cmdOut) CaptureExecStdout(stdout string) {}
func (d *cmdOut) CaptureExecStderr(stderr string) {}
Expand Down
2 changes: 1 addition & 1 deletion debugger.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (d *debugger) CaptureDBResponse(name string, res *DBResponse) {
}
}

func (d *debugger) CaptureExecCommand(command, shell string) {
func (d *debugger) CaptureExecCommand(command, shell string, background bool) {
_, _ = fmt.Fprintf(d.out, "-----START COMMAND-----\n%s\n-----END COMMAND-----\n", command)
}

Expand Down
31 changes: 27 additions & 4 deletions exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/cli/safeexec"
"github.com/k1LoW/donegroup"
"github.com/k1LoW/exec"
)

Expand All @@ -24,9 +25,10 @@ const execDefaultShell = "sh"
type execRunner struct{}

type execCommand struct {
command string
shell string
stdin string
command string
shell string
stdin string
background bool
}

func newExecRunner() *execRunner {
Expand Down Expand Up @@ -66,7 +68,7 @@ func (rnr *execRunner) run(ctx context.Context, c *execCommand, s *step) error {
if c.shell == "" {
c.shell = execDefaultShell
}
o.capturers.captureExecCommand(c.command, c.shell)
o.capturers.captureExecCommand(c.command, c.shell, c.background)

sh, err := safeexec.LookPath(c.shell)
if err != nil {
Expand All @@ -80,6 +82,27 @@ func (rnr *execRunner) run(ctx context.Context, c *execCommand, s *step) error {
}
cmd.Stdout = stdout
cmd.Stderr = stderr

if c.background {
// run in background
if err := cmd.Start(); err != nil {
o.capturers.captureExecStdout(stdout.String())
o.capturers.captureExecStderr(stderr.String())
o.record(map[string]any{
string(execStoreStdoutKey): stdout.String(),
string(execStoreStderrKey): stderr.String(),
string(execStoreExitCodeKey): cmd.ProcessState.ExitCode(),
})
return nil
}
donegroup.Go(ctx, func() error {
_ = cmd.Wait() // WHY: Because it is only necessary to wait. For example, SIGNAL KILL is also normal.
return nil
})
o.record(map[string]any{})
return nil
}

_ = cmd.Run()

o.capturers.captureExecStdout(stdout.String())
Expand Down
20 changes: 12 additions & 8 deletions exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/cli/safeexec"
"github.com/google/go-cmp/cmp"
"github.com/k1LoW/donegroup"
)

func TestExecRun(t *testing.T) {
Expand All @@ -20,32 +21,35 @@ func TestExecRun(t *testing.T) {
}
})
tests := []struct {
command string
stdin string
shell string
want map[string]any
command string
stdin string
shell string
background bool
want map[string]any
}{
{"echo hello!!", "", "", map[string]any{
{"echo hello!!", "", "", false, map[string]any{
"stdout": "hello!!\n",
"stderr": "",
"exit_code": 0,
}},
{"cat", "hello!!", "", map[string]any{
{"cat", "hello!!", "", false, map[string]any{
"stdout": "hello!!",
"stderr": "",
"exit_code": 0,
}},
{"sleep 1000", "", "", true, map[string]any{}},
}
ctx := context.Background()
for _, tt := range tests {
t.Run(tt.command, func(t *testing.T) {
ctx, cancel := donegroup.WithCancel(context.Background())
t.Cleanup(cancel)
o, err := New()
if err != nil {
t.Fatal(err)
}
r := newExecRunner()
s := newStep(0, "stepKey", o, nil)
c := &execCommand{command: tt.command, stdin: tt.stdin, shell: tt.shell}
c := &execCommand{command: tt.command, stdin: tt.stdin, shell: tt.shell, background: tt.background}
if err := r.run(ctx, c, s); err != nil {
t.Error(err)
return
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ require (
github.com/k1LoW/curlreq v0.3.3
github.com/k1LoW/donegroup v1.6.0
github.com/k1LoW/duration v1.2.0
github.com/k1LoW/exec v0.2.0
github.com/k1LoW/exec v0.3.0
github.com/k1LoW/expand v0.12.0
github.com/k1LoW/ghfs v1.3.1
github.com/k1LoW/go-github-client/v58 v58.0.12
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ github.com/k1LoW/donegroup v1.6.0 h1:PAxNrGipcrHie/d8EHreA0rx8yqZZrpZnhelG9QvzHY
github.com/k1LoW/donegroup v1.6.0/go.mod h1:QLpekEK17lNfHoCdqxPns+WacNORIJ+/DK7pSZ9U2Nw=
github.com/k1LoW/duration v1.2.0 h1:qq1gWtPh7YROFyerBufVP+ATR11mOOHDInrcC/Xe/6A=
github.com/k1LoW/duration v1.2.0/go.mod h1:qUa0NptIiUl5EUsCc8wIiSaHuNjS4wmpYNMHp0l6pos=
github.com/k1LoW/exec v0.2.0 h1:b3mOuJtNgPWpvpdW/fRz64wDS7tskW/deAslTyCL9e8=
github.com/k1LoW/exec v0.2.0/go.mod h1:zW7HJpLP/ZndnbPrspA9Z3Q2CxHMK/PAUztlvZem+Ro=
github.com/k1LoW/exec v0.3.0 h1:lNUqhF5IXhm2aDKcaWxhGwYC/WLcCbLOqoe97oxW1XQ=
github.com/k1LoW/exec v0.3.0/go.mod h1:LSd4t5/1qGJHUdB2RUtoHuHfaZ3ks+BfQ+sGHzvwhnE=
github.com/k1LoW/expand v0.12.0 h1:EfkT/VoGVe/B6Jo8WYS5dliXOPJ0xkdkGfzOQPl+0Y8=
github.com/k1LoW/expand v0.12.0/go.mod h1:jJkWgMSibfX88Q+4m4Jse6FQP62M4ia2YaQWQKmD4nA=
github.com/k1LoW/ghfs v1.3.1 h1:xq/VenCDhSUDf1IsL0LBfWIn3QTCOOd8+pE0SNZF6wM=
Expand Down
10 changes: 9 additions & 1 deletion parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"strings"
"time"

"github.com/k1LoW/runn/tmpmod/github.com/goccy/go-yaml"
"github.com/k1LoW/duration"
"github.com/k1LoW/runn/tmpmod/github.com/goccy/go-yaml"
"google.golang.org/grpc/metadata"
)

Expand Down Expand Up @@ -410,6 +410,14 @@ func parseExecCommand(v map[string]any) (*execCommand, error) {
}
c.shell = sh
}
b, ok := v["background"]
if ok {
bg, ok := b.(bool)
if !ok {
return nil, fmt.Errorf("invalid background: %s", string(part))
}
c.background = bg
}
return c, nil
}

Expand Down
5 changes: 5 additions & 0 deletions testdata/book/exec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ steps:
command: basename `echo $0`
shell: bash
test: 'current.stdout == "bash\n"'
-
exec:
command: sleep 1000
background: true
test: 'current.stdout == nil'
3 changes: 3 additions & 0 deletions testdata/exec.yml.debugger.golden
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ bash
-----START STDERR-----

-----END STDERR-----
-----START COMMAND-----
sleep 1000
-----END COMMAND-----
4 changes: 4 additions & 0 deletions testdata/exec.yml.runbook.golden
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ steps:
test: |
current.stdout == "bash\n"
&& current.stderr == ""
- exec:
command: sleep 1000
shell: sh
background: true

0 comments on commit 01d041d

Please sign in to comment.