diff --git a/commands/docker.go b/commands/docker.go index 6e1b7349..2d977a2b 100644 --- a/commands/docker.go +++ b/commands/docker.go @@ -1,9 +1,11 @@ package commands import ( + "fmt" "kool-dev/kool/core/builder" "kool-dev/kool/core/environment" "os" + "path" "runtime" "github.com/spf13/cobra" @@ -15,6 +17,7 @@ type KoolDockerFlags struct { Volumes []string Publish []string Network []string + Context string } // KoolDocker holds handlers and functions to implement the docker command logic @@ -39,7 +42,7 @@ func AddKoolDocker(root *cobra.Command) { func NewKoolDocker() *KoolDocker { return &KoolDocker{ *newDefaultKoolService(), - &KoolDockerFlags{[]string{}, []string{}, []string{}, []string{}}, + &KoolDockerFlags{[]string{}, []string{}, []string{}, []string{}, ""}, environment.NewEnvStorage(), builder.NewCommand("docker", "run", "--init", "--rm", "-w", "/app", "-i"), } @@ -49,6 +52,14 @@ func NewKoolDocker() *KoolDocker { func (d *KoolDocker) Execute(args []string) (err error) { workDir, _ := os.Getwd() + if context := d.Flags.Context; context != "" { + workDir = path.Join(workDir, context) + if _, err = os.Stat(workDir); err != nil { + err = fmt.Errorf("please enter a valid context directory") + return + } + } + if d.Shell().IsTerminal() { d.dockerRun.AppendArgs("-t") } @@ -107,6 +118,7 @@ the [COMMAND] to provide optional arguments required by the COMMAND.`, cmd.Flags().StringArrayVarP(&docker.Flags.Volumes, "volume", "v", []string{}, "Bind mount a volume.") cmd.Flags().StringArrayVarP(&docker.Flags.Publish, "publish", "p", []string{}, "Publish a container's port(s) to the host.") cmd.Flags().StringArrayVarP(&docker.Flags.Network, "network", "n", []string{}, "Connect a container to a network.") + cmd.Flags().StringVarP(&docker.Flags.Context, "context", "c", "", "Working directory context.") //After a non-flag arg, stop parsing flags cmd.Flags().SetInterspersed(false) diff --git a/commands/docker_test.go b/commands/docker_test.go index 366c672c..75f8d0b9 100644 --- a/commands/docker_test.go +++ b/commands/docker_test.go @@ -7,6 +7,7 @@ import ( "kool-dev/kool/core/environment" "kool-dev/kool/core/shell" "os" + "path" "runtime" "testing" ) @@ -14,7 +15,7 @@ import ( func newFakeKoolDocker() *KoolDocker { return &KoolDocker{ *(newDefaultKoolService().Fake()), - &KoolDockerFlags{[]string{}, []string{}, []string{}, []string{}}, + &KoolDockerFlags{[]string{}, []string{}, []string{}, []string{}, ""}, environment.NewFakeEnvStorage(), &builder.FakeCommand{MockCmd: "docker"}, } @@ -23,7 +24,7 @@ func newFakeKoolDocker() *KoolDocker { func newFailedFakeKoolDocker() *KoolDocker { return &KoolDocker{ *(newDefaultKoolService().Fake()), - &KoolDockerFlags{[]string{}, []string{}, []string{}, []string{}}, + &KoolDockerFlags{[]string{}, []string{}, []string{}, []string{}, ""}, environment.NewFakeEnvStorage(), &builder.FakeCommand{MockCmd: "docker", MockInteractiveError: errors.New("error docker")}, } @@ -50,6 +51,10 @@ func TestNewKoolDocker(t *testing.T) { if len(k.Flags.Publish) > 0 { t.Errorf("bad default value for Publish flag on default KoolDocker instance") } + + if k.Flags.Context != "" { + t.Errorf("bad default value for Context flag on default KoolDocker instance") + } } if _, ok := k.dockerRun.(*builder.DefaultCommand); !ok { @@ -269,3 +274,35 @@ func TestNonTerminalNewDockerCommand(t *testing.T) { t.Errorf("bad arguments to KoolDocker.dockerRun Command on non terminal environment") } } + +func TestContextFlagNewDockerCommand(t *testing.T) { + f := newFakeKoolDocker() + f.shell.(*shell.FakeShell).MockIsTerminal = false + cmd := NewDockerCommand(f) + + cmd.SetArgs([]string{"--context=context_test", "image"}) + + workDir, _ := os.Getwd() + workDir = path.Join(workDir, "context_test") + _ = os.MkdirAll(workDir, 0755) + + if err := cmd.Execute(); err != nil { + t.Errorf("unexpected error executing docker command; error: %v", err) + } + + argsAppend := f.dockerRun.(*builder.FakeCommand).ArgsAppend + + if argsAppend[0] != "--volume" || argsAppend[1] != workDir+":/app:delegated" { + t.Errorf("bad arguments to KoolDocker.dockerRun Command with context flag: %v", argsAppend) + } +} + +func TestInvalidContextFlagNewDockerCommand(t *testing.T) { + f := newFakeKoolDocker() + f.shell.(*shell.FakeShell).MockIsTerminal = false + cmd := NewDockerCommand(f) + + cmd.SetArgs([]string{"--context=invalid_context", "image"}) + + assertExecGotError(t, cmd, "please enter a valid context directory") +} diff --git a/docs/4-Commands/kool-docker.md b/docs/4-Commands/kool-docker.md index 716f5161..f794a07a 100644 --- a/docs/4-Commands/kool-docker.md +++ b/docs/4-Commands/kool-docker.md @@ -16,6 +16,7 @@ kool docker [OPTIONS] IMAGE [COMMAND] [--] [ARG...] ### Options ``` + -c, --context string Working directory context. -e, --env stringArray Environment variables. -h, --help help for docker -n, --network stringArray Connect a container to a network.