Skip to content

Commit

Permalink
refactor: keep things imperative rather than non-idiomatic FSM
Browse files Browse the repository at this point in the history
  • Loading branch information
HandOfGod94 committed Sep 18, 2023
1 parent cae4e31 commit b9a9b04
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 196 deletions.
2 changes: 1 addition & 1 deletion cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var (
fromRef string
toRef string
writeTo string
DefaultTimeout = 60 * time.Second
DefaultTimeout = 10 * time.Second
requiredFlags = []string{"base_url", "email_id", "api_token", "repo_url"}
)

Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module github.com/handofgod94/gh-jira-changelog
go 1.20

require (
github.com/looplab/fsm v1.0.1
github.com/samber/lo v1.38.1
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.16.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/looplab/fsm v1.0.1 h1:OEW0ORrIx095N/6lgoGkFkotqH6s7vaFPsgjLAaF5QU=
github.com/looplab/fsm v1.0.1/go.mod h1:PmD3fFvQEIsjMEfvZdrCDZ6y8VwKTwWNjlpEr6IKPO4=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
Expand Down
70 changes: 10 additions & 60 deletions pkg/jira_changelog/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import (
"context"
"fmt"

. "github.com/handofgod94/gh-jira-changelog/pkg/jira_changelog/fsm_util"
"github.com/handofgod94/gh-jira-changelog/pkg/jira_changelog/git"
"github.com/handofgod94/gh-jira-changelog/pkg/jira_changelog/jira"
"github.com/looplab/fsm"
"github.com/samber/lo"
"golang.org/x/exp/slog"
)
Expand All @@ -18,24 +16,8 @@ type Generator struct {
toRef string
repoURL string
client jira.Client

commits []git.Commit
jiraIssues []jira.Issue
changes Changes
FSM *fsm.FSM
}

const (
Initial = State("initial")
CommitsFetched = State("commits_fetched")
JiraIssuesFetched = State("jira_issues_fetched")
ChangesRecorded = State("changes_recorded")

FetchCommits = Event("fetch_commits")
FetchJiraIssues = Event("fetch_jira_issues")
RecordChanges = Event("record_changes")
)

func NewGenerator(jiraConfig jira.Config, fromRef, toRef, repoURL string) *Generator {
client := jira.NewClient(jiraConfig)
g := &Generator{
Expand All @@ -46,42 +28,6 @@ func NewGenerator(jiraConfig jira.Config, fromRef, toRef, repoURL string) *Gener
client: client,
}

g.FSM = fsm.NewFSM(
Initial,
fsm.Events{
{Name: FetchCommits, Src: []string{Initial}, Dst: CommitsFetched},
{Name: FetchJiraIssues, Src: []string{CommitsFetched}, Dst: JiraIssuesFetched},
{Name: RecordChanges, Src: []string{JiraIssuesFetched}, Dst: ChangesRecorded},
},
fsm.Callbacks{
Before(FetchCommits): func(ctx context.Context, e *fsm.Event) {
gcw := git.NewCommitParseWorkflow(fromRef, toRef)
commits, err := gcw.Commits(ctx)
if err != nil {
e.Cancel(err)
return
}
g.commits = commits
},
Before(FetchJiraIssues): func(ctx context.Context, e *fsm.Event) {
issues, err := g.fetchJiraIssues(g.commits)
if err != nil {
e.Cancel(err)
return
}
g.jiraIssues = lo.Uniq(issues)
},
RecordChanges: func(ctx context.Context, e *fsm.Event) {
slog.Debug("Total jira issues ids", "count", len(g.jiraIssues))
slog.Debug("Recroding changelog")

issuesByEpic := lo.GroupBy(g.jiraIssues, func(issue jira.Issue) string { return issue.Epic() })

slog.Debug("Total epics", "count", len(issuesByEpic))
g.changes = issuesByEpic
},
},
)
return g
}

Expand All @@ -92,13 +38,17 @@ func panicIfErr(err error) {
}

func (c *Generator) Generate(ctx context.Context) *Changelog {
panicIfErr(c.FSM.Event(ctx, FetchCommits))
panicIfErr(c.FSM.Event(ctx, FetchJiraIssues))
panicIfErr(c.FSM.Event(ctx, RecordChanges))
commits, err := git.NewCommitPopulator(c.fromRef, c.toRef).Commits(ctx)
panicIfErr(err)

issues, err := c.fetchJiraIssues(commits)
panicIfErr(err)

issuesByEpic := lo.GroupBy(issues, func(issue jira.Issue) string { return issue.Epic() })

slog.Debug("Total changelog items", "count", len(c.changes))
slog.Debug("Total epics", "count", len(issuesByEpic))

return NewChangelog(c.fromRef, c.toRef, c.repoURL, c.changes)
return NewChangelog(c.fromRef, c.toRef, c.repoURL, issuesByEpic)
}

func (c *Generator) fetchJiraIssues(commits []git.Commit) ([]jira.Issue, error) {
Expand All @@ -115,7 +65,7 @@ func (c *Generator) fetchJiraIssues(commits []git.Commit) ([]jira.Issue, error)
slog.Debug("fetched issue", "issue", issue)
jiraIssues = append(jiraIssues, issue)
}
return jiraIssues, nil
return lo.Uniq(jiraIssues), nil
}

func (c *Generator) fetchJiraIssue(commit git.Commit) (jira.Issue, error) {
Expand Down
52 changes: 7 additions & 45 deletions pkg/jira_changelog/generator_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package jira_changelog

import (
"context"
"testing"
"time"

Expand All @@ -22,7 +21,7 @@ func TestFetchJiraIssuesEvent(t *testing.T) {
{Time: time.Now(), Message: "foobar commit message random", Sha: "3245vw"},
}

jiraIssues := []jira.Issue{
want := []jira.Issue{
jira.NewIssue("TEST-1234", "Ticket description", "done", "Epic1"),
jira.NewIssue("TEST-4546", "Ticket description for 4546 issue", "done", "Epic2"),
jira.NewIssue("TEST-12345", "Ticket description of another card from same epic", "done", "Epic1"),
Expand All @@ -31,53 +30,16 @@ func TestFetchJiraIssuesEvent(t *testing.T) {
}

mockedClient := mocks.NewClient(t)
mockedClient.On("FetchIssue", "TEST-1234").Return(jiraIssues[0], nil).Twice()
mockedClient.On("FetchIssue", "TEST-4546").Return(jiraIssues[1], nil).Twice()
mockedClient.On("FetchIssue", "TEST-12345").Return(jiraIssues[2], nil)
mockedClient.On("FetchIssue", "TEST-1234").Return(want[0], nil).Twice()
mockedClient.On("FetchIssue", "TEST-4546").Return(want[1], nil).Twice()
mockedClient.On("FetchIssue", "TEST-12345").Return(want[2], nil)

// Setup
generator := NewGenerator(jira.Config{}, "fromRef", "toRef", "http://example-repo.com")
generator.client = mockedClient
generator.commits = commits
generator.FSM.SetState(CommitsFetched)

// invoke event
err := generator.FSM.Event(context.Background(), FetchJiraIssues)
got, err := generator.fetchJiraIssues(commits)

assert.NoError(t, err)
assert.Equal(t, len(jiraIssues), len(generator.jiraIssues))
assert.Equal(t, jiraIssues, generator.jiraIssues)
assert.Equal(t, generator.FSM.Current(), JiraIssuesFetched)
}

func TestRecordChangeLogEvent(t *testing.T) {
issues := []jira.Issue{
jira.NewIssue("TEST-1234", "Ticket description", "done", "Epic1"),
jira.NewIssue("TEST-12345", "Ticket description of another from same epic", "done", "Epic1"),
jira.NewIssue("TEST-4546", "Ticket description for 4546 issue", "done", "Epic2"),
jira.NewIssue("", "[NO-CARD] commit message random (3245vw)", "done", ""),
jira.NewIssue("", "foobar commit message random (3245vw)", "done", ""),
}
expected := Changes{
"Epic1": {
jira.NewIssue("TEST-1234", "Ticket description", "done", "Epic1"),
jira.NewIssue("TEST-12345", "Ticket description of another from same epic", "done", "Epic1"),
},
"Epic2": {
jira.NewIssue("TEST-4546", "Ticket description for 4546 issue", "done", "Epic2"),
},
"Miscellaneous": {
jira.NewIssue("", "[NO-CARD] commit message random (3245vw)", "done", ""),
jira.NewIssue("", "foobar commit message random (3245vw)", "done", ""),
},
}

generator := NewGenerator(jira.Config{}, "fromRef", "toRef", "http://example-repo.com")
generator.jiraIssues = issues
generator.FSM.SetState(JiraIssuesFetched)
generator.FSM.Event(context.Background(), RecordChanges)

actual := generator.changes
assert.Equal(t, expected, actual)
assert.Equal(t, generator.FSM.Current(), ChangesRecorded)
assert.Equal(t, len(want), len(got))
assert.Equal(t, want, got)
}
59 changes: 9 additions & 50 deletions pkg/jira_changelog/git/commits.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import (
"os/exec"
"regexp"
"time"

. "github.com/handofgod94/gh-jira-changelog/pkg/jira_changelog/fsm_util"
"github.com/looplab/fsm"
)

type Commit struct {
Expand All @@ -19,69 +16,31 @@ type Commit struct {

var gitoutputPattern = regexp.MustCompile(`^\((\d+)\)\s+\{(\w+)\}\s*(.*)`)

const (
InitialState = State("initial_state")
CommandExecuted = State("command_executed")
OutuptParsed = State("output_parsed")

ExecuteGitLog = Event("execute_git_log")
ParseOutput = Event("parse_output")
)

type commitParseWorkflow struct {
fromRef string
toRef string
GitOutput GitOutput
commits []Commit
FSM *fsm.FSM
type commitPopulator struct {
fromRef string
toRef string
}

func NewCommitParseWorkflow(fromRef, toRef string) *commitParseWorkflow {
cpw := &commitParseWorkflow{
func NewCommitPopulator(fromRef, toRef string) *commitPopulator {
cpw := &commitPopulator{
fromRef: fromRef,
toRef: toRef,
}

cpw.FSM = fsm.NewFSM(
InitialState,
fsm.Events{
{Name: ExecuteGitLog, Src: []string{InitialState}, Dst: CommandExecuted},
{Name: ParseOutput, Src: []string{CommandExecuted}, Dst: OutuptParsed},
},
fsm.Callbacks{
Before(ExecuteGitLog): func(ctx context.Context, e *fsm.Event) {
ouptut, err := execGitLog(ctx, fromRef, toRef)
if err != nil {
e.Cancel(err)
return
}
cpw.GitOutput = ouptut
},
Before(ParseOutput): func(ctx context.Context, e *fsm.Event) {
commits, err := cpw.GitOutput.Commits()
if err != nil {
e.Cancel(err)
return
}
cpw.commits = commits
},
},
)
return cpw
}

func (cpw *commitParseWorkflow) Commits(ctx context.Context) ([]Commit, error) {
err := cpw.FSM.Event(ctx, ExecuteGitLog)
func (cpw *commitPopulator) Commits(ctx context.Context) ([]Commit, error) {
gitOutput, err := execGitLog(ctx, cpw.fromRef, cpw.toRef)
if err != nil {
return []Commit{}, fmt.Errorf("failed to execute git log. %w", err)
}

err = cpw.FSM.Event(ctx, ParseOutput)
commits, err := gitOutput.Commits()
if err != nil {
return []Commit{}, fmt.Errorf("failed to parse output. %w", err)
}

return cpw.commits, nil
return commits, nil
}

func execGitLog(ctx context.Context, fromRef, toRef string) (GitOutput, error) {
Expand Down
37 changes: 0 additions & 37 deletions pkg/jira_changelog/git/commits_test.go

This file was deleted.

0 comments on commit b9a9b04

Please sign in to comment.