Skip to content

Commit

Permalink
feat!: templates v2 and tui stability upgrades (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
jahvon authored Sep 23, 2024
1 parent 752d4e9 commit 57bcd5a
Show file tree
Hide file tree
Showing 74 changed files with 2,599 additions and 842 deletions.
108 changes: 79 additions & 29 deletions cmd/internal/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import (
"time"

"github.com/gen2brain/beeep"
"github.com/jahvon/tuikit/components"
"github.com/jahvon/tuikit/views"
"github.com/spf13/cobra"

"github.com/jahvon/flow/cmd/internal/interactive"
"github.com/jahvon/flow/internal/cache"
"github.com/jahvon/flow/internal/context"
"github.com/jahvon/flow/internal/io"
Expand Down Expand Up @@ -62,14 +61,13 @@ func RegisterExecCmd(ctx *context.Context, rootCmd *cobra.Command) {
rootCmd.AddCommand(subCmd)
}

func execPreRun(ctx *context.Context, cmd *cobra.Command, _ []string) {
func execPreRun(_ *context.Context, _ *cobra.Command, _ []string) {
runner.RegisterRunner(exec.NewRunner())
runner.RegisterRunner(launch.NewRunner())
runner.RegisterRunner(request.NewRunner())
runner.RegisterRunner(render.NewRunner())
runner.RegisterRunner(serial.NewRunner())
runner.RegisterRunner(parallel.NewRunner())
interactive.InitInteractiveCommand(ctx, cmd)
}

//nolint:gocognit
Expand Down Expand Up @@ -114,15 +112,18 @@ func execFunc(ctx *context.Context, cmd *cobra.Command, verb executable.Verb, ar
envMap = make(map[string]string)
}

setAuthEnv(ctx, e)
textInputs := pendingTextInputs(ctx, e)
setAuthEnv(ctx, cmd, e)
textInputs := pendingFormFields(ctx, e)
if len(textInputs) > 0 {
inputs, err := components.ProcessInputs(io.Theme(), textInputs...)
form, err := views.NewForm(io.Theme(), ctx.StdIn(), ctx.StdOut(), textInputs...)
if err != nil {
logger.FatalErr(err)
}
for _, input := range inputs {
envMap[input.Key] = input.Value()
if err := form.Run(ctx.Ctx); err != nil {
logger.FatalErr(err)
}
for key, val := range form.ValueMap() {
envMap[key] = fmt.Sprintf("%v", val)
}
}
startTime := time.Now()
Expand All @@ -131,7 +132,7 @@ func execFunc(ctx *context.Context, cmd *cobra.Command, verb executable.Verb, ar
}
dur := time.Since(startTime)
logger.Infox(fmt.Sprintf("%s flow completed", ref), "Elapsed", dur.Round(time.Millisecond))
if interactive.UIEnabled(ctx, cmd) {
if TUIEnabled(ctx, cmd) {
if dur > 1*time.Minute && ctx.Config.SendSoundNotification() {
_ = beeep.Beep(beeep.DefaultFreq, beeep.DefaultDuration)
}
Expand Down Expand Up @@ -172,19 +173,24 @@ func runByRef(ctx *context.Context, cmd *cobra.Command, argsStr string) error {
return nil
}

func setAuthEnv(ctx *context.Context, executable *executable.Executable) {
func setAuthEnv(ctx *context.Context, _ *cobra.Command, executable *executable.Executable) {
if authRequired(ctx, executable) {
resp, err := components.ProcessInputs(
form, err := views.NewForm(
io.Theme(),
&components.TextInput{
Key: vault.EncryptionKeyEnvVar,
Prompt: "Enter vault encryption key",
Hidden: true,
ctx.StdIn(),
ctx.StdOut(),
&views.FormField{
Key: vault.EncryptionKeyEnvVar,
Title: "Enter vault encryption key",
Type: views.PromptTypeMasked,
})
if err != nil {
ctx.Logger.FatalErr(err)
}
val := resp.ValueMap()[vault.EncryptionKeyEnvVar]
if err := form.Run(ctx.Ctx); err != nil {
ctx.Logger.FatalErr(err)
}
val := form.FindByKey(vault.EncryptionKeyEnvVar).Value()
if val == "" {
ctx.Logger.FatalErr(fmt.Errorf("vault encryption key required"))
}
Expand All @@ -194,7 +200,9 @@ func setAuthEnv(ctx *context.Context, executable *executable.Executable) {
}
}

//nolint:gocognit
// TODO: refactor this function to simplify the logic
//
//nolint:all
func authRequired(ctx *context.Context, rootExec *executable.Executable) bool {
if os.Getenv(vault.EncryptionKeyEnvVar) != "" {
return false
Expand Down Expand Up @@ -239,6 +247,17 @@ func authRequired(ctx *context.Context, rootExec *executable.Executable) bool {
return true
}
}
for _, e := range rootExec.Serial.Execs {
if e.Ref != "" {
childExec, err := ctx.ExecutableCache.GetExecutableByRef(ctx.Logger, e.Ref)
if err != nil {
continue
}
if authRequired(ctx, childExec) {
return true
}
}
}
case rootExec.Parallel != nil:
for _, param := range rootExec.Parallel.Params {
if param.SecretRef != "" {
Expand All @@ -254,66 +273,97 @@ func authRequired(ctx *context.Context, rootExec *executable.Executable) bool {
return true
}
}
for _, e := range rootExec.Parallel.Execs {
if e.Ref != "" {
childExec, err := ctx.ExecutableCache.GetExecutableByRef(ctx.Logger, e.Ref)
if err != nil {
continue
}
if authRequired(ctx, childExec) {
return true
}
}
}
}
return false
}

//nolint:gocognit
func pendingTextInputs(ctx *context.Context, rootExec *executable.Executable) []*components.TextInput {
pending := make([]*components.TextInput, 0)
//nolint:gocognit,funlen
func pendingFormFields(ctx *context.Context, rootExec *executable.Executable) []*views.FormField {
pending := make([]*views.FormField, 0)
switch {
case rootExec.Exec != nil:
for _, param := range rootExec.Exec.Params {
if param.Prompt != "" {
pending = append(pending, &components.TextInput{Key: param.EnvKey, Prompt: param.Prompt})
pending = append(pending, &views.FormField{Key: param.EnvKey, Title: param.Prompt})
}
}
case rootExec.Launch != nil:
for _, param := range rootExec.Launch.Params {
if param.Prompt != "" {
pending = append(pending, &components.TextInput{Key: param.EnvKey, Prompt: param.Prompt})
pending = append(pending, &views.FormField{Key: param.EnvKey, Title: param.Prompt})
}
}
case rootExec.Request != nil:
for _, param := range rootExec.Request.Params {
if param.Prompt != "" {
pending = append(pending, &components.TextInput{Key: param.EnvKey, Prompt: param.Prompt})
pending = append(pending, &views.FormField{Key: param.EnvKey, Title: param.Prompt})
}
}
case rootExec.Render != nil:
for _, param := range rootExec.Render.Params {
if param.Prompt != "" {
pending = append(pending, &components.TextInput{Key: param.EnvKey, Prompt: param.Prompt})
pending = append(pending, &views.FormField{Key: param.EnvKey, Title: param.Prompt})
}
}
case rootExec.Serial != nil:
for _, param := range rootExec.Serial.Params {
if param.Prompt != "" {
pending = append(pending, &components.TextInput{Key: param.EnvKey, Prompt: param.Prompt})
pending = append(pending, &views.FormField{Key: param.EnvKey, Title: param.Prompt})
}
}
for _, child := range rootExec.Serial.Refs {
childExec, err := ctx.ExecutableCache.GetExecutableByRef(ctx.Logger, child)
if err != nil {
continue
}
childPending := pendingTextInputs(ctx, childExec)
childPending := pendingFormFields(ctx, childExec)
pending = append(pending, childPending...)
}
for _, child := range rootExec.Serial.Execs {
if child.Ref != "" {
childExec, err := ctx.ExecutableCache.GetExecutableByRef(ctx.Logger, child.Ref)
if err != nil {
continue
}
childPending := pendingFormFields(ctx, childExec)
pending = append(pending, childPending...)
}
}
case rootExec.Parallel != nil:
for _, param := range rootExec.Parallel.Params {
if param.Prompt != "" {
pending = append(pending, &components.TextInput{Key: param.EnvKey, Prompt: param.Prompt})
pending = append(pending, &views.FormField{Key: param.EnvKey, Title: param.Prompt})
}
}
for _, child := range rootExec.Parallel.Refs {
childExec, err := ctx.ExecutableCache.GetExecutableByRef(ctx.Logger, child)
if err != nil {
continue
}
childPending := pendingTextInputs(ctx, childExec)
childPending := pendingFormFields(ctx, childExec)
pending = append(pending, childPending...)
}
for _, child := range rootExec.Parallel.Execs {
if child.Ref != "" {
childExec, err := ctx.ExecutableCache.GetExecutableByRef(ctx.Logger, child.Ref)
if err != nil {
continue
}
childPending := pendingFormFields(ctx, childExec)
pending = append(pending, childPending...)
}
}
}
return pending
}
Expand Down
22 changes: 15 additions & 7 deletions cmd/internal/flags/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,26 +124,34 @@ var LastLogEntryFlag = &Metadata{
Required: false,
}

var SubPathFlag = &Metadata{
Name: "subPath",
Shorthand: "p",
Usage: "Sub-path within the workspace to create the executable definition and its artifacts.",
var TemplateWorkspaceFlag = &Metadata{
Name: "workspace",
Shorthand: "w",
Usage: "Workspace to create the flow file and its artifacts. Defaults to the current workspace.",
Default: "",
Required: false,
}

var TemplateOutputPathFlag = &Metadata{
Name: "output",
Shorthand: "o",
Usage: "Output directory (within the workspace) to create the flow file and its artifacts. If the directory does not exist, it will be created.",
Default: "",
Required: false,
}

var TemplateFlag = &Metadata{
Name: "template",
Shorthand: "t",
Usage: "Template to use as the template for the executables. Templates are registered in the flow configuration file.",
Usage: "Registered template name. Templates can be registered in the flow configuration file or with `flow set template`.",
Default: "",
Required: false,
}

var FileFlag = &Metadata{
var TemplateFilePathFlag = &Metadata{
Name: "file",
Shorthand: "f",
Usage: "File to use as the template for the executables. It must be a valid executable definition template.",
Usage: "Path to the template file. It must be a valid flow file template.",
Default: "",
Required: false,
}
Loading

0 comments on commit 57bcd5a

Please sign in to comment.