From 3ae8ecb32fb2b3f22c74214d0a5752da0d3f62cf Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 22 Aug 2017 13:05:24 -0700 Subject: [PATCH] Autocomplete deployment commands --- api/contexts/contexts.go | 11 +++++----- command/deployment_fail.go | 22 +++++++++++++++++++ command/deployment_fail_test.go | 34 ++++++++++++++++++++++++++++++ command/deployment_pause.go | 22 +++++++++++++++++++ command/deployment_pause_test.go | 34 ++++++++++++++++++++++++++++++ command/deployment_promote.go | 21 ++++++++++++++++++ command/deployment_promote_test.go | 34 ++++++++++++++++++++++++++++++ command/deployment_resume.go | 22 +++++++++++++++++++ command/deployment_resume_test.go | 34 ++++++++++++++++++++++++++++++ command/deployment_status.go | 21 ++++++++++++++++++ command/deployment_status_test.go | 34 ++++++++++++++++++++++++++++++ 11 files changed, 284 insertions(+), 5 deletions(-) diff --git a/api/contexts/contexts.go b/api/contexts/contexts.go index f505ec561..48390b5a1 100644 --- a/api/contexts/contexts.go +++ b/api/contexts/contexts.go @@ -4,9 +4,10 @@ package contexts type Context string const ( - Allocs Context = "allocs" - Evals Context = "evals" - Jobs Context = "jobs" - Nodes Context = "nodes" - All Context = "" + Allocs Context = "allocs" + Deployments Context = "deployment" + Evals Context = "evals" + Jobs Context = "jobs" + Nodes Context = "nodes" + All Context = "" ) diff --git a/command/deployment_fail.go b/command/deployment_fail.go index 759254e9e..ae99e9193 100644 --- a/command/deployment_fail.go +++ b/command/deployment_fail.go @@ -3,6 +3,9 @@ package command import ( "fmt" "strings" + + "github.com/hashicorp/nomad/api/contexts" + "github.com/posener/complete" ) type DeploymentFailCommand struct { @@ -39,6 +42,25 @@ func (c *DeploymentFailCommand) Synopsis() string { return "Manually fail a deployment" } +func (c *DeploymentFailCommand) AutocompleteFlags() complete.Flags { + return nil +} + +func (c *DeploymentFailCommand) AutocompleteArgs() complete.Predictor { + client, _ := c.Meta.Client() + return complete.PredictFunc(func(a complete.Args) []string { + if len(a.Completed) > 1 { + return nil + } + + resp, err := client.Search().PrefixSearch(a.Last, contexts.Deployments) + if err != nil { + return []string{} + } + return resp.Matches[contexts.Deployments] + }) +} + func (c *DeploymentFailCommand) Run(args []string) int { var detach, verbose bool diff --git a/command/deployment_fail_test.go b/command/deployment_fail_test.go index 638954454..dffaa8aaf 100644 --- a/command/deployment_fail_test.go +++ b/command/deployment_fail_test.go @@ -4,7 +4,10 @@ import ( "strings" "testing" + "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" + "github.com/posener/complete" + "github.com/stretchr/testify/assert" ) func TestDeploymentFailCommand_Implements(t *testing.T) { @@ -34,3 +37,34 @@ func TestDeploymentFailCommand_Fails(t *testing.T) { } ui.ErrorWriter.Reset() } + +func TestDeploymentFailCommand_AutocompleteArgs(t *testing.T) { + assert := assert.New(t) + t.Parallel() + + srv, _, url := testServer(t, true, nil) + defer srv.Shutdown() + + ui := new(cli.MockUi) + cmd := &DeploymentFailCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + // Create a fake deployment + state := srv.Agent.Server().State() + d := mock.Deployment() + assert.Nil(state.UpsertDeployment(1000, d)) + + prefix := d.ID[:5] + args := complete.Args{Last: prefix} + predictor := cmd.AutocompleteArgs() + + res := predictor.Predict(args) + assert.Equal(1, len(res)) + assert.Equal(d.ID, res[0]) + + // Autocomplete should only complete once + args = complete.Args{Last: prefix, Completed: []string{prefix, "a", "b"}} + predictor = cmd.AutocompleteArgs() + + res = predictor.Predict(args) + assert.Nil(res) +} diff --git a/command/deployment_pause.go b/command/deployment_pause.go index bc6deeff7..e0b824863 100644 --- a/command/deployment_pause.go +++ b/command/deployment_pause.go @@ -3,6 +3,9 @@ package command import ( "fmt" "strings" + + "github.com/hashicorp/nomad/api/contexts" + "github.com/posener/complete" ) type DeploymentPauseCommand struct { @@ -32,6 +35,25 @@ func (c *DeploymentPauseCommand) Synopsis() string { return "Pause a deployment" } +func (c *DeploymentPauseCommand) AutocompleteFlags() complete.Flags { + return nil +} + +func (c *DeploymentPauseCommand) AutocompleteArgs() complete.Predictor { + client, _ := c.Meta.Client() + return complete.PredictFunc(func(a complete.Args) []string { + if len(a.Completed) > 1 { + return nil + } + + resp, err := client.Search().PrefixSearch(a.Last, contexts.Deployments) + if err != nil { + return []string{} + } + return resp.Matches[contexts.Deployments] + }) +} + func (c *DeploymentPauseCommand) Run(args []string) int { var verbose bool diff --git a/command/deployment_pause_test.go b/command/deployment_pause_test.go index 5f495db16..9be462a31 100644 --- a/command/deployment_pause_test.go +++ b/command/deployment_pause_test.go @@ -4,7 +4,10 @@ import ( "strings" "testing" + "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" + "github.com/posener/complete" + "github.com/stretchr/testify/assert" ) func TestDeploymentPauseCommand_Implements(t *testing.T) { @@ -34,3 +37,34 @@ func TestDeploymentPauseCommand_Fails(t *testing.T) { } ui.ErrorWriter.Reset() } + +func TestDeploymentPauseCommand_AutocompleteArgs(t *testing.T) { + assert := assert.New(t) + t.Parallel() + + srv, _, url := testServer(t, true, nil) + defer srv.Shutdown() + + ui := new(cli.MockUi) + cmd := &DeploymentPauseCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + // Create a fake deployment + state := srv.Agent.Server().State() + d := mock.Deployment() + assert.Nil(state.UpsertDeployment(1000, d)) + + prefix := d.ID[:5] + args := complete.Args{Last: prefix} + predictor := cmd.AutocompleteArgs() + + res := predictor.Predict(args) + assert.Equal(1, len(res)) + assert.Equal(d.ID, res[0]) + + // Autocomplete should only complete once + args = complete.Args{Last: prefix, Completed: []string{prefix, "a", "b"}} + predictor = cmd.AutocompleteArgs() + + res = predictor.Predict(args) + assert.Nil(res) +} diff --git a/command/deployment_promote.go b/command/deployment_promote.go index 15288bcf5..603ecad2d 100644 --- a/command/deployment_promote.go +++ b/command/deployment_promote.go @@ -5,7 +5,9 @@ import ( "strings" "github.com/hashicorp/nomad/api" + "github.com/hashicorp/nomad/api/contexts" flaghelper "github.com/hashicorp/nomad/helper/flag-helpers" + "github.com/posener/complete" ) type DeploymentPromoteCommand struct { @@ -49,6 +51,25 @@ func (c *DeploymentPromoteCommand) Synopsis() string { return "Promote canaries in a deployment" } +func (c *DeploymentPromoteCommand) AutocompleteFlags() complete.Flags { + return nil +} + +func (c *DeploymentPromoteCommand) AutocompleteArgs() complete.Predictor { + client, _ := c.Meta.Client() + return complete.PredictFunc(func(a complete.Args) []string { + if len(a.Completed) > 1 { + return nil + } + + resp, err := client.Search().PrefixSearch(a.Last, contexts.Deployments) + if err != nil { + return []string{} + } + return resp.Matches[contexts.Deployments] + }) +} + func (c *DeploymentPromoteCommand) Run(args []string) int { var detach, verbose bool var groups []string diff --git a/command/deployment_promote_test.go b/command/deployment_promote_test.go index e8628699c..432897458 100644 --- a/command/deployment_promote_test.go +++ b/command/deployment_promote_test.go @@ -4,7 +4,10 @@ import ( "strings" "testing" + "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" + "github.com/posener/complete" + "github.com/stretchr/testify/assert" ) func TestDeploymentPromoteCommand_Implements(t *testing.T) { @@ -34,3 +37,34 @@ func TestDeploymentPromoteCommand_Fails(t *testing.T) { } ui.ErrorWriter.Reset() } + +func TestDeploymentPromoteCommand_AutocompleteArgs(t *testing.T) { + assert := assert.New(t) + t.Parallel() + + srv, _, url := testServer(t, true, nil) + defer srv.Shutdown() + + ui := new(cli.MockUi) + cmd := &DeploymentPromoteCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + // Create a fake deployment + state := srv.Agent.Server().State() + d := mock.Deployment() + assert.Nil(state.UpsertDeployment(1000, d)) + + prefix := d.ID[:5] + args := complete.Args{Last: prefix} + predictor := cmd.AutocompleteArgs() + + res := predictor.Predict(args) + assert.Equal(1, len(res)) + assert.Equal(d.ID, res[0]) + + // Autocomplete should only complete once + args = complete.Args{Last: prefix, Completed: []string{prefix, "a", "b"}} + predictor = cmd.AutocompleteArgs() + + res = predictor.Predict(args) + assert.Nil(res) +} diff --git a/command/deployment_resume.go b/command/deployment_resume.go index 47a599fc6..5e0ebadac 100644 --- a/command/deployment_resume.go +++ b/command/deployment_resume.go @@ -3,6 +3,9 @@ package command import ( "fmt" "strings" + + "github.com/hashicorp/nomad/api/contexts" + "github.com/posener/complete" ) type DeploymentResumeCommand struct { @@ -37,6 +40,25 @@ func (c *DeploymentResumeCommand) Synopsis() string { return "Resume a paused deployment" } +func (c *DeploymentResumeCommand) AutocompleteFlags() complete.Flags { + return nil +} + +func (c *DeploymentResumeCommand) AutocompleteArgs() complete.Predictor { + client, _ := c.Meta.Client() + return complete.PredictFunc(func(a complete.Args) []string { + if len(a.Completed) > 1 { + return nil + } + + resp, err := client.Search().PrefixSearch(a.Last, contexts.Deployments) + if err != nil { + return []string{} + } + return resp.Matches[contexts.Deployments] + }) +} + func (c *DeploymentResumeCommand) Run(args []string) int { var detach, verbose bool diff --git a/command/deployment_resume_test.go b/command/deployment_resume_test.go index 2a319259a..b783b43aa 100644 --- a/command/deployment_resume_test.go +++ b/command/deployment_resume_test.go @@ -4,7 +4,10 @@ import ( "strings" "testing" + "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" + "github.com/posener/complete" + "github.com/stretchr/testify/assert" ) func TestDeploymentResumeCommand_Implements(t *testing.T) { @@ -34,3 +37,34 @@ func TestDeploymentResumeCommand_Fails(t *testing.T) { } ui.ErrorWriter.Reset() } + +func TestDeploymentResumeCommand_AutocompleteArgs(t *testing.T) { + assert := assert.New(t) + t.Parallel() + + srv, _, url := testServer(t, true, nil) + defer srv.Shutdown() + + ui := new(cli.MockUi) + cmd := &DeploymentResumeCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + // Create a fake deployment + state := srv.Agent.Server().State() + d := mock.Deployment() + assert.Nil(state.UpsertDeployment(1000, d)) + + prefix := d.ID[:5] + args := complete.Args{Last: prefix} + predictor := cmd.AutocompleteArgs() + + res := predictor.Predict(args) + assert.Equal(1, len(res)) + assert.Equal(d.ID, res[0]) + + // Autocomplete should only complete once + args = complete.Args{Last: prefix, Completed: []string{prefix, "a", "b"}} + predictor = cmd.AutocompleteArgs() + + res = predictor.Predict(args) + assert.Nil(res) +} diff --git a/command/deployment_status.go b/command/deployment_status.go index c8093d960..513f6e178 100644 --- a/command/deployment_status.go +++ b/command/deployment_status.go @@ -5,6 +5,8 @@ import ( "strings" "github.com/hashicorp/nomad/api" + "github.com/hashicorp/nomad/api/contexts" + "github.com/posener/complete" ) type DeploymentStatusCommand struct { @@ -40,6 +42,25 @@ func (c *DeploymentStatusCommand) Synopsis() string { return "Display the status of a deployment" } +func (c *DeploymentStatusCommand) AutocompleteFlags() complete.Flags { + return nil +} + +func (c *DeploymentStatusCommand) AutocompleteArgs() complete.Predictor { + client, _ := c.Meta.Client() + return complete.PredictFunc(func(a complete.Args) []string { + if len(a.Completed) > 1 { + return nil + } + + resp, err := client.Search().PrefixSearch(a.Last, contexts.Deployments) + if err != nil { + return []string{} + } + return resp.Matches[contexts.Deployments] + }) +} + func (c *DeploymentStatusCommand) Run(args []string) int { var json, verbose bool var tmpl string diff --git a/command/deployment_status_test.go b/command/deployment_status_test.go index d5ecd9445..5b2b52374 100644 --- a/command/deployment_status_test.go +++ b/command/deployment_status_test.go @@ -4,7 +4,10 @@ import ( "strings" "testing" + "github.com/hashicorp/nomad/nomad/mock" "github.com/mitchellh/cli" + "github.com/posener/complete" + "github.com/stretchr/testify/assert" ) func TestDeploymentStatusCommand_Implements(t *testing.T) { @@ -34,3 +37,34 @@ func TestDeploymentStatusCommand_Fails(t *testing.T) { } ui.ErrorWriter.Reset() } + +func TestDeploymentStatusCommand_AutocompleteArgs(t *testing.T) { + assert := assert.New(t) + t.Parallel() + + srv, _, url := testServer(t, true, nil) + defer srv.Shutdown() + + ui := new(cli.MockUi) + cmd := &DeploymentStatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} + + // Create a fake deployment + state := srv.Agent.Server().State() + d := mock.Deployment() + assert.Nil(state.UpsertDeployment(1000, d)) + + prefix := d.ID[:5] + args := complete.Args{Last: prefix} + predictor := cmd.AutocompleteArgs() + + res := predictor.Predict(args) + assert.Equal(1, len(res)) + assert.Equal(d.ID, res[0]) + + // Autocomplete should only complete once + args = complete.Args{Last: prefix, Completed: []string{prefix, "a", "b"}} + predictor = cmd.AutocompleteArgs() + + res = predictor.Predict(args) + assert.Nil(res) +}