heidi 0.1.2 → 0.2.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
data/bin/heidi CHANGED
@@ -32,7 +32,7 @@ when "new"
32
32
 
33
33
  puts "running bundle install"
34
34
  shell.in(for_a) do |sh|
35
- sh.bundle "install"
35
+ sh.bundle "install --binstubs --deployment"
36
36
  end
37
37
 
38
38
  when "project"
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.1.2"
8
+ s.version = "0.2.0"
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-08"
12
+ s.date = "2012-02-09"
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"]
data/lib/heidi/build.rb CHANGED
@@ -4,7 +4,7 @@ require 'time'
4
4
  class Heidi
5
5
  # An integration is called a build.
6
6
  # The collections of builds is the log of the project.
7
- # A single build lives in $project/logs
7
+ # A single build lives in $project/
8
8
  # A build is tied to a commit
9
9
  #
10
10
  class Build
@@ -28,6 +28,14 @@ class Heidi
28
28
  @logs = Logs.new(@log_root)
29
29
  end
30
30
 
31
+ def author
32
+ project.author(@commit)
33
+ end
34
+
35
+ def date
36
+ project.date(@commit)
37
+ end
38
+
31
39
  def load_hooks
32
40
  log :info, "Loading hooks"
33
41
  @hooks = {
@@ -77,7 +85,7 @@ class Heidi
77
85
  @shell.mkdir %W(-p #{@log_root})
78
86
  end
79
87
 
80
- def log(type, msg)
88
+ def log(type, msg, raw=false)
81
89
  name = case type
82
90
  when :error
83
91
  "heidi.errors"
@@ -85,7 +93,7 @@ class Heidi
85
93
  "heidi.#{type}"
86
94
  end
87
95
 
88
- logs[name].write(msg)
96
+ logs[name].send(raw == false ? :write : :raw, msg)
89
97
  end
90
98
 
91
99
  def lock_file
@@ -177,7 +185,8 @@ class Heidi
177
185
  end
178
186
 
179
187
  def each(&block)
180
- @logs.each(&block)
188
+ heidi = @logs.select { |l| l.file_name =~ /heidi/ }
189
+ (heidi + (@logs - heidi)).each(&block)
181
190
  end
182
191
 
183
192
  class Log
data/lib/heidi/builder.rb CHANGED
@@ -11,32 +11,7 @@ class Heidi
11
11
  end
12
12
 
13
13
  def build!
14
- return false if self.setup_build_dir != true
15
-
16
- if build.hooks[:build].any?
17
- build_failed = false
18
- build.hooks[:build].each do |hook|
19
- next if build_failed == true
20
-
21
- res = hook.perform(build.build_root)
22
- if res.S?.to_i != 0
23
- log("--- Build hook #{hook.name} failed ---")
24
- log(res.err.empty? ? "no error message given" : res.err)
25
- build_failed = true
26
- break
27
-
28
- else
29
- log(res.out) unless res.out.empty?
30
- end
31
- end
32
-
33
- if build_failed == true
34
- build.log :error, "Build failed, revert to build.log for details"
35
- return false
36
- end
37
- end
38
-
39
- return true
14
+ return self.setup_build_dir
40
15
  end
41
16
 
42
17
  def setup_build_dir
@@ -83,7 +58,7 @@ class Heidi
83
58
  def create_tar_ball
84
59
  shell = SimpleShell.new(build.root)
85
60
  shell.mv %W(build #{build.commit})
86
- tar = shell.tar %W(-cjf #{build.commit}.tar.bz2 #{build.commit})
61
+ tar = shell.tar %W(--exclude .git -cjf #{build.commit}.tar.bz2 #{build.commit})
87
62
  if tar.S?.to_i == 0
88
63
  shell.rm %W(-rf #{build.commit}/)
89
64
  else
data/lib/heidi/git.rb CHANGED
@@ -100,6 +100,24 @@ class Heidi
100
100
  @shell.system(*command)
101
101
  end
102
102
 
103
+ def log(amount, format=nil, commit=nil)
104
+ args = %W(log -n#{amount})
105
+
106
+ if !format.nil? && format !~ /\%/
107
+ commit = format
108
+ format = nil
109
+ end
110
+
111
+ args << "--pretty=#{format}" unless format.nil?
112
+ args << commit unless commit.nil?
113
+
114
+ @shell.git(args).out
115
+ end
116
+
117
+ def graph(amount=40)
118
+ @shell.git %W(log -n#{amount} --color --graph --pretty=oneline --abbrev-commit)
119
+ end
120
+
103
121
  # git config $key $value
104
122
  def []=(key, value)
105
123
  @shell.system("git", "config", "heidi.#{key}", value)
data/lib/heidi/hook.rb CHANGED
@@ -14,21 +14,49 @@ class Heidi
14
14
  where = build.root
15
15
  end
16
16
 
17
+ start = Time.now
17
18
  env = {
18
- 'HEIDI_LOG_DIR' => build.log_root,
19
- 'HEIDI_BUILD_DIR' => where,
19
+ 'HEIDI_LOG_DIR' => build.log_root,
20
+ 'HEIDI_BUILD_DIR' => where,
21
+ 'HEIDI_BUILD_COMMIT' => build.commit,
22
+
20
23
  'RUBYOPT' => nil,
21
24
  'BUNDLE_BIN_PATH' => nil,
22
25
  'BUNDLE_GEMFILE' => nil,
26
+ 'GEM_HOME' => nil,
27
+ 'GEM_PATH' => nil,
23
28
  }
24
29
 
25
30
  shell = SimpleShell.new(where, env)
26
- res = shell.do @script
27
- return res
31
+ @res = shell.do @script
32
+
33
+ return @res
34
+ end
35
+
36
+ def message
37
+ @res.err.empty? ?
38
+ @res.out.empty? ?
39
+ "No error message given" :
40
+ @res.out :
41
+ @res.err
42
+ end
43
+
44
+ def output
45
+ @res.out.empty? ?
46
+ @res.err.empty? ?
47
+ "No output" :
48
+ @res.err :
49
+ @res.out
50
+ end
51
+
52
+ def failed?
53
+ @res.S?.to_i != 0
54
+ rescue
55
+ false
28
56
  end
29
57
 
30
58
  def name
31
- File.basename(@script)
59
+ File.join(File.basename(File.dirname(@script)), File.basename(@script))
32
60
  end
33
61
  end
34
62
  end
@@ -43,10 +43,12 @@ class Heidi
43
43
  return failure if !run_hooks(:before)
44
44
 
45
45
  builder = Heidi::Builder.new(build)
46
- tester = Heidi::Tester.new(build)
47
-
48
46
  return failure if !builder.build!
47
+ return failure if !run_hooks(:build)
48
+
49
+ tester = Heidi::Tester.new(build)
49
50
  return failure if !tester.test!
51
+ return failure if !run_hooks(:tests)
50
52
 
51
53
  return failure if !run_hooks(:success)
52
54
 
@@ -62,7 +64,7 @@ class Heidi
62
64
  return $!
63
65
 
64
66
  ensure
65
- run_hooks(:failed) if @failed == true
67
+ run_hooks(:failure) if @failed == true
66
68
 
67
69
  # always unlock the build root, no matter what
68
70
  build.unlock
@@ -75,18 +77,24 @@ class Heidi
75
77
 
76
78
  hooks_failed = false
77
79
  build.hooks[where].each do |hook|
78
- res = hook.perform
80
+ start = Time.now
81
+ build.log :info, "Running #{hook.name} :"
82
+
83
+ hook.perform
79
84
 
80
- if res.S?.to_i != 0
81
- build.log :error, "--- #{where} hook: #{hook.name} failed ---"
82
- build.log :error, res.err
85
+ if hook.failed?
86
+ build.log :info, "\tfailed. See heidi.error"
87
+ build.log :error, "--- #{hook.name}: failed ---"
88
+ build.log :error, hook.message, true
83
89
 
84
90
  hooks_failed = true
85
91
  break
86
92
 
87
93
  else
88
- build.log :info, res.out
94
+ build.log :info, "#{hook.output.lines.collect { |l| "\t#{l}" }.join("")}", true
89
95
  end
96
+
97
+ build.log(:info, ("Took %.2fs" % (Time.now-start)))
90
98
  end
91
99
 
92
100
  @hooks_ran << where
data/lib/heidi/project.rb CHANGED
@@ -5,14 +5,17 @@ require 'time'
5
5
 
6
6
  class Heidi
7
7
  class Project
8
- attr_reader :root, :cached_root, :lock_file, :builds
8
+ attr_reader :root, :cached_root, :lock_file
9
9
 
10
10
  def initialize(root)
11
11
  @root = root
12
12
  @lock_file = File.join(root, ".lock")
13
13
  @cached_root = File.join(root, "cached")
14
14
  @git = Heidi::Git.new(@cached_root)
15
- load_builds
15
+ end
16
+
17
+ def builds
18
+ @builds || load_builds
16
19
  end
17
20
 
18
21
  def load_builds
@@ -27,9 +30,11 @@ class Heidi
27
30
  return nil unless commit.length >= 5
28
31
 
29
32
  self.select do |build|
30
- build.commit == commit || build.commit =~ Regexp.new(commit)
33
+ build.commit == commit || build.commit =~ Regexp.new("^#{commit}")
31
34
  end.first
32
35
  end
36
+
37
+ return @builds
33
38
  end
34
39
 
35
40
  def name=(name)
@@ -45,6 +50,14 @@ class Heidi
45
50
  @git.commit[0..8]
46
51
  end
47
52
 
53
+ def author(commit=self.commit)
54
+ @git.log(1, "%cN <%cE>", commit)
55
+ end
56
+
57
+ def date(commit=self.commit)
58
+ @git.log(1, "%ci", commit)
59
+ end
60
+
48
61
  def last_commit
49
62
  @git["commit"]
50
63
  end
@@ -79,12 +92,13 @@ class Heidi
79
92
  end
80
93
 
81
94
  def integrate(forced=false)
82
- return "locked" if locked?
83
95
  return true if !forced && self.current_build == self.commit
96
+ return "locked" if locked?
84
97
 
85
98
  status = "unknown"
86
99
 
87
100
  self.lock do
101
+ record_current_build
88
102
  res = Heidi::Integrator.new(self).integrate
89
103
  if res == true
90
104
  status = nil
@@ -115,7 +129,6 @@ class Heidi
115
129
  # when the head has changed, update some stuff
116
130
  if last_commit != self.commit
117
131
  record_last_commit
118
- record_current_build
119
132
  end
120
133
  end
121
134
 
@@ -131,12 +144,12 @@ class Heidi
131
144
  end
132
145
 
133
146
  def log
134
- shell = SimpleShell.new(@cached_root)
135
- log = shell.git %W(log -n40 --color --graph --pretty=oneline --abbrev-commit)
147
+ log = @git.graph(120)
136
148
 
137
149
  lines = []
138
150
  log.out.lines.each do |line|
139
- commit = line.scan(/^[|*\s\e\[m\d]+(\w+)/).flatten.first
151
+ color_less = line.gsub(/\e\[[^m]+m/, '')
152
+ commit = color_less.scan(/^[\| \*]+ ([a-z0-9]+)/).flatten.first
140
153
  lines << { :line => line, :build => builds.find(commit) }
141
154
  end
142
155
 
data/lib/heidi/tester.rb CHANGED
@@ -11,37 +11,14 @@ class Heidi
11
11
  def test!
12
12
  build.log(:info, "Starting tests")
13
13
 
14
- tests_failed = false
15
-
16
14
  if build.hooks[:tests].empty?
17
15
  build.log(:error, "There are no test hooks")
18
16
  @message = "There are no test hooks"
19
17
  return false
20
18
  end
21
19
 
22
- build.hooks[:tests].each do |hook|
23
- res = hook.perform(build.build_root)
24
-
25
- if res.S?.to_i != 0
26
- log "--- test #{hook.name} failed ---"
27
- log(res.err.empty? ? "No error message given" : res.err)
28
-
29
- @message = "tests failed"
30
- tests_failed = true
31
- break
32
-
33
- else
34
- log(res.out) unless res.out.empty?
35
- end
36
- end
37
-
38
- return tests_failed ? false : true
39
- end
40
-
41
- def log(string)
42
- build.logs["test.log"].raw(string)
20
+ return true
43
21
  end
44
22
 
45
-
46
23
  end
47
24
  end
@@ -39,8 +39,8 @@ h1 a {
39
39
  text-decoration: line-through;
40
40
  }
41
41
 
42
- .color30 {
43
- color: black !important;
42
+ .DNF, .color30 {
43
+ color: #333 !important;
44
44
  }
45
45
 
46
46
  .failed, .color31 {
@@ -63,7 +63,7 @@ h1 a {
63
63
  color: purple !important;
64
64
  }
65
65
 
66
- .color36 {
66
+ .terminal .DNF, .color36 {
67
67
  color: aqua !important;
68
68
  }
69
69
 
@@ -102,7 +102,7 @@ h1 a {
102
102
  }
103
103
 
104
104
  .status {
105
- padding-left: 2em;
105
+ padding-left: 3em;
106
106
  }
107
107
 
108
108
  p {
@@ -110,7 +110,7 @@ p {
110
110
  }
111
111
 
112
112
  a {
113
- color: #00a;
113
+ color: #333;
114
114
  }
115
115
 
116
116
  a:hover {
@@ -118,7 +118,7 @@ a:hover {
118
118
  }
119
119
 
120
120
  a:visited {
121
- color: #a0a;
121
+ color: #333;
122
122
  }
123
123
 
124
124
  table {
@@ -9,21 +9,21 @@
9
9
  latest = builds.select { |b| b.commit == project.latest_build }.first
10
10
  %>
11
11
 
12
- <% unless current.nil? && latest.nil?%>
13
- <h2>Overview</h2>
14
- <strong class="label">Current</strong> :
12
+ <h2>Overview</h2>
13
+ <strong class="label">Current</strong> :
14
+ <% unless current.nil? %>
15
15
  <a class="<%= current.status %>" href="/projects/<%= project.name %>/build/<%= current.commit %>"><%= current.commit %></a>
16
- <br />
17
- <strong class="label">Latest successful</strong> :
16
+ <% end %>
17
+ <br />
18
+ <strong class="label">Latest successful</strong> :
19
+ <% unless latest.nil? %>
18
20
  <a class="<%= latest.status %>" href="/projects/<%= project.name %>/build/<%= latest.commit %>"><%= latest == current ? "current" : latest.commit %></a>
19
- <br />
20
- <br />
21
- <br />
22
21
  <% end %>
22
+ <br />
23
+ <br />
24
+ <br />
23
25
 
24
26
  <h2>Build history</h2>
25
- <div class="column">
26
- <pre class="terminal"><% project.log.each do |line| %><% build = nil; if (build = line[:build]) %><a href="/projects/<%= project.name %>/build/<%= build.commit %>"><%= ansi_color_codes(line[:line]).chomp %></a> <span class="status">[<span class="<%= build.status %>"><%= build.status %></span>]</span>
27
+ <pre style="width: 75%" class="terminal"><% project.log.each do |line| %><% build = nil; if (build = line[:build]) %><a title="<%= build.author %>" href="/projects/<%= project.name %>/build/<%= build.commit %>"><%= ansi_color_codes(line[:line]).chomp %></a> <span class="status">[<span class="<%= build.status %>"><%= build.status %></span>] (<%= build.date %>, <%= build.author.gsub '<', '&lt;' %>)</span>
27
28
  <% else %><%= ansi_color_codes line[:line] %>
28
29
  <% end %><% end %></pre>
29
- </div>
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.1.2
4
+ version: 0.2.0
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-08 00:00:00.000000000Z
12
+ date: 2012-02-09 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thin
16
- requirement: &86199260 !ruby/object:Gem::Requirement
16
+ requirement: &85154280 !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: *86199260
24
+ version_requirements: *85154280
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sinatra
27
- requirement: &86198960 !ruby/object:Gem::Requirement
27
+ requirement: &85153980 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *86198960
35
+ version_requirements: *85153980
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: simple_shell
38
- requirement: &86198610 !ruby/object:Gem::Requirement
38
+ requirement: &85153630 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *86198610
46
+ version_requirements: *85153630
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &86198320 !ruby/object:Gem::Requirement
49
+ requirement: &85153340 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.8.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *86198320
57
+ version_requirements: *85153340
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rdoc
60
- requirement: &86198000 !ruby/object:Gem::Requirement
60
+ requirement: &85153020 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '3.12'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *86198000
68
+ version_requirements: *85153020
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
- requirement: &86193660 !ruby/object:Gem::Requirement
71
+ requirement: &85148650 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 1.0.0
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *86193660
79
+ version_requirements: *85148650
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: jeweler
82
- requirement: &86193270 !ruby/object:Gem::Requirement
82
+ requirement: &85148280 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 1.8.3
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *86193270
90
+ version_requirements: *85148280
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rcov
93
- requirement: &86192970 !ruby/object:Gem::Requirement
93
+ requirement: &85147950 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *86192970
101
+ version_requirements: *85147950
102
102
  description: CI-Joe alike CI system called Heidi.
103
103
  email: hartog@organisedminds.com
104
104
  executables:
@@ -164,7 +164,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
164
164
  version: '0'
165
165
  segments:
166
166
  - 0
167
- hash: -593404611
167
+ hash: -232203085
168
168
  required_rubygems_version: !ruby/object:Gem::Requirement
169
169
  none: false
170
170
  requirements: