ginst 2.0.1 → 2009.11.23
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/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 %>
|