langalex-cijoe 0.0.1

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.
@@ -0,0 +1,33 @@
1
+ class CIJoe
2
+ class Build < Struct.new(:user, :project, :started_at, :finished_at, :sha, :status, :output)
3
+ def initialize(*args)
4
+ super
5
+ self.started_at = Time.now
6
+ end
7
+
8
+ def status
9
+ return super if started_at && finished_at
10
+ :building
11
+ end
12
+
13
+ def failed?
14
+ status == :failed
15
+ end
16
+
17
+ def worked?
18
+ status == :worked
19
+ end
20
+
21
+ def short_sha
22
+ sha[0,7] if sha
23
+ end
24
+
25
+ def clean_output
26
+ output.gsub(/\e\[.+?m/, '').strip
27
+ end
28
+
29
+ def commit
30
+ @commit ||= Commit.new(sha, user, project)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ class CIJoe
2
+ class Commit < Struct.new(:sha, :user, :project)
3
+ def url
4
+ "http://github.com/#{user}/#{project}/commit/#{sha}"
5
+ end
6
+
7
+ def author
8
+ raw_commit_lines[1].split(':')[-1]
9
+ end
10
+
11
+ def committed_at
12
+ raw_commit_lines[2].split(':', 2)[-1]
13
+ end
14
+
15
+ def message
16
+ raw_commit_lines[4].split(':')[-1].strip
17
+ end
18
+
19
+ def raw_commit
20
+ @raw_commit ||= `git show #{sha}`.chomp
21
+ end
22
+
23
+ def raw_commit_lines
24
+ @raw_commit_lines ||= raw_commit.split("\n")
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ class CIJoe
2
+ class Config
3
+ def self.method_missing(command, *args)
4
+ new(command)
5
+ end
6
+
7
+ def initialize(command, parent = nil)
8
+ @command = command
9
+ @parent = parent
10
+ end
11
+
12
+ def method_missing(command, *args)
13
+ Config.new(command, self)
14
+ end
15
+
16
+ def to_s
17
+ `git config #{config_string}`.chomp
18
+ end
19
+
20
+ def config_string
21
+ @parent ? "#{@parent.config_string}.#{@command}" : @command
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/../mmmail'
2
+
3
+ class CIJoe
4
+ module Email
5
+ def self.activate
6
+ if valid_config?
7
+ CIJoe::Build.class_eval do
8
+ include CIJoe::Email
9
+ end
10
+
11
+ puts "Loaded Email notifier"
12
+ else
13
+ puts "Can't load Email notifier."
14
+ puts "Please add the following to your project's .git/config:"
15
+ puts "[email]"
16
+ puts "\tto = build@example.com"
17
+ puts "\tuser = horst"
18
+ puts "\tpass = passw0rd"
19
+ puts "\thost = mail.example.com"
20
+ end
21
+ end
22
+
23
+ def self.config
24
+ @config ||= {
25
+ :to => Config.email.to.to_s,
26
+ :user => Config.email.user.to_s,
27
+ :pass => Config.email.pass.to_s,
28
+ :host => Config.email.host.to_s
29
+ }
30
+ end
31
+
32
+ def self.valid_config?
33
+ %w( host user pass to ).all? do |key|
34
+ !config[key.intern].empty?
35
+ end
36
+ end
37
+
38
+ def notify
39
+ options = {
40
+ :to => Email.config[:to],
41
+ :from => Email.config[:to],
42
+ :subject => 'Build failed',
43
+ :body => "The commit #{commit.url} causes the build to fail."
44
+ }
45
+ MmMail.send(options) if failed?
46
+ end
47
+
48
+ end
49
+ end
Binary file
@@ -0,0 +1,212 @@
1
+ /*****************************************************************************/
2
+ /*
3
+ /* Common
4
+ /*
5
+ /*****************************************************************************/
6
+
7
+ /* Global Reset */
8
+
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ }
13
+
14
+ html, body {
15
+ height: 100%;
16
+ }
17
+
18
+ body {
19
+ background-color: white;
20
+ font: 13.34px helvetica, arial, clean, sans-serif;
21
+ *font-size: small;
22
+ text-align: center;
23
+ }
24
+
25
+ h1, h2, h3, h4, h5, h6 {
26
+ font-size: 100%;
27
+ }
28
+
29
+ h1 {
30
+ margin-bottom: 1em;
31
+ }
32
+
33
+ h1 a {
34
+ text-decoration: none;
35
+ color: #000;
36
+ }
37
+
38
+ .failed, .color31 {
39
+ color: red !important;
40
+ }
41
+
42
+ .worked, .color32 {
43
+ color: green !important;
44
+ }
45
+
46
+ .errored, .color33 {
47
+ color: yellow !important;
48
+ }
49
+
50
+ p {
51
+ margin: 1em 0;
52
+ }
53
+
54
+ a {
55
+ color: #00a;
56
+ }
57
+
58
+ a:hover {
59
+ color: black;
60
+ }
61
+
62
+ a:visited {
63
+ color: #a0a;
64
+ }
65
+
66
+ table {
67
+ font-size: inherit;
68
+ font: 100%;
69
+ }
70
+
71
+ /*****************************************************************************/
72
+ /*
73
+ /* Home
74
+ /*
75
+ /*****************************************************************************/
76
+
77
+ ul.posts {
78
+ list-style-type: none;
79
+ margin-bottom: 2em;
80
+ }
81
+
82
+ ul.posts li {
83
+ line-height: 1.75em;
84
+ }
85
+
86
+ ul.posts .date {
87
+ color: #aaa;
88
+ font-family: Monaco, "Courier New", monospace;
89
+ font-size: 80%;
90
+ }
91
+
92
+ /*****************************************************************************/
93
+ /*
94
+ /* Site
95
+ /*
96
+ /*****************************************************************************/
97
+
98
+ .site {
99
+ font-size: 110%;
100
+ text-align: justify;
101
+ width: 40em;
102
+ margin: 3em auto 2em auto;
103
+ line-height: 1.5em;
104
+ }
105
+
106
+ .title {
107
+ color: #a00;
108
+ font-weight: bold;
109
+ margin-bottom: 2em;
110
+ }
111
+
112
+ .site .title a {
113
+ color: #a00;
114
+ text-decoration: none;
115
+ }
116
+
117
+ .site .title a:hover {
118
+ color: black;
119
+ }
120
+
121
+ .site .title .extra {
122
+ color: #aaa;
123
+ text-decoration: none;
124
+ margin-left: 1em;
125
+ font-size: 0.9em;
126
+ }
127
+
128
+ .site .title a.extra:hover {
129
+ color: black;
130
+ }
131
+
132
+ .site .meta {
133
+ color: #aaa;
134
+ }
135
+
136
+ .site .footer {
137
+ font-size: 80%;
138
+ color: #666;
139
+ border-top: 4px solid #eee;
140
+ margin-top: 2em;
141
+ overflow: hidden;
142
+ }
143
+
144
+ .site .footer .contact {
145
+ float: left;
146
+ margin-right: 3em;
147
+ }
148
+
149
+ .site .footer .contact a {
150
+ color: #8085C1;
151
+ }
152
+
153
+ .site .footer .rss {
154
+ margin-top: 1.1em;
155
+ margin-right: -.2em;
156
+ float: right;
157
+ }
158
+
159
+ .site .footer .rss img {
160
+ border: 0;
161
+ }
162
+
163
+ /*****************************************************************************/
164
+ /*
165
+ /* Posts
166
+ /*
167
+ /*****************************************************************************/
168
+
169
+ #post {
170
+
171
+ }
172
+
173
+ /* standard */
174
+
175
+ #post pre {
176
+ border: 1px solid #ddd;
177
+ background-color: #eef;
178
+ padding: 0 .4em;
179
+ }
180
+
181
+ #post ul,
182
+ #post ol {
183
+ margin-left: 1.25em;
184
+ }
185
+
186
+ #post code {
187
+ border: 1px solid #ddd;
188
+ background-color: #eef;
189
+ font-size: 95%;
190
+ padding: 0 .2em;
191
+ }
192
+
193
+ #post pre code {
194
+ border: none;
195
+ }
196
+
197
+ /* terminal */
198
+
199
+ pre.terminal {
200
+ border: 1px solid black;
201
+ background-color: #333;
202
+ color: white;
203
+ padding: 5px;
204
+ overflow: auto;
205
+ word-wrap: break-word;
206
+ }
207
+
208
+ pre.terminal code {
209
+ font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
210
+ background-color: #333;
211
+ }
212
+
@@ -0,0 +1,74 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+
4
+ class CIJoe
5
+ class Server < Sinatra::Base
6
+ dir = File.dirname(File.expand_path(__FILE__))
7
+
8
+ set :views, "#{dir}/views"
9
+ set :public, "#{dir}/public"
10
+ set :static, true
11
+
12
+ get '/?' do
13
+ erb(:template, {}, :joe => @joe)
14
+ end
15
+
16
+ post '/?' do
17
+ payload = params[:payload].to_s
18
+ if payload.empty? || payload.include?(@joe.git_branch)
19
+ @joe.build
20
+ end
21
+ redirect request.path
22
+ end
23
+
24
+ user, pass = Config.cijoe.user.to_s, Config.cijoe.pass.to_s
25
+ if user != '' && pass != ''
26
+ use Rack::Auth::Basic do |username, password|
27
+ [ username, password ] == [ user, pass ]
28
+ end
29
+ puts "Using HTTP basic auth"
30
+ end
31
+
32
+ helpers do
33
+ include Rack::Utils
34
+ alias_method :h, :escape_html
35
+
36
+ # thanks integrity!
37
+ def ansi_color_codes(string)
38
+ string.gsub("\e[0m", '</span>').
39
+ gsub(/\e\[(\d+)m/, "<span class=\"color\\1\">")
40
+ end
41
+
42
+ def pretty_time(time)
43
+ time.strftime("%Y-%m-%d %H:%M")
44
+ end
45
+
46
+ def cijoe_root
47
+ root = request.path
48
+ root = "" if root == "/"
49
+ root
50
+ end
51
+ end
52
+
53
+ def initialize(*args)
54
+ super
55
+ check_project
56
+ @joe = CIJoe.new(options.project_path)
57
+
58
+ CIJoe::Email.activate
59
+ end
60
+
61
+ def self.start(host, port, project_path)
62
+ set :project_path, project_path
63
+ CIJoe::Server.run! :host => host, :port => port
64
+ end
65
+
66
+ def check_project
67
+ if options.project_path.nil? || !File.exists?(File.expand_path(options.project_path))
68
+ puts "Whoops! I need the path to a Git repo."
69
+ puts " $ git clone git@github.com:username/project.git project"
70
+ abort " $ cijoe project"
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,3 @@
1
+ class CIJoe
2
+ Version = "0.1.2"
3
+ end
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <link href="<%= cijoe_root %>/screen.css" media="screen" rel="stylesheet" type="text/css" />
5
+ <title><%= h(joe.project) %>: CI Joe</title>
6
+ </head>
7
+ <body>
8
+ <div class="site">
9
+ <div class="title">
10
+ <a href="<%= cijoe_root %>/">CI Joe</a>
11
+ <span class="extra">because knowing is half the battle</span>
12
+ </div>
13
+
14
+ <div id="home">
15
+ <h1><a href="<%= joe.url %>"><%= joe.project %></a></h1>
16
+ <ul class="posts">
17
+ <% if joe.current_build %>
18
+ <li>
19
+ <span class="date"><%= pretty_time(joe.current_build.started_at) if joe.current_build %></span> &raquo;
20
+ <% if joe.current_build.sha %>
21
+ Building <a href="<%= joe.url %>/commits/<%= joe.current_build.sha %>"><%= joe.current_build.short_sha %></a> <small>(pid: <%= joe.pid %>)</small>
22
+ <% else %>
23
+ Build starting...
24
+ <% end %>
25
+ </li>
26
+ <% else %>
27
+ <li><form method="POST"><input type="submit" value="Build"/></form></li>
28
+ <% end %>
29
+
30
+ <% if joe.last_build %>
31
+ <li><span class="date"><%= pretty_time(joe.last_build.finished_at) %></span> &raquo; Built <a href="<%= joe.url %>/commits/<%= joe.last_build.sha %>"><%= joe.last_build.short_sha %></a> <span class="<%= joe.last_build.status %>">(<%= joe.last_build.status %>)</span></li>
32
+ <% if joe.last_build.failed? %>
33
+ <li><pre class="terminal"><code><%=ansi_color_codes h(joe.last_build.output) %></code></pre></li>
34
+ <% end %>
35
+ <% end %>
36
+ </ul>
37
+ </div>
38
+
39
+ <div class="footer">
40
+ <div class="contact">
41
+ <p>
42
+ <a href="http://github.com/defunkt/cijoe/tree/master#readme">Documentation</a><br/>
43
+ <a href="http://github.com/defunkt/cijoe">Source</a><br/>
44
+ <a href="http://github.com/defunkt/cijoe/issues">Issues</a><br/>
45
+ <a href="http://twitter.com/defunkt">Twitter</a>
46
+ </p>
47
+ </div>
48
+ <div class="contact">
49
+ <p>
50
+ Designed by <a href="http://tom.preston-werner.com/">Tom Preston-Werner</a><br/>
51
+ Influenced by <a href="http://integrityapp.com/">Integrity</a><br/>
52
+ Built with <a href="http://sinatrarb.com/">Sinatra</a><br/>
53
+ Keep it simple, Sam.
54
+ </p>
55
+ </div>
56
+ <div class="rss">
57
+ <a href="http://github.com/defunkt/cijoe">
58
+ <img src="<%= cijoe_root %>/octocat.png" alt="Octocat!" />
59
+ </a>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </body>
64
+ </html>