From 98bf589158996b89b5bb6688a22eb249699d3423 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 1 Apr 2016 23:32:20 +0900 Subject: [PATCH 1/3] support for tracking scores, migration script for score tracking --- handlers/check.go | 29 ++++++++++++++- handlers/high_scores.go | 12 ++++++- tools/init_repo_scores.go | 75 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 tools/init_repo_scores.go diff --git a/handlers/check.go b/handlers/check.go index 076c9c5..5e2ebe8 100644 --- a/handlers/check.go +++ b/handlers/check.go @@ -109,7 +109,12 @@ func CheckHandler(w http.ResponseWriter, r *http.Request) { } } - return updateHighScores(mb, resp, repo) + err = updateHighScores(mb, resp, repo) + if err != nil { + return err + } + + return updateStats(mb, resp, repo) }) if err != nil { @@ -187,6 +192,28 @@ func updateHighScores(mb *bolt.Bucket, resp checksResp, repo string) error { return nil } +func updateStats(mb *bolt.Bucket, resp checksResp, repo string) error { + scores := make([]int, 101, 101) + statsBytes := mb.Get([]byte("stats")) + if statsBytes == nil { + statsBytes, _ = json.Marshal(scores) + } + err := json.Unmarshal(statsBytes, &scores) + if err != nil { + return err + } + scores[int(resp.Average*100)]++ + newStats, err := json.Marshal(scores) + if err != nil { + return err + } + err = mb.Put([]byte("stats"), newStats) + if err != nil { + return err + } + return nil +} + func updateReposCount(mb *bolt.Bucket, resp checksResp, repo string) (err error) { log.Printf("New repo %q, adding to repo count...", repo) totalInt := 0 diff --git a/handlers/high_scores.go b/handlers/high_scores.go index 2323ca2..b74c9de 100644 --- a/handlers/high_scores.go +++ b/handlers/high_scores.go @@ -31,7 +31,7 @@ func HighScoresHandler(w http.ResponseWriter, r *http.Request) { } defer db.Close() - count, scores := 0, &scoreHeap{} + count, scores, stats := 0, &scoreHeap{}, make([]int, 101, 101) err = db.View(func(tx *bolt.Tx) error { hsb := tx.Bucket([]byte(MetaBucket)) if hsb == nil { @@ -46,6 +46,15 @@ func HighScoresHandler(w http.ResponseWriter, r *http.Request) { } json.Unmarshal(scoreBytes, scores) + statsBytes := hsb.Get([]byte("stats")) + if statsBytes == nil { + statsBytes, err = json.Marshal(stats) + if err != nil { + return err + } + } + json.Unmarshal(statsBytes, &stats) + heap.Init(scores) total := hsb.Get([]byte("total_repos")) @@ -72,6 +81,7 @@ func HighScoresHandler(w http.ResponseWriter, r *http.Request) { t.Execute(w, map[string]interface{}{ "HighScores": sortedScores, + "Stats": stats, "Count": humanize.Comma(int64(count)), "google_analytics_key": googleAnalyticsKey, }) diff --git a/tools/init_repo_scores.go b/tools/init_repo_scores.go new file mode 100644 index 0000000..9b46c11 --- /dev/null +++ b/tools/init_repo_scores.go @@ -0,0 +1,75 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "time" + + "github.com/boltdb/bolt" + "github.com/gojp/goreportcard/handlers" +) + +const ( + dbPath string = "goreportcard.db" + repoBucket string = "repos" + metaBucket string = "meta" +) + +type checksResp struct { + Repo string `json:"repo"` + Average float64 `json:"average"` +} + +func main() { + db, err := bolt.Open(handlers.DBPath, 0600, &bolt.Options{Timeout: 1 * time.Second}) + if err != nil { + log.Fatal(err) + } + defer db.Close() + stats := make([]int, 101, 101) + err = db.Update(func(tx *bolt.Tx) error { + rb := tx.Bucket([]byte(repoBucket)) + if rb == nil { + return fmt.Errorf("repo bucket not found") + } + rb.ForEach(func(k, v []byte) error { + resp := checksResp{} + err := json.Unmarshal(v, &resp) + if err != nil { + return err + } + log.Printf("%s - %.2f", resp.Repo, resp.Average*100) + stats[int(resp.Average*100)]++ + return nil + }) + + // finally update the stats + mb := tx.Bucket([]byte(metaBucket)) + if mb == nil { + return fmt.Errorf("meta bucket not found") + } + var statsBytes []byte + statsBytes, err = json.Marshal(stats) + if err != nil { + return err + } + log.Printf("Stats: %v", stats) + err = mb.Put([]byte("stats"), statsBytes) + if err != nil { + return err + } + + tResp := mb.Get([]byte("stats")) + tStats := []int{} + err = json.Unmarshal(tResp, &tStats) + if err != nil { + return err + } + log.Printf("Stats Confirmation: %v", tStats) + return nil + }) + if err != nil { + log.Fatal(err) + } +} From fb78f46a69015c73b3edc5163cec22192f971f5f Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Fri, 1 Apr 2016 23:40:23 +0900 Subject: [PATCH 2/3] move tool scripts into subdirs for separate scopes --- tools/{ => names}/migrate_repo_names.go | 0 tools/{ => scores}/init_repo_scores.go | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tools/{ => names}/migrate_repo_names.go (100%) rename tools/{ => scores}/init_repo_scores.go (100%) diff --git a/tools/migrate_repo_names.go b/tools/names/migrate_repo_names.go similarity index 100% rename from tools/migrate_repo_names.go rename to tools/names/migrate_repo_names.go diff --git a/tools/init_repo_scores.go b/tools/scores/init_repo_scores.go similarity index 100% rename from tools/init_repo_scores.go rename to tools/scores/init_repo_scores.go From a66a84495779cc3aeba884fdf66a9e72da0329bc Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 2 Apr 2016 00:00:43 +0900 Subject: [PATCH 3/3] decrement old score stats --- handlers/check.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/handlers/check.go b/handlers/check.go index 5e2ebe8..2c0d117 100644 --- a/handlers/check.go +++ b/handlers/check.go @@ -67,18 +67,32 @@ func CheckHandler(w http.ResponseWriter, r *http.Request) { // is this a new repo? if so, increase the count in the high scores bucket later isNewRepo := false + var oldRepoBytes []byte err = db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(RepoBucket)) if b == nil { return fmt.Errorf("repo bucket not found") } - isNewRepo = b.Get([]byte(repo)) == nil + oldRepoBytes = b.Get([]byte(repo)) return nil }) if err != nil { log.Println(err) } + // get the old score and store it for stats updating + var oldScore *float64 + if isNewRepo = oldRepoBytes == nil; !isNewRepo { + oldRepo := checksResp{} + err = json.Unmarshal(oldRepoBytes, &oldRepo) + if err != nil { + log.Println("ERROR: could not unmarshal json:", err) + http.Error(w, err.Error(), 500) + return + } + oldScore = &oldRepo.Average + } + // if this is a new repo, or the user force-refreshed, update the cache if isNewRepo || forceRefresh { err = db.Update(func(tx *bolt.Tx) error { @@ -114,7 +128,7 @@ func CheckHandler(w http.ResponseWriter, r *http.Request) { return err } - return updateStats(mb, resp, repo) + return updateStats(mb, resp, repo, oldScore) }) if err != nil { @@ -192,7 +206,7 @@ func updateHighScores(mb *bolt.Bucket, resp checksResp, repo string) error { return nil } -func updateStats(mb *bolt.Bucket, resp checksResp, repo string) error { +func updateStats(mb *bolt.Bucket, resp checksResp, repo string, oldScore *float64) error { scores := make([]int, 101, 101) statsBytes := mb.Get([]byte("stats")) if statsBytes == nil { @@ -203,6 +217,9 @@ func updateStats(mb *bolt.Bucket, resp checksResp, repo string) error { return err } scores[int(resp.Average*100)]++ + if oldScore != nil { + scores[int(*oldScore*100)]-- + } newStats, err := json.Marshal(scores) if err != nil { return err