diff --git a/GNUmakefile b/GNUmakefile index b221f6490..12fe7527c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -409,3 +409,8 @@ missing: ## Check for packages not being tested ec2info: ## Generate AWS EC2 CPU specification table @echo "==> Generating AWS EC2 specifications ..." @go run -modfile tools/go.mod tools/ec2info/main.go + +.PHONY: cl +cl: ## Create a new Changelog entry + @go run -modfile tools/go.mod tools/cl-entry/main.go + diff --git a/contributing/CHANGELOG.md b/contributing/CHANGELOG.md index c7816d6d5..27e346656 100644 --- a/contributing/CHANGELOG.md +++ b/contributing/CHANGELOG.md @@ -18,6 +18,12 @@ Use the PR number as the file name. Enterprise private changes should have an en The `.txt` files have a markdown-like syntax, with a tag signifying the entry type. +Use the `tools/cl-entry` command to help generate a changelog entry file. + +```shell +make cl +``` + Below are some examples of how to generate a CHANGELOG entry with your pull request. ### Improvement diff --git a/tools/cl-entry/main.go b/tools/cl-entry/main.go new file mode 100644 index 000000000..477fd6228 --- /dev/null +++ b/tools/cl-entry/main.go @@ -0,0 +1,128 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" +) + +const ( + pr = `Must have a Pull Request already open. + Enter PR # => ` + + kind = `Choose type, one of + 1. bug + 2. improvement + 3. security + 4. breaking-change + 5. note + 6. deprecation + Enter Kind => ` + + note = `Write a note, for example + build: Added make target for creating changelog entries + Enter Note => ` +) + +var noteRe = regexp.MustCompile(`[a-z0-9/\s]+: .+`) + +func main() { + pr, err := ask(pr) + check(err) + + n, err := ask(kind) + check(err) + + label, err := label(n) + check(err) + + body, err := askStr(note) + check(err) + + msg, err := cleanup(body) + check(err) + + file, err := write(pr, label, msg) + check(err) + + fmt.Println("Created", file) +} + +func write(pr int, label, msg string) (string, error) { + filename := filepath.Join(".changelog", fmt.Sprintf("%d.txt", pr)) + sb := new(strings.Builder) + sb.WriteString("```release-note:") + sb.WriteString(label) + sb.WriteString("\n") + sb.WriteString(msg) + sb.WriteString("\n") + sb.WriteString("```\n") + s := sb.String() + if err := os.WriteFile(filename, []byte(s), 0o644); err != nil { + return "", err + } + return filename, nil +} + +func cleanup(note string) (string, error) { + note = strings.TrimSpace(note) + note = strings.TrimSuffix(note, ".") + if !noteRe.MatchString(note) { + return "", errors.New("note does not comply with format") + } + return note, nil +} + +func label(n int) (string, error) { + var label string + switch n { + case 1: + label = "bug" + case 2: + label = "improvement" + case 3: + label = "security" + case 4: + label = "breaking-change" + case 5: + label = "note" + case 6: + label = "deprecation" + default: + return "", errors.New("not a valid type, must be 1-6") + } + return label, nil +} + +func ask(q string) (int, error) { + r := bufio.NewReader(os.Stdin) + fmt.Print(q) + line, err := r.ReadString('\n') + if err != nil { + return 0, err + } + i, err := strconv.Atoi(strings.TrimSpace(line)) + if err != nil { + return 0, err + } + return i, nil +} + +func askStr(q string) (string, error) { + r := bufio.NewReader(os.Stdin) + fmt.Print(q) + line, err := r.ReadString('\n') + return strings.TrimSpace(line), err +} + +func check(err error) { + if err != nil { + fmt.Fprintf(os.Stderr, "failure: %v\n", err) + os.Exit(1) + } +} diff --git a/tools/go.mod b/tools/go.mod index 4e570d979..a36f7ad90 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -1,11 +1,11 @@ module github.com/hashicorp/nomad/tools -go 1.18 +go 1.19 require ( github.com/aws/aws-sdk-go v1.37.26 github.com/hashicorp/go-set v0.1.6 - github.com/shoenig/test v0.4.0 + github.com/shoenig/test v0.4.4 ) require ( diff --git a/tools/go.sum b/tools/go.sum index 5433d3e56..271d35160 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -13,8 +13,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/shoenig/test v0.4.0 h1:3X4xG/Chx7mzi0h71Sm6Vo38q0EYaQIBZpYFRcA1HVM= -github.com/shoenig/test v0.4.0/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0= +github.com/shoenig/test v0.4.4 h1:juucmjQTPYUfO2+rID1wfQqsreSlk+2I8K/bQFsUZ9c= +github.com/shoenig/test v0.4.4/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=