diff --git a/cmd/root.go b/cmd/root.go index 9759a5b..b6a85a2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -198,7 +198,7 @@ func initConfig() { } } -func displayReleases(rr []gh.Release) { +func displayReleases(rr []gh.ReleaseList) { opt := make(printer.Options) switch output { diff --git a/gh/checkrelease.go b/gh/checkrelease.go index b122468..61bd181 100644 --- a/gh/checkrelease.go +++ b/gh/checkrelease.go @@ -39,8 +39,11 @@ type Release struct { Body *string `json:"body"` } +// ReleaseList represents a list of new releases for a given project +type ReleaseList []*Release + // checkReleaseWorker is a worker to check new releases -func (c *Config) checkReleaseWorker(ctx context.Context, wID int, repoQueue <-chan RepoConfig, newRel chan<- *Release) { +func (c *Config) checkReleaseWorker(ctx context.Context, wID int, repoQueue <-chan RepoConfig, newRel chan<- ReleaseList) { logrus.Debugf("[%d] checkReleaseWorker starting.", wID) for r := range repoQueue { logrus.Debugf("[%d] checkReleaseWorker - repository '%s'", wID, r.Repo) @@ -58,7 +61,7 @@ func (c *Config) checkReleaseWorker(ctx context.Context, wID int, repoQueue <-ch } // CheckReleases checks all configured repositories for new releases -func (c *Config) CheckReleases(readOnly bool) ([]Release, error) { +func (c *Config) CheckReleases(readOnly bool) ([]ReleaseList, error) { if c == nil || c.client == nil { return nil, errors.New("uninitialized client") } @@ -67,7 +70,7 @@ func (c *Config) CheckReleases(readOnly bool) ([]Release, error) { return nil, errors.Wrap(err, "cannot load state file") } - newReleases := make(chan *Release) + newReleases := make(chan ReleaseList) repoQ := make(chan RepoConfig) ctx := context.Background() @@ -85,17 +88,17 @@ func (c *Config) CheckReleases(readOnly bool) ([]Release, error) { }() // Collect results - var newReleaseList []Release + var newReleaseList []ReleaseList for resultCount := len(c.Repositories); resultCount > 0; { rel := <-newReleases resultCount-- - if rel == nil { + if len(rel) == 0 { continue } // Queue the release for states updates - newReleaseList = append(newReleaseList, *rel) + newReleaseList = append(newReleaseList, rel) } // Leave now if the result list is empty or if we don't need to save them @@ -110,7 +113,7 @@ func (c *Config) CheckReleases(readOnly bool) ([]Release, error) { rm := make(map[string]RepoState) c.states = &States{Repositories: rm} } - c.states.Repositories[s.Repo] = *s.RepoState + c.states.Repositories[s[0].Repo] = *(s[0].RepoState) } // Save states @@ -131,7 +134,7 @@ func (c *Config) getOldState(repo string) RepoState { return RepoState{Repo: repo} } -func (c *Config) checkRepoReleases(ctx context.Context, wID int, prereleases bool, prevState RepoState) (*Release, error) { +func (c *Config) checkRepoReleases(ctx context.Context, wID int, prereleases bool, prevState RepoState) (ReleaseList, error) { client := c.client pp := strings.Split(prevState.Repo, "/") @@ -171,6 +174,7 @@ func (c *Config) checkRepoReleases(ctx context.Context, wID int, prereleases boo } lastCheck := false + var newReleaseList ReleaseList for _, r := range rr { if lastCheck { @@ -200,27 +204,37 @@ func (c *Config) checkRepoReleases(ctx context.Context, wID int, prereleases boo newTag := r.GetTagName() newDate := r.GetPublishedAt() - if (prevState.Version != newVersion) || - (prevState.PublishDate == nil || prevState.PublishDate.Unix() < newDate.Unix()) || - (prevState.Tag == nil || *prevState.Tag != newTag) { - if prevState.Version == newVersion && newVersion != "" { - logrus.Infof("[%d] (%s) Same version but date or tag has changed", - wID, prevState.Repo) - } - rel := &Release{ - RepoState: &RepoState{ - Repo: prevState.Repo, - Version: newVersion, - Tag: r.TagName, - PreRelease: r.Prerelease, - PublishDate: r.PublishedAt, - body: r.Body, - }, - Body: r.Body, - } - return rel, nil + logrus.Debugf("[%d] version: '%s' tag: '%s' date: %v", + wID, newVersion, newTag, newDate) + + if prevState.PublishDate != nil && prevState.PublishDate.Unix() > newDate.Unix() { + break // Old release + } + if newVersion != "" && prevState.Version == newVersion { + break // Already seen + } + if (prevState.Tag != nil && *prevState.Tag == newTag) && prevState.Version == newVersion { + break // Already seen + } + + newReleaseList = append(newReleaseList, &Release{ + RepoState: &RepoState{ + Repo: prevState.Repo, + Version: newVersion, + Tag: r.TagName, + PreRelease: r.Prerelease, + PublishDate: r.PublishedAt, + body: r.Body, + }, + Body: r.Body, + }) + + if prevState.PublishDate == nil { + // It must be the first time this project is checked, + // let's not list all releases. + break } } - return nil, nil + return newReleaseList, nil } diff --git a/gh/printer/jsonprinter.go b/gh/printer/jsonprinter.go index 0e1a477..6de6dac 100644 --- a/gh/printer/jsonprinter.go +++ b/gh/printer/jsonprinter.go @@ -38,7 +38,7 @@ func NewPrinterJSON(options Options) (*JSONPrinter, error) { } // PrintReleases displays a list of releases in JSON format -func (p *JSONPrinter) PrintReleases(rr []gh.Release) error { +func (p *JSONPrinter) PrintReleases(rr []gh.ReleaseList) error { if len(rr) == 0 { return nil } diff --git a/gh/printer/plainprinter.go b/gh/printer/plainprinter.go index 09690ce..f6a5e5d 100644 --- a/gh/printer/plainprinter.go +++ b/gh/printer/plainprinter.go @@ -44,27 +44,29 @@ func NewPrinterPlain(options Options) (*PlainPrinter, error) { } // PrintReleases displays a list of releases to the standard output -func (p *PlainPrinter) PrintReleases(rr []gh.Release) error { - for _, r := range rr { - pre := "" - if r.PreRelease != nil && *r.PreRelease { - pre = "pre-" - } - fmt.Printf("New %srelease for %s: %s\n", pre, r.Repo, r.Version) - if r.Tag != nil { - fmt.Printf(" Tag: %s\n", *r.Tag) - } - if r.PublishDate != nil { - fmt.Printf(" Date: %s\n", r.PublishDate.Local(). - Format("2006-01-02 15:04:05 -0700 MST")) - } +func (p *PlainPrinter) PrintReleases(rr []gh.ReleaseList) error { + for _, rl := range rr { + for _, r := range rl { + pre := "" + if r.PreRelease != nil && *r.PreRelease { + pre = "pre-" + } + fmt.Printf("New %srelease for %s: %s\n", pre, r.Repo, r.Version) + if r.Tag != nil { + fmt.Printf(" Tag: %s\n", *r.Tag) + } + if r.PublishDate != nil { + fmt.Printf(" Date: %s\n", r.PublishDate.Local(). + Format("2006-01-02 15:04:05 -0700 MST")) + } - if r.Body != nil && p.showBody { - fmt.Println(" Release body:") - fmt.Println(text.Indent(strings.TrimSpace(*r.Body), " ")) - } + if r.Body != nil && p.showBody { + fmt.Println(" Release body:") + fmt.Println(text.Indent(strings.TrimSpace(*r.Body), " ")) + } - fmt.Println() + fmt.Println() + } } return nil diff --git a/gh/printer/printer.go b/gh/printer/printer.go index ba8f494..8a4a377 100644 --- a/gh/printer/printer.go +++ b/gh/printer/printer.go @@ -33,7 +33,7 @@ type Options map[string]interface{} type Printer interface { // PrintReleases receives a list of releases, // formats it and prints it to stdout. - PrintReleases([]gh.Release) error + PrintReleases([]gh.ReleaseList) error } // NewPrinter returns a printer of the requested kind diff --git a/gh/printer/templateprinter.go b/gh/printer/templateprinter.go index 0356547..16d04f7 100644 --- a/gh/printer/templateprinter.go +++ b/gh/printer/templateprinter.go @@ -68,22 +68,24 @@ func NewPrinterTemplate(options Options) (*TemplatePrinter, error) { } // PrintReleases displays a list of releases to the standard output -func (p *TemplatePrinter) PrintReleases(rr []gh.Release) error { +func (p *TemplatePrinter) PrintReleases(rr []gh.ReleaseList) error { if p.template == nil { return fmt.Errorf("template not built") } - for _, r := range rr { - data, err := json.Marshal(r) - if err != nil { - return err - } - out := map[string]interface{}{} - if err := json.Unmarshal(data, &out); err != nil { - return err - } - if err = p.safeExecute(os.Stdout, out); err != nil { - return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err) + for _, rl := range rr { + for _, r := range rl { + data, err := json.Marshal(r) + if err != nil { + return err + } + out := map[string]interface{}{} + if err := json.Unmarshal(data, &out); err != nil { + return err + } + if err = p.safeExecute(os.Stdout, out); err != nil { + return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err) + } } } return nil diff --git a/gh/printer/yamlprinter.go b/gh/printer/yamlprinter.go index 31b0dea..158db73 100644 --- a/gh/printer/yamlprinter.go +++ b/gh/printer/yamlprinter.go @@ -39,7 +39,7 @@ func NewPrinterYAML(options Options) (*YAMLPrinter, error) { } // PrintReleases displays a list of releases in YAML format -func (p *YAMLPrinter) PrintReleases(rr []gh.Release) error { +func (p *YAMLPrinter) PrintReleases(rr []gh.ReleaseList) error { if len(rr) == 0 { return nil }