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/public/styles/builds.css
CHANGED
@@ -1,62 +1,11 @@
|
|
1
|
-
.build-
|
2
|
-
|
3
|
-
white-space: pre-wrap;
|
4
|
-
word-wrap: break-word;
|
5
|
-
text-align: left;
|
6
|
-
}
|
1
|
+
.build-heading-pending { color: #111 }
|
2
|
+
:hover .build-heading-pending { color: #111 }
|
7
3
|
|
8
|
-
.
|
9
|
-
|
10
|
-
}
|
4
|
+
.build-heading-failed { color: #C10 }
|
5
|
+
:hover .build-heading-failed { color: #C10 }
|
11
6
|
|
12
|
-
.build-
|
13
|
-
color: #
|
14
|
-
}
|
15
|
-
|
16
|
-
.build-output .ansible_1 {
|
17
|
-
color: #ffffff;
|
18
|
-
}
|
19
|
-
|
20
|
-
.build-output .ansible_30 {
|
21
|
-
color: #222222;
|
22
|
-
}
|
23
|
-
.build-output .ansible_31 {
|
24
|
-
color: #a80000;
|
25
|
-
}
|
26
|
-
.build-output .ansible_32 {
|
27
|
-
color: #00a800;
|
28
|
-
}
|
29
|
-
.build-output .ansible_33 {
|
30
|
-
color: #a8a800;
|
31
|
-
}
|
32
|
-
.build-output .ansible_34 {
|
33
|
-
color: #3333a8;
|
34
|
-
}
|
35
|
-
.build-output .ansible_35 {
|
36
|
-
color: #a800a8;
|
37
|
-
}
|
38
|
-
.build-output .ansible_36 {
|
39
|
-
color: #00a8a8;
|
40
|
-
}
|
41
|
-
.build-output .ansible_30.ansible_1 {
|
42
|
-
color: #545454;
|
43
|
-
}
|
44
|
-
.build-output .ansible_31.ansible_1 {
|
45
|
-
color: #ff0054;
|
46
|
-
}
|
47
|
-
.build-output .ansible_32.ansible_1 {
|
48
|
-
color: #00ff54;
|
49
|
-
}
|
50
|
-
.build-output .ansible_33.ansible_1 {
|
51
|
-
color: #ffff54;
|
52
|
-
}
|
53
|
-
.build-output .ansible_34.ansible_1 {
|
54
|
-
color: #5555ff;
|
55
|
-
}
|
56
|
-
.build-output .ansible_35.ansible_1 {
|
57
|
-
color: #ff00ff;
|
58
|
-
}
|
59
|
-
.build-output .ansible_36.ansible_1 {
|
60
|
-
color: #00ffff;
|
61
|
-
}
|
7
|
+
.build-heading-success { color: #4A0 }
|
8
|
+
:hover .build-heading-success { color: #4A0 }
|
62
9
|
|
10
|
+
.build-heading-started { color: #CC0 }
|
11
|
+
:hover .build-heading-started { color: #CC0 }
|
data/public/styles/juici.css
CHANGED
@@ -1,226 +1,2 @@
|
|
1
|
-
body {
|
2
|
-
|
3
|
-
a { color: white; font-weight: bold; }
|
4
|
-
a:hover { color: red; text-decoration: none; }
|
5
|
-
|
6
|
-
.navbar, .navbar-inner, .nav { background: #2dffff !important; border-bottom-color: #00dfe0; }
|
7
|
-
.nav > li > a { color: black !important; text-shadow: none !important; }
|
8
|
-
.nav > li:hover { background-color: #00dfe0; }
|
9
|
-
.nav > li.active > a { background-color: #00dfe0 !important; }
|
10
|
-
.accordion-inner {border-top: none;}
|
11
|
-
.currently-building { white-space: pre-wrap; word-wrap: break-word; }
|
12
|
-
.block-header { font-size: 12px; line-height: 24px; color: black; background-color: #2dffff; font-weight: bold; padding: 0 3px 0 3px; }
|
13
|
-
.builds-header { margin: 10px 0 0 0; }
|
14
|
-
.builds-header--failure { color: #fff; background-color: #c800c9; }
|
15
|
-
.builds-header--success { background-color: #7e9eff; }
|
16
|
-
.project-title { margin-top: 0; }
|
17
|
-
|
18
|
-
/* Builds */
|
19
|
-
.table-flipper { color: white; }
|
20
|
-
.builds { list-style: none; overflow: auto; padding: 0; margin: 0; }
|
21
|
-
.builds a { display: block; font-weight: normal; text-decoration: none; padding: 34px 3px 3px 3px; border-top: 2px solid #000; }
|
22
|
-
|
23
|
-
.recently-built--fail {
|
24
|
-
color: black;
|
25
|
-
background-color: #ff7bff;
|
26
|
-
padding: 16px 3px 3px 3px !important;
|
27
|
-
}
|
28
|
-
|
29
|
-
.recently-built--fail:hover {
|
30
|
-
color: white;
|
31
|
-
background-color: #e100e1;
|
32
|
-
}
|
33
|
-
|
34
|
-
.recently-built--pass {
|
35
|
-
color: white;
|
36
|
-
background-color: #595959;
|
37
|
-
padding: 16px 3px 3px 3px !important;
|
38
|
-
}
|
39
|
-
|
40
|
-
.recently-built-pass:hover {
|
41
|
-
color: white;
|
42
|
-
background-color: #3f3f3f;
|
43
|
-
}
|
44
|
-
|
45
|
-
.submit-build label {
|
46
|
-
font-size: 12px;
|
47
|
-
color: #8091ff;
|
48
|
-
}
|
49
|
-
|
50
|
-
button, .btn {
|
51
|
-
font-size: 12px;
|
52
|
-
font-weight: normal;
|
53
|
-
border: 2px solid rgba(255,255,255,0.25);
|
54
|
-
padding: 5px;
|
55
|
-
border-radius: 0;
|
56
|
-
background: #8091ff !important;
|
57
|
-
text-shadow: none !important;
|
58
|
-
color: #000 !important;
|
59
|
-
font-family: "Monaco";
|
60
|
-
}
|
61
|
-
|
62
|
-
button:hover, .btn:hover {
|
63
|
-
background: red !important;
|
64
|
-
color: #FFF;
|
65
|
-
}
|
66
|
-
|
67
|
-
button:before, button:after, .btn:before, .btn:after {
|
68
|
-
content: " ** ";
|
69
|
-
}
|
70
|
-
|
71
|
-
.build-heading-started {
|
72
|
-
color: #DFFF80;
|
73
|
-
border: 2px dashed #DFFF80;
|
74
|
-
}
|
75
|
-
.build-heading-started:hover {
|
76
|
-
color: #ccff33;
|
77
|
-
border: 2px dashed #ccff33;
|
78
|
-
}
|
79
|
-
|
80
|
-
.build-heading-failed {
|
81
|
-
color: black;
|
82
|
-
background-color: #ff7bff;
|
83
|
-
}
|
84
|
-
.build-heading-failed:hover {
|
85
|
-
color: white;
|
86
|
-
background-color: #e100e1;
|
87
|
-
}
|
88
|
-
|
89
|
-
.build-heading-success {
|
90
|
-
color: white;
|
91
|
-
background: #8091ff;
|
92
|
-
}
|
93
|
-
.build-heading-success:hover {
|
94
|
-
color: white;
|
95
|
-
background-color: #334fff;
|
96
|
-
}
|
97
|
-
|
98
|
-
.build-heading-pending { color: gray; }
|
99
|
-
.build-heading-pending:hover { color: gray; }
|
100
|
-
|
101
|
-
.build-sidebar {
|
102
|
-
height: 48px;
|
103
|
-
}
|
104
|
-
|
105
|
-
.build-sidebar > span {
|
106
|
-
float: left;
|
107
|
-
}
|
108
|
-
|
109
|
-
.build-sidebar > span > form > button {
|
110
|
-
margin-left: 10px;
|
111
|
-
margin-right: 10px;
|
112
|
-
}
|
113
|
-
|
114
|
-
.build-output {
|
115
|
-
padding: 20px;
|
116
|
-
background-color: black;
|
117
|
-
border: 1px solid #2dffff;
|
118
|
-
box-shadow: 0 0 2px #2dffff;
|
119
|
-
border-radius: 3px;
|
120
|
-
}
|
121
|
-
|
122
|
-
.bloop {
|
123
|
-
color: transparent;
|
124
|
-
text-decoration: none;
|
125
|
-
font-size: 12px;
|
126
|
-
font-weight: normal;
|
127
|
-
display: block;
|
128
|
-
height: 79px;
|
129
|
-
width: 20px;
|
130
|
-
margin: 3px auto 0 auto;
|
131
|
-
background-color: #ff7bff;
|
132
|
-
}
|
133
|
-
.bloop:hover, .bloop.active { color: transparent; background-color: #c800c9; }
|
134
|
-
|
135
|
-
.disclosure { display: inline-block; width: 20px; }
|
136
|
-
.link-to-build { padding: 10px 0 10px 0; }
|
137
|
-
|
138
|
-
.bowlG{
|
139
|
-
margin-top: 2px;
|
140
|
-
position:relative;
|
141
|
-
width:14px;
|
142
|
-
height:14px;
|
143
|
-
}
|
144
|
-
|
145
|
-
.bowl_ringG{
|
146
|
-
position:absolute;
|
147
|
-
width:14px;
|
148
|
-
height:14px;
|
149
|
-
border:1px solid #DFFF80;
|
150
|
-
-moz-border-radius:14px;
|
151
|
-
-webkit-border-radius:14px;
|
152
|
-
border-radius:14px;
|
153
|
-
box-shadow: 0 0 3px #DFFF80;
|
154
|
-
}
|
155
|
-
|
156
|
-
.ball_holderG{
|
157
|
-
position:absolute;
|
158
|
-
width:4px;
|
159
|
-
height:14px;
|
160
|
-
left:5px;
|
161
|
-
top:0px;
|
162
|
-
-webkit-animation-name:ball_moveG;
|
163
|
-
-webkit-animation-duration:1.8s;
|
164
|
-
-webkit-animation-iteration-count:infinite;
|
165
|
-
-webkit-animation-timing-function:linear;
|
166
|
-
-moz-animation-name:ball_moveG;
|
167
|
-
-moz-animation-duration:1.8s;
|
168
|
-
-moz-animation-iteration-count:infinite;
|
169
|
-
-moz-animation-timing-function:linear;
|
170
|
-
-o-animation-name:ball_moveG;
|
171
|
-
-o-animation-duration:1.8s;
|
172
|
-
-o-animation-iteration-count:infinite;
|
173
|
-
-o-animation-timing-function:linear;
|
174
|
-
-ms-animation-name:ball_moveG;
|
175
|
-
-ms-animation-duration:1.8s;
|
176
|
-
-ms-animation-iteration-count:infinite;
|
177
|
-
-ms-animation-timing-function:linear;
|
178
|
-
}
|
179
|
-
|
180
|
-
.ballG{
|
181
|
-
position:absolute;
|
182
|
-
left:0px;
|
183
|
-
top:-3px;
|
184
|
-
width:6px;
|
185
|
-
height:6px;
|
186
|
-
background:#DFFF80;
|
187
|
-
-moz-border-radius:5px;
|
188
|
-
-webkit-border-radius:5px;
|
189
|
-
border-radius:5px;
|
190
|
-
box-shadow: 0 0 3px #DFFF80;
|
191
|
-
}
|
192
|
-
|
193
|
-
@-webkit-keyframes ball_moveG{
|
194
|
-
0%{
|
195
|
-
-webkit-transform:rotate(0deg)}
|
196
|
-
|
197
|
-
100%{
|
198
|
-
-webkit-transform:rotate(360deg)}
|
199
|
-
|
200
|
-
}
|
201
|
-
|
202
|
-
@-moz-keyframes ball_moveG{
|
203
|
-
0%{
|
204
|
-
-moz-transform:rotate(0deg)}
|
205
|
-
|
206
|
-
100%{
|
207
|
-
-moz-transform:rotate(360deg)}
|
208
|
-
|
209
|
-
}
|
210
|
-
|
211
|
-
@-o-keyframes ball_moveG{
|
212
|
-
0%{
|
213
|
-
-o-transform:rotate(0deg)}
|
214
|
-
|
215
|
-
100%{
|
216
|
-
-o-transform:rotate(360deg)}
|
217
|
-
|
218
|
-
}
|
219
|
-
|
220
|
-
@-ms-keyframes ball_moveG{
|
221
|
-
0%{
|
222
|
-
-ms-transform:rotate(0deg)}
|
223
|
-
|
224
|
-
100%{
|
225
|
-
-ms-transform:rotate(360deg)}
|
226
|
-
}
|
1
|
+
body { padding-top: 60px; }
|
2
|
+
.build-output { white-space: pre-wrap; }
|
data/spec/build_callback_spec.rb
CHANGED
@@ -3,52 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
describe "Juicy::Build::Callback" do
|
4
4
|
|
5
5
|
it "should call #process! on each of it's callbacks" do
|
6
|
-
|
7
|
-
mock(:payload= => nil).tap do |callback|
|
8
|
-
callback.expects(:process!).once
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
callbacks = ["rawr", "test"]
|
13
|
-
|
14
|
-
callbacks.each do |callback|
|
15
|
-
Juici::Callback.stubs(:new).with(callback).
|
16
|
-
returns(mock_callback)
|
17
|
-
end
|
18
|
-
|
19
|
-
build = Juici::Build.new(:callbacks => callbacks)
|
20
|
-
build.start!
|
21
|
-
build.success!
|
22
|
-
build.destroy
|
23
|
-
end
|
24
|
-
|
25
|
-
# TODO DRY This right up
|
26
|
-
it "should have status success on success" do
|
27
|
-
cb = Juici::Callback.new("test")
|
28
|
-
cb.stubs(:process!)
|
29
|
-
|
30
|
-
Juici::Callback.stubs(:new).with("test").returns(cb)
|
31
|
-
|
32
|
-
build = Juici::Build.new(:callbacks => ["test"])
|
33
|
-
build.start!
|
34
|
-
build.success!
|
35
|
-
|
36
|
-
JSON.load(cb.payload)["status"].should == Juici::BuildStatus::PASS
|
37
|
-
build.destroy
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should have status failed on failure" do
|
41
|
-
cb = Juici::Callback.new("test")
|
42
|
-
cb.stubs(:process!)
|
43
|
-
|
44
|
-
Juici::Callback.stubs(:new).with("test").returns(cb)
|
45
|
-
|
46
|
-
build = Juici::Build.new(:callbacks => ["test"])
|
47
|
-
build.start!
|
48
|
-
build.failure!
|
49
|
-
|
50
|
-
JSON.load(cb.payload)["status"].should == Juici::BuildStatus::FAIL
|
51
|
-
build.destroy
|
6
|
+
pending("Not yet specced")
|
52
7
|
end
|
53
8
|
|
54
9
|
end
|
data/spec/build_process_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
describe "Juici build abstraction" do
|
4
4
|
|
5
5
|
before(:all) do
|
6
|
-
@app = Juici::App.new
|
6
|
+
@app = Juici::App.new(workers: 0)
|
7
7
|
end
|
8
8
|
|
9
9
|
after(:all) do
|
@@ -12,85 +12,19 @@ describe "Juici build abstraction" do
|
|
12
12
|
|
13
13
|
|
14
14
|
it "Should run a given command in a subshell" do
|
15
|
-
|
15
|
+
worker = Juici::Watcher.start!
|
16
16
|
build = Juici::Build.new(parent: "test project",
|
17
17
|
environment: {},
|
18
18
|
command: "/bin/echo 'test build succeeded'")
|
19
19
|
$build_queue << build
|
20
|
-
|
21
20
|
# Wait a reasonable time for build to finish
|
22
21
|
# TODO: This can leverage the hooks system
|
23
22
|
# TODO: Easer will be to have worker.block or something
|
24
|
-
|
25
|
-
poll_build(build)
|
26
|
-
|
27
|
-
build.reload
|
28
|
-
build.status.should == Juici::BuildStatus::PASS
|
29
|
-
build[:output].chomp.should == "test build succeeded"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
it "Should catch failed builds" do
|
34
|
-
watcher = Juici::Watcher.instance.start
|
35
|
-
build = Juici::Build.new(parent: "test project",
|
36
|
-
environment: {},
|
37
|
-
command: "exit 3")
|
38
|
-
$build_queue << build
|
39
|
-
|
40
|
-
# Wait a reasonable time for build to finish
|
41
|
-
# TODO: This can leverage the hooks system
|
42
|
-
# TODO: Easer will be to have worker.block or something
|
43
|
-
Timeout::timeout(2) do
|
44
|
-
poll_build(build)
|
45
|
-
|
46
|
-
build.reload
|
47
|
-
build.status.should == Juici::BuildStatus::FAIL
|
48
|
-
build[:output].chomp.should == ""
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
it "Should kill builds" do
|
53
|
-
build = Juici::Build.new(parent: "test",
|
54
|
-
command: "sleep 30")
|
55
|
-
$build_queue << build
|
56
|
-
sleep 1
|
57
|
-
build.kill!
|
23
|
+
sleep 5
|
58
24
|
|
59
25
|
build.reload
|
60
|
-
|
61
|
-
build.
|
62
|
-
build.warnings.should include("Killed!")
|
63
|
-
end
|
64
|
-
|
65
|
-
it "Can create and fetch new bundles" do
|
66
|
-
watcher = Juici::Watcher.instance.start
|
67
|
-
build = Juici::Build.new(parent: "test project",
|
68
|
-
environment: ::Juici::BuildEnvironment.new.to_hash,
|
69
|
-
command: <<-EOS)
|
70
|
-
#!/bin/sh
|
71
|
-
set -e
|
72
|
-
|
73
|
-
cat > Gemfile <<EOF
|
74
|
-
source :rubygems
|
75
|
-
gem "m2a"
|
76
|
-
EOF
|
77
|
-
|
78
|
-
env
|
79
|
-
|
80
|
-
bundle install
|
81
|
-
bundle list
|
82
|
-
bundle config
|
83
|
-
EOS
|
84
|
-
|
85
|
-
build.save!
|
86
|
-
$build_queue << build
|
87
|
-
|
88
|
-
Timeout::timeout(10) do
|
89
|
-
poll_build(build)
|
90
|
-
|
91
|
-
build.status.should == Juici::BuildStatus::PASS
|
92
|
-
build[:output].chomp.should match /m2a/
|
93
|
-
end
|
26
|
+
build[:status].should == :success
|
27
|
+
build[:output].chomp.should == "test build succeeded"
|
94
28
|
end
|
95
29
|
|
96
30
|
end
|