Skip to content

Commit

Permalink
ref(*): fix changelog global command
Browse files Browse the repository at this point in the history
To compensate for individual components now following their own release cadences
  • Loading branch information
Vaughn Dice committed Oct 31, 2016
1 parent e1f9e77 commit 569db22
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 21 deletions.
65 changes: 50 additions & 15 deletions actions/generate_changelog.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,66 @@ 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)
}
err = toml.Unmarshal(out, &res)
if 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)
}
err = json.Unmarshal(out, &mapping)
if 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,8 +74,14 @@ 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}
_, err = changelog.SingleRepoVals(client, vals, componentVersion.ComponentVersion, repo, true)
if err != nil {
errCh <- err
return
Expand All @@ -84,3 +108,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 .Migrations) gt 0 -}}
### Migrations
{{range .Migrations}}- {{.}}
{{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
Migrations []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.Migrations = append(ret.Migrations, 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.Migrations
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.Migrations, []string{"repo-a v1.2.3 -> v1.2.4", "repo-b v4.5.6 -> v4.6.0"}, "migrations 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

0 comments on commit 569db22

Please sign in to comment.