From f13b990fee6657073ac74334402170bb3402b586 Mon Sep 17 00:00:00 2001 From: "Bryan T. Meyers" Date: Sun, 5 Aug 2018 08:20:10 -0400 Subject: [PATCH] Actually fixed github tags this time --- providers/cpan/provider.go | 21 +++--- providers/github/provider.go | 44 +----------- providers/github/tags.go | 127 +++++++++++++++++++++++++++++++++-- results/resultset.go | 16 ++--- 4 files changed, 143 insertions(+), 65 deletions(-) diff --git a/providers/cpan/provider.go b/providers/cpan/provider.go index 51b0161..51e8da5 100644 --- a/providers/cpan/provider.go +++ b/providers/cpan/provider.go @@ -48,10 +48,10 @@ func (c Provider) Match(query string) string { filename := sms[len(sms)-1] pieces := strings.Split(filename, "-") pieces = pieces[0 : len(sms)-2] - name := pieces[0] - if len(pieces) > 2 { - name = strings.Join(pieces, "-") - } + name := pieces[0] + if len(pieces) > 2 { + name = strings.Join(pieces, "-") + } return name } @@ -60,9 +60,8 @@ func (c Provider) Name() string { return "CPAN" } - type CPANRelease struct { - Module string `json:"main_module"` + Module string `json:"main_module"` } func nameToModule(name string) (module string, s results.Status) { @@ -93,17 +92,17 @@ func nameToModule(name string) (module string, s results.Status) { if err != nil { panic(err.Error()) } - module = r.Module - return + module = r.Module + return } // Latest finds the newest release for a CPAN package func (c Provider) Latest(name string) (r *results.Result, s results.Status) { // Query the APIDownloadURL module, s := nameToModule(name) - if s != results.OK { - return - } + if s != results.OK { + return + } resp, err := http.Get(fmt.Sprintf(APIDownloadURL, module)) if err != nil { panic(err.Error()) diff --git a/providers/github/provider.go b/providers/github/provider.go index 6169849..cf667d1 100644 --- a/providers/github/provider.go +++ b/providers/github/provider.go @@ -31,7 +31,7 @@ const ( // APIReleases is a format string for the Releases API APIReleases = "https://api.github.com/repos/%s/releases" // APITags is a format string for the Tags API - APITags = "https://api.github.com/repos/%s/tags" + APITags = "https://api.github.com/repos/%s/git/refs/tags" // SourceFormat is the format string for Github release tarballs SourceFormat = "https://github.com/%s/archive/%s.tar.gz" ) @@ -67,7 +67,7 @@ func (c Provider) Latest(name string) (r *results.Result, s results.Status) { if s != results.OK || rs.Empty() { return } - r = rs.First() + r = rs.Last() return default: s = results.Unavailable @@ -102,46 +102,6 @@ func (c Provider) Name() string { return "GitHub" } -func getTags(name string) (rs *results.ResultSet, s results.Status) { - // Query the API - req, _ := http.NewRequest("GET", fmt.Sprintf(APITags, name), nil) - if key := config.Global.Github.Key; len(key) > 0 { - req.Header["Authorization"] = []string{"token " + key} - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - panic(err.Error()) - } - defer resp.Body.Close() - // Translate Status Code - switch resp.StatusCode { - case 200: - s = results.OK - case 404: - s = results.NotFound - default: - s = results.Unavailable - } - - // Fail if not OK - if s != results.OK { - return - } - - dec := json.NewDecoder(resp.Body) - tags := make(Tags, 0) - err = dec.Decode(&tags) - if err != nil { - panic(err.Error()) - } - if len(tags) == 0 { - s = results.NotFound - return - } - rs = tags.Convert(name) - return -} - // Releases finds all matching releases for a github package func (c Provider) Releases(name string) (rs *results.ResultSet, s results.Status) { // Query the API diff --git a/providers/github/tags.go b/providers/github/tags.go index a42150a..da17df3 100644 --- a/providers/github/tags.go +++ b/providers/github/tags.go @@ -17,14 +17,64 @@ package github import ( + "encoding/json" "fmt" + "github.com/DataDrake/cuppa/config" "github.com/DataDrake/cuppa/results" + "net/http" + "sort" "strings" + "time" ) +// Ref is a representation of a Github Git Reference +type Ref struct { + Object struct { + URL string `json:"url"` + } `json:"object"` +} + +// Refs is a list of Refs +type Refs []Ref + +// ToTags converts Refs to Tags +func (rs Refs) ToTags() Tags { + tags := make(Tags, 0) + for _, ref := range rs { + if len(ref.Object.URL) == 0 { + continue + } + req, _ := http.NewRequest("GET", ref.Object.URL, nil) + if key := config.Global.Github.Key; len(key) > 0 { + req.Header["Authorization"] = []string{"token " + key} + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + panic(err.Error()) + } + if resp.StatusCode != 200 { + resp.Body.Close() + continue + } + dec := json.NewDecoder(resp.Body) + tag := Tag{} + err = dec.Decode(&tag) + if err != nil { + panic(err.Error()) + continue + } + resp.Body.Close() + tags = append(tags, tag) + } + return tags +} + // Tag is a JSON representation of a Github tag type Tag struct { - Name string `json:"name"` + Tag string `json:"tag"` + Tagger struct { + Date string `json:"date"` + } `json:"tagger"` } // Convert turns a Github tag into a Cuppa result @@ -32,7 +82,7 @@ func (t *Tag) Convert(name string) *results.Result { r := &results.Result{} pieces := strings.Split(name, "/") r.Name = pieces[len(pieces)-1] - pieces = strings.Split(t.Name, "/") + pieces = strings.Split(t.Tag, "/") r.Version = pieces[len(pieces)-1] r.Location = fmt.Sprintf(SourceFormat, name, r.Version) return r @@ -41,10 +91,79 @@ func (t *Tag) Convert(name string) *results.Result { // Tags are a JSON representation of one or more tags type Tags []Tag +// Len gets the length of Tags +func (ts Tags) Len() int { + return len(ts) +} + +// Swap is used by Sort +func (ts Tags) Swap(i, j int) { + ts[i], ts[j] = ts[j], ts[i] +} + +// Less is used by Sort +func (ts Tags) Less(i, j int) bool { + d1, err := time.Parse(time.RFC3339, ts[i].Tagger.Date) + if err != nil { + return true + } + d2, err := time.Parse(time.RFC3339, ts[j].Tagger.Date) + if err != nil { + return false + } + return d1.Before(d2) +} + +func getTags(name string) (rs *results.ResultSet, s results.Status) { + // Query the API + req, _ := http.NewRequest("GET", fmt.Sprintf(APITags, name), nil) + if key := config.Global.Github.Key; len(key) > 0 { + req.Header["Authorization"] = []string{"token " + key} + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + panic(err.Error()) + } + defer resp.Body.Close() + // Translate Status Code + switch resp.StatusCode { + case 200: + s = results.OK + case 404: + s = results.NotFound + default: + s = results.Unavailable + } + + // Fail if not OK + if s != results.OK { + return + } + + dec := json.NewDecoder(resp.Body) + refs := make(Refs, 0) + err = dec.Decode(&refs) + if err != nil { + panic(err.Error()) + } + if len(refs) == 0 { + s = results.NotFound + return + } + tags := refs.ToTags() + if len(tags) == 0 { + s = results.NotFound + return + } + rs = tags.Convert(name) + return +} + // Convert a Github tagset to a Cuppa result set -func (ts *Tags) Convert(name string) *results.ResultSet { +func (ts Tags) Convert(name string) *results.ResultSet { + sort.Sort(ts) rs := results.NewResultSet(name) - for _, t := range *ts { + for _, t := range ts { r := t.Convert(name) if r != nil { rs.AddResult(r) diff --git a/results/resultset.go b/results/resultset.go index 2488019..c1b268e 100644 --- a/results/resultset.go +++ b/results/resultset.go @@ -50,14 +50,14 @@ func (rs *ResultSet) First() *Result { // Last retrieves the first result from a query func (rs *ResultSet) Last() *Result { - switch len(rs.results) { - case 0: - return nil - case 1: - return rs.results[0] - default: - return rs.results[len(rs.results)-1] - } + switch len(rs.results) { + case 0: + return nil + case 1: + return rs.results[0] + default: + return rs.results[len(rs.results)-1] + } } // PrintAll pretty-prints an entire ResultSet