Skip to content

Commit

Permalink
Merge pull request #1008 from j0n3lson/fr-use-templates
Browse files Browse the repository at this point in the history
Add support for using arbitrary Go template when generating markdown.
  • Loading branch information
k8s-ci-robot committed Mar 4, 2020
2 parents 15d26e2 + 4d518e7 commit 85301b5
Show file tree
Hide file tree
Showing 15 changed files with 588 additions and 18 deletions.
2 changes: 2 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,5 @@ linters-settings:
- typeUnparen
- unnamedResult
- unnecessaryBlock
gocyclo:
min-complexity: 31
10 changes: 7 additions & 3 deletions cmd/release-notes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ level=debug timestamp=2019-07-30T04:02:44.3716249Z caller=notes.go:497 msg="Excl
| release-tars | RELEASE_TARS | | No | Directory of tars to sha512 sum for display |
| **OUTPUT OPTIONS** |
| output | OUTPUT | | No | The path where the release notes will be written |
| format | FORMAT | markdown | Yes | The format for notes output (options: markdown, json) |
| format | FORMAT | markdown | Yes | The format for notes output (options: markdown, json, go-template:path/to/template.file) |
| release-version | RELEASE_VERSION | | No | The release version to tag the notes with |
| **LOG OPTIONS** |
| debug | DEBUG | false | No | Enable debug logging (options: true, false) |
Expand Down Expand Up @@ -125,6 +125,10 @@ cp ./bazel-bin/cmd/release-notes/darwin_amd64_stripped/release-notes /usr/local/

Check out the rendering of 1.11's release notes [here](https://gist.github.com/marpaia/acfdb889f362195bb683e9e09ce196bc).

### Why formats are supported?
### What formats are supported?

Right now the tool can output release notes in Markdown and JSON. The tool
also supports arbitrary formats using go-templates. The template has access
to fields in the `Document` struct. For an example, see the default markdown
template (`pkg/notes/internal/template.go`) used to render the stock format.

Right now the tool can output release notes in Markdown and JSON.
23 changes: 15 additions & 8 deletions cmd/release-notes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ func init() {
cmd.PersistentFlags().StringVar(
&opts.Format,
"format",
util.EnvDefault("FORMAT", "markdown"),
"The format for notes output (options: markdown, json)",
util.EnvDefault("FORMAT", "go-template:default"),
fmt.Sprintf("The format for notes output (options: %s)",
strings.Join([]string{"markdown", "json", "go-template:default"}, ", "),
),
)

cmd.PersistentFlags().StringVar(
Expand Down Expand Up @@ -241,8 +243,8 @@ func WriteReleaseNotes(releaseNotes notes.ReleaseNotes, history notes.ReleaseNot
}

// Contextualized release notes can be printed in a variety of formats
switch opts.Format {
case "json":
switch format := opts.Format; {
case format == "json":
byteValue, err := ioutil.ReadAll(output)
if err != nil {
return err
Expand Down Expand Up @@ -275,15 +277,20 @@ func WriteReleaseNotes(releaseNotes notes.ReleaseNotes, history notes.ReleaseNot
if err := enc.Encode(releaseNotes); err != nil {
return errors.Wrapf(err, "encoding JSON output")
}
case "markdown":
case strings.Contains(format, "go-template"):
goTemplate := strings.Split(format, ":")[1]

doc, err := document.CreateDocument(releaseNotes, history)
if err != nil {
return errors.Wrapf(err, "creating release note document")
}

markdown, err := doc.RenderMarkdown(
opts.ReleaseBucket, opts.ReleaseTars, opts.StartRev, opts.EndRev,
)
// TODO: Not sure these options are guaranteed to be set but we need
// them in rendering. Perhaps these should be set in CreateDocument()?
doc.PreviousRevision = opts.StartRev
doc.CurrentRevision = opts.EndRev

markdown, err := doc.RenderMarkdownTemplate(opts.ReleaseBucket, opts.ReleaseTars, goTemplate)
if err != nil {
return errors.Wrapf(err, "rendering release note document to markdown")
}
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ go 1.13
require (
cloud.google.com/go v0.44.3
github.com/GoogleCloudPlatform/testgrid v0.0.1-alpha.4
github.com/bazelbuild/rules_go v0.22.1
github.com/blang/semver v3.5.1+incompatible
github.com/golangci/golangci-lint v1.23.3
github.com/google/go-github/v29 v29.0.3
github.com/google/uuid v1.1.1
github.com/kr/pretty v0.1.0
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481
github.com/pkg/errors v0.9.1
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYU
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bazelbuild/rules_go v0.22.1 h1:GRtyhztX3PNl4lhPhhn+eORpNfrFvygcVCQKgMv8lG8=
github.com/bazelbuild/rules_go v0.22.1/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
Expand Down Expand Up @@ -188,6 +190,7 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk=
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s=
Expand Down
8 changes: 7 additions & 1 deletion pkg/notes/document/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["document_test.go"],
data = ["testdata/document.md.golden"],
embed = [":go_default_library"],
deps = ["@com_github_stretchr_testify//require:go_default_library"],
deps = [
"//pkg/notes/internal:go_default_library",
"@com_github_kr_pretty//:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
],
)

filegroup(
Expand Down
119 changes: 116 additions & 3 deletions pkg/notes/document/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,101 @@ import (
"path/filepath"
"sort"
"strings"
"text/template"

"github.com/pkg/errors"
"k8s.io/release/pkg/notes"
)

// Document represents the underlying structure of a release notes document.
type Document struct {
NotesWithActionRequired Notes `json:"action_required"`
NotesUncategorized Notes `json:"uncategorized"`
NotesByKind NotesByKind `json:"kinds"`
NotesWithActionRequired Notes `json:"action_required"`
NotesUncategorized Notes `json:"uncategorized"`
NotesByKind NotesByKind `json:"kinds"`
Downloads *FileMetadata `json:"downloads"`
CurrentRevision string `json:"release_tag"`
PreviousRevision string
}

// FileMetadata contains metadata about files associated with the release.
type FileMetadata struct {
// Files containing source code.
Source []File

// Client binaries.
Client []File

// Server binaries.
Server []File

// TODO: What is this?
Node []File
}

// FetchMetadata generates file metadata from files in `dir`
func (f *FileMetadata) FetchMetadata(dir, urlPrefix, tag string) (*FileMetadata, error) {
if dir == "" {
return nil, nil
}
if tag == "" {
return nil, errors.New("release tags not specified")
}
if urlPrefix == "" {
return nil, errors.New("url prefix not specified")
}

fm := new(FileMetadata)
m := map[*[]File][]string{
&fm.Source: {"kubernetes.tar.gz", "kubernetes-src.tar.gz"},
&fm.Client: {"kubernetes-client*.tar.gz"},
&fm.Server: {"kubernetes-server*.tar.gz"},
&fm.Node: {"kubernetes-node*.tar.gz"},
}
for fileType, patterns := range m {
fileMetadata, err := f.newFile(dir, patterns, urlPrefix, tag)
if err != nil {
return nil, errors.Wrap(err, "fetching file metadata")
}
*fileType = append(*fileType, fileMetadata...)
}

return fm, nil
}

func (f *FileMetadata) newFile(dir string, patterns []string, urlPrefix, tag string) ([]File, error) {
var files []File
for _, pattern := range patterns {
matches, err := filepath.Glob(filepath.Join(dir, pattern))
if err != nil {
return nil, err
}

for _, filePath := range matches {
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer f.Close()

h := sha512.New()
if _, err := io.Copy(h, f); err != nil {
return nil, err
}

fileName := filepath.Base(filePath)
files = append(files, File{
Checksum: fmt.Sprintf("%x", h.Sum(nil)),
Name: fileName,
URL: fmt.Sprintf("%s/%s/%s", urlPrefix, tag, fileName),
})
}
}
return files, nil
}

// A File is a downloadable file.
type File struct {
Checksum, Name, URL string
}

type Kind string
Expand Down Expand Up @@ -117,6 +202,34 @@ func CreateDocument(releaseNotes notes.ReleaseNotes, history notes.ReleaseNotesH
return doc, nil
}

// RenderMarkdownTemplate renders a document using the Go template in `goTemplate`.
func (d *Document) RenderMarkdownTemplate(bucket, fileDir, goTemplate string) (string, error) {
urlPrefix := fmt.Sprintf("https://storage.googleapis.com/%s/release", bucket)
if bucket == "kubernetes-release" {
urlPrefix = "https://dl.k8s.io"
}

fm := new(FileMetadata)
fileMetadata, err := fm.FetchMetadata(fileDir, urlPrefix, d.CurrentRevision)
if err != nil {
return "", errors.Wrap(err, "fetching downloads metadata")
}
d.Downloads = fileMetadata

tmpl, err := template.New("markdown").
Funcs(template.FuncMap{"prettyKind": prettyKind}).
Parse(goTemplate)
if err != nil {
return "", errors.Wrap(err, "parsing template")
}

var s strings.Builder
if err := tmpl.Execute(&s, d); err != nil {
return "", errors.Wrapf(err, "rendering with template")
}
return s.String(), nil
}

// RenderMarkdown accepts a Document and writes a version of that document to
// supplied io.Writer in markdown format.
func (d *Document) RenderMarkdown(bucket, tars, prevTag, newTag string) (string, error) {
Expand Down

0 comments on commit 85301b5

Please sign in to comment.