@@ -18,11 +18,16 @@ package main
1818
1919import (
2020 "fmt"
21+ "io/ioutil"
2122 "os"
23+ "path"
24+ "path/filepath"
25+ "regexp"
2226 "sort"
2327 "text/tabwriter"
2428 "text/template"
2529
30+ "github.com/pkg/errors"
2631 "github.com/sirupsen/logrus"
2732 "github.com/urfave/cli"
2833)
@@ -43,13 +48,24 @@ type dependency struct {
4348 Name string
4449 Commit string
4550 Previous string
51+ CloneURL string
4652}
4753
4854type download struct {
4955 Filename string
5056 Hash string
5157}
5258
59+ type projectChange struct {
60+ Name string
61+ Changes []change
62+ }
63+
64+ type projectRename struct {
65+ Old string `toml:"old"`
66+ New string `toml:"new"`
67+ }
68+
5369type release struct {
5470 ProjectName string `toml:"project_name"`
5571 GithubRepo string `toml:"github_repo"`
@@ -59,8 +75,13 @@ type release struct {
5975 Preface string `toml:"preface"`
6076 Notes map [string ]note `toml:"notes"`
6177 BreakingChanges map [string ]change `toml:"breaking"`
78+
79+ // dependency options
80+ MatchDeps string `toml:"match_deps"`
81+ RenameDeps map [string ]projectRename `toml:"rename_deps"`
82+
6283 // generated fields
63- Changes []change
84+ Changes []projectChange
6485 Contributors []string
6586 Dependencies []dependency
6687 Version string
@@ -79,6 +100,10 @@ This tool should be ran from the root of the project repository for a new releas
79100 Name : "dry,n" ,
80101 Usage : "run the release tooling as a dry run to print the release notes to stdout" ,
81102 },
103+ cli.BoolFlag {
104+ Name : "debug,d" ,
105+ Usage : "show debug output" ,
106+ },
82107 cli.StringFlag {
83108 Name : "template,t" ,
84109 Usage : "template filepath to use in place of the default" ,
@@ -87,45 +112,120 @@ This tool should be ran from the root of the project repository for a new releas
87112 }
88113 app .Action = func (context * cli.Context ) error {
89114 var (
90- path = context .Args ().First ()
91- tag = parseTag (path )
115+ releasePath = context .Args ().First ()
116+ tag = parseTag (releasePath )
92117 )
93- r , err := loadRelease (path )
118+ if context .Bool ("debug" ) {
119+ logrus .SetLevel (logrus .DebugLevel )
120+ }
121+ r , err := loadRelease (releasePath )
94122 if err != nil {
95123 return err
96124 }
97125 logrus .Infof ("Welcome to the %s release tool..." , r .ProjectName )
98- previous , err := getPreviousDeps (r .Previous )
126+
127+ mailmapPath , err := filepath .Abs (".mailmap" )
99128 if err != nil {
100- return err
129+ return errors . Wrap ( err , "failed to resolve mailmap" )
101130 }
131+ gitConfigs ["mailmap.file" ] = mailmapPath
132+
133+ var (
134+ contributors = map [contributor ]int {}
135+ projectChanges = []projectChange {}
136+ )
137+
102138 changes , err := changelog (r .Previous , r .Commit )
103139 if err != nil {
104140 return err
105141 }
142+ if err := addContributors (r .Previous , r .Commit , contributors ); err != nil {
143+ return err
144+ }
145+ projectChanges = append (projectChanges , projectChange {
146+ Name : "" ,
147+ Changes : changes ,
148+ })
149+
106150 logrus .Infof ("creating new release %s with %d new changes..." , tag , len (changes ))
107151 rd , err := fileFromRev (r .Commit , vendorConf )
108152 if err != nil {
109153 return err
110154 }
111- deps , err := parseDependencies ( rd )
155+ previous , err := getPreviousDeps ( r . Previous )
112156 if err != nil {
113157 return err
114158 }
115- updatedDeps := updatedDeps (previous , deps )
116- contributors , err := getContributors (r .Previous , r .Commit )
159+ deps , err := parseDependencies (rd )
117160 if err != nil {
118161 return err
119162 }
163+ renameDependencies (previous , r .RenameDeps )
164+ updatedDeps := updatedDeps (previous , deps )
120165
121166 sort .Slice (updatedDeps , func (i , j int ) bool {
122167 return updatedDeps [i ].Name < updatedDeps [j ].Name
123168 })
124169
170+ if r .MatchDeps != "" && len (updatedDeps ) > 0 {
171+ re , err := regexp .Compile (r .MatchDeps )
172+ if err != nil {
173+ return errors .Wrap (err , "unable to compile 'match_deps' regexp" )
174+ }
175+ td , err := ioutil .TempDir ("" , "tmp-clone-" )
176+ if err != nil {
177+ return errors .Wrap (err , "unable to create temp clone directory" )
178+ }
179+ defer os .RemoveAll (td )
180+
181+ cwd , err := os .Getwd ()
182+ if err != nil {
183+ return errors .Wrap (err , "unable to get cwd" )
184+ }
185+ for _ , dep := range updatedDeps {
186+ matches := re .FindStringSubmatch (dep .Name )
187+ if matches == nil {
188+ continue
189+ }
190+ logrus .Debugf ("Matched dependency %s with %s" , dep .Name , r .MatchDeps )
191+ var name string
192+ if len (matches ) < 2 {
193+ name = path .Base (dep .Name )
194+ } else {
195+ name = matches [1 ]
196+ }
197+ if err := os .Chdir (td ); err != nil {
198+ return errors .Wrap (err , "unable to chdir to temp clone directory" )
199+ }
200+ git ("clone" , dep .CloneURL , name )
201+
202+ if err := os .Chdir (name ); err != nil {
203+ return errors .Wrapf (err , "unable to chdir to cloned %s directory" , name )
204+ }
205+
206+ changes , err := changelog (dep .Previous , dep .Commit )
207+ if err != nil {
208+ return errors .Wrapf (err , "failed to get changelog for %s" , name )
209+ }
210+ if err := addContributors (dep .Previous , dep .Commit , contributors ); err != nil {
211+ return errors .Wrapf (err , "failed to get authors for %s" , name )
212+ }
213+
214+ projectChanges = append (projectChanges , projectChange {
215+ Name : name ,
216+ Changes : changes ,
217+ })
218+
219+ }
220+ if err := os .Chdir (cwd ); err != nil {
221+ return errors .Wrap (err , "unable to chdir to previous cwd" )
222+ }
223+ }
224+
125225 // update the release fields with generated data
126- r .Contributors = contributors
226+ r .Contributors = orderContributors ( contributors )
127227 r .Dependencies = updatedDeps
128- r .Changes = changes
228+ r .Changes = projectChanges
129229 r .Version = tag
130230
131231 tmpl , err := getTemplate (context )
0 commit comments