mirror of
https://github.com/thegeeklab/git-sv.git
synced 2024-11-21 22:10:39 +00:00
Merge pull request #1 from bvieira/tag-change-log
Feature: generate release notes and commit log from a existing tag
This commit is contained in:
commit
7183bc4a1f
5
Makefile
5
Makefile
@ -1,4 +1,4 @@
|
|||||||
.PHONY: usage build run test
|
.PHONY: usage build test run tidy release release-all
|
||||||
|
|
||||||
OK_COLOR=\033[32;01m
|
OK_COLOR=\033[32;01m
|
||||||
NO_COLOR=\033[0m
|
NO_COLOR=\033[0m
|
||||||
@ -10,7 +10,8 @@ BIN = git-sv
|
|||||||
|
|
||||||
ECHOFLAGS ?=
|
ECHOFLAGS ?=
|
||||||
|
|
||||||
VERSION ?=
|
BUILD_TIME = $(shell date +"%Y%m%d%H%M")
|
||||||
|
VERSION ?= dev-$(BUILD_TIME)
|
||||||
|
|
||||||
BUILDOS ?= linux
|
BUILDOS ?= linux
|
||||||
BUILDARCH ?= amd64
|
BUILDARCH ?= amd64
|
||||||
|
37
README.md
37
README.md
@ -42,30 +42,27 @@ git sv next-version
|
|||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
|
use `--help` or `-h` to get usage information, dont forget that some commands have unique options too
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
NAME:
|
# sv help
|
||||||
sv - semantic version for git
|
git-sv -h
|
||||||
|
|
||||||
USAGE:
|
|
||||||
git-sv [global options] command [command options] [arguments...]
|
|
||||||
|
|
||||||
VERSION:
|
|
||||||
1.0.0
|
|
||||||
|
|
||||||
COMMANDS:
|
|
||||||
current-version, cv get last released version from git
|
|
||||||
next-version, nv generate the next version based on git commit messages
|
|
||||||
commit-log, cl list all commit logs since last version as jsons
|
|
||||||
release-notes, rn generate release notes
|
|
||||||
tag, tg generate tag with version based on git commit messages
|
|
||||||
help, h Shows a list of commands or help for one command
|
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
|
||||||
--help, -h show help
|
|
||||||
--version, -v print the version
|
|
||||||
|
|
||||||
|
# sv release-notes command help
|
||||||
|
git-sv rn -h
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Available commands
|
||||||
|
|
||||||
|
| Variable | description |
|
||||||
|
| --------- | ---------- |
|
||||||
|
| current-version, cv | get last released version from git |
|
||||||
|
| next-version, nv | generate the next version based on git commit messages |
|
||||||
|
| commit-log, cl | list all commit logs since last version as jsons |
|
||||||
|
| release-notes, rn | generate release notes |
|
||||||
|
| tag, tg | generate tag with version based on git commit messages |
|
||||||
|
| help, h | Shows a list of commands or help for one command |
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Makefile
|
### Makefile
|
||||||
|
@ -4,8 +4,10 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sv4git/sv"
|
"sv4git/sv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"github.com/Masterminds/semver"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func currentVersionHandler(git sv.Git) func(c *cli.Context) error {
|
func currentVersionHandler(git sv.Git) func(c *cli.Context) error {
|
||||||
@ -30,7 +32,7 @@ func nextVersionHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor) f
|
|||||||
return fmt.Errorf("error parsing version: %s from describe, message: %v", describe, err)
|
return fmt.Errorf("error parsing version: %s from describe, message: %v", describe, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err := git.Log(describe)
|
commits, err := git.Log(describe, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting git log, message: %v", err)
|
return fmt.Errorf("error getting git log, message: %v", err)
|
||||||
}
|
}
|
||||||
@ -43,9 +45,14 @@ func nextVersionHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor) f
|
|||||||
|
|
||||||
func commitLogHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor) func(c *cli.Context) error {
|
func commitLogHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor) func(c *cli.Context) error {
|
||||||
return func(c *cli.Context) error {
|
return func(c *cli.Context) error {
|
||||||
describe := git.Describe()
|
var commits []sv.GitCommitLog
|
||||||
|
var err error
|
||||||
|
|
||||||
commits, err := git.Log(describe)
|
if tag := c.String("t"); tag != "" {
|
||||||
|
commits, err = getTagCommits(git, tag)
|
||||||
|
} else {
|
||||||
|
commits, err = git.Log(git.Describe(), "")
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting git log, message: %v", err)
|
return fmt.Errorf("error getting git log, message: %v", err)
|
||||||
}
|
}
|
||||||
@ -61,29 +68,99 @@ func commitLogHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor) fun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTagCommits(git sv.Git, tag string) ([]sv.GitCommitLog, error) {
|
||||||
|
prev, _, err := getTags(git, tag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return git.Log(prev, tag)
|
||||||
|
}
|
||||||
|
|
||||||
func releaseNotesHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor, rnProcessor sv.ReleaseNoteProcessor) func(c *cli.Context) error {
|
func releaseNotesHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor, rnProcessor sv.ReleaseNoteProcessor) func(c *cli.Context) error {
|
||||||
return func(c *cli.Context) error {
|
return func(c *cli.Context) error {
|
||||||
|
var commits []sv.GitCommitLog
|
||||||
|
var rnVersion semver.Version
|
||||||
|
var date time.Time
|
||||||
|
var err error
|
||||||
|
|
||||||
describe := git.Describe()
|
if tag := c.String("t"); tag != "" {
|
||||||
|
rnVersion, date, commits, err = getTagVersionInfo(git, semverProcessor, tag)
|
||||||
currentVer, err := sv.ToVersion(describe)
|
} else {
|
||||||
if err != nil {
|
rnVersion, date, commits, err = getNextVersionInfo(git, semverProcessor)
|
||||||
return fmt.Errorf("error parsing version: %s from describe, message: %v", describe, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err := git.Log(describe)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting git log, message: %v", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nextVer := semverProcessor.NextVersion(currentVer, commits)
|
releasenote := rnProcessor.Get(date, commits)
|
||||||
|
fmt.Println(rnProcessor.Format(releasenote, rnVersion))
|
||||||
releasenote := rnProcessor.Get(commits)
|
|
||||||
fmt.Println(rnProcessor.Format(releasenote, nextVer))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTagVersionInfo(git sv.Git, semverProcessor sv.SemVerCommitsProcessor, tag string) (semver.Version, time.Time, []sv.GitCommitLog, error) {
|
||||||
|
tagVersion, err := sv.ToVersion(tag)
|
||||||
|
if err != nil {
|
||||||
|
return semver.Version{}, time.Time{}, nil, fmt.Errorf("error parsing version: %s from tag, message: %v", tag, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
previousTag, currentTag, err := getTags(git, tag)
|
||||||
|
if err != nil {
|
||||||
|
return semver.Version{}, time.Time{}, nil, fmt.Errorf("error listing tags, message: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
commits, err := git.Log(previousTag, tag)
|
||||||
|
if err != nil {
|
||||||
|
return semver.Version{}, time.Time{}, nil, fmt.Errorf("error getting git log from tag: %s, message: %v", tag, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagVersion, currentTag.Date, commits, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTags(git sv.Git, tag string) (string, sv.GitTag, error) {
|
||||||
|
tags, err := git.Tags()
|
||||||
|
if err != nil {
|
||||||
|
return "", sv.GitTag{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
index := find(tag, tags)
|
||||||
|
if index < 0 {
|
||||||
|
return "", sv.GitTag{}, fmt.Errorf("tag: %s not found", tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
previousTag := ""
|
||||||
|
if index > 0 {
|
||||||
|
previousTag = tags[index-1].Name
|
||||||
|
}
|
||||||
|
return previousTag, tags[index], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func find(tag string, tags []sv.GitTag) int {
|
||||||
|
for i := 0; i < len(tags); i++ {
|
||||||
|
if tag == tags[i].Name {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNextVersionInfo(git sv.Git, semverProcessor sv.SemVerCommitsProcessor) (semver.Version, time.Time, []sv.GitCommitLog, error) {
|
||||||
|
describe := git.Describe()
|
||||||
|
|
||||||
|
currentVer, err := sv.ToVersion(describe)
|
||||||
|
if err != nil {
|
||||||
|
return semver.Version{}, time.Time{}, nil, fmt.Errorf("error parsing version: %s from describe, message: %v", describe, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
commits, err := git.Log(describe, "")
|
||||||
|
if err != nil {
|
||||||
|
return semver.Version{}, time.Time{}, nil, fmt.Errorf("error getting git log, message: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return semverProcessor.NextVersion(currentVer, commits), time.Now(), commits, nil
|
||||||
|
}
|
||||||
|
|
||||||
func tagHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor, rnProcessor sv.ReleaseNoteProcessor) func(c *cli.Context) error {
|
func tagHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor, rnProcessor sv.ReleaseNoteProcessor) func(c *cli.Context) error {
|
||||||
return func(c *cli.Context) error {
|
return func(c *cli.Context) error {
|
||||||
describe := git.Describe()
|
describe := git.Describe()
|
||||||
@ -93,7 +170,7 @@ func tagHandler(git sv.Git, semverProcessor sv.SemVerCommitsProcessor, rnProcess
|
|||||||
return fmt.Errorf("error parsing version: %s from describe, message: %v", describe, err)
|
return fmt.Errorf("error parsing version: %s from describe, message: %v", describe, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
commits, err := git.Log(describe)
|
commits, err := git.Log(describe, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting git log, message: %v", err)
|
return fmt.Errorf("error getting git log, message: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sv4git/sv"
|
"sv4git/sv"
|
||||||
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version for git-sv
|
// Version for git-sv
|
||||||
@ -22,7 +22,7 @@ func main() {
|
|||||||
app.Name = "sv"
|
app.Name = "sv"
|
||||||
app.Version = Version
|
app.Version = Version
|
||||||
app.Usage = "semantic version for git"
|
app.Usage = "semantic version for git"
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "current-version",
|
Name: "current-version",
|
||||||
Aliases: []string{"cv"},
|
Aliases: []string{"cv"},
|
||||||
@ -40,12 +40,14 @@ func main() {
|
|||||||
Aliases: []string{"cl"},
|
Aliases: []string{"cl"},
|
||||||
Usage: "list all commit logs since last version as jsons",
|
Usage: "list all commit logs since last version as jsons",
|
||||||
Action: commitLogHandler(git, semverProcessor),
|
Action: commitLogHandler(git, semverProcessor),
|
||||||
|
Flags: []cli.Flag{&cli.StringFlag{Name: "t", Usage: "get commit log from tag"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "release-notes",
|
Name: "release-notes",
|
||||||
Aliases: []string{"rn"},
|
Aliases: []string{"rn"},
|
||||||
Usage: "generate release notes",
|
Usage: "generate release notes",
|
||||||
Action: releaseNotesHandler(git, semverProcessor, releasenotesProcessor),
|
Action: releaseNotesHandler(git, semverProcessor, releasenotesProcessor),
|
||||||
|
Flags: []cli.Flag{&cli.StringFlag{Name: "t", Usage: "get release note from tag"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "tag",
|
Name: "tag",
|
||||||
|
2
go.mod
2
go.mod
@ -6,5 +6,5 @@ require (
|
|||||||
github.com/Masterminds/semver v1.5.0
|
github.com/Masterminds/semver v1.5.0
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
github.com/kelseyhightower/envconfig v1.4.0
|
github.com/kelseyhightower/envconfig v1.4.0
|
||||||
github.com/urfave/cli v1.22.1
|
github.com/urfave/cli/v2 v2.1.1
|
||||||
)
|
)
|
||||||
|
4
go.sum
4
go.sum
@ -13,7 +13,7 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
|
|||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
|
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
50
sv/git.go
50
sv/git.go
@ -7,6 +7,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
)
|
)
|
||||||
@ -21,8 +22,9 @@ const (
|
|||||||
// Git commands
|
// Git commands
|
||||||
type Git interface {
|
type Git interface {
|
||||||
Describe() string
|
Describe() string
|
||||||
Log(lastTag string) ([]GitCommitLog, error)
|
Log(initialTag, endTag string) ([]GitCommitLog, error)
|
||||||
Tag(version semver.Version) error
|
Tag(version semver.Version) error
|
||||||
|
Tags() ([]GitTag, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitCommitLog description of a single commit log
|
// GitCommitLog description of a single commit log
|
||||||
@ -35,6 +37,12 @@ type GitCommitLog struct {
|
|||||||
Metadata map[string]string `json:"metadata,omitempty"`
|
Metadata map[string]string `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GitTag git tag info
|
||||||
|
type GitTag struct {
|
||||||
|
Name string
|
||||||
|
Date time.Time
|
||||||
|
}
|
||||||
|
|
||||||
// GitImpl git command implementation
|
// GitImpl git command implementation
|
||||||
type GitImpl struct {
|
type GitImpl struct {
|
||||||
messageMetadata map[string]string
|
messageMetadata map[string]string
|
||||||
@ -57,11 +65,17 @@ func (GitImpl) Describe() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Log return git log
|
// Log return git log
|
||||||
func (g GitImpl) Log(lastTag string) ([]GitCommitLog, error) {
|
func (g GitImpl) Log(initialTag, endTag string) ([]GitCommitLog, error) {
|
||||||
format := "--pretty=format:\"%h" + logSeparator + "%s" + logSeparator + "%b" + endLine + "\""
|
format := "--pretty=format:\"%h" + logSeparator + "%s" + logSeparator + "%b" + endLine + "\""
|
||||||
cmd := exec.Command("git", "log", format)
|
var cmd *exec.Cmd
|
||||||
if lastTag != "" {
|
if initialTag == "" && endTag == "" {
|
||||||
cmd = exec.Command("git", "log", lastTag+"..HEAD", format)
|
cmd = exec.Command("git", "log", format)
|
||||||
|
} else if endTag == "" {
|
||||||
|
cmd = exec.Command("git", "log", initialTag+"..HEAD", format)
|
||||||
|
} else if initialTag == "" {
|
||||||
|
cmd = exec.Command("git", "log", endTag, format)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("git", "log", initialTag+".."+endTag, format)
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
@ -85,6 +99,32 @@ func (g GitImpl) Tag(version semver.Version) error {
|
|||||||
return pushCommand.Run()
|
return pushCommand.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tags list repository tags
|
||||||
|
func (g GitImpl) Tags() ([]GitTag, error) {
|
||||||
|
cmd := exec.Command("git", "tag", "-l", "--format", "%(taggerdate:iso8601)#%(refname:short)")
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return parseTagsOutput(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTagsOutput(input string) ([]GitTag, error) {
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(input))
|
||||||
|
var result []GitTag
|
||||||
|
for scanner.Scan() {
|
||||||
|
if line := strings.TrimSpace(scanner.Text()); line != "" {
|
||||||
|
values := strings.Split(line, "#")
|
||||||
|
date, err := time.Parse("2006-01-02 15:04:05 -0700", values[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse tag data, message: %v", err)
|
||||||
|
}
|
||||||
|
result = append(result, GitTag{Name: values[1], Date: date})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseLogOutput(messageMetadata map[string]string, log string) []GitCommitLog {
|
func parseLogOutput(messageMetadata map[string]string, log string) []GitCommitLog {
|
||||||
scanner := bufio.NewScanner(strings.NewReader(log))
|
scanner := bufio.NewScanner(strings.NewReader(log))
|
||||||
scanner.Split(splitAt([]byte(endLine)))
|
scanner.Split(splitAt([]byte(endLine)))
|
||||||
|
@ -19,9 +19,9 @@ func commitlog(t string, metadata map[string]string) GitCommitLog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func releaseNote(sections map[string]ReleaseNoteSection, breakingChanges []string) ReleaseNote {
|
func releaseNote(date time.Time, sections map[string]ReleaseNoteSection, breakingChanges []string) ReleaseNote {
|
||||||
return ReleaseNote{
|
return ReleaseNote{
|
||||||
Date: time.Now().Truncate(time.Minute),
|
Date: date.Truncate(time.Minute),
|
||||||
Sections: sections,
|
Sections: sections,
|
||||||
BreakingChanges: breakingChanges,
|
BreakingChanges: breakingChanges,
|
||||||
}
|
}
|
||||||
|
@ -16,24 +16,24 @@ type releaseNoteTemplate struct {
|
|||||||
BreakingChanges []string
|
BreakingChanges []string
|
||||||
}
|
}
|
||||||
|
|
||||||
const markdownTemplate = `# v{{.Version}} ({{.Date}})
|
const markdownTemplate = `## v{{.Version}} ({{.Date}})
|
||||||
|
|
||||||
{{if .Sections.feat}}## {{.Sections.feat.Name}}
|
{{if .Sections.feat}}### {{.Sections.feat.Name}}
|
||||||
{{range $k,$v := .Sections.feat.Items}}
|
{{range $k,$v := .Sections.feat.Items}}
|
||||||
- {{if $v.Scope}}**{{$v.Scope}}:** {{end}}{{$v.Subject}} ({{$v.Hash}}) {{if $v.Metadata.issueid}}({{$v.Metadata.issueid}}){{end}}{{end}}{{end}}
|
- {{if $v.Scope}}**{{$v.Scope}}:** {{end}}{{$v.Subject}} ({{$v.Hash}}) {{if $v.Metadata.issueid}}({{$v.Metadata.issueid}}){{end}}{{end}}{{end}}
|
||||||
|
|
||||||
{{if .Sections.fix}}## {{.Sections.fix.Name}}
|
{{if .Sections.fix}}### {{.Sections.fix.Name}}
|
||||||
{{range $k,$v := .Sections.fix.Items}}
|
{{range $k,$v := .Sections.fix.Items}}
|
||||||
- {{if $v.Scope}}**{{$v.Scope}}:** {{end}}{{$v.Subject}} ({{$v.Hash}}) {{if $v.Metadata.issueid}}({{$v.Metadata.issueid}}){{end}}{{end}}{{end}}
|
- {{if $v.Scope}}**{{$v.Scope}}:** {{end}}{{$v.Subject}} ({{$v.Hash}}) {{if $v.Metadata.issueid}}({{$v.Metadata.issueid}}){{end}}{{end}}{{end}}
|
||||||
|
|
||||||
{{if .BreakingChanges}}## Breaking Changes
|
{{if .BreakingChanges}}### Breaking Changes
|
||||||
{{range $k,$v := .BreakingChanges}}
|
{{range $k,$v := .BreakingChanges}}
|
||||||
- {{$v}}{{end}}
|
- {{$v}}{{end}}
|
||||||
{{end}}`
|
{{end}}`
|
||||||
|
|
||||||
// ReleaseNoteProcessor release note processor interface.
|
// ReleaseNoteProcessor release note processor interface.
|
||||||
type ReleaseNoteProcessor interface {
|
type ReleaseNoteProcessor interface {
|
||||||
Get(commits []GitCommitLog) ReleaseNote
|
Get(date time.Time, commits []GitCommitLog) ReleaseNote
|
||||||
Format(releasenote ReleaseNote, version semver.Version) string
|
Format(releasenote ReleaseNote, version semver.Version) string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ func NewReleaseNoteProcessor(tags map[string]string) *ReleaseNoteProcessorImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get generate a release note based on commits.
|
// Get generate a release note based on commits.
|
||||||
func (p ReleaseNoteProcessorImpl) Get(commits []GitCommitLog) ReleaseNote {
|
func (p ReleaseNoteProcessorImpl) Get(date time.Time, commits []GitCommitLog) ReleaseNote {
|
||||||
sections := make(map[string]ReleaseNoteSection)
|
sections := make(map[string]ReleaseNoteSection)
|
||||||
var breakingChanges []string
|
var breakingChanges []string
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
@ -67,7 +67,7 @@ func (p ReleaseNoteProcessorImpl) Get(commits []GitCommitLog) ReleaseNote {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReleaseNote{Date: time.Now().Truncate(time.Minute), Sections: sections, BreakingChanges: breakingChanges}
|
return ReleaseNote{Date: date.Truncate(time.Minute), Sections: sections, BreakingChanges: breakingChanges}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format format a release note.
|
// Format format a release note.
|
||||||
|
@ -3,34 +3,41 @@ package sv
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReleaseNoteProcessorImpl_Get(t *testing.T) {
|
func TestReleaseNoteProcessorImpl_Get(t *testing.T) {
|
||||||
|
date := time.Now()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
date time.Time
|
||||||
commits []GitCommitLog
|
commits []GitCommitLog
|
||||||
want ReleaseNote
|
want ReleaseNote
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "mapped tag",
|
name: "mapped tag",
|
||||||
|
date: date,
|
||||||
commits: []GitCommitLog{commitlog("t1", map[string]string{})},
|
commits: []GitCommitLog{commitlog("t1", map[string]string{})},
|
||||||
want: releaseNote(map[string]ReleaseNoteSection{"t1": rnSection("Tag 1", []GitCommitLog{commitlog("t1", map[string]string{})})}, nil),
|
want: releaseNote(date, map[string]ReleaseNoteSection{"t1": rnSection("Tag 1", []GitCommitLog{commitlog("t1", map[string]string{})})}, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unmapped tag",
|
name: "unmapped tag",
|
||||||
|
date: date,
|
||||||
commits: []GitCommitLog{commitlog("t1", map[string]string{}), commitlog("unmapped", map[string]string{})},
|
commits: []GitCommitLog{commitlog("t1", map[string]string{}), commitlog("unmapped", map[string]string{})},
|
||||||
want: releaseNote(map[string]ReleaseNoteSection{"t1": rnSection("Tag 1", []GitCommitLog{commitlog("t1", map[string]string{})})}, nil),
|
want: releaseNote(date, map[string]ReleaseNoteSection{"t1": rnSection("Tag 1", []GitCommitLog{commitlog("t1", map[string]string{})})}, nil),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "breaking changes tag",
|
name: "breaking changes tag",
|
||||||
|
date: date,
|
||||||
commits: []GitCommitLog{commitlog("t1", map[string]string{}), commitlog("unmapped", map[string]string{"breakingchange": "breaks"})},
|
commits: []GitCommitLog{commitlog("t1", map[string]string{}), commitlog("unmapped", map[string]string{"breakingchange": "breaks"})},
|
||||||
want: releaseNote(map[string]ReleaseNoteSection{"t1": rnSection("Tag 1", []GitCommitLog{commitlog("t1", map[string]string{})})}, []string{"breaks"}),
|
want: releaseNote(date, map[string]ReleaseNoteSection{"t1": rnSection("Tag 1", []GitCommitLog{commitlog("t1", map[string]string{})})}, []string{"breaks"}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
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(map[string]string{"t1": "Tag 1", "t2": "Tag 2"})
|
p := NewReleaseNoteProcessor(map[string]string{"t1": "Tag 1", "t2": "Tag 2"})
|
||||||
if got := p.Get(tt.commits); !reflect.DeepEqual(got, tt.want) {
|
if got := p.Get(tt.date, tt.commits); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("ReleaseNoteProcessorImpl.Get() = %v, want %v", got, tt.want)
|
t.Errorf("ReleaseNoteProcessorImpl.Get() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user