diff --git a/Runfile.yml b/Runfile.yml index 60f97cb..c5c36d1 100644 --- a/Runfile.yml +++ b/Runfile.yml @@ -17,8 +17,22 @@ tasks: - go test -json ./pkg/runfile | gotestfmt test: + env: + pattern: + default: "" + watch: + enable: true + dir: + - ./parser + onlySuffixes: + - .go cmd: - - go test -json ./parser/... | gotestfmt + - |+ + if [ -z "$pattern" ]; then + go test -json ./parser/... | gotestfmt + else + go test -json ./parser/... -run "$pattern" | gotestfmt + fi test:only-failing: cmd: diff --git a/cmd/run/completions.go b/cmd/run/completions.go index f68e2b5..8899294 100644 --- a/cmd/run/completions.go +++ b/cmd/run/completions.go @@ -20,7 +20,7 @@ func generateShellCompletion(_ context.Context, writer io.Writer, rfpath string) // panic(err) // } - runfile, err := parser.Parse(rfpath) + runfile, err := parser.ParseRunfile(rfpath) if err != nil { slog.Error("parsing, got", "err", err) panic(err) diff --git a/cmd/run/main.go b/cmd/run/main.go index af450ee..ac0c7ef 100644 --- a/cmd/run/main.go +++ b/cmd/run/main.go @@ -78,6 +78,11 @@ func main() { Value: false, Aliases: []string{"ls"}, }, + + &cli.BoolFlag{ + Name: "debug-env", + Value: false, + }, }, // ShellCompletionCommandName: "completion:shell", @@ -150,7 +155,7 @@ func main() { return err } - rf, err2 := parser.Parse(runfilePath) + rf, err2 := parser.ParseRunfile(runfilePath) if err2 != nil { slog.Error("parsing runfile, got", "err", err2) panic(err2) diff --git a/examples/run1/Runfile b/examples/run1/Runfile index 458f200..5e2e74d 100644 --- a/examples/run1/Runfile +++ b/examples/run1/Runfile @@ -1,4 +1,5 @@ -version: 0.0.1 +env: + file1_env1: "value1" tasks: echo: @@ -11,3 +12,7 @@ tasks: interactive: true cmd: - node + + printenv: + cmd: + - printenv file1_env1 diff --git a/parser/parse-includes.go b/parser/parse-includes.go index 7109c60..9279e96 100644 --- a/parser/parse-includes.go +++ b/parser/parse-includes.go @@ -8,7 +8,7 @@ import ( func parseIncludes(includes map[string]types.IncludeSpec) (map[string]*types.ParsedRunfile, error) { m := make(map[string]*types.ParsedRunfile, len(includes)) for k, v := range includes { - r, err := parse(v.Runfile) + r, err := parseRunfileFromFile(v.Runfile) if err != nil { return nil, errors.ErrParseIncludes.Wrap(err).KV("include", v.Runfile) } diff --git a/parser/parser-runfile.go b/parser/parser-runfile.go index 730e76c..789bf63 100644 --- a/parser/parser-runfile.go +++ b/parser/parser-runfile.go @@ -12,34 +12,28 @@ import ( "sigs.k8s.io/yaml" ) -func parse(file string) (*types.ParsedRunfile, error) { - var runfile types.Runfile - f, err := os.ReadFile(file) - if err != nil { - return nil, errors.ErrReadRunfile.Wrap(err).KV("file", file) +func parseRunfile(runfile *types.Runfile) (*types.ParsedRunfile, error) { + prf := &types.ParsedRunfile{ + Env: make(map[string]string), + Tasks: make(map[string]types.Task), } - if err = yaml.Unmarshal(f, &runfile); err != nil { - return nil, errors.ErrParseRunfile.Wrap(err).KV("file", file) - } - - var prf types.ParsedRunfile - - // prf.Metadata.RunfilePath = fn.Must(filepath.Rel(fn.Must(os.Getwd()), file)) - prf.Metadata.RunfilePath = file + prf.Tasks = runfile.Tasks m, err := parseIncludes(runfile.Includes) if err != nil { return nil, err } - prf.Tasks = runfile.Tasks for k, iprf := range m { for taskName, task := range iprf.Tasks { task.Metadata.RunfilePath = &iprf.Metadata.RunfilePath - // task.Metadata.RunfilePath = fn.New(fn.Must(filepath.Rel(fn.Must(os.Getwd()), iprf.Metadata.RunfilePath))) prf.Tasks[fmt.Sprintf("%s:%s", k, taskName)] = task } + + for k, v := range iprf.Env { + prf.Env[k] = v + } } dotEnvFiles := make([]string, 0, len(runfile.DotEnv)) @@ -58,11 +52,32 @@ func parse(file string) (*types.ParsedRunfile, error) { return nil, err } - prf.Env = fn.MapMerge(dotenvVars, envVars) + prf.Env = fn.MapMerge(prf.Env, dotenvVars, envVars) + + return prf, nil +} + +func parseRunfileFromFile(file string) (*types.ParsedRunfile, error) { + var runfile types.Runfile + + f, err := os.ReadFile(file) + if err != nil { + return nil, errors.ErrReadRunfile.Wrap(err).KV("file", file) + } + + if err := yaml.Unmarshal(f, &runfile); err != nil { + return nil, errors.ErrParseRunfile.Wrap(err) + } - return &prf, nil + prf, err := parseRunfile(&runfile) + if err != nil { + return nil, err + } + + prf.Metadata.RunfilePath = file + return prf, nil } -func Parse(file string) (*types.ParsedRunfile, error) { - return parse(file) +func ParseRunfile(file string) (*types.ParsedRunfile, error) { + return parseRunfileFromFile(file) } diff --git a/parser/parser-runfile_test.go b/parser/parser-runfile_test.go new file mode 100644 index 0000000..91c05ee --- /dev/null +++ b/parser/parser-runfile_test.go @@ -0,0 +1,59 @@ +package parser + +import ( + "encoding/json" + "reflect" + "testing" + + "github.com/nxtcoder17/runfile/types" +) + +func pretty(v any) []byte { + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + panic(err) + } + return b +} + +func Test_parseRunfile(t *testing.T) { + type args struct { + runfile *types.Runfile + } + tests := []struct { + name string + args args + want *types.ParsedRunfile + wantErr bool + }{ + { + name: "1. parsing env vars", + args: args{ + runfile: &types.Runfile{ + Env: map[string]any{ + "env1": "value1", + }, + }, + }, + want: &types.ParsedRunfile{ + Env: map[string]string{ + "env1": "value1", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseRunfile(tt.args.runfile) + if (err != nil) != tt.wantErr { + t.Errorf("parseRunfile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseRunfile:\ngot: %s\n\nwant:%s\n", pretty(got), pretty(tt.want)) + // t.Errorf("parseRunfile() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/runner/run-task.go b/runner/run-task.go index ec7ea2f..8a2a73c 100644 --- a/runner/run-task.go +++ b/runner/run-task.go @@ -25,6 +25,8 @@ type runTaskArgs struct { taskTrail []string taskName string envOverrides map[string]string + + DebugEnv bool } func isDarkTheme() bool { @@ -148,13 +150,16 @@ func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error { s := lipgloss.NewStyle().BorderForeground(lipgloss.Color(borderColor)).PaddingLeft(1).PaddingRight(1).Border(lipgloss.RoundedBorder(), true, true, true, true) // labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(borderColor)).Blink(true) + if args.DebugEnv { + fmt.Printf("%s\n", s.Render(padString(fmt.Sprintf("%+v", prf.Env), "DEBUG: env"))) + } + hlCode := new(bytes.Buffer) // choose colorschemes from `https://swapoff.org/chroma/playground/` colorscheme := "catppuccin-macchiato" if !isDarkTheme() { colorscheme = "monokailight" } - _ = colorscheme // quick.Highlight(hlCode, strings.TrimSpace(command.Command), "bash", "terminal16m", colorscheme) cmdStr := strings.TrimSpace(command.Command) @@ -205,10 +210,6 @@ func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error { os.Exit(0) }() - // if err := ex.Exec(); err != nil { - // return errors.ErrTaskFailed.Wrap(err).KV("task", args.taskName) - // } - watch.WatchEvents(func(event watcher.Event, fp string) error { relPath, err := filepath.Rel(fn.Must(os.Getwd()), fp) if err != nil { diff --git a/runner/runner.go b/runner/runner.go index a1b207d..c55a780 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -115,7 +115,7 @@ func Run(ctx Context, prf *types.ParsedRunfile, args RunArgs) error { } for _, tn := range args.Tasks { - if err := runTask(ctx, prf, runTaskArgs{taskName: tn}); err != nil { + if err := runTask(ctx, prf, runTaskArgs{taskName: tn, DebugEnv: false}); err != nil { return errors.WithErr(err).KV(attr(tn)...) } } diff --git a/types/parsed-types.go b/types/parsed-types.go index 2108289..4e97ada 100644 --- a/types/parsed-types.go +++ b/types/parsed-types.go @@ -1,5 +1,14 @@ package types +type ParsedRunfile struct { + Env map[string]string `json:"env,omitempty"` + Tasks map[string]Task `json:"tasks"` + + Metadata struct { + RunfilePath string + } `json:"-"` +} + type ParsedTask struct { Shell []string `json:"shell"` WorkingDir string `json:"workingDir"` diff --git a/types/types.go b/types/types.go index 07be5de..d091ccc 100644 --- a/types/types.go +++ b/types/types.go @@ -8,15 +8,6 @@ type Runfile struct { Tasks map[string]Task `json:"tasks"` } -type ParsedRunfile struct { - Env map[string]string `json:"env,omitempty"` - Tasks map[string]Task `json:"tasks"` - - Metadata struct { - RunfilePath string - } `json:"-"` -} - type IncludeSpec struct { Runfile string `json:"runfile"` Dir string `json:"dir,omitempty"`