Add govet parsing
This commit is contained in:
parent
4627bbbcb9
commit
aad8c6b884
5 changed files with 126 additions and 52 deletions
73
cmd/add.go
73
cmd/add.go
|
@ -5,20 +5,19 @@ import (
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"git.ctrlz.es/mgdelacroix/campaigner/campaign"
|
"git.ctrlz.es/mgdelacroix/campaigner/campaign"
|
||||||
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
||||||
|
"git.ctrlz.es/mgdelacroix/campaigner/parsers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GrepAddCmd() *cobra.Command {
|
func GrepAddCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "grep",
|
Use: "grep",
|
||||||
Short: "Generates the tickets reading grep's output from stdin",
|
Short: "Generates the tickets reading grep's output from stdin",
|
||||||
Long: `Generates tickets for the campaign reading from the standard input the output grep. The grep command must be run with the -n flag. The generated ticket will contain three fields:
|
Long: `Generates tickets for the campaign reading the output of grep from the standard input. The grep command must be run with the -n flag. The generated ticket will contain three fields:
|
||||||
|
|
||||||
- filename: the filename yield by grep
|
- filename: the filename yield by grep
|
||||||
- lineNo: the line number yield by grep
|
- lineNo: the line number yield by grep
|
||||||
|
@ -53,10 +52,15 @@ func GovetAddCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "govet",
|
Use: "govet",
|
||||||
Short: "Generates the tickets reading govet's output from stdin",
|
Short: "Generates the tickets reading govet's output from stdin",
|
||||||
Long: "Generates tickets for the campaign reading from the standard input the output grep. The grep command must be run with the -json flag",
|
Long: `Generates tickets for the campaign reading the output of govet from the standard input. Govet usually writes to the standard error descriptor, so the output must be redirected. The generated ticket will contain three fields:
|
||||||
Example: ` govet -json ./... | campaigner add govet`,
|
|
||||||
|
- filename: the filename yield by grep
|
||||||
|
- lineNo: the line number yield by grep
|
||||||
|
- text: the text containing the govet error
|
||||||
|
`,
|
||||||
|
Example: ` govet ./... 2>&1 | campaigner add govet`,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: govetAddCmdF,
|
Run: govetAddCmdF,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().BoolP("file-only", "f", false, "Generates one ticket per file instead of per match")
|
cmd.Flags().BoolP("file-only", "f", false, "Generates one ticket per file instead of per match")
|
||||||
|
@ -91,46 +95,10 @@ func AddCmd() *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseGrepLine(line string) (*model.Ticket, error) {
|
|
||||||
// ToDo: it would be great to be able to relate a line with its
|
|
||||||
// parent method, at least for JS and Golang
|
|
||||||
parts := strings.Split(line, ":")
|
|
||||||
if len(parts) < 3 {
|
|
||||||
return nil, fmt.Errorf("cannot parse line: %s", line)
|
|
||||||
}
|
|
||||||
|
|
||||||
filename := parts[0]
|
|
||||||
lineNo, err := strconv.Atoi(parts[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
text := strings.Join(parts[2:], "")
|
|
||||||
|
|
||||||
return &model.Ticket{
|
|
||||||
Data: map[string]interface{}{
|
|
||||||
"filename": filename,
|
|
||||||
"lineNo": lineNo,
|
|
||||||
"text": strings.TrimSpace(text),
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseGrep() []*model.Ticket {
|
|
||||||
tickets := []*model.Ticket{}
|
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
|
||||||
for scanner.Scan() {
|
|
||||||
ticket, _ := parseGrepLine(scanner.Text())
|
|
||||||
if ticket != nil {
|
|
||||||
tickets = append(tickets, ticket)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tickets
|
|
||||||
}
|
|
||||||
|
|
||||||
func grepAddCmdF(cmd *cobra.Command, _ []string) {
|
func grepAddCmdF(cmd *cobra.Command, _ []string) {
|
||||||
fileOnly, _ := cmd.Flags().GetBool("file-only")
|
fileOnly, _ := cmd.Flags().GetBool("file-only")
|
||||||
|
|
||||||
tickets := parseGrep()
|
tickets := parsers.ParseWith(parsers.GREP)
|
||||||
|
|
||||||
cmp, err := campaign.Read()
|
cmp, err := campaign.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -150,8 +118,23 @@ func agAddCmdF(_ *cobra.Command, _ []string) error {
|
||||||
return fmt.Errorf("not implemented yet")
|
return fmt.Errorf("not implemented yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
func govetAddCmdF(_ *cobra.Command, _ []string) error {
|
func govetAddCmdF(cmd *cobra.Command, _ []string) {
|
||||||
return fmt.Errorf("not implemented yet")
|
fileOnly, _ := cmd.Flags().GetBool("file-only")
|
||||||
|
|
||||||
|
tickets := parsers.ParseWith(parsers.GOVET)
|
||||||
|
|
||||||
|
cmp, err := campaign.Read()
|
||||||
|
if err != nil {
|
||||||
|
ErrorAndExit(cmd, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp.Tickets = append(cmp.Tickets, tickets...)
|
||||||
|
cmp.Tickets = model.RemoveDuplicateTickets(cmp.Tickets, fileOnly)
|
||||||
|
|
||||||
|
if err := campaign.Save(cmp); err != nil {
|
||||||
|
ErrorAndExit(cmd, err)
|
||||||
|
}
|
||||||
|
cmd.Printf("%d tickets have been added\n", len(tickets))
|
||||||
}
|
}
|
||||||
|
|
||||||
func csvAddCmdF(cmd *cobra.Command, args []string) {
|
func csvAddCmdF(cmd *cobra.Command, args []string) {
|
||||||
|
|
|
@ -71,6 +71,10 @@ func (c *GithubClient) PublishNextTicket(cmp *model.Campaign, dryRun bool) (bool
|
||||||
}
|
}
|
||||||
|
|
||||||
ticket.GithubLink = issue.GetNumber()
|
ticket.GithubLink = issue.GetNumber()
|
||||||
|
if user := issue.GetUser(); user != nil {
|
||||||
|
ticket.GithubAssignee = user.GetLogin()
|
||||||
|
}
|
||||||
|
ticket.GithubStatus = issue.GetState()
|
||||||
if err := campaign.Save(cmp); err != nil {
|
if err := campaign.Save(cmp); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,6 +135,7 @@ func (c *JiraClient) PublishNextTicket(cmp *model.Campaign, dryRun bool) (bool,
|
||||||
ticket.JiraLink = issue.Key
|
ticket.JiraLink = issue.Key
|
||||||
ticket.Summary = issue.Fields.Summary
|
ticket.Summary = issue.Fields.Summary
|
||||||
ticket.Description = issue.Fields.Description
|
ticket.Description = issue.Fields.Description
|
||||||
|
// ToDo: sync JiraStatus
|
||||||
if err := campaign.Save(cmp); err != nil {
|
if err := campaign.Save(cmp); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
type Ticket struct {
|
type Ticket struct {
|
||||||
GithubLink int `json:"github_link,omitempty"`
|
GithubLink int `json:"github_link,omitempty"`
|
||||||
GithubStatus string `json:"github_status,omitempty"`
|
GithubStatus string `json:"github_status,omitempty"`
|
||||||
|
GithubAssignee string `json:"github_assignee,omitempty"`
|
||||||
JiraLink string `json:"jira_link,omitempty"`
|
JiraLink string `json:"jira_link,omitempty"`
|
||||||
JiraStatus string `json:"jira_status,omitempty"`
|
JiraStatus string `json:"jira_status,omitempty"`
|
||||||
Summary string `json:"summary,omitempty"`
|
Summary string `json:"summary,omitempty"`
|
||||||
|
|
85
parsers/parsers.go
Normal file
85
parsers/parsers.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package parsers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.ctrlz.es/mgdelacroix/campaigner/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GREP = "grep"
|
||||||
|
GOVET = "govet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseGrepLine(line string) (*model.Ticket, error) {
|
||||||
|
// ToDo: it would be great to be able to relate a line with its
|
||||||
|
// parent method, at least for JS and Golang
|
||||||
|
parts := strings.Split(line, ":")
|
||||||
|
if len(parts) < 3 {
|
||||||
|
return nil, fmt.Errorf("cannot parse line: %s", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := parts[0]
|
||||||
|
lineNo, err := strconv.Atoi(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
text := strings.Join(parts[2:], "")
|
||||||
|
|
||||||
|
return &model.Ticket{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"filename": filename,
|
||||||
|
"lineNo": lineNo,
|
||||||
|
"text": strings.TrimSpace(text),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGovetLine(line string) (*model.Ticket, error) {
|
||||||
|
parts := strings.Split(line, ":")
|
||||||
|
if len(parts) < 4 {
|
||||||
|
return nil, fmt.Errorf("cannot parse line: %s", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := parts[0]
|
||||||
|
lineNo, err := strconv.Atoi(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
text := strings.Join(parts[3:], "")
|
||||||
|
|
||||||
|
return &model.Ticket{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"filename": filename,
|
||||||
|
"lineNo": lineNo,
|
||||||
|
"text": strings.TrimSpace(text),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseWith(parser string) []*model.Ticket {
|
||||||
|
var parseFn func(string) (*model.Ticket, error)
|
||||||
|
switch parser {
|
||||||
|
case GREP:
|
||||||
|
parseFn = parseGrepLine
|
||||||
|
case GOVET:
|
||||||
|
parseFn = parseGovetLine
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "Unknown parser %s", parser)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tickets := []*model.Ticket{}
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
for scanner.Scan() {
|
||||||
|
ticket, _ := parseFn(scanner.Text())
|
||||||
|
if ticket != nil {
|
||||||
|
tickets = append(tickets, ticket)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tickets
|
||||||
|
}
|
Loading…
Reference in a new issue