feat(changelog): use newly markdown parser and generate
parent
c8e5bf3ffc
commit
25ead5004d
14
main.go
14
main.go
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -155,10 +156,17 @@ func (a *action) generateChangelog(c *cli.Context, path string, commits []conven
|
|||
return fmt.Errorf("invalid semver %s", version)
|
||||
}
|
||||
|
||||
markdownGenerator := changelog.NewMarkdownGenerator(changelogPath, version, time.Now())
|
||||
var oldData string
|
||||
bytes, err := ioutil.ReadFile(changelogPath)
|
||||
if err == nil {
|
||||
oldData = string(bytes)
|
||||
}
|
||||
|
||||
if err := markdownGenerator.Generate(commits); err != nil {
|
||||
return err
|
||||
markdownGenerator := changelog.NewMarkdownGenerator(oldData, version, time.Now())
|
||||
newData := markdownGenerator.Generate(commits)
|
||||
|
||||
if err := ioutil.WriteFile(changelogPath, []byte(newData), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write file %s: %w", changelogPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -2,135 +2,113 @@ package changelog
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/haunt98/changeloguru/pkg/convention"
|
||||
"github.com/haunt98/changeloguru/pkg/markdown"
|
||||
)
|
||||
|
||||
// https://guides.github.com/features/mastering-markdown/
|
||||
|
||||
const (
|
||||
markdownTitle = "# CHANGELOG"
|
||||
title = "CHANGELOG"
|
||||
|
||||
defaultLinesLen = 10
|
||||
defaultBasesLen = 10
|
||||
)
|
||||
|
||||
type MarkdownGenerator struct {
|
||||
path string
|
||||
oldData string
|
||||
version string
|
||||
t time.Time
|
||||
}
|
||||
|
||||
func NewMarkdownGenerator(path string, version string, t time.Time) *MarkdownGenerator {
|
||||
func NewMarkdownGenerator(oldData, version string, t time.Time) *MarkdownGenerator {
|
||||
return &MarkdownGenerator{
|
||||
path: path,
|
||||
oldData: oldData,
|
||||
version: version,
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *MarkdownGenerator) Generate(commits []convention.Commit) error {
|
||||
lines := g.getLines(commits)
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
func (g *MarkdownGenerator) Generate(commits []convention.Commit) string {
|
||||
newBases := g.getNewMarkdownBases(commits)
|
||||
if len(newBases) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
previousLines := g.getPreviousLines()
|
||||
bases := make([]markdown.Base, 0, defaultBasesLen)
|
||||
|
||||
lines = append(lines, previousLines...)
|
||||
// title
|
||||
bases = append(bases, markdown.NewHeader(1, title))
|
||||
|
||||
if err := g.writeLines(lines); err != nil {
|
||||
return err
|
||||
}
|
||||
// version
|
||||
year, month, day := g.t.Date()
|
||||
versionHeader := fmt.Sprintf("%s (%d-%d-%d)", g.version, year, month, day)
|
||||
bases = append(bases, markdown.NewHeader(2, versionHeader))
|
||||
|
||||
return nil
|
||||
// new
|
||||
bases = append(bases, newBases...)
|
||||
|
||||
// old
|
||||
oldBases := g.getOldBases()
|
||||
bases = append(bases, oldBases...)
|
||||
|
||||
return markdown.Generate(bases)
|
||||
}
|
||||
|
||||
func (g *MarkdownGenerator) getLines(commits []convention.Commit) []string {
|
||||
func (g *MarkdownGenerator) getNewMarkdownBases(commits []convention.Commit) []markdown.Base {
|
||||
if len(commits) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
lines := make([]string, 0, defaultLinesLen)
|
||||
lines = append(lines, markdownTitle)
|
||||
lines = append(lines, g.composeVersionHeader())
|
||||
result := make([]markdown.Base, 0, defaultBasesLen)
|
||||
|
||||
addedLines := make([]string, 0, defaultLinesLen)
|
||||
fixedLines := make([]string, 0, defaultLinesLen)
|
||||
othersLines := make([]string, 0, defaultLinesLen)
|
||||
commitBases := make(map[string][]markdown.Base)
|
||||
commitBases[addedType] = make([]markdown.Base, 0, defaultBasesLen)
|
||||
commitBases[fixedType] = make([]markdown.Base, 0, defaultBasesLen)
|
||||
commitBases[othersType] = make([]markdown.Base, 0, defaultBasesLen)
|
||||
|
||||
for _, commit := range commits {
|
||||
t := getType(commit.Type)
|
||||
switch t {
|
||||
case addedType:
|
||||
addedLines = append(addedLines, g.composeListItem(commit.RawHeader))
|
||||
commitBases[addedType] = append(commitBases[addedType], markdown.NewListItem(commit.RawHeader))
|
||||
case fixedType:
|
||||
fixedLines = append(fixedLines, g.composeListItem(commit.RawHeader))
|
||||
commitBases[fixedType] = append(commitBases[fixedType], markdown.NewListItem(commit.RawHeader))
|
||||
case othersType:
|
||||
othersLines = append(othersLines, g.composeListItem(commit.RawHeader))
|
||||
commitBases[othersType] = append(commitBases[othersType], markdown.NewListItem(commit.RawHeader))
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(addedLines) != 0 {
|
||||
lines = append(lines, g.composeTypeHeader(addedType))
|
||||
lines = append(lines, addedLines...)
|
||||
if len(commitBases[addedType]) != 0 {
|
||||
result = append(result, markdown.NewHeader(3, addedType))
|
||||
result = append(result, commitBases[addedType]...)
|
||||
}
|
||||
|
||||
if len(fixedLines) != 0 {
|
||||
lines = append(lines, g.composeTypeHeader(fixedType))
|
||||
lines = append(lines, fixedLines...)
|
||||
if len(commitBases[fixedType]) != 0 {
|
||||
result = append(result, markdown.NewHeader(3, fixedType))
|
||||
result = append(result, commitBases[addedType]...)
|
||||
}
|
||||
|
||||
if len(othersLines) != 0 {
|
||||
lines = append(lines, g.composeTypeHeader(othersType))
|
||||
lines = append(lines, othersLines...)
|
||||
if len(commitBases[othersType]) != 0 {
|
||||
result = append(result, markdown.NewHeader(3, othersType))
|
||||
result = append(result, commitBases[othersType]...)
|
||||
}
|
||||
|
||||
return lines
|
||||
return result
|
||||
}
|
||||
|
||||
func (g *MarkdownGenerator) getPreviousLines() []string {
|
||||
prevData, err := ioutil.ReadFile(g.path)
|
||||
if err != nil {
|
||||
return nil
|
||||
func (g *MarkdownGenerator) getOldBases() []markdown.Base {
|
||||
result := make([]markdown.Base, 0, defaultBasesLen)
|
||||
|
||||
lines := strings.Split(g.oldData, string(markdown.NewlineToken))
|
||||
|
||||
result = append(result, markdown.Parse(lines)...)
|
||||
|
||||
if len(result) > 0 && markdown.Equal(result[0], markdown.NewHeader(1, title)) {
|
||||
result = result[1:]
|
||||
}
|
||||
|
||||
prevLines := strings.Split(string(prevData), "\n")
|
||||
finalPrevLines := make([]string, 0, len(prevLines))
|
||||
for _, prevLine := range prevLines {
|
||||
prevLine = strings.TrimSpace(prevLine)
|
||||
if prevLine == "" || prevLine == markdownTitle {
|
||||
continue
|
||||
}
|
||||
|
||||
finalPrevLines = append(finalPrevLines, prevLine)
|
||||
}
|
||||
|
||||
return finalPrevLines
|
||||
}
|
||||
|
||||
func (g *MarkdownGenerator) writeLines(lines []string) error {
|
||||
data := strings.Join(lines, "\n\n")
|
||||
if err := ioutil.WriteFile(g.path, []byte(data), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *MarkdownGenerator) composeVersionHeader() string {
|
||||
year, month, day := g.t.Date()
|
||||
return fmt.Sprintf("## %s (%d-%d-%d)", g.version, year, month, day)
|
||||
}
|
||||
|
||||
func (g *MarkdownGenerator) composeTypeHeader(t string) string {
|
||||
return fmt.Sprintf("### %s", t)
|
||||
}
|
||||
|
||||
func (g *MarkdownGenerator) composeListItem(text string) string {
|
||||
return fmt.Sprintf("- %s", text)
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package changelog
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/haunt98/changeloguru/pkg/convention"
|
||||
"github.com/sebdah/goldie/v2"
|
||||
)
|
||||
|
||||
func TestMarkdownGeneratorGetLines(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
commits []convention.Commit
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
},
|
||||
{
|
||||
name: "1 commit feat",
|
||||
commits: []convention.Commit{
|
||||
{
|
||||
RawHeader: "feat: description",
|
||||
Type: convention.FeatType,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "1 commit fixed",
|
||||
commits: []convention.Commit{
|
||||
{
|
||||
RawHeader: "fix: description",
|
||||
Type: convention.FixType,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "1 commit other",
|
||||
commits: []convention.Commit{
|
||||
{
|
||||
RawHeader: "ci: description",
|
||||
Type: convention.CiType,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed",
|
||||
commits: []convention.Commit{
|
||||
{
|
||||
RawHeader: "feat: description feat",
|
||||
Type: convention.FeatType,
|
||||
},
|
||||
{
|
||||
RawHeader: "fix: description fix",
|
||||
Type: convention.FixType,
|
||||
},
|
||||
{
|
||||
RawHeader: "ci: description ci",
|
||||
Type: convention.CiType,
|
||||
},
|
||||
{
|
||||
RawHeader: "build: description build",
|
||||
Type: convention.BuildType,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
g := goldie.New(t)
|
||||
|
||||
generator := NewMarkdownGenerator("path", "v1.0.0", time.Time{})
|
||||
lines := generator.getLines(tc.commits)
|
||||
g.AssertJson(t, t.Name(), lines)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
[
|
||||
"# CHANGELOG",
|
||||
"## v1.0.0 (1-1-1)",
|
||||
"### Added",
|
||||
"- feat: description"
|
||||
]
|
|
@ -1,6 +0,0 @@
|
|||
[
|
||||
"# CHANGELOG",
|
||||
"## v1.0.0 (1-1-1)",
|
||||
"### Fixed",
|
||||
"- fix: description"
|
||||
]
|
|
@ -1,6 +0,0 @@
|
|||
[
|
||||
"# CHANGELOG",
|
||||
"## v1.0.0 (1-1-1)",
|
||||
"### Others",
|
||||
"- ci: description"
|
||||
]
|
|
@ -1 +0,0 @@
|
|||
null
|
|
@ -1,11 +0,0 @@
|
|||
[
|
||||
"# CHANGELOG",
|
||||
"## v1.0.0 (1-1-1)",
|
||||
"### Added",
|
||||
"- feat: description feat",
|
||||
"### Fixed",
|
||||
"- fix: description fix",
|
||||
"### Others",
|
||||
"- ci: description ci",
|
||||
"- build: description build"
|
||||
]
|
|
@ -9,7 +9,7 @@ const (
|
|||
defaultListToken = '-'
|
||||
alternativeListToken = '*'
|
||||
spaceToken = ' '
|
||||
newlineToken = '\n'
|
||||
NewlineToken = '\n'
|
||||
)
|
||||
|
||||
// Base is single markdown syntax representation
|
||||
|
@ -60,3 +60,7 @@ func (i listItem) String() string {
|
|||
|
||||
return string(defaultListToken) + string(spaceToken) + text
|
||||
}
|
||||
|
||||
func Equal(base1, base2 Base) bool {
|
||||
return base1.String() == base2.String()
|
||||
}
|
||||
|
|
|
@ -9,5 +9,5 @@ func Generate(bases []Base) string {
|
|||
lines[i] = base.String()
|
||||
}
|
||||
|
||||
return strings.Join(lines, string(newlineToken)+string(newlineToken))
|
||||
return strings.Join(lines, string(NewlineToken)+string(NewlineToken))
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func TestGenerate(t *testing.T) {
|
|||
text: "item 2",
|
||||
},
|
||||
},
|
||||
want: "# header\n- item 1\n- item 2",
|
||||
want: "# header\n\n- item 1\n\n- item 2",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue