kashi 0.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +117 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/kashi +4 -0
- data/kashi.gemspec +31 -0
- data/lib/kashi/cli.rb +70 -0
- data/lib/kashi/client.rb +229 -0
- data/lib/kashi/client_wrapper.rb +17 -0
- data/lib/kashi/converter.rb +21 -0
- data/lib/kashi/dsl/cake.rb +49 -0
- data/lib/kashi/dsl/contact_group.rb +125 -0
- data/lib/kashi/dsl/test.rb +275 -0
- data/lib/kashi/dsl.rb +54 -0
- data/lib/kashi/ext/string-ext.rb +9 -0
- data/lib/kashi/output_test.erb +89 -0
- data/lib/kashi/utils.rb +52 -0
- data/lib/kashi/version.rb +3 -0
- data/lib/kashi.rb +15 -0
- metadata +163 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'kashi/utils'
|
2
|
+
require 'kashi/client_wrapper'
|
3
|
+
|
4
|
+
module Kashi
|
5
|
+
class DSL
|
6
|
+
class ContactGroup
|
7
|
+
attr_reader :result
|
8
|
+
|
9
|
+
class Result
|
10
|
+
PARAMS = %i/ContactID GroupName DesktopAlert Email Boxcar Pushover PingURL Mobile/
|
11
|
+
ATTRIBUTES = %i/contact_id group_name desktop_alert email boxcar pushover ping_url mobile/
|
12
|
+
attr_accessor *ATTRIBUTES
|
13
|
+
|
14
|
+
def initialize(context)
|
15
|
+
@context = context
|
16
|
+
@options = context.options
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h
|
20
|
+
Hash[ATTRIBUTES.sort.map { |name| [name, public_send(name)] }]
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_params
|
24
|
+
hash = modify_params
|
25
|
+
hash.delete(:ContactID)
|
26
|
+
hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def modify_params
|
30
|
+
hash = to_h.select { |k, _| ATTRIBUTES.include?(k) }
|
31
|
+
ATTRIBUTES.zip(PARAMS).each do |from, to|
|
32
|
+
hash[to] = hash.delete(from)
|
33
|
+
end
|
34
|
+
hash[:Email] = Array(hash[:Email]).join(',')
|
35
|
+
hash
|
36
|
+
end
|
37
|
+
|
38
|
+
def create
|
39
|
+
Kashi.logger.info("Create ContactGroup `#{group_name}`")
|
40
|
+
Kashi.logger.debug(create_params)
|
41
|
+
return { 'Success' => true } if @options[:dry_run]
|
42
|
+
|
43
|
+
client.contactgroups_update(create_params)
|
44
|
+
end
|
45
|
+
|
46
|
+
def cake(sc_contact_group)
|
47
|
+
@sc_contact_group = sc_contact_group
|
48
|
+
self.contact_id = sc_contact_group['ContactID']
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def dsl_hash
|
53
|
+
Kashi::Utils.normalize_hash(to_h)
|
54
|
+
end
|
55
|
+
|
56
|
+
def sc_hash
|
57
|
+
hash = @sc_contact_group.to_h.keys.each_with_object({}) do |k, h|
|
58
|
+
h[k.to_s.to_snake.to_sym] = @sc_contact_group.to_h[k]
|
59
|
+
end
|
60
|
+
{ emails: :email, mobiles: :mobile }.each do |k, v|
|
61
|
+
hash[v] = hash.delete(k)
|
62
|
+
end
|
63
|
+
Kashi::Utils.normalize_hash(hash)
|
64
|
+
end
|
65
|
+
|
66
|
+
def updated?
|
67
|
+
dsl_hash != sc_hash
|
68
|
+
end
|
69
|
+
|
70
|
+
def modify
|
71
|
+
return unless updated?
|
72
|
+
Kashi.logger.info("Modify ContactGroup `#{group_name}` #{contact_id}")
|
73
|
+
Kashi.logger.info("<diff>\n#{Kashi::Utils.diff(sc_hash, dsl_hash, color: @options[:color])}")
|
74
|
+
Kashi.logger.debug(modify_params)
|
75
|
+
return if @options[:dry_run]
|
76
|
+
|
77
|
+
client.contactgroups_update(modify_params)
|
78
|
+
end
|
79
|
+
|
80
|
+
def client
|
81
|
+
@client ||= ClientWrapper.new(@options)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize(context, contact_id, &block)
|
86
|
+
@context = context.merge(contact_id: contact_id)
|
87
|
+
|
88
|
+
@result = Result.new(@context)
|
89
|
+
@result.contact_id = contact_id
|
90
|
+
|
91
|
+
instance_eval(&block)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def group_name(name)
|
97
|
+
@result.group_name = name
|
98
|
+
end
|
99
|
+
|
100
|
+
def desktop_alert(alert)
|
101
|
+
@result.desktop_alert = alert
|
102
|
+
end
|
103
|
+
|
104
|
+
def email(email)
|
105
|
+
@result.email = Array(email)
|
106
|
+
end
|
107
|
+
|
108
|
+
def boxcar(boxcar)
|
109
|
+
@result.boxcar = boxcar
|
110
|
+
end
|
111
|
+
|
112
|
+
def pushover(pushover)
|
113
|
+
@result.pushover = pushover
|
114
|
+
end
|
115
|
+
|
116
|
+
def ping_url(url)
|
117
|
+
@result.ping_url = url
|
118
|
+
end
|
119
|
+
|
120
|
+
def mobile(mobile)
|
121
|
+
@result.mobile = mobile
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Kashi
|
4
|
+
class DSL
|
5
|
+
class Test
|
6
|
+
class Result
|
7
|
+
PARAMS = %i/
|
8
|
+
TestID Paused WebsiteName WebsiteURL Port NodeLocations Timeout CustomHeader Confirmation CheckRate
|
9
|
+
DNSServer DNSIP BasicUser BasicPass LogoImage UseJar WebsiteHost Virus FindString DoNotFind
|
10
|
+
TestType ContactGroup TriggerRate TestTags StatusCodes EnableSSLWarning FollowRedirect
|
11
|
+
/ # PingURL RealBrowser Public Branding
|
12
|
+
ATTRIBUTES = %i/
|
13
|
+
test_id paused website_name website_url port node_locations timeout custom_header confirmation check_rate
|
14
|
+
dns_server dns_ip basic_user basic_pass logo_image use_jar website_host virus find_string do_not_find
|
15
|
+
test_type contact_group trigger_rate test_tags status_codes enable_ssl_warning follow_redirect
|
16
|
+
/ # ping_url real_browser public branding
|
17
|
+
attr_accessor *ATTRIBUTES
|
18
|
+
|
19
|
+
def initialize(context)
|
20
|
+
@context = context
|
21
|
+
@options = context.options
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_h
|
25
|
+
Hash[ATTRIBUTES.sort.map { |name| [name, public_send(name)] }]
|
26
|
+
end
|
27
|
+
|
28
|
+
def modify_params
|
29
|
+
hash = to_h.select { |k, _| ATTRIBUTES.include?(k) }
|
30
|
+
ATTRIBUTES.zip(PARAMS).each do |from, to|
|
31
|
+
hash[to] = hash.delete(from)
|
32
|
+
end
|
33
|
+
%i/NodeLocations TestTags StatusCodes/.each do |k|
|
34
|
+
hash[k] = Array(hash[k]).join(',')
|
35
|
+
end
|
36
|
+
contact_group_id_by_group_name = client.contactgroups.each_with_object({}) do |contact_group, h|
|
37
|
+
h[contact_group['GroupName']] = contact_group['ContactID']
|
38
|
+
end
|
39
|
+
hash[:ContactGroup] = contact_group.map { |name|
|
40
|
+
contact_group_id_by_group_name[name]
|
41
|
+
}.compact.join(',')
|
42
|
+
hash
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_params
|
46
|
+
hash = modify_params
|
47
|
+
hash.delete(:TestID)
|
48
|
+
hash
|
49
|
+
end
|
50
|
+
|
51
|
+
def create
|
52
|
+
Kashi.logger.info("Create Test `#{website_name}`")
|
53
|
+
Kashi.logger.debug(create_params)
|
54
|
+
return { 'Success' => true } if @options[:dry_run]
|
55
|
+
|
56
|
+
client.tests_update(create_params)
|
57
|
+
end
|
58
|
+
|
59
|
+
def cake(sc_test)
|
60
|
+
@sc_test = sc_test
|
61
|
+
self.test_id = sc_test['TestID']
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def dsl_hash
|
66
|
+
Kashi::Utils.normalize_hash(to_h)
|
67
|
+
end
|
68
|
+
|
69
|
+
def sc_hash
|
70
|
+
hash = @sc_test.to_h.keys.each_with_object({}) do |k, h|
|
71
|
+
next if %w/DownTimes LastTested NextLocation Processing ProcessingOn ProcessingState Sensitive Status Uptime Method ContactGroup ContactID/.include?(k)
|
72
|
+
h[k.to_s.to_snake.to_sym] = @sc_test.to_h[k]
|
73
|
+
end
|
74
|
+
# rename
|
75
|
+
{ uri: :website_url, dnsip: :dns_ip, tags: :test_tags }.each do |k, v|
|
76
|
+
hash[v] = hash.delete(k)
|
77
|
+
end
|
78
|
+
%i/basic_user basic_pass/.each do |k|
|
79
|
+
hash[k] = ''
|
80
|
+
end
|
81
|
+
%i/port use_jar virus/.each do |k|
|
82
|
+
hash[k] = '' unless hash.key?(k)
|
83
|
+
end
|
84
|
+
%i/paused enable_ssl_warning follow_redirect do_not_find/.each do |k|
|
85
|
+
hash[k] = hash[k] ? 1 : 0
|
86
|
+
end
|
87
|
+
hash[:contact_group] = hash.delete(:contact_groups).map { |contact_group| contact_group['Name'] }
|
88
|
+
hash[:test_tags] = Array(hash[:test_tags])
|
89
|
+
if hash[:custom_header] == false || hash[:custom_header] == ''
|
90
|
+
hash[:custom_header] = ''
|
91
|
+
else
|
92
|
+
hash[:custom_header] = JSON.parse(hash[:custom_header]).to_json
|
93
|
+
end
|
94
|
+
Kashi::Utils.normalize_hash(hash)
|
95
|
+
end
|
96
|
+
|
97
|
+
def updated?
|
98
|
+
dsl_hash != sc_hash
|
99
|
+
end
|
100
|
+
|
101
|
+
def modify
|
102
|
+
return unless updated?
|
103
|
+
Kashi.logger.info("Modify Test `#{website_name}` #{test_id}")
|
104
|
+
Kashi.logger.info("<diff>\n#{Kashi::Utils.diff(sc_hash, dsl_hash, color: @options[:color])}")
|
105
|
+
Kashi.logger.debug(modify_params)
|
106
|
+
return if @options[:dry_run]
|
107
|
+
|
108
|
+
client.tests_update(modify_params)
|
109
|
+
end
|
110
|
+
|
111
|
+
def client
|
112
|
+
@client ||= ClientWrapper.new(@options)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
attr_reader :result
|
117
|
+
|
118
|
+
def initialize(context, test_id, &block)
|
119
|
+
@context = context.merge(test_id: test_id)
|
120
|
+
|
121
|
+
@result = Result.new(@context)
|
122
|
+
@result.test_id = test_id
|
123
|
+
|
124
|
+
# default values
|
125
|
+
@result.paused = 0
|
126
|
+
@result.timeout = 30
|
127
|
+
@result.confirmation = 0
|
128
|
+
@result.check_rate = 300
|
129
|
+
# @result.public = 0
|
130
|
+
# @result.use_jar = 0
|
131
|
+
# @result.branding = 0
|
132
|
+
@result.do_not_find = 0
|
133
|
+
# @result.real_browser = 0
|
134
|
+
@result.trigger_rate = 5
|
135
|
+
@result.enable_ssl_warning = 1
|
136
|
+
@result.follow_redirect = 1
|
137
|
+
@result.test_tags = []
|
138
|
+
@result.node_locations = ['']
|
139
|
+
@result.status_codes = []
|
140
|
+
@result.virus = ''
|
141
|
+
|
142
|
+
instance_eval(&block)
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def paused(paused)
|
148
|
+
@result.paused = paused
|
149
|
+
end
|
150
|
+
|
151
|
+
def website_url(url)
|
152
|
+
@result.website_url = url
|
153
|
+
end
|
154
|
+
|
155
|
+
def website_name(name)
|
156
|
+
@result.website_name = name
|
157
|
+
end
|
158
|
+
|
159
|
+
def port(port)
|
160
|
+
@result.port = port
|
161
|
+
end
|
162
|
+
|
163
|
+
# def ping_url(url)
|
164
|
+
# @result.ping_url = url
|
165
|
+
# end
|
166
|
+
|
167
|
+
def custom_header(header)
|
168
|
+
if header == '' || header == nil
|
169
|
+
@result.custom_header = ''
|
170
|
+
else
|
171
|
+
@result.custom_header = header.to_json
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def confirmation(confirmation)
|
176
|
+
@result.confirmation = confirmation
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_type(type)
|
180
|
+
@result.test_type = type
|
181
|
+
end
|
182
|
+
|
183
|
+
def contact_group(groups)
|
184
|
+
@result.contact_group = Array(groups)
|
185
|
+
end
|
186
|
+
|
187
|
+
def check_rate(rate)
|
188
|
+
@result.check_rate = rate
|
189
|
+
end
|
190
|
+
|
191
|
+
def timeout(timeout)
|
192
|
+
@result.timeout = timeout
|
193
|
+
end
|
194
|
+
|
195
|
+
def website_host(host)
|
196
|
+
@result.website_host = host
|
197
|
+
end
|
198
|
+
|
199
|
+
def node_locations(locations)
|
200
|
+
@result.node_locations = locations
|
201
|
+
end
|
202
|
+
|
203
|
+
def find_string(str)
|
204
|
+
@result.find_string = str
|
205
|
+
end
|
206
|
+
|
207
|
+
def do_not_find(do_not_find)
|
208
|
+
@result.do_not_find = do_not_find
|
209
|
+
end
|
210
|
+
|
211
|
+
def basic_user(user)
|
212
|
+
@result.basic_user = user
|
213
|
+
end
|
214
|
+
|
215
|
+
def basic_pass(pass)
|
216
|
+
@result.basic_pass = pass
|
217
|
+
end
|
218
|
+
|
219
|
+
# def public(pub)
|
220
|
+
# @result.public = pub
|
221
|
+
# end
|
222
|
+
|
223
|
+
def logo_image(logo)
|
224
|
+
@result.logo_image = logo
|
225
|
+
end
|
226
|
+
|
227
|
+
def use_jar(use_jar)
|
228
|
+
@result.use_jar = use_jar
|
229
|
+
end
|
230
|
+
|
231
|
+
# def branding(branding)
|
232
|
+
# @result.branding = branding
|
233
|
+
# end
|
234
|
+
|
235
|
+
def virus(virus)
|
236
|
+
@result.virus = virus
|
237
|
+
end
|
238
|
+
|
239
|
+
# def real_browser(real_browser)
|
240
|
+
# @result.real_browser = real_browser
|
241
|
+
# end
|
242
|
+
|
243
|
+
def dns_server(dns_server)
|
244
|
+
@result.dns_server = dns_server
|
245
|
+
end
|
246
|
+
|
247
|
+
def dns_ip(ip)
|
248
|
+
@result.dns_ip = ip
|
249
|
+
end
|
250
|
+
|
251
|
+
def trigger_rate(rate)
|
252
|
+
@result.trigger_rate = rate
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_tags(tags)
|
256
|
+
if tags == nil
|
257
|
+
@result.test_tags = []
|
258
|
+
end
|
259
|
+
@result.test_tags = Array(tags)
|
260
|
+
end
|
261
|
+
|
262
|
+
def status_codes(codes)
|
263
|
+
@result.status_codes = codes
|
264
|
+
end
|
265
|
+
|
266
|
+
def enable_ssl_warning(enable_ssl_warning)
|
267
|
+
@result.enable_ssl_warning = enable_ssl_warning
|
268
|
+
end
|
269
|
+
|
270
|
+
def follow_redirect(follow_redirect)
|
271
|
+
@result.follow_redirect = follow_redirect
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
data/lib/kashi/dsl.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'hashie'
|
3
|
+
require 'kashi/dsl/cake'
|
4
|
+
|
5
|
+
module Kashi
|
6
|
+
class DSL
|
7
|
+
class << self
|
8
|
+
def define(source, filepath, options)
|
9
|
+
self.new(filepath, options) do
|
10
|
+
eval(source, binding, filepath)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :result
|
16
|
+
|
17
|
+
def initialize(filepath, options, &block)
|
18
|
+
@filepath = filepath
|
19
|
+
@result = OpenStruct.new(cake: nil)
|
20
|
+
|
21
|
+
@context = Hashie::Mash.new(
|
22
|
+
filepath: filepath,
|
23
|
+
templates: {},
|
24
|
+
options: options,
|
25
|
+
)
|
26
|
+
|
27
|
+
instance_eval(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def require(file)
|
31
|
+
scfile = (file =~ %r|\A/|) ? file : File.expand_path(File.join(File.dirname(@filepath), file))
|
32
|
+
|
33
|
+
if File.exist?(scfile)
|
34
|
+
instance_eval(File.read(scfile), scfile)
|
35
|
+
elsif File.exist?("#{scfile}.rb")
|
36
|
+
instance_eval(File.read("#{scfile}.rb"), "#{scfile}.rb")
|
37
|
+
else
|
38
|
+
Kernel.require(file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def template(name, &block)
|
43
|
+
@context.templates[name.to_s] = block
|
44
|
+
end
|
45
|
+
|
46
|
+
def cake(&block)
|
47
|
+
if @result.cake
|
48
|
+
@result.cake = Cake.new(@context, @result.cake.tests, @result.cake.contact_groups, &block).result
|
49
|
+
else
|
50
|
+
@result.cake = Cake.new(@context, &block).result
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
cake do
|
2
|
+
<%- contact_groups_by_id.each do |contact_id, contact_group| -%>
|
3
|
+
contact_group <%= contact_id %> do
|
4
|
+
group_name <%= contact_group['GroupName'].inspect %>
|
5
|
+
desktop_alert <%= contact_group['DesktopAlert'].inspect %>
|
6
|
+
email <%= contact_group['Emails'].inspect %>
|
7
|
+
boxcar <%= contact_group['Boxcar'].inspect %>
|
8
|
+
pushover <%= contact_group['Pushover'].inspect %>
|
9
|
+
ping_url <%= contact_group['PingURL'].inspect %>
|
10
|
+
mobile <%= contact_group['Mobiles'].inspect %>
|
11
|
+
end
|
12
|
+
<%- if contact_groups_by_id.keys.last != contact_id -%>
|
13
|
+
|
14
|
+
<%- end -%>
|
15
|
+
<%- end -%>
|
16
|
+
<%- if !contact_groups_by_id.empty? && !tests_by_id.empty? -%>
|
17
|
+
|
18
|
+
<%- end -%>
|
19
|
+
<%- tests_by_id.each do |test_id, test| -%>
|
20
|
+
test <%= test_id.inspect %> do
|
21
|
+
paused <%= test['Paused'] ? 1 : 0 %>
|
22
|
+
|
23
|
+
test_type <%= test['TestType'].inspect %>
|
24
|
+
|
25
|
+
# Required Details
|
26
|
+
website_name <%= test['WebsiteName'].inspect %>
|
27
|
+
website_url <%= test['URI'].inspect %>
|
28
|
+
<%- if %w/SMTP SSH TCP/.include?(test['TestType']) -%>
|
29
|
+
port <%= test['Port'].inspect %>
|
30
|
+
<%- end -%>
|
31
|
+
<%- if test['TestType'] == 'DNS' -%>
|
32
|
+
dns_ip <%= test['DNSIP'].inspect %>
|
33
|
+
dns_server <%= test['DNSServer'].inspect %>
|
34
|
+
<%- end -%>
|
35
|
+
<%- if %w/HTTP HEAD SSH/.include?(test['TestType']) -%>
|
36
|
+
<%- if test['BasicUser'] -%>
|
37
|
+
basic_user <%= test['BasicUser'].inspect %>
|
38
|
+
<%- end -%>
|
39
|
+
<%- if test['BasicPass'] -%>
|
40
|
+
basic_pass <%= test['BasicPass'].inspect %>
|
41
|
+
<%- end -%>
|
42
|
+
<%- end -%>
|
43
|
+
|
44
|
+
contact_group <%= test['ContactGroups'].map { |contact_group| contact_group['Name'] }.inspect %>
|
45
|
+
|
46
|
+
<%- if %w/HTTP HEAD/.include?(test['TestType']) -%>
|
47
|
+
# Scans
|
48
|
+
enable_ssl_warning <%= test['EnableSSLWarning'] ? 1 : 0 %>
|
49
|
+
<%- if test['Virus'] -%>
|
50
|
+
virus 1
|
51
|
+
<%- end -%>
|
52
|
+
|
53
|
+
# HTTP Communication Options
|
54
|
+
find_string <%= test['FindString'].inspect %>
|
55
|
+
do_not_find <%= test['DoNotFind'] ? 1 : 0 %>
|
56
|
+
<%- if test['UseJar'] -%>
|
57
|
+
use_jar <%= test['UseJar'].inspect %>
|
58
|
+
<%- end -%>
|
59
|
+
follow_redirect <%= test['FollowRedirect'] ? 1 : 0 %>
|
60
|
+
custom_header(
|
61
|
+
<%= (test['CustomHeader'] == '' ? '' : JSON.parse(test['CustomHeader'])).inspect %>
|
62
|
+
)
|
63
|
+
status_codes <%= test['StatusCodes'].inspect %>
|
64
|
+
<%- end -%>
|
65
|
+
|
66
|
+
logo_image <%= test['LogoImage'].inspect %>
|
67
|
+
|
68
|
+
<%- if test['NodeLocations'] -%>
|
69
|
+
# Test Locations
|
70
|
+
node_locations <%= test['NodeLocations'].inspect %>
|
71
|
+
<%- end -%>
|
72
|
+
|
73
|
+
# Threshold Control
|
74
|
+
trigger_rate <%= test['TriggerRate'].inspect %>
|
75
|
+
confirmation <%= test['Confirmation'].inspect %>
|
76
|
+
|
77
|
+
# Additional Options
|
78
|
+
check_rate <%= test['CheckRate'].inspect %>
|
79
|
+
timeout <%= test['Timeout'].inspect %>
|
80
|
+
<%- if test['Tags'] -%>
|
81
|
+
test_tags <%= test['Tags'].inspect %>
|
82
|
+
<%- end -%>
|
83
|
+
website_host <%= test['WebsiteHost'].inspect %>
|
84
|
+
end
|
85
|
+
<%- if tests_by_id.keys.last != test_id -%>
|
86
|
+
|
87
|
+
<%- end -%>
|
88
|
+
<%- end -%>
|
89
|
+
end
|
data/lib/kashi/utils.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'diffy'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
module Kashi
|
5
|
+
class Utils
|
6
|
+
class << self
|
7
|
+
def normalize_hash(hash)
|
8
|
+
hash.dup.each do |k, v|
|
9
|
+
if v.kind_of?(Array)
|
10
|
+
v.sort!
|
11
|
+
if v.first.kind_of?(Hash)
|
12
|
+
hash[k] = v.map { |o| normalize_hash(o) }
|
13
|
+
elsif v.first.respond_to?(:to_h)
|
14
|
+
hash[k] = v.map { |o| normalize_hash(o.to_h) }
|
15
|
+
end
|
16
|
+
elsif v == nil
|
17
|
+
hash[k] = ''
|
18
|
+
elsif v.respond_to?(:to_h)
|
19
|
+
hash[k] = normalize_hash(v.to_h)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
sort_keys(hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
def sort_keys(hash)
|
26
|
+
hash = Hash[hash.sort]
|
27
|
+
hash.each do |k, v|
|
28
|
+
if v.kind_of?(Array)
|
29
|
+
if v.first.kind_of?(Hash)
|
30
|
+
hash[k] = v.map { |h| sort_keys(h) }
|
31
|
+
end
|
32
|
+
elsif v.kind_of?(Hash)
|
33
|
+
hash[k] = sort_keys(v)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
hash
|
37
|
+
end
|
38
|
+
|
39
|
+
def diff(obj1, obj2, options = {})
|
40
|
+
diffy = Diffy::Diff.new(
|
41
|
+
obj1.pretty_inspect,
|
42
|
+
obj2.pretty_inspect,
|
43
|
+
:diff => '-u'
|
44
|
+
)
|
45
|
+
|
46
|
+
out = diffy.to_s(options[:color] ? :color : :text).gsub(/\s+\z/m, '')
|
47
|
+
out.gsub!(/^/, options[:indent]) if options[:indent]
|
48
|
+
out
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/kashi.rb
ADDED