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
data/Gemfile CHANGED
@@ -1,5 +1,2 @@
1
1
  source :rubygems
2
-
3
- ruby '1.9.3'
4
-
5
- gemspec :name => "juici"
2
+ gemspec
@@ -2,13 +2,11 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  juici (0.0.0)
5
- ansible
6
5
  bson_ext
7
6
  github-markdown
8
7
  json
9
- mongoid
8
+ mongoid (~> 2)
10
9
  sinatra
11
- thin
12
10
 
13
11
  GEM
14
12
  remote: http://rubygems.org/
@@ -19,28 +17,24 @@ GEM
19
17
  activesupport (3.2.8)
20
18
  i18n (~> 0.6)
21
19
  multi_json (~> 1.0)
22
- ansible (0.2.0)
23
20
  bson (1.7.0)
24
21
  bson_ext (1.7.0)
25
22
  bson (~> 1.7.0)
26
- builder (3.0.4)
27
- daemons (1.1.9)
23
+ builder (3.0.3)
28
24
  diff-lcs (1.1.3)
29
- eventmachine (1.0.0)
30
- github-markdown (0.5.3)
25
+ github-markdown (0.5.1)
31
26
  i18n (0.6.1)
32
27
  json (1.7.5)
33
28
  metaclass (0.0.1)
34
29
  mocha (0.11.4)
35
30
  metaclass (~> 0.0.1)
36
- mongoid (3.0.10)
31
+ mongo (1.7.0)
32
+ bson (~> 1.7.0)
33
+ mongoid (2.5.0)
37
34
  activemodel (~> 3.1)
38
- moped (~> 1.1)
39
- origin (~> 1.0)
35
+ mongo (~> 1.7)
40
36
  tzinfo (~> 0.3.22)
41
- moped (1.2.7)
42
- multi_json (1.3.7)
43
- origin (1.0.10)
37
+ multi_json (1.3.6)
44
38
  rack (1.4.1)
45
39
  rack-protection (1.2.0)
46
40
  rack
@@ -57,12 +51,8 @@ GEM
57
51
  rack (~> 1.3, >= 1.3.6)
58
52
  rack-protection (~> 1.2)
59
53
  tilt (~> 1.3, >= 1.3.3)
60
- thin (1.5.0)
61
- daemons (>= 1.0.9)
62
- eventmachine (>= 0.12.6)
63
- rack (>= 1.0.0)
64
54
  tilt (1.3.3)
65
- tzinfo (0.3.34)
55
+ tzinfo (0.3.33)
66
56
 
67
57
  PLATFORMS
68
58
  ruby
data/README.md CHANGED
@@ -13,8 +13,8 @@ It's designed to work well with [agent99](https://github.com/99designs/agent99)
13
13
 
14
14
  ## Important but Miscellaneous
15
15
 
16
- If you create child processes in modules/plugins then you need to register your
17
- disinterest or JuiCI will think they're builds and that would be bad.
16
+ If you create child process in modules/plugins then you need to register your
17
+ disinterest or JuiCI will think they're builds and that would be bad
18
18
 
19
19
  ## Setup
20
20
 
@@ -27,26 +27,12 @@ bundle exec bin/juici
27
27
 
28
28
  is all you need to have a working instance (provided that you have mongo installed)
29
29
 
30
- ### Gotchas
31
-
32
- Make sure you don't do something innocuous like
33
-
34
- ```bash
35
- bundle install --path .bundle
36
- ```
37
-
38
- this might look sane (and it is, kinda) but owing to a quick in bundler, it
39
- will break any ruby code you try to build.
40
-
41
- I'm working on a workaround, but in the meantime the fix is to not do it!
42
-
43
30
  ## Usage
44
31
 
45
- JuiCI is very focused on minimal configuration; meaning that beyond starting
46
- the server and pointing it at a mongoDB instance, you do not need to do
47
- anything special to build a new project. Just request a build; however this
48
- means that on your first build you will need to send the commands to create
49
- your test environment)
32
+ JuiCI chooses to be very "Mongo" (which is an adjective now), in that you don't
33
+ need to formally create a project. Just request a build; however this means
34
+ that on your first build you will need to send the commands to create your test
35
+ environment)
50
36
 
51
37
  Example:
52
38
 
@@ -81,20 +67,6 @@ called with an (as yet unformalised) json body as the body if/when the build
81
67
  reaches that state. Alternately you may specify "any" as the callback state and
82
68
  it will be called on all state changes.
83
69
 
84
- ## Integration
85
-
86
- Apps written in ruby wanting to interact with Juici can include the
87
- `juici-interface` gem, which presently exposes a few constants to line up with
88
- JuiCI's internal state.
89
- Over time this will be expanded, but for now they are:
90
-
91
- ```ruby
92
- Juici::BuildStatus::PASS
93
- Juici::BuildStatus::FAIL
94
- Juici::BuildStatus::START
95
- Juici::BuildStatus::WAIT
96
- ```
97
-
98
70
  ## Security
99
71
 
100
72
  JuiCI poses some interesting security conecerns. First off, it will allow
@@ -120,19 +92,8 @@ specifically implement it, your process won't see any of the signal handling
120
92
  madness. The shell(`/bin/sh`) will see everything, and if killed, your
121
93
  processes will become orphaned, but carry on.
122
94
 
123
- ## Authors
124
-
125
- * [Richo Healey](https://github.com/rcho)
126
- * [Alec Sloman](https://github.com/alecsloman)
127
-
128
95
  ## Contact
129
96
 
130
97
  JuiCI's code lives on [Github](https://github.com/richo/juici)
131
98
  and the [author](mailto:richo@psych0tik.net) can be contacted on
132
99
  [Twitter](https://twitter.com/rich0H)
133
-
134
- ## Legalese
135
-
136
- (c) Richo Healey 2012, richo@psych0tik.net
137
-
138
- Released under the terms of the MIT license.
data/Rakefile CHANGED
@@ -1,33 +1,9 @@
1
1
  require 'rake'
2
2
  require 'rspec/core/rake_task'
3
3
 
4
- require 'juici/database'
5
-
6
4
  RSpec::Core::RakeTask.new(:spec) do |t|
7
5
  t.pattern = "spec/**/*_spec.rb"
8
6
  end
9
7
 
10
8
  desc 'Default: run specs'
11
9
  task :default => :spec
12
-
13
- namespace :db do
14
- desc "Destroy the test db specified in mongoid.yml"
15
- task :destroy do
16
- Juici::Database.initialize!
17
- Mongoid.purge!
18
- end
19
- end
20
-
21
- desc "Build all gems"
22
- task :gems do
23
- %w[juici juici-interface].each do |gem|
24
- `gem build #{gem}.gemspec`
25
- end
26
- end
27
-
28
- desc "Delete all built gems"
29
- task :clean do
30
- Dir["juici-*.gem"].each do |gem|
31
- File.unlink(gem)
32
- end
33
- end
@@ -1,25 +1,10 @@
1
1
  development:
2
- sessions:
3
- default:
4
- database: juici
5
- hosts:
6
- - localhost:27017
2
+ database: juici
3
+ host: localhost
7
4
 
8
5
  production:
9
- sessions:
10
- default:
11
- database: juici
12
- hosts:
13
- - localhost:27017
14
-
15
- test:
16
- sessions:
17
- default:
18
- database: juici-test
19
- hosts:
20
- - localhost:27017
6
+ database: juici
7
+ host: localhost
21
8
 
22
9
  heroku:
23
- sessions:
24
- default:
25
- uri: <%= ENV['MONGOLAB_URI'] %>
10
+ uri: <%= ENV['MONGOLAB_URI'] %>
@@ -1,10 +1,8 @@
1
1
  # vim: ft=ruby
2
- #
3
- require File.expand_path("../lib/juici/version", __FILE__)
4
2
 
5
3
  Gem::Specification.new do |s|
6
4
  s.name = "juici"
7
- s.version = Juici::VERSION
5
+ s.version = "0.0.0"
8
6
  s.authors = ["Richo Healey"]
9
7
  s.email = ["richo@psych0tik.net"]
10
8
  s.homepage = "http://github.com/richo/juici"
@@ -12,12 +10,10 @@ Gem::Specification.new do |s|
12
10
  s.description = s.summary
13
11
 
14
12
  s.add_dependency "sinatra"
15
- s.add_dependency "thin"
16
13
  s.add_dependency "json"
17
- s.add_dependency "mongoid"
14
+ s.add_dependency "mongoid", "~> 2"
18
15
  s.add_dependency "bson_ext"
19
16
  s.add_dependency "github-markdown"
20
- s.add_dependency "ansible"
21
17
 
22
18
  s.add_development_dependency "rake"
23
19
  s.add_development_dependency "mocha"
@@ -25,7 +21,7 @@ Gem::Specification.new do |s|
25
21
 
26
22
  s.files = `git ls-files`.split("\n")
27
23
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
- s.executables = 'juici'
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
25
  s.require_paths = ["lib"]
30
26
  end
31
27
 
@@ -1,17 +1,12 @@
1
+ require 'mongo'
2
+ require 'mongoid'
1
3
  require 'github/markdown'
2
- require 'ansible'
3
4
 
4
5
  ENV['RACK_ENV'] ||= "development"
5
6
 
6
7
  module Juici
7
8
  def self.dbgp(*args)
8
- if ENV['JUICI_DEBUG'] || env == "development"
9
- $stderr.puts(args)
10
- end
11
- end
12
-
13
- def self.env
14
- ENV['JUICI_ENV'] || ENV['RACK_ENV']
9
+ ENV['JUICY_DEBUG'] && $stderr.puts(args)
15
10
  end
16
11
  end
17
12
 
@@ -8,20 +8,31 @@ module Juici
8
8
 
9
9
  def self.shutdown
10
10
  ::Juici.dbgp "Shutting down Juici"
11
- ::Juici::Watcher.instance.shutdown!
11
+ @@watchers.each do |watcher|
12
+ ::Juici.dbgp "Killing #{watcher.inspect}"
13
+ watcher.kill
14
+ watcher.join
15
+ ::Juici.dbgp "Dead: #{watcher.inspect}"
16
+ end
12
17
 
13
18
  shutdown_build_queue
14
19
  end
15
20
 
16
21
  attr_reader :opts
17
22
  def initialize(opts={})
18
- Database.initialize!
19
23
  @opts = opts
20
- reset_stale_children
21
- start_watcher
24
+ # NOTE: this happening before we start a build queue is important, it
25
+ # means we can't start any more workers and get tied in knots
26
+ # clear_stale_children
27
+ #
28
+ # Urgh
22
29
  init_build_queue
23
30
  reload_unfinished_work
24
- start_queue
31
+ start_workers
32
+ end
33
+
34
+ def spawn_watcher
35
+ @@watchers << Watcher.start!
25
36
  end
26
37
 
27
38
  private
@@ -40,28 +51,21 @@ module Juici
40
51
  # Ensure that any killed builds will be retried
41
52
  end
42
53
 
43
- def start_watcher
44
- ::Juici::Watcher.instance.start
54
+ def start_workers
55
+ no_workers = opts[:workers] || 1
56
+ warn "More than 1 worker is liable to do strange things" if no_workers > 1
57
+ no_workers.times do
58
+ spawn_watcher
59
+ end
45
60
  end
46
61
 
47
62
  def reload_unfinished_work
48
63
  # At this point no workers have started yet, we can safely assume that
49
64
  # :started means aborted
50
- Build.where(:status => Juici::BuildStatus::WAIT).each do |build|
65
+ Build.where(:status.in => [:started, :waiting]).each do |build|
51
66
  $build_queue << build
52
67
  end
53
68
  end
54
69
 
55
- def reset_stale_children
56
- Build.where(:status => Juici::BuildStatus::START).each do |build|
57
- build[:status] = Juici::BuildStatus::WAIT
58
- build.save!
59
- end
60
- end
61
-
62
- def start_queue
63
- $build_queue.start!
64
- end
65
-
66
70
  end
67
71
  end
@@ -1,5 +1,5 @@
1
1
  module Juici
2
- BUILD_SENSITIVE_VARIABLES = %w[RUBYOPT BUNDLE_GEMFILE RACK_ENV MONGOLAB_URI GEM_PATH WORKING_DIR]
2
+ BUILD_SENSITIVE_VARIABLES = %w[RUBYOPT BUNDLE_GEMFILE RACK_ENV MONGOLAB_URI]
3
3
  class BuildEnvironment
4
4
 
5
5
  attr_reader :env
@@ -1,20 +1,11 @@
1
1
  require 'fileutils'
2
2
  require 'tempfile'
3
3
  module Juici
4
- module BuildLogic
4
+ module BuildLogic
5
5
 
6
6
  def spawn_build
7
7
  raise "No such work tree" unless FileUtils.mkdir_p(worktree)
8
8
  spawn(command, worktree)
9
- rescue AbortBuild
10
- :buildaborted
11
- end
12
-
13
- def kill!
14
- warn! "Killed!"
15
- if pid = self[:pid]
16
- Process.kill(15, pid)
17
- end
18
9
  end
19
10
 
20
11
  private
@@ -9,7 +9,6 @@ module Juici
9
9
  @child_pids = []
10
10
  # This is never expired, for now
11
11
  @builds_by_pid = {}
12
- @started = false
13
12
  end
14
13
 
15
14
  def shutdown!
@@ -40,28 +39,17 @@ module Juici
40
39
  end
41
40
  end
42
41
 
43
- def delete(id)
44
- purge(:_id, OpenStruct.new(:_id => id))
45
- end
46
-
47
42
  # Magic hook that starts a process if there's a good reason to.
48
43
  # Stopgap measure that means you can knock on this if there's a chance we
49
44
  # should start a process
50
45
  def bump!
51
- return unless @started
52
46
  update_children
53
47
  if not_working? && work_to_do?
54
48
  Juici.dbgp "Starting another child process"
55
49
  next_child.tap do |child|
56
- if pid = child.build!
57
- Juici.dbgp "Started child: #{pid}"
58
- @child_pids << pid
59
- @builds_by_pid[pid] = child
60
- else
61
- Juici.dbgp "Child #{child} failed to start"
62
- bump! # Ruby's recursion isn't great, but re{try,do} may as well be
63
- # undefined behaviour here.
64
- end
50
+ pid = child.build!
51
+ @child_pids << pid
52
+ @builds_by_pid[pid] = child
65
53
  end
66
54
  else
67
55
  Juici.dbgp "I have quite enough to do"
@@ -92,20 +80,5 @@ module Juici
92
80
  @builds.length > 0
93
81
  end
94
82
 
95
- def currently_building
96
- @child_pids.map do |pid|
97
- get_build_by_pid(pid)
98
- end
99
- end
100
-
101
- def start!
102
- @started = true
103
- bump!
104
- end
105
-
106
- def builds
107
- @builds
108
- end
109
-
110
83
  end
111
84
  end
@@ -2,24 +2,20 @@ require 'net/http'
2
2
  module Juici
3
3
  class Callback
4
4
 
5
- attr_reader :url
6
- attr_accessor :payload
5
+ attr_reader :build, :url
7
6
 
8
- def initialize(url, pl=nil)
7
+ def initialize(build, url)
8
+ @build = build
9
9
  @url = URI(url)
10
- @payload = pl if pl
11
10
  end
12
11
 
13
12
  def process!
14
13
  Net::HTTP.start(url.host, url.port) do |http|
15
14
  request = Net::HTTP::Post.new(url.request_uri)
16
- request.body = payload
15
+ request.body = build.to_callback_json
17
16
 
18
- http.request request # Net::HTTPResponse object
17
+ response = http.request request # Net::HTTPResponse object
19
18
  end
20
- rescue SocketError => e
21
- # We don't get a reference to build any more, can't warn :(
22
- # TODO Throw a warning on the build
23
19
  end
24
20
 
25
21
  end