watchdoge 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/watchdoge/notification/base.rb +35 -0
- data/lib/watchdoge/notification/gitlab_repo.rb +45 -26
- data/lib/watchdoge/notification/mattermost.rb +4 -6
- data/lib/watchdoge/notification/slack_webhook.rb +10 -11
- data/lib/watchdoge/notification.rb +5 -1
- data/lib/watchdoge/pixel_test.rb +61 -0
- data/lib/watchdoge/regression/dsl.rb +4 -9
- data/lib/watchdoge/regression.rb +1 -0
- data/lib/watchdoge/version.rb +1 -1
- data/lib/watchdoge.rb +1 -1
- data/watchdoge.gemspec +1 -1
- metadata +3 -2
- data/lib/watchdoge/image_diff.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db9eab410f530c1dd00de8bfb39a4cfaa86d3e41aa86105d776c47e8c68ad9cb
|
4
|
+
data.tar.gz: 3196f93d3121f1aaafe6a4dfea5fc702dfbe54c4a985dfdd6b4f08abc3e515af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef68aed278dc48dd7eac239a9c91bbaf532b010f4bb28f4c32ddbd3c57d3dd271a26e7c087e86bf2d7b64abe37dc73a2c51c1990e3a73882ce41f05bdbc9f2ea
|
7
|
+
data.tar.gz: a9d02b67e9534ccf26047f4eb260b738251a68a92971fa7333689220dc13e1c4b089c36b0d507c950543cc3fbeff5d7adc3beb3602c32ecb373102fa868e7197
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'net_http_ssl_fix'
|
3
|
+
|
4
|
+
require 'chunky_png'
|
5
|
+
require 'json'
|
6
|
+
require 'net/http'
|
7
|
+
require 'net/http/post/multipart'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module WatchDoge
|
11
|
+
module Notification
|
12
|
+
class Base
|
13
|
+
def initialize opt
|
14
|
+
@message_queue = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def push message
|
18
|
+
@message_queue << message
|
19
|
+
end
|
20
|
+
|
21
|
+
def flush
|
22
|
+
@message_queue.each do |message|
|
23
|
+
case message
|
24
|
+
when String
|
25
|
+
puts message
|
26
|
+
when ChunkyPNG::Image
|
27
|
+
File.write 'image.png', message.to_blob
|
28
|
+
when WatchDoge::PixelTest
|
29
|
+
File.write 'image.png', message.diff.to_blob
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -9,40 +9,47 @@ require 'uri'
|
|
9
9
|
|
10
10
|
module WatchDoge
|
11
11
|
module Notification
|
12
|
-
class GitlabRepo
|
12
|
+
class GitlabRepo < WatchDoge::Notification::Base
|
13
13
|
def initialize opt
|
14
|
+
super
|
15
|
+
|
14
16
|
@host = opt[:host] || ENV['CI_API_V4_URL']
|
15
17
|
@project_id = opt[:project_id] || ENV['CI_PROJECT_ID']
|
16
18
|
@source_branch = opt[:source_branch] || ENV['CI_COMMIT_REF_NAME']
|
17
19
|
|
18
20
|
@private_token = opt[:private_token]
|
19
|
-
|
20
|
-
@message_queue = []
|
21
|
-
end
|
22
|
-
|
23
|
-
def push message
|
24
|
-
@message_queue << message
|
25
21
|
end
|
26
22
|
|
27
23
|
def flush
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
24
|
+
iid = get_latest_request_iid
|
25
|
+
|
26
|
+
@message_queue = [] if iid.nil?
|
27
|
+
|
28
|
+
table = markdown_table do |table_context|
|
29
|
+
@message_queue.each do |message|
|
30
|
+
case message
|
31
|
+
when String
|
32
|
+
post_discussion request_iid: iid, message: message
|
33
|
+
when ChunkyPNG::Image
|
34
|
+
upload_link = upload_image message
|
35
|
+
link = md_img_link upload_link
|
36
|
+
|
37
|
+
post_discussion request_iid: iid, message: link
|
38
|
+
when WatchDoge::PixelTest
|
39
|
+
before = md_img_link upload_image(message.before)
|
40
|
+
after = md_img_link upload_image(message.after)
|
41
|
+
diff = md_img_link upload_image(message.diff)
|
42
|
+
|
43
|
+
table_context << markdown_table_row(before, after, diff)
|
44
|
+
end
|
44
45
|
end
|
46
|
+
|
47
|
+
table_context
|
45
48
|
end
|
49
|
+
|
50
|
+
@message_queue = []
|
51
|
+
|
52
|
+
post_discussion request_iid: iid, message: table
|
46
53
|
end
|
47
54
|
|
48
55
|
def post_discussion request_iid:, message:
|
@@ -54,11 +61,11 @@ module WatchDoge
|
|
54
61
|
"PRIVATE-TOKEN": @private_token
|
55
62
|
end
|
56
63
|
|
57
|
-
def upload_image
|
64
|
+
def upload_image image
|
58
65
|
uri = project_uri "/uploads"
|
59
66
|
|
60
67
|
req = Net::HTTP::Post::Multipart.new uri.path, {
|
61
|
-
file: UploadIO.new(StringIO.new(
|
68
|
+
file: UploadIO.new(StringIO.new(image.to_blob), 'image/png', 'image.png')
|
62
69
|
}
|
63
70
|
|
64
71
|
req.add_field("PRIVATE-TOKEN", @private_token)
|
@@ -67,7 +74,7 @@ module WatchDoge
|
|
67
74
|
res = http.request(req).body
|
68
75
|
end
|
69
76
|
|
70
|
-
JSON.parse(res)
|
77
|
+
JSON.parse(res)['url']
|
71
78
|
end
|
72
79
|
|
73
80
|
def get_latest_request_iid
|
@@ -87,6 +94,10 @@ module WatchDoge
|
|
87
94
|
|
88
95
|
private
|
89
96
|
|
97
|
+
def md_img_link link
|
98
|
+
"![image](#{ENV['CI_PROJECT_URL']}#{link})"
|
99
|
+
end
|
100
|
+
|
90
101
|
# markdown_table do |context|
|
91
102
|
def markdown_table
|
92
103
|
"<table>
|
@@ -99,6 +110,14 @@ module WatchDoge
|
|
99
110
|
</table>"
|
100
111
|
end
|
101
112
|
|
113
|
+
def markdown_table_row before, after, diff
|
114
|
+
"<tr>
|
115
|
+
<td>#{before}</td>
|
116
|
+
<td>#{after}</td>
|
117
|
+
<td>#{diff}</td>
|
118
|
+
</tr>"
|
119
|
+
end
|
120
|
+
|
102
121
|
def project_uri path
|
103
122
|
URI(@host + "/projects/#{@project_id}#{path}")
|
104
123
|
end
|
@@ -8,15 +8,11 @@ module WatchDoge
|
|
8
8
|
module Notification
|
9
9
|
class Mattermost
|
10
10
|
def initialize args
|
11
|
+
super
|
12
|
+
|
11
13
|
@host = args[:host]
|
12
14
|
@channel_id = args[:channel_id]
|
13
15
|
@auth_token = args[:auth_token]
|
14
|
-
|
15
|
-
@message_queue = []
|
16
|
-
end
|
17
|
-
|
18
|
-
def push message
|
19
|
-
@message_queue << message
|
20
16
|
end
|
21
17
|
|
22
18
|
def flush
|
@@ -26,6 +22,8 @@ module WatchDoge
|
|
26
22
|
post matter_most_meta(message)
|
27
23
|
when ChunkyPNG::Image
|
28
24
|
post_file matter_most_meta(message)
|
25
|
+
when WatchDoge::PixelTest
|
26
|
+
post_file matter_most_meta(message.diff)
|
29
27
|
end
|
30
28
|
end
|
31
29
|
end
|
@@ -1,19 +1,10 @@
|
|
1
|
-
require 'chunky_png'
|
2
|
-
require 'json'
|
3
|
-
require 'net/http'
|
4
|
-
require 'uri'
|
5
|
-
|
6
1
|
module WatchDoge
|
7
2
|
module Notification
|
8
3
|
class SlackWebhook
|
9
4
|
def initialize opt
|
10
|
-
|
11
|
-
|
12
|
-
@message_queue = []
|
13
|
-
end
|
5
|
+
super
|
14
6
|
|
15
|
-
|
16
|
-
@message_queue << message
|
7
|
+
@incoming_url = opt[:incoming_url]
|
17
8
|
end
|
18
9
|
|
19
10
|
def flush
|
@@ -36,6 +27,14 @@ module WatchDoge
|
|
36
27
|
when ChunkyPNG::Image
|
37
28
|
data = ['data:image/png;base64,', message.to_blob].pack('A*m').gsub(/\n/, '')
|
38
29
|
|
30
|
+
{
|
31
|
+
attachments: [{
|
32
|
+
image_url: data
|
33
|
+
}]
|
34
|
+
}
|
35
|
+
when WatchDoge::PixelTest
|
36
|
+
data = ['data:image/png;base64,', message.diff.to_blob].pack('A*m').gsub(/\n/, '')
|
37
|
+
|
39
38
|
{
|
40
39
|
attachments: [{
|
41
40
|
image_url: data
|
@@ -21,6 +21,8 @@
|
|
21
21
|
# end
|
22
22
|
|
23
23
|
# built-in sources
|
24
|
+
require 'watchdoge/notification/base'
|
25
|
+
|
24
26
|
require 'watchdoge/notification/slack_webhook'
|
25
27
|
require 'watchdoge/notification/mattermost'
|
26
28
|
require 'watchdoge/notification/gitlab_repo'
|
@@ -51,7 +53,9 @@ module WatchDoge
|
|
51
53
|
def sources
|
52
54
|
@sources ||= WatchDoge.configuration.notifications
|
53
55
|
|
54
|
-
|
56
|
+
@sources = {
|
57
|
+
base: {}
|
58
|
+
} if @sources.empty?
|
55
59
|
|
56
60
|
@sources.each do |klass_sym, source_args|
|
57
61
|
sources_map[klass_sym] ||=
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# generating diff image of two input image
|
2
|
+
|
3
|
+
# usage:
|
4
|
+
# diff_image = WatchDoge::PixelTest.diff(chunky_png_image, another_chunky_png_image)
|
5
|
+
# WatchDoge::PixelTest.new diff_image, before:
|
6
|
+
|
7
|
+
# spec:
|
8
|
+
# 1. input only accept ChunkyPNG::Image, output image is also ChunkyPNG::Image
|
9
|
+
# 2. able to testing RGBA pixel by pixel. then blending with mask color if diff detected
|
10
|
+
|
11
|
+
# todo: should improve testing boundary for more accurate diff imagenot.
|
12
|
+
|
13
|
+
module WatchDoge
|
14
|
+
class PixelTest
|
15
|
+
def self.diff input_image, reference_image, opacity: 0.7, mask_base_color: "#F163FF"
|
16
|
+
return nil if input_image.pixels.hash == reference_image.pixels.hash
|
17
|
+
|
18
|
+
mask_color = mask_base_color.concat (opacity * 256).to_i.to_s(16).upcase
|
19
|
+
|
20
|
+
dup_input_image = input_image.dup
|
21
|
+
|
22
|
+
input_image.height.times do |y|
|
23
|
+
pixels = input_image.row(y)
|
24
|
+
|
25
|
+
if y >= reference_image.height
|
26
|
+
pixels.each_with_index do |pixel, x|
|
27
|
+
dup_input_image.compose_pixel(x, y, mask_color)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
reference_pixels = reference_image.row(y)
|
31
|
+
|
32
|
+
next if (pixels.hash == reference_pixels.hash)
|
33
|
+
|
34
|
+
pixels.each_with_index do |pixel, x|
|
35
|
+
if pixels[x] != reference_pixels[x]
|
36
|
+
dup_input_image.compose_pixel(x, y, reference_pixels[x])
|
37
|
+
dup_input_image.compose_pixel(x, y, mask_color)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
dup_input_image
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :diff
|
47
|
+
attr_reader :before
|
48
|
+
attr_reader :after
|
49
|
+
|
50
|
+
def initialize input, reference
|
51
|
+
@before = reference
|
52
|
+
@after = input
|
53
|
+
|
54
|
+
@diff = self.class.diff input, reference
|
55
|
+
end
|
56
|
+
|
57
|
+
def diff?
|
58
|
+
@diff
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -63,15 +63,10 @@ module WatchDoge
|
|
63
63
|
when :regression
|
64
64
|
puts " -> compare reference images on worker #{@worker}"
|
65
65
|
reference_image = WatchDoge::Regression::Utils.load_png self.reference_image
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
WatchDoge::Notification.push cycle_image
|
71
|
-
WatchDoge::Notification.push reference_image
|
72
|
-
end
|
73
|
-
WatchDoge::Notification.push diff
|
74
|
-
end
|
66
|
+
input_image = WatchDoge::Regression::Utils.load_png @worker.screenshot.png
|
67
|
+
pixel_test = WatchDoge::PixelTest.new(input_image, reference_image)
|
68
|
+
|
69
|
+
WatchDoge::Notification.push pixel_test if pixel_test.diff?
|
75
70
|
end
|
76
71
|
end
|
77
72
|
|
data/lib/watchdoge/regression.rb
CHANGED
data/lib/watchdoge/version.rb
CHANGED
data/lib/watchdoge.rb
CHANGED
@@ -4,7 +4,7 @@ require 'watchdoge/configuration'
|
|
4
4
|
require 'watchdoge/cookie_pool'
|
5
5
|
require 'watchdoge/worker'
|
6
6
|
require 'watchdoge/notification'
|
7
|
-
require 'watchdoge/
|
7
|
+
require 'watchdoge/pixel_test'
|
8
8
|
require 'watchdoge/regression'
|
9
9
|
require 'watchdoge/rails/railtie' if defined?(Rails)
|
10
10
|
require 'watchdoge/rails/generator' if defined?(Rails)
|
data/watchdoge.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: watchdoge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shen Lee
|
@@ -114,11 +114,12 @@ files:
|
|
114
114
|
- lib/watchdoge.rb
|
115
115
|
- lib/watchdoge/configuration.rb
|
116
116
|
- lib/watchdoge/cookie_pool.rb
|
117
|
-
- lib/watchdoge/image_diff.rb
|
118
117
|
- lib/watchdoge/notification.rb
|
118
|
+
- lib/watchdoge/notification/base.rb
|
119
119
|
- lib/watchdoge/notification/gitlab_repo.rb
|
120
120
|
- lib/watchdoge/notification/mattermost.rb
|
121
121
|
- lib/watchdoge/notification/slack_webhook.rb
|
122
|
+
- lib/watchdoge/pixel_test.rb
|
122
123
|
- lib/watchdoge/rails/generator.rb
|
123
124
|
- lib/watchdoge/rails/railtie.rb
|
124
125
|
- lib/watchdoge/regression.rb
|
data/lib/watchdoge/image_diff.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# generating diff image of two input image
|
2
|
-
|
3
|
-
# usage:
|
4
|
-
# diff_image = WatchDoge::ImageDiff.diff(chunky_png_image, another_chunky_png_image)
|
5
|
-
|
6
|
-
# spec:
|
7
|
-
# 1. input only accept ChunkyPNG::Image, output image is also ChunkyPNG::Image
|
8
|
-
# 2. able to testing RGBA pixel by pixel. then blending with mask color if diff detected
|
9
|
-
|
10
|
-
# todo: should improve testing boundary for more accurate diff imagenot.
|
11
|
-
|
12
|
-
module WatchDoge
|
13
|
-
module ImageDiff
|
14
|
-
class << self
|
15
|
-
def diff input_image, reference_image, opacity: 0.7, mask_base_color: "#F163FF"
|
16
|
-
return nil if input_image.pixels.hash == reference_image.pixels.hash
|
17
|
-
|
18
|
-
mask_color = mask_base_color.concat (opacity * 256).to_i.to_s(16).upcase
|
19
|
-
|
20
|
-
dup_input_image = input_image.dup
|
21
|
-
|
22
|
-
input_image.height.times do |y|
|
23
|
-
pixels = input_image.row(y)
|
24
|
-
|
25
|
-
if y >= reference_image.height
|
26
|
-
pixels.each_with_index do |pixel, x|
|
27
|
-
dup_input_image.compose_pixel(x, y, mask_color)
|
28
|
-
end
|
29
|
-
else
|
30
|
-
reference_pixels = reference_image.row(y)
|
31
|
-
|
32
|
-
next if (pixels.hash == reference_pixels.hash)
|
33
|
-
|
34
|
-
pixels.each_with_index do |pixel, x|
|
35
|
-
if pixels[x] != reference_pixels[x]
|
36
|
-
dup_input_image.compose_pixel(x, y, reference_pixels[x])
|
37
|
-
dup_input_image.compose_pixel(x, y, mask_color)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
dup_input_image
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|