Skip to content

Commit

Permalink
Add confirm step
Browse files Browse the repository at this point in the history
Signed-off-by: Mathieu Frenette <[email protected]>
  • Loading branch information
silphid committed Mar 7, 2021
1 parent 466f185 commit c89c0d5
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 7 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,6 @@ To associate a template with an existing project that was not initially generate

# Wishlist

- Add `confirm` step (similar to `if`, but `confirm` property contains message to display and `then` the steps to execute).
- Allow `do` step to define multiple actions to call.
- Add reusable modules (including both templates and scripts).
- Add support for injecting snippets in specific sections of files in a second time (ie: adding multiple endpoints to an existing service).
Expand Down
10 changes: 7 additions & 3 deletions examples/templates/hello-world/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ actions:

# By convention, the "uninstall" action is in charge of removing the project from infra
uninstall:
# Here the "exec" step is invoked multiple times, each executing a single command
- exec: remove-docker-repo
- exec: remove-cicd-triggers
# The "confirm" step is similar to "if", however it prompts user with given message and
# only upon confirmation executes steps in the "then" clause.
- confirm: Are you sure you want to completely uninstall project {{.PROJECT}} from infrastructure?
then:
# Here the "exec" step is invoked multiple times, each executing a single command
- exec: remove-docker-repo
- exec: remove-cicd-triggers
2 changes: 1 addition & 1 deletion src/internal/evaluation/evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (c context) GetPlaceholders() map[string]string {
return c.placeholders
}

func (c context) GetShellVars() []string {
func (c context) GetShellVars(includeProcessVars bool) []string {
vars := make([]string, len(c.vars))
for key, value := range c.vars {
entry := fmt.Sprintf("%s=%v", key, value)
Expand Down
25 changes: 24 additions & 1 deletion src/internal/spec/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,17 @@ func loadExecutables(list yaml.List, templateDir string) (exec.Executables, erro
}

func loadExecutable(node yaml.Node, templateDir string) (exec.Executable, error) {
// Special case for if step
// Special case for if and confirm steps
_map, ok := node.(yaml.Map)
if ok {
_, ok = _map["if"]
if ok {
return loadIfStep(_map, templateDir)
}
_, ok = _map["confirm"]
if ok {
return loadConfirmStep(_map, templateDir)
}
}

// Other steps
Expand Down Expand Up @@ -186,6 +190,25 @@ func loadIfStep(_map yaml.Map, templateDir string) (exec.Executable, error) {
}, nil
}

func loadConfirmStep(_map yaml.Map, templateDir string) (exec.Executable, error) {
message, err := getRequiredStringFromMap(_map, "confirm")
if err != nil {
return nil, err
}
list, err := getRequiredList(_map, "then")
if err != nil {
return nil, err
}
executables, err := loadExecutables(list, templateDir)
if err != nil {
return nil, err
}
return steps.Confirm{
Message: message,
Then: executables,
}, nil
}

func loadInputStep(_map yaml.Map, templateDir string) (exec.Executable, error) {
question, err := getRequiredStringFromMap(_map, "question")
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions src/internal/spec/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,26 @@ then:
},
},
},
{
Name: "confirm",
Buffer: `
confirm: Message
then:
- input:
question: Message
var: Variable
default: Default`,
Expected: steps.Confirm{
Message: "Message",
Then: exec.Executables{
input.Prompt{
Message: "Message",
Var: "Variable",
Default: "Default",
},
},
},
},
{
Name: "input prompt",
Buffer: `
Expand Down
41 changes: 41 additions & 0 deletions src/internal/steps/confirm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package steps

import (
"github.com/AlecAivazis/survey/v2"
"github.com/Samasource/jen/src/internal/evaluation"
"github.com/Samasource/jen/src/internal/exec"
logging "github.com/Samasource/jen/src/internal/logging"
)

// Confirm represents a conditional step that executes its child executable only if
// user answers Yes when prompted for given message
type Confirm struct {
Message string
Then exec.Executables
}

func (c Confirm) String() string {
return "confirm"
}

// Execute executes a child action only if user answers Yes when prompted for given message
func (c Confirm) Execute(context exec.Context) error {
message, err := evaluation.EvalTemplate(context, c.Message)
if err != nil {
return err
}
prompt := &survey.Confirm{
Message: message,
Default: false,
}
value := false
if err := survey.AskOne(prompt, &value); err != nil {
return err
}
if !value {
logging.Log("Skipping sub-steps because user cancelled")
return nil
}
logging.Log("Executing sub-steps because user confirmed")
return c.Then.Execute(context)
}
2 changes: 1 addition & 1 deletion src/internal/steps/if.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type If struct {
}

func (i If) String() string {
return "do"
return "if"
}

// Execute executes a child action only when a given condition evaluates to true
Expand Down
4 changes: 4 additions & 0 deletions src/internal/steps/input/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ type Prompt struct {
Default string
}

func (p Prompt) String() string {
return "input"
}

// Execute prompts user for input value
func (p Prompt) Execute(context exec.Context) error {
if context.IsVarOverriden(p.Var) {
Expand Down

0 comments on commit c89c0d5

Please sign in to comment.