From 8a3e2115b16b1a4f2f0ea4940e707acc5050672c Mon Sep 17 00:00:00 2001 From: Olivier Vernin Date: Fri, 17 May 2024 13:09:04 +0200 Subject: [PATCH] feat: add option to clean files not generated by releasepost (#36) Signed-off-by: Olivier Vernin --- cmd/root.go | 7 +++- internal/core/engine/clean.go | 70 +++++++++++++++++++++++++++++++ internal/core/engine/init.go | 4 ++ internal/core/engine/main.go | 2 + internal/core/engine/run.go | 14 ++++++- internal/core/result/changelog.go | 59 ++++++++++++++++++++++++++ internal/core/result/main.go | 38 ----------------- internal/core/result/result.go | 35 ++++++++++++++++ 8 files changed, 188 insertions(+), 41 deletions(-) create mode 100644 internal/core/engine/clean.go create mode 100644 internal/core/result/changelog.go create mode 100644 internal/core/result/result.go diff --git a/cmd/root.go b/cmd/root.go index 9668aa3..067318a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,6 +15,7 @@ var ( configFile string e engine.Engine dryRun bool + cleanRun bool rootCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { @@ -36,7 +37,10 @@ var ( dryrun.Enabled = true fmt.Println("Dry run mode enabled, no changelog will be saved to disk") } - err = e.Run() + err = e.Run(cleanRun) + if cleanRun { + fmt.Println("Clean run mode enabled, releasepost will remove any files not created by releasepost in changelogs directories !") + } if err != nil { fmt.Printf("Failed to run releasepost: %v", err) os.Exit(2) @@ -59,6 +63,7 @@ It can creates files using different formats like markdown, asciidoctor, or json func init() { rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "releasepost configuration file") rootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "d", false, "Dry run mode") + rootCmd.PersistentFlags().BoolVar(&cleanRun, "clean", false, "Clean run, removes files from changelog directories not created by releasepost.") rootCmd.AddCommand( versionCmd, ) diff --git a/internal/core/engine/clean.go b/internal/core/engine/clean.go new file mode 100644 index 0000000..070ef98 --- /dev/null +++ b/internal/core/engine/clean.go @@ -0,0 +1,70 @@ +package engine + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/updatecli/releasepost/internal/core/result" +) + +// Clean analyze changelog monitored directories and remove any changelog that +// weren't created or modified by releasepost. +func (e *Engine) Clean(clean bool) error { + + fmt.Printf("\n\nCleaning\n") + for dirpath, dir := range e.result.Dir { + files, err := filepath.Glob(filepath.Join(dirpath, "*")) + if err != nil { + return err + } + + for _, f := range files { + info, err := os.Stat(f) + if err != nil { + fmt.Printf("unable to get file info: %v\n", err.Error()) + continue + } + + if info.IsDir() { + continue + } + + if !dir.IsFileExist(f) { + err := filepath.Walk(f, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + result.ChangelogResult.UnTracked = append(result.ChangelogResult.UnTracked, f) + if clean { + fmt.Printf("\t* removing %s\n", f) + err = os.Remove(path) + if err != nil { + return err + } + } + + return nil + }) + if err != nil { + return err + } + } + } + } + + if len(result.ChangelogResult.UnTracked) > 0 { + fmt.Printf("Untracked files detected:\n") + for _, f := range result.ChangelogResult.UnTracked { + fmt.Printf("\t* %s\n", f) + } + } + + fmt.Printf("\n\n") + return nil +} diff --git a/internal/core/engine/init.go b/internal/core/engine/init.go index 14b2b88..dde6922 100644 --- a/internal/core/engine/init.go +++ b/internal/core/engine/init.go @@ -28,5 +28,9 @@ func (e *Engine) Init() error { e.runners = append(e.runners, runner) } + if len(e.config.Changelogs) == 0 { + return fmt.Errorf("no changelog found in configuration file") + } + return nil } diff --git a/internal/core/engine/main.go b/internal/core/engine/main.go index 3a4ad16..8403f14 100644 --- a/internal/core/engine/main.go +++ b/internal/core/engine/main.go @@ -2,6 +2,7 @@ package engine import ( "github.com/updatecli/releasepost/internal/core/config" + "github.com/updatecli/releasepost/internal/core/result" "github.com/updatecli/releasepost/internal/core/runner" ) @@ -11,4 +12,5 @@ Engine is the main structure of the application type Engine struct { config config.Config runners []runner.Runner + result result.Result } diff --git a/internal/core/engine/run.go b/internal/core/engine/run.go index 3312ea3..5f6328f 100644 --- a/internal/core/engine/run.go +++ b/internal/core/engine/run.go @@ -10,7 +10,7 @@ import ( Run executes the engine. It will run all the runners and save the changelogs to disk. */ -func (e *Engine) Run() error { +func (e *Engine) Run(cleanRun bool) error { for i := range e.config.Changelogs { changelogs, err := e.runners[i].Run() @@ -35,9 +35,19 @@ func (e *Engine) Run() error { fmt.Printf("unable to save changelog index to disk: %v\n", err.Error()) continue } + + err = result.ChangelogResult.UpdateResult(&e.result) + if err != nil { + fmt.Printf("unable to update result: %v\n", err.Error()) + continue + } + } + + if err := e.Clean(cleanRun); err != nil { + fmt.Printf("unable to clean changelog: %v\n", err.Error()) } - result.ChangelogResult.String() + fmt.Println(e.result) return nil } diff --git a/internal/core/result/changelog.go b/internal/core/result/changelog.go new file mode 100644 index 0000000..d20ea2f --- /dev/null +++ b/internal/core/result/changelog.go @@ -0,0 +1,59 @@ +package result + +import "path/filepath" + +const ( + // Created state + CREATEDSTATE = "created" + // Modified state + MODIFIEDSTATE = "modified" + // UnModified state + UNMODIFIEDSTATE = "unmodified" + // UnTracked state + UNTRACKEDSTATE = "untracked" +) + +type Changelog struct { + Created []string `json:"created"` + Modified []string `json:"modified"` + UnModified []string `json:"unmodified"` + UnTracked []string `json:"untracked"` +} + +func (c Changelog) ExitCode() int { + if len(c.Created) == 0 && len(c.Modified) == 0 { + return 1 + } + return 0 +} + +// UpdateResult update the result with the current changelog information +func (c Changelog) UpdateResult(result *Result) error { + + parser := func(files []string, state string) { + for _, f := range files { + dirname := filepath.Dir(f) + + if result.Dir[dirname].IsFileExist(f) { + continue + } + + if result.Dir == nil { + result.Dir = make(map[string]FileResults) + } + + result.Dir[dirname] = append( + result.Dir[dirname], + FileResult{ + Path: f, + State: state, + }) + } + } + + parser(c.Created, CREATEDSTATE) + parser(c.Modified, MODIFIEDSTATE) + parser(c.UnModified, UNMODIFIEDSTATE) + + return nil +} diff --git a/internal/core/result/main.go b/internal/core/result/main.go index 7f93c24..9bb7ae2 100644 --- a/internal/core/result/main.go +++ b/internal/core/result/main.go @@ -1,43 +1,5 @@ package result -import "fmt" - -type Changelog struct { - Created []string `json:"created"` - Modified []string `json:"modified"` - UnModified []string `json:"unmodified"` -} - var ( ChangelogResult Changelog ) - -func (c Changelog) String() { - if len(c.Created) > 0 { - fmt.Println("Changelogs reposted:") - for _, v := range c.Created { - fmt.Printf("\t* %s\n", v) - } - } - - if len(c.Modified) > 0 { - fmt.Println("Changelogs modified:") - for _, v := range c.Modified { - fmt.Printf("\t* %s\n", v) - } - } - - if len(c.UnModified) > 0 { - fmt.Println("Changelogs unmodified:") - for _, v := range c.UnModified { - fmt.Printf("\t* %s\n", v) - } - } -} - -func (c Changelog) ExitCode() int { - if len(c.Created) == 0 && len(c.Modified) == 0 { - return 1 - } - return 0 -} diff --git a/internal/core/result/result.go b/internal/core/result/result.go new file mode 100644 index 0000000..15e21b0 --- /dev/null +++ b/internal/core/result/result.go @@ -0,0 +1,35 @@ +package result + +import ( + "fmt" +) + +type FileResult struct { + State string + Path string +} + +type FileResults []FileResult + +type Result struct { + Dir map[string]FileResults +} + +func (f FileResults) IsFileExist(file string) bool { + for _, f := range f { + if f.Path == file { + return true + } + } + return false +} + +func (f Result) String() string { + s := "Result\n" + for _, files := range f.Dir { + for _, f := range files { + s = fmt.Sprintf("%s\t* %s (%s)\n", s, f.Path, f.State) + } + } + return s +}