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.
- data/Gemfile +1 -4
- data/Gemfile.lock +9 -19
- data/README.md +6 -45
- data/Rakefile +0 -24
- data/config/mongoid.yml.sample +5 -20
- data/juici.gemspec +3 -7
- data/lib/juici.rb +3 -8
- data/lib/juici/app.rb +23 -19
- data/lib/juici/build_environment.rb +1 -1
- data/lib/juici/build_logic.rb +1 -10
- data/lib/juici/build_queue.rb +3 -30
- data/lib/juici/callback.rb +5 -9
- data/lib/juici/config.rb +0 -4
- data/lib/juici/controllers/build_controller.rb +0 -0
- data/lib/juici/controllers/{trigger.rb → trigger_controller.rb} +5 -24
- data/lib/juici/database.rb +13 -19
- data/lib/juici/helpers/url_helpers.rb +0 -28
- data/lib/juici/models/build.rb +24 -81
- data/lib/juici/models/project.rb +1 -1
- data/lib/juici/server.rb +40 -103
- data/lib/juici/url_helpers.rb +15 -0
- data/lib/juici/views/README.markdown +6 -45
- data/lib/juici/views/about.erb +5 -5
- data/lib/juici/views/builds/list.erb +33 -26
- data/lib/juici/views/builds/new.erb +37 -42
- data/lib/juici/views/builds/show.erb +28 -4
- data/lib/juici/views/index.erb +13 -30
- data/lib/juici/views/layout.erb +13 -22
- data/lib/juici/views/partials/builds/debug.erb +18 -12
- data/lib/juici/watcher.rb +25 -33
- data/public/styles/builds.css +8 -59
- data/public/styles/juici.css +2 -226
- data/spec/build_callback_spec.rb +1 -46
- data/spec/build_process_spec.rb +5 -71
- data/spec/build_queue_spec.rb +1 -3
- data/spec/juici_app_spec.rb +15 -0
- data/spec/spec_helper.rb +0 -13
- metadata +12 -76
- data/.gitignore +0 -2
- data/bin/juicic +0 -54
- data/juici-interface.gemspec +0 -19
- data/lib/juici/controllers.rb +0 -6
- data/lib/juici/controllers/base.rb +0 -26
- data/lib/juici/controllers/build_queue.rb +0 -14
- data/lib/juici/controllers/builds.rb +0 -74
- data/lib/juici/controllers/index.rb +0 -20
- data/lib/juici/exceptions.rb +0 -2
- data/lib/juici/find_logic.rb +0 -11
- data/lib/juici/helpers/form_helpers.rb +0 -11
- data/lib/juici/helpers/html_helpers.rb +0 -4
- data/lib/juici/interface.rb +0 -13
- data/lib/juici/version.rb +0 -8
- data/lib/juici/views/builds/edit.erb +0 -23
- data/lib/juici/views/not_found.erb +0 -3
- data/lib/juici/views/partials/builds/output.erb +0 -1
- data/lib/juici/views/partials/builds/show.erb +0 -19
- data/lib/juici/views/partials/builds/sidebar.erb +0 -13
- data/lib/juici/views/partials/index/recently_built.erb +0 -19
- data/lib/juici/views/queue/list.erb +0 -6
- data/public/favicon.ico +0 -0
- data/public/images/black_denim.png +0 -0
- data/public/vendor/bootstrap.css +0 -6004
- data/public/vendor/bootstrap.js +0 -2036
- data/public/vendor/img/glyphicons-halflings-white.png +0 -0
- data/public/vendor/jquery.js +0 -9440
- data/script/cibuild +0 -10
- data/spec/controllers/builds_spec.rb +0 -68
- data/spec/controllers/index_spec.rb +0 -28
- data/spec/models/build_spec.rb +0 -54
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -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.
|
27
|
-
daemons (1.1.9)
|
23
|
+
builder (3.0.3)
|
28
24
|
diff-lcs (1.1.3)
|
29
|
-
|
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
|
-
|
31
|
+
mongo (1.7.0)
|
32
|
+
bson (~> 1.7.0)
|
33
|
+
mongoid (2.5.0)
|
37
34
|
activemodel (~> 3.1)
|
38
|
-
|
39
|
-
origin (~> 1.0)
|
35
|
+
mongo (~> 1.7)
|
40
36
|
tzinfo (~> 0.3.22)
|
41
|
-
|
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.
|
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
|
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
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
data/config/mongoid.yml.sample
CHANGED
@@ -1,25 +1,10 @@
|
|
1
1
|
development:
|
2
|
-
|
3
|
-
|
4
|
-
database: juici
|
5
|
-
hosts:
|
6
|
-
- localhost:27017
|
2
|
+
database: juici
|
3
|
+
host: localhost
|
7
4
|
|
8
5
|
production:
|
9
|
-
|
10
|
-
|
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
|
-
|
24
|
-
default:
|
25
|
-
uri: <%= ENV['MONGOLAB_URI'] %>
|
10
|
+
uri: <%= ENV['MONGOLAB_URI'] %>
|
data/juici.gemspec
CHANGED
@@ -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 =
|
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 =
|
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
|
|
data/lib/juici.rb
CHANGED
@@ -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
|
-
|
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
|
|
data/lib/juici/app.rb
CHANGED
@@ -8,20 +8,31 @@ module Juici
|
|
8
8
|
|
9
9
|
def self.shutdown
|
10
10
|
::Juici.dbgp "Shutting down Juici"
|
11
|
-
|
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
|
-
|
21
|
-
|
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
|
-
|
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
|
44
|
-
|
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 =>
|
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
|
data/lib/juici/build_logic.rb
CHANGED
@@ -1,20 +1,11 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'tempfile'
|
3
3
|
module Juici
|
4
|
-
|
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
|
data/lib/juici/build_queue.rb
CHANGED
@@ -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
|
-
|
57
|
-
|
58
|
-
|
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
|
data/lib/juici/callback.rb
CHANGED
@@ -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(
|
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 =
|
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
|