qabot 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/dbclasses.rb +499 -0
- data/lib/qabot.rb +249 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1a4a77bc1c0e5d1a1667b935df168d08e7d34e71
|
4
|
+
data.tar.gz: d892ff34caba0b887d45396ac3aa6f49c5e28e21
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 004704ab96d13f2ed72231a711d837be00bea93c7d341fbe5d2dc640d577620cd518e12f595636d7b9ecd55d199d95a297b2257e91062b9b5380d41d20c69579
|
7
|
+
data.tar.gz: dbdff29081158455c92ed69be4ab107869e8744463ee2094d9d14cd303cf0969514c096808bc87f3b71822b26ed4988c98eb836d64b6e918a3ed3101b3d21fbd
|
data/lib/dbclasses.rb
ADDED
@@ -0,0 +1,499 @@
|
|
1
|
+
# sequel class fro the qacategory table
|
2
|
+
module BlackStack
|
3
|
+
class User < Sequel::Model(:user)
|
4
|
+
one_to_many :boolflags, :class=>:'BlackStack::QABot::BoolFlag', :key=>:id_user
|
5
|
+
one_to_many :intflags, :class=>:'BlackStack::QABot::IntFlag', :key=>:id_user
|
6
|
+
one_to_many :floatflags, :class=>:'BlackStack::QABot::FloatFlag', :key=>:id_user
|
7
|
+
one_to_many :categories, :class=>:'BlackStack::QABot::Category', :key=>:id_user
|
8
|
+
|
9
|
+
# return all flags of this user
|
10
|
+
def flags()
|
11
|
+
return self.boolflags + self.intflags + self.floatflags
|
12
|
+
end
|
13
|
+
|
14
|
+
end # class User
|
15
|
+
|
16
|
+
class Client < Sequel::Model(:client)
|
17
|
+
# return all flags of all the users of this client
|
18
|
+
def flags()
|
19
|
+
return self.users.map{|u| u.flags}.flatten
|
20
|
+
end
|
21
|
+
|
22
|
+
# return all categories of all the users of this client
|
23
|
+
def categories()
|
24
|
+
return self.users.map{|u| u.categories}.flatten
|
25
|
+
end
|
26
|
+
|
27
|
+
end # class Client
|
28
|
+
|
29
|
+
module QABot
|
30
|
+
#
|
31
|
+
class Category < Sequel::Model(:qacategory)
|
32
|
+
BlackStack::QABot::Category.dataset = BlackStack::QABot::Category.dataset.disable_insert_output
|
33
|
+
many_to_one :user, :class=>:'BlackStack::User', :key=>:id_user
|
34
|
+
one_to_many :boolflags, :class=>:'BlackStack::BoolFlag', :key=>:id_qacategory
|
35
|
+
one_to_many :intflags, :class=>:'BlackStack::IntFlag', :key=>:id_qacategory
|
36
|
+
one_to_many :floatflags, :class=>:'BlackStack::FloatFlag', :key=>:id_qacategory
|
37
|
+
end # class Category
|
38
|
+
|
39
|
+
#
|
40
|
+
class Alert < Sequel::Model(:qaalert)
|
41
|
+
many_to_one :user, :class=>:'BlackStack::User', :key=>:id_user
|
42
|
+
many_to_one :receiver, :class=>:'BlackStack::User', :key=>:id_receiver
|
43
|
+
|
44
|
+
end # class Alert
|
45
|
+
|
46
|
+
#
|
47
|
+
class BoolFlag < Sequel::Model(:qaboolflag)
|
48
|
+
BlackStack::QABot::BoolFlag.dataset = BlackStack::QABot::BoolFlag.dataset.disable_insert_output
|
49
|
+
include BlackStack::QABot::Flag
|
50
|
+
many_to_one :user, :class=>:'BlackStack::User', :key=>:id_user
|
51
|
+
many_to_one :category, :class=>:'BlackStack::QABot::Category', :key=>:id_category
|
52
|
+
one_to_many :alerts, :class=>:'BlackStack::QABot::Alert', :key=>:id_qaxflag
|
53
|
+
|
54
|
+
# map the attributes of this object to a hash.
|
55
|
+
# add custom elements to the hash: `:up_to_date`, `:last_update_description`
|
56
|
+
# return such a hash.
|
57
|
+
def to_hash()
|
58
|
+
{
|
59
|
+
:id => self.id,
|
60
|
+
:type => BlackStack::QABot::BOOL,
|
61
|
+
:id_qacategory => self.id_qacategory,
|
62
|
+
:create_time => self.create_time,
|
63
|
+
:delete_time => self.delete_time,
|
64
|
+
:id_user => self.id_user,
|
65
|
+
:name => self.name,
|
66
|
+
:html_description => self.html_description,
|
67
|
+
# how often run this qa check - what is the frequency to show the timeline -- ss, mi, hh, mm, dd, qq, yy
|
68
|
+
:trace_frequency_period => self.trace_frequency_period,
|
69
|
+
:trace_frequency_units => self.trace_frequency_units,
|
70
|
+
# show this flag public in the web
|
71
|
+
:public => self.public,
|
72
|
+
# what is the latest value reported
|
73
|
+
:value => self.value,
|
74
|
+
# what is the value to show red (true or false).
|
75
|
+
:trigger_red => self.trigger_red,
|
76
|
+
# each time the value is changed, you can show a comment about the last status.
|
77
|
+
:alert_comments => self.alert_comments,
|
78
|
+
# if it is currently red
|
79
|
+
:stat_red => self.stat_red,
|
80
|
+
# order to show it inside the category, in the dashboard
|
81
|
+
:order => self.order,
|
82
|
+
# sharing this with other people, so other people can add my alert on their dashboards.
|
83
|
+
:share => self.share,
|
84
|
+
# activate this flag to show in the flags column of the dashboard
|
85
|
+
:show_as_flag => self.show_as_flag,
|
86
|
+
# activate tis flag to show in the timelines column of the dashboard
|
87
|
+
:show_as_timeline => self.show_as_timeline,
|
88
|
+
# custom elements
|
89
|
+
:up_to_date => self.up_to_date?,
|
90
|
+
:last_update_description => self.last_update_description,
|
91
|
+
}
|
92
|
+
end # def to_hash()
|
93
|
+
|
94
|
+
# it is red if the `value` is the same than the value assigned to `trigger_red`
|
95
|
+
def is_red?
|
96
|
+
self.value == self.trigger_red
|
97
|
+
end
|
98
|
+
|
99
|
+
# map the attributes of the hash `h` to this object.
|
100
|
+
def parse(h)
|
101
|
+
self.value = h[:value] == true
|
102
|
+
self.value_red = h[:value_red] == true
|
103
|
+
q = "
|
104
|
+
UPDATE qaboolflag
|
105
|
+
SET
|
106
|
+
id_qacategory = '#{h[:id_qacategory]}',
|
107
|
+
--create_time = '#{h[:create_time]}',
|
108
|
+
--delete_time = '#{h[:delete_time]}',
|
109
|
+
id_user = '#{h[:id_user]}',
|
110
|
+
name = '#{h[:name].to_s.to_sql}',
|
111
|
+
html_description = '#{h[:html_description].to_s.to_sql}',
|
112
|
+
-- how often run this qa check - what is the frequency to show the timeline -- ss, mi, hh, mm, dd, qq, yy
|
113
|
+
trace_frequency_period = '#{h[:trace_frequency_period]}',
|
114
|
+
trace_frequency_units = #{h[:trace_frequency_units]},
|
115
|
+
-- show this flag public in the web
|
116
|
+
[public] = #{h[:public] == true ? 1 : 0},
|
117
|
+
-- what is the latest value reported
|
118
|
+
[value] = #{h[:value] == true ? 1 : 0},
|
119
|
+
-- what is the value to show red (true or false). Default value is `false`.
|
120
|
+
trigger_red = #{h[:trigger_red] == true ? 1 : 0},
|
121
|
+
-- each time the value is changed, you can show a comment about the last status.
|
122
|
+
alert_comments = '#{h[:alert_comments].to_s.to_sql}',
|
123
|
+
-- if it is currently red
|
124
|
+
stat_red = #{self.is_red? ? 1 : 0},
|
125
|
+
-- order to show it inside the category, in the dashboard
|
126
|
+
[order] = #{h[:order].to_i},
|
127
|
+
-- sharing this with other people, so other people can add my alert on their dashboards.
|
128
|
+
share = #{h[:share] == true ? 1 : 0},
|
129
|
+
-- activate this flag to show in the flags column of the dashboard
|
130
|
+
show_as_flag = #{h[:show_as_flag] == true ? 1 : 0},
|
131
|
+
-- activate tis flag to show in the timelines column of the dashboard
|
132
|
+
show_as_timeline = #{h[:show_as_timeline] == true ? 1 : 0}
|
133
|
+
WHERE
|
134
|
+
id = '#{h[:id]}'
|
135
|
+
"
|
136
|
+
#puts
|
137
|
+
#puts
|
138
|
+
#puts q
|
139
|
+
#puts
|
140
|
+
#puts
|
141
|
+
DB.execute(q)
|
142
|
+
end # def parse(h)
|
143
|
+
|
144
|
+
# create a new object.
|
145
|
+
# map the attributes of the hash `h` to this object.
|
146
|
+
# return such an object.
|
147
|
+
def self.create(client, h)
|
148
|
+
u = client.users.first # TODO: the email of the user should be included in the hash descriptor, and validate the user exists and is belonging this client.
|
149
|
+
g = client.categories.select { |g| g.name == h[:category] }.first
|
150
|
+
if g.nil?
|
151
|
+
g = BlackStack::QABot::Category.new
|
152
|
+
g.id = guid()
|
153
|
+
g.create_time = now()
|
154
|
+
g.id_user = u.id
|
155
|
+
g.name = h[:category]
|
156
|
+
g.save
|
157
|
+
end # g.nil?
|
158
|
+
o = BlackStack::QABot::BoolFlag.new
|
159
|
+
h[:id] = guid()
|
160
|
+
h[:id_qacategory] = g.id
|
161
|
+
h[:id_user] = u.id
|
162
|
+
h[:create_time] = now()
|
163
|
+
o.parse(h)
|
164
|
+
o
|
165
|
+
end # def create(h)
|
166
|
+
|
167
|
+
# return true if the flag has been updated after `dateadd(#{self.trace_frequency_period}, -#{self.trace_frequency_units}, getdate())`
|
168
|
+
def up_to_date?
|
169
|
+
!DB["
|
170
|
+
select top 1 id
|
171
|
+
from qaboolflagtrace with (nolock)
|
172
|
+
where trace_time > dateadd(#{self.trace_frequency_period}, -#{self.trace_frequency_units}, getdate())
|
173
|
+
and id_qaboolflag = '#{self.id}'
|
174
|
+
"].first.nil?
|
175
|
+
end
|
176
|
+
|
177
|
+
# return a label to describe when this flag has been updated the last time
|
178
|
+
def last_update_description
|
179
|
+
row = DB["
|
180
|
+
select top 1 dbo.fnTimeAgoDescription(trace_time, getdate()) as timeago
|
181
|
+
from qaboolflagtrace with (nolock)
|
182
|
+
where id_qaboolflag = '#{self.id}'
|
183
|
+
order by trace_time desc
|
184
|
+
"].first
|
185
|
+
return !row.nil? ? row[:timeago] : 'never'
|
186
|
+
end
|
187
|
+
end # class BoolFlag
|
188
|
+
|
189
|
+
#
|
190
|
+
class IntFlag < Sequel::Model(:qaintflag)
|
191
|
+
BlackStack::QABot::IntFlag.dataset = BlackStack::QABot::IntFlag.dataset.disable_insert_output
|
192
|
+
include BlackStack::QABot::Flag
|
193
|
+
many_to_one :user, :class=>:'BlackStack::User', :key=>:id_user
|
194
|
+
many_to_one :category, :class=>:'BlackStack::QABot::Category', :key=>:id_category
|
195
|
+
one_to_many :alerts, :class=>:'BlackStack::QABot::Alert', :key=>:id_qaxflag
|
196
|
+
|
197
|
+
# map the attributes of this object to a hash.
|
198
|
+
# add custom elements to the hash: `:up_to_date`, `:last_update_description`
|
199
|
+
# return such a hash.
|
200
|
+
def to_hash()
|
201
|
+
{
|
202
|
+
:id => self.id,
|
203
|
+
:type => BlackStack::QABot::INT,
|
204
|
+
:id_qacategory => self.id_qacategory,
|
205
|
+
:create_time => self.create_time,
|
206
|
+
:delete_time => self.delete_time,
|
207
|
+
:id_user => self.id_user,
|
208
|
+
:name => self.name,
|
209
|
+
:html_description => self.html_description,
|
210
|
+
# how often run this qa check - what is the frequency to show the timeline -- ss, mi, hh, mm, dd, qq, yy
|
211
|
+
:trace_frequency_period => self.trace_frequency_period,
|
212
|
+
:trace_frequency_units => self.trace_frequency_units,
|
213
|
+
# show this flag public in the web
|
214
|
+
:public => self.public,
|
215
|
+
# what is the latest value reported
|
216
|
+
:value => self.value,
|
217
|
+
# what is the value to decide to go green or red.
|
218
|
+
value_threshold => self.value_threshold,
|
219
|
+
# what is the value to show red (true or false).
|
220
|
+
:trigger_red => self.trigger_red,
|
221
|
+
# each time the value is changed, you can show a comment about the last status.
|
222
|
+
:alert_comments => self.alert_comments,
|
223
|
+
# if it is currently red
|
224
|
+
:stat_red => self.stat_red,
|
225
|
+
# order to show it inside the category, in the dashboard
|
226
|
+
:order => self.order,
|
227
|
+
# sharing this with other people, so other people can add my alert on their dashboards.
|
228
|
+
:share => self.share,
|
229
|
+
# activate this flag to show in the flags column of the dashboard
|
230
|
+
:show_as_flag => self.show_as_flag,
|
231
|
+
# activate tis flag to show in the timelines column of the dashboard
|
232
|
+
:show_as_timeline => self.show_as_timeline,
|
233
|
+
# custom elements
|
234
|
+
:up_to_date => self.up_to_date?,
|
235
|
+
:last_update_description => self.last_update_description,
|
236
|
+
}
|
237
|
+
end # def to_hash()
|
238
|
+
|
239
|
+
# it is red if the `value` is the same than the value assigned to `trigger_red`
|
240
|
+
def is_red?
|
241
|
+
if self.trigger_red == BlackStack::QABot::LOWER_OR_EQUAL
|
242
|
+
return self.value <= self.value_threshold
|
243
|
+
elsif self.trigger_red == BlackStack::QABot::LOWER
|
244
|
+
return self.value < self.value_threshold
|
245
|
+
elsif self.trigger_red == BlackStack::QABot::EQUAL
|
246
|
+
return self.value == self.value_threshold
|
247
|
+
elsif self.trigger_red == BlackStack::QABot::GREATER
|
248
|
+
return self.value > self.value_threshold
|
249
|
+
elsif self.trigger_red == BlackStack::QABot::GREATER_OR_EQUAL
|
250
|
+
return self.value >= self.value_threshold
|
251
|
+
else
|
252
|
+
return nil
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# map the attributes of the hash `h` to this object.
|
257
|
+
def parse(h)
|
258
|
+
self.value = h[:value].to_i
|
259
|
+
self.value_threshold = h[:value_threshold].to_i
|
260
|
+
self.value_red = h[:value_red].to_i
|
261
|
+
q = "
|
262
|
+
UPDATE qaboolflag
|
263
|
+
SET
|
264
|
+
id_qacategory = '#{h[:id_qacategory]}',
|
265
|
+
--create_time = '#{h[:create_time]}',
|
266
|
+
--delete_time = '#{h[:delete_time]}',
|
267
|
+
id_user = '#{h[:id_user]}',
|
268
|
+
name = '#{h[:name].to_s.to_sql}',
|
269
|
+
html_description = '#{h[:html_description].to_s.to_sql}',
|
270
|
+
-- how often run this qa check - what is the frequency to show the timeline -- ss, mi, hh, mm, dd, qq, yy
|
271
|
+
trace_frequency_period = '#{h[:trace_frequency_period]}',
|
272
|
+
trace_frequency_units = #{h[:trace_frequency_units]},
|
273
|
+
-- show this flag public in the web
|
274
|
+
[public] = #{h[:public] == true ? 1 : 0},
|
275
|
+
-- what is the latest value reported
|
276
|
+
[value] = #{h[:value].to_i.to_s},
|
277
|
+
-- what is the value to decide to go green or red.
|
278
|
+
value_threshold = #{h[:value_threshold].to_i.to_s},
|
279
|
+
-- what is the value to show red (true or false). Default value is `false`.
|
280
|
+
trigger_red = #{h[:trigger_red].to_i.to_s},
|
281
|
+
-- each time the value is changed, you can show a comment about the last status.
|
282
|
+
alert_comments = '#{h[:alert_comments].to_s.to_sql}',
|
283
|
+
-- if it is currently red
|
284
|
+
stat_red = #{self.is_red? ? 1 : 0},
|
285
|
+
-- order to show it inside the category, in the dashboard
|
286
|
+
[order] = #{h[:order].to_i},
|
287
|
+
-- sharing this with other people, so other people can add my alert on their dashboards.
|
288
|
+
share = #{h[:share] == true ? 1 : 0},
|
289
|
+
-- activate this flag to show in the flags column of the dashboard
|
290
|
+
show_as_flag = #{h[:show_as_flag] == true ? 1 : 0},
|
291
|
+
-- activate tis flag to show in the timelines column of the dashboard
|
292
|
+
show_as_timeline = #{h[:show_as_timeline] == true ? 1 : 0}
|
293
|
+
WHERE
|
294
|
+
id = '#{h[:id]}'
|
295
|
+
"
|
296
|
+
DB.execute(q)
|
297
|
+
end # def parse(h)
|
298
|
+
|
299
|
+
# create a new object.
|
300
|
+
# map the attributes of the hash `h` to this object.
|
301
|
+
# return such an object.
|
302
|
+
def self.create(client, h)
|
303
|
+
u = client.users.first # TODO: the email of the user should be included in the hash descriptor, and validate the user exists and is belonging this client.
|
304
|
+
g = client.categories.select { |g| g.name == h[:category] }.first
|
305
|
+
if g.nil?
|
306
|
+
g = BlackStack::QABot::Category.new
|
307
|
+
g.id = guid()
|
308
|
+
g.create_time = now()
|
309
|
+
g.id_user = u.id
|
310
|
+
g.name = h[:category]
|
311
|
+
g.save
|
312
|
+
end # g.nil?
|
313
|
+
o = BlackStack::QABot::IntFlag.new
|
314
|
+
h[:id] = guid()
|
315
|
+
h[:id_qacategory] = g.id
|
316
|
+
h[:id_user] = u.id
|
317
|
+
h[:create_time] = now()
|
318
|
+
o.parse(h)
|
319
|
+
o
|
320
|
+
end # def parse(h)
|
321
|
+
|
322
|
+
# return true if the flag has been updated after `dateadd(#{self.trace_frequency_period}, -#{self.trace_frequency_units}, getdate())`
|
323
|
+
def up_to_date?
|
324
|
+
!DB["
|
325
|
+
select top 1 id
|
326
|
+
from qaintflagtrace with (nolock)
|
327
|
+
where trace_time > dateadd(#{self.trace_frequency_period}, -#{self.trace_frequency_units}, getdate())
|
328
|
+
and id_qaintflag = '#{self.id}'
|
329
|
+
"].first.nil?
|
330
|
+
end
|
331
|
+
|
332
|
+
# return a label to describe when this flag has been updated the last time
|
333
|
+
def last_update_description
|
334
|
+
row = DB["
|
335
|
+
select top 1 dbo.fnTimeAgoDescription(trace_time, getdate()) as timeago
|
336
|
+
from qaintflagtrace with (nolock)
|
337
|
+
where id_qaintflag = '#{self.id}'
|
338
|
+
order by trace_time desc
|
339
|
+
"].first
|
340
|
+
return !row.nil? ? row[:timeago] : 'never'
|
341
|
+
end
|
342
|
+
end # class IntFlag
|
343
|
+
|
344
|
+
#
|
345
|
+
class FloatFlag < Sequel::Model(:qafloatflag)
|
346
|
+
BlackStack::QABot::FloatFlag.dataset = BlackStack::QABot::FloatFlag.dataset.disable_insert_output
|
347
|
+
include BlackStack::QABot::Flag
|
348
|
+
many_to_one :user, :class=>:'BlackStack::User', :key=>:id_user
|
349
|
+
many_to_one :category, :class=>:'BlackStack::QABot::Category', :key=>:id_category
|
350
|
+
one_to_many :alerts, :class=>:'BlackStack::QABot::Alert', :key=>:id_qaxflag
|
351
|
+
|
352
|
+
# map the attributes of this object to a hash.
|
353
|
+
# add custom elements to the hash: `:up_to_date`, `:last_update_description`
|
354
|
+
# return such a hash.
|
355
|
+
def to_hash()
|
356
|
+
{
|
357
|
+
:id => self.id,
|
358
|
+
:type => BlackStack::QABot::FLOAT,
|
359
|
+
:id_qacategory => self.id_qacategory,
|
360
|
+
:create_time => self.create_time,
|
361
|
+
:delete_time => self.delete_time,
|
362
|
+
:id_user => self.id_user,
|
363
|
+
:name => self.name,
|
364
|
+
:html_description => self.html_description,
|
365
|
+
# how often run this qa check - what is the frequency to show the timeline -- ss, mi, hh, mm, dd, qq, yy
|
366
|
+
:trace_frequency_period => self.trace_frequency_period,
|
367
|
+
:trace_frequency_units => self.trace_frequency_units,
|
368
|
+
# show this flag public in the web
|
369
|
+
:public => self.public,
|
370
|
+
# what is the latest value reported
|
371
|
+
:value => self.value,
|
372
|
+
# what is the value to decide to go green or red.
|
373
|
+
value_threshold => self.value_threshold,
|
374
|
+
# what is the value to show red (true or false).
|
375
|
+
:trigger_red => self.trigger_red,
|
376
|
+
# each time the value is changed, you can show a comment about the last status.
|
377
|
+
:alert_comments => self.alert_comments,
|
378
|
+
# if it is currently red
|
379
|
+
:stat_red => self.stat_red,
|
380
|
+
# order to show it inside the category, in the dashboard
|
381
|
+
:order => self.order,
|
382
|
+
# sharing this with other people, so other people can add my alert on their dashboards.
|
383
|
+
:share => self.share,
|
384
|
+
# activate this flag to show in the flags column of the dashboard
|
385
|
+
:show_as_flag => self.show_as_flag,
|
386
|
+
# activate tis flag to show in the timelines column of the dashboard
|
387
|
+
:show_as_timeline => self.show_as_timeline,
|
388
|
+
# custom elements
|
389
|
+
:up_to_date => self.up_to_date?,
|
390
|
+
:last_update_description => self.last_update_description,
|
391
|
+
}
|
392
|
+
end # def to_hash()
|
393
|
+
|
394
|
+
# it is red if the `value` is the same than the value assigned to `trigger_red`
|
395
|
+
def is_red?
|
396
|
+
if self.trigger_red == BlackStack::QABot::LOWER_OR_EQUAL
|
397
|
+
return self.value <= self.value_threshold
|
398
|
+
elsif self.trigger_red == BlackStack::QABot::LOWER
|
399
|
+
return self.value < self.value_threshold
|
400
|
+
elsif self.trigger_red == BlackStack::QABot::EQUAL
|
401
|
+
return self.value == self.value_threshold
|
402
|
+
elsif self.trigger_red == BlackStack::QABot::GREATER
|
403
|
+
return self.value > self.value_threshold
|
404
|
+
elsif self.trigger_red == BlackStack::QABot::GREATER_OR_EQUAL
|
405
|
+
return self.value >= self.value_threshold
|
406
|
+
else
|
407
|
+
return nil
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
# map the attributes of the hash `h` to this object.
|
412
|
+
def parse(h)
|
413
|
+
self.value = h[:value].to_f
|
414
|
+
self.value_threshold = h[:value_threshold].to_f
|
415
|
+
self.value_red = h[:value_red].to_f
|
416
|
+
q = "
|
417
|
+
UPDATE qaboolflag
|
418
|
+
SET
|
419
|
+
id_qacategory = '#{h[:id_qacategory]}',
|
420
|
+
--create_time = '#{h[:create_time]}',
|
421
|
+
--delete_time = '#{h[:delete_time]}',
|
422
|
+
id_user = '#{h[:id_user]}',
|
423
|
+
name = '#{h[:name].to_s.to_sql}',
|
424
|
+
html_description = '#{h[:html_description].to_s.to_sql}',
|
425
|
+
-- how often run this qa check - what is the frequency to show the timeline -- ss, mi, hh, mm, dd, qq, yy
|
426
|
+
trace_frequency_period = '#{h[:trace_frequency_period]}',
|
427
|
+
trace_frequency_units = #{h[:trace_frequency_units]},
|
428
|
+
-- show this flag public in the web
|
429
|
+
[public] = #{h[:public] == true ? 1 : 0},
|
430
|
+
-- what is the latest value reported
|
431
|
+
[value] = #{h[:value].to_f.to_s},
|
432
|
+
-- what is the value to decide to go green or red.
|
433
|
+
value_threshold = #{h[:value_threshold].to_f.to_s},
|
434
|
+
-- what is the value to show red (true or false). Default value is `false`.
|
435
|
+
trigger_red = #{h[:trigger_red].to_f.to_s},
|
436
|
+
-- each time the value is changed, you can show a comment about the last status.
|
437
|
+
alert_comments = '#{h[:alert_comments].to_s.to_sql}',
|
438
|
+
-- if it is currently red
|
439
|
+
stat_red = #{self.is_red? ? 1 : 0},
|
440
|
+
-- order to show it inside the category, in the dashboard
|
441
|
+
[order] = #{h[:order].to_i},
|
442
|
+
-- sharing this with other people, so other people can add my alert on their dashboards.
|
443
|
+
share = #{h[:share] == true ? 1 : 0},
|
444
|
+
-- activate this flag to show in the flags column of the dashboard
|
445
|
+
show_as_flag = #{h[:show_as_flag] == true ? 1 : 0},
|
446
|
+
-- activate tis flag to show in the timelines column of the dashboard
|
447
|
+
show_as_timeline = #{h[:show_as_timeline] == true ? 1 : 0}
|
448
|
+
WHERE
|
449
|
+
id = '#{h[:id]}'
|
450
|
+
"
|
451
|
+
DB.execute(q)
|
452
|
+
end # def parse(h)
|
453
|
+
|
454
|
+
# create a new object.
|
455
|
+
# map the attributes of the hash `h` to this object.
|
456
|
+
# return such an object.
|
457
|
+
def self.create(h)
|
458
|
+
u = client.users.first # TODO: the email of the user should be included in the hash descriptor, and validate the user exists and is belonging this client.
|
459
|
+
g = client.categories.select { |g| g.name == h[:category] }.first
|
460
|
+
if g.nil?
|
461
|
+
g = BlackStack::QABot::Category.new
|
462
|
+
g.id = guid()
|
463
|
+
g.create_time = now()
|
464
|
+
g.id_user = u.id
|
465
|
+
g.name = h[:category]
|
466
|
+
g.save
|
467
|
+
end # g.nil?
|
468
|
+
o = BlackStack::QABot::FloatFlag.new
|
469
|
+
h[:id] = guid()
|
470
|
+
h[:id_qacategory] = g.id
|
471
|
+
h[:id_user] = u.id
|
472
|
+
h[:create_time] = now()
|
473
|
+
o.parse(h)
|
474
|
+
o
|
475
|
+
end # def parse(h)
|
476
|
+
|
477
|
+
# return true if the flag has been updated after `dateadd(#{self.trace_frequency_period}, -#{self.trace_frequency_units}, getdate())`
|
478
|
+
def up_to_date?
|
479
|
+
!DB["
|
480
|
+
select top 1 id
|
481
|
+
from qafloatflagtrace with (nolock)
|
482
|
+
where trace_time > dateadd(#{self.trace_frequency_period}, -#{self.trace_frequency_units}, getdate())
|
483
|
+
and id_qafloatflag = '#{self.id}'
|
484
|
+
"].first.nil?
|
485
|
+
end
|
486
|
+
|
487
|
+
# return a label to describe when this flag has been updated the last time
|
488
|
+
def last_update_description
|
489
|
+
row = DB["
|
490
|
+
select top 1 dbo.fnTimeAgoDescription(trace_time, getdate()) as timeago
|
491
|
+
from qafloatflagtrace with (nolock)
|
492
|
+
where id_qafloatflag = '#{self.id}'
|
493
|
+
order by trace_time desc
|
494
|
+
"].first
|
495
|
+
return !row.nil? ? row[:timeago] : 'never'
|
496
|
+
end
|
497
|
+
end # class FloatFlag
|
498
|
+
end # module QABot
|
499
|
+
end # module BlackStack
|
data/lib/qabot.rb
ADDED
@@ -0,0 +1,249 @@
|
|
1
|
+
|
2
|
+
# sequel class fro the qacategory table
|
3
|
+
module BlackStack
|
4
|
+
module QABot
|
5
|
+
BOOL = 'bool'
|
6
|
+
INT = 'int'
|
7
|
+
FLOAT = 'float'
|
8
|
+
|
9
|
+
SS = 'ss'
|
10
|
+
MI = 'mi'
|
11
|
+
HH = 'hh'
|
12
|
+
DD = 'dd'
|
13
|
+
WW = 'ww'
|
14
|
+
MM = 'mm'
|
15
|
+
QQ = 'qq'
|
16
|
+
YY = 'yy'
|
17
|
+
|
18
|
+
LOWER_OR_EQUAL = -2
|
19
|
+
LOWER = -1
|
20
|
+
EQUAL = 0
|
21
|
+
GREATER = 1
|
22
|
+
GREATER_OR_EQUAL = 2
|
23
|
+
|
24
|
+
@@flags_descriptors = []
|
25
|
+
|
26
|
+
def self.require_db_classes()
|
27
|
+
# CRM classes
|
28
|
+
require_relative '../lib/dbclasses.rb'
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.flag_descriptors()
|
32
|
+
@@flags_descriptors
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.types()
|
36
|
+
[
|
37
|
+
BlackStack::QABot::BOOL,
|
38
|
+
BlackStack::QABot::INT,
|
39
|
+
BlackStack::QABot::FLOAT,
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.periods()
|
44
|
+
[
|
45
|
+
BlackStack::QABot::SS,
|
46
|
+
BlackStack::QABot::MI,
|
47
|
+
BlackStack::QABot::HH,
|
48
|
+
BlackStack::QABot::DD,
|
49
|
+
BlackStack::QABot::WW,
|
50
|
+
BlackStack::QABot::MM,
|
51
|
+
BlackStack::QABot::QQ,
|
52
|
+
BlackStack::QABot::YY,
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.trigger_red_values()
|
57
|
+
[
|
58
|
+
BlackStack::QABot::LOWER_OR_EQUAL,
|
59
|
+
BlackStack::QABot::LOWER,
|
60
|
+
BlackStack::QABot::EQUAL,
|
61
|
+
BlackStack::QABot::GREATER_OR_EQUAL,
|
62
|
+
BlackStack::QABot::GREATER,
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
66
|
+
# Validate the values of the hash, after executing the `:value_function` procedure
|
67
|
+
def self.validate_descriptor_values(h)
|
68
|
+
errors = []
|
69
|
+
# VALIDATE: if `:type` is `BOOL`, `:value` must be boolean.
|
70
|
+
errors << "`:value` must be boolean" if h[:type] == BlackStack::QABot::BOOL && ![true, false].include?(h[:value])
|
71
|
+
# VALIDATE: if `:type` is `INT`, `:value` must be integer.
|
72
|
+
errors << "`:value` must be integer" if h[:type] == BlackStack::QABot::INT && !h[:value].is_a?(Integer)
|
73
|
+
# VALIDATE: if `:type` is `FLOAT`, `:value` must be float.
|
74
|
+
errors << "`:value` must be float" if h[:type] == BlackStack::QABot::FLOAT && !h[:value].is_a?(Float)
|
75
|
+
# return
|
76
|
+
errors
|
77
|
+
end
|
78
|
+
|
79
|
+
# Validate the values of the hash, prior executing the `:value_function` procedure
|
80
|
+
def self.validate_descriptor_parameters_except_functions(h)
|
81
|
+
errors = []
|
82
|
+
# VALIDATE: the `:type` is a valid value
|
83
|
+
errors << "Invalid type: #{h[:type]}" unless BlackStack::QABot.types().include?(h[:type])
|
84
|
+
# VALIDATE: the ':category' is a string no longer than 500 chars
|
85
|
+
errors << "Invalid category: #{h[:category]}. Must be string lower than 500 chars." unless h[:category].is_a?(String) && h[:category].length <= 500
|
86
|
+
# VALIDATE: the `:name` is a string no longer than 500 chars
|
87
|
+
errors << "Invalid name: #{h[:name]}. Must be string lower than 500 chars." unless h[:name].is_a?(String) && h[:name].length <= 500
|
88
|
+
# VALIDATE: the `:description` is a string no longer than 8000 chars
|
89
|
+
errors << "Invalid description: #{h[:description]}. Must be string lower than 8000 chars." unless h[:description].is_a?(String) && h[:description].length <= 8000
|
90
|
+
# VALIDATE: the ':trace_fraquency_period` is a valid value
|
91
|
+
errors << "Invalid trace_frequency_period: #{h[:trace_frequency_period]}" unless BlackStack::QABot.periods().include?(h[:trace_frequency_period])
|
92
|
+
# VALIDATE: the `:trace_frequency_units` is an integer higher than 0
|
93
|
+
errors << "Invalid trace_frequency_units: #{h[:trace_frequency_units]}. Must be integer higher than 0." unless h[:trace_frequency_units].is_a?(Integer) && h[:trace_frequency_units] > 0
|
94
|
+
# VALIDATE: the `:show_as_flag` is a boolean
|
95
|
+
errors << "Invalid show_as_flag: #{h[:show_as_flag]}. Must be boolean." unless h[:show_as_flag].is_a?(TrueClass) || h[:show_as_flag].is_a?(FalseClass)
|
96
|
+
# VALIDATE: the `:show_as_timeline` is a boolean
|
97
|
+
errors << "Invalid show_as_timeline: #{h[:show_as_timeline]}. Must be boolean." unless h[:show_as_timeline].is_a?(TrueClass) || h[:show_as_timeline].is_a?(FalseClass)
|
98
|
+
# VALIDATE: the `:public` is a boolean
|
99
|
+
errors << "Invalid public: #{h[:public]}. Must be boolean." unless h[:public].is_a?(TrueClass) || h[:public].is_a?(FalseClass)
|
100
|
+
# VALIDATE: the `:share` is a boolean
|
101
|
+
errors << "Invalid share: #{h[:share]}. Must be boolean." unless h[:share].is_a?(TrueClass) || h[:share].is_a?(FalseClass)
|
102
|
+
# VALIDATE: if `:type` is `BOOL`, then `:trigger_red` must be a boolean
|
103
|
+
errors << "Invalid trigger_red: #{h[:trigger_red]}. Must be boolean." if h[:type] == BlackStack::QABot::BOOL && !(h[:trigger_red].is_a?(TrueClass) || h[:trigger_red].is_a?(FalseClass))
|
104
|
+
# VALIDATE: if `:type` is `INT` OR `FLOAT`, then `:trigger_red` must be beloning `trigger_red_values`
|
105
|
+
errors << "Invalid trigger_red: #{h[:trigger_red]}. Must be one of #{trigger_red_values.to_s}" if (h[:type] == BlackStack::QABot::INT || h[:type] == BlackStack::QABot::FLOAT) && !trigger_red_values.include?(h[:trigger_red])
|
106
|
+
# VALIDATE: if `:type` is 'INT', then `:value_threshold` must ba an integer.
|
107
|
+
errors << "Invalid trigger_red: #{h[:value_threshold]}. Must be integer." if h[:type] == BlackStack::QABot::INT && !h[:value_threshold].is_a?(Integer)
|
108
|
+
# VALIDATE: if `:ty[e` is `FLOAT`, then `:trigger_red` must be a float.
|
109
|
+
errors << "Invalid trigger_red: #{h[:value_threshold]}. Must be float." if h[:type] == BlackStack::QABot::FLOAT && !h[:value_threshold].is_a?(Float)
|
110
|
+
# return errors
|
111
|
+
errors
|
112
|
+
end # def self.validate_descriptor_parameters_except_functions
|
113
|
+
|
114
|
+
# return a `flag` object belonging this client, with this name
|
115
|
+
def self.find(client, name)
|
116
|
+
return nil if client.nil? || name.nil?
|
117
|
+
return nil if client.flags.nil?
|
118
|
+
client.flags.each do |flag|
|
119
|
+
return flag if flag.name == name
|
120
|
+
end
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
|
124
|
+
# return `true` if exists a flag belonging this client, with this name
|
125
|
+
def self.exists?(client, name)
|
126
|
+
!BlackStack::QABot::find(client, name).nil?
|
127
|
+
end
|
128
|
+
|
129
|
+
# create a new flag belonging this client, with this name
|
130
|
+
def self.create(client, h)
|
131
|
+
o = nil
|
132
|
+
o = BlackStack::QABot::BoolFlag.create(client, h) if h[:type] == BlackStack::QABot::BOOL
|
133
|
+
o = BlackStack::QABot::IntFlag.create(client, h) if h[:type] == BlackStack::QABot::INT
|
134
|
+
o = BlackStack::QABot::FloatFlag.create(client, h) if h[:type] == BlackStack::QABot::FLOAT
|
135
|
+
o
|
136
|
+
end # def self.create
|
137
|
+
|
138
|
+
# update the flag belonging this client, with this name, with the values in the hash descriptor
|
139
|
+
def self.parse(client, h)
|
140
|
+
o = BlackStack::QABot::find(client, h[:name])
|
141
|
+
return nil if o.nil?
|
142
|
+
h[:id] = o.id
|
143
|
+
|
144
|
+
g = client.categories.select { |g| g.name == h[:category] }.first
|
145
|
+
if g.nil?
|
146
|
+
g = BlackStack::QABot::Category.new
|
147
|
+
g.id = guid()
|
148
|
+
g.create_time = now()
|
149
|
+
g.id_user = u.id
|
150
|
+
g.name = h[:category]
|
151
|
+
g.save
|
152
|
+
end # g.nil?
|
153
|
+
h[:id_qacategory] = g.id
|
154
|
+
h[:id_user] = client.users.first.id # TODO: I should receive the email of the email in the hash descriptor, and validate the email is belonging the client.
|
155
|
+
h[:html_description] = h[:description]
|
156
|
+
o.parse(h)
|
157
|
+
o
|
158
|
+
end # def self.parse
|
159
|
+
|
160
|
+
# return `true` if exists a flag belonging this client, with this name
|
161
|
+
def self.exists_by_id?(client, id)
|
162
|
+
return false if client.nil? || id.nil?
|
163
|
+
return false if client.flags.nil?
|
164
|
+
client.flags.each do |flag|
|
165
|
+
return true if flag.id == id
|
166
|
+
end
|
167
|
+
false
|
168
|
+
end
|
169
|
+
|
170
|
+
# return `true` if exists a flag belonging this client, with this name
|
171
|
+
def self.exists_by_id_and_name?(client, id, name)
|
172
|
+
return false if client.nil? || id.nil? || name.nil?
|
173
|
+
return false if client.flags.nil?
|
174
|
+
client.flags.each do |flag|
|
175
|
+
return true if flag.id == id && flag.name == name
|
176
|
+
end
|
177
|
+
false
|
178
|
+
end
|
179
|
+
|
180
|
+
# return `true` if exists a flag belonging this client, with this name
|
181
|
+
def self.exists_by_name?(client, name)
|
182
|
+
return false if client.nil? || name.nil?
|
183
|
+
return false if client.flags.nil?
|
184
|
+
client.flags.each do |flag|
|
185
|
+
return true if flag.name == name
|
186
|
+
end
|
187
|
+
false
|
188
|
+
end
|
189
|
+
|
190
|
+
# return `true` if exists a flag belonging this client, with this name
|
191
|
+
def self.exists_by_name_and_id?(client, name, id)
|
192
|
+
return false if client.nil? || name.nil? || id.nil?
|
193
|
+
return false if client.flags.nil?
|
194
|
+
client.flags.each do |flag|
|
195
|
+
return true if flag.name == name && flag.id == id
|
196
|
+
end
|
197
|
+
false
|
198
|
+
end
|
199
|
+
|
200
|
+
#
|
201
|
+
def self.add_flag(h)
|
202
|
+
# get the errors on all parameters except functions
|
203
|
+
errors = BlackStack::QABot::validate_descriptor_parameters_except_functions(h)
|
204
|
+
# VALIDATE: the `:value_function` is a procedure
|
205
|
+
errors << "Invalid value_function. Must be procedure." unless h[:value_function].is_a?(Proc)
|
206
|
+
# VALIDATE: the `:alert_comments_function` is a procedure
|
207
|
+
errors << "Invalid alert_comments_function. Must be procedure." unless h[:alert_comments_function].is_a?(Proc)
|
208
|
+
# raise an exception if `errors` has any element
|
209
|
+
raise errors.join("\n") if errors.length > 0
|
210
|
+
# add `h` to `@@flags_descriptors`
|
211
|
+
@@flags_descriptors << h
|
212
|
+
# return the array
|
213
|
+
@@flags_descriptors
|
214
|
+
end # def self.add_flag
|
215
|
+
|
216
|
+
def self.run_all()
|
217
|
+
@@flags_descriptors.each do |h|
|
218
|
+
BlackStack::QABot.run(h)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def self.run(h)
|
223
|
+
h[:value] = h[:value_function].call()
|
224
|
+
h[:alert_comments] = h[:alert_comments_function].call()
|
225
|
+
BlackStack::QABot::Flag.push(h)
|
226
|
+
end
|
227
|
+
|
228
|
+
# this module contains methods that are commons to any kind flags
|
229
|
+
module Flag
|
230
|
+
# return true of the latest trace is `stat_red==true`, and the previous trace is `stat_red==false`.
|
231
|
+
def should_alert?
|
232
|
+
# TODO: Code Me!
|
233
|
+
false
|
234
|
+
end # def should_alert?
|
235
|
+
|
236
|
+
# send an email notification to all the receivers of this flag.
|
237
|
+
def alert()
|
238
|
+
# TODO: Code Me!
|
239
|
+
end # def alert()
|
240
|
+
|
241
|
+
# submit a flag descriptor to the server, via REST-API.
|
242
|
+
def self.push(h)
|
243
|
+
url = "#{BlackStack::Pampa::api_url}/api.1.1.0/qabot/push.json"
|
244
|
+
api_key = BlackStack::Pampa::api_key
|
245
|
+
BlackStack::Netting::api_call( url, {:api_key => api_key}.merge(h) )
|
246
|
+
end
|
247
|
+
end # module Flag
|
248
|
+
end # module QABot
|
249
|
+
end # module BlackStack
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: qabot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leandro Daniel Sardi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-04-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.8.1
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.8.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.8.1
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.8.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: tiny_tds
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.0.5
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.0.5
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.0.5
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.0.5
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: sequel
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 4.28.0
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 4.28.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 4.28.0
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 4.28.0
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: pampa_workers
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 1.1.36
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.1.36
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.1.36
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.1.36
|
93
|
+
description: 'THIS GEM IS STILL IN DEVELOPMENT STAGE. Find documentation here: https://github.com/leandrosardi/pampa_dispatcher.'
|
94
|
+
email: leandro.sardi@expandedventure.com
|
95
|
+
executables: []
|
96
|
+
extensions: []
|
97
|
+
extra_rdoc_files: []
|
98
|
+
files:
|
99
|
+
- lib/dbclasses.rb
|
100
|
+
- lib/qabot.rb
|
101
|
+
homepage: https://rubygems.org/gems/pampa_deployer
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.4.5.1
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: THIS GEM IS STILL IN DEVELOPMENT STAGE. Distribute work along a pool of Pampa
|
125
|
+
workers.
|
126
|
+
test_files: []
|