diff --git a/cli/common/pipeline.go b/cli/common/pipeline.go new file mode 100644 index 000000000..c66f58e53 --- /dev/null +++ b/cli/common/pipeline.go @@ -0,0 +1,65 @@ +package common + +import ( + "fmt" + "os" + + "github.com/urfave/cli/v2" +) + +func DetectPipelineConfig() (multiplies bool, config string, _ error) { + config = ".woodpecker" + if fi, err := os.Stat(config); err == nil && fi.IsDir() { + return true, config, nil + } + + config = ".woodpecker.yml" + if fi, err := os.Stat(config); err == nil && !fi.IsDir() { + return true, config, nil + } + + config = ".drone.yml" + fi, err := os.Stat(config) + if err == nil && !fi.IsDir() { + return false, config, nil + } + return false, "", fmt.Errorf("could not detect pipeline config") +} + +func RunPipelineFunc(c *cli.Context, fileFunc, dirFunc func(*cli.Context, string) error) error { + if c.Args().Len() == 0 { + isDir, path, err := DetectPipelineConfig() + if err != nil { + return err + } + if isDir { + return dirFunc(c, path) + } + return fileFunc(c, path) + } + + multiArgs := c.Args().Len() > 1 + for _, arg := range c.Args().Slice() { + fi, err := os.Stat(arg) + if err != nil { + return err + } + if multiArgs { + fmt.Println("#", fi.Name()) + } + if fi.IsDir() { + if err := dirFunc(c, arg); err != nil { + return err + } + } else { + if err := fileFunc(c, arg); err != nil { + return err + } + } + if multiArgs { + fmt.Println("") + } + } + + return nil +} diff --git a/cli/exec/exec.go b/cli/exec/exec.go index 37ea2eb0f..da569fb0b 100644 --- a/cli/exec/exec.go +++ b/cli/exec/exec.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "io/ioutil" + "os" "path" "path/filepath" "runtime" @@ -31,16 +32,46 @@ var Command = &cli.Command{ Name: "exec", Usage: "execute a local build", ArgsUsage: "[path/to/.woodpecker.yml]", - Action: exec, + Action: run, Flags: append(common.GlobalFlags, flags...), } -func exec(c *cli.Context) error { - file := c.Args().First() - if file == "" { - file = ".woodpecker.yml" - } +func run(c *cli.Context) error { + return common.RunPipelineFunc(c, execFile, execDir) +} +func execDir(c *cli.Context, dir string) error { + // TODO: respect pipeline dependency + repoPath, _ := filepath.Abs(filepath.Dir(dir)) + if runtime.GOOS == "windows" { + repoPath = convertPathForWindows(repoPath) + } + return filepath.Walk(dir, func(path string, info os.FileInfo, e error) error { + if e != nil { + return e + } + + // check if it is a regular file (not dir) + if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".yml") { + fmt.Println("#", info.Name()) + _ = runExec(c, path, repoPath) // TODO: should we drop errors or store them and report back? + fmt.Println("") + return nil + } + + return nil + }) +} + +func execFile(c *cli.Context, file string) error { + repoPath, _ := filepath.Abs(filepath.Dir(file)) + if runtime.GOOS == "windows" { + repoPath = convertPathForWindows(repoPath) + } + return runExec(c, file, repoPath) +} + +func runExec(c *cli.Context, file, repoPath string) error { dat, err := ioutil.ReadFile(file) if err != nil { return err @@ -55,7 +86,7 @@ func exec(c *cli.Context) error { axes = append(axes, matrix.Axis{}) } for _, axis := range axes { - err := execWithAxis(c, axis) + err := execWithAxis(c, file, repoPath, axis) if err != nil { return err } @@ -63,12 +94,7 @@ func exec(c *cli.Context) error { return nil } -func execWithAxis(c *cli.Context, axis matrix.Axis) error { - file := c.Args().First() - if file == "" { - file = ".woodpecker.yml" - } - +func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error { metadata := metadataFromContext(c, axis) environ := metadata.Environ() var secrets []compiler.Secret @@ -115,13 +141,9 @@ func execWithAxis(c *cli.Context, axis matrix.Axis) error { if workspacePath == "" { workspacePath = c.String("workspace-path") } - dir, _ := filepath.Abs(filepath.Dir(file)) - if runtime.GOOS == "windows" { - dir = convertPathForWindows(dir) - } volumes = append(volumes, c.String("prefix")+"_default:"+workspaceBase) - volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath)) + volumes = append(volumes, repoPath+":"+path.Join(workspaceBase, workspacePath)) } // lint the yaml file diff --git a/cli/lint/lint.go b/cli/lint/lint.go index df7b58d86..56507b5e5 100644 --- a/cli/lint/lint.go +++ b/cli/lint/lint.go @@ -22,20 +22,11 @@ var Command = &cli.Command{ } func lint(c *cli.Context) error { - file := c.Args().First() - if file == "" { - file = ".woodpecker.yml" - } + return common.RunPipelineFunc(c, lintFile, lintDir) +} - fi, err := os.Stat(file) - if err != nil { - return err - } - if !fi.IsDir() { - return lintFile(file) - } - - return filepath.Walk(file, func(path string, info os.FileInfo, e error) error { +func lintDir(c *cli.Context, dir string) error { + return filepath.Walk(dir, func(path string, info os.FileInfo, e error) error { if e != nil { return e } @@ -43,7 +34,7 @@ func lint(c *cli.Context) error { // check if it is a regular file (not dir) if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".yml") { fmt.Println("#", info.Name()) - _ = lintFile(path) // TODO: should we drop errors or store them and report back? + _ = lintFile(c, path) // TODO: should we drop errors or store them and report back? fmt.Println("") return nil } @@ -52,7 +43,7 @@ func lint(c *cli.Context) error { }) } -func lintFile(file string) error { +func lintFile(_ *cli.Context, file string) error { configErrors, err := schema.Lint(file) if err != nil { fmt.Println("❌ Config is invalid")