heidi 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: