Skip to content

Commit

Permalink
Merge pull request #4 from smlx/fix-submit
Browse files Browse the repository at this point in the history
Various usability fixes
  • Loading branch information
smlx authored Jul 20, 2021
2 parents 98970d7 + c53a6d8 commit d5c9102
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 48 deletions.
3 changes: 2 additions & 1 deletion cmd/jiratime/submit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ type SubmitCmd struct {

// Run the Submit command.
func (cmd *SubmitCmd) Run() error {
ctx, cancel := getContext(8 * time.Second)
// global timeout of 60 seconds
ctx, cancel := getContext(60 * time.Second)
defer cancel()
// read config file
conf, err := config.Read()
Expand Down
3 changes: 2 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ type Issue struct {

// Config represents the structure of the config file.
type Config struct {
Issues []Issue `json:"issues"`
Issues []Issue `json:"issues"`
Ignore []Regexp `json:"ignore"`
}

// Read the config file.
Expand Down
34 changes: 25 additions & 9 deletions internal/parse/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
matchDuration
matchExplicitIssue
noMatch
ignore
eof
)

Expand All @@ -37,6 +38,8 @@ type TimesheetParser struct {
duration time.Duration
// comment is appended to until worklog submission
comment []string
// defaultComment is appended to comment if comment is otherwise empty
defaultComment string
// issue is the JIRA issue name e.g. XYZ-123
issue string
}
Expand All @@ -52,47 +55,60 @@ func (t *TimesheetParser) Occur(e fsm.Event, l string) error {
// timesheetTransitions defines the transitions for the TimesheetParser FSM
var timesheetTransitions = []fsm.Transition{
{
// first entry
// first entry, or after ignore
Src: start,
Event: matchDuration,
Dst: gotDuration,
}, {
// first line is XYZ-123...
// first line is XYZ-123, explicitly identifying an issue
Src: gotDuration,
Event: matchExplicitIssue,
Dst: gotExplicitIssue,
}, {
// subsequent lines after first line XYZ-123...
// subsequent lines after explicit issue are comments until the next
// duration is found
Src: gotExplicitIssue,
Event: noMatch,
Dst: gotExplicitIssue,
}, {
// attempt match against config
Src: gotExplicitIssue,
Event: ignore,
Dst: gotExplicitIssue,
}, {
// match first line of timesheet entry against config
Src: gotDuration,
Event: noMatch,
Dst: gotImplicitIssue,
}, {
// subsequent lines after config match
// subsequent lines after config match are comments until the next duration
// is found
Src: gotImplicitIssue,
Event: noMatch,
Dst: gotImplicitIssue,
}, {
// new entry after config match
Src: gotImplicitIssue,
Event: ignore,
Dst: gotImplicitIssue,
}, {
// issue hasn't been identified and match an ignore regex: return to start
Src: gotDuration,
Event: ignore,
Dst: start,
}, {
// new duration signifies a new timesheet entry
Src: gotImplicitIssue,
Event: matchDuration,
Dst: gotDuration,
}, {
// new entry after explicit issue
Src: gotExplicitIssue,
Event: matchDuration,
Dst: gotDuration,
}, {
// last entry
// reached the end of the timesheet
Src: gotExplicitIssue,
Event: eof,
Dst: end,
}, {
// last entry
Src: gotImplicitIssue,
Event: eof,
Dst: end,
Expand Down
79 changes: 48 additions & 31 deletions internal/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,31 @@ func getImplicitIssue(line string, c *config.Config) (string, string, string, er
return "", "", "", fmt.Errorf("couldn't match issue to line: %v", line)
}

// addWorklog adds the worklog entry defined in the fields of the given
// TimesheetParser to the worklogs map.
func addWorklog(worklogs map[string][]Worklog, timesheet *TimesheetParser) {
if len(timesheet.comment) == 0 && timesheet.defaultComment != "" {
timesheet.comment =
append(timesheet.comment, timesheet.defaultComment)
}
worklogs[timesheet.issue] = append(worklogs[timesheet.issue], Worklog{
Started: timesheet.started,
Duration: timesheet.duration,
Comment: strings.Join(timesheet.comment, "\n"),
})
}

// matchIgnore returns true if the line matches any of the ignore regexes, and
// false otherwise.
func matchIgnore(c *config.Config, line string) bool {
for _, r := range c.Ignore {
if r.MatchString(line) {
return true
}
}
return false
}

// Input parses text form stdin and returns an issue-Worklog map.
func Input(r io.Reader, c *config.Config) (map[string][]Worklog, error) {
var err error
Expand All @@ -84,26 +109,22 @@ func Input(r io.Reader, c *config.Config) (map[string][]Worklog, error) {
// If we are transitioning from start then this is the first entry and
// there is nothing to submit yet.
if s != start {
worklogs[timesheet.issue] = append(worklogs[timesheet.issue], Worklog{
Started: timesheet.started,
Duration: timesheet.duration,
Comment: strings.Join(timesheet.comment, "\n"),
})
addWorklog(worklogs, &timesheet)
}
timesheet.started, timesheet.duration, err =
parseTimeRange(timesheet.line)
return err
},
},
gotExplicitIssue: {
func(e fsm.Event, _ fsm.State) error {
if e == noMatch {
func(e fsm.Event, s fsm.State) error {
if s == gotExplicitIssue {
timesheet.comment =
append(timesheet.comment, strings.Trim(timesheet.line, " -"))
return nil
}
// we have just identified an explicit issue on the first line of an
// entry, so reset state
// we have identified an explicit issue on the first line of an
// entry, so reset timesheet state
matches := jiraIssue.FindStringSubmatch(timesheet.line)
timesheet.issue = matches[1]
if matches[2] == "" {
Expand All @@ -116,33 +137,25 @@ func Input(r io.Reader, c *config.Config) (map[string][]Worklog, error) {
},
gotImplicitIssue: {
func(e fsm.Event, s fsm.State) error {
if s == gotDuration {
// we haven't identified an issue yet, so try to do so here
var defaultComment, comment string
timesheet.issue, defaultComment, comment, err =
getImplicitIssue(timesheet.line, c)
timesheet.comment = nil
if defaultComment != "" {
timesheet.comment = append(timesheet.comment, defaultComment)
}
if comment != "" {
timesheet.comment = append(timesheet.comment, comment)
}
return err
if s == gotImplicitIssue {
timesheet.comment =
append(timesheet.comment, strings.Trim(timesheet.line, " -"))
return nil
}
// we are just appending comments here
timesheet.comment = append(timesheet.comment, timesheet.line)
return nil
// we haven't identified an issue yet, so try to do so here
var comment string
timesheet.issue, timesheet.defaultComment, comment, err =
getImplicitIssue(timesheet.line, c)
timesheet.comment = nil
if comment != "" {
timesheet.comment = append(timesheet.comment, comment)
}
return err
},
},
end: {
func(e fsm.Event, _ fsm.State) error {
// insert the final entry
worklogs[timesheet.issue] = append(worklogs[timesheet.issue], Worklog{
Started: timesheet.started,
Duration: timesheet.duration,
Comment: strings.Join(timesheet.comment, "\n"),
})
addWorklog(worklogs, &timesheet)
return nil
},
},
Expand All @@ -162,6 +175,10 @@ func Input(r io.Reader, c *config.Config) (map[string][]Worklog, error) {
if err = timesheet.Occur(matchExplicitIssue, line); err != nil {
return nil, err
}
case matchIgnore(c, line):
if err = timesheet.Occur(ignore, line); err != nil {
return nil, err
}
default:
if err = timesheet.Occur(noMatch, line); err != nil {
return nil, err
Expand Down
12 changes: 8 additions & 4 deletions internal/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func TestParseInput(t *testing.T) {
Regexes: wrapRegexes([]string{
"^fooCustomer devops( .+)?$",
}),
DefaultComment: "default fooCustomer work comment",
},
{
ID: "INTERNAL-1",
Expand Down Expand Up @@ -112,7 +113,7 @@ func TestParseInput(t *testing.T) {
Started: time.Date(now.Year(), now.Month(), now.Day(), 16, 30, 0,
0, now.Location()),
Duration: 30 * time.Minute,
Comment: "platform ops\nexample5 cluster melting down again",
Comment: "example5 cluster melting down again",
},
},
"FOO-12": {
Expand Down Expand Up @@ -229,6 +230,9 @@ func TestParseInput(t *testing.T) {
}),
},
},
Ignore: wrapRegexes([]string{
"^lunch$",
}),
},
},
expect: map[string][]parse.Worklog{
Expand All @@ -250,15 +254,15 @@ func TestParseInput(t *testing.T) {
},
"ABC-987": {
{
Started: time.Date(now.Year(), now.Month(), now.Day(), 12, 0, 0,
Started: time.Date(now.Year(), now.Month(), now.Day(), 13, 0, 0,
0, now.Location()),
Duration: 60 * time.Minute,
Comment: "more meetings",
Comment: "more meetings after...\nlunch",
},
},
"ABC-988": {
{
Started: time.Date(now.Year(), now.Month(), now.Day(), 13, 0, 0,
Started: time.Date(now.Year(), now.Month(), now.Day(), 14, 0, 0,
0, now.Location()),
Duration: 30 * time.Minute,
Comment: "will the meetings\never stop?",
Expand Down
7 changes: 5 additions & 2 deletions internal/parse/testdata/worklog1
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ admin
0945-1200
XYZ-123 - fighting fires
1200-1300
lunch
1300-1400
ABC-987
- more meetings
1300-1330
- more meetings after...
lunch
1400-1430
ABC-988
will the meetings
ever stop?

0 comments on commit d5c9102

Please sign in to comment.