juici 0.0.0 → 0.0.1.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +4 -1
  3. data/Gemfile.lock +26 -16
  4. data/README.md +45 -6
  5. data/Rakefile +24 -0
  6. data/bin/juicic +54 -0
  7. data/config/mongoid.yml.sample +20 -5
  8. data/juici-interface.gemspec +19 -0
  9. data/juici.gemspec +7 -3
  10. data/lib/juici.rb +8 -3
  11. data/lib/juici/app.rb +19 -23
  12. data/lib/juici/build_environment.rb +1 -1
  13. data/lib/juici/build_logic.rb +10 -1
  14. data/lib/juici/build_queue.rb +30 -3
  15. data/lib/juici/callback.rb +9 -5
  16. data/lib/juici/config.rb +4 -0
  17. data/lib/juici/controllers.rb +6 -0
  18. data/lib/juici/controllers/base.rb +26 -0
  19. data/lib/juici/controllers/build_queue.rb +14 -0
  20. data/lib/juici/controllers/builds.rb +74 -0
  21. data/lib/juici/controllers/index.rb +20 -0
  22. data/lib/juici/controllers/{trigger_controller.rb → trigger.rb} +24 -5
  23. data/lib/juici/database.rb +19 -13
  24. data/lib/juici/exceptions.rb +2 -0
  25. data/lib/juici/find_logic.rb +11 -0
  26. data/lib/juici/helpers/form_helpers.rb +11 -0
  27. data/lib/juici/helpers/html_helpers.rb +4 -0
  28. data/lib/juici/helpers/url_helpers.rb +28 -0
  29. data/lib/juici/interface.rb +13 -0
  30. data/lib/juici/models/build.rb +81 -24
  31. data/lib/juici/models/project.rb +1 -1
  32. data/lib/juici/server.rb +103 -40
  33. data/lib/juici/version.rb +8 -0
  34. data/lib/juici/views/README.markdown +45 -6
  35. data/lib/juici/views/about.erb +5 -5
  36. data/lib/juici/views/builds/edit.erb +23 -0
  37. data/lib/juici/views/builds/list.erb +26 -33
  38. data/lib/juici/views/builds/new.erb +42 -37
  39. data/lib/juici/views/builds/show.erb +4 -28
  40. data/lib/juici/views/index.erb +30 -13
  41. data/lib/juici/views/layout.erb +22 -13
  42. data/lib/juici/views/not_found.erb +3 -0
  43. data/lib/juici/views/partials/builds/debug.erb +12 -18
  44. data/lib/juici/views/partials/builds/output.erb +1 -0
  45. data/lib/juici/views/partials/builds/show.erb +19 -0
  46. data/lib/juici/views/partials/builds/sidebar.erb +13 -0
  47. data/lib/juici/views/partials/index/recently_built.erb +19 -0
  48. data/lib/juici/views/queue/list.erb +6 -0
  49. data/lib/juici/watcher.rb +33 -25
  50. data/public/favicon.ico +0 -0
  51. data/public/images/black_denim.png +0 -0
  52. data/public/styles/builds.css +59 -8
  53. data/public/styles/juici.css +226 -2
  54. data/public/vendor/bootstrap.css +6004 -0
  55. data/public/vendor/bootstrap.js +2036 -0
  56. data/public/vendor/img/glyphicons-halflings-white.png +0 -0
  57. data/public/vendor/jquery.js +9440 -0
  58. data/script/cibuild +10 -0
  59. data/spec/build_callback_spec.rb +46 -1
  60. data/spec/build_process_spec.rb +71 -5
  61. data/spec/build_queue_spec.rb +3 -1
  62. data/spec/controllers/builds_spec.rb +68 -0
  63. data/spec/controllers/index_spec.rb +28 -0
  64. data/spec/juici_app_spec.rb +0 -15
  65. data/spec/models/build_spec.rb +54 -0
  66. data/spec/spec_helper.rb +13 -0
  67. metadata +76 -12
  68. data/lib/juici/controllers/build_controller.rb +0 -0
  69. data/lib/juici/url_helpers.rb +0 -15
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ config/mongoid.yml
data/Gemfile CHANGED
@@ -1,2 +1,5 @@
1
1
  source :rubygems
2
- gemspec
2
+
3
+ ruby '1.9.3'
4
+
5
+ gemspec :name => "juici"
@@ -1,40 +1,46 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- juici (0.0.0)
4
+ juici (0.0.0.alpha1)
5
+ ansible
5
6
  bson_ext
6
7
  github-markdown
7
8
  json
8
- mongoid (~> 2)
9
+ mongoid
9
10
  sinatra
11
+ thin
10
12
 
11
13
  GEM
12
14
  remote: http://rubygems.org/
13
15
  specs:
14
- activemodel (3.2.8)
15
- activesupport (= 3.2.8)
16
+ activemodel (3.2.9)
17
+ activesupport (= 3.2.9)
16
18
  builder (~> 3.0.0)
17
- activesupport (3.2.8)
19
+ activesupport (3.2.9)
18
20
  i18n (~> 0.6)
19
21
  multi_json (~> 1.0)
20
- bson (1.7.0)
21
- bson_ext (1.7.0)
22
- bson (~> 1.7.0)
23
- builder (3.0.3)
22
+ ansible (0.2.0)
23
+ bson (1.7.1)
24
+ bson_ext (1.7.1)
25
+ bson (~> 1.7.1)
26
+ builder (3.0.4)
27
+ daemons (1.1.9)
24
28
  diff-lcs (1.1.3)
25
- github-markdown (0.5.1)
29
+ eventmachine (1.0.0)
30
+ github-markdown (0.5.3)
26
31
  i18n (0.6.1)
27
32
  json (1.7.5)
28
33
  metaclass (0.0.1)
29
34
  mocha (0.11.4)
30
35
  metaclass (~> 0.0.1)
31
- mongo (1.7.0)
32
- bson (~> 1.7.0)
33
- mongoid (2.5.0)
36
+ mongoid (3.0.13)
34
37
  activemodel (~> 3.1)
35
- mongo (~> 1.7)
38
+ moped (~> 1.1)
39
+ origin (~> 1.0)
36
40
  tzinfo (~> 0.3.22)
37
- multi_json (1.3.6)
41
+ moped (1.2.9)
42
+ multi_json (1.3.7)
43
+ origin (1.0.10)
38
44
  rack (1.4.1)
39
45
  rack-protection (1.2.0)
40
46
  rack
@@ -51,8 +57,12 @@ GEM
51
57
  rack (~> 1.3, >= 1.3.6)
52
58
  rack-protection (~> 1.2)
53
59
  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)
54
64
  tilt (1.3.3)
55
- tzinfo (0.3.33)
65
+ tzinfo (0.3.35)
56
66
 
57
67
  PLATFORMS
58
68
  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 process 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 processes 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,12 +27,26 @@ 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
+
30
43
  ## Usage
31
44
 
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)
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)
36
50
 
37
51
  Example:
38
52
 
@@ -67,6 +81,20 @@ called with an (as yet unformalised) json body as the body if/when the build
67
81
  reaches that state. Alternately you may specify "any" as the callback state and
68
82
  it will be called on all state changes.
69
83
 
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
+
70
98
  ## Security
71
99
 
72
100
  JuiCI poses some interesting security conecerns. First off, it will allow
@@ -92,8 +120,19 @@ specifically implement it, your process won't see any of the signal handling
92
120
  madness. The shell(`/bin/sh`) will see everything, and if killed, your
93
121
  processes will become orphaned, but carry on.
94
122
 
123
+ ## Authors
124
+
125
+ * [Richo Healey](https://github.com/rcho)
126
+ * [Alec Sloman](https://github.com/alecsloman)
127
+
95
128
  ## Contact
96
129
 
97
130
  JuiCI's code lives on [Github](https://github.com/richo/juici)
98
131
  and the [author](mailto:richo@psych0tik.net) can be contacted on
99
132
  [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,9 +1,33 @@
1
1
  require 'rake'
2
2
  require 'rspec/core/rake_task'
3
3
 
4
+ require 'juici/database'
5
+
4
6
  RSpec::Core::RakeTask.new(:spec) do |t|
5
7
  t.pattern = "spec/**/*_spec.rb"
6
8
  end
7
9
 
8
10
  desc 'Default: run specs'
9
11
  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
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ require 'net/http'
3
+ require 'json'
4
+ require 'juici/interface'
5
+
6
+ # TODO Refactor
7
+ def main(args)
8
+ action = args.shift.to_sym
9
+ options = {}
10
+
11
+ until args.empty?
12
+ case args.shift
13
+ when "--command"
14
+ command = args.shift
15
+ options[:command] = if command == "-"
16
+ File.read(command)
17
+ else
18
+ command
19
+ end
20
+ when "--host"
21
+ options[:host] = args.shift
22
+ when "--title"
23
+ options[:title] = args.shift
24
+ when "--project"
25
+ options[:project] = args.shift
26
+ when "--priority"
27
+ options[:priority] = args.shift
28
+ end
29
+ end
30
+
31
+ send(action, options)
32
+ end
33
+
34
+ def build(opts)
35
+ host = URI(opts[:host])
36
+ Net::HTTP.start(host.host, host.port) do |h|
37
+ req = Net::HTTP::Post.new(Juici::Routes::NEW_BUILD)
38
+ req.body = _create_payload(opts)
39
+ h.request req
40
+ end
41
+ end
42
+
43
+ def _create_payload(opts)
44
+ URI.encode_www_form({
45
+ "project" => opts[:project],
46
+ "environment" => (opts[:environment] || {}).to_json,
47
+ "command" => opts[:command],
48
+ "priority" => opts[:priority] || 1,
49
+ "callbacks" => (opts[:callbacks] || []).to_json,
50
+ "title" => opts[:title]
51
+ })
52
+ end
53
+
54
+ main(ARGV.dup)
@@ -1,10 +1,25 @@
1
1
  development:
2
- database: juici
3
- host: localhost
2
+ sessions:
3
+ default:
4
+ database: juici
5
+ hosts:
6
+ - localhost:27017
4
7
 
5
8
  production:
6
- database: juici
7
- host: localhost
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
8
21
 
9
22
  heroku:
10
- uri: <%= ENV['MONGOLAB_URI'] %>
23
+ sessions:
24
+ default:
25
+ uri: <%= ENV['MONGOLAB_URI'] %>
@@ -0,0 +1,19 @@
1
+ # vim: ft=ruby
2
+ #
3
+ require File.expand_path("../lib/juici/version", __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "juici-interface"
7
+ s.version = Juici::VERSION
8
+ s.authors = ["Richo Healey"]
9
+ s.email = ["richo@psych0tik.net"]
10
+ s.homepage = "http://github.com/richo/juici"
11
+ s.summary = "Interface definition for JuiCI callbacks and API"
12
+ s.description = s.summary
13
+
14
+ s.files = "lib/juici/interface.rb"
15
+ s.require_paths = ["lib"]
16
+ s.executables = "juicic"
17
+ end
18
+
19
+
@@ -1,8 +1,10 @@
1
1
  # vim: ft=ruby
2
+ #
3
+ require File.expand_path("../lib/juici/version", __FILE__)
2
4
 
3
5
  Gem::Specification.new do |s|
4
6
  s.name = "juici"
5
- s.version = "0.0.0"
7
+ s.version = Juici::VERSION
6
8
  s.authors = ["Richo Healey"]
7
9
  s.email = ["richo@psych0tik.net"]
8
10
  s.homepage = "http://github.com/richo/juici"
@@ -10,10 +12,12 @@ Gem::Specification.new do |s|
10
12
  s.description = s.summary
11
13
 
12
14
  s.add_dependency "sinatra"
15
+ s.add_dependency "thin"
13
16
  s.add_dependency "json"
14
- s.add_dependency "mongoid", "~> 2"
17
+ s.add_dependency "mongoid"
15
18
  s.add_dependency "bson_ext"
16
19
  s.add_dependency "github-markdown"
20
+ s.add_dependency "ansible"
17
21
 
18
22
  s.add_development_dependency "rake"
19
23
  s.add_development_dependency "mocha"
@@ -21,7 +25,7 @@ Gem::Specification.new do |s|
21
25
 
22
26
  s.files = `git ls-files`.split("\n")
23
27
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
28
+ s.executables = 'juici'
25
29
  s.require_paths = ["lib"]
26
30
  end
27
31
 
@@ -1,12 +1,17 @@
1
- require 'mongo'
2
- require 'mongoid'
3
1
  require 'github/markdown'
2
+ require 'ansible'
4
3
 
5
4
  ENV['RACK_ENV'] ||= "development"
6
5
 
7
6
  module Juici
8
7
  def self.dbgp(*args)
9
- ENV['JUICY_DEBUG'] && $stderr.puts(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']
10
15
  end
11
16
  end
12
17
 
@@ -8,31 +8,20 @@ module Juici
8
8
 
9
9
  def self.shutdown
10
10
  ::Juici.dbgp "Shutting down Juici"
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
11
+ ::Juici::Watcher.instance.shutdown!
17
12
 
18
13
  shutdown_build_queue
19
14
  end
20
15
 
21
16
  attr_reader :opts
22
17
  def initialize(opts={})
18
+ Database.initialize!
23
19
  @opts = opts
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
20
+ reset_stale_children
21
+ start_watcher
29
22
  init_build_queue
30
23
  reload_unfinished_work
31
- start_workers
32
- end
33
-
34
- def spawn_watcher
35
- @@watchers << Watcher.start!
24
+ start_queue
36
25
  end
37
26
 
38
27
  private
@@ -51,21 +40,28 @@ module Juici
51
40
  # Ensure that any killed builds will be retried
52
41
  end
53
42
 
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
43
+ def start_watcher
44
+ ::Juici::Watcher.instance.start
60
45
  end
61
46
 
62
47
  def reload_unfinished_work
63
48
  # At this point no workers have started yet, we can safely assume that
64
49
  # :started means aborted
65
- Build.where(:status.in => [:started, :waiting]).each do |build|
50
+ Build.where(:status => Juici::BuildStatus::WAIT).each do |build|
66
51
  $build_queue << build
67
52
  end
68
53
  end
69
54
 
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
+
70
66
  end
71
67
  end
@@ -1,5 +1,5 @@
1
1
  module Juici
2
- BUILD_SENSITIVE_VARIABLES = %w[RUBYOPT BUNDLE_GEMFILE RACK_ENV MONGOLAB_URI]
2
+ BUILD_SENSITIVE_VARIABLES = %w[RUBYOPT BUNDLE_GEMFILE RACK_ENV MONGOLAB_URI GEM_PATH WORKING_DIR]
3
3
  class BuildEnvironment
4
4
 
5
5
  attr_reader :env