hubba-reports 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,37 @@
1
+ module Hubba
2
+
3
+
4
+ class ReportStars < Report
5
+
6
+ def build
7
+
8
+ ## add stars, last_updates, etc.
9
+ ## org description etc??
10
+
11
+ ## note: orgs is orgs+users e.g. geraldb, yorobot etc
12
+ buf = String.new('')
13
+ buf << "# Stars"
14
+ buf << " - #{@stats.repos.size} Repos @ #{@stats.orgs.size} Orgs"
15
+ buf << "\n\n"
16
+
17
+
18
+ repos = @stats.repos.sort do |l,r|
19
+ ## note: use reverse sort (right,left) - e.g. most stars first
20
+ r.stats.stars <=> l.stats.stars
21
+ end
22
+
23
+ ## pp repos
24
+
25
+ repos.each_with_index do |repo,i|
26
+ buf << "#{i+1}. ★#{repo.stats.stars} **#{repo.full_name}** (#{repo.stats.size} kb)\n"
27
+ end
28
+ buf << "<!-- break -->\n" ## markdown hack: add a list end marker
29
+ buf << "\n\n"
30
+
31
+
32
+ buf
33
+ end # method build
34
+ end # class ReportStars
35
+
36
+
37
+ end # module Hubba
@@ -0,0 +1,39 @@
1
+ module Hubba
2
+
3
+
4
+ class ReportSummary < Report
5
+
6
+ def build
7
+ ## create a (summary report)
8
+ ##
9
+ ## add stars, last_updates, etc.
10
+ ## org description etc??
11
+
12
+ ## note: orgs is orgs+users e.g. geraldb, yorobot etc
13
+ buf = String.new('')
14
+ buf << "# Summary"
15
+ buf << " - #{@stats.repos.size} Repos @ #{@stats.orgs.size} Orgs"
16
+ buf << "\n\n"
17
+
18
+
19
+ @stats.orgs.each do |org|
20
+ name = org[0]
21
+ repos = org[1]
22
+ buf << "### #{name} _(#{repos.size})_\n"
23
+ buf << "\n"
24
+
25
+ ### add stats for repos
26
+ entries = []
27
+ repos.each do |repo|
28
+ entries << "**#{repo.name}** ★#{repo.stats.stars} (#{repo.stats.size} kb)"
29
+ end
30
+
31
+ buf << entries.join( ' · ' ) ## use interpunct? - was: • (bullet)
32
+ buf << "\n\n"
33
+ end
34
+
35
+ buf
36
+ end # method build
37
+ end # class ReportSummary
38
+
39
+ end # module Hubba
@@ -0,0 +1,53 @@
1
+ module Hubba
2
+
3
+
4
+ class ReportTimeline < Report
5
+
6
+ def build
7
+ ## create a (timeline report)
8
+
9
+ ## note: orgs is orgs+users e.g. geraldb, yorobot etc
10
+ buf = String.new('')
11
+ buf << "# Timeline"
12
+ buf << " - #{@stats.repos.size} Repos @ #{@stats.orgs.size} Orgs"
13
+ buf << "\n\n"
14
+
15
+
16
+ repos = @stats.repos.sort do |l,r|
17
+ ## note: use reverse sort (right,left) - e.g. most stars first
18
+ ## r[:stars] <=> l[:stars]
19
+
20
+ ## sort by created_at (use julian days)
21
+ r.stats.created.jd <=> l.stats.created.jd
22
+ end
23
+
24
+
25
+ ## pp repos
26
+
27
+
28
+ last_year = -1
29
+ last_month = -1
30
+
31
+ repos.each_with_index do |repo,i|
32
+ year = repo.stats.created.year
33
+ month = repo.stats.created.month
34
+
35
+ if last_year != year
36
+ buf << "\n## #{year}\n\n"
37
+ end
38
+
39
+ if last_month != month
40
+ buf << "\n### #{month}\n\n"
41
+ end
42
+
43
+ last_year = year
44
+ last_month = month
45
+
46
+ buf << "- #{repo.stats.created_at.strftime('%Y-%m-%d')} ★#{repo.stats.stars} **#{repo.full_name}** (#{repo.stats.size} kb)\n"
47
+ end
48
+
49
+ buf
50
+ end # method build
51
+ end # class ReportTimeline
52
+
53
+ end # module Hubba
@@ -0,0 +1,48 @@
1
+ module Hubba
2
+
3
+
4
+ class ReportTopics < Report
5
+
6
+ def build
7
+
8
+ ## note: orgs is orgs+users e.g. geraldb, yorobot etc
9
+ buf = String.new('')
10
+ buf << "# Topics"
11
+ buf << " - #{@stats.repos.size} Repos @ #{@stats.orgs.size} Orgs"
12
+ buf << "\n\n"
13
+
14
+
15
+ topics = {} ## collect all topics with refs to repos
16
+
17
+ @stats.repos.each do |repo|
18
+ repo.stats.topics.each do |topic|
19
+ repos = topics[ topic ] ||= []
20
+ repos << repo
21
+ end
22
+ end
23
+
24
+ topics = topics.sort {|(ltopic,_),(rtopic,_)|
25
+ ltopic <=> rtopic ## sort topic by a-z
26
+ }
27
+ .to_h # convert back to hash (from array)
28
+
29
+
30
+ topics.each do |topic,repos|
31
+ buf << "`#{topic}` _(#{repos.size})_\n"
32
+ end
33
+ buf << "\n"
34
+
35
+
36
+ topics.each do |topic,repos|
37
+ buf << "## `#{topic}` _(#{repos.size})_\n"
38
+
39
+ buf << repos.map {|repo| repo.full_name }.join( ' · ' ) ## use interpunct? - was: • (bullet)
40
+ buf << "\n\n"
41
+ end
42
+
43
+
44
+ buf
45
+ end # method build
46
+ end # class ReportTopics
47
+
48
+ end # module Hubba
@@ -0,0 +1,112 @@
1
+ module Hubba
2
+
3
+
4
+ class ReportTraffic < Report
5
+
6
+ def build
7
+
8
+
9
+ ## note: orgs is orgs+users e.g. geraldb, yorobot etc
10
+ buf = String.new('')
11
+ buf << "# Traffic"
12
+ buf << " - #{@stats.repos.size} Repos @ #{@stats.orgs.size} Orgs"
13
+ buf << "\n\n"
14
+
15
+ buf << "traffic over the last 14 days - page views / unique, clones / unique\n"
16
+ buf << "\n"
17
+
18
+
19
+ ### step 1: filter all repos w/o traffic summary
20
+ repos = @stats.repos.select do |repo|
21
+ traffic = repo.stats.traffic || {}
22
+ summary = traffic['summary'] || {}
23
+
24
+ res = summary['views'] && summary['clones'] ## return true if present
25
+ puts " no traffic/summary/{views,clones} - skipping >#{repo.full_name}<..." unless res
26
+ res
27
+ end
28
+
29
+
30
+ repos = repos.sort do |l,r|
31
+ lsummary = l.stats.traffic['summary']
32
+ rsummary = r.stats.traffic['summary']
33
+
34
+ ## note: use reverse sort (right,left) - e.g. most page views first
35
+ res = rsummary['views']['count'] <=> lsummary['views']['count']
36
+ res = rsummary['views']['uniques'] <=> lsummary['views']['uniques'] if res == 0
37
+ res = rsummary['clones']['count'] <=> lsummary['clones']['count'] if res == 0
38
+ res = rsummary['clones']['uniques'] <=> lsummary['clones']['uniques'] if res == 0
39
+ res = l.full_name <=> r.full_name if res == 0
40
+ res
41
+ end
42
+
43
+
44
+ repos_by_org = repos.group_by { |repo|
45
+ # csvreader/csvreader" =>
46
+ # csvreader
47
+ repo.owner # user username / org | login
48
+ }
49
+ .sort { |(lowner,lrepos), (rowner,rrepos)|
50
+ lviews = lrepos.reduce(0) {|sum,repo| sum+repo.stats.traffic['summary']['views']['count'] }
51
+ rviews = rrepos.reduce(0) {|sum,repo| sum+repo.stats.traffic['summary']['views']['count'] }
52
+ lclones = lrepos.reduce(0) {|sum,repo| sum+repo.stats.traffic['summary']['clones']['count'] }
53
+ rclones = rrepos.reduce(0) {|sum,repo| sum+repo.stats.traffic['summary']['clones']['count'] }
54
+ res = rviews <=> lviews
55
+ res = rclones <=> lclones if res == 0
56
+ res = lrepos.size <=> rrepos.size if res == 0
57
+ res = lowner <=> rowner if res == 0
58
+ res
59
+ }
60
+ .to_h ## convert back to hash
61
+
62
+
63
+ repos_by_org.each_with_index do |(owner, repos),i|
64
+ views = repos.reduce(0) {|sum,repo| sum+repo.stats.traffic['summary']['views']['count'] }
65
+ clones = repos.reduce(0) {|sum,repo| sum+repo.stats.traffic['summary']['clones']['count'] }
66
+
67
+ buf << "#{i+1}. **#{owner}** views: #{views}, clones: #{clones} _(#{repos.size})_"
68
+ buf << "\n"
69
+
70
+ ### todo - sort by count / uniques !!
71
+ repos.each do |repo|
72
+
73
+ summary = repo.stats.traffic['summary']
74
+
75
+ ## note: sublist indent four (4) spaces
76
+ buf << " - #{repo.name} -- "
77
+ buf << " views: #{summary['views']['count']} / #{summary['views']['uniques']} - "
78
+ buf << " clones: #{summary['clones']['count']} / #{summary['clones']['uniques']}"
79
+ buf << "\n"
80
+ end
81
+ end
82
+
83
+ buf << "<!-- break -->\n" ## markdown hack: add a list end marker
84
+ buf << "\n\n"
85
+
86
+
87
+
88
+ ### all page paths
89
+ buf << "All repos:"
90
+ buf << "\n\n"
91
+
92
+
93
+ ## pp repos
94
+
95
+ repos.each_with_index do |repo,i|
96
+ summary = repo.stats.traffic['summary']
97
+
98
+ buf << "#{i+1}. **#{repo.full_name}** -- "
99
+ buf << " views: #{summary['views']['count']} / #{summary['views']['uniques']} - "
100
+ buf << " clones: #{summary['clones']['count']} / #{summary['clones']['uniques']}"
101
+ buf << "\n"
102
+ end
103
+ buf << "<!-- break -->\n" ## markdown hack: add a list end marker
104
+ buf << "\n\n"
105
+
106
+
107
+ buf
108
+ end # method build
109
+ end # class ReportTraffic
110
+
111
+
112
+ end # module Hubba
@@ -0,0 +1,133 @@
1
+ module Hubba
2
+
3
+
4
+ class ReportTrafficPages < Report ## todo/check: rename to TrafficPaths - why? why not?
5
+
6
+ def build
7
+
8
+ ## note: orgs is orgs+users e.g. geraldb, yorobot etc
9
+ buf = String.new('')
10
+ buf << "# Traffic Pages"
11
+ buf << " - #{@stats.repos.size} Repos @ #{@stats.orgs.size} Orgs"
12
+ buf << "\n\n"
13
+
14
+ buf << "popular pages over the last 14 days - page views / unique\n"
15
+ buf << "\n"
16
+
17
+
18
+ ### step 1: filter all repos w/o traffic summary
19
+ repos = @stats.repos.select do |repo|
20
+ traffic = repo.stats.traffic || {}
21
+ summary = traffic['summary'] || {}
22
+
23
+ paths = summary['paths']
24
+ res = paths && paths.size > 0 ## return true if present and non-empty array too
25
+ puts " no traffic/summary/paths - skipping >#{repo.full_name}<..." unless res
26
+ res
27
+ end
28
+
29
+ ## collect all paths entries
30
+ lines = []
31
+ repos.each do |repo|
32
+ summary = repo.stats.traffic['summary']
33
+ # e.g.
34
+ # "paths": [
35
+ # {
36
+ # "path": "/csvreader/csvreader",
37
+ # "title": "GitHub - csvreader/csvreader: csvreader library / gem - read tabular data in ...",
38
+ # "count": 33,
39
+ # "uniques": 25
40
+ # },
41
+
42
+ paths = summary['paths']
43
+ if paths
44
+ ### clean (normalize) paths
45
+ paths.each do |line|
46
+ # "/csvreader/csvreader" =>
47
+ # csvreader/csvreader
48
+ path = line['path'][1..-1] ## cut of leading slash (/)
49
+
50
+ ## /blob/master, /tree/master, /master
51
+ path = path.sub( %r{/blob/(master|gh-pages)(?=/)}, '' )
52
+ path = path.sub( %r{/tree/(master|gh-pages)(?=/)}, '' )
53
+ path = path.sub( %r{/(master|gh-pages)(?=/|$)}, '' ) ## ending in master (e.g. /search/master)
54
+
55
+ line['path'] = path
56
+ end
57
+ lines += paths
58
+ end
59
+ end
60
+
61
+
62
+ ## sort by 1) count
63
+ ## 2) uniques
64
+ ## 3) a-z path
65
+ lines = lines.sort do |l,r|
66
+ res = r['count'] <=> l['count']
67
+ res = r['uniques'] <=> l['uniques'] if res == 0
68
+ res = l['path'] <=> r['path'] if res == 0
69
+ res
70
+ end
71
+
72
+
73
+ lines_by_path = lines.group_by { |line|
74
+ parts = line['path'].split( '/' )
75
+ parts[0]
76
+ }
77
+ .sort { |(lpath,llines), (rpath,rlines)|
78
+ lcount = llines.reduce(0) {|sum,line| sum+line['count'] }
79
+ rcount = rlines.reduce(0) {|sum,line| sum+line['count'] }
80
+ res = rcount <=> lcount
81
+ res = llines.size <=> rlines.size if res == 0
82
+ res = lpath <=> rpath if res == 0
83
+ res
84
+ }
85
+ .to_h ## convert back to hash
86
+
87
+
88
+ lines_by_path.each_with_index do |(path, lines),i|
89
+ count = lines.reduce(0) {|sum,line| sum+line['count']}
90
+ uniques = lines.reduce(0) {|sum,line| sum+line['uniques']}
91
+ buf << "#{i+1}. **#{path}** #{count} / #{uniques} _(#{lines.size})_"
92
+ buf << "\n"
93
+
94
+ ### todo - sort by count / uniques !!
95
+ lines.each do |line|
96
+ ## e.g. convert
97
+ ## openfootball/football.json/tree/master/2020 =>
98
+ ## football.json/tree/master/2020
99
+ parts = line['path'].split( '/' )
100
+ path = parts[1..-1].join( '/' )
101
+
102
+ ## note: sublist indent four (4) spaces
103
+ buf << " - #{line['count']} / #{line['uniques']} -- #{path}"
104
+ buf << "\n"
105
+ end
106
+ end
107
+
108
+ buf << "<!-- break -->\n" ## markdown hack: add a list end marker
109
+ buf << "\n\n"
110
+
111
+
112
+ ### all page paths
113
+ buf << "All pages:"
114
+ buf << "\n\n"
115
+
116
+ lines.each_with_index do |line,i|
117
+ buf << "#{i+1}. #{line['count']} / #{line['uniques']} -- #{line['path']}"
118
+ buf << "\n"
119
+ end
120
+ buf << "<!-- break -->\n" ## markdown hack: add a list end marker
121
+ buf << "\n\n"
122
+
123
+
124
+ buf
125
+ end # method build
126
+
127
+
128
+
129
+
130
+ end # class ReportTrafficPages
131
+
132
+
133
+ end # module Hubba
@@ -0,0 +1,115 @@
1
+ module Hubba
2
+
3
+
4
+ class ReportTrafficReferrers < Report
5
+
6
+ def build
7
+
8
+ ## note: orgs is orgs+users e.g. geraldb, yorobot etc
9
+ buf = String.new('')
10
+ buf << "# Traffic Referrers"
11
+ buf << " - #{@stats.repos.size} Repos @ #{@stats.orgs.size} Orgs"
12
+ buf << "\n\n"
13
+
14
+
15
+ buf << "popular referrer sources over the last 14 days - page views / unique\n"
16
+ buf << "\n"
17
+
18
+
19
+ ### step 1: filter all repos w/o traffic summary
20
+ repos = @stats.repos.select do |repo|
21
+ traffic = repo.stats.traffic || {}
22
+ summary = traffic['summary'] || {}
23
+
24
+ referrers = summary['referrers']
25
+ res = referrers && referrers.size > 0 ## return true if present and non-empty array too
26
+ puts " no traffic/summary/referrers - skipping >#{repo.full_name}<..." unless res
27
+ res
28
+ end
29
+
30
+ ## collect all referrers entries
31
+ lines = []
32
+ repos.each do |repo|
33
+ summary = repo.stats.traffic['summary']
34
+ # e.g.
35
+ # "referrers" =>
36
+ # [{"referrer"=>"github.com", "count"=>327, "uniques"=>198},
37
+ # {"referrer"=>"openfootball.github.io", "count"=>71, "uniques"=>54},
38
+ # {"referrer"=>"Google", "count"=>5, "uniques"=>5},
39
+ # {"referrer"=>"reddit.com", "count"=>4, "uniques"=>4}]
40
+
41
+
42
+ referrers = summary['referrers']
43
+ if referrers
44
+ lines += referrers.map do |referrer|
45
+ # note: return a new copy with (repo) path added
46
+ referrer.merge( 'path' => repo.full_name )
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+
53
+ ## sort by 1) count
54
+ ## 2) uniques
55
+ ## 3) a-z referrer
56
+ ## 4) a-z path
57
+ lines = lines.sort do |l,r|
58
+ res = r['count'] <=> l['count']
59
+ res = r['uniques'] <=> l['uniques'] if res == 0
60
+ res = l['referrer'] <=> r['referrer'] if res == 0
61
+ res = l['path'] <=> r['path'] if res == 0
62
+ res
63
+ end
64
+
65
+
66
+ lines_by_referrer = lines.group_by { |line| line['referrer'] }
67
+ .sort { |(lreferrer,llines),
68
+ (rreferrer,rlines)|
69
+ lcount = llines.reduce(0) {|sum,line| sum+line['count'] }
70
+ rcount = rlines.reduce(0) {|sum,line| sum+line['count'] }
71
+ res = rcount <=> lcount
72
+ res = llines.size <=> rlines.size if res == 0
73
+ res = lreferrer <=> rreferrer if res == 0
74
+ res
75
+ }
76
+ .to_h ## convert back to hash
77
+
78
+
79
+ lines_by_referrer.each_with_index do |(referrer, lines),i|
80
+ count = lines.reduce(0) {|sum,line| sum+line['count']}
81
+ uniques = lines.reduce(0) {|sum,line| sum+line['uniques']}
82
+ buf << "#{i+1}. **#{referrer}** #{count} / #{uniques} _(#{lines.size})_"
83
+ buf << "\n"
84
+
85
+ ### todo - sort by count / uniques !!
86
+ lines.each do |line|
87
+ ## note: sublist indent four (4) spaces
88
+ buf << " - #{line['count']} / #{line['uniques']} -- #{line['path']}"
89
+ buf << "\n"
90
+ end
91
+ end
92
+
93
+ buf << "<!-- break -->\n" ## markdown hack: add a list end marker
94
+ buf << "\n\n"
95
+
96
+
97
+ ### all referrer sources / records by page views
98
+ buf << "All referrers:"
99
+ buf << "\n\n"
100
+
101
+ lines.each_with_index do |line,i|
102
+ buf << "- #{line['referrer']} -- #{line['count']} / #{line['uniques']} -- #{line['path']}"
103
+ buf << "\n"
104
+ end
105
+
106
+ buf << "<!-- break -->\n" ## markdown hack: add a list end marker
107
+ buf << "\n\n"
108
+
109
+
110
+
111
+ buf
112
+ end # method build
113
+ end # class ReportTrafficReferrers
114
+
115
+ end # module Hubba