hubba 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c7c4d9d7af183756855559bc03b8910bdcb1ace
4
- data.tar.gz: 4cfd725ee9c1a3138370cbcb61e1bd900d689012
3
+ metadata.gz: 6dfdf158420e74f4a2810c18e46cab065aa2dcce
4
+ data.tar.gz: 51357a2974422d2e9c4c0bb7b961d08ee43297bd
5
5
  SHA512:
6
- metadata.gz: a6cb53226a5a73777bc9ad86d82a22a39ea56710514233d5530b489d9fcce1bd9cc67b65f6d41f488d3ee4a266e0be5cbcbeef9231cef9007427928d60785214
7
- data.tar.gz: 38395c69b0e45a174a1629029803f41b3e5d1ca7dba27d893dfcebd70f59ed4f17e60e6ec1715c331b61d8e49ef727de564aba14a03b0dfe75a6c15850e3bdc8
6
+ metadata.gz: 7388e0646b07392b35ad13ea738c440b49f37cca283b4abf380071069ce48ef22bbe2d9fe293e266056ee1c7c386c92547740bb84a74cf3c03651a1f48ac48b2
7
+ data.tar.gz: 4ffbc0a84814db71694e6f0d750c7269916ae30f46a64ca79679976de222e06cbb63918b73b47c679ef8b92fa4fc9abce86f2cc3128903c1e2c8da634cfd96e2
@@ -4,19 +4,11 @@ README.md
4
4
  Rakefile
5
5
  lib/hubba.rb
6
6
  lib/hubba/config.rb
7
- lib/hubba/folio.rb
8
7
  lib/hubba/github.rb
9
- lib/hubba/hubba.rb
10
- lib/hubba/reports.rb
8
+ lib/hubba/reposet.rb
11
9
  lib/hubba/stats.rb
12
10
  lib/hubba/update.rb
13
11
  lib/hubba/update_traffic.rb
14
12
  lib/hubba/version.rb
15
13
  test/helper.rb
16
- test/stats/jekyll~minima.json
17
- test/stats/openblockchains~awesome-blockchains.json
18
- test/stats/opendatajson~factbook.json.json
19
- test/stats/poole~hyde.json
20
14
  test/test_config.rb
21
- test/test_stats.rb
22
- test/test_stats_tmp.rb
data/README.md CHANGED
@@ -87,6 +87,8 @@ account that are forks get auto-excluded.
87
87
  ### Step 2: Update repo statistics (daily / weekly / monthly)
88
88
 
89
89
 
90
+ #### Basics (commits, stars, forks, topics, etc.)
91
+
90
92
  Use `update_stats` to
91
93
  to get the latest commit, star count and more for all your repos
92
94
  listed in `./repos.yml` via the GitHub API:
@@ -99,150 +101,27 @@ Note: By default the datafiles (one per repo)
99
101
  get stored in the `./data` directory.
100
102
 
101
103
 
104
+ #### Traffic (page views, clones, referrers, etc.)
102
105
 
103
-
104
- ### Step 3: Generate some statistics / reports
105
-
106
-
107
- Hubba has four built-in reports (for now):
108
-
109
- - `ReportSummary` - A-Z list of your repos by orgs with stars and size in kb
110
- - `ReportStars` - your repos ranked by stars
111
- - `ReportTimeline` - your repos in reverse chronological order by creation
112
- - `ReportUpdates` - your repos in reverse chronological order by last commit
113
-
114
-
115
- If you only generate a single report, use:
116
-
117
- ``` ruby
118
- report = Hubba::ReportSummary.new( './repos.yml' )
119
- report.save( './SUMMARY.md' )
120
- ```
121
-
122
-
123
- If you generate more reports, (re)use the in-memory statistics cache / object:
106
+ Use `update_traffic` to
107
+ to get the latest traffic stats (page views, clones, referrers, etc.)
108
+ for all your repos listed in `./repos.yml` via the GitHub API.
124
109
 
125
110
  ``` ruby
126
- stats = Hubba.stats( './repos.yml' )
127
-
128
- report = Hubba::ReportSummary.new( stats )
129
- report.save( './SUMMARY.md' )
130
-
131
- report = Hubba::ReportStars.new( stats )
132
- report.save( './STARS.md' )
133
-
134
- report = Hubba::ReportTimeline.new( stats )
135
- report.save( './TIMELINE.md' )
136
-
137
- report = Hubba::ReportUpdates.new( stats )
138
- report.save( './UPDATES.md' )
111
+ Hubba.update_traffic( './repos.yml' )
139
112
  ```
140
113
 
114
+ Note: Access to traffic statistics via the GitHub API
115
+ requires push access for your GitHub (personal access) token.
141
116
 
142
- ### Report Examples
143
-
144
- #### Report Example - Summary
145
-
146
- A-Z list of your repos by orgs with stars and size in kb.
147
- Results in:
148
-
149
- ---
150
-
151
- > 593 repos @ 83 orgs
152
- >
153
- > ### geraldb _(11)_
154
- >
155
- > **austria** ★1 (552 kb) · **catalog** ★3 (156 kb) · **chelitas** ★1 (168 kb) · **geraldb.github.io** ★1 (520 kb) · **logos** ★1 (363 kb) · **sandbox** ★2 (529 kb) · **talks** ★200 (16203 kb) · **web-proxy-win** ★8 (152 kb) · **webcomponents** ★1 (164 kb) · **webpub-reader** ★3 (11 kb) · **wine.db.tools** ★1 (252 kb)
156
- >
157
- > ...
158
-
159
- ---
160
-
161
- (Live Example - [`SUMMARY.md`](https://github.com/yorobot/backup/blob/master/SUMMARY.md))
162
-
163
-
164
- #### Report Example - Stars
165
-
166
- Your repos ranked by stars. Results in:
167
-
168
- ---
169
-
170
- > 593 repos @ 83 orgs
171
- >
172
- > 1. ★2936 **openblockchains/awesome-blockchains** (2514 kb)
173
- > 2. ★851 **planetjekyll/awesome-jekyll-plugins** (148 kb)
174
- > 3. ★604 **factbook/factbook.json** (7355 kb)
175
- > 4. ★593 **openfootball/football.json** (2135 kb)
176
- > 5. ★570 **openmundi/world.db** (1088 kb)
177
- > 6. ★552 **openblockchains/programming-blockchains** (552 kb)
178
- > 7. ★547 **mundimark/awesome-markdown** (83 kb)
179
- > 8. ★532 **planetjekyll/awesome-jekyll** (110 kb)
180
- > 9. ★489 **cryptocopycats/awesome-cryptokitties** (4154 kb)
181
- > 10. ★445 **openfootball/world-cup** (638 kb)
182
- >
183
- > ...
184
-
185
- ---
186
-
187
- (Live Example: [`STARS.md`](https://github.com/yorobot/backup/blob/master/STARS.md))
188
-
189
-
190
- #### Report Example - Timeline
191
-
192
- Your repos in reverse chronological order by creation.
193
- Results in:
194
-
195
- ---
196
-
197
- > 593 repos @ 83 orgs
198
- >
199
- > ## 2020
200
- >
201
- > ### 9
202
- >
203
- > - 2020-09-18 ★1 **yorobot/workflow** (83 kb)
204
- >
205
- > ### 6
206
- >
207
- > - 2020-06-27 ★2 **yorobot/sport.db.more** (80 kb)
208
- > - 2020-06-24 ★1 **yorobot/stage** (554 kb)
209
- > - 2020-06-11 ★1 **yorobot/cache.csv** (336 kb)
210
- >
211
- > ...
212
-
213
- ---
214
-
215
- (Live Example: [`TIMELINE.md`](https://github.com/yorobot/backup/blob/master/TIMELINE.md))
216
-
217
-
218
-
219
- #### Report Example - Updates
220
117
 
221
- Your repos in reverse chronological order by last commit. Results in:
222
118
 
223
- ---
224
119
 
225
- > 593 repos @ 83 orgs
226
- >
227
- > committed / pushed / updated / created
228
- >
229
- > - (1d) **yorobot/backup** ★4 - 2020-10-08 (=/=) / 2020-10-08 (=) / 2020-10-08 / 2015-04-04 - ‹› (1595 kb)
230
- > - (1d) **yorobot/logs** ★1 - 2020-10-08 (=/=) / 2020-10-08 (=) / 2020-10-08 / 2016-09-13 - ‹› (172 kb)
231
- > - (1d) **rubycoco/git** ★9 - 2020-10-08 (=/=) / 2020-10-08 (=) / 2020-10-08 / 2015-11-16 - ‹› (88 kb)
232
- > - (1d) **openfootball/football.json** ★593 - 2020-10-08 (=/=) / 2020-10-08 (=) / 2020-10-08 / 2015-09-17 - ‹› (2135 kb)
233
- > - (2d) **yorobot/workflow** ★1 - 2020-10-07 (=/=) / 2020-10-07 (=) / 2020-10-07 / 2020-09-18 - ‹› (83 kb)
234
- > - (2d) **rubycoco/webclient** ★5 - 2020-10-07 (=/=) / 2020-10-07 (=) / 2020-10-07 / 2012-06-02 - ‹› (39 kb)
235
- > - (3d) **footballcsv/belgium** ★1 - 2020-10-06 (=/=) / 2020-10-06 (=) / 2020-10-06 / 2014-07-25 - ‹› (314 kb)
236
- > - (3d) **footballcsv/england** ★105 - 2020-10-06 (=/=) / 2020-10-06 (=) / 2020-10-06 / 2014-07-23 - ‹› (8666 kb)
237
- > - (3d) **footballcsv/austria** ★1 - 2020-10-06 (=/=) / 2020-10-06 (=) / 2020-10-06 / 2018-07-16 - ‹› (91 kb)
238
- > - (3d) **footballcsv/espana** ★15 - 2020-10-06 (=/=) / 2020-10-06 (=) / 2020-10-06 / 2014-07-23 - ‹› (1107 kb)
239
- > - (3d) **footballcsv/deutschland** ★5 - 2020-10-06 (=/=) / 2020-10-06 (=) / 2020-10-06 / 2014-07-25 - ‹› (1343 kb)
240
- >
241
- > ...
120
+ ### Step 3: Generate some statistics / analytics reports
242
121
 
243
- ---
244
122
 
245
- (Live Example: [`UPDATES.md`](https://github.com/yorobot/backup/blob/master/UPDATES.md))
123
+ See the [hubba-reports gem](https://github.com/rubycoco/git/tree/master/hubba-reports) on how to use pre-built/pre-packaged ready-to-use
124
+ github statistics / analytics reports.
246
125
 
247
126
 
248
127
 
@@ -23,15 +23,14 @@ end
23
23
  require 'hubba/version' # note: let version always go first
24
24
  require 'hubba/config'
25
25
  require 'hubba/github'
26
- require 'hubba/stats'
26
+ require 'hubba/reposet'
27
27
 
28
- ## "higher level" porcelain services / helpers for easy (re)use
29
- require 'hubba/folio' ## "access layer" for reports
30
- require 'hubba/hubba'
28
+ ### update stats (github data) machinery
29
+ require 'hubba/stats'
31
30
  require 'hubba/update'
32
31
  require 'hubba/update_traffic'
33
32
 
34
- require 'hubba/reports'
33
+
35
34
 
36
35
 
37
36
  ############
@@ -42,4 +41,6 @@ end
42
41
 
43
42
 
44
43
  # say hello
45
- puts Hubba.banner if defined?($RUBYCOCO_DEBUG)
44
+ puts Hubba.banner
45
+
46
+
@@ -80,18 +80,4 @@ def self.reposet( *users, orgs: true,
80
80
  h
81
81
  end ## method reposet
82
82
 
83
-
84
- def self.stats( hash_or_path='./repos.yml' ) ## use read_stats or such - why? why not?
85
- h = if hash_or_path.is_a?( String ) ## assume it is a file path!!!
86
- path = hash_or_path
87
- YAML.load_file( path )
88
- else
89
- hash_or_path # assume its a hash / reposet already!!!
90
- end
91
-
92
- Folio.new( h ) ## wrap in "easy-access" facade / wrapper
93
- end ## method stats
94
-
95
-
96
83
  end # module Hubba
97
-
@@ -5,227 +5,16 @@ module Hubba
5
5
 
6
6
  class Stats ## todo/check: rename to GithubRepoStats or RepoStats - why? why not?
7
7
 
8
- attr_reader :data
9
-
10
8
  def initialize( full_name )
11
9
  @data = {}
12
10
  @data['full_name'] = full_name # e.g. poole/hyde etc.
13
11
 
14
- @cache = {}
15
- end
16
-
17
-
18
- def full_name() @data['full_name']; end
19
-
20
-
21
- ## note: return datetime objects (NOT strings); if not present/available return nil/null
22
- def created_at() @cache['created_at'] ||= parse_datetime( @data['created_at'] ); end
23
- def updated_at() @cache['updated_at'] ||= parse_datetime( @data['updated_at'] ); end
24
- def pushed_at() @cache['pushed_at'] ||= parse_datetime( @data['pushed_at'] ); end
25
-
26
- ## date (only) versions
27
- def created() @cache['created'] ||= parse_date( @data['created_at'] ); end
28
- def updated() @cache['updated'] ||= parse_date( @data['updated_at'] ); end
29
- def pushed() @cache['pushed'] ||= parse_date( @data['pushed_at'] ); end
30
-
31
- def size
32
- # size of repo in kb (as reported by github api)
33
- @data['size'] || 0 ## return 0 if not found - why? why not? (return nil - why? why not??)
34
- end
35
-
36
-
37
- def history
38
- @cache['history'] ||= begin
39
- if @data['history']
40
- build_history( @data['history'] )
41
- else
42
- nil
43
- end
44
- end
45
- end
46
-
47
-
48
- def stars
49
- ## return last stargazers_count entry (as number; 0 if not found)
50
- @cache['stars'] ||= history ? history[0].stars : 0
51
- end
52
-
53
-
54
- def commits() @data['commits']; end
55
-
56
- def last_commit ## convenience shortcut; get first/last commit (use [0]) or nil
57
- if @data['commits'] && @data['commits'][0]
58
- @data['commits'][0]
59
- else
60
- nil
61
- end
62
- end
63
-
64
-
65
- def committed ## last commit date (from author NOT committer)
66
- @cache['committed'] ||= parse_date( last_commit_author_date )
67
- end
68
-
69
- def committed_at() ## last commit date (from author NOT committer)
70
- @cache['committed_at'] ||= parse_datetime( last_commit_author_date )
71
- end
72
-
73
- def last_commit_author_date
74
- h = last_commit
75
- h ? h['author']['date'] : nil
12
+ @cache = {} ## keep a lookup cache - why? why not?
76
13
  end
77
14
 
78
15
 
79
- def last_commit_message ## convenience shortcut; last commit message
80
- h = last_commit
81
-
82
- committer_name = h['committer']['name']
83
- author_name = h['author']['name']
84
- message = h['message']
85
-
86
- buf = ""
87
- buf << message
88
- buf << " by #{author_name}"
89
-
90
- if committer_name != author_name
91
- buf << " w/ #{committer_name}"
92
- end
93
- end # method commit_message
94
-
95
-
96
-
97
- ###
98
- # helpers
99
- def parse_datetime( str ) str ? DateTime.strptime( str, '%Y-%m-%dT%H:%M:%S') : nil; end
100
- def parse_date( str ) str ? Date.strptime( str, '%Y-%m-%d') : nil; end
101
-
102
- ########
103
- ## build history items (structs)
104
-
105
- class HistoryItem
106
-
107
- attr_reader :date, :stars ## read-only attributes
108
- attr_accessor :prev, :next ## read/write attributes (for double linked list/nodes/items)
109
-
110
- def initialize( date:, stars: )
111
- @date = date
112
- @stars = stars
113
- @next = nil
114
- end
115
-
116
- ## link items (append item at the end/tail)
117
- def append( item )
118
- @next = item
119
- item.prev = self
120
- end
121
-
122
- def diff_days
123
- if @next
124
- ## note: use jd=julian days for calculation
125
- @date.jd - @next.date.jd
126
- else
127
- nil ## last item (tail)
128
- end
129
- end
130
-
131
- def diff_stars
132
- if @next
133
- @stars - @next.stars
134
- else
135
- nil ## last item (tail)
136
- end
137
- end
138
- end ## class HistoryItem
139
-
140
-
141
- def build_history( timeseries )
142
- items = []
143
-
144
- keys = timeseries.keys.sort.reverse ## newest (latest) items first
145
- keys.each do |key|
146
- h = timeseries[ key ]
147
-
148
- item = HistoryItem.new(
149
- date: Date.strptime( key, '%Y-%m-%d' ),
150
- stars: h['stargazers_count'] || 0 )
151
-
152
- ## link items
153
- last_item = items[-1]
154
- last_item.append( item ) if last_item ## if not nil? append (note first item has no prev item)
155
-
156
- items << item
157
- end
158
-
159
- ## todo/check: return [] for empty items array (items.empty?) - why?? why not??
160
- if items.empty?
161
- nil
162
- else
163
- items
164
- end
165
- end ## method build_history
166
-
167
-
168
-
169
- def calc_diff_stars( samples: 3, days: 30 )
170
- ## samples: use n history item samples e.g. 3 samples
171
- ## days e.g. 7 days (per week), 30 days (per month)
172
-
173
- if history.nil?
174
- nil ## todo/check: return 0.0 too - why? why not?
175
- elsif history.size == 1
176
- ## just one item; CANNOT calc diff; return zero
177
- 0.0
178
- else
179
- idx = [history.size, samples].min ## calc last index
180
- last = history[idx-1]
181
- first = history[0]
182
-
183
- diff_days = first.date.jd - last.date.jd
184
- diff_stars = first.stars - last.stars
185
-
186
- ## note: use factor 1000 for fixed integer division
187
- ## converts to float at the end
188
-
189
- ## todo: check for better way (convert to float upfront - why? why not?)
190
-
191
- diff = (diff_stars * days * 1000) / diff_days
192
- ## puts "diff=#{diff}:#{diff.class.name}" ## check if it's a float
193
- (diff.to_f/1000.0)
194
- end
195
- end
196
-
197
-
198
- def history_str ## todo/check: rename/change to format_history or fmt_history - why? why not?
199
- ## returns "pretty printed" history as string buffer
200
- buf = ''
201
- buf << "[#{history.size}]: "
202
-
203
- history.each do |item|
204
- buf << "#{item.stars}"
205
-
206
- diff_stars = item.diff_stars
207
- diff_days = item.diff_days
208
- if diff_stars && diff_days ## note: last item has no diffs
209
- if diff_stars > 0 || diff_stars < 0
210
- if diff_stars > 0
211
- buf << " (+#{diff_stars}"
212
- else
213
- buf << " (#{diff_stars}"
214
- end
215
- buf << " in #{diff_days}d) "
216
- else ## diff_stars == 0
217
- buf << " (#{diff_days}d) "
218
- end
219
- end
220
- end
221
- buf
222
- end # method history_str
223
-
224
-
225
-
226
16
  ##################
227
17
  ## update
228
-
229
18
  def update_traffic( clones: nil,
230
19
  views: nil,
231
20
  paths: nil,
@@ -415,25 +204,28 @@ end # method update_traffic
415
204
 
416
205
  ########################################
417
206
  ## read / write methods / helpers
418
-
419
207
  def write
420
- basename = full_name.gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
421
- data_dir = Hubba.config.data_dir
208
+ basename = @data['full_name'].gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
209
+ letter = basename[0] ## use first letter as index dir e.g. p/poole~hyde
210
+ data_dir = "#{Hubba.config.data_dir}/#{letter}"
211
+ path = "#{data_dir}/#{basename}.json"
212
+
422
213
  puts " writing stats to #{basename} (#{data_dir})..."
423
214
 
424
- ## todo/fix: add FileUtils.makepath_r or such!!!
425
- File.open( "#{data_dir}/#{basename}.json", 'w:utf-8' ) do |f|
426
- f.write JSON.pretty_generate( data )
215
+ FileUtils.mkdir_p( File.dirname( path )) ## make sure path exists
216
+ File.open( path, 'w:utf-8' ) do |f|
217
+ f.write( JSON.pretty_generate( @data ))
427
218
  end
428
219
  self ## return self for (easy chaining)
429
- end
220
+ end # method write
430
221
 
431
222
 
432
223
  def read
433
224
  ## note: skip reading if file not present
434
- basename = full_name.gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
435
- data_dir = Hubba.config.data_dir
436
- path = "#{data_dir}/#{basename}.json"
225
+ basename = @data['full_name'].gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
226
+ letter = basename[0] ## use first letter as index dir e.g. p/poole~hyde
227
+ data_dir = "#{Hubba.config.data_dir}/#{letter}"
228
+ path = "#{data_dir}/#{basename}.json"
437
229
 
438
230
  if File.exist?( path )
439
231
  puts " reading stats from #{basename} (#{data_dir})..."
@@ -447,8 +239,7 @@ end # method update_traffic
447
239
  puts "!! WARN: - skipping reading stats from #{basename} -- file not found"
448
240
  end
449
241
  self ## return self for (easy chaining)
450
- end
451
-
242
+ end # method read
452
243
  end # class Stats
453
244
 
454
245
 
@@ -1,7 +1,7 @@
1
1
  module Hubba
2
2
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
3
- MINOR = 6
4
- PATCH = 2
3
+ MINOR = 7
4
+ PATCH = 0
5
5
  VERSION = [MAJOR,MINOR,PATCH].join('.')
6
6
 
7
7
  def self.version
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hubba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-11 00:00:00.000000000 Z
11
+ date: 2020-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: webclient
@@ -73,22 +73,14 @@ files:
73
73
  - Rakefile
74
74
  - lib/hubba.rb
75
75
  - lib/hubba/config.rb
76
- - lib/hubba/folio.rb
77
76
  - lib/hubba/github.rb
78
- - lib/hubba/hubba.rb
79
- - lib/hubba/reports.rb
77
+ - lib/hubba/reposet.rb
80
78
  - lib/hubba/stats.rb
81
79
  - lib/hubba/update.rb
82
80
  - lib/hubba/update_traffic.rb
83
81
  - lib/hubba/version.rb
84
82
  - test/helper.rb
85
- - test/stats/jekyll~minima.json
86
- - test/stats/openblockchains~awesome-blockchains.json
87
- - test/stats/opendatajson~factbook.json.json
88
- - test/stats/poole~hyde.json
89
83
  - test/test_config.rb
90
- - test/test_stats.rb
91
- - test/test_stats_tmp.rb
92
84
  homepage: https://github.com/rubycoco/git
93
85
  licenses:
94
86
  - Public Domain
@@ -1,60 +0,0 @@
1
- module Hubba
2
-
3
- class Folio # todo/check: use a different name e.g (Port)Folio, Cache, Summary, (Data)Base, Census, Catalog, Collection, Index, Register or such???
4
- class Repo ## (nested) class
5
-
6
- attr_reader :owner,
7
- :name
8
-
9
- def initialize( owner, name )
10
- @owner = owner ## rename to login, username - why? why not?
11
- @name = name ## rename to reponame ??
12
- end
13
-
14
- def full_name() "#{owner}/#{name}"; end
15
-
16
- def stats
17
- ## note: load stats on demand only (first access) for now - why? why not?
18
- @stats ||= begin
19
- stats = Stats.new( full_name )
20
- stats.read
21
- stats
22
- end
23
- end
24
-
25
- def diff
26
- @diff ||= stats.calc_diff_stars( samples: 3, days: 30 )
27
- end
28
- end # (nested) class Repo
29
-
30
-
31
- attr_reader :orgs, :repos
32
-
33
- def initialize( h )
34
- @orgs = [] # orgs and users -todo/check: use better name - logins or owners? why? why not?
35
- @repos = []
36
- add( h )
37
-
38
- puts "#{@repos.size} repos @ #{@orgs.size} orgs"
39
- end
40
-
41
- #############
42
- ## private helpes
43
- def add( h ) ## add repos.yml set
44
- h.each do |org_with_counter, names|
45
- ## remove optional number from key e.g.
46
- ## mrhydescripts (3) => mrhydescripts
47
- ## footballjs (4) => footballjs
48
- ## etc.
49
- org = org_with_counter.sub( /\([0-9]+\)/, '' ).strip
50
- repos = []
51
- names.each do |name|
52
- repo = Repo.new( org, name )
53
- repos << repo
54
- end
55
- @orgs << [org, repos]
56
- @repos += repos
57
- end
58
- end
59
- end # class Folio
60
- end # module Hubba
@@ -1,249 +0,0 @@
1
- module Hubba
2
-
3
-
4
- class Report
5
- def initialize( stats_or_hash_or_path=Hubba.stats )
6
- ## puts "[debug] Report#initialize:"
7
- ## pp stats_or_hash_or_path if stats_or_hash_or_path.is_a?( String )
8
-
9
- @stats = if stats_or_hash_or_path.is_a?( String ) ||
10
- stats_or_hash_or_path.is_a?( Hash )
11
- hash_or_path = stats_or_hash_or_path
12
- Hubba.stats( hash_or_path )
13
- else
14
- stats_or_hash_or_path ## assume Summary/Stats - todo/fix: double check!!!
15
- end
16
- end
17
-
18
- def save( path )
19
- buf = build
20
- puts "writing report >#{path}< ..."
21
- File.open( path, "w:utf-8" ) do |f|
22
- f.write( buf )
23
- end
24
- end
25
- end ## class Report
26
-
27
-
28
-
29
- class ReportSummary < Report
30
-
31
- def build
32
- ## create a (summary report)
33
- ##
34
- ## add stars, last_updates, etc.
35
- ## org description etc??
36
-
37
- ## note: orgs is orgs+users e.g. geraldb, yorobot etc
38
- buf = String.new('')
39
- buf << "# #{@stats.repos.size} repos @ #{@stats.orgs.size} orgs\n"
40
- buf << "\n"
41
-
42
-
43
- @stats.orgs.each do |org|
44
- name = org[0]
45
- repos = org[1]
46
- buf << "### #{name} _(#{repos.size})_\n"
47
- buf << "\n"
48
-
49
- ### add stats for repos
50
- entries = []
51
- repos.each do |repo|
52
- entries << "**#{repo.name}** ★#{repo.stats.stars} (#{repo.stats.size} kb)"
53
- end
54
-
55
- buf << entries.join( ' · ' ) ## use interpunct? - was: • (bullet)
56
- buf << "\n"
57
- buf << "\n"
58
- end
59
-
60
- buf
61
- end # method build
62
- end # class ReportSummary
63
-
64
-
65
-
66
- class ReportStars < Report
67
-
68
- def build
69
-
70
- ## add stars, last_updates, etc.
71
- ## org description etc??
72
-
73
- ## note: orgs is orgs+users e.g. geraldb, yorobot etc
74
- buf = String.new('')
75
- buf << "# #{@stats.repos.size} repos @ #{@stats.orgs.size} orgs\n"
76
- buf << "\n"
77
-
78
-
79
- repos = @stats.repos.sort do |l,r|
80
- ## note: use reverse sort (right,left) - e.g. most stars first
81
- r.stats.stars <=> l.stats.stars
82
- end
83
-
84
- ## pp repos
85
-
86
- repos.each_with_index do |repo,i|
87
- buf << "#{i+1}. ★#{repo.stats.stars} **#{repo.full_name}** (#{repo.stats.size} kb)\n"
88
- end
89
-
90
- buf
91
- end # method build
92
- end # class ReportStars
93
-
94
-
95
-
96
- class ReportTimeline < Report
97
-
98
- def build
99
- ## create a (timeline report)
100
-
101
- ## note: orgs is orgs+users e.g. geraldb, yorobot etc
102
- buf = String.new('')
103
- buf << "# #{@stats.repos.size} repos @ #{@stats.orgs.size} orgs\n"
104
- buf << "\n"
105
-
106
-
107
- repos = @stats.repos.sort do |l,r|
108
- ## note: use reverse sort (right,left) - e.g. most stars first
109
- ## r[:stars] <=> l[:stars]
110
-
111
- ## sort by created_at (use julian days)
112
- r.stats.created.jd <=> l.stats.created.jd
113
- end
114
-
115
-
116
- ## pp repos
117
-
118
-
119
- last_year = -1
120
- last_month = -1
121
-
122
- repos.each_with_index do |repo,i|
123
- year = repo.stats.created.year
124
- month = repo.stats.created.month
125
-
126
- if last_year != year
127
- buf << "\n## #{year}\n\n"
128
- end
129
-
130
- if last_month != month
131
- buf << "\n### #{month}\n\n"
132
- end
133
-
134
- last_year = year
135
- last_month = month
136
-
137
- buf << "- #{repo.stats.created_at.strftime('%Y-%m-%d')} ★#{repo.stats.stars} **#{repo.full_name}** (#{repo.stats.size} kb)\n"
138
- end
139
-
140
- buf
141
- end # method build
142
- end # class ReportTimeline
143
-
144
-
145
-
146
- class ReportTrending < Report
147
-
148
- def build
149
-
150
- ## note: orgs is orgs+users e.g. geraldb, yorobot etc
151
- buf = String.new('')
152
- buf << "# #{@stats.repos.size} repos @ #{@stats.orgs.size} orgs\n"
153
- buf << "\n"
154
-
155
- ###
156
- ## todo:
157
- ## use calc per month (days: 30)
158
- ## per week is too optimistic (e.g. less than one star/week e.g. 0.6 or something)
159
-
160
- repos = @stats.repos.sort do |l,r|
161
- ## note: use reverse sort (right,left) - e.g. most stars first
162
- ## r[:stars] <=> l[:stars]
163
-
164
- ## sort by created_at (use julian days)
165
- ## r[:created_at].to_date.jd <=> l[:created_at].to_date.jd
166
-
167
- res = r.diff <=> l.diff
168
- res = r.stats.stars <=> l.stats.stars if res == 0
169
- res = r.stats.created.jd <=> l.stats.created.jd if res == 0
170
- res
171
- end
172
-
173
-
174
- ## pp repos
175
-
176
-
177
- repos.each_with_index do |repo,i|
178
- if repo.diff == 0
179
- buf << "- -/- "
180
- else
181
- buf << "- #{repo.diff}/month "
182
- end
183
-
184
- buf << " ★#{repo.stats.stars} **#{repo.full_name}** (#{repo.stats.size} kb) - "
185
- buf << "#{repo.stats.history_str}\n"
186
- end
187
-
188
-
189
- buf
190
- end # method build
191
- end # class ReportTrending
192
-
193
-
194
-
195
- class ReportUpdates < Report
196
-
197
- def build
198
-
199
- ## note: orgs is orgs+users e.g. geraldb, yorobot etc
200
- buf = String.new('')
201
- buf << "# #{@stats.repos.size} repos @ #{@stats.orgs.size} orgs\n"
202
- buf << "\n"
203
-
204
- repos = @stats.repos.sort do |l,r|
205
- r.stats.committed.jd <=> l.stats.committed.jd
206
- end
207
-
208
- ## pp repos
209
-
210
-
211
- buf << "committed / pushed / updated / created\n\n"
212
-
213
- today = Date.today
214
-
215
- repos.each_with_index do |repo,i|
216
-
217
- days_ago = today.jd - repo.stats.committed.jd
218
-
219
- diff1 = repo.stats.committed.jd - repo.stats.pushed.jd
220
- diff2 = repo.stats.committed.jd - repo.stats.updated.jd
221
- diff3 = repo.stats.pushed.jd - repo.stats.updated.jd
222
-
223
- buf << "- (#{days_ago}d) **#{repo.full_name}** ★#{repo.stats.stars} - "
224
- buf << "#{repo.stats.committed} "
225
- buf << "("
226
- buf << (diff1==0 ? '=' : "#{diff1}d")
227
- buf << "/"
228
- buf << (diff2==0 ? '=' : "#{diff2}d")
229
- buf << ")"
230
- buf << " / "
231
- buf << "#{repo.stats.pushed} "
232
- buf << "("
233
- buf << (diff3==0 ? '=' : "#{diff3}d")
234
- buf << ")"
235
- buf << " / "
236
- buf << "#{repo.stats.updated} / "
237
- buf << "#{repo.stats.created} - "
238
- buf << "‹#{repo.stats.last_commit_message}›"
239
- buf << " (#{repo.stats.size} kb)"
240
- buf << "\n"
241
- end
242
-
243
-
244
- buf
245
- end # method build
246
- end # class ReportUpdates
247
-
248
-
249
- end # module Hubba
@@ -1,25 +0,0 @@
1
- {
2
- "full_name": "jekyll/minima",
3
- "created_at": "2016-05-20T23:07:56Z",
4
- "updated_at": "2018-02-11T16:13:33Z",
5
- "pushed_at": "2018-02-07T22:14:11Z",
6
- "size": 321,
7
- "history": {
8
- "2018-02-12": {
9
- "stargazers_count": 717
10
- }
11
- },
12
- "commits": [
13
- {
14
- "author": {
15
- "name": "ashmaroli",
16
- "date": "2018-02-21T19:35:59Z"
17
- },
18
- "committer": {
19
- "name": "Frank Taillandier",
20
- "date": "2018-02-21T19:35:59Z"
21
- },
22
- "message": "social icons should resolve baseurl properly (#201)"
23
- }
24
- ]
25
- }
@@ -1,27 +0,0 @@
1
- {
2
- "full_name": "openblockchains/awesome-blockchains",
3
- "created_at": "2017-09-13T22:33:56Z",
4
- "size": 1620,
5
- "history": {
6
- "2017-12-10": {
7
- "stargazers_count": 1084
8
- },
9
- "2018-01-28": {
10
- "stargazers_count": 1411
11
- },
12
- "2018-02-08": {
13
- "stargazers_count": 1526
14
- }
15
- },
16
- "commits": [
17
- {
18
- "committer": {
19
- "date": "2018-02-08T09:33:28Z",
20
- "name": "Gerald Bauer"
21
- },
22
- "message": "Update README.md\n\nJust a little typo cryto -> crypto."
23
- }
24
- ],
25
- "updated_at": "2018-02-08T19:26:35Z",
26
- "pushed_at": "2018-02-08T09:33:29Z"
27
- }
@@ -1,39 +0,0 @@
1
- {
2
- "full_name": "opendatajson/factbook.json",
3
- "created_at": "2014-07-12T12:43:52Z",
4
- "history": {
5
- "2017-02-11": {
6
- "stargazers_count": 457
7
- },
8
- "2017-02-12": {
9
- "stargazers_count": 457
10
- },
11
- "2017-06-18": {
12
- "stargazers_count": 505
13
- },
14
- "2017-07-28": {
15
- "stargazers_count": 512
16
- },
17
- "2017-12-10": {
18
- "stargazers_count": 533
19
- },
20
- "2018-01-28": {
21
- "stargazers_count": 536
22
- },
23
- "2018-02-08": {
24
- "stargazers_count": 539
25
- }
26
- },
27
- "commits": [
28
- {
29
- "committer": {
30
- "date": "2017-03-29T17:23:29Z",
31
- "name": "GitHub"
32
- },
33
- "message": "Update MONGO.md"
34
- }
35
- ],
36
- "size": 7355,
37
- "updated_at": "2018-02-01T12:35:19Z",
38
- "pushed_at": "2017-03-29T17:23:30Z"
39
- }
@@ -1,21 +0,0 @@
1
- {
2
- "full_name": "poole/hyde",
3
- "created_at": "2013-02-07T07:01:38Z",
4
- "updated_at": "2018-02-12T05:44:07Z",
5
- "pushed_at": "2018-01-14T02:41:16Z",
6
- "size": 28428,
7
- "history": {
8
- "2018-02-12": {
9
- "stargazers_count": 2125
10
- }
11
- },
12
- "commits": [
13
- {
14
- "committer": {
15
- "date": "2015-05-11T20:21:43Z",
16
- "name": "Mark Otto"
17
- },
18
- "message": "Merge pull request #91 from pborreli/patch-1\n\nFixed typo"
19
- }
20
- ]
21
- }
@@ -1,125 +0,0 @@
1
- ###
2
- # to run use
3
- # ruby -I ./lib -I ./test test/test_stats.rb
4
-
5
-
6
- require 'helper'
7
-
8
-
9
- class TestStats < MiniTest::Test
10
-
11
-
12
- def test_jekyll_minima
13
-
14
- stats = Hubba::Stats.new( 'jekyll/minima' )
15
-
16
- assert_equal 0, stats.size
17
- assert_equal 0, stats.stars
18
- assert_nil stats.history
19
-
20
- Hubba.config.data_dir = "#{Hubba.root}/test/stats"
21
- stats.read
22
-
23
- assert_equal 321, stats.size
24
- assert_equal 717, stats.stars
25
- assert_equal 717, stats.history[0].stars
26
- assert_equal 1, stats.history.size
27
-
28
- assert_equal Date.new(2018, 2, 12 ), stats.history[0].date
29
-
30
- assert_nil stats.history[0].diff_days
31
-
32
- assert_equal Date.new(2018, 2, 21 ), stats.committed
33
- assert_equal Date.new(2016, 5, 20 ), stats.created
34
- assert_equal Date.new(2018, 2, 11 ), stats.updated
35
- assert_equal Date.new(2018, 2, 7 ), stats.pushed
36
-
37
- assert_equal DateTime.new(2018, 2, 21, 19, 35, 59 ), stats.committed_at
38
- assert_equal DateTime.new(2016, 5, 20, 23, 7, 56 ), stats.created_at
39
- assert_equal DateTime.new(2018, 2, 11, 16, 13, 33 ), stats.updated_at
40
- assert_equal DateTime.new(2018, 2, 7, 22, 14, 11 ), stats.pushed_at
41
-
42
-
43
- pp stats.last_commit
44
- pp stats.last_commit_message
45
- pp stats.history_str ## pp history pretty printed to string (buffer)
46
- end
47
-
48
-
49
-
50
- def test_awesome_blockchains
51
-
52
- stats = Hubba::Stats.new( 'openblockchains/awesome-blockchains' )
53
-
54
- assert_equal 0, stats.size
55
- assert_equal 0, stats.stars
56
- assert_nil stats.history
57
-
58
- Hubba.config.data_dir = "#{Hubba.root}/test/stats"
59
- stats.read
60
-
61
- assert_equal 1620, stats.size
62
- assert_equal 1526, stats.stars
63
- assert_equal 1526, stats.history[0].stars
64
- assert_equal 1411, stats.history[1].stars
65
- assert_equal 1084, stats.history[2].stars
66
- assert_equal 1084, stats.history[-1].stars
67
- assert_equal 3, stats.history.size
68
-
69
- assert_equal Date.new(2018, 2, 8 ), stats.history[0].date
70
- assert_equal Date.new(2018, 1, 28 ), stats.history[1].date
71
- assert_equal Date.new(2017, 12, 10 ), stats.history[2].date
72
-
73
- assert_equal 11, stats.history[0].diff_days
74
- assert_equal 49, stats.history[1].diff_days
75
- assert_nil stats.history[2].diff_days
76
-
77
- assert_equal 115, stats.history[0].diff_stars
78
- assert_equal 327, stats.history[1].diff_stars
79
- assert_nil stats.history[2].diff_stars
80
-
81
- assert_equal 221.0, stats.calc_diff_stars ## defaults to samples: 3, days: 30
82
- assert_equal 51.566, stats.calc_diff_stars( samples: 5, days: 7 )
83
-
84
- pp stats.history_str ## pp history pretty printed to string (buffer)
85
- end
86
-
87
-
88
- def test_factbook_json
89
-
90
- stats = Hubba::Stats.new( 'opendatajson/factbook.json' )
91
-
92
- assert_equal 0, stats.size
93
- assert_equal 0, stats.stars
94
- assert_nil stats.history
95
-
96
- Hubba.config.data_dir = "#{Hubba.root}/test/stats"
97
- stats.read
98
-
99
- assert_equal 7355, stats.size
100
- assert_equal 539, stats.stars
101
- assert_equal 539, stats.history[0].stars
102
- assert_equal 536, stats.history[1].stars
103
- assert_equal 533, stats.history[2].stars
104
- assert_equal 457, stats.history[-1].stars
105
- assert_equal 7, stats.history.size
106
-
107
- assert_equal Date.new(2018, 2, 8 ), stats.history[0].date
108
- assert_equal Date.new(2018, 1, 28 ), stats.history[1].date
109
- assert_equal Date.new(2017, 12, 10 ), stats.history[2].date
110
-
111
- assert_equal 11, stats.history[0].diff_days
112
- assert_equal 49, stats.history[1].diff_days
113
- assert_nil stats.history[-1].diff_days
114
-
115
- assert_equal 3, stats.history[0].diff_stars
116
- assert_equal 3, stats.history[1].diff_stars
117
- assert_nil stats.history[-1].diff_stars
118
-
119
- assert_equal 3.0, stats.calc_diff_stars ## defaults to samples: 3, days: 30
120
- assert_equal 1.012, stats.calc_diff_stars( samples: 5, days: 7 )
121
-
122
- pp stats.history_str ## pp history pretty printed to string (buffer)
123
- end
124
-
125
- end # class TestStats
@@ -1,44 +0,0 @@
1
- ###
2
- # to run use
3
- # ruby -I ./lib -I ./test test/test_stats_tmp.rb
4
-
5
-
6
- require 'helper'
7
-
8
-
9
- class TestStatsTmp < MiniTest::Test
10
-
11
- def setup
12
- @gh = Hubba::Github.new
13
- end
14
-
15
- def test_stats
16
- repos = [
17
- 'poole/hyde',
18
- 'jekyll/minima'
19
- ]
20
-
21
-
22
- repos.each do |repo|
23
- stats = Hubba::Stats.new( repo )
24
-
25
- Hubba.config.data_dir = "#{Hubba.root}/test/stats"
26
- stats.read()
27
-
28
- puts "stars before fetch: #{stats.stars}"
29
- puts "size before fetch: #{stats.size} kb"
30
-
31
- ## note/todo: enable for "live" online testing
32
- ## @gh.update( stats )
33
-
34
- puts "stars after fetch: #{stats.stars}"
35
- puts "size after fetch: #{stats.size} kb"
36
-
37
- Hubba.config.data_dir = './tmp'
38
- stats.write()
39
- end
40
-
41
- assert true # for now everything ok if we get here
42
- end
43
-
44
- end # class TestStatsTmp