ginst 2.0.1 → 2009.11.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Rakefile +20 -21
  2. data/VERSION +1 -1
  3. data/app/controllers/application_controller.rb +1 -1
  4. data/app/controllers/status_controller.rb +10 -0
  5. data/app/controllers/tasks_controller.rb +9 -7
  6. data/app/helpers/projects_helper.rb +9 -4
  7. data/app/models/project.rb +38 -15
  8. data/app/models/task.rb +15 -3
  9. data/app/views/grit/commits/_commit.html.erb +3 -12
  10. data/app/views/layouts/projects.html.erb +1 -1
  11. data/app/views/status/show.html.erb +6 -1
  12. data/app/views/tasks/_task.html.erb +43 -26
  13. data/app/views/tasks/_task_item.html.erb +22 -0
  14. data/app/views/tasks/index.html.erb +3 -2
  15. data/app/views/tasks/show.html.erb +1 -46
  16. data/config/database.yml +4 -1
  17. data/config/environment.rb +4 -4
  18. data/config/routes.rb +1 -5
  19. data/ginst.gemspec +17 -18
  20. data/lib/ginst.rb +5 -2
  21. data/lib/ginst/builder.rb +2 -0
  22. data/lib/ginst/cli.rb +21 -44
  23. data/lib/ginst/console.rb +9 -0
  24. data/lib/ginst/ginst_template/webserver.ymlt +2 -0
  25. data/lib/ginst/logger.rb +31 -0
  26. data/lib/ginst/template.rb +1 -0
  27. data/lib/ginst/web_server.rb +28 -6
  28. data/log/development.log +49 -0
  29. data/public/stylesheets/screen.css +73 -38
  30. data/script/builder.rb +6 -1
  31. data/{features/step_definitions/ginst_steps.rb → tmp/.gittouch} +0 -0
  32. data/tmp/cache/.gittouch +0 -0
  33. data/tmp/pids/.gittouch +0 -0
  34. data/tmp/sessions/.gittouch +0 -0
  35. data/tmp/sockets/.gittouch +0 -0
  36. metadata +19 -17
  37. data/features/ginst.feature +0 -9
  38. data/features/support/env.rb +0 -4
  39. data/spec/ginst_spec.rb +0 -7
  40. data/spec/spec.opts +0 -1
  41. 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 'spec/rake/spectask'
34
- Spec::Rake::SpecTask.new(:spec) do |spec|
35
- spec.libs << 'lib' << 'spec'
36
- spec.spec_files = FileList['spec/**/*_spec.rb']
37
- end
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 'cucumber/rake/task'
49
- Cucumber::Rake::Task.new(:features)
50
-
51
- task :features => :check_dependencies
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 :features do
54
- abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
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 :default => :spec
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
- 2.0.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
@@ -5,4 +5,14 @@ class StatusController < ApplicationController
5
5
  @environment = Rails.env
6
6
  end
7
7
 
8
+
9
+ def update
10
+ case params['what']
11
+ when 'restart_builder'
12
+ Ginst::Builder.restart
13
+ else
14
+ end
15
+
16
+ redirect_to :back
17
+ end
8
18
  end
@@ -4,13 +4,16 @@ class TasksController < ApplicationController
4
4
 
5
5
 
6
6
  def index
7
- scope = @project.tasks
8
- if params[:scope] && Task.valid_scopes.include?(params[:scope].to_sym)
9
- scope = scope.send(params[:scope].to_sym)
10
- end
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, :id => 'heads', :class => 'tabs' do
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 gravatar_url_for(commit, size = 30)
14
- md5 = Digest::MD5.hexdigest(commit.author.email.strip.downcase)
15
- "http://www.gravatar.com/avatar/#{md5}?s=30"
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)
@@ -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 repo for #{name}"
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 -t
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 == preferences.branch_status[branch.name])
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
- Rails.logger.debug "[#{Time.current.to_s(:small)}] * Creating repo for #{name}"
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
 
@@ -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
- buff +=input.read_nonblock(9999999)
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
- process_status.exitstatus
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
- <img src="<%= gravatar_url_for(commit) %>">
4
- <p>
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 %></p>
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(:li, task, :class=> task.status) do %>
2
- <pre><%= link_to task.name, project_task_path(@project, task) %></pre>
3
- <p><%= simple_format(h(truncate(task.output))) %></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
- <dt>created_at</dt>
9
- <dd><%= show_time(task.created_at) %></dd>
10
- <dt>started_at</dt>
11
- <dd><%= show_time(task.started_at) %></dd>
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
- <dt>ended_At</dt>
14
- <dd><%= show_time(task.ended_at) %></dd>
15
-
16
- <dt>status</dt>
17
- <dd><%= task.status %></dd>
18
-
19
- <!-- <dt>output</dt>
20
- <dd><pre><code><%= simple_format(task.output) %></code></pre></dd>
21
-
22
- <dt>exit_code</dt>
23
- <dd><%= task.exit_code %></dd> -->
24
- </dl>
25
- <!-- <% form_for task, :url => project_task_path(task.project, task) do |f| %>
26
- <%= f.submit 'ReRun' %>
27
- <% end %> -->
28
- <% end %>
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 %>