Skip to content

Commit

Permalink
refactor(parser): tidy up logic and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmckendry committed Jan 12, 2025
1 parent 5c511f5 commit 7b6cf30
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 155 deletions.
138 changes: 81 additions & 57 deletions changelog/changelog.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,32 @@ import (
"cl-parse/git"
)

const (
dateFormat = "2006-01-02"
versionPattern = `## (?:\[)?(?:v)?([\d.]+(?:-[a-zA-Z0-9]+(?:\.[0-9]+)?)?)\]?(?:\((.*?)\))? \((\d{4}-\d{2}-\d{2})\)`
changePattern = `\* (?:\*\*(.*?)\*\*: )?(.+?)\s*(?:\((?:#(\d+))?\)?)?\s*(?:\((.*?)\))?(?:,\s*closes.*)?$`
)

type ChangelogEntry struct {
Version string `json:"version" yaml:"version" toml:"version"`
Date time.Time `json:"date" yaml:"date" toml:"date"`
CompareURL string `json:"compareUrl" yaml:"compareUrl" toml:"compareUrl"`
Changes map[string][]Change `json:"changes" yaml:"changes" toml:"changes"`
Version string `json:"version" yaml:"version" toml:"version"`
Date time.Time `json:"date" yaml:"date" toml:"date"`
CompareURL string `json:"compareUrl" yaml:"compareUrl" toml:"compareUrl"`
Changes map[string][]Change `json:"changes" yaml:"changes" toml:"changes"`
}

type Change struct {
Scope string `json:"scope,omitempty" yaml:"scope,omitempty" toml:"scope,omitempty"`
Description string `json:"description" yaml:"description" toml:"description"`
PR string `json:"pr,omitempty" yaml:"pr,omitempty" toml:"pr,omitempty"`
Commit string `json:"commit,omitempty" yaml:"commit,omitempty" toml:"commit,omitempty"`
CommitBody string `json:"commitBody,omitempty" yaml:"commitBody,omitempty" toml:"commitBody,omitempty"`
Scope string `json:"scope,omitempty" yaml:"scope,omitempty" toml:"scope,omitempty"`
Description string `json:"description" yaml:"description" toml:"description"`
PR string `json:"pr,omitempty" yaml:"pr,omitempty" toml:"pr,omitempty"`
Commit string `json:"commit,omitempty" yaml:"commit,omitempty" toml:"commit,omitempty"`
CommitBody string `json:"commitBody,omitempty" yaml:"commitBody,omitempty" toml:"commitBody,omitempty"`
}

type Parser struct {
entries []ChangelogEntry
IncludeBody bool
}

// Create a new Parser
func NewParser() *Parser {
return &Parser{
entries: make([]ChangelogEntry, 0),
Expand All @@ -50,27 +55,19 @@ func (p *Parser) GetVersion(version string) (*ChangelogEntry, error) {
return &entry, nil
}
}

return nil, fmt.Errorf("version %s not found", version)
}

// Parse the changelog content and return a slice of ChangelogEntry
func (p *Parser) Parse(content string) ([]ChangelogEntry, error) {
scanner := bufio.NewScanner(strings.NewReader(content))

var currentEntry *ChangelogEntry
var currentSection string

versionRegex := regexp.MustCompile(
`## (?:\[)?(?:v)?([\d.]+(?:-[a-zA-Z0-9]+(?:\.[0-9]+)?)?)\]?(?:\((.*?)\))? \((\d{4}-\d{2}-\d{2})\)`,
)
changeRegex := regexp.MustCompile(
`\* (?:\*\*(.*?)\*\*: )?(.+?)\s*(?:\((?:#(\d+))?\)?)?\s*(?:\((.*?)\))?(?:,\s*closes.*)?$`,
)
versionRegex := regexp.MustCompile(versionPattern)
changeRegex := regexp.MustCompile(changePattern)

for scanner.Scan() {
line := scanner.Text()
line = strings.TrimSpace(line)
line := strings.TrimSpace(scanner.Text())

if line == "" || line == "# Changelog" {
continue
Expand All @@ -81,12 +78,10 @@ func (p *Parser) Parse(content string) ([]ChangelogEntry, error) {
p.entries = append(p.entries, *currentEntry)
}

date, _ := time.Parse("2006-01-02", matches[3])
currentEntry = &ChangelogEntry{
Version: matches[1],
Date: date,
CompareURL: matches[2],
Changes: make(map[string][]Change),
var err error
currentEntry, err = p.createNewEntry(matches)
if err != nil {
return nil, err
}
continue
}
Expand All @@ -97,51 +92,80 @@ func (p *Parser) Parse(content string) ([]ChangelogEntry, error) {
}

if strings.HasPrefix(line, "* ") && currentEntry != nil {
matches := changeRegex.FindStringSubmatch(line)
if matches != nil {
change := Change{
Scope: matches[1],
Description: matches[2],
}

if matches[3] != "" {
change.PR = matches[3]
}
if matches[4] != "" {
change.Commit = parseCommitHashFromLink(matches[4])

if p.IncludeBody && change.Commit != "" {
var err error
change.CommitBody, err = git.GetCommmitBodyFromSha(".", change.Commit)
if err != nil {
return nil, fmt.Errorf("failed to get commit message: %w", err)
}
}
}

if currentSection != "" {
currentEntry.Changes[currentSection] = append(
currentEntry.Changes[currentSection],
change,
)
}
if err := p.parseChange(line, changeRegex, currentSection, currentEntry); err != nil {
return nil, err
}
}
}

// add the last entry
if currentEntry != nil {
p.entries = append(p.entries, *currentEntry)
}

return p.entries, nil
}

func (p *Parser) createNewEntry(matches []string) (*ChangelogEntry, error) {
date, err := time.Parse(dateFormat, matches[3])
if err != nil {
return nil, fmt.Errorf("invalid date format: %w", err)
}

return &ChangelogEntry{
Version: matches[1],
Date: date,
CompareURL: matches[2],
Changes: make(map[string][]Change),
}, nil
}

func (p *Parser) parseChange(line string, changeRegex *regexp.Regexp, currentSection string, currentEntry *ChangelogEntry) error {
matches := changeRegex.FindStringSubmatch(line)
if matches == nil {
return nil
}

change := Change{
Scope: matches[1],
Description: matches[2],
}

if matches[3] != "" {
change.PR = matches[3]
}
if matches[4] != "" {
change.Commit = parseCommitHashFromLink(matches[4])
if err := p.addCommitBody(&change); err != nil {
return err
}
}

if currentSection != "" {
currentEntry.Changes[currentSection] = append(
currentEntry.Changes[currentSection],
change,
)
}
return nil
}

func (p *Parser) addCommitBody(change *Change) error {
if !p.IncludeBody || change.Commit == "" {
return nil
}

body, err := git.GetCommmitBodyFromSha(".", change.Commit)
if err != nil {
return fmt.Errorf("failed to get commit message: %w", err)
}
change.CommitBody = body
return nil
}

func parseCommitHashFromLink(link string) string {
parts := strings.Split(link, "/")
possibleHash := parts[len(parts)-1]

// remove the closing parenthesis
if possibleHash[len(possibleHash)-1] == ')' {
possibleHash = possibleHash[:len(possibleHash)-1]
}
Expand Down
Loading

0 comments on commit 7b6cf30

Please sign in to comment.