diff --git a/changelog.go b/changelog.go new file mode 100644 index 0000000..ac43bb6 --- /dev/null +++ b/changelog.go @@ -0,0 +1,69 @@ +package rp + +import ( + "bytes" + "html/template" + "log" + + "github.com/go-git/go-git/v5" +) + +var ( + changelogTemplate *template.Template +) + +func init() { + var err error + changelogTemplate, err = template.New("changelog").Parse(`## [{{.Version}}]({{.VersionLink}}) +{{- if (gt (len .Features) 0) }} +### Features + +{{ range .Features -}} +- {{ if .Scope }}**{{.Scope}}**: {{end}}{{.Description}} +{{ end -}} +{{- end -}} +{{- if (gt (len .Fixes) 0) }} +### Bug Fixes + +{{ range .Fixes -}} +- {{ if .Scope }}**{{.Scope}}**: {{end}}{{.Description}} +{{ end -}} +{{- end -}} +`, + ) + if err != nil { + log.Fatalf("failed to parse changelog template: %v", err) + } +} + +func UpdateChangelog(wt *git.Worktree, commits []AnalyzedCommit) error { + return nil +} + +func formatChangelog(commits []AnalyzedCommit, version, link string) (string, error) { + features := make([]AnalyzedCommit, 0) + fixes := make([]AnalyzedCommit, 0) + + for _, commit := range commits { + switch commit.Type { + case "feat": + features = append(features, commit) + case "fix": + fixes = append(fixes, commit) + } + } + + var changelog bytes.Buffer + err := changelogTemplate.Execute(&changelog, map[string]any{ + "Features": features, + "Fixes": fixes, + "Version": version, + "VersionLink": link, + }) + if err != nil { + return "", err + } + + return changelog.String(), nil + +} diff --git a/changelog_test.go b/changelog_test.go new file mode 100644 index 0000000..c0f05bb --- /dev/null +++ b/changelog_test.go @@ -0,0 +1,121 @@ +package rp + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func ptr[T any](input T) *T { + return &input +} + +func Test_formatChangelog(t *testing.T) { + type args struct { + commits []AnalyzedCommit + version string + link string + } + tests := []struct { + name string + args args + want string + wantErr assert.ErrorAssertionFunc + }{ + { + name: "empty", + args: args{ + commits: []AnalyzedCommit{}, + version: "1.0.0", + link: "https://example.com/1.0.0", + }, + want: "## [1.0.0](https://example.com/1.0.0)", + wantErr: assert.NoError, + }, + { + name: "single feature", + args: args{ + commits: []AnalyzedCommit{ + { + Commit: Commit{}, + Type: "feat", + Description: "Foobar!", + }, + }, + version: "1.0.0", + link: "https://example.com/1.0.0", + }, + want: "## [1.0.0](https://example.com/1.0.0)\n### Features\n\n- Foobar!\n", + wantErr: assert.NoError, + }, + { + name: "single fix", + args: args{ + commits: []AnalyzedCommit{ + { + Commit: Commit{}, + Type: "fix", + Description: "Foobar!", + }, + }, + version: "1.0.0", + link: "https://example.com/1.0.0", + }, + want: "## [1.0.0](https://example.com/1.0.0)\n### Bug Fixes\n\n- Foobar!\n", + wantErr: assert.NoError, + }, + { + name: "multiple commits with scopes", + args: args{ + commits: []AnalyzedCommit{ + { + Commit: Commit{}, + Type: "feat", + Description: "Blabla!", + }, + { + Commit: Commit{}, + Type: "feat", + Description: "So awesome!", + Scope: ptr("awesome"), + }, + { + Commit: Commit{}, + Type: "fix", + Description: "Foobar!", + }, + { + Commit: Commit{}, + Type: "fix", + Description: "So sad!", + Scope: ptr("sad"), + }, + }, + version: "1.0.0", + link: "https://example.com/1.0.0", + }, + want: `## [1.0.0](https://example.com/1.0.0) +### Features + +- Blabla! +- **awesome**: So awesome! + +### Bug Fixes + +- Foobar! +- **sad**: So sad! +`, + wantErr: assert.NoError, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := formatChangelog(tt.args.commits, tt.args.version, tt.args.link) + if !tt.wantErr(t, err) { + return + } + assert.Equal(t, tt.want, got) + }) + } +}