Skip to content

Commit 923ace5

Browse files
authored
Resolves #404 - Add template support for attributes (#469)
1 parent c09ece5 commit 923ace5

File tree

15 files changed

+330
-38
lines changed

15 files changed

+330
-38
lines changed

cmd/create.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,12 @@ func NewCreateCommand(parentCmd *cobra.Command) func() {
185185
})
186186
} else { // This is an attribute value
187187
return completion.Complete(completion.Request{
188-
Type: completion.CompleteAttributeValue,
189-
Resource: resource,
190-
Verb: completion.Create,
191-
Attribute: args[len(args)-1],
192-
ToComplete: toComplete,
188+
Type: completion.CompleteAttributeValue,
189+
Resource: resource,
190+
Verb: completion.Create,
191+
Attribute: args[len(args)-1],
192+
ToComplete: toComplete,
193+
AllowTemplates: true,
193194
})
194195
}
195196
} else {

cmd/delete.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,12 @@ func NewDeleteCommand(parentCmd *cobra.Command) func() {
161161
})
162162
} else { // This is an attribute value
163163
return completion.Complete(completion.Request{
164-
Type: completion.CompleteAttributeValue,
165-
Resource: resource,
166-
Verb: completion.Delete,
167-
Attribute: args[len(args)-1],
168-
ToComplete: toComplete,
164+
Type: completion.CompleteAttributeValue,
165+
Resource: resource,
166+
Verb: completion.Delete,
167+
Attribute: args[len(args)-1],
168+
ToComplete: toComplete,
169+
AllowTemplates: true,
169170
})
170171
}
171172
}

cmd/helper.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,9 @@ epcc %s %s%s key [] => %s
299299
300300
# To send a nested object use the . character to nest values deeper.
301301
epcc %s %s%s key.some.child hello key.some.other goodbye => %s
302-
`,
302+
303+
# Attributes can also be generated using Go templates and Sprig (https://masterminds.github.io/sprig/) functions.
304+
epcc %s %s%s key 'Test {{ randAlphaNum 6 | upper }} Value' => %s`,
303305
verb, resource.SingularName, id, toJsonExample([]string{"key", "b"}, resource),
304306
verb, resource.SingularName, id, toJsonExample([]string{"key", "1"}, resource),
305307
verb, resource.SingularName, id, toJsonExample([]string{"key", "\"1\""}, resource),
@@ -310,6 +312,7 @@ epcc %s %s%s key.some.child hello key.some.other goodbye => %s
310312
verb, resource.SingularName, id, toJsonExample([]string{"key[0]", "a", "key[1]", "true"}, resource),
311313
verb, resource.SingularName, id, toJsonExample([]string{"key", "[]"}, resource),
312314
verb, resource.SingularName, id, toJsonExample([]string{"key.some.child", "hello", "key.some.other", "goodbye"}, resource),
315+
verb, resource.SingularName, id, toJsonExample([]string{"key", "Test {{ randAlphaNum 6 | upper }} Value"}, resource),
313316
)
314317
}
315318

cmd/login.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -428,11 +428,12 @@ var loginAccountManagement = &cobra.Command{
428428
})
429429
} else {
430430
return completion.Complete(completion.Request{
431-
Type: completion.CompleteAttributeValue,
432-
Verb: completion.Create,
433-
Resource: res,
434-
Attributes: usedAttributes,
435-
ToComplete: toComplete,
431+
Type: completion.CompleteAttributeValue,
432+
Verb: completion.Create,
433+
Resource: res,
434+
Attributes: usedAttributes,
435+
ToComplete: toComplete,
436+
AllowTemplates: true,
436437
})
437438
}
438439

cmd/root.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,6 @@ func Execute() {
290290

291291
os.Exit(1)
292292
} else {
293-
294293
os.Exit(0)
295294
}
296295
}

cmd/runbooks.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,11 +421,9 @@ func processRunbookVariablesOnCommand(runbookActionRunActionCommand *cobra.Comma
421421
}
422422
} else {
423423
description := ""
424-
425424
if variable.Description != nil {
426425
description = variable.Description.Short
427426
}
428-
429427
runbookActionRunActionCommand.Flags().StringVar(runbookStringArguments[key], key, variable.Default, description)
430428
}
431429

cmd/update.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,12 @@ func NewUpdateCommand(parentCmd *cobra.Command) func() {
161161
})
162162
} else { // This is an attribute value
163163
return completion.Complete(completion.Request{
164-
Type: completion.CompleteAttributeValue,
165-
Resource: resource,
166-
Verb: completion.Update,
167-
Attribute: args[len(args)-1],
168-
ToComplete: toComplete,
164+
Type: completion.CompleteAttributeValue,
165+
Resource: resource,
166+
Verb: completion.Update,
167+
Attribute: args[len(args)-1],
168+
ToComplete: toComplete,
169+
AllowTemplates: true,
169170
})
170171
}
171172
} else {

docs/runbook-development.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,17 +171,17 @@ description:
171171
short: "A hello world runbook"
172172
actions:
173173
sequential-sleeps:
174-
variables:
175-
count:
176-
type: INT
177-
default: 2
178-
description:
179-
short: "The number of sleeps"
180-
commands:
181-
- |2
182-
{{- range untilStep 0 .count 1}}
183-
- sleep 1
184-
{{- end -}}
174+
variables:
175+
count:
176+
type: INT
177+
default: 2
178+
description:
179+
short: "The number of sleeps"
180+
commands:
181+
- |2
182+
{{- range untilStep 0 .count 1}}
183+
- sleep 1
184+
{{- end -}}
185185
concurrent-sleeps:
186186
variables:
187187
count:

external/completion/completion.go

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package completion
22

33
import (
4+
"fmt"
45
"github.com/elasticpath/epcc-cli/external/aliases"
56
"github.com/elasticpath/epcc-cli/external/resources"
67
"github.com/spf13/cobra"
8+
"os"
79
"regexp"
810
"strconv"
911
"strings"
@@ -48,8 +50,9 @@ type Request struct {
4850
QueryParam string
4951
Header string
5052
// The current string argument being completed
51-
ToComplete string
52-
NoAliases bool
53+
ToComplete string
54+
NoAliases bool
55+
AllowTemplates bool
5356
}
5457

5558
func Complete(c Request) ([]string, cobra.ShellCompDirective) {
@@ -295,6 +298,79 @@ func Complete(c Request) ([]string, cobra.ShellCompDirective) {
295298
results = append(results, supportedFileTypes...)
296299
}
297300
}
301+
302+
if c.AllowTemplates {
303+
lastPipe := strings.LastIndex(c.ToComplete, "|")
304+
prefix := ""
305+
if lastPipe == -1 {
306+
prefix = "{{ "
307+
} else {
308+
prefix = c.ToComplete[0:lastPipe+1] + " "
309+
}
310+
311+
myResults := []string{}
312+
myResults = append(myResults,
313+
prefix+"date",
314+
prefix+"now",
315+
prefix+"randAlphaNum",
316+
prefix+"randAlpha",
317+
prefix+"randAscii",
318+
prefix+"randNumeric",
319+
prefix+"randAlphaNum",
320+
prefix+"randAlpha",
321+
prefix+"randAscii",
322+
prefix+"randNumeric",
323+
prefix+"pseudoRandAlphaNum",
324+
prefix+"pseudoRandAlpha",
325+
prefix+"pseudoRandNumeric",
326+
prefix+"pseudoRandString",
327+
prefix+"pseudoRandInt",
328+
prefix+"uuidv4",
329+
prefix+"duration",
330+
)
331+
332+
if prefix != "{{ " {
333+
// Functions that make sense as continuations
334+
myResults = append(myResults,
335+
prefix+"trim",
336+
prefix+"trimAll",
337+
prefix+"trimSuffix",
338+
prefix+"trimPrefix",
339+
prefix+"upper",
340+
prefix+"lower",
341+
prefix+"title",
342+
prefix+"repeat",
343+
prefix+"substr",
344+
prefix+"nospace",
345+
prefix+"trunc",
346+
prefix+"abbrev",
347+
prefix+"initials",
348+
prefix+"wrap",
349+
prefix+"cat",
350+
prefix+"replace",
351+
prefix+"snakecase",
352+
prefix+"camelcase",
353+
prefix+"kebabcase",
354+
prefix+"swapcase",
355+
prefix+"shufflecase",
356+
)
357+
}
358+
359+
re := regexp.MustCompile(`env\s+[A-Za-z]*\s*$`)
360+
if re.MatchString(c.ToComplete) {
361+
for _, v := range os.Environ() {
362+
myResults = append(myResults,
363+
fmt.Sprintf("%venv \"%v\"", prefix, strings.Split(v, "=")[0]),
364+
)
365+
}
366+
} else {
367+
myResults = append(myResults, prefix+"env")
368+
}
369+
//myResults = append(myResults, strings.TrimSuffix(c.ToComplete, " ")+" }}", strings.TrimSuffix(c.ToComplete, " ")+" |")
370+
for _, r := range myResults {
371+
results = append(results, r+" |", r+" }}")
372+
}
373+
}
298374
}
299375
}
300376

external/completion/completion_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package completion
22

33
import (
4+
"github.com/elasticpath/epcc-cli/external/resources"
45
"github.com/spf13/cobra"
56
"github.com/stretchr/testify/require"
67
"testing"
@@ -72,3 +73,73 @@ func TestHeaderValueWithNonNilValueCompletes(t *testing.T) {
7273
require.Equal(t, compDir, cobra.ShellCompDirectiveNoFileComp)
7374
require.Contains(t, completions, "USD")
7475
}
76+
77+
func TestAttributeValueWithNoTemplating(t *testing.T) {
78+
// Fixture Setup
79+
toComplete := ""
80+
acct := resources.MustGetResourceByName("password-profiles")
81+
request := Request{
82+
Type: CompleteAttributeValue,
83+
Verb: Create,
84+
ToComplete: toComplete,
85+
Attribute: "username_format",
86+
Resource: acct,
87+
}
88+
89+
// Exercise SUT
90+
completions, compDir := Complete(request)
91+
92+
// Verify Results
93+
require.Equal(t, compDir, cobra.ShellCompDirectiveNoFileComp)
94+
require.Contains(t, completions, "any")
95+
require.Contains(t, completions, "email")
96+
require.Equal(t, 2, len(completions))
97+
}
98+
99+
func TestAttributeValueWithTemplating(t *testing.T) {
100+
// Fixture Setup
101+
toComplete := ""
102+
acct := resources.MustGetResourceByName("password-profiles")
103+
request := Request{
104+
Type: CompleteAttributeValue,
105+
Verb: Create,
106+
ToComplete: toComplete,
107+
Attribute: "username_format",
108+
Resource: acct,
109+
AllowTemplates: true,
110+
}
111+
112+
// Exercise SUT
113+
completions, compDir := Complete(request)
114+
115+
// Verify Results
116+
require.Equal(t, compDir, cobra.ShellCompDirectiveNoFileComp)
117+
require.Contains(t, completions, "any")
118+
require.Contains(t, completions, "email")
119+
require.Contains(t, completions, `{{\ randAlphaNum\ |`)
120+
require.Contains(t, completions, `{{\ randAlphaNum\ }}`)
121+
}
122+
123+
func TestAttributeValueWithTemplatingAndPipe(t *testing.T) {
124+
// Fixture Setup
125+
toComplete := "{{ randAlphaNum 3 | "
126+
acct := resources.MustGetResourceByName("password-profiles")
127+
request := Request{
128+
Type: CompleteAttributeValue,
129+
Verb: Create,
130+
ToComplete: toComplete,
131+
Attribute: "username_format",
132+
Resource: acct,
133+
AllowTemplates: true,
134+
}
135+
136+
// Exercise SUT
137+
completions, compDir := Complete(request)
138+
139+
// Verify Results
140+
require.Equal(t, compDir, cobra.ShellCompDirectiveNoFileComp)
141+
require.Contains(t, completions, "any")
142+
require.Contains(t, completions, "email")
143+
require.Contains(t, completions, `{{\ randAlphaNum\ 3\ |\ upper\ |`)
144+
require.Contains(t, completions, `{{\ randAlphaNum\ 3\ |\ lower\ }}`)
145+
}

0 commit comments

Comments
 (0)