Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .envrc

This file was deleted.

17 changes: 8 additions & 9 deletions Runfile.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
tasks:
build:
env:
CGO_ENABLED: 0
cmd:
- |+
echo "building ..."
Expand All @@ -16,12 +18,7 @@ tasks:
example:
dir: ./examples
cmd:
- |+
run cook clean

test:old:
cmd:
- go test -json ./pkg/runfile | gotestfmt
- echo "hello world"

test:
env:
Expand All @@ -30,7 +27,6 @@ tasks:
only_failing:
default: false
watch:
enable: true
dir:
- ./parser
onlySuffixes:
Expand All @@ -43,8 +39,11 @@ tasks:
testfmt_args=""
[ "$only_failing" = "true" ] && testfmt_args="--hide successful-tests"

go test -json ./pkg/runfile/... $pattern_args | gotestfmt $testfmt_args
go test -json ./pkg/runfile/resolver/... $pattern_args | gotestfmt $testfmt_args
go test -json ./pkg/executor/... $pattern_args | gotestfmt $testfmt_args

test:only-failing:
cmd:
- go test -json ./pkg/runfile | gotestfmt --hide successful-tests
- go test -json ./pkg/runfile/resolver/... | gotestfmt --hide successful-tests
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
- go test -json ./pkg/executor/... | gotestfmt --hide successful-tests

45 changes: 23 additions & 22 deletions cmd/run/completions.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
package main

import (
"context"
"fmt"
"io"
"log/slog"
//
// import (
// "context"
// "fmt"
// "io"
// "log/slog"
//
// "github.com/nxtcoder17/fastlog"
// "github.com/nxtcoder17/runfile/pkg/runfile"
// )

"github.com/nxtcoder17/fastlog"
"github.com/nxtcoder17/runfile/pkg/runfile"
)

func generateShellCompletion(ctx context.Context, writer io.Writer, rfpath string) error {
runfile, err := runfile.ParseFromFile(runfile.NewContext(ctx, fastlog.New()), rfpath)
if err != nil {
slog.Error("parsing, got", "err", err)
panic(err)
}

for k := range runfile.Tasks {
fmt.Fprintf(writer, "%s\n", k)
}

return nil
}
// func generateShellCompletion(ctx context.Context, writer io.Writer, rfpath string) error {
// runfile, err := runfile.ParseFromFile(runfile.NewContext(ctx, fastlog.New()), rfpath)
// if err != nil {
// slog.Error("parsing, got", "err", err)
// panic(err)
// }
//
// for k := range runfile.Tasks {
// fmt.Fprintf(writer, "%s\n", k)
// }
//
// return nil
// }
41 changes: 29 additions & 12 deletions cmd/run/completions/run.fish
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
# args: (1)
# run fish shell completion
set PROGNAME run

# list_targets fetches all targets, with all flags provided on the cli
function list_targets
# eval $PROGNAME --list
eval (commandline -b) --list
# # args: (1)
# # run fish shell completion
# set PROGNAME run
#
# # list_targets fetches all targets, with all flags provided on the cli
# function list_targets
# # eval $PROGNAME --list
# eval (commandline -b) --list
# echo "shell:completion"
# end
#
# complete -c $PROGNAME -d "runs named task" -xa '(list_targets)'
# complete -c $PROGNAME -d "runs named task" -xa '(list_targets)'
# complete -c $PROGNAME -l help -s h -d 'show help'
# complete -c $PROGNAME -l list -s l -d 'list all tasks'
# complete -c $PROGNAME -rF -l file -s f -d 'runs targets from this runfile'

# completion fish shell completion

function __fish_completion_no_subcommand --description 'Test if there has been any subcommand yet'
for i in (commandline -opc)
if contains -- $i
return 1
end
end
return 0
end

complete -c $PROGNAME -d "runs named task" -xa '(list_targets)'
complete -c $PROGNAME -l help -s h -d 'show help'
complete -c $PROGNAME -l list -s l -d 'list all tasks'
complete -c $PROGNAME -rF -l file -s f -d 'runs targets from this runfile'
complete -c run -n '__fish_completion_no_subcommand' -f -l help -s h -d 'show help'
complete -c run -n '__fish_completion_no_subcommand' -f -l list -s l -d 'list all tasks'
complete -c run -n '__fish_completion_no_subcommand' -rF -l file -s f -d 'runs targets from this runfile'

158 changes: 88 additions & 70 deletions cmd/run/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"time"

"github.com/nxtcoder17/fastlog"
"github.com/nxtcoder17/runfile/pkg/errors"
"github.com/nxtcoder17/go.errors"
"github.com/nxtcoder17/runfile/pkg/runfile"
"github.com/urfave/cli/v3"
)
Expand Down Expand Up @@ -95,24 +95,26 @@ func main() {
return
}

runfilePath, err := locateRunfile(c)
if err != nil {
slog.Error("locating runfile", "err", err)
panic(err)
}
// runfilePath, err := locateRunfile(c)
// if err != nil {
// slog.Error("locating runfile", "err", err)
// panic(err)
// }

generateShellCompletion(ctx, c.Root().Writer, runfilePath)
// generateShellCompletion(ctx, c.Root().Writer, runfilePath)
},

Commands: []*cli.Command{
{
Name: "shell:completion",
Usage: "<bash|zsh|fish|ps>",
Suggest: true,
Name: "shell:completion",
Usage: "[shell]",
EnableShellCompletion: false,
Action: func(ctx context.Context, c *cli.Command) error {
fmt.Printf("args: (%d)\n", c.NArg())
if c.NArg() != 1 {
return fmt.Errorf("needs argument one of [bash,zsh,fish,ps]")
if c.NArg() == 0 {
for _, shell := range []string{"fish", "bash", "zsh", "powershell"} {
fmt.Fprintf(c.Writer, "%s\n", shell)
}
Comment on lines 107 to +116
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): CLI now only runs the first task argument and drops support for suffix flags, which may break existing usage.

Previously you could run multiple tasks in one command (e.g. run build test) and use flags like -p/--parallel and -w/--watch even when they appeared after task names via post‑processing c.Args().Slice(). The new RunTask only uses args[0] and the suffix‑flag logic is gone, so extra tasks and trailing flags are now silently ignored. If this change isn’t deliberate, either (a) loop over all task args and call RunTask for each, and (b) restore suffix‑flag handling, or (c) explicitly reject multiple task args with a clear error to avoid silent behavior changes.

return nil
}

switch c.Args().First() {
Expand All @@ -129,6 +131,26 @@ func main() {
return nil
},
},
{
Name: "init",
EnableShellCompletion: false,
Action: func(ctx context.Context, c *cli.Command) error {
dir, err := os.Getwd()
if err != nil {
return err
}

_, err = getRunfilePath(dir)
if err == nil {
slog.Info("Runfile already exists in current directory")
return nil
}

// TODO: implement init command to create a sample Runfile
slog.Info("init command not yet implemented")
return nil
},
},
},

Suggest: true,
Expand All @@ -139,12 +161,12 @@ func main() {

showList := c.Bool("list")
if showList {
runfilePath, err := locateRunfile(c)
if err != nil {
slog.Error("locating runfile, got", "err", err)
return err
}
return generateShellCompletion(ctx, c.Root().Writer, runfilePath)
// runfilePath, err := locateRunfile(c)
// if err != nil {
// slog.Error("locating runfile, got", "err", err)
// return err
// }
// return generateShellCompletion(ctx, c.Root().Writer, runfilePath)
}

if c.NArg() == 0 {
Expand All @@ -157,16 +179,6 @@ func main() {
// INFO: for supporting flags that have been suffixed post arguments
args := make([]string, 0, len(c.Args().Slice()))
for _, arg := range c.Args().Slice() {
if arg == "-p" || arg == "--parallel" {
parallel = true
continue
}

if arg == "-w" || arg == "--watch" {
watch = true
continue
}

if arg == "--debug" {
debug = true
continue
Expand All @@ -185,37 +197,17 @@ func main() {
return fmt.Errorf("parallel and watch can't be set together")
}

logger := fastlog.New(fastlog.Options{
Format: fastlog.ConsoleFormat,
EnableColors: true,
ShowCaller: debug,
ShowTimestamp: false,
ShowDebugLogs: debug,
})
logger := fastlog.New(fastlog.Console(), fastlog.ShowDebugLogs(debug), fastlog.WithoutTimestamp())
slog.SetDefault(logger.Slog())

runfilePath, err := locateRunfile(c)
if err != nil {
slog.Error("locating runfile, got", "err", err)
return err
}

rctx := runfile.NewContext(ctx, logger)

rf, err := runfile.ParseFromFile(rctx, runfilePath)
if err != nil {
slog.Error("parsing runfile, got", "err", err)
panic(err)
}

if err := rf.Run(rctx, args, runfile.RunOption{
ExecuteInParallel: parallel,
Watch: watch,
Debug: debug,
KVs: kv,
}); err != nil {
if err2, ok := err.(*errors.Error); ok {
logger.Error(err2.Error(), err2.SlogAttrs()...)
}
if err := runfile.RunTask(ctx, runfilePath, args[0], kv); err != nil {
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
return err
}

return nil
Expand All @@ -231,8 +223,40 @@ func main() {
}()

if err := cmd.Run(ctx, os.Args); err != nil {
slog.Error("while running cmd, got", "err", err)
if err2, ok := err.(*errors.Error); ok {
slog.Error("failed to run task", err2.AsKeyValues()...)
return
}
slog.Error("failed to run task", "err", err)
}
}

var ErrRunfileNotFound = fmt.Errorf("failed to locate your nearest Runfile")

func getRunfilePath(dir string) (string, error) {
runfileNames := []string{
"Runfile",
"Runfile.yml",
"Runfile.yaml",
}

for _, f := range runfileNames {
stat, err := os.Stat(filepath.Join(dir, f))
if err != nil {
if !os.IsNotExist(err) {
return "", err
}
continue
}
Comment thread
sourcery-ai[bot] marked this conversation as resolved.

if stat.IsDir() {
return "", fmt.Errorf("%s is a directory", filepath.Join(dir, f))
}

return filepath.Join(dir, f), nil
}

return "", ErrRunfileNotFound
}

func locateRunfile(c *cli.Command) (string, error) {
Expand All @@ -247,28 +271,22 @@ func locateRunfile(c *cli.Command) (string, error) {

oldDir := ""

runfileNames := []string{
"Runfile",
"Runfile.yml",
"Runfile.yaml",
}

for oldDir != dir {
for _, fn := range runfileNames {
if _, err := os.Stat(filepath.Join(dir, fn)); err != nil {
if !os.IsNotExist(err) {
return "", err
}
fp, err := getRunfilePath(dir)
if err != nil {
if errors.Is(err, ErrRunfileNotFound) {
// Not found in this dir, try parent
oldDir = dir
dir = filepath.Dir(dir)
continue
}

return filepath.Join(dir, fn), nil
// Some other error
return "", err
}

oldDir = dir
dir = filepath.Dir(dir)
return fp, nil
}

return "", fmt.Errorf("failed to locate your nearest Runfile")
return "", ErrRunfileNotFound
}
}
Loading