watchdoge 0.1.8 → 0.1.9
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 +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
|
+
""
|
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
|