Modify add to parse stdin

This commit is contained in:
Miguel de la Cruz 2020-02-29 17:45:53 +01:00
parent 41b8e5db55
commit b38a0ff437
3 changed files with 42 additions and 67 deletions

View file

@ -41,7 +41,7 @@ Use "campaigner [command] --help" for more information about a command.
## Roadmap ## Roadmap
- [ ] Modify the add command to only act on `stdin`, using the - [x] Modify the add command to only act on `stdin`, using the
`--grep` and `--govet` flags to distinguish how to parse the `--grep` and `--govet` flags to distinguish how to parse the
input. input.
- [ ] Add `--ag` to the `add` command. - [ ] Add `--ag` to the `add` command.

View file

@ -1,8 +1,9 @@
package cmd package cmd
import ( import (
"bufio"
"fmt" "fmt"
"os/exec" "os"
"strconv" "strconv"
"strings" "strings"
@ -12,28 +13,29 @@ import (
"git.ctrlz.es/mgdelacroix/campaigner/model" "git.ctrlz.es/mgdelacroix/campaigner/model"
) )
const defaultGrepOpts = "-nrFI"
func AddCmd() *cobra.Command { func AddCmd() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "add", Use: "add",
Short: "Adds tickets to the campaign", Short: "Adds tickets to the campaign from the output of grep/ag/govet",
Long: `Generates tickets for the campaign reading from the standard input the output of one of the following three commands:
- grep (should be run with the -n flag)
- ag
- govet (should be run with the -json flag)`,
Example: ` grep -nriIF --include \*.go cobra.Command | campaigner add --grep
ag cobra.Command | campaigner add --ag
govet -json ./... | campaigner add --govet`,
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: addCmdF, RunE: addCmdF,
} }
cmd.Flags().StringP("dir", "d", "", "directory containing the source code") cmd.Flags().BoolP("ag", "a", false, "generates the tickets reading ag's output from stdin")
_ = cmd.MarkFlagRequired("dir") cmd.Flags().BoolP("grep", "g", false, "generates the tickets reading grep's output from stdin")
cmd.Flags().StringSliceP("grep", "g", []string{}, "runs a grep command to generate the tickets") cmd.Flags().BoolP("govet", "v", false, "generates the tickets reading govet's output from stdin")
cmd.Flags().BoolP("case-insensitive", "i", false, "makes the search case insensitive")
cmd.Flags().StringSliceP("ext", "e", []string{}, "limits the grep to files with certain extensions")
// cmd.Flags().StringP("govet", "v", "", "runs a govet command to generate the tickets")
// govet bin path?
return cmd return cmd
} }
func parseLine(line string) (*model.Ticket, error) { func parseGrepLine(line string) (*model.Ticket, error) {
// ToDo: it would be great to be able to relate a line with its // ToDo: it would be great to be able to relate a line with its
// parent method, at least for JS and Golang // parent method, at least for JS and Golang
parts := strings.Split(line, ":") parts := strings.Split(line, ":")
@ -48,68 +50,40 @@ func parseLine(line string) (*model.Ticket, error) {
} }
text := strings.Join(parts[2:], "") text := strings.Join(parts[2:], "")
return &model.Ticket{filename, lineNo, text}, nil return &model.Ticket{
Filename: filename,
LineNo: lineNo,
Text: text,
}, nil
} }
func RunGrep(dir, str string, exts []string, caseInsensitive bool) ([]*model.Ticket, error) { func parseGrep() []*model.Ticket {
opts := defaultGrepOpts
if caseInsensitive {
opts = opts + "i"
}
includes := []string{}
for _, ext := range exts {
if strings.HasPrefix(ext, ".") {
ext = ext[1:]
}
includes = append(includes, []string{"--include", "*." + ext}...)
}
args := append([]string{opts}, includes...)
args = append(args, str, dir)
out, err := exec.Command("grep", args...).Output()
if err != nil {
return nil, fmt.Errorf("execution of grep failed: %w", err)
}
tickets := []*model.Ticket{} tickets := []*model.Ticket{}
for _, line := range strings.Split(string(out), "\n") { scanner := bufio.NewScanner(os.Stdin)
// ToDo: get and check error for scanner.Scan() {
ticket, _ := parseLine(line) ticket, _ := parseGrepLine(scanner.Text())
if ticket != nil { if ticket != nil {
tickets = append(tickets, ticket) tickets = append(tickets, ticket)
} }
} }
return tickets
return tickets, nil
} }
func RunGreps(dir string, strs, exts []string, caseInsensitive bool) ([]*model.Ticket, error) { func addCmdF(cmd *cobra.Command, _ []string) error {
tickets := []*model.Ticket{} grep, _ := cmd.Flags().GetBool("grep")
for _, str := range strs { ag, _ := cmd.Flags().GetBool("ag")
results, err := RunGrep(dir, str, exts, caseInsensitive) govet, _ := cmd.Flags().GetBool("govet")
if err != nil {
return nil, err if !grep && !ag && !govet {
} return fmt.Errorf("one of --grep --ag --govet flags should be active")
tickets = append(tickets, results...)
} }
tickets = model.RemoveDuplicateTickets(tickets) var tickets []*model.Ticket
fmt.Printf("%d matches found\n", len(tickets)) switch {
case grep:
return tickets, nil tickets = parseGrep()
} default:
return fmt.Errorf("not implemented yet")
func addCmdF(cmd *cobra.Command, _ []string) {
dir, _ := cmd.Flags().GetString("dir")
grepStrs, _ := cmd.Flags().GetStringSlice("grep")
extStrs, _ := cmd.Flags().GetStringSlice("ext")
caseInsensitive, _ := cmd.Flags().GetBool("case-insensitive")
tickets, err := RunGreps(dir, grepStrs, extStrs, caseInsensitive)
if err != nil {
ErrorAndExit(cmd, err)
} }
cmp, err := campaign.Read() cmp, err := campaign.Read()
@ -123,4 +97,5 @@ func addCmdF(cmd *cobra.Command, _ []string) {
if err := campaign.Save(cmp); err != nil { if err := campaign.Save(cmp); err != nil {
ErrorAndExit(cmd, err) ErrorAndExit(cmd, err)
} }
return nil
} }

View file

@ -16,7 +16,7 @@ func InitCmd() *cobra.Command {
} }
cmd.Flags().StringP("epic", "e", "", "the epic id to associate this campaign with") cmd.Flags().StringP("epic", "e", "", "the epic id to associate this campaign with")
cmd.MarkFlagRequired("epic") _ = cmd.MarkFlagRequired("epic")
return cmd return cmd
} }