build_status_server 0.7 → 0.8

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.
@@ -27,16 +27,20 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
27
27
 
28
28
  puts "Listening on UDP #{udp_server["address"]}:#{udp_server["port"]}" if config.verbose
29
29
 
30
- while true
31
- data, addr = sock.recvfrom(2048)
30
+ begin
31
+ while true
32
+ data, addr = sock.recvfrom(2048)
32
33
 
33
- if process_job(data)
34
- status = process_all_statuses
35
- notify(status)
34
+ if process_job(data)
35
+ status = process_all_statuses
36
+ notify(status)
37
+ end
36
38
  end
39
+ rescue Interrupt
40
+ puts "Good bye."
41
+ sock.close
42
+ exit
37
43
  end
38
-
39
- sock.close
40
44
  end
41
45
 
42
46
  private
@@ -0,0 +1,162 @@
1
+ # TODO
2
+ # move all configuration stuff to Config
3
+ # and just call config[:blaj] instead of if blah
4
+ module BuildStatusServer
5
+ class Server
6
+ attr_reader :config, :store
7
+
8
+ def initialize(options = {})
9
+ @config = Config.new
10
+ config.load(options)
11
+ end
12
+
13
+ def listen
14
+ sock = UDPSocket.new
15
+ udp_server = config.udp_server
16
+
17
+ begin
18
+ sock.bind(udp_server["address"], udp_server["port"])
19
+ rescue Errno::EADDRINUSE
20
+ STDERR.puts <<-EOT
21
+ There appears that another instance is running, or another process
22
+ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
23
+
24
+ EOT
25
+ exit
26
+ end
27
+
28
+ puts "Listening on UDP #{udp_server["address"]}:#{udp_server["port"]}" if config.verbose
29
+
30
+ begin
31
+ while true
32
+ data, addr = sock.recvfrom(2048)
33
+
34
+ if process_job(data)
35
+ status = process_all_statuses
36
+ notify(status)
37
+ end
38
+ end
39
+ rescue Interrupt
40
+ puts "Good bye."
41
+ exit
42
+ end
43
+
44
+ sock.close
45
+ end
46
+
47
+ private
48
+
49
+ def load_store
50
+ @store = begin
51
+ YAML.load_file(config.store_file)
52
+ rescue
53
+ {}
54
+ end
55
+ @store = {} unless store.class == Hash
56
+ end
57
+
58
+
59
+ def process_job(data = "{}")
60
+ job = JSON.parse(data)
61
+
62
+ build_name = job["name"]
63
+
64
+ unless should_process_build(build_name)
65
+ STDOUT.puts "Ignoring #{build_name} (#{config.mask["regex"]}--#{config.mask["policy"]})" if config.verbose
66
+ return false
67
+ end
68
+
69
+ if job.class != Hash or
70
+ job["build"].class != Hash
71
+ STDERR.puts "Pinged with an invalid payload"
72
+ return false
73
+ end
74
+
75
+ phase = job["build"]["phase"]
76
+ status = job["build"]["status"]
77
+
78
+ if phase == "FINISHED"
79
+ STDOUT.puts "Got #{status} for #{build_name} on #{Time.now} [#{job.inspect}]" if config.verbose
80
+ case status
81
+ when "SUCCESS", "FAILURE"
82
+ load_store
83
+ store[build_name] = status
84
+ File.open(config.store_file, "w") { |file| YAML.dump(store, file) }
85
+ return true
86
+ end
87
+ else
88
+ STDOUT.puts "Started for #{build_name} on #{Time.now} [#{job.inspect}]" if config.verbose
89
+ end
90
+
91
+ return false
92
+ end
93
+
94
+ def should_process_build(build_name)
95
+ # If mask exists, then ...
96
+ ! (
97
+ !!config.mask &&
98
+ !!config.mask["regex"] &&
99
+ ((config.mask["policy"] == "include" && build_name !~ config.mask["regex"]) ||
100
+ (config.mask["policy"] != "include" && build_name =~ config.mask["regex"])
101
+ ))
102
+ end
103
+
104
+ def process_all_statuses
105
+ pass = true
106
+
107
+ @store.values.each do |val|
108
+ pass &&= (val == "pass" || val == "SUCCESS")
109
+ end
110
+
111
+ pass
112
+ end
113
+
114
+ def notify(status)
115
+ tcp_client = config.tcp_client
116
+
117
+ attempts = 0
118
+ light = status ? tcp_client["pass"] : tcp_client["fail"]
119
+
120
+ begin
121
+ timeout(5) do
122
+ attempts += 1
123
+ client = TCPSocket.new(tcp_client["host"], tcp_client["port"])
124
+ client.print "GET #{light} HTTP/1.0\n\n"
125
+ answer = client.gets(nil)
126
+ STDOUT.puts answer if config.verbose
127
+ client.close
128
+ end
129
+ rescue Timeout::Error => ex
130
+ STDERR.puts "Error: #{ex} while trying to send #{light}"
131
+ retry unless attempts > 2
132
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH => ex
133
+ STDERR.puts "Error: #{ex} while trying to send #{light}"
134
+ STDERR.puts "Will wait for 2 seconds and try again..."
135
+ sleep 2
136
+ retry unless attempts > 2
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ __END__
143
+
144
+ Example payload:
145
+ {
146
+ "name":"test",
147
+ "url":"job/test/",
148
+ "build":{
149
+ "full_url":"http://cronus.local:3001/job/test/20/",
150
+ "number":20,
151
+ "phase":"FINISHED",
152
+ "status":"SUCCESS",
153
+ "url":"job/test/20/"
154
+ }
155
+ }
156
+
157
+ We're getting this error once in a while:
158
+ /usr/local/lib/ruby/1.8/timeout.rb:64:in `notify': execution expired (Timeout::Error)
159
+ from /home/jcmuller/build_notifier/lib/server.rb:102:in `notify'
160
+ from /home/jcmuller/build_notifier/lib/server.rb:33:in `listen'
161
+ from bin/server:5
162
+
@@ -1,3 +1,3 @@
1
1
  module BuildStatusServer
2
- VERSION = "0.7"
2
+ VERSION = "0.8"
3
3
  end
@@ -1,3 +1,3 @@
1
1
  module BuildStatusServer
2
- VERSION = "0.6"
2
+ VERSION = "0.7"
3
3
  end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build_status_server
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 7
9
- version: "0.7"
8
+ - 8
9
+ version: "0.8"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Juan C. Muller
@@ -83,6 +83,7 @@ extra_rdoc_files: []
83
83
  files:
84
84
  - lib/build_status_server/config.rb
85
85
  - lib/build_status_server/server.rb
86
+ - lib/build_status_server/server.rb~
86
87
  - lib/build_status_server/version.rb
87
88
  - lib/build_status_server/version.rb~
88
89
  - lib/build_status_server.rb