heidi 0.0.1 → 0.0.2
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.
- data/Gemfile +2 -0
- data/Gemfile.lock +15 -1
- data/README.rdoc +8 -3
- data/VERSION +1 -1
- data/bin/heidi +61 -57
- data/bin/heidi_web +2 -6
- data/heidi.gemspec +11 -5
- data/lib/heidi/build.rb +83 -27
- data/lib/heidi/builder.rb +3 -8
- data/lib/heidi/hook.rb +11 -5
- data/lib/heidi/tester.rb +3 -8
- data/lib/heidi/web/public/css/screen.css +93 -0
- data/lib/heidi/web/public/images/heidi.jpeg +0 -0
- data/lib/heidi/web/views/build.erb +20 -0
- data/lib/heidi/web/views/home.erb +7 -0
- data/lib/heidi/web/views/layout.erb +13 -0
- data/lib/heidi/web/views/project.erb +11 -0
- data/lib/heidi/web.rb +71 -4
- metadata +36 -22
- data/lib/heidi/web/routes/home.rb +0 -9
- data/lib/heidi/web/routes/projects.rb +0 -61
- data/lib/heidi/web/routes.rb +0 -13
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/rstacruz/sinatra-assetpack.git
|
3
|
+
revision: ab2a413026099492807bd19affd60bd3d3bc1cca
|
4
|
+
specs:
|
5
|
+
sinatra-assetpack (0.0.10)
|
6
|
+
jsmin
|
7
|
+
rack-test
|
8
|
+
sinatra
|
9
|
+
tilt (>= 1.3.0)
|
10
|
+
|
1
11
|
GEM
|
2
12
|
remote: http://rubygems.org/
|
3
13
|
specs:
|
@@ -10,10 +20,13 @@ GEM
|
|
10
20
|
git (>= 1.2.5)
|
11
21
|
rake
|
12
22
|
rdoc
|
23
|
+
jsmin (1.0.1)
|
13
24
|
json (1.6.5)
|
14
25
|
rack (1.4.1)
|
15
26
|
rack-protection (1.2.0)
|
16
27
|
rack
|
28
|
+
rack-test (0.6.1)
|
29
|
+
rack (>= 1.0)
|
17
30
|
rake (0.9.2.2)
|
18
31
|
rcov (0.9.10)
|
19
32
|
rdoc (3.12)
|
@@ -26,7 +39,7 @@ GEM
|
|
26
39
|
rspec-expectations (2.8.0)
|
27
40
|
diff-lcs (~> 1.1.2)
|
28
41
|
rspec-mocks (2.8.0)
|
29
|
-
simple_shell (1.0.
|
42
|
+
simple_shell (1.0.1)
|
30
43
|
sinatra (1.3.2)
|
31
44
|
rack (~> 1.3, >= 1.3.6)
|
32
45
|
rack-protection (~> 1.2)
|
@@ -48,4 +61,5 @@ DEPENDENCIES
|
|
48
61
|
rspec (~> 2.8.0)
|
49
62
|
simple_shell
|
50
63
|
sinatra
|
64
|
+
sinatra-assetpack!
|
51
65
|
thin
|
data/README.rdoc
CHANGED
@@ -1,9 +1,14 @@
|
|
1
|
-
=
|
1
|
+
= Heidi
|
2
2
|
|
3
|
-
|
3
|
+
A Continious Integration thingy. Naive, and therefor called Heidi.
|
4
|
+
|
5
|
+
http://www.tv-nostalgie.de/sound/Heidi2.jpg
|
6
|
+
|
7
|
+
Heidi is still taking form and is/will-be used to do CI at OrganisedMinds.com
|
8
|
+
(http://organisedminds.com) - Why don't you sign up there? It's free!
|
4
9
|
|
5
10
|
== Contributing to heidi
|
6
|
-
|
11
|
+
|
7
12
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
8
13
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
9
14
|
* Fork the project.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/bin/heidi
CHANGED
@@ -1,70 +1,74 @@
|
|
1
|
-
#!/bin/
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require 'simple_shell'
|
4
|
+
require 'heidi'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
cmd = ARGV.shift
|
7
|
+
for_a = ARGV.shift
|
8
|
+
|
9
|
+
shell = SimpleShell.new
|
10
|
+
|
11
|
+
def check_heidi_root()
|
12
|
+
if !File.exists?("./projects") && File.directory?("./projects")
|
13
|
+
$stderr.puts "You're not inside Heidi"
|
11
14
|
exit 1
|
12
|
-
|
13
|
-
|
15
|
+
end
|
16
|
+
end
|
14
17
|
|
15
|
-
case
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
;;
|
18
|
+
case cmd
|
19
|
+
when "new"
|
20
|
+
puts "creating #{for_a}"
|
21
|
+
puts "creating #{for_a}/projects"
|
22
|
+
shell.mkdir %W(-p #{for_a}/projects)
|
23
|
+
puts "creating #{for_a}/bin"
|
24
|
+
shell.mkdir %W(-p #{for_a}/bin)
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
+
when "project"
|
27
|
+
check_heidi_root
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
# create a logs dir
|
30
|
+
puts "creating projects/#{for_a}"
|
31
|
+
puts "creating projects/#{for_a}/logs"
|
32
|
+
shell.mkdir %W(-p projects/#{for_a}/logs)
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
mkdir -p projects
|
35
|
-
|
34
|
+
%w(build tests failure success before).each do |hook|
|
35
|
+
puts "creating projects/#{for_a}/hooks/#{hook}"
|
36
|
+
shell.mkdir %W(-p projects/#{for_a}/hooks/#{hook})
|
37
|
+
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
# make a clone
|
40
|
+
shell.in("projects/#{for_a}") do |sh|
|
41
|
+
puts "filling #{for_a} cache"
|
42
|
+
repo = ARGV.shift
|
43
|
+
puts "git clone #{repo}"
|
44
|
+
sh.git %W(clone #{repo} cached)
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
sh.in("cached") do |cached|
|
47
|
+
puts "setting the name of the project to: #{for_a}"
|
48
|
+
cached.git %W(config heidi.name #{for_a})
|
49
|
+
end
|
50
|
+
end
|
51
|
+
puts "\n"
|
52
|
+
puts "Now define some hooks in projects/#{for_a}/hooks/tests"
|
46
53
|
|
47
|
-
|
48
|
-
|
54
|
+
when "drop"
|
55
|
+
check_heidi_root
|
49
56
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
;;
|
60
|
-
web)
|
61
|
-
check_heidi_root
|
57
|
+
# remove build and cache dir, expose logs directly
|
58
|
+
puts "removing build dir"
|
59
|
+
shell.rm %W(-r projects/#{for_a}/build)
|
60
|
+
puts "removing cache (preserving project config)"
|
61
|
+
shell.cp %W(-pr projects/#{for_a}/cached/.git/config projects/#{for_a})
|
62
|
+
shell.rm %W(-r projects/#{for_a}/cached)
|
63
|
+
puts "exposing builds"
|
64
|
+
shell.mv %W(projects/#{for_a}/logs/* projects/#{for_a}/)
|
65
|
+
shell.rm %W(-r projects/#{for_a}/logs)
|
62
66
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
+
when "integrate"
|
68
|
+
heidi = Heidi.new
|
69
|
+
heidi.projects.each do |project|
|
70
|
+
next if !for_a.nil? && project.name != for_a
|
71
|
+
project.fetch && project.integrate
|
72
|
+
end
|
67
73
|
|
68
|
-
|
69
|
-
;;
|
70
|
-
esac
|
74
|
+
end
|
data/bin/heidi_web
CHANGED
@@ -2,11 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# hartog/20120131: Heidi, the CI mistress
|
4
4
|
|
5
|
-
require 'sinatra'
|
6
|
-
require 'heidi'
|
7
|
-
require 'heidi/web'
|
8
5
|
|
9
|
-
|
6
|
+
require 'heidi/web'
|
7
|
+
Heidi::Web.start
|
10
8
|
|
11
|
-
# modular setup with all the freebees of a non modular setup.
|
12
|
-
include Heidi::Web::Routes
|
data/heidi.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "heidi"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Hartog C. de Mik"]
|
12
|
-
s.date = "2012-02-
|
12
|
+
s.date = "2012-02-06"
|
13
13
|
s.description = "CI-Joe alike CI system called Heidi."
|
14
14
|
s.email = "hartog@organisedminds.com"
|
15
15
|
s.executables = ["heidi", "heidi_console", "heidi_cron", "heidi_web"]
|
@@ -40,9 +40,12 @@ Gem::Specification.new do |s|
|
|
40
40
|
"lib/heidi/project.rb",
|
41
41
|
"lib/heidi/tester.rb",
|
42
42
|
"lib/heidi/web.rb",
|
43
|
-
"lib/heidi/web/
|
44
|
-
"lib/heidi/web/
|
45
|
-
"lib/heidi/web/
|
43
|
+
"lib/heidi/web/public/css/screen.css",
|
44
|
+
"lib/heidi/web/public/images/heidi.jpeg",
|
45
|
+
"lib/heidi/web/views/build.erb",
|
46
|
+
"lib/heidi/web/views/home.erb",
|
47
|
+
"lib/heidi/web/views/layout.erb",
|
48
|
+
"lib/heidi/web/views/project.erb",
|
46
49
|
"spec/heidi/build_spec.rb",
|
47
50
|
"spec/heidi/builder_spec.rb",
|
48
51
|
"spec/heidi/git_spec.rb",
|
@@ -66,6 +69,7 @@ Gem::Specification.new do |s|
|
|
66
69
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
67
70
|
s.add_runtime_dependency(%q<thin>, [">= 0"])
|
68
71
|
s.add_runtime_dependency(%q<sinatra>, [">= 0"])
|
72
|
+
s.add_runtime_dependency(%q<sinatra-assetpack>, [">= 0"])
|
69
73
|
s.add_runtime_dependency(%q<simple_shell>, [">= 0"])
|
70
74
|
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
71
75
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
@@ -75,6 +79,7 @@ Gem::Specification.new do |s|
|
|
75
79
|
else
|
76
80
|
s.add_dependency(%q<thin>, [">= 0"])
|
77
81
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
82
|
+
s.add_dependency(%q<sinatra-assetpack>, [">= 0"])
|
78
83
|
s.add_dependency(%q<simple_shell>, [">= 0"])
|
79
84
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
80
85
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
@@ -85,6 +90,7 @@ Gem::Specification.new do |s|
|
|
85
90
|
else
|
86
91
|
s.add_dependency(%q<thin>, [">= 0"])
|
87
92
|
s.add_dependency(%q<sinatra>, [">= 0"])
|
93
|
+
s.add_dependency(%q<sinatra-assetpack>, [">= 0"])
|
88
94
|
s.add_dependency(%q<simple_shell>, [">= 0"])
|
89
95
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
90
96
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
data/lib/heidi/build.rb
CHANGED
@@ -8,40 +8,46 @@ class Heidi
|
|
8
8
|
# A build is tied to a commit
|
9
9
|
#
|
10
10
|
class Build
|
11
|
-
attr_reader :project, :commit, :root, :
|
11
|
+
attr_reader :project, :commit, :root, :log_root, :build_root, :shell,
|
12
|
+
:hooks, :logs
|
12
13
|
|
13
14
|
def initialize(project, commit=project.commit)
|
14
15
|
@project = project
|
15
16
|
@commit = commit
|
16
|
-
|
17
|
+
|
18
|
+
@root = File.join(project.root, "logs", commit)
|
19
|
+
@log_root = File.join(@root, "logs")
|
20
|
+
@build_root = File.join(@root, "build")
|
17
21
|
|
18
22
|
if !File.exists? @root
|
19
23
|
SimpleShell.new(project.root).mkdir %W(-p #{@root})
|
20
24
|
end
|
21
|
-
|
22
25
|
@shell = SimpleShell.new(@root)
|
26
|
+
|
27
|
+
@shell.mkdir %W(-p #{@log_root}) unless File.exists?(@log_root)
|
28
|
+
@logs = Logs.new(@log_root)
|
23
29
|
end
|
24
30
|
|
25
31
|
def load_hooks
|
26
32
|
log :info, "Loading hooks"
|
27
33
|
@hooks = {
|
28
|
-
:build
|
29
|
-
:tests
|
30
|
-
:before
|
31
|
-
:
|
32
|
-
:
|
34
|
+
:build => [],
|
35
|
+
:tests => [],
|
36
|
+
:before => [],
|
37
|
+
:success => [],
|
38
|
+
:failure => [],
|
33
39
|
}
|
34
40
|
|
35
41
|
@hooks.keys.each do |key|
|
36
42
|
log :debug, "Loading #{key} hooks"
|
37
43
|
|
38
|
-
Dir[File.join(project.root, "hooks", key.to_s, "*")].each do |hook|
|
44
|
+
Dir[File.join(project.root, "hooks", key.to_s, "*")].sort.each do |hook|
|
39
45
|
next if File.directory? hook
|
40
46
|
next unless File.executable? hook
|
41
47
|
|
42
48
|
log :debug, "Loaded hook: #{hook}"
|
43
49
|
|
44
|
-
@hooks[key] << Heidi::Hook.new(self
|
50
|
+
@hooks[key] << Heidi::Hook.new(self, hook)
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
@@ -49,13 +55,26 @@ class Heidi
|
|
49
55
|
end
|
50
56
|
|
51
57
|
def clean
|
52
|
-
|
58
|
+
1.downto(0) do |i|
|
59
|
+
if File.exists? "#{@log_root}.#{i}"
|
60
|
+
if i - 1 < 0
|
61
|
+
shell.mv %W(#{@log_root}.#{i} #{@log_root}.#{i+1})
|
62
|
+
else
|
63
|
+
shell.rm %W(-rf #{@log_root}.#{i})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if File.exists? "#{@log_root}"
|
69
|
+
shell.mv %W(#{@log_root} #{@log_root}.0)
|
70
|
+
end
|
71
|
+
|
72
|
+
%w(build/ SUCCESS FAILURE).each do |inode|
|
53
73
|
shell.rm("-r", "-f", inode) if File.exists? File.join(@root, inode)
|
54
74
|
end
|
55
|
-
end
|
56
75
|
|
57
|
-
|
58
|
-
|
76
|
+
# re-instate the logs
|
77
|
+
@shell.mkdir %W(-p #{@log_root})
|
59
78
|
end
|
60
79
|
|
61
80
|
def log(type, msg)
|
@@ -66,12 +85,7 @@ class Heidi
|
|
66
85
|
"heidi.#{type}"
|
67
86
|
end
|
68
87
|
|
69
|
-
|
70
|
-
File.join(@root, name),
|
71
|
-
File::CREAT|File::WRONLY|File::APPEND
|
72
|
-
) do |f|
|
73
|
-
f.puts "%s\t%s" % [ Time.now.strftime("%c"), msg ]
|
74
|
-
end
|
88
|
+
logs[name].write(msg)
|
75
89
|
end
|
76
90
|
|
77
91
|
def lock_file
|
@@ -134,14 +148,56 @@ class Heidi
|
|
134
148
|
"DNF"
|
135
149
|
end
|
136
150
|
|
137
|
-
def logs(what)
|
138
|
-
File.read(File.join(@root, what))
|
139
|
-
rescue
|
140
|
-
""
|
141
|
-
end
|
142
|
-
|
143
151
|
def create_tar_ball
|
144
152
|
# TODO
|
145
153
|
end
|
154
|
+
|
155
|
+
class Logs
|
156
|
+
def initialize(log_root)
|
157
|
+
@log_root = log_root
|
158
|
+
@logs = []
|
159
|
+
|
160
|
+
Dir[File.join(@log_root, "*")].each do |file|
|
161
|
+
@logs << Log.new(file)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def [](key)
|
166
|
+
log = @logs.select { |log| log.file_name == "#{key}" }.first
|
167
|
+
if log.nil?
|
168
|
+
@logs << ( log = Log.new( File.join(@log_root, "#{key}") ) )
|
169
|
+
end
|
170
|
+
|
171
|
+
return log
|
172
|
+
end
|
173
|
+
|
174
|
+
def each(&block)
|
175
|
+
@logs.each(&block)
|
176
|
+
end
|
177
|
+
|
178
|
+
class Log
|
179
|
+
attr_reader :file_name, :contents
|
180
|
+
def initialize(file)
|
181
|
+
@file = file
|
182
|
+
@file_name = File.basename(file)
|
183
|
+
@contents = File.read(file) rescue ""
|
184
|
+
end
|
185
|
+
|
186
|
+
def write(msg,fmt=true)
|
187
|
+
File.open(@file, File::CREAT|File::APPEND|File::WRONLY) do |f|
|
188
|
+
if fmt == true
|
189
|
+
f.puts "%s\t%s" % [ Time.now.strftime("%c"), msg ]
|
190
|
+
else
|
191
|
+
f.puts msg
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def raw(msg)
|
197
|
+
write(msg, false)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
146
202
|
end
|
147
|
-
end
|
203
|
+
end
|
data/lib/heidi/builder.rb
CHANGED
@@ -21,12 +21,12 @@ class Heidi
|
|
21
21
|
res = hook.perform(build.build_root)
|
22
22
|
if res.S?.to_i != 0
|
23
23
|
log("--- Build hook #{hook.name} failed ---")
|
24
|
-
log(res.err)
|
24
|
+
log(res.err.empty? ? "no error message given" : res.err)
|
25
25
|
build_failed = true
|
26
26
|
break
|
27
27
|
|
28
28
|
else
|
29
|
-
log(res.out)
|
29
|
+
log(res.out) unless res.out.empty?
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -83,12 +83,7 @@ class Heidi
|
|
83
83
|
|
84
84
|
|
85
85
|
def log(string)
|
86
|
-
|
87
|
-
File.join(project.log_root, "builder.log"),
|
88
|
-
File::CREAT|File::WRONLY|File::APPEND
|
89
|
-
) do |f|
|
90
|
-
f.puts string
|
91
|
-
end
|
86
|
+
build.logs["builder.log"].raw(string)
|
92
87
|
end
|
93
88
|
|
94
89
|
end
|
data/lib/heidi/hook.rb
CHANGED
@@ -2,13 +2,19 @@ require 'simple_shell'
|
|
2
2
|
|
3
3
|
class Heidi
|
4
4
|
class Hook
|
5
|
-
|
6
|
-
|
7
|
-
@
|
5
|
+
attr_reader :build
|
6
|
+
def initialize(build, script)
|
7
|
+
@build = build
|
8
|
+
@script = script
|
8
9
|
end
|
9
10
|
|
10
|
-
def perform(where)
|
11
|
-
|
11
|
+
def perform(where=build.build_root)
|
12
|
+
env = {
|
13
|
+
'HEIDI_LOG_DIR' => build.log_root,
|
14
|
+
'HEIDI_BUILD_DIR' => build.build_root,
|
15
|
+
}
|
16
|
+
|
17
|
+
shell = SimpleShell.new(where, env)
|
12
18
|
res = shell.do @script
|
13
19
|
return res
|
14
20
|
end
|
data/lib/heidi/tester.rb
CHANGED
@@ -24,14 +24,14 @@ class Heidi
|
|
24
24
|
|
25
25
|
if res.S?.to_i != 0
|
26
26
|
log "--- test #{hook.name} failed ---"
|
27
|
-
log res.err
|
27
|
+
log(res.err.empty? ? "No error message given" : res.err)
|
28
28
|
|
29
29
|
@message = "tests failed"
|
30
30
|
tests_failed = true
|
31
31
|
break
|
32
32
|
|
33
33
|
else
|
34
|
-
log res.out
|
34
|
+
log(res.out) unless res.out.empty?
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -39,12 +39,7 @@ class Heidi
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def log(string)
|
42
|
-
|
43
|
-
File.join(build.root, "test.log"),
|
44
|
-
File::CREAT|File::WRONLY|File::APPEND
|
45
|
-
) do |f|
|
46
|
-
f.puts string
|
47
|
-
end
|
42
|
+
build.logs["test.log"].raw(string)
|
48
43
|
end
|
49
44
|
|
50
45
|
|
@@ -0,0 +1,93 @@
|
|
1
|
+
* {
|
2
|
+
margin: 0;
|
3
|
+
padding: 0;
|
4
|
+
}
|
5
|
+
|
6
|
+
html, body {
|
7
|
+
height: 100%;
|
8
|
+
}
|
9
|
+
|
10
|
+
body {
|
11
|
+
background-color: white;
|
12
|
+
font: 13.34px helvetica, arial, clean, sans-serif;
|
13
|
+
*font-size: small;
|
14
|
+
text-align: center;
|
15
|
+
}
|
16
|
+
|
17
|
+
h1, h2, h3 {
|
18
|
+
margin-bottom: 1em;
|
19
|
+
}
|
20
|
+
|
21
|
+
h1 a {
|
22
|
+
text-decoration: none;
|
23
|
+
color: #000;
|
24
|
+
}
|
25
|
+
|
26
|
+
.failed, .color31 {
|
27
|
+
color: red !important;
|
28
|
+
}
|
29
|
+
|
30
|
+
.passed, .worked, .color32 {
|
31
|
+
color: green !important;
|
32
|
+
}
|
33
|
+
|
34
|
+
.errored, .color33 {
|
35
|
+
color: yellow !important;
|
36
|
+
}
|
37
|
+
|
38
|
+
p {
|
39
|
+
margin: 1em 0;
|
40
|
+
}
|
41
|
+
|
42
|
+
a {
|
43
|
+
color: #00a;
|
44
|
+
}
|
45
|
+
|
46
|
+
a:hover {
|
47
|
+
color: black;
|
48
|
+
}
|
49
|
+
|
50
|
+
a:visited {
|
51
|
+
color: #a0a;
|
52
|
+
}
|
53
|
+
|
54
|
+
table {
|
55
|
+
font-size: inherit;
|
56
|
+
font: 100%;
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
.container {
|
61
|
+
width: 80%;
|
62
|
+
text-align: justify;
|
63
|
+
margin: 2em auto;
|
64
|
+
}
|
65
|
+
|
66
|
+
pre.terminal {
|
67
|
+
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
68
|
+
border: 1px solid black;
|
69
|
+
background-color: #333;
|
70
|
+
color: white;
|
71
|
+
padding: 5px;
|
72
|
+
overflow: auto;
|
73
|
+
word-wrap: break-word;
|
74
|
+
margin-bottom: 1em;
|
75
|
+
clear: both;
|
76
|
+
}
|
77
|
+
|
78
|
+
ul {
|
79
|
+
margin-left: 3em;
|
80
|
+
}
|
81
|
+
|
82
|
+
.top {
|
83
|
+
float: left;
|
84
|
+
padding-left: 2em;
|
85
|
+
}
|
86
|
+
|
87
|
+
.log {
|
88
|
+
float: left;
|
89
|
+
}
|
90
|
+
|
91
|
+
.clear {
|
92
|
+
clear: both;
|
93
|
+
}
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<h1><%= project.name %></h1>
|
2
|
+
|
3
|
+
<a href="/projects/<%= project.name %>"><< back</a>
|
4
|
+
<br /><br />
|
5
|
+
|
6
|
+
<h2 class="<%= build.status %>"><%= build.commit %></h2>
|
7
|
+
|
8
|
+
| <% build.logs.each do |log| %>
|
9
|
+
<a href="#<%= log.file_name %>"><%= log.file_name %></a> |
|
10
|
+
<% end %>
|
11
|
+
<br class="clear" />
|
12
|
+
<br />
|
13
|
+
<br />
|
14
|
+
|
15
|
+
<% build.logs.each do |log| %>
|
16
|
+
<h3 class="log"><%= log.file_name %></h3>
|
17
|
+
<a name="<%= log.file_name %>" href="#top" class="top">top</a>
|
18
|
+
<pre class="terminal"><%= ansi_color_codes(log.contents) %></pre>
|
19
|
+
<% end %>
|
20
|
+
<br /><br />
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<link rel="stylesheet" media="screen" href="/css/screen.css" />
|
5
|
+
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
|
6
|
+
<title>Heidi!</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<div class="container">
|
10
|
+
<%= yield %>
|
11
|
+
</div>
|
12
|
+
</body>
|
13
|
+
</html>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<h1><%= project.name %></h1>
|
2
|
+
|
3
|
+
<h2 class="<%= project.build_status %>"><%= project.build_status %></h2>
|
4
|
+
|
5
|
+
<h2>Build history</h2>
|
6
|
+
|
7
|
+
<ul>
|
8
|
+
<% project.builds.each do |build| %>
|
9
|
+
<li class="<%= build.status %>"><a href='/projects/<%= project.name %>/build/<%= build.commit %>'><%= build.commit %></a> - <%= build.status %></li>
|
10
|
+
<% end %>
|
11
|
+
</ul>
|
data/lib/heidi/web.rb
CHANGED
@@ -1,8 +1,75 @@
|
|
1
|
-
require 'sinatra'
|
2
|
-
require 'heidi
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'heidi'
|
3
|
+
require 'simple_shell'
|
3
4
|
|
4
5
|
class Heidi
|
5
|
-
|
6
|
-
|
6
|
+
class Web < Sinatra::Base
|
7
|
+
|
8
|
+
def self.start(host="0.0.0.0", port="4567", project_path=Dir.pwd)
|
9
|
+
@project_path = project_path
|
10
|
+
Heidi::Web.run! :host => host, :port => port
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.project_path
|
14
|
+
@project_path
|
15
|
+
end
|
16
|
+
|
17
|
+
before {
|
18
|
+
@heidi = Heidi.new(self.class.project_path)
|
19
|
+
}
|
20
|
+
|
21
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
22
|
+
$stderr.puts dir
|
23
|
+
|
24
|
+
set :sessions, true
|
25
|
+
|
26
|
+
set :views, "#{dir}/web/views"
|
27
|
+
set :public_folder, "#{dir}/web/public"
|
28
|
+
set :root, dir
|
29
|
+
|
30
|
+
get '/' do
|
31
|
+
redirect '/projects', 302
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/projects' do
|
35
|
+
erb(:home, { :locals => { :projects => @heidi.projects }})
|
36
|
+
end
|
37
|
+
|
38
|
+
get '/projects/:name' do
|
39
|
+
project = @heidi[params[:name]]
|
40
|
+
if project.nil?
|
41
|
+
return "no project by that name: #{params[:name]}"
|
42
|
+
end
|
43
|
+
|
44
|
+
erb(:project, { :locals => { :project => project }})
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/projects/:name/build/:commit' do
|
48
|
+
project = @heidi[params[:name]]
|
49
|
+
if project.nil?
|
50
|
+
return "no project by that name: #{params[:name]}"
|
51
|
+
end
|
52
|
+
|
53
|
+
# load build of project
|
54
|
+
build = Heidi::Build.new(project, params[:commit])
|
55
|
+
erb(:build, { :locals => { :build => build, :project => project }})
|
56
|
+
end
|
57
|
+
|
58
|
+
put '/projects/:name/build' do
|
59
|
+
project = $heidi[params[:name]]
|
60
|
+
if project.nil?
|
61
|
+
return "no project by that name: #{params[:name]}"
|
62
|
+
end
|
63
|
+
|
64
|
+
project.integrate
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
helpers do
|
69
|
+
def ansi_color_codes(string)
|
70
|
+
string.gsub("\e[0m", '</span>').
|
71
|
+
gsub(/\e\[(\d+)m/, "<span class=\"color\\1\">")
|
72
|
+
end
|
73
|
+
end
|
7
74
|
end
|
8
75
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heidi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-06 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thin
|
16
|
-
requirement: &
|
16
|
+
requirement: &78955270 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *78955270
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: sinatra
|
27
|
-
requirement: &
|
27
|
+
requirement: &78955000 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,21 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *78955000
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: sinatra-assetpack
|
38
|
+
requirement: &78954750 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *78954750
|
36
47
|
- !ruby/object:Gem::Dependency
|
37
48
|
name: simple_shell
|
38
|
-
requirement: &
|
49
|
+
requirement: &78954490 !ruby/object:Gem::Requirement
|
39
50
|
none: false
|
40
51
|
requirements:
|
41
52
|
- - ! '>='
|
@@ -43,10 +54,10 @@ dependencies:
|
|
43
54
|
version: '0'
|
44
55
|
type: :runtime
|
45
56
|
prerelease: false
|
46
|
-
version_requirements: *
|
57
|
+
version_requirements: *78954490
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: rspec
|
49
|
-
requirement: &
|
60
|
+
requirement: &78954240 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ~>
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: 2.8.0
|
55
66
|
type: :development
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *78954240
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: rdoc
|
60
|
-
requirement: &
|
71
|
+
requirement: &78950220 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ~>
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '3.12'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *78950220
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: bundler
|
71
|
-
requirement: &
|
82
|
+
requirement: &78949910 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ~>
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: 1.0.0
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *78949910
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: jeweler
|
82
|
-
requirement: &
|
93
|
+
requirement: &78949650 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ~>
|
@@ -87,10 +98,10 @@ dependencies:
|
|
87
98
|
version: 1.8.3
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *78949650
|
91
102
|
- !ruby/object:Gem::Dependency
|
92
103
|
name: rcov
|
93
|
-
requirement: &
|
104
|
+
requirement: &78949400 !ruby/object:Gem::Requirement
|
94
105
|
none: false
|
95
106
|
requirements:
|
96
107
|
- - ! '>='
|
@@ -98,7 +109,7 @@ dependencies:
|
|
98
109
|
version: '0'
|
99
110
|
type: :development
|
100
111
|
prerelease: false
|
101
|
-
version_requirements: *
|
112
|
+
version_requirements: *78949400
|
102
113
|
description: CI-Joe alike CI system called Heidi.
|
103
114
|
email: hartog@organisedminds.com
|
104
115
|
executables:
|
@@ -133,9 +144,12 @@ files:
|
|
133
144
|
- lib/heidi/project.rb
|
134
145
|
- lib/heidi/tester.rb
|
135
146
|
- lib/heidi/web.rb
|
136
|
-
- lib/heidi/web/
|
137
|
-
- lib/heidi/web/
|
138
|
-
- lib/heidi/web/
|
147
|
+
- lib/heidi/web/public/css/screen.css
|
148
|
+
- lib/heidi/web/public/images/heidi.jpeg
|
149
|
+
- lib/heidi/web/views/build.erb
|
150
|
+
- lib/heidi/web/views/home.erb
|
151
|
+
- lib/heidi/web/views/layout.erb
|
152
|
+
- lib/heidi/web/views/project.erb
|
139
153
|
- spec/heidi/build_spec.rb
|
140
154
|
- spec/heidi/builder_spec.rb
|
141
155
|
- spec/heidi/git_spec.rb
|
@@ -161,7 +175,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
175
|
version: '0'
|
162
176
|
segments:
|
163
177
|
- 0
|
164
|
-
hash:
|
178
|
+
hash: 785079379
|
165
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
180
|
none: false
|
167
181
|
requirements:
|
@@ -1,61 +0,0 @@
|
|
1
|
-
class Heidi; module Web; module Routes
|
2
|
-
|
3
|
-
module Projects
|
4
|
-
get '/projects' do
|
5
|
-
output = ""
|
6
|
-
$heidi.projects.each do |project|
|
7
|
-
output += "<a href='/projects/#{project.name}'>#{project.name}</a><br />"
|
8
|
-
end
|
9
|
-
|
10
|
-
output
|
11
|
-
end
|
12
|
-
|
13
|
-
get '/projects/:name' do
|
14
|
-
project = $heidi[params[:name]]
|
15
|
-
if project.nil?
|
16
|
-
return "no project by that name: #{params[:name]}"
|
17
|
-
end
|
18
|
-
|
19
|
-
output = "<h1>#{project.name}</h1>"
|
20
|
-
output += "Build status: #{project.build_status}"
|
21
|
-
output += "<br /><br /><h2>Build history</h2>"
|
22
|
-
project.builds.each do |build|
|
23
|
-
output += %Q{<a href="/projects/#{project.name}/build/#{build.commit}">#{build.commit}</a> - #{build.status}<br />}
|
24
|
-
end
|
25
|
-
|
26
|
-
output
|
27
|
-
end
|
28
|
-
|
29
|
-
get '/projects/:name/build/:commit' do
|
30
|
-
project = $heidi[params[:name]]
|
31
|
-
if project.nil?
|
32
|
-
return "no project by that name: #{params[:name]}"
|
33
|
-
end
|
34
|
-
|
35
|
-
# load build of project
|
36
|
-
build = Heidi::Build.new(project, params[:commit])
|
37
|
-
output = "<h1>#{project.name}</h1>"
|
38
|
-
output += "<h2>Build: #{build.commit} - #{build.status}<h2>"
|
39
|
-
|
40
|
-
%w(heidi.info heidi.errors build.log test.log).each do |log_file|
|
41
|
-
log = build.logs(log_file)
|
42
|
-
if (!log.nil? and !log.empty?)
|
43
|
-
output += "<h3>#{log_file}</h3>"
|
44
|
-
output += "<pre>#{log}</pre>"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
output
|
49
|
-
end
|
50
|
-
|
51
|
-
put '/projects/:name/build' do
|
52
|
-
project = $heidi[params[:name]]
|
53
|
-
if project.nil?
|
54
|
-
return "no project by that name: #{params[:name]}"
|
55
|
-
end
|
56
|
-
|
57
|
-
project.integrate
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
end; end; end
|
data/lib/heidi/web/routes.rb
DELETED