580023a60b9068b1c6804e6e87d239fb2ca4bf3a
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Statistics about the Game.
19 # This module uses `GameReactor` to extract statistics about the game from
20 # triggered `Github::Event`.
27 redef class GameEntity
29 # Statistics manager for this entity.
30 fun stats
: GameStatsManager is abstract
35 redef var stats
is lazy
do return new GameStatsManager(game
, self)
39 stats
.save_in
(self.key
)
43 var res
= new FlatBuffer
45 res
.append
"# stats:\n"
46 res
.append stats
.pretty
47 return res
.write_to_string
53 redef var stats
is lazy
do return new GameStatsManager(game
, self)
57 stats
.save_in
(self.key
)
61 var res
= new FlatBuffer
63 res
.append
"# stats:\n"
64 res
.append stats
.pretty
65 return res
.write_to_string
69 # Store game stats for defined period.
70 class GameStatsManager
76 # The GameEntity monitored by these statistics.
79 redef var key
= "stats"
81 # Returns the `GameStats` instance for the overall statistics.
82 var overall
: GameStats is lazy
do
83 return load_stats_for
("all")
86 # Returns the `GameStats` instance for the current year statistics.
87 var yearly
: GameStats is lazy
do
88 var date
= new Tm.gmtime
89 var key
= date
.strftime
("%Y")
90 return load_stats_for
(key
)
93 # Returns the `GameStats` instance for the current month statistics.
94 var monthly
: GameStats is lazy
do
95 var date
= new Tm.gmtime
96 var key
= date
.strftime
("%Y-%m")
97 return load_stats_for
(key
)
100 # Returns the `GameStats` instance for the current day statistics.
101 var daily
: GameStats is lazy
do
102 var date
= new Tm.gmtime
103 var key
= date
.strftime
("%Y-%m-%d")
104 return load_stats_for
(key
)
107 # Returns the `GameStats` instance for the current week statistics.
108 var weekly
: GameStats is lazy
do
109 var date
= new Tm.gmtime
110 var key
= date
.strftime
("%Y-W%U")
111 return load_stats_for
(key
)
114 # Load statistics for a `period` key.
115 fun load_stats_for
(period
: String): GameStats do
116 var key
= owner
.key
/ self.key
/ period
117 if not game
.store
.has_key
(key
) then
118 return new GameStats(game
, period
)
120 var json
= game
.store
.load_object
(key
)
121 return new GameStats.from_json
(game
, period
, json
)
124 redef fun [](key
) do return overall
[key
]
126 redef fun []=(key
, value
) do
150 redef fun save_in
(key
) do
151 overall
.save_in
(key
/ self.key
)
152 yearly
.save_in
(key
/ self.key
)
153 monthly
.save_in
(key
/ self.key
)
154 daily
.save_in
(key
/ self.key
)
155 weekly
.save_in
(key
/ self.key
)
158 redef fun pretty
do return overall
.pretty
161 # Game statistics structure that can be saved as a `GameEntity`.
164 super Counter[String]
168 # The pedriod these stats are about.
171 redef fun key
do return period
173 # Load `self` from saved data.
174 init from_json
(game
: Game, period
: String, json
: JsonObject) do
175 for k
, v
in json
do self[k
] = v
.as(Int)
179 var obj
= new JsonObject
180 for k
, v
in self do obj
[k
] = v
185 var res
= new FlatBuffer
187 res
.append
"# {v} {k}\n"
189 return res
.write_to_string
193 # `GameReactor` that computes statistics about the game.
194 class StatisticsReactor
197 redef fun react_event
(game
, e
) do e
.react_stats_event
(game
)
200 redef class GithubEvent
201 # Reacts to a statistics related event.
203 # Called by `StatisticsReactor::react_event`.
205 private fun react_stats_event
(game
: Game) do end
208 redef class IssuesEvent
210 # Count opened and closed issues.
211 redef fun react_stats_event
(game
) do
212 var player
= issue
.user
.player
(game
)
213 if action
== "opened" then
214 game
.stats
.inc
("issues")
215 game
.stats
.inc
("issues_open")
217 player
.stats
.inc
("issues")
218 player
.stats
.inc
("issues_open")
220 else if action
== "reopened" then
221 game
.stats
.inc
("issues_open")
223 player
.stats
.inc
("issues_open")
225 else if action
== "closed" then
226 game
.stats
.dec
("issues_open")
228 player
.stats
.dec
("issues_open")
234 redef class PullRequestEvent
236 # Count opened and closed pull requests.
237 redef fun react_stats_event
(game
) do
238 var player
= pull
.user
.player
(game
)
239 if action
== "opened" then
240 game
.stats
.inc
("pulls")
241 game
.stats
.inc
("pulls_open")
243 player
.stats
.inc
("pulls")
244 player
.stats
.inc
("pulls_open")
246 else if action
== "reopened" then
247 game
.stats
.inc
("pulls_open")
249 player
.stats
.inc
("pulls_open")
251 else if action
== "closed" then
252 game
.stats
.dec
("pulls_open")
253 player
.stats
.dec
("pulls_open")
255 game
.stats
["commits"] += pull
.commits
256 player
.stats
["commits"] += pull
.commits
264 redef class IssueCommentEvent
266 # Count posted comments
267 redef fun react_stats_event
(game
) do
268 if action
== "created" then
269 var player
= comment
.user
.player
(game
)
270 game
.stats
.inc
("comments")
271 player
.stats
.inc
("comments")
272 # FIXME use a more precise way to locate reviews
273 if comment
.has_ok_review
then
274 game
.stats
.inc
("reviews")
275 player
.stats
.inc
("reviews")
283 redef class IssueComment
284 # Does this comment contain a "+1"?
285 fun has_ok_review
: Bool do return body
.has
("\\+1\\b".to_re
)