ciquantum 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,6 +43,7 @@ Choice.options do
43
43
  exit
44
44
  end
45
45
  end
46
+
46
47
  end
47
48
 
48
49
  options = Choice.choices
@@ -5,6 +5,7 @@ require 'ciquantum/unfuddle'
5
5
  require 'ciquantum/unfuddle/changeset'
6
6
  require 'ciquantum/utils/mailer'
7
7
  require 'ciquantum/utils/coverage_merger'
8
+ require 'ciquantum/git'
8
9
  require 'ciquantum/commit'
9
10
  require 'ciquantum/build'
10
11
  require 'ciquantum/server'
@@ -1,7 +1,7 @@
1
1
  require 'yaml'
2
2
 
3
3
  module CIQuantum
4
- class Build < Struct.new(:project_path, :user, :project, :started_at, :finished_at, :sha, :status, :output, :pid, :branch)
4
+ class Build < Struct.new(:project_path, :started_at, :finished_at, :sha, :status, :output, :pid, :branch)
5
5
  def initialize(*args)
6
6
  super
7
7
  self.started_at ||= Time.now
@@ -30,7 +30,7 @@ module CIQuantum
30
30
  end
31
31
 
32
32
  def id
33
- "#{sha}-#{finished_at.to_i}"
33
+ finished_at.to_i.to_s
34
34
  end
35
35
 
36
36
  def short_sha
@@ -52,7 +52,7 @@ module CIQuantum
52
52
 
53
53
  def commit
54
54
  return if sha.nil?
55
- @commit ||= Commit.new(sha, user, project, project_path)
55
+ @commit ||= Commit.new(sha, project_path)
56
56
  end
57
57
 
58
58
  def test_results
@@ -68,7 +68,7 @@ module CIQuantum
68
68
  end
69
69
 
70
70
  def dump file
71
- config = [user, project, started_at, finished_at, sha, status, output, pid, branch]
71
+ config = [started_at, finished_at, sha, status, output, pid, branch]
72
72
  data = YAML.dump(config)
73
73
  File.open(file, 'wb') { |io| io.write(data) }
74
74
  end
@@ -1,7 +1,10 @@
1
1
  module CIQuantum
2
- class Commit < Struct.new(:sha, :user, :project, :project_path)
3
- def url
4
- Unfuddle.commit_url self
2
+ class Commit < Struct.new(:sha, :project_path)
3
+
4
+ attr_reader :url
5
+
6
+ def get_url! adapter
7
+ @url = adapter.commit_url self
5
8
  end
6
9
 
7
10
  def author
@@ -11,6 +11,10 @@ module CIQuantum
11
11
  end
12
12
 
13
13
  def method_missing(command, *args)
14
+ self[command]
15
+ end
16
+
17
+ def [](command)
14
18
  Config.new(command, @project_path, self)
15
19
  end
16
20
 
@@ -2,24 +2,26 @@ require 'fileutils'
2
2
 
3
3
  module CIQuantum
4
4
  class Core
5
- attr_reader :user
6
- attr_reader :project
5
+ attr_reader :adapter
7
6
  attr_reader :url
8
7
  attr_reader :current_build
9
8
  attr_reader :last_build
10
9
  attr_reader :projectname
11
10
  attr_reader :coverage_path
11
+ attr_reader :git
12
+ attr_reader :is_building
12
13
  attr_accessor :shared_path
13
14
 
14
- HistoryLimit = 10
15
+ HistoryLimit = 20
15
16
 
16
17
  def initialize(project_path)
18
+ @is_building = false
17
19
  @project_path = File.expand_path(project_path)
20
+ @adapter = Unfuddle.from_config(repo_config)
18
21
 
19
- @user, @project = git_user_and_project
20
- @url = project_url
21
22
  @projectname = repo_config.projectname.to_s
22
23
  @coverage_path = repo_config.coveragepath.to_s
24
+ @git = Git.new(@project_path)
23
25
 
24
26
  @last_build = nil
25
27
  @current_build = nil
@@ -28,23 +30,26 @@ module CIQuantum
28
30
  trap("INT") { stop }
29
31
  end
30
32
 
31
- # is a build running?
32
33
  def building?
33
34
  !!@current_build
34
35
  end
35
36
 
36
- # the pid of the running child process
37
37
  def pid
38
38
  building? and current_build.pid
39
39
  end
40
40
 
41
- # kill the child and exit
42
41
  def stop
43
- Process.kill(9, pid) if pid
42
+ stop_build
44
43
  exit!
45
44
  end
46
45
 
47
- # build callbacks
46
+ def stop_build
47
+ @is_building = false
48
+ Process.kill(9, @current_build.pid) if @current_build && @current_build.pid
49
+ write_build 'current', nil
50
+ @current_build = nil
51
+ end
52
+
48
53
  def build_failed(output, error)
49
54
  finish_build :failed, "#{error}\n\n#{output}"
50
55
  run_hook "build-failed"
@@ -66,23 +71,28 @@ module CIQuantum
66
71
  write_last_build
67
72
  run_hook "postbuild"
68
73
  save_coverage_for_build @last_build
74
+ @is_building = false
69
75
 
70
76
  build(@queue.next_branch_to_build) if @queue.waiting?
71
77
  end
72
78
 
73
79
  def build(branch=nil)
80
+ branch ||= tracked_branch
81
+ puts "Preparing branch build with param:#{branch}"
74
82
  if building?
75
83
  @queue.append_unless_already_exists(branch)
76
- # leave anyway because a current build runs
77
84
  return
78
85
  end
79
- @current_build = Build.new(@project_path, @user, @project)
86
+
87
+ @is_building = true
88
+ @current_build = Build.new(@project_path)
80
89
  write_current_build
81
90
 
82
91
  Thread.new {
83
92
  build!(branch)
84
93
  }
85
94
 
95
+ @current_build = read_current_build
86
96
  end
87
97
 
88
98
  def open_pipe(cmd)
@@ -99,14 +109,13 @@ module CIQuantum
99
109
  yield read, pid
100
110
  end
101
111
 
102
- # update git then run the build
103
- def build!(branch=nil)
104
- @git_branch = branch
112
+ def build!(branch)
105
113
  build = @current_build
106
- git_update
114
+ update_tracked_branch branch
115
+ @current_build = read_current_build
107
116
  output = ''
108
- build.sha = git_sha
109
- build.branch = git_branch
117
+ build.sha = @git.sha
118
+ build.branch = @git.branch
110
119
  write_build 'current', build
111
120
  run_hook "prebuild"
112
121
 
@@ -135,26 +144,13 @@ module CIQuantum
135
144
  runner == '' ? "rake -s --color test:units" : runner
136
145
  end
137
146
 
138
- def git_update
139
- `cd #{@project_path} && git fetch origin && git reset --hard origin/#{git_branch} && git submodule update --init`
140
- run_hook "after-reset"
141
- end
142
-
143
- def git_user_and_project
144
- config = repo_config.send Unfuddle.name
145
- Unfuddle.git_user_and_project config
146
- end
147
-
148
- def project_url
149
- Unfuddle.project_url @user, @project
150
- end
151
-
152
147
  # massage our repo
153
148
  def run_hook(hook)
154
149
  file = path_in_project(".git/hooks/#{hook}")
155
150
  if File.exists?(file) && File.executable?(file)
156
151
  data =
157
152
  if @last_build && @last_build.commit
153
+ @last_build.commit.get_url! @adapter
158
154
  {
159
155
  "MESSAGE" => @last_build.commit.message,
160
156
  "AUTHOR" => @last_build.commit.author,
@@ -178,7 +174,6 @@ module CIQuantum
178
174
  end
179
175
  end
180
176
 
181
- # restore current / last build state from disk.
182
177
  def restore
183
178
  @last_build = read_last_build
184
179
  @current_build = read_current_build
@@ -217,27 +212,16 @@ module CIQuantum
217
212
  Config.ciquantum(@project_path)
218
213
  end
219
214
 
220
- def swith_branch branch
221
- repo_config.branch.set branch if git_branches.include? branch
222
- end
223
-
224
- def git_branches
225
- branches = `cd #{@project_path} && git branch -r`.split("\n")
226
- branches.collect{|s| s =~ /(?:\s|^)origin\/(?!HEAD)(\w+)(?:\s|$)/ ? $1.strip : nil}.compact
215
+ def update_tracked_branch branch
216
+ new_branch = branch.strip
217
+ repo_config.branch.set new_branch
218
+ @tracked_branch = new_branch
219
+ @git.checkout new_branch
227
220
  end
228
221
 
229
- def git_branch
230
- return @git_branch if @git_branch
222
+ def tracked_branch
231
223
  branch = repo_config.branch.to_s
232
- @git_branch = (branch == '' ? "master" : branch)
233
- end
234
-
235
- def is_current_git_branch? branch
236
- return branch.eql? git_branch
237
- end
238
-
239
- def git_sha
240
- `cd #{@project_path} && git rev-parse origin/#{git_branch}`.chomp
224
+ @tracked_branch ||= (branch.empty? ? "master" : branch.strip)
241
225
  end
242
226
 
243
227
  def read_build(name)
@@ -261,8 +245,8 @@ module CIQuantum
261
245
  old_builds.each do |build_file|
262
246
  build = read_build(build_file)
263
247
  active_builds << build
264
- if build.status == :worked
265
- remove_builds_from build
248
+ if build.status == :worked || active_builds.size >= HistoryLimit
249
+ remove_elder_builds build
266
250
  break
267
251
  end
268
252
  end
@@ -287,7 +271,7 @@ module CIQuantum
287
271
 
288
272
  def write_build(name, build)
289
273
  filename = path_in_project(".git/builds/#{name}")
290
- Dir.mkdir path_in_project('.git/builds') unless File.directory?(path_in_project('.git/builds'))
274
+ FileUtils.mkdir_p path_in_project('.git/builds')
291
275
  if build
292
276
  build.dump filename
293
277
  elsif File.exist?(filename)
@@ -295,7 +279,7 @@ module CIQuantum
295
279
  end
296
280
  end
297
281
 
298
- def remove_builds_from limit_build
282
+ def remove_elder_builds limit_build
299
283
  old_builds.each do |build_file|
300
284
  build = read_build(build_file)
301
285
  if build.finished_at < limit_build.finished_at
@@ -0,0 +1,64 @@
1
+ module CIQuantum
2
+ class Git < Struct.new(:path)
3
+
4
+ def exec command
5
+ puts "Executing git command: #{command}"
6
+ res = `#{command}`
7
+ puts "Result for git command:\n#{res}"
8
+ res
9
+ end
10
+
11
+ def sha
12
+ exec("cd #{path} && git rev-parse origin/#{branch}").chomp
13
+ end
14
+
15
+ def update
16
+ fetch
17
+ exec("cd #{path} && git reset --hard origin/#{branch} && git submodule update --init")
18
+ end
19
+
20
+ def branches
21
+ branches_to_list `cd #{path} && git branch -r`
22
+ end
23
+
24
+ def fetch
25
+ exec("cd #{path} && git fetch origin")
26
+ end
27
+
28
+ def branch
29
+ if !@branch && exec("cd #{path} && git branch 2>/dev/null | grep -e '\*' ") =~ /^\*\s(\w+)/
30
+ @branch = $1.strip
31
+ end
32
+ @branch
33
+ end
34
+
35
+ def is_current_branch? other_branch
36
+ return branch.eql? other_branch
37
+ end
38
+
39
+ def checkout other_branch
40
+ unless is_current_branch?(other_branch)
41
+ fetch
42
+ exec("cd #{path} && git checkout #{other_branch}") if branches.include?(other_branch)
43
+ @branch = nil
44
+ end
45
+ update
46
+ end
47
+
48
+ def branches_with_commit commit_sha
49
+ fetch
50
+ branches_to_list exec("cd #{path} && git branch -r --contains #{commit_sha}")
51
+ end
52
+
53
+ def current_branch_contains_commit? commit_sha
54
+ branches_with_commit(commit_sha).include?(branch)
55
+ end
56
+
57
+ private
58
+ def branches_to_list branch_output
59
+ raw_branches = branch_output.split("\n")
60
+ raw_branches.collect{|s| s =~ /^\s*(?:origin\/)?(\w+)\s*$/ ? $1.strip : nil}.compact.uniq
61
+ end
62
+
63
+ end
64
+ end
@@ -53,13 +53,20 @@ module CIQuantum
53
53
  end
54
54
 
55
55
  post '/build' do
56
- quantum.build quantum.git_branch
56
+ puts "Building!"
57
+ quantum.build
57
58
  redirect '/'
58
59
  end
59
60
 
60
61
  post '/switch_branch' do
61
- quantum.swith_branch params[:branch]
62
- quantum.build params[:branch]
62
+ puts "Switching branch! params: #{params.inspect}"
63
+ quantum.build params[:branch].strip
64
+ redirect '/'
65
+ end
66
+
67
+ post '/cancel_build' do
68
+ puts "Stop build!"
69
+ quantum.stop_build
63
70
  redirect '/'
64
71
  end
65
72
 
@@ -78,7 +85,9 @@ module CIQuantum
78
85
  begin
79
86
  xml = request.body.read
80
87
  changeset = Unfuddle::Changeset.new(xml)
81
- quantum.build quantum.repo_config.branch
88
+ if quantum.git.current_branch_contains_commit? changeset.commit
89
+ quantum.build
90
+ end
82
91
  rescue Unfuddle::ChangesetError => e
83
92
  logger.error "[error] Changeset error: #{e.inspect}, Content: #{xml.inspect}"
84
93
  halt 400, "Changeset Error: #{e.message}"
@@ -1,20 +1,24 @@
1
1
  module CIQuantum
2
- module Unfuddle
2
+ class Unfuddle < Struct.new(:config)
3
3
 
4
- def self.name
5
- "unfuddle"
4
+ def self.config_name
5
+ 'unfuddle'
6
6
  end
7
7
 
8
- def self.commit_url commit
9
- "http://#{commit.user}.unfuddle.com/a#/repositories/#{commit.project}/commit?commit=#{commit.sha}"
8
+ def self.from_config config
9
+ self.new config[config_name]
10
10
  end
11
11
 
12
- def self.git_user_and_project config
13
- [ config.user, config.project ]
12
+ def commit_url commit
13
+ "http://#{config.user}.unfuddle.com/a#/repositories/#{config.project}/commit?commit=#{commit.sha}"
14
14
  end
15
15
 
16
- def self.project_url user, project
17
- "https://#{user}.unfuddle.com/a#/repositories/#{project}/browse"
16
+ def url
17
+ "https://#{config.user}.unfuddle.com/a#/repositories/#{config.project}/browse"
18
+ end
19
+
20
+ def [] command
21
+ return @config[command]
18
22
  end
19
23
 
20
24
  end
@@ -1,7 +1,7 @@
1
1
  require 'active_support/core_ext'
2
2
 
3
3
  module CIQuantum
4
- module Unfuddle
4
+ class Unfuddle
5
5
  class ChangesetError < StandardError ; end
6
6
 
7
7
  class Changeset
@@ -1,3 +1,3 @@
1
1
  module CIQuantum
2
- Version = VERSION = "0.0.16"
2
+ Version = VERSION = "0.0.17"
3
3
  end
@@ -12,7 +12,7 @@
12
12
  <% end %>
13
13
  <div class="results">
14
14
  <h4 class="result">Test results: <%= build.test_results %></h4>
15
- <a href="<%= quantum.coverage_for_build(build) %>">Show coverage</a> |
15
+ <a href="<%= quantum.coverage_for_build(build) %>">Show coverage</a> |
16
16
  <a href="#" onclick="toggleVisibility('<%= build.id %>')">Show output</a>
17
17
  <div id="<%= build.id %>" style="display:none">
18
18
  <pre class="terminal"><code><%= ansi_color_codes h(build.output) %></code></pre>
@@ -3,7 +3,7 @@
3
3
  <% if quantum.last_build %>
4
4
  {
5
5
  "name":"<%= quantum.projectname || quantum.project %>",
6
- "url":"<%= quantum.url %>",
6
+ "url":"<%= quantum.adapter.url %>",
7
7
  "color":"<%= quantum.last_build.status.to_s == "failed" ? 'red' : 'blue' %>",
8
8
  "status":"<%= quantum.last_build.status %>",
9
9
  "started_at":"<%= pretty_time(quantum.last_build.started_at) %>",
@@ -11,7 +11,7 @@
11
11
  "duration":"<%= quantum.last_build.duration if quantum.last_build.duration %>",
12
12
  "sha":"<%= quantum.last_build.sha %>",
13
13
  "short_sha":"<%= quantum.last_build.short_sha %>",
14
- "commit_url":"<%= quantum.last_build.commit.url if quantum.last_build.commit %>",
14
+ "commit_url":"<%= quantum.adapter_commit_url(quantum.last_build.commit) if quantum.last_build.commit %>",
15
15
  "branch":"<%= quantum.last_build.branch %>"
16
16
  }
17
17
  <% end %>
@@ -4,7 +4,7 @@
4
4
  <style type="text/css">
5
5
 
6
6
  .title {
7
- font-size: 120%;
7
+ font-size: 120%;
8
8
  font-family: Verdana, Arial, Helvetica, sans-serif;
9
9
  border: 1px solid black;
10
10
  margin: 10px 20px;
@@ -15,28 +15,32 @@
15
15
  <div id="home">
16
16
  <h1><a href="<%= quantum.url %>"><%= quantum.projectname %></a></h1>
17
17
  <ul class="posts">
18
- <% if quantum.current_build %>
18
+ <% if quantum.is_building %>
19
19
  <li>
20
- <span class="date"><%= pretty_time(quantum.current_build.started_at) if quantum.current_build %></span> &raquo;
21
- <% if quantum.current_build.sha %>
22
- Building <%= quantum.current_build.branch %> at <a href="<%= quantum.current_build.commit.url %>"><%= quantum.current_build.short_sha %></a> <small>(pid: <%= quantum.pid %>)</small>
23
- <% else %>
24
- Build starting...
25
- <% end %>
20
+ <span class="date"><%= pretty_time(quantum.current_build ? quantum.current_build.started_at : Time.now) %></span> &raquo;
21
+ Current branch: <%= quantum.git.branch %>.
22
+ <% if quantum.current_build %>
23
+ Building <%= quantum.current_build.branch %> at <a href="<%= quantum.current_build.commit.url %>"><%= quantum.current_build.short_sha %></a> <small>(pid: <%= quantum.pid %>)</small>
24
+ <% else %>
25
+ Build starting...
26
+ <% end %>
27
+ <form method="POST" action="/cancel_build">
28
+ <input type="submit" name="cancel" value="Cancel"/>
29
+ </form>
26
30
  </li>
27
31
  <% else %>
28
32
  <li>
29
33
  <form method="POST" action="/build">
30
- <span class="branch">Current branch: <%= quantum.git_branch %></span>
31
- <input type="submit" name="switch" value="Build"/>
34
+ <span class="branch">Current branch: <%= quantum.git.branch %></span>
35
+ <input type="submit" name="build" value="Build"/>
32
36
  </form>
33
37
  </li>
34
38
  <li>
35
39
  <% if can_change_branch %>
36
40
  <form method="POST" action="/switch_branch">
37
41
  <select name="branch">
38
- <% for @branch in quantum.git_branches %>
39
- <option value="<%= @branch %>" <%= 'selected="selected"' if quantum.is_current_git_branch?(@branch) %>>"<%= @branch %>"</option>
42
+ <% for @branch in quantum.git.branches %>
43
+ <option value="<%= @branch %>" <%= 'selected="selected"' if quantum.git.is_current_branch?(@branch.strip) %>>"<%= @branch %>"</option>
40
44
  <% end %>
41
45
  </select>
42
46
  <input type="submit" name="switch" value="Switch branch and build"/>
@@ -45,8 +49,9 @@
45
49
  </li>
46
50
  <% end %>
47
51
 
48
- <% if ! quantum.active_builds.empty?%>
49
- <% for @build in quantum.active_builds %>
52
+ <% builds = quantum.active_builds %>
53
+ <% if ! builds.empty?%>
54
+ <% for @build in builds %>
50
55
  <ul><%= erb(:build, {}, :quantum => quantum, :build => @build) %></ul>
51
56
  <% end %>
52
57
  <% end %>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ciquantum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.0.17
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-06-06 00:00:00.000000000 Z
14
+ date: 2012-06-22 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -197,6 +197,7 @@ files:
197
197
  - lib/ciquantum/commit.rb
198
198
  - lib/ciquantum/config.rb
199
199
  - lib/ciquantum/core.rb
200
+ - lib/ciquantum/git.rb
200
201
  - lib/ciquantum/public/javascript.js
201
202
  - lib/ciquantum/public/screen.css
202
203
  - lib/ciquantum/queue.rb