ginst 2.0.1 → 2009.11.23
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +20 -21
- data/VERSION +1 -1
- data/app/controllers/application_controller.rb +1 -1
- data/app/controllers/status_controller.rb +10 -0
- data/app/controllers/tasks_controller.rb +9 -7
- data/app/helpers/projects_helper.rb +9 -4
- data/app/models/project.rb +38 -15
- data/app/models/task.rb +15 -3
- data/app/views/grit/commits/_commit.html.erb +3 -12
- data/app/views/layouts/projects.html.erb +1 -1
- data/app/views/status/show.html.erb +6 -1
- data/app/views/tasks/_task.html.erb +43 -26
- data/app/views/tasks/_task_item.html.erb +22 -0
- data/app/views/tasks/index.html.erb +3 -2
- data/app/views/tasks/show.html.erb +1 -46
- data/config/database.yml +4 -1
- data/config/environment.rb +4 -4
- data/config/routes.rb +1 -5
- data/ginst.gemspec +17 -18
- data/lib/ginst.rb +5 -2
- data/lib/ginst/builder.rb +2 -0
- data/lib/ginst/cli.rb +21 -44
- data/lib/ginst/console.rb +9 -0
- data/lib/ginst/ginst_template/webserver.ymlt +2 -0
- data/lib/ginst/logger.rb +31 -0
- data/lib/ginst/template.rb +1 -0
- data/lib/ginst/web_server.rb +28 -6
- data/log/development.log +49 -0
- data/public/stylesheets/screen.css +73 -38
- data/script/builder.rb +6 -1
- data/{features/step_definitions/ginst_steps.rb → tmp/.gittouch} +0 -0
- data/tmp/cache/.gittouch +0 -0
- data/tmp/pids/.gittouch +0 -0
- data/tmp/sessions/.gittouch +0 -0
- data/tmp/sockets/.gittouch +0 -0
- metadata +19 -17
- data/features/ginst.feature +0 -9
- data/features/support/env.rb +0 -4
- data/spec/ginst_spec.rb +0 -7
- data/spec/spec.opts +0 -1
- data/spec/spec_helper.rb +0 -9
data/Rakefile
CHANGED
@@ -17,9 +17,10 @@ begin
|
|
17
17
|
gem.homepage = "http://guillermo.github.com/ginst"
|
18
18
|
gem.authors = ["Guillermo Álvarez Fernández"]
|
19
19
|
gem.rubyforge_project = "ginst"
|
20
|
-
gem.add_development_dependency "rspec", ">= 1.2.9"
|
21
|
-
gem.add_development_dependency "cucumber", ">= 0"
|
22
20
|
gem.add_dependency "sys-proctable"
|
21
|
+
gem.add_dependency "mime-types"
|
22
|
+
gem.add_dependency "mongrel"
|
23
|
+
|
23
24
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
24
25
|
end
|
25
26
|
Jeweler::GemcutterTasks.new
|
@@ -30,32 +31,30 @@ rescue LoadError
|
|
30
31
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
31
32
|
end
|
32
33
|
|
33
|
-
require '
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
40
|
-
spec.libs << 'lib' << 'spec'
|
41
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
42
|
-
spec.rcov = true
|
34
|
+
require 'rake/testtask'
|
35
|
+
Rake::TestTask.new(:test) do |test|
|
36
|
+
test.libs << 'lib' << 'test' << 'app/*'
|
37
|
+
test.pattern = 'test/**/test_*.rb'
|
38
|
+
test.verbose = true
|
43
39
|
end
|
44
40
|
|
45
|
-
task :spec => :check_dependencies
|
46
|
-
|
47
41
|
begin
|
48
|
-
require '
|
49
|
-
|
50
|
-
|
51
|
-
|
42
|
+
require 'rcov/rcovtask'
|
43
|
+
Rcov::RcovTask.new do |test|
|
44
|
+
test.libs << 'lib' << 'test' << 'app/*'
|
45
|
+
test.pattern = 'test/**/test_*.rb'
|
46
|
+
test.verbose = true
|
47
|
+
end
|
52
48
|
rescue LoadError
|
53
|
-
task :
|
54
|
-
abort "
|
49
|
+
task :rcov do
|
50
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
55
51
|
end
|
56
52
|
end
|
57
53
|
|
58
|
-
task :
|
54
|
+
task :test => :check_dependencies
|
55
|
+
task :'test:integration' => [:install] # Integration test need the gem to be installed
|
56
|
+
|
57
|
+
task :default => :test
|
59
58
|
|
60
59
|
require 'rake/rdoctask'
|
61
60
|
Rake::RDocTask.new do |rdoc|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2009.11.23
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Filters added to this controller apply to all controllers in the application.
|
2
2
|
# Likewise, all the methods added will be available for all controllers.
|
3
|
-
|
3
|
+
|
4
4
|
class ApplicationController < ActionController::Base
|
5
5
|
helper :all
|
6
6
|
helper_method :current_user_session, :current_user
|
@@ -4,13 +4,16 @@ class TasksController < ApplicationController
|
|
4
4
|
|
5
5
|
|
6
6
|
def index
|
7
|
-
|
8
|
-
|
9
|
-
scope
|
10
|
-
|
11
|
-
|
12
|
-
@tasks = scope.all(:order => 'ended_at DESC')
|
7
|
+
if Task.valid_scopes.include?(params[:scope].try(:to_sym))
|
8
|
+
scope = @project.tasks
|
9
|
+
if params[:scope] && Task.valid_scopes.include?(params[:scope].to_sym)
|
10
|
+
scope = scope.send(params[:scope].to_sym)
|
11
|
+
end
|
13
12
|
|
13
|
+
@tasks = scope.all(:order => 'ended_at DESC')
|
14
|
+
else
|
15
|
+
redirect_to :scope => 'prepared'
|
16
|
+
end
|
14
17
|
end
|
15
18
|
|
16
19
|
def update
|
@@ -24,7 +27,6 @@ class TasksController < ApplicationController
|
|
24
27
|
end
|
25
28
|
|
26
29
|
def show
|
27
|
-
Task.first
|
28
30
|
@task = @project.tasks.find(params[:id])
|
29
31
|
|
30
32
|
respond_to do |wants|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ProjectsHelper
|
2
2
|
|
3
3
|
def show_branch_links
|
4
|
-
content_tag :ul, :
|
4
|
+
content_tag :ul, :class => 'submenu' do
|
5
5
|
@project.branchs.map{ |h|
|
6
6
|
content_tag :li do
|
7
7
|
link_to_unless params["branch"]==h.name, h.name,"?branch=#{h.name}"
|
@@ -10,9 +10,14 @@ module ProjectsHelper
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
13
|
+
def gravatar_img_for(commit,size = 30)
|
14
|
+
"<img class=\"avatar_#{size}\" src=\"#{gravatar_url_for(commit, size)}\" alt=\"#{commit.author.name}\" />"
|
15
|
+
end
|
16
|
+
|
17
|
+
def gravatar_url_for(email, size = 30)
|
18
|
+
email = email.author.email.strip.downcase unless email.kind_of? String
|
19
|
+
md5 = Digest::MD5.hexdigest(email)
|
20
|
+
"http://www.gravatar.com/avatar/#{md5}?s=#{size}"
|
16
21
|
end
|
17
22
|
|
18
23
|
def show_time(time)
|
data/app/models/project.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
class Project < ActiveRecord::Base
|
2
2
|
include Slugify
|
3
3
|
|
4
|
-
has_many :tasks, :order => 'system desc, priority ASC'
|
4
|
+
has_many :tasks, :order => 'updated_at desc, system desc, priority ASC'
|
5
5
|
delegate :prepared, :to => :tasks, :prefix => :tasks
|
6
6
|
|
7
|
-
after_create :create_setup_task
|
7
|
+
after_create :log_create, :create_setup_task
|
8
8
|
before_create :create_secret
|
9
9
|
|
10
10
|
validates_presence_of :name, :repo
|
@@ -24,8 +24,12 @@ class Project < ActiveRecord::Base
|
|
24
24
|
status == 'building'
|
25
25
|
end
|
26
26
|
|
27
|
+
def log_create
|
28
|
+
logger "#{name} project created for #{repo}"
|
29
|
+
end
|
27
30
|
|
28
31
|
def run_tasks!
|
32
|
+
logger "Running tasks"
|
29
33
|
if !:locked_at || !tasks_prepared.empty?
|
30
34
|
update_attribute(:locked_at, Time.current)
|
31
35
|
|
@@ -40,13 +44,16 @@ class Project < ActiveRecord::Base
|
|
40
44
|
|
41
45
|
|
42
46
|
def create_fetch_task
|
47
|
+
logger "creating fetch task"
|
43
48
|
current_fetch_task = tasks.unfinished.fetch_tasks.first
|
49
|
+
|
50
|
+
# Don't create another if one exists
|
44
51
|
return current_fetch_task if current_fetch_task
|
45
52
|
|
46
|
-
Rails.logger.debug "[#{Time.current.to_s(:small)}] * Creating
|
53
|
+
Rails.logger.debug "[#{Time.current.to_s(:small)}] * Creating fetch task for #{name}"
|
47
54
|
|
48
55
|
command = "cd #{local_repo_dir}
|
49
|
-
git fetch -
|
56
|
+
git fetch -fv origin
|
50
57
|
"
|
51
58
|
|
52
59
|
tasks.create(
|
@@ -57,20 +64,17 @@ class Project < ActiveRecord::Base
|
|
57
64
|
)
|
58
65
|
end
|
59
66
|
|
67
|
+
# call after fetch, to check if new commits exists
|
60
68
|
def process_new_heads
|
61
|
-
preferences.branch_status ||= {}
|
62
69
|
#look for changes in heads
|
63
70
|
branchs.each do |branch|
|
64
|
-
unless (branch.commit.id
|
71
|
+
unless tasks.find_by_commit_sha1(branch.commit.id)
|
65
72
|
process_new_head(branch)
|
66
|
-
preferences.branch_status[branch.name] = branch.commit.id
|
67
|
-
save
|
68
73
|
end
|
69
74
|
end
|
70
75
|
end
|
71
76
|
|
72
77
|
def process_new_head(branch)
|
73
|
-
logger.info("Processing new commit for #{branch.name}, #{branch.commit.id} ")
|
74
78
|
plugins.each do |plugin|
|
75
79
|
plugin.on_commit(self, branch) if plugin.respond_to? :on_commit
|
76
80
|
end
|
@@ -81,8 +85,7 @@ class Project < ActiveRecord::Base
|
|
81
85
|
end
|
82
86
|
|
83
87
|
def create_setup_task
|
84
|
-
|
85
|
-
|
88
|
+
logger "created setup task"
|
86
89
|
command = "
|
87
90
|
echo removing previous repo
|
88
91
|
rm -Rf #{local_repo_dir}
|
@@ -101,13 +104,13 @@ class Project < ActiveRecord::Base
|
|
101
104
|
:on_success => "p = Project.find(#{id}) ; p.set_default_tracking_branchs ; p.update_attribute(:status, 'prepared') "
|
102
105
|
)
|
103
106
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
+
|
108
|
+
|
107
109
|
def to_param
|
108
110
|
slug
|
109
111
|
end
|
110
|
-
|
112
|
+
|
113
|
+
|
111
114
|
def grit_repo
|
112
115
|
@grit_repo || Grit::Repo.new(local_repo_dir)
|
113
116
|
rescue Grit::NoSuchPathError
|
@@ -162,6 +165,10 @@ class Project < ActiveRecord::Base
|
|
162
165
|
grit_repo.commits(*args)
|
163
166
|
end
|
164
167
|
|
168
|
+
def commit(sha1)
|
169
|
+
grit_repo.commit(sha1)
|
170
|
+
end
|
171
|
+
|
165
172
|
def commits_between_dates(from,to)
|
166
173
|
grit_repo.commits_between_dates(from,to)
|
167
174
|
end
|
@@ -192,5 +199,21 @@ class Project < ActiveRecord::Base
|
|
192
199
|
Array.new(8).map{ keys[rand(keys.size)] }.join
|
193
200
|
end
|
194
201
|
|
202
|
+
|
203
|
+
def log_file
|
204
|
+
Ginst.data_dir+"/log/#{slug}.log"
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
def logger(msg = nil)
|
209
|
+
if msg
|
210
|
+
logger.log(msg, caller)
|
211
|
+
else
|
212
|
+
@logger ||= Ginst::Logger.new(log_file)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
|
195
218
|
end
|
196
219
|
|
data/app/models/task.rb
CHANGED
@@ -23,6 +23,8 @@ class Task < ActiveRecord::Base
|
|
23
23
|
|
24
24
|
named_scope :fetch_tasks, {:conditions => {:name => 'fetch.sh'}}
|
25
25
|
|
26
|
+
delegate :logger, :to => :project
|
27
|
+
|
26
28
|
def self.valid_scopes
|
27
29
|
[:prepared,:building,:fail,:success,:finished]
|
28
30
|
end
|
@@ -54,6 +56,7 @@ class Task < ActiveRecord::Base
|
|
54
56
|
|
55
57
|
|
56
58
|
def kill(signal = 'INT')
|
59
|
+
logger "Recived kill signal #{signal} for task #{id}"
|
57
60
|
return nil unless pid
|
58
61
|
pids = Sys::ProcTable.ps.find_all{|p| p.ppid == pid || p.pid == pid }.map{|p| p.pid}
|
59
62
|
pids.each{ |pid| Process.kill(signal,pid) }
|
@@ -73,7 +76,9 @@ class Task < ActiveRecord::Base
|
|
73
76
|
end
|
74
77
|
end
|
75
78
|
|
76
|
-
|
79
|
+
def commit
|
80
|
+
project.commit(commit_sha1)
|
81
|
+
end
|
77
82
|
|
78
83
|
class TaskAlreadyRunningException < Exception ; end
|
79
84
|
class TaskAlreadyExecuteException < Exception ; end
|
@@ -81,6 +86,7 @@ class Task < ActiveRecord::Base
|
|
81
86
|
def execute
|
82
87
|
raise TaskAlreadyExecuteException if reload[:ended_at]
|
83
88
|
raise TaskAlreadyRunningException if reload[:started_at]
|
89
|
+
logger "Executing task #{id} named #{name}"
|
84
90
|
status = 'fail'
|
85
91
|
|
86
92
|
ObjectSpace.define_finalizer(self,lambda{
|
@@ -148,16 +154,22 @@ class Task < ActiveRecord::Base
|
|
148
154
|
while ( !inputs.empty? ) do
|
149
155
|
select(inputs).first.each do |input|
|
150
156
|
begin
|
151
|
-
|
157
|
+
read = input.read_nonblock(99999999)
|
158
|
+
logger read
|
159
|
+
buff += read
|
152
160
|
self.update_attribute(:output, buff) if output != buff && Time.now.to_i > updated_at.to_i + DATABASE_UPDATE_INTERVAL
|
153
161
|
rescue EOFError
|
162
|
+
logger "EOFError. removing #{stdout == input ? 'stdout' : 'stderr'} input"
|
154
163
|
inputs.delete input
|
155
164
|
end
|
156
165
|
end
|
157
166
|
end
|
158
167
|
|
159
168
|
end
|
160
|
-
|
169
|
+
logger "Finished popen"
|
170
|
+
Process.wait
|
171
|
+
logger "Really finished command"
|
172
|
+
process_status.exitstatus
|
161
173
|
ensure
|
162
174
|
self.update_attributes(:output => buff,:pid => nil, :exit_code => (process_status && process_status.exitstatus))
|
163
175
|
end
|
@@ -1,18 +1,9 @@
|
|
1
1
|
<% content_tag_for :li, commit do %>
|
2
2
|
<pre><%= link_to commit.short_message, project_commit_path(@project, commit.id) %></pre>
|
3
|
-
|
4
|
-
|
3
|
+
<%= gravatar_img_for(commit) %>
|
4
|
+
|
5
5
|
<strong><%= commit.author.name %></strong> (author)<br/>
|
6
|
-
<em><%= commit.committed_date.to_s(:short) %></em>
|
7
|
-
|
8
|
-
<% task = @project.tasks.for_commit(commit.id).first %>
|
9
|
-
<% if task %>
|
10
|
-
<%= link_to "Build status: #{task.status}", project_task_path(@project,task), :class => task.status %>
|
11
|
-
<% else %>
|
12
|
-
<% form_for commit, :url => project_commit_path(@project, commit) do |f| %>
|
13
|
-
<button type="submit">build!</button>
|
14
|
-
<% end %>
|
15
|
-
<% end %>
|
6
|
+
<em><%= commit.committed_date.to_s(:short) %></em>
|
16
7
|
</p>
|
17
8
|
<dl>
|
18
9
|
<dt>sha1</dt>
|
@@ -26,10 +26,10 @@
|
|
26
26
|
<div id="header">
|
27
27
|
<h1><%= @project.slug %></h1>
|
28
28
|
<ul class="tabs">
|
29
|
+
<%= plugins_links %>
|
29
30
|
<li><%= link_to 'Commits', project_commits_path(@project) %></li>
|
30
31
|
<li><%= link_to 'Tasks', project_tasks_path(@project) %></li>
|
31
32
|
<li><%= link_to 'Admin', edit_project_path(@project) %></li>
|
32
|
-
<%= plugins_links %>
|
33
33
|
</ul>
|
34
34
|
</div>
|
35
35
|
|
@@ -1,5 +1,10 @@
|
|
1
1
|
<h1>Builder Daemon Status</h1>
|
2
|
-
<p><%= @builder_daemon_status
|
2
|
+
<p><%= @builder_daemon_status %>
|
3
|
+
<% form_tag('/status', :method => :put) do %>
|
4
|
+
<%= hidden_field_tag('what', 'restart_builder') %>
|
5
|
+
<%= submit_tag 'restart' %>
|
6
|
+
<% end %>
|
7
|
+
</p>
|
3
8
|
|
4
9
|
<h1>Current plugins</h1>
|
5
10
|
<ul>
|
@@ -1,29 +1,46 @@
|
|
1
|
-
<% content_tag_for
|
2
|
-
<
|
3
|
-
<p
|
4
|
-
<dl>
|
5
|
-
<dt>Command:</dt>
|
6
|
-
<dd><%= truncate(task.code,:length => 35) %></dd>
|
1
|
+
<% content_tag_for :div, task, :class=> "#{task.status} task" do %>
|
2
|
+
<h1><%= task.name %></h1>
|
3
|
+
<p class="status <%= task.status %>">Build status: <%= task.status %></p>
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
<
|
11
|
-
<
|
5
|
+
<div class='task_description'>
|
6
|
+
<% if task.prepared? %>
|
7
|
+
<p>This tasks is prepared to be run. Please wait other tasks finish.</p>
|
8
|
+
<pre id="output"><%= task.parsed_output %></pre>
|
12
9
|
|
13
|
-
|
14
|
-
<
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
<%
|
10
|
+
<% else %>
|
11
|
+
<dl>
|
12
|
+
<dt>Started at:</dt>
|
13
|
+
<dd><%= show_time(task.started_at) %></dd>
|
14
|
+
|
15
|
+
<% if task.building? %>
|
16
|
+
<dt>Elapsed time</dt>
|
17
|
+
<dd class="elapsed_time"><%= show_elapsed(task.build_duration) %></dd>
|
18
|
+
<dt>Pid</dt>
|
19
|
+
<dd><%= task.pid %>
|
20
|
+
<% form_for task, :url => project_task_path(@project,task) do |f| %>
|
21
|
+
<%= hidden_field_tag :kill, 'INT' %>
|
22
|
+
<%= f.submit 'INT' %>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
<% form_for task, :url => project_task_path(@project,task) do |f| %>
|
26
|
+
<%= hidden_field_tag :kill, 'QUIT' %>
|
27
|
+
<%= f.submit 'QUIT' %>
|
28
|
+
<% end %>
|
29
|
+
|
30
|
+
<% form_for task, :url => project_task_path(@project,task) do |f| %>
|
31
|
+
<%= hidden_field_tag :kill, 'KILL' %>
|
32
|
+
<%= f.submit 'QUIT' %>
|
33
|
+
<% end %>
|
29
34
|
|
35
|
+
</dd>
|
36
|
+
<% else %>
|
37
|
+
<dt>Ended at:</dt>
|
38
|
+
<dd><%= show_time(task.ended_at) %>
|
39
|
+
<span><%= show_elapsed(task.build_duration) %></span></dd>
|
40
|
+
<% end %>
|
41
|
+
<%= link_to 'raw', project_task_path(@project,task, 'text'), :class => 'raw_link' %>
|
42
|
+
</dl>
|
43
|
+
<pre id="output"><%= task.parsed_output %></pre>
|
44
|
+
<% end %>
|
45
|
+
</div>
|
46
|
+
<% end %>
|