Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref(*): fix changelog global command #146

Merged
merged 1 commit into from
Nov 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 47 additions & 15 deletions actions/generate_changelog.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,64 @@ import (
"io"
"io/ioutil"
"log"
"sort"
"sync"

"github.com/BurntSushi/toml"
"github.com/deis/deisrel/changelog"
"github.com/deis/deisrel/components"
"github.com/google/go-github/github"
"github.com/urfave/cli"
)

// GenerateChangelog is the CLI action for creating an aggregated changelog from all of the Deis Workflow repos.
func GenerateChangelog(client *github.Client, dest io.Writer) func(*cli.Context) error {
return func(c *cli.Context) error {
repoMapFile := c.Args().Get(0)
oldTag := c.Args().Get(1)
newTag := c.Args().Get(2)
if repoMapFile == "" || oldTag == "" || newTag == "" {
log.Fatal("Usage: changelog global <repo map> <old-release> <new-release>")
paramsFile := c.Args().Get(0)
repoMapFile := c.Args().Get(1)
if paramsFile == "" || repoMapFile == "" {
log.Fatal("Usage: changelog global <previous chart release params file> <repo map>")
}
versions := []components.ComponentVersion{}

out, err := ioutil.ReadFile(repoMapFile)
res := make(map[string]interface{})
out, err := ioutil.ReadFile(paramsFile)
if err != nil {
log.Fatal(err.Error())
return cli.NewExitError(err.Error(), 2)
}
if err := toml.Unmarshal(out, &res); err != nil {
return cli.NewExitError(err.Error(), 3)
}

mapping := make(map[string][]string)
out, err = ioutil.ReadFile(repoMapFile)
if err != nil {
return cli.NewExitError(err.Error(), 2)
}
if err := json.Unmarshal(out, &mapping); err != nil {
return cli.NewExitError(err.Error(), 3)
}

repoMap := make(map[string][]string)
err = json.Unmarshal(out, &repoMap)
versions, err = components.CheckVersions(res, mapping, client)
if err != nil {
log.Fatal(err.Error())
return cli.NewExitError(err.Error(), 4)
}

vals, errs := generateChangelogVals(client, repoMap, oldTag, newTag)
vals, errs := generateChangelogVals(client, mapping, versions)
if len(errs) > 0 {
for _, err := range errs {
log.Printf("Error: %s", err)
}
}
if err := changelog.Tpl.Execute(dest, changelog.MergeValues(oldTag, newTag, vals)); err != nil {
sort.Sort(changelog.ByName(vals))
if err := changelog.Tpl.Execute(dest, changelog.MergeValues("", "", vals)); err != nil {
log.Fatalf("could not template changelog: %s", err)
}
return nil
}
}

func generateChangelogVals(client *github.Client, repoMap map[string][]string, oldTag, newTag string) ([]changelog.Values, []error) {
func generateChangelogVals(client *github.Client, repoMap map[string][]string, versions []components.ComponentVersion) ([]changelog.Values, []error) {
var wg sync.WaitGroup
done := make(chan bool)
valsCh := make(chan changelog.Values)
Expand All @@ -56,12 +72,17 @@ func generateChangelogVals(client *github.Client, repoMap map[string][]string, o
wg.Add(1)
go func(repo string) {
defer wg.Done()
vals := &changelog.Values{OldRelease: oldTag, NewRelease: newTag}
_, err := changelog.SingleRepoVals(client, vals, newTag, repo, true)
component := repoMap[repo][0]
componentVersion, err := findComponentVersionByName(versions, component)
if err != nil {
errCh <- err
return
}
vals := &changelog.Values{RepoName: repo, OldRelease: componentVersion.ChartVersion, NewRelease: componentVersion.ComponentVersion}
if _, err := changelog.SingleRepoVals(client, vals, componentVersion.ComponentVersion, repo, true); err != nil {
errCh <- err
return
}
valsCh <- *vals
}(repo)
}
Expand All @@ -84,3 +105,14 @@ func generateChangelogVals(client *github.Client, repoMap map[string][]string, o
}
}
}

// findComponentVersionByName finds a particular ComponentVersion from an array of
// ComponentVersions based on Name; returns errComponentVersionNotFound if not found
func findComponentVersionByName(componentVersions []components.ComponentVersion, componentName string) (components.ComponentVersion, error) {
for _, componentVersion := range componentVersions {
if componentVersion.Name == componentName {
return componentVersion, nil
}
}
return components.ComponentVersion{}, errComponentVersionNotFound{componentName: componentName}
}
13 changes: 13 additions & 0 deletions actions/generate_changelog_err.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package actions

import (
"fmt"
)

type errComponentVersionNotFound struct {
componentName string
}

func (e errComponentVersionNotFound) Error() string {
return fmt.Sprintf("A ComponentVersion for component named '%s' not found.", e.componentName)
}
24 changes: 23 additions & 1 deletion changelog/changelog.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
package changelog

import (
"fmt"
"text/template"
)

const (
tplStr = `### {{.OldRelease}} -> {{.NewRelease}}
tplStr = `{{ if and .OldRelease .NewRelease }}
### {{.OldRelease}} -> {{.NewRelease}}
{{end}}

{{ if (len .Releases) gt 0 -}}
#### Releases

{{range .Releases}}- {{.}}
{{end}}

{{- end}}
{{ if (len .Features) gt 0 -}}
#### Features

Expand Down Expand Up @@ -55,8 +65,16 @@ var (
Tpl = template.Must(template.New("changelog").Parse(tplStr))
)

// ByName takes an array of Values structs and sorts in alphabetical order of name
type ByName []Values

func (v ByName) Len() int { return len(v) }
func (v ByName) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v ByName) Less(i, j int) bool { return v[i].RepoName < v[j].RepoName }

// Values represents the values that are required to render a changelog
type Values struct {
RepoName string
OldRelease string
NewRelease string
Features []string
Expand All @@ -65,6 +83,7 @@ type Values struct {
Tests []string
Maintenance []string
Refactors []string
Releases []string
}

// MergeValues merges all of the slices in vals together into a single Values struct which has OldRelease set to oldRel and NewRelease set to newRel
Expand All @@ -77,6 +96,9 @@ func MergeValues(oldRel, newRel string, vals []Values) *Values {
ret.Documentation = append(ret.Documentation, val.Documentation...)
ret.Tests = append(ret.Tests, val.Tests...)
ret.Maintenance = append(ret.Maintenance, val.Maintenance...)
if (val.OldRelease != val.NewRelease) {
ret.Releases = append(ret.Releases, fmt.Sprintf("%s %s -> %s", val.RepoName, val.OldRelease, val.NewRelease))
}
}
return ret
}
8 changes: 5 additions & 3 deletions changelog/changelog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,15 @@ func TestTemplate(t *testing.T) {
}

func TestMergeValues(t *testing.T) {
val1 := Values{Features: []string{"feat1"}}
val2 := Values{Fixes: []string{"fix1"}, Features: []string{"feat2"}}
res := MergeValues("old", "new", []Values{val1, val2})
val1 := Values{RepoName: "repo-a", OldRelease: "v1.2.3", NewRelease: "v1.2.4", Features: []string{"feat1"}}
val2 := Values{RepoName: "repo-b", OldRelease: "v4.5.6", NewRelease: "v4.6.0", Fixes: []string{"fix1"}, Features: []string{"feat2"}}
val3 := Values{OldRelease: "v1.2.3", NewRelease: "v1.2.3"} // no change; should not be added to res.Releases
res := MergeValues("old", "new", []Values{val1, val2, val3})
assert.Equal(t, res.OldRelease, "old", "old release")
assert.Equal(t, res.NewRelease, "new", "new release")
assert.Equal(t, len(res.Features), 2, "length of features slice")
assert.Equal(t, len(res.Fixes), 1, "length of fixes slice")
assert.Equal(t, res.Features, []string{"feat1", "feat2"}, "features slice")
assert.Equal(t, res.Fixes, []string{"fix1"}, "fixes slice")
assert.Equal(t, res.Releases, []string{"repo-a v1.2.3 -> v1.2.4", "repo-b v4.5.6 -> v4.6.0"}, "releases slice")
}
2 changes: 1 addition & 1 deletion changelog/single_repo_err.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type errTagNotFoundForRepo struct {
}

func (e errTagNotFoundForRepo) Error() string {
return fmt.Sprintf("tag %s not found for repo %s", e.tagName, e.repoName)
return fmt.Sprintf("tag %s not found for repo %s; Changelog entries will need to be added in manually", e.tagName, e.repoName)
}

type errCouldNotCompareCommits struct {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func main() {
cli.Command{
Name: "global",
Action: actions.GenerateChangelog(ghclient, os.Stdout),
Usage: "deisrel changelog global <repo map> <old-release> <new-release>",
Usage: "deisrel changelog global <previous chart release params file> <repo map>",
Description: "Aggregate changelog entries from all known repositories for a specified release",
},
cli.Command{
Expand Down