build_status_server 0.8 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -6,10 +6,11 @@ gem "json"
6
6
 
7
7
  group :test do
8
8
  gem "rspec"
9
+ gem "ci_reporter"
10
+ gem "ruby-debug"
9
11
  end
10
12
 
11
13
  group :development do
12
- gem "ruby-debug"
13
14
  gem "sinatra"
14
15
  end
15
16
 
data/Gemfile.lock CHANGED
@@ -1,12 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- build_status_server (0.7)
4
+ build_status_server (0.8)
5
5
  json
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
+ builder (3.0.0)
11
+ ci_reporter (1.7.0)
12
+ builder (>= 2.1.2)
10
13
  columnize (0.3.6)
11
14
  diff-lcs (1.1.3)
12
15
  json (1.6.5)
@@ -41,6 +44,7 @@ PLATFORMS
41
44
 
42
45
  DEPENDENCIES
43
46
  build_status_server!
47
+ ci_reporter
44
48
  json
45
49
  rake
46
50
  rspec
@@ -19,7 +19,7 @@ Notification Plugin)) and an Arduino powered Traffic Light controller
19
19
  EOS
20
20
  s.description = "A build notifier server for Jenkins CI that controls an XFD over HTTP"
21
21
 
22
- s.files = Dir["{lib/**/*,spec/**/*}"] + %w(
22
+ s.files = Dir["{lib/**/*,spec/**/*.rb,spec/support/*}"] + %w(
23
23
  Gemfile
24
24
  Gemfile.lock
25
25
  LICENSE
@@ -6,6 +6,7 @@
6
6
  port: 4567
7
7
  pass: /green
8
8
  fail: /red
9
+ attempts: 5
9
10
  store:
10
11
  filename: /tmp/build_result.yml
11
12
  mask:
@@ -0,0 +1,118 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>build_status_server.rb</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <div id="background"></div>
11
+ <div id="jump_to">
12
+ Jump To &hellip;
13
+ <div id="jump_wrapper">
14
+ <div id="jump_page">
15
+ <a class="source" href="build_status_server.html">build_status_server.rb</a>
16
+ <a class="source" href="build_status_server/config.html">config.rb</a>
17
+ <a class="source" href="build_status_server/server.html">server.rb</a>
18
+ <a class="source" href="build_status_server/version.html">version.rb</a>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ <table cellspacing=0 cellpadding=0>
23
+ <thead>
24
+ <tr>
25
+ <th class=docs><h1>build_status_server.rb</h1></th>
26
+ <th class=code></th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <tr id='section-Installation'>
31
+ <td class=docs>
32
+ <div class="pilwrap">
33
+ <a class="pilcrow" href="#section-Installation">&#182;</a>
34
+ </div>
35
+ <p><strong>Build Notifier</strong></p>
36
+
37
+ <p>This utility is part of an XFD (eXtreeme Feedback Device) solution designed and
38
+ built for my employer <a href="http://challengepost.com">ChallengePost</a>. It works in
39
+ conjunction with our <a href="http://jenkins-ci.org">Jenkins</a> Continuous Integration
40
+ server (and its
41
+ <a href="https://wiki.jenkins-ci.org/display/JENKINS/Notification+Plugin">Notification Plugin</a>)
42
+ and an <a href="http://arduino.cc">Arduino</a> powered
43
+ <a href="https://github.com/jcmuller/TrafficLightController">Traffic Light controller</a>
44
+ with a
45
+ pseudo-<a href="http://en.wikipedia.org/wiki/Representational_state_transfer">REST</a>ful
46
+ API.</p>
47
+
48
+ <p>To run, you need to create a <code>config.yml</code> file. The first time you run the
49
+ application without any arguments, you will get a sample.</p>
50
+
51
+ <h1>Installation</h1>
52
+
53
+ <p>$ gem install build<em>status</em>server</p>
54
+
55
+ <h1>Execution</h1>
56
+
57
+ <p>See the options you can pass in by:</p>
58
+
59
+ <p>$ build<em>status</em>server -h</p>
60
+
61
+ <h1>Configuration file</h1>
62
+
63
+ <h2>UDP Server</h2>
64
+
65
+ <p>This section defines what interface and port should the UDP server listen at.
66
+ The Jenkins&#39; Notification Plugin should be set to this parameters as well.</p>
67
+
68
+ <h2>TCP Client</h2>
69
+
70
+ <p>This section is where we tell the server how to communicate with the web
71
+ enabled XFD. In the example case, there is a web server running somewhere
72
+ listening on port 4567 that responds to <code>/green</code> and <code>/red</code>.</p>
73
+
74
+ <p>On our installation, this represents the Traffic Light&#39;s Arduino web server.</p>
75
+
76
+ <h2>Store</h2>
77
+
78
+ <p>Where the persistent state will be stored.</p>
79
+
80
+ <h2>Mask (optional)</h2>
81
+
82
+ <p>You can decide to either include or ignore certain builds whose names match a
83
+ given <a href="http://en.wikipedia.org/wiki/Regular_expression">Regular Expression</a>.</p>
84
+
85
+ <h2>Verbose</h2>
86
+
87
+ <p>Whether to display informative output messages.</p>
88
+
89
+ <h1>Development</h1>
90
+
91
+ <p><code>bin/build_status_server_traffic_light_mock</code> is provided for development
92
+ purposes only.</p>
93
+
94
+ <h1>Finished product</h1>
95
+
96
+ <p><img src="http://i.imgur.com/aK5rs.jpg" alt="my image"></p>
97
+
98
+ <h1>Wiring the traffic light</h1>
99
+
100
+ <p><img src="http://i.imgur.com/gUpWe.jpg" alt="my image"></p>
101
+
102
+ </td>
103
+ <td class=code>
104
+ <div class='highlight'><pre><span class="nb">require</span> <span class="s2">&quot;rubygems&quot;</span>
105
+ <span class="nb">require</span> <span class="s2">&quot;json&quot;</span>
106
+ <span class="nb">require</span> <span class="s2">&quot;socket&quot;</span>
107
+ <span class="nb">require</span> <span class="s2">&quot;timeout&quot;</span>
108
+ <span class="nb">require</span> <span class="s2">&quot;yaml&quot;</span>
109
+
110
+ <span class="k">module</span> <span class="nn">BuildStatusServer</span>
111
+ <span class="nb">autoload</span> <span class="ss">:Config</span><span class="p">,</span> <span class="s1">&#39;build_status_server/config&#39;</span>
112
+ <span class="nb">autoload</span> <span class="ss">:Server</span><span class="p">,</span> <span class="s1">&#39;build_status_server/server&#39;</span>
113
+ <span class="k">end</span></pre></div>
114
+ </td>
115
+ </tr>
116
+ </table>
117
+ </div>
118
+ </body>
@@ -0,0 +1,157 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>config.rb</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <div id="background"></div>
11
+ <div id="jump_to">
12
+ Jump To &hellip;
13
+ <div id="jump_wrapper">
14
+ <div id="jump_page">
15
+ <a class="source" href="../build_status_server.html">build_status_server.rb</a>
16
+ <a class="source" href="config.html">config.rb</a>
17
+ <a class="source" href="server.html">server.rb</a>
18
+ <a class="source" href="version.html">version.rb</a>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ <table cellspacing=0 cellpadding=0>
23
+ <thead>
24
+ <tr>
25
+ <th class=docs><h1>config.rb</h1></th>
26
+ <th class=code></th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <tr id='section-1'>
31
+ <td class=docs>
32
+ <div class="pilwrap">
33
+ <a class="pilcrow" href="#section-1">&#182;</a>
34
+ </div>
35
+
36
+ </td>
37
+ <td class=code>
38
+ <div class='highlight'><pre><span class="k">module</span> <span class="nn">BuildStatusServer</span>
39
+ <span class="k">class</span> <span class="nc">Config</span>
40
+ <span class="kp">attr_reader</span> <span class="ss">:config</span>
41
+
42
+ <span class="k">def</span> <span class="nf">initialize</span>
43
+ <span class="vi">@config</span> <span class="o">=</span> <span class="p">{}</span>
44
+ <span class="k">end</span></pre></div>
45
+ </td>
46
+ </tr>
47
+ <tr id='section-2'>
48
+ <td class=docs>
49
+ <div class="pilwrap">
50
+ <a class="pilcrow" href="#section-2">&#182;</a>
51
+ </div>
52
+ <p>This is responsible of loading the config object</p>
53
+ </td>
54
+ <td class=code>
55
+ <div class='highlight'><pre> <span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
56
+ <span class="n">config</span> <span class="o">=</span> <span class="n">load_config_file</span><span class="p">(</span><span class="n">options</span><span class="o">[</span><span class="ss">:config</span><span class="o">]</span><span class="p">)</span>
57
+ <span class="n">import_config</span><span class="p">(</span><span class="n">config</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span>
58
+ <span class="k">end</span>
59
+
60
+ <span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="n">meth</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span>
61
+ <span class="k">return</span> <span class="n">config</span><span class="o">[</span><span class="n">meth</span><span class="o">.</span><span class="n">to_s</span><span class="o">]</span> <span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">has_key?</span><span class="p">(</span><span class="n">meth</span><span class="o">.</span><span class="n">to_s</span><span class="p">)</span>
62
+ <span class="k">super</span>
63
+ <span class="k">end</span>
64
+
65
+ <span class="k">def</span> <span class="nf">store_file</span>
66
+ <span class="k">return</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">,</span> <span class="n">store</span><span class="o">[</span><span class="s2">&quot;filename&quot;</span><span class="o">]</span><span class="p">)</span> <span class="k">if</span> <span class="n">store</span>
67
+ <span class="kp">nil</span>
68
+ <span class="k">end</span>
69
+
70
+ <span class="kp">private</span></pre></div>
71
+ </td>
72
+ </tr>
73
+ <tr id='section-3'>
74
+ <td class=docs>
75
+ <div class="pilwrap">
76
+ <a class="pilcrow" href="#section-3">&#182;</a>
77
+ </div>
78
+ <p>This will load the passed in config object into the config attribute</p>
79
+ </td>
80
+ <td class=code>
81
+ <div class='highlight'><pre> <span class="k">def</span> <span class="nf">import_config</span><span class="p">(</span><span class="n">config</span> <span class="o">=</span> <span class="p">{},</span> <span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
82
+ <span class="n">config</span><span class="o">[</span><span class="s2">&quot;verbose&quot;</span><span class="o">]</span> <span class="o">=</span> <span class="n">options</span><span class="o">[</span><span class="ss">:verbose</span><span class="o">]</span> <span class="k">unless</span> <span class="n">options</span><span class="o">[</span><span class="ss">:verbose</span><span class="o">].</span><span class="n">nil?</span>
83
+ <span class="vi">@config</span> <span class="o">=</span> <span class="n">config</span>
84
+ <span class="k">end</span></pre></div>
85
+ </td>
86
+ </tr>
87
+ <tr id='section-4'>
88
+ <td class=docs>
89
+ <div class="pilwrap">
90
+ <a class="pilcrow" href="#section-4">&#182;</a>
91
+ </div>
92
+ <p>This is responsible to return a hash with the contents of a YAML file</p>
93
+
94
+ </td>
95
+ <td class=code>
96
+ <div class='highlight'><pre> <span class="k">def</span> <span class="nf">load_config_file</span><span class="p">(</span><span class="n">config_file</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span>
97
+ <span class="n">curated_file</span> <span class="o">=</span> <span class="kp">nil</span>
98
+
99
+ <span class="k">if</span> <span class="n">config_file</span>
100
+ <span class="n">f</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="n">config_file</span><span class="p">)</span>
101
+ <span class="k">if</span> <span class="no">File</span><span class="o">.</span><span class="n">exists?</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
102
+ <span class="n">curated_file</span> <span class="o">=</span> <span class="n">f</span>
103
+ <span class="k">else</span>
104
+ <span class="k">raise</span> <span class="s2">&quot;Supplied config file (</span><span class="si">#{</span><span class="n">config_file</span><span class="si">}</span><span class="s2">) doesn&#39;t seem to exist&quot;</span>
105
+ <span class="k">end</span>
106
+ <span class="k">else</span>
107
+ <span class="n">locations_to_try</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">possible_conf_file</span><span class="o">|</span>
108
+ <span class="n">f</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="n">possible_conf_file</span><span class="p">)</span>
109
+ <span class="k">if</span> <span class="no">File</span><span class="o">.</span><span class="n">exists?</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
110
+ <span class="n">curated_file</span> <span class="o">=</span> <span class="n">f</span>
111
+ <span class="k">break</span>
112
+ <span class="k">end</span>
113
+ <span class="k">end</span>
114
+
115
+ <span class="k">if</span> <span class="n">curated_file</span><span class="o">.</span><span class="n">nil?</span>
116
+ <span class="no">STDERR</span><span class="o">.</span><span class="n">puts</span> <span class="o">&lt;&lt;-</span><span class="no">EOT</span>
117
+ <span class="sh">Looks like there isn&#39;t an available configuration file for this program.</span>
118
+ <span class="sh">We&#39;re very diligently going to use some sensible defaults, but you&#39;re</span>
119
+ <span class="sh">strongly recommended to create one in any of the following locations:</span>
120
+
121
+ <span class="sh"> #{locations_to_try.join(&quot;\n &quot;)}</span>
122
+
123
+ <span class="sh"> Here is a sample of the contents for that file (and the settings we&#39;re going</span>
124
+ <span class="sh"> to use):</span>
125
+
126
+ <span class="sh">#{get_example_config}</span>
127
+ <span class="no"> EOT</span>
128
+
129
+ <span class="k">return</span> <span class="no">YAML</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">get_example_config</span><span class="p">)</span>
130
+ <span class="k">end</span>
131
+ <span class="k">end</span>
132
+
133
+ <span class="no">YAML</span><span class="o">.</span><span class="n">load_file</span><span class="p">(</span><span class="n">curated_file</span><span class="p">)</span><span class="o">.</span><span class="n">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
134
+ <span class="k">raise</span> <span class="s2">&quot;This is an invalid configuration file!&quot;</span> <span class="k">unless</span> <span class="n">config</span><span class="o">.</span><span class="n">class</span> <span class="o">==</span> <span class="no">Hash</span>
135
+ <span class="k">end</span>
136
+ <span class="k">end</span>
137
+
138
+ <span class="k">def</span> <span class="nf">locations_to_try</span>
139
+ <span class="sx">%w(</span>
140
+ <span class="sx"> ~/.config/build_status_server/config.yml</span>
141
+ <span class="sx"> ./config/config.yml</span>
142
+ <span class="sx"> /etc/build_status_server/config.yml</span>
143
+ <span class="sx"> /usr/local/etc/build_status_server/config.yml</span>
144
+ <span class="sx"> )</span>
145
+ <span class="k">end</span>
146
+
147
+ <span class="k">def</span> <span class="nf">get_example_config</span>
148
+ <span class="n">filename</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">))</span><span class="si">}</span><span class="s2">/../../config/config-example.yml&quot;</span>
149
+ <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">read</span>
150
+ <span class="k">end</span>
151
+ <span class="k">end</span>
152
+ <span class="k">end</span></pre></div>
153
+ </td>
154
+ </tr>
155
+ </table>
156
+ </div>
157
+ </body>
@@ -17,6 +17,10 @@ module BuildStatusServer
17
17
  super
18
18
  end
19
19
 
20
+ def respond_to?(meth)
21
+ config.has_key?(meth.to_s) || super
22
+ end
23
+
20
24
  def store_file
21
25
  return File.expand_path(".", store["filename"]) if store
22
26
  nil
@@ -0,0 +1,202 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>server.rb</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <div id="background"></div>
11
+ <div id="jump_to">
12
+ Jump To &hellip;
13
+ <div id="jump_wrapper">
14
+ <div id="jump_page">
15
+ <a class="source" href="../build_status_server.html">build_status_server.rb</a>
16
+ <a class="source" href="config.html">config.rb</a>
17
+ <a class="source" href="server.html">server.rb</a>
18
+ <a class="source" href="version.html">version.rb</a>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ <table cellspacing=0 cellpadding=0>
23
+ <thead>
24
+ <tr>
25
+ <th class=docs><h1>server.rb</h1></th>
26
+ <th class=code></th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <tr id='section-1'>
31
+ <td class=docs>
32
+ <div class="pilwrap">
33
+ <a class="pilcrow" href="#section-1">&#182;</a>
34
+ </div>
35
+ <p>TODO
36
+ move all configuration stuff to Config
37
+ and just call config[:blaj] instead of if blah</p>
38
+
39
+ </td>
40
+ <td class=code>
41
+ <div class='highlight'><pre><span class="k">module</span> <span class="nn">BuildStatusServer</span>
42
+ <span class="k">class</span> <span class="nc">Server</span>
43
+ <span class="kp">attr_reader</span> <span class="ss">:config</span><span class="p">,</span> <span class="ss">:store</span>
44
+
45
+ <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
46
+ <span class="vi">@config</span> <span class="o">=</span> <span class="no">Config</span><span class="o">.</span><span class="n">new</span>
47
+ <span class="n">config</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
48
+ <span class="k">end</span>
49
+
50
+ <span class="k">def</span> <span class="nf">listen</span>
51
+ <span class="n">sock</span> <span class="o">=</span> <span class="no">UDPSocket</span><span class="o">.</span><span class="n">new</span>
52
+ <span class="n">udp_server</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">udp_server</span>
53
+
54
+ <span class="k">begin</span>
55
+ <span class="n">sock</span><span class="o">.</span><span class="n">bind</span><span class="p">(</span><span class="n">udp_server</span><span class="o">[</span><span class="s2">&quot;address&quot;</span><span class="o">]</span><span class="p">,</span> <span class="n">udp_server</span><span class="o">[</span><span class="s2">&quot;port&quot;</span><span class="o">]</span><span class="p">)</span>
56
+ <span class="k">rescue</span> <span class="no">Errno</span><span class="o">::</span><span class="no">EADDRINUSE</span>
57
+ <span class="no">STDERR</span><span class="o">.</span><span class="n">puts</span> <span class="o">&lt;&lt;-</span><span class="no">EOT</span>
58
+ <span class="sh">There appears that another instance is running, or another process</span>
59
+ <span class="sh">is listening at the same port (#{udp_server[&quot;address&quot;]}:#{udp_server[&quot;port&quot;]}</span>
60
+
61
+ <span class="no"> EOT</span>
62
+ <span class="nb">exit</span>
63
+ <span class="k">end</span>
64
+
65
+ <span class="nb">puts</span> <span class="s2">&quot;Listening on UDP </span><span class="si">#{</span><span class="n">udp_server</span><span class="o">[</span><span class="s2">&quot;address&quot;</span><span class="o">]</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">udp_server</span><span class="o">[</span><span class="s2">&quot;port&quot;</span><span class="o">]</span><span class="si">}</span><span class="s2">&quot;</span> <span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">verbose</span>
66
+
67
+ <span class="k">begin</span>
68
+ <span class="k">while</span> <span class="kp">true</span>
69
+ <span class="n">data</span><span class="p">,</span> <span class="n">addr</span> <span class="o">=</span> <span class="n">sock</span><span class="o">.</span><span class="n">recvfrom</span><span class="p">(</span><span class="mi">2048</span><span class="p">)</span>
70
+
71
+ <span class="k">if</span> <span class="n">process_job</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
72
+ <span class="n">status</span> <span class="o">=</span> <span class="n">process_all_statuses</span>
73
+ <span class="n">notify</span><span class="p">(</span><span class="n">status</span><span class="p">)</span>
74
+ <span class="k">end</span>
75
+ <span class="k">end</span>
76
+ <span class="k">rescue</span> <span class="no">Interrupt</span>
77
+ <span class="nb">puts</span> <span class="s2">&quot;Good bye.&quot;</span>
78
+ <span class="n">sock</span><span class="o">.</span><span class="n">close</span>
79
+ <span class="nb">exit</span>
80
+ <span class="k">end</span>
81
+ <span class="k">end</span>
82
+
83
+ <span class="kp">private</span>
84
+
85
+ <span class="k">def</span> <span class="nf">load_store</span>
86
+ <span class="vi">@store</span> <span class="o">=</span> <span class="k">begin</span>
87
+ <span class="no">YAML</span><span class="o">.</span><span class="n">load_file</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">store_file</span><span class="p">)</span>
88
+ <span class="k">rescue</span>
89
+ <span class="p">{}</span>
90
+ <span class="k">end</span>
91
+ <span class="vi">@store</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">unless</span> <span class="n">store</span><span class="o">.</span><span class="n">class</span> <span class="o">==</span> <span class="no">Hash</span>
92
+ <span class="k">end</span>
93
+
94
+
95
+ <span class="k">def</span> <span class="nf">process_job</span><span class="p">(</span><span class="n">data</span> <span class="o">=</span> <span class="s2">&quot;{}&quot;</span><span class="p">)</span>
96
+ <span class="n">job</span> <span class="o">=</span> <span class="no">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
97
+
98
+ <span class="n">build_name</span> <span class="o">=</span> <span class="n">job</span><span class="o">[</span><span class="s2">&quot;name&quot;</span><span class="o">]</span>
99
+
100
+ <span class="k">unless</span> <span class="n">should_process_build</span><span class="p">(</span><span class="n">build_name</span><span class="p">)</span>
101
+ <span class="no">STDOUT</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Ignoring </span><span class="si">#{</span><span class="n">build_name</span><span class="si">}</span><span class="s2"> (</span><span class="si">#{</span><span class="n">config</span><span class="o">.</span><span class="n">mask</span><span class="o">[</span><span class="s2">&quot;regex&quot;</span><span class="o">]</span><span class="si">}</span><span class="s2">--</span><span class="si">#{</span><span class="n">config</span><span class="o">.</span><span class="n">mask</span><span class="o">[</span><span class="s2">&quot;policy&quot;</span><span class="o">]</span><span class="si">}</span><span class="s2">)&quot;</span> <span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">verbose</span>
102
+ <span class="k">return</span> <span class="kp">false</span>
103
+ <span class="k">end</span>
104
+
105
+ <span class="k">if</span> <span class="n">job</span><span class="o">.</span><span class="n">class</span> <span class="o">!=</span> <span class="no">Hash</span> <span class="ow">or</span>
106
+ <span class="n">job</span><span class="o">[</span><span class="s2">&quot;build&quot;</span><span class="o">].</span><span class="n">class</span> <span class="o">!=</span> <span class="no">Hash</span>
107
+ <span class="no">STDERR</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Pinged with an invalid payload&quot;</span>
108
+ <span class="k">return</span> <span class="kp">false</span>
109
+ <span class="k">end</span>
110
+
111
+ <span class="n">phase</span> <span class="o">=</span> <span class="n">job</span><span class="o">[</span><span class="s2">&quot;build&quot;</span><span class="o">][</span><span class="s2">&quot;phase&quot;</span><span class="o">]</span>
112
+ <span class="n">status</span> <span class="o">=</span> <span class="n">job</span><span class="o">[</span><span class="s2">&quot;build&quot;</span><span class="o">][</span><span class="s2">&quot;status&quot;</span><span class="o">]</span>
113
+
114
+ <span class="k">if</span> <span class="n">phase</span> <span class="o">==</span> <span class="s2">&quot;FINISHED&quot;</span>
115
+ <span class="no">STDOUT</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Got </span><span class="si">#{</span><span class="n">status</span><span class="si">}</span><span class="s2"> for </span><span class="si">#{</span><span class="n">build_name</span><span class="si">}</span><span class="s2"> on </span><span class="si">#{</span><span class="no">Time</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2"> [</span><span class="si">#{</span><span class="n">job</span><span class="o">.</span><span class="n">inspect</span><span class="si">}</span><span class="s2">]&quot;</span> <span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">verbose</span>
116
+ <span class="k">case</span> <span class="n">status</span>
117
+ <span class="k">when</span> <span class="s2">&quot;SUCCESS&quot;</span><span class="p">,</span> <span class="s2">&quot;FAILURE&quot;</span>
118
+ <span class="n">load_store</span>
119
+ <span class="n">store</span><span class="o">[</span><span class="n">build_name</span><span class="o">]</span> <span class="o">=</span> <span class="n">status</span>
120
+ <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">store_file</span><span class="p">,</span> <span class="s2">&quot;w&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">file</span><span class="o">|</span> <span class="no">YAML</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">store</span><span class="p">,</span> <span class="n">file</span><span class="p">)</span> <span class="p">}</span>
121
+ <span class="k">return</span> <span class="kp">true</span>
122
+ <span class="k">end</span>
123
+ <span class="k">else</span>
124
+ <span class="no">STDOUT</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Started for </span><span class="si">#{</span><span class="n">build_name</span><span class="si">}</span><span class="s2"> on </span><span class="si">#{</span><span class="no">Time</span><span class="o">.</span><span class="n">now</span><span class="si">}</span><span class="s2"> [</span><span class="si">#{</span><span class="n">job</span><span class="o">.</span><span class="n">inspect</span><span class="si">}</span><span class="s2">]&quot;</span> <span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">verbose</span>
125
+ <span class="k">end</span>
126
+
127
+ <span class="k">return</span> <span class="kp">false</span>
128
+ <span class="k">end</span>
129
+
130
+ <span class="k">def</span> <span class="nf">should_process_build</span><span class="p">(</span><span class="n">build_name</span><span class="p">)</span>
131
+ <span class="c1"># If mask exists, then ...</span>
132
+ <span class="o">!</span> <span class="p">(</span>
133
+ <span class="o">!!</span><span class="n">config</span><span class="o">.</span><span class="n">mask</span> <span class="o">&amp;&amp;</span>
134
+ <span class="o">!!</span><span class="n">config</span><span class="o">.</span><span class="n">mask</span><span class="o">[</span><span class="s2">&quot;regex&quot;</span><span class="o">]</span> <span class="o">&amp;&amp;</span>
135
+ <span class="p">((</span><span class="n">config</span><span class="o">.</span><span class="n">mask</span><span class="o">[</span><span class="s2">&quot;policy&quot;</span><span class="o">]</span> <span class="o">==</span> <span class="s2">&quot;include&quot;</span> <span class="o">&amp;&amp;</span> <span class="n">build_name</span> <span class="o">!~</span> <span class="n">config</span><span class="o">.</span><span class="n">mask</span><span class="o">[</span><span class="s2">&quot;regex&quot;</span><span class="o">]</span><span class="p">)</span> <span class="o">||</span>
136
+ <span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">mask</span><span class="o">[</span><span class="s2">&quot;policy&quot;</span><span class="o">]</span> <span class="o">!=</span> <span class="s2">&quot;include&quot;</span> <span class="o">&amp;&amp;</span> <span class="n">build_name</span> <span class="o">=~</span> <span class="n">config</span><span class="o">.</span><span class="n">mask</span><span class="o">[</span><span class="s2">&quot;regex&quot;</span><span class="o">]</span><span class="p">)</span>
137
+ <span class="p">))</span>
138
+ <span class="k">end</span>
139
+
140
+ <span class="k">def</span> <span class="nf">process_all_statuses</span>
141
+ <span class="n">pass</span> <span class="o">=</span> <span class="kp">true</span>
142
+
143
+ <span class="vi">@store</span><span class="o">.</span><span class="n">values</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">val</span><span class="o">|</span>
144
+ <span class="n">pass</span> <span class="o">&amp;&amp;=</span> <span class="p">(</span><span class="n">val</span> <span class="o">==</span> <span class="s2">&quot;pass&quot;</span> <span class="o">||</span> <span class="n">val</span> <span class="o">==</span> <span class="s2">&quot;SUCCESS&quot;</span><span class="p">)</span>
145
+ <span class="k">end</span>
146
+
147
+ <span class="n">pass</span>
148
+ <span class="k">end</span>
149
+
150
+ <span class="k">def</span> <span class="nf">notify</span><span class="p">(</span><span class="n">status</span><span class="p">)</span>
151
+ <span class="n">tcp_client</span> <span class="o">=</span> <span class="n">config</span><span class="o">.</span><span class="n">tcp_client</span>
152
+
153
+ <span class="n">attempts</span> <span class="o">=</span> <span class="mi">0</span>
154
+ <span class="n">light</span> <span class="o">=</span> <span class="n">status</span> <span class="p">?</span> <span class="n">tcp_client</span><span class="o">[</span><span class="s2">&quot;pass&quot;</span><span class="o">]</span> <span class="p">:</span> <span class="n">tcp_client</span><span class="o">[</span><span class="s2">&quot;fail&quot;</span><span class="o">]</span>
155
+
156
+ <span class="k">begin</span>
157
+ <span class="n">timeout</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="k">do</span>
158
+ <span class="n">attempts</span> <span class="o">+=</span> <span class="mi">1</span>
159
+ <span class="n">client</span> <span class="o">=</span> <span class="no">TCPSocket</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">tcp_client</span><span class="o">[</span><span class="s2">&quot;host&quot;</span><span class="o">]</span><span class="p">,</span> <span class="n">tcp_client</span><span class="o">[</span><span class="s2">&quot;port&quot;</span><span class="o">]</span><span class="p">)</span>
160
+ <span class="n">client</span><span class="o">.</span><span class="n">print</span> <span class="s2">&quot;GET </span><span class="si">#{</span><span class="n">light</span><span class="si">}</span><span class="s2"> HTTP/1.0</span><span class="se">\n\n</span><span class="s2">&quot;</span>
161
+ <span class="n">answer</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">gets</span><span class="p">(</span><span class="kp">nil</span><span class="p">)</span>
162
+ <span class="no">STDOUT</span><span class="o">.</span><span class="n">puts</span> <span class="n">answer</span> <span class="k">if</span> <span class="n">config</span><span class="o">.</span><span class="n">verbose</span>
163
+ <span class="n">client</span><span class="o">.</span><span class="n">close</span>
164
+ <span class="k">end</span>
165
+ <span class="k">rescue</span> <span class="no">Timeout</span><span class="o">::</span><span class="no">Error</span> <span class="o">=&gt;</span> <span class="n">ex</span>
166
+ <span class="no">STDERR</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Error: </span><span class="si">#{</span><span class="n">ex</span><span class="si">}</span><span class="s2"> while trying to send </span><span class="si">#{</span><span class="n">light</span><span class="si">}</span><span class="s2">&quot;</span>
167
+ <span class="k">retry</span> <span class="k">unless</span> <span class="n">attempts</span> <span class="o">&gt;</span> <span class="mi">2</span>
168
+ <span class="k">rescue</span> <span class="no">Errno</span><span class="o">::</span><span class="no">ECONNREFUSED</span><span class="p">,</span> <span class="no">Errno</span><span class="o">::</span><span class="no">EHOSTUNREACH</span> <span class="o">=&gt;</span> <span class="n">ex</span>
169
+ <span class="no">STDERR</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Error: </span><span class="si">#{</span><span class="n">ex</span><span class="si">}</span><span class="s2"> while trying to send </span><span class="si">#{</span><span class="n">light</span><span class="si">}</span><span class="s2">&quot;</span>
170
+ <span class="no">STDERR</span><span class="o">.</span><span class="n">puts</span> <span class="s2">&quot;Will wait for 2 seconds and try again...&quot;</span>
171
+ <span class="nb">sleep</span> <span class="mi">2</span>
172
+ <span class="k">retry</span> <span class="k">unless</span> <span class="n">attempts</span> <span class="o">&gt;</span> <span class="mi">2</span>
173
+ <span class="k">end</span>
174
+ <span class="k">end</span>
175
+ <span class="k">end</span>
176
+ <span class="k">end</span>
177
+
178
+ <span class="cp">__END__</span>
179
+
180
+ <span class="cp">Example payload:</span>
181
+ <span class="cp">{</span>
182
+ <span class="cp"> &quot;name&quot;:&quot;test&quot;,</span>
183
+ <span class="cp"> &quot;url&quot;:&quot;job/test/&quot;,</span>
184
+ <span class="cp"> &quot;build&quot;:{</span>
185
+ <span class="cp"> &quot;full_url&quot;:&quot;http://cronus.local:3001/job/test/20/&quot;,</span>
186
+ <span class="cp"> &quot;number&quot;:20,</span>
187
+ <span class="cp"> &quot;phase&quot;:&quot;FINISHED&quot;,</span>
188
+ <span class="cp"> &quot;status&quot;:&quot;SUCCESS&quot;,</span>
189
+ <span class="cp"> &quot;url&quot;:&quot;job/test/20/&quot;</span>
190
+ <span class="cp"> }</span>
191
+ <span class="cp">}</span>
192
+
193
+ <span class="cp">We&#39;re getting this error once in a while:</span>
194
+ <span class="cp">/usr/local/lib/ruby/1.8/timeout.rb:64:in `notify&#39;: execution expired (Timeout::Error)</span>
195
+ <span class="cp"> from /home/jcmuller/build_notifier/lib/server.rb:102:in `notify&#39;</span>
196
+ <span class="cp"> from /home/jcmuller/build_notifier/lib/server.rb:33:in `listen&#39;</span>
197
+ <span class="cp"> from bin/server:5</span></pre></div>
198
+ </td>
199
+ </tr>
200
+ </table>
201
+ </div>
202
+ </body>