mirror of
https://github.com/thegeeklab/git-sv.git
synced 2024-11-24 11:10:39 +00:00
feat: add sections to release-notes config (headers is deprecated)
issue: #40
This commit is contained in:
parent
e64d4ddcc1
commit
e650f64783
@ -77,8 +77,14 @@ func defaultConfig() Config {
|
|||||||
UpdatePatch: []string{"build", "ci", "chore", "docs", "fix", "perf", "refactor", "style", "test"},
|
UpdatePatch: []string{"build", "ci", "chore", "docs", "fix", "perf", "refactor", "style", "test"},
|
||||||
IgnoreUnknown: false,
|
IgnoreUnknown: false,
|
||||||
},
|
},
|
||||||
Tag: sv.TagConfig{Pattern: "%d.%d.%d"},
|
Tag: sv.TagConfig{Pattern: "%d.%d.%d"},
|
||||||
ReleaseNotes: sv.ReleaseNotesConfig{Headers: map[string]string{"fix": "Bug Fixes", "feat": "Features", "breaking-change": "Breaking Changes"}},
|
ReleaseNotes: sv.ReleaseNotesConfig{
|
||||||
|
Sections: []sv.ReleaseNotesSectionConfig{
|
||||||
|
{Name: "Features", SectionType: "commits", CommitTypes: []string{"feat"}},
|
||||||
|
{Name: "Bug Fixes", SectionType: "commits", CommitTypes: []string{"fix"}},
|
||||||
|
{Name: "Breaking Changes", SectionType: "breaking-change"},
|
||||||
|
},
|
||||||
|
},
|
||||||
Branches: sv.BranchesConfig{
|
Branches: sv.BranchesConfig{
|
||||||
Prefix: "([a-z]+\\/)?",
|
Prefix: "([a-z]+\\/)?",
|
||||||
Suffix: "(-.*)?",
|
Suffix: "(-.*)?",
|
||||||
@ -129,3 +135,35 @@ func (t *mergeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.V
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func migrateConfig(cfg Config) Config {
|
||||||
|
if cfg.ReleaseNotes.Headers == nil {
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
warnf("config 'release-notes.headers' is deprecated, please use 'sections' instead!")
|
||||||
|
|
||||||
|
return Config{
|
||||||
|
Version: cfg.Version,
|
||||||
|
Versioning: cfg.Versioning,
|
||||||
|
Tag: cfg.Tag,
|
||||||
|
ReleaseNotes: sv.ReleaseNotesConfig{
|
||||||
|
Sections: migrateReleaseNotesConfig(cfg.ReleaseNotes.Headers),
|
||||||
|
},
|
||||||
|
Branches: cfg.Branches,
|
||||||
|
CommitMessage: cfg.CommitMessage,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateReleaseNotesConfig(headers map[string]string) []sv.ReleaseNotesSectionConfig {
|
||||||
|
order := []string{"feat", "fix", "refactor", "perf", "test", "build", "ci", "chore", "docs", "style"}
|
||||||
|
var sections []sv.ReleaseNotesSectionConfig
|
||||||
|
for _, key := range order {
|
||||||
|
if name, exists := headers[key]; exists {
|
||||||
|
sections = append(sections, sv.ReleaseNotesSectionConfig{Name: name, SectionType: sv.ReleaseNotesSectionTypeCommits, CommitTypes: []string{key}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name, exists := headers["breaking-change"]; exists {
|
||||||
|
sections = append(sections, sv.ReleaseNotesSectionConfig{Name: name, SectionType: sv.ReleaseNotesSectionTypeBreakingChange})
|
||||||
|
}
|
||||||
|
return sections
|
||||||
|
}
|
||||||
|
26
sv/config.go
26
sv/config.go
@ -68,5 +68,29 @@ type TagConfig struct {
|
|||||||
|
|
||||||
// ReleaseNotesConfig release notes preferences.
|
// ReleaseNotesConfig release notes preferences.
|
||||||
type ReleaseNotesConfig struct {
|
type ReleaseNotesConfig struct {
|
||||||
Headers map[string]string `yaml:"headers"`
|
Headers map[string]string `yaml:"headers"`
|
||||||
|
Sections []ReleaseNotesSectionConfig `yaml:"sections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg ReleaseNotesConfig) sectionConfig(sectionType string) *ReleaseNotesSectionConfig {
|
||||||
|
for _, sectionCfg := range cfg.Sections {
|
||||||
|
if sectionCfg.SectionType == sectionType {
|
||||||
|
return §ionCfg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReleaseNotesSectionConfig preferences for a single section on release notes.
|
||||||
|
type ReleaseNotesSectionConfig struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
SectionType string `yaml:"section-type"`
|
||||||
|
CommitTypes []string `yaml:"commit-types"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ReleaseNotesSectionTypeCommits ReleaseNotesSectionConfig.SectionType value.
|
||||||
|
ReleaseNotesSectionTypeCommits = "commits"
|
||||||
|
// ReleaseNotesSectionTypeBreakingChange ReleaseNotesSectionConfig.SectionType value.
|
||||||
|
ReleaseNotesSectionTypeBreakingChange = "breaking-change"
|
||||||
|
)
|
||||||
|
@ -23,18 +23,20 @@ func NewReleaseNoteProcessor(cfg ReleaseNotesConfig) *ReleaseNoteProcessorImpl {
|
|||||||
|
|
||||||
// Create create a release note based on commits.
|
// Create create a release note based on commits.
|
||||||
func (p ReleaseNoteProcessorImpl) Create(version *semver.Version, tag string, date time.Time, commits []GitCommitLog) ReleaseNote {
|
func (p ReleaseNoteProcessorImpl) Create(version *semver.Version, tag string, date time.Time, commits []GitCommitLog) ReleaseNote {
|
||||||
|
mapping := commitSectionMapping(p.cfg.Sections)
|
||||||
|
|
||||||
sections := make(map[string]ReleaseNoteSection)
|
sections := make(map[string]ReleaseNoteSection)
|
||||||
authors := make(map[string]struct{})
|
authors := make(map[string]struct{})
|
||||||
var breakingChanges []string
|
var breakingChanges []string
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
authors[commit.AuthorName] = struct{}{}
|
authors[commit.AuthorName] = struct{}{}
|
||||||
if name, exists := p.cfg.Headers[commit.Message.Type]; exists {
|
if sectionCfg, exists := mapping[commit.Message.Type]; exists {
|
||||||
section, sexists := sections[commit.Message.Type]
|
section, sexists := sections[sectionCfg.Name]
|
||||||
if !sexists {
|
if !sexists {
|
||||||
section = ReleaseNoteSection{Name: name, Types: []string{commit.Message.Type}} //TODO: change to support more than one type per section
|
section = ReleaseNoteSection{Name: sectionCfg.Name, Types: sectionCfg.CommitTypes}
|
||||||
}
|
}
|
||||||
section.Items = append(section.Items, commit)
|
section.Items = append(section.Items, commit)
|
||||||
sections[commit.Message.Type] = section
|
sections[sectionCfg.Name] = section
|
||||||
}
|
}
|
||||||
if commit.Message.BreakingMessage() != "" {
|
if commit.Message.BreakingMessage() != "" {
|
||||||
// TODO: if no message found, should use description instead?
|
// TODO: if no message found, should use description instead?
|
||||||
@ -43,12 +45,24 @@ func (p ReleaseNoteProcessorImpl) Create(version *semver.Version, tag string, da
|
|||||||
}
|
}
|
||||||
|
|
||||||
var breakingChangeSection BreakingChangeSection
|
var breakingChangeSection BreakingChangeSection
|
||||||
if name, exists := p.cfg.Headers[breakingChangeMetadataKey]; exists && len(breakingChanges) > 0 {
|
if bcCfg := p.cfg.sectionConfig(ReleaseNotesSectionTypeBreakingChange); bcCfg != nil && len(breakingChanges) > 0 {
|
||||||
breakingChangeSection = BreakingChangeSection{Name: name, Messages: breakingChanges}
|
breakingChangeSection = BreakingChangeSection{Name: bcCfg.Name, Messages: breakingChanges}
|
||||||
}
|
}
|
||||||
return ReleaseNote{Version: version, Tag: tag, Date: date.Truncate(time.Minute), Sections: sections, BreakingChanges: breakingChangeSection, AuthorsNames: authors}
|
return ReleaseNote{Version: version, Tag: tag, Date: date.Truncate(time.Minute), Sections: sections, BreakingChanges: breakingChangeSection, AuthorsNames: authors}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func commitSectionMapping(sections []ReleaseNotesSectionConfig) map[string]ReleaseNotesSectionConfig {
|
||||||
|
mapping := make(map[string]ReleaseNotesSectionConfig)
|
||||||
|
for _, section := range sections {
|
||||||
|
if section.SectionType == ReleaseNotesSectionTypeCommits {
|
||||||
|
for _, commitType := range section.CommitTypes {
|
||||||
|
mapping[commitType] = section
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mapping
|
||||||
|
}
|
||||||
|
|
||||||
// ReleaseNote release note.
|
// ReleaseNote release note.
|
||||||
type ReleaseNote struct {
|
type ReleaseNote struct {
|
||||||
Version *semver.Version
|
Version *semver.Version
|
||||||
|
@ -25,7 +25,7 @@ func TestReleaseNoteProcessorImpl_Create(t *testing.T) {
|
|||||||
tag: "v1.0.0",
|
tag: "v1.0.0",
|
||||||
date: date,
|
date: date,
|
||||||
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "a")},
|
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "a")},
|
||||||
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"t1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "a")})}, nil, map[string]struct{}{"a": {}}),
|
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"Tag 1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "a")})}, nil, map[string]struct{}{"a": {}}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unmapped tag",
|
name: "unmapped tag",
|
||||||
@ -33,7 +33,7 @@ func TestReleaseNoteProcessorImpl_Create(t *testing.T) {
|
|||||||
tag: "v1.0.0",
|
tag: "v1.0.0",
|
||||||
date: date,
|
date: date,
|
||||||
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "a"), commitlog("unmapped", map[string]string{}, "a")},
|
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "a"), commitlog("unmapped", map[string]string{}, "a")},
|
||||||
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"t1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "a")})}, nil, map[string]struct{}{"a": {}}),
|
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"Tag 1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "a")})}, nil, map[string]struct{}{"a": {}}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "breaking changes tag",
|
name: "breaking changes tag",
|
||||||
@ -41,7 +41,7 @@ func TestReleaseNoteProcessorImpl_Create(t *testing.T) {
|
|||||||
tag: "v1.0.0",
|
tag: "v1.0.0",
|
||||||
date: date,
|
date: date,
|
||||||
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "a"), commitlog("unmapped", map[string]string{"breaking-change": "breaks"}, "a")},
|
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "a"), commitlog("unmapped", map[string]string{"breaking-change": "breaks"}, "a")},
|
||||||
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"t1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "a")})}, []string{"breaks"}, map[string]struct{}{"a": {}}),
|
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"Tag 1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "a")})}, []string{"breaks"}, map[string]struct{}{"a": {}}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple authors",
|
name: "multiple authors",
|
||||||
@ -49,12 +49,14 @@ func TestReleaseNoteProcessorImpl_Create(t *testing.T) {
|
|||||||
tag: "v1.0.0",
|
tag: "v1.0.0",
|
||||||
date: date,
|
date: date,
|
||||||
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "author3"), commitlog("t1", map[string]string{}, "author2"), commitlog("t1", map[string]string{}, "author1")},
|
commits: []GitCommitLog{commitlog("t1", map[string]string{}, "author3"), commitlog("t1", map[string]string{}, "author2"), commitlog("t1", map[string]string{}, "author1")},
|
||||||
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"t1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "author3"), commitlog("t1", map[string]string{}, "author2"), commitlog("t1", map[string]string{}, "author1")})}, nil, map[string]struct{}{"author1": {}, "author2": {}, "author3": {}}),
|
want: releaseNote(semver.MustParse("1.0.0"), "v1.0.0", date, map[string]ReleaseNoteSection{"Tag 1": newReleaseNoteSection("Tag 1", []string{"t1"}, []GitCommitLog{commitlog("t1", map[string]string{}, "author3"), commitlog("t1", map[string]string{}, "author2"), commitlog("t1", map[string]string{}, "author1")})}, nil, map[string]struct{}{"author1": {}, "author2": {}, "author3": {}}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
p := NewReleaseNoteProcessor(ReleaseNotesConfig{Headers: map[string]string{"t1": "Tag 1", "t2": "Tag 2", "breaking-change": "Breaking Changes"}})
|
p := NewReleaseNoteProcessor(ReleaseNotesConfig{Sections: []ReleaseNotesSectionConfig{{Name: "Tag 1", SectionType: "commits", CommitTypes: []string{"t1"}},
|
||||||
|
{Name: "Tag 2", SectionType: "commits", CommitTypes: []string{"t2"}},
|
||||||
|
{Name: "Breaking Changes", SectionType: "breaking-change"}}})
|
||||||
if got := p.Create(tt.version, tt.tag, tt.date, tt.commits); !reflect.DeepEqual(got, tt.want) {
|
if got := p.Create(tt.version, tt.tag, tt.date, tt.commits); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("ReleaseNoteProcessorImpl.Create() = %v, want %v", got, tt.want)
|
t.Errorf("ReleaseNoteProcessorImpl.Create() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user