-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add command to create a markdown changelog file
- Loading branch information
1 parent
6a27211
commit b874c81
Showing
21 changed files
with
2,144 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,4 @@ | |
|
||
# Dependency directories (remove the comment below to include it) | ||
# vendor/ | ||
dist/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
--- | ||
run: | ||
tests: true | ||
# tests: false | ||
skip-dirs: | ||
- .github | ||
- build | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/zbindenren/cc/internal/cmd" | ||
) | ||
|
||
func main() { | ||
command := cmd.New() | ||
if err := command.Run(); err != nil { | ||
log.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
// Package config configures the changelog generation. | ||
package config | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"sort" | ||
|
||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
const ( | ||
// FileName is the configuration file name. | ||
FileName = ".cc.yml" | ||
) | ||
|
||
// common errors | ||
var ( | ||
ErrNotFound = errors.New("not found") | ||
ErrEmpty = errors.New("empty config") | ||
) | ||
|
||
// Changelog configures the changelog. | ||
type Changelog struct { | ||
Sections []Section `yaml:"sections"` | ||
Flavor string `yaml:"flavor"` | ||
} | ||
|
||
// Section is a section config. | ||
type Section struct { | ||
Type string `yaml:"type"` | ||
Title string `yaml:"title"` | ||
Hidden bool `yaml:"hidden"` | ||
} | ||
|
||
// Title creates the title from the header type. | ||
func (c Changelog) Title(headerType string) (title string, ok bool) { | ||
for _, s := range c.Sections { | ||
if s.Type == headerType { | ||
return s.Title, true | ||
} | ||
} | ||
|
||
return "", false | ||
} | ||
|
||
// IsHidden returns true if section should be hidden in changelog. | ||
func (c Changelog) IsHidden(headerType string) bool { | ||
for _, s := range c.Sections { | ||
if s.Type == headerType { | ||
return s.Hidden | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
// List returns not hidden section titles. | ||
func (c Changelog) List() []string { | ||
l := make([]string, 0, len(c.Sections)) | ||
|
||
for _, s := range c.Sections { | ||
if !s.Hidden { | ||
l = append(l, s.Title) | ||
} | ||
} | ||
|
||
sort.Strings(l) | ||
|
||
l = append([]string{"Breaking Changes"}, l...) | ||
|
||
return l | ||
} | ||
|
||
// Validate validates configuration. | ||
func (c Changelog) Validate() error { | ||
for _, s := range c.Sections { | ||
if err := s.validate(); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
if !(c.Flavor == "gitlab" || c.Flavor == "github") { | ||
return errors.New("flavor has to be either 'gitlab' or github") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Load is looking for a configuration file named '.cc.yml' in dir. If found | ||
// it tries to unmarshal it into Changelog. | ||
func Load(dir string) (*Changelog, error) { | ||
configPath := filepath.Join(dir, FileName) | ||
if _, err := os.Stat(configPath); os.IsNotExist(err) { | ||
return nil, ErrNotFound | ||
} | ||
|
||
b, err := ioutil.ReadFile(configPath) // nolint: gosec | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to read %s: %w", configPath, err) | ||
} | ||
|
||
c := Changelog{ | ||
Flavor: "gitlab", | ||
} | ||
|
||
if err := yaml.Unmarshal(b, &c); err != nil { | ||
return nil, fmt.Errorf("failed to parse %s: %w", configPath, err) | ||
} | ||
|
||
if len(c.Sections) == 0 { | ||
return nil, ErrEmpty | ||
} | ||
|
||
return &c, nil | ||
} | ||
|
||
// Write writes section configration to <dir>/.cc.yml | ||
func Write(dir string, c Changelog) error { | ||
p := filepath.Join(dir, FileName) | ||
|
||
b, err := yaml.Marshal(c) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if err := ioutil.WriteFile(p, b, 0600); err != nil { | ||
return fmt.Errorf("failed to write file %s: %w", p, err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Default represents the default configuration. | ||
var Default = Changelog{ | ||
Flavor: "gitlab", | ||
Sections: []Section{ | ||
{ | ||
Type: "build", | ||
Title: "Build System", | ||
Hidden: true, | ||
}, | ||
{ | ||
Type: "docs", | ||
Title: "Documentation", | ||
Hidden: true, | ||
}, | ||
{ | ||
Type: "feat", | ||
Title: "New Features", | ||
Hidden: false, | ||
}, | ||
{ | ||
Type: "fix", | ||
Title: "Bug Fixes", | ||
Hidden: false, | ||
}, | ||
{ | ||
Type: "refactor", | ||
Title: "Code Refactoring", | ||
Hidden: true, | ||
}, | ||
{ | ||
Type: "test", | ||
Title: "Test", | ||
Hidden: true, | ||
}, | ||
{ | ||
Type: "chore", | ||
Title: "Tasks", | ||
Hidden: true, | ||
}, | ||
}, | ||
} | ||
|
||
func (s Section) validate() error { | ||
if s.Title == "" { | ||
return errors.New("title cannot be empty") | ||
} | ||
|
||
if s.Type == "" { | ||
return errors.New("type cannot be empty") | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package config | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"github.com/tj/assert" | ||
) | ||
|
||
func TestWriteLoadConfig(t *testing.T) { | ||
tmpDir, err := ioutil.TempDir("", "writeloadtest") | ||
require.NoError(t, err) | ||
|
||
defer os.RemoveAll(tmpDir) | ||
|
||
err = Write(tmpDir, Default) | ||
require.NoError(t, err) | ||
|
||
c, err := Load(tmpDir) | ||
require.NoError(t, err) | ||
|
||
require.Equal(t, Default, *c) | ||
|
||
_, err = Load(".") | ||
require.Equal(t, ErrNotFound, err) | ||
} | ||
|
||
func TestIsHidden(t *testing.T) { | ||
assert.True(t, Default.IsHidden("chore")) | ||
assert.False(t, Default.IsHidden("fix")) | ||
} | ||
|
||
func TestTitle(t *testing.T) { | ||
title, ok := Default.Title("feat") | ||
assert.True(t, ok) | ||
assert.Equal(t, "New Features", title) | ||
|
||
_, ok = Default.Title("not-exist") | ||
assert.False(t, ok) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.