contrib/nitrpg: move logging to `listener`
[nit.git] / contrib / nitrpg / src / statistics.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Statistics about the Game.
18 #
19 # This module uses `GameReactor` to extract statistics about the game from
20 # triggered `Github::Event`.
21 module statistics
22
23 import game
24 import github::hooks
25 import counter
26
27 redef class GameEntity
28
29 # Load statistics for this `MEntity` if any.
30 fun load_statistics: nullable GameStats do
31 var key = self.key / "statistics"
32 if not game.store.has_key(key) then return null
33 var json = game.store.load_object(key)
34 return new GameStats.from_json(game, json)
35 end
36
37 # Save statistics under this `MEntity`.
38 fun save_statistics(stats: GameStats) do
39 game.store.store_object(key / stats.key, stats.to_json)
40 end
41 end
42
43 redef class Game
44
45 # Statistics for this game instance.
46 var stats: GameStats is lazy do
47 return load_statistics or else new GameStats(game)
48 end
49
50 redef fun save do
51 super
52 save_statistics(stats)
53 end
54
55 redef fun pretty do
56 var res = new FlatBuffer
57 res.append super
58 res.append "# stats:\n"
59 res.append stats.pretty
60 return res.write_to_string
61 end
62 end
63
64 redef class Player
65
66 # Statistics for this player.
67 var stats: GameStats is lazy do
68 return load_statistics or else new GameStats(game)
69 end
70
71 redef fun save do
72 super
73 save_statistics(stats)
74 end
75
76 redef fun pretty do
77 var res = new FlatBuffer
78 res.append super
79 res.append "# stats:\n"
80 res.append stats.pretty
81 return res.write_to_string
82 end
83 end
84
85 # Game statistics structure that can be saved as a `GameEntity`.
86 class GameStats
87 super GameEntity
88 super Counter[String]
89
90 redef var game
91
92 redef var key = "statistics"
93
94 # Load `self` from saved data
95 init from_json(game: Game, json: JsonObject) do
96 self.game = game
97 for k, v in json do self[k] = v.as(Int)
98 end
99
100 redef fun to_json do
101 var obj = new JsonObject
102 for k, v in self do obj[k] = v
103 return obj
104 end
105
106 # Decrements the value of `key` statistic entry by 1.
107 fun dec(key: String) do
108 if not has_key(key) then
109 self[key] = 0
110 else
111 self[key] -= 1
112 end
113 end
114
115 redef fun pretty do
116 var res = new FlatBuffer
117 for k, v in self do
118 res.append "# {v} {k}\n"
119 end
120 return res.write_to_string
121 end
122 end
123
124 # `GameReactor` that computes statistics about the game.
125 class StatisticsReactor
126 super GameReactor
127
128 redef fun react_event(game, e) do
129 e.react_stats_event(game)
130 end
131 end
132
133 redef class GithubEvent
134 # Reacts to a statistics related event.
135 #
136 # Called by `StatisticsReactor::react_event`.
137 # No-op by default.
138 private fun react_stats_event(game: Game) do end
139 end
140
141 redef class IssuesEvent
142
143 # Count opened and closed issues.
144 redef fun react_stats_event(game) do
145 var player = issue.user.player(game)
146 if action == "opened" then
147 game.stats.inc("issues")
148 game.stats.inc("issues_open")
149 game.save
150 player.stats.inc("issues")
151 player.stats.inc("issues_open")
152 player.save
153 else if action == "reopened" then
154 game.stats.inc("issues_open")
155 game.save
156 player.stats.inc("issues_open")
157 player.save
158 else if action == "closed" then
159 game.stats.dec("issues_open")
160 game.save
161 player.stats.dec("issues_open")
162 player.save
163 end
164 end
165 end
166
167 redef class PullRequestEvent
168
169 # Count opened and closed pull requests.
170 redef fun react_stats_event(game) do
171 var player = pull.user.player(game)
172 if action == "opened" then
173 game.stats.inc("pulls")
174 game.stats.inc("pulls_open")
175 game.save
176 player.stats.inc("pulls")
177 player.stats.inc("pulls_open")
178 player.save
179 else if action == "reopened" then
180 game.stats.inc("pulls_open")
181 game.save
182 player.stats.inc("pulls_open")
183 player.save
184 else if action == "closed" then
185 game.stats.dec("pulls_open")
186 player.stats.dec("pulls_open")
187 if pull.merged then
188 game.stats["commits"] += pull.commits
189 player.stats["commits"] += pull.commits
190 end
191 game.save
192 player.save
193 end
194 end
195 end