juici 0.0.0.alpha1 → 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/Gemfile +1 -4
  2. data/Gemfile.lock +9 -19
  3. data/README.md +6 -45
  4. data/Rakefile +0 -24
  5. data/config/mongoid.yml.sample +5 -20
  6. data/juici.gemspec +3 -7
  7. data/lib/juici.rb +3 -8
  8. data/lib/juici/app.rb +23 -19
  9. data/lib/juici/build_environment.rb +1 -1
  10. data/lib/juici/build_logic.rb +1 -10
  11. data/lib/juici/build_queue.rb +3 -30
  12. data/lib/juici/callback.rb +5 -9
  13. data/lib/juici/config.rb +0 -4
  14. data/lib/juici/controllers/build_controller.rb +0 -0
  15. data/lib/juici/controllers/{trigger.rb → trigger_controller.rb} +5 -24
  16. data/lib/juici/database.rb +13 -19
  17. data/lib/juici/helpers/url_helpers.rb +0 -28
  18. data/lib/juici/models/build.rb +24 -81
  19. data/lib/juici/models/project.rb +1 -1
  20. data/lib/juici/server.rb +40 -103
  21. data/lib/juici/url_helpers.rb +15 -0
  22. data/lib/juici/views/README.markdown +6 -45
  23. data/lib/juici/views/about.erb +5 -5
  24. data/lib/juici/views/builds/list.erb +33 -26
  25. data/lib/juici/views/builds/new.erb +37 -42
  26. data/lib/juici/views/builds/show.erb +28 -4
  27. data/lib/juici/views/index.erb +13 -30
  28. data/lib/juici/views/layout.erb +13 -22
  29. data/lib/juici/views/partials/builds/debug.erb +18 -12
  30. data/lib/juici/watcher.rb +25 -33
  31. data/public/styles/builds.css +8 -59
  32. data/public/styles/juici.css +2 -226
  33. data/spec/build_callback_spec.rb +1 -46
  34. data/spec/build_process_spec.rb +5 -71
  35. data/spec/build_queue_spec.rb +1 -3
  36. data/spec/juici_app_spec.rb +15 -0
  37. data/spec/spec_helper.rb +0 -13
  38. metadata +12 -76
  39. data/.gitignore +0 -2
  40. data/bin/juicic +0 -54
  41. data/juici-interface.gemspec +0 -19
  42. data/lib/juici/controllers.rb +0 -6
  43. data/lib/juici/controllers/base.rb +0 -26
  44. data/lib/juici/controllers/build_queue.rb +0 -14
  45. data/lib/juici/controllers/builds.rb +0 -74
  46. data/lib/juici/controllers/index.rb +0 -20
  47. data/lib/juici/exceptions.rb +0 -2
  48. data/lib/juici/find_logic.rb +0 -11
  49. data/lib/juici/helpers/form_helpers.rb +0 -11
  50. data/lib/juici/helpers/html_helpers.rb +0 -4
  51. data/lib/juici/interface.rb +0 -13
  52. data/lib/juici/version.rb +0 -8
  53. data/lib/juici/views/builds/edit.erb +0 -23
  54. data/lib/juici/views/not_found.erb +0 -3
  55. data/lib/juici/views/partials/builds/output.erb +0 -1
  56. data/lib/juici/views/partials/builds/show.erb +0 -19
  57. data/lib/juici/views/partials/builds/sidebar.erb +0 -13
  58. data/lib/juici/views/partials/index/recently_built.erb +0 -19
  59. data/lib/juici/views/queue/list.erb +0 -6
  60. data/public/favicon.ico +0 -0
  61. data/public/images/black_denim.png +0 -0
  62. data/public/vendor/bootstrap.css +0 -6004
  63. data/public/vendor/bootstrap.js +0 -2036
  64. data/public/vendor/img/glyphicons-halflings-white.png +0 -0
  65. data/public/vendor/jquery.js +0 -9440
  66. data/script/cibuild +0 -10
  67. data/spec/controllers/builds_spec.rb +0 -68
  68. data/spec/controllers/index_spec.rb +0 -28
  69. data/spec/models/build_spec.rb +0 -54
@@ -4,8 +4,4 @@ class Juici::Config; class << self
4
4
  "/tmp/juici/workspace"
5
5
  end
6
6
 
7
- def builds_per_page
8
- 10
9
- end
10
-
11
7
  end; end
@@ -1,31 +1,15 @@
1
- module Juici::Controllers
2
- class Trigger
1
+ module Juici
2
+ class TriggerController
3
3
 
4
4
  attr_reader :project, :params
5
5
  def initialize(project, params)
6
- @project = ::Juici::Project.find_or_create_by(name: project)
6
+ @project = Project.find_or_create_by(name: project)
7
7
  @params = params
8
8
  end
9
9
 
10
- # Find an existing build, duplicate the sane parts of it.
11
- def rebuild!
12
- unless project = ::Juici::Project.where(name: params[:project]).first
13
- not_found
14
- end
15
- unless build = ::Juici::Build.where(parent: project.name, _id: params[:id]).first
16
- not_found
17
- end
18
-
19
- ::Juici::Build.new_from(build).tap do |new_build|
20
- new_build.save!
21
- $build_queue << new_build
22
- $build_queue.bump!
23
- end
24
- end
25
-
26
10
  def build!
27
- environment = ::Juici::BuildEnvironment.new
28
- ::Juici::Build.new(parent: project.name).tap do |build|
11
+ environment = BuildEnvironment.new
12
+ Build.new(parent: project.name).tap do |build|
29
13
  # The seperation of concerns around this madness is horrifying
30
14
  unless environment.load_json!(params['environment'])
31
15
  build.warn!("Failed to parse environment")
@@ -52,9 +36,6 @@ module Juici::Controllers
52
36
  # TODO Throw 422 not acceptable if missing
53
37
  params['command'].tap do |c|
54
38
  raise "No command given" if c.nil?
55
- # TODO Detect that we've recieved this from a browser session and only
56
- # do this replacement there, we can trust API supplied data.
57
- c.gsub!(/\r\n/, "\n")
58
39
  end
59
40
  end
60
41
 
@@ -1,25 +1,19 @@
1
- require 'mongoid'
2
- module Juici
3
- class Database
4
- class << self
5
- def mongoid_config_file
6
- %w[mongoid.yml mongoid.yml.sample].each do |file|
7
- path = File.join("config", file)
8
- return path if File.exist?(path)
9
- end
10
- raise "No database config file"
1
+ class Juici::Database
2
+ class << self
3
+ def mongoid_config_file
4
+ %w[mongoid.yml mongoid.yml.sample].each do |file|
5
+ path = File.join("config", file)
6
+ return path if File.exist?(path)
11
7
  end
8
+ raise "No database config file"
9
+ end
12
10
 
13
- def initialize!
14
- if ::Juici.respond_to? :dbgp
15
- ::Juici.dbgp "initializing Mongoid with environment: #{ENV['RACK_ENV']}"
16
- end
17
- if ENV['RACK_ENV'] == "development"
18
- Mongoid.logger.level = Logger::INFO
19
- end
20
-
21
- Mongoid.load!(mongoid_config_file)
11
+ def initialize!
12
+ if ENV['RACK_ENV'] == "development"
13
+ Mongoid.logger.level = Logger::INFO
22
14
  end
15
+
16
+ Mongoid.load!(mongoid_config_file)
23
17
  end
24
18
  end
25
19
  end
@@ -8,31 +8,3 @@ def build_url_for(entity)
8
8
  "/builds/#{entity[:parent]}/show/#{entity[:_id]}"
9
9
  end
10
10
  end
11
-
12
- def rebuild_url_for(entity)
13
- URI.escape case entity
14
- when ::Juici::Build
15
- "/builds/#{entity[:parent]}/rebuild/#{entity[:_id]}"
16
- end
17
- end
18
-
19
- def kill_url_for(entity)
20
- URI.escape case entity
21
- when ::Juici::Build
22
- "/builds/kill"
23
- end
24
- end
25
-
26
- def cancel_url_for(entity)
27
- URI.escape case entity
28
- when ::Juici::Build
29
- "/builds/cancel"
30
- end
31
- end
32
-
33
- def edit_url_for(entity)
34
- URI.escape case entity
35
- when ::Juici::Build
36
- "/builds/#{entity[:parent]}/edit/#{entity[:_id]}"
37
- end
38
- end
@@ -1,43 +1,29 @@
1
1
  require 'json'
2
-
2
+ # status enum
3
+ # :waiting
4
+ # :started
5
+ # :failed
6
+ # :success
7
+ #
8
+ # ???
9
+ # :profit!
10
+ #
3
11
  module Juici
4
12
  class Build
5
13
  # A wrapper around the build process
6
14
 
7
15
  include Mongoid::Document
16
+ include ::Juici.url_helpers("builds")
8
17
  include BuildLogic
9
- include BuildStatus
10
- extend FindLogic
11
18
  # TODO Builds should probably be children of projects in the URL?
12
19
 
13
- # Finder classmethods
14
- def self.get_recent(n, opts={})
15
- self.where(opts).
16
- limit(n).
17
- desc(:_id)
18
- end
19
-
20
- CLONABLE_FIELDS = [:command, :priority, :environment, :callbacks, :title, :parent]
21
- EDITABLE_ATTRIBUTES = {
22
- :string => [:priority, :title],
23
- :array => [:environment, :callbacks]
24
- }
25
-
26
- def self.new_from(other)
27
- new.tap do |b|
28
- CLONABLE_FIELDS.each do |prop|
29
- b[prop] = other[prop]
30
- end
31
- end
32
- end
33
-
34
20
  field :parent, type: String
35
21
  field :command, type: String
36
22
  field :environment, type: Hash
37
23
  field :create_time, type: Time, :default => Proc.new { Time.now }
38
24
  field :start_time, type: Time, :default => nil
39
25
  field :end_time, type: Time, :default => nil
40
- field :status, type: Symbol, :default => WAIT.to_sym
26
+ field :status, type: Symbol, :default => :waiting
41
27
  field :priority, type: Fixnum, :default => 1
42
28
  field :pid, type: Fixnum
43
29
  field :buffer, type: String
@@ -46,43 +32,37 @@ module Juici
46
32
  field :title, type: String, :default => Proc.new { Time.now.to_s }
47
33
 
48
34
  def set_status(value)
49
- self.status= value
35
+ self[:status] = value
50
36
  save!
51
37
  end
52
38
 
53
39
  def start!
54
40
  self[:start_time] = Time.now
55
- set_status START
41
+ set_status :started
56
42
  end
57
43
 
58
44
  def success!
59
45
  finish
60
- set_status PASS
46
+ set_status :success
61
47
  process_callbacks
62
48
  end
63
49
 
64
50
  def failure!
65
51
  finish
66
- set_status FAIL
52
+ set_status :failed
67
53
  process_callbacks
68
54
  end
69
55
 
70
56
  def finish
71
57
  self[:end_time] = Time.now
72
58
  self[:output] = get_output
73
- $build_queue.purge(:pid, self) if $build_queue
74
- end
75
-
76
- def cancel
77
- warn! "Cancelled"
78
- set_status FAIL
79
- $build_queue.delete(self[:_id]) if $build_queue
59
+ $build_queue.purge(:pid, self)
80
60
  end
81
61
 
82
62
  def build!
83
- start!
84
63
  case pid = spawn_build
85
64
  when Fixnum
65
+ start!
86
66
  Juici.dbgp "#{pid} away!"
87
67
  self[:pid] = pid
88
68
  self[:buffer] = @buffer.path
@@ -100,22 +80,18 @@ module Juici
100
80
 
101
81
  def worktree
102
82
  File.join(Config.workspace, parent)
103
- rescue TypeError => e
104
- warn! "Invalid workdir"
105
- failure!
106
- raise AbortBuild
107
83
  end
108
84
 
109
85
  # View helpers
110
86
  def heading_color
111
87
  case status
112
- when WAIT
88
+ when :waiting
113
89
  "build-heading-pending"
114
- when FAIL
90
+ when :failed
115
91
  "build-heading-failed"
116
- when PASS
92
+ when :success
117
93
  "build-heading-success"
118
- when START
94
+ when :started
119
95
  "build-heading-started"
120
96
  end
121
97
  end
@@ -133,20 +109,14 @@ module Juici
133
109
  self[:title] || self[:create_time]
134
110
  end
135
111
 
136
- def link_title
137
- "#{self[:parent]}/#{display_title}"
138
- end
139
-
140
112
  def warn!(msg)
141
113
  warnings << msg
142
114
  save!
143
115
  end
144
116
 
145
117
  def process_callbacks
146
- callbacks.each do |callback_url|
147
- c = Callback.new(callback_url)
148
- c.payload = self.to_callback_json
149
- c.process!
118
+ self[:callbacks].each do |callback_url|
119
+ Callback.new(self, callback_url).process!
150
120
  end
151
121
  end
152
122
 
@@ -155,36 +125,9 @@ module Juici
155
125
  {
156
126
  "project" => self[:parent],
157
127
  "status" => self[:status],
158
- "url" => build_url_for(self),
159
- "time" => time_elapsed
128
+ "url" => build_url_for(self)
160
129
  }.to_json
161
130
  end
162
131
 
163
- def callbacks
164
- self[:callbacks] || []
165
- end
166
-
167
- def time_elapsed
168
- if self[:end_time]
169
- self[:end_time] - self[:start_time]
170
- elsif self[:start_time]
171
- Time.now - self[:start_time]
172
- else
173
- nil
174
- end
175
- rescue
176
- -1 # Throw an obviously impossible build time.
177
- # This will only occur as a result of old builds.
178
- end
179
-
180
- # Use symbols internally
181
- def status
182
- self[:status].to_s
183
- end
184
-
185
- def status=(s)
186
- self[:status] = s.to_sym
187
- end
188
-
189
132
  end
190
133
  end
@@ -1,7 +1,7 @@
1
1
  module Juici
2
2
  class Project
3
3
  include Mongoid::Document
4
- extend FindLogic
4
+ include Juici.url_helpers("builds")
5
5
 
6
6
  field :name, type: String
7
7
 
@@ -11,8 +11,6 @@ module Juici
11
11
  end
12
12
 
13
13
  helpers do
14
- include Ansible
15
-
16
14
  Dir[File.dirname(__FILE__) + "/helpers/**/*.rb"].each do |file|
17
15
  load file
18
16
  end
@@ -21,16 +19,9 @@ module Juici
21
19
  dir = File.dirname(File.expand_path(__FILE__))
22
20
 
23
21
  def self.start(host, port)
24
- @@juici = App.new
25
- Juici::Server.run!(:host => host, :port => port) do |server|
26
- [:INT, :TERM].each do |sig|
27
- trap(sig) do
28
- $stderr.puts "Shutting down JuiCI"
29
- App.shutdown
30
- server.respond_to?(:stop!) ? server.stop! : server.stop
31
- end
32
- end
33
- end
22
+ Database.initialize!
23
+ @@juici = App.new
24
+ Juici::Server.run! :host => host, :port => port
34
25
  end
35
26
 
36
27
  def self.rack_start(project_path)
@@ -42,130 +33,76 @@ module Juici
42
33
  set :static, true
43
34
 
44
35
  get '/' do
45
- Controllers::Index.new.index do |template, opts|
46
- erb(template, {}, opts)
47
- end
36
+ @page = :index
37
+ erb(:index, {}, :juici => juici)
48
38
  end
49
39
 
50
40
  get '/about' do
51
- Controllers::Index.new.about do |template, opts|
52
- erb(template, {}, opts)
53
- end
41
+ @page = :about
42
+ @action = :show
43
+ erb(:about)
54
44
  end
55
45
 
56
46
  get '/builds' do
57
- Controllers::Index.new.builds do |template, opts|
58
- erb(template, {}, opts)
59
- end
47
+ @page = :builds
48
+ @action = :list
49
+ erb(:builds, {}, :juici => juici)
60
50
  end
61
51
 
62
- get '/support' do
63
- Controllers::Index.new.support do |template, opts|
64
- erb(template, {}, opts)
65
- end
52
+ get '/builds/new' do
53
+ @page = :builds
54
+ @action = :new
55
+ erb(:"builds/new", :juici => juici)
66
56
  end
67
57
 
68
58
  post '/builds/new' do
69
- build = Controllers::Trigger.new(params[:project], params).build!
70
- @redirect_to = build_url_for(build)
71
- erb(:redirect, {}, {})
72
- end
73
-
74
- post '/builds/:project/rebuild/:id' do
75
- build = Controllers::Trigger.new(params[:project], params).rebuild!
76
- @redirect_to = build_url_for(build)
77
- erb(:redirect, {}, {})
78
- end
79
-
80
- post '/builds/:user/:project/rebuild/:id' do
81
- params[:project] = "#{params[:user]}/#{params[:project]}"
82
- build = Controllers::Trigger.new(params[:project], params).rebuild!
83
- @redirect_to = build_url_for(build)
84
- erb(:redirect, {}, {})
59
+ TriggerController.new(params[:project], params).build!
60
+ @redirect_to = build_url_for(params[:project])
61
+ erb(:redirect, {}, :juici => juici)
85
62
  end
86
63
 
87
- post '/builds/kill' do
88
- build = Controllers::Builds.new(params).kill
89
- @redirect_to = build_url_for(build)
90
- erb(:redirect, {}, {})
91
- end
92
-
93
- post '/builds/cancel' do
94
- build = Controllers::Builds.new(params).cancel
95
- @redirect_to = build_url_for(build)
96
- erb(:redirect, {}, {})
97
- end
98
-
99
- get ::Juici::Routes::NEW_BUILD do
100
- Controllers::Builds.new(params).new do |template, opts|
101
- erb(template, {}, opts)
102
- end
64
+ def list_builds(params)
65
+ erb(:"builds/list", {}, :juici => juici, :project => params[:project])
103
66
  end
104
67
 
105
68
  get '/builds/:project/list' do
106
- Controllers::Builds.new(params).list do |template, opts|
107
- erb(template, {}, opts)
108
- end
69
+ @page = :builds
70
+ @action = :list
71
+ list_builds(params)
109
72
  end
110
73
 
111
74
  get '/builds/:user/:project/list' do
75
+ @page = :builds
76
+ @action = :list
112
77
  params[:project] = "#{params[:user]}/#{params[:project]}"
113
- Controllers::Builds.new(params).list do |template, opts|
114
- erb(template, {}, opts)
115
- end
116
- end
117
-
118
- get '/builds/:project/edit/:id' do
119
- Controllers::Builds.new(params).edit do |template, opts|
120
- erb(template, {}, opts)
121
- end
122
- end
123
-
124
- get '/builds/:user/:project/edit/:id' do
125
- params[:project] = "#{params[:user]}/#{params[:project]}"
126
- Controllers::Builds.new(params).edit do |template, opts|
127
- erb(template, {}, opts)
128
- end
129
- end
130
-
131
- post '/builds/:project/edit/:id' do
132
- build = Controllers::Builds.new(params).update!
133
- @redirect_to = build_url_for(build)
134
- erb(:redirect, {}, {})
78
+ list_builds(params)
135
79
  end
136
80
 
137
- post '/builds/:user/:project/edit/:id' do
138
- params[:project] = "#{params[:user]}/#{params[:project]}"
139
- build = Controllers::Builds.new(params).update!
140
- @redirect_to = build_url_for(build)
141
- erb(:redirect, {}, {})
81
+ def show_build(params)
82
+ erb(:"builds/show", {}, :juici => juici, :project => params[:project], :id => params[:id])
142
83
  end
143
84
 
144
85
  get '/builds/:project/show/:id' do
145
- Controllers::Builds.new(params).show do |template, opts|
146
- erb(template, {}, opts)
147
- end
86
+ @page = :builds
87
+ @action = :show
88
+ show_build(params)
148
89
  end
149
90
 
150
91
  get '/builds/:user/:project/show/:id' do
92
+ @page = :builds
93
+ @action = :show
151
94
  params[:project] = "#{params[:user]}/#{params[:project]}"
152
- Controllers::Builds.new(params).show do |template, opts|
153
- erb(template, {}, opts)
154
- end
95
+ show_build(params)
155
96
  end
156
97
 
157
- post '/trigger/:project' do
158
- Controllers::Trigger.new(params[:project], params).build!
159
- end
160
-
161
- get '/queue' do
162
- Controllers::BuildQueue.new(params).list do |template, opts|
163
- erb(template, {}, opts)
164
- end
98
+ get '/support' do
99
+ @page = :support
100
+ @action = :show
101
+ erb(:"support", {})
165
102
  end
166
103
 
167
- not_found do
168
- erb(:not_found, {}, {})
104
+ post '/trigger/:project' do
105
+ TriggerController.new(params[:project], params).build!
169
106
  end
170
107
 
171
108
  end