ci_in_a_can 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +32 -9
- data/ci_in_a_can.gemspec +1 -0
- data/lib/ci_in_a_can/app.rb +44 -10
- data/lib/ci_in_a_can/build.rb +6 -2
- data/lib/ci_in_a_can/last_run_list.rb +17 -0
- data/lib/ci_in_a_can/persistence.rb +7 -0
- data/lib/ci_in_a_can/test_result.rb +12 -2
- data/lib/ci_in_a_can/test_result_notifier.rb +1 -0
- data/lib/ci_in_a_can/version.rb +1 -1
- data/lib/ci_in_a_can/web_content.rb +22 -0
- data/spec/ci_in_a_can/build_spec.rb +16 -0
- data/spec/ci_in_a_can/last_run_list_spec.rb +49 -0
- data/spec/ci_in_a_can/test_result_notifier_spec.rb +10 -0
- data/spec/ci_in_a_can/test_result_spec.rb +33 -0
- data/spec/spec_helper.rb +7 -0
- metadata +25 -5
data/README.md
CHANGED
@@ -1,24 +1,47 @@
|
|
1
|
-
#
|
1
|
+
# CI In a Can
|
2
2
|
|
3
|
-
|
3
|
+
Super-easy continuous integration. With one command, you can turn a cloud server (AWS, Digital Ocean) into a CI server for Ruby apps. Others (like node, .Net) coming soon.
|
4
4
|
|
5
|
-
|
5
|
+
This currently only hooks to Github repos. More later.
|
6
|
+
|
7
|
+
## Philosophy
|
6
8
|
|
7
|
-
|
9
|
+
CI should be as easy as running tests on your own computer. When a change is made, your CI server should download the changes, run the tests, and report the results.
|
8
10
|
|
9
|
-
|
11
|
+
So that's what this application does. It handles the basics... receiving notifications of new pushes, running the tests, and reporting back the results.
|
10
12
|
|
11
|
-
And
|
13
|
+
And just like running the tests on your own computer... you'll have to set up your server to run your app. That's outside the scope of CI In a Can. But once your server can run the tests, CI In a Can will work for you.
|
12
14
|
|
13
|
-
|
15
|
+
## Installation
|
14
16
|
|
15
|
-
|
17
|
+
Install with:
|
16
18
|
|
17
19
|
$ gem install ci_in_a_can
|
18
20
|
|
19
21
|
## Usage
|
20
22
|
|
21
|
-
|
23
|
+
Run:
|
24
|
+
|
25
|
+
````
|
26
|
+
ciinacan YOUR_NAME
|
27
|
+
cd YOUR_NAME
|
28
|
+
rake start &
|
29
|
+
disown
|
30
|
+
````
|
31
|
+
|
32
|
+
This will create a directory named YOUR_NAME, start up a Sinatra app on port 80, and start a backend service for running builds. **You now have a running CI server.**
|
33
|
+
|
34
|
+
For any project you want to hook to a CI server, add a Github webhook to "http://YOUR_WEBSITE".
|
35
|
+
|
36
|
+
When any push is made to your Github repository, Github will send a notification to your Sinatra site. This will initiate a clone, run the usual stuff you need "bundle install, etc.", then run "bundle exec rake" to run your tests.
|
37
|
+
|
38
|
+
## Requirements
|
39
|
+
|
40
|
+
1. A default rake task that runs all of your tests.
|
41
|
+
2. An environment variable named GITHUB_AUTH_TOKEN. This is used to report results back to Github.
|
42
|
+
3. An environment variable named SITE_URL. This will be the URL of your site, for things like providing Github with a link back to the site to show test results.
|
43
|
+
2. A server that will "just run" your application. Set up your own server with whatever dependencies your application needs.
|
44
|
+
|
22
45
|
|
23
46
|
## Contributing
|
24
47
|
|
data/ci_in_a_can.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency "mocha"
|
23
23
|
spec.add_development_dependency "subtle"
|
24
24
|
spec.add_development_dependency "contrast"
|
25
|
+
spec.add_development_dependency "timecop"
|
25
26
|
|
26
27
|
spec.add_runtime_dependency "rake"
|
27
28
|
spec.add_runtime_dependency "sinatra"
|
data/lib/ci_in_a_can/app.rb
CHANGED
@@ -9,25 +9,59 @@ module CiInACan
|
|
9
9
|
end
|
10
10
|
|
11
11
|
get '/test_result/:id' do
|
12
|
-
CiInACan::TestResult.find(params[:id]).to_json
|
12
|
+
test_result = CiInACan::TestResult.find(params[:id]).to_json
|
13
|
+
|
14
|
+
CiInACan::WebContent.full_page_of(
|
15
|
+
<<EOF
|
16
|
+
<table class="table table-bordered">
|
17
|
+
<tbody>
|
18
|
+
<tr>
|
19
|
+
<td>
|
20
|
+
Id
|
21
|
+
</td>
|
22
|
+
<td>
|
23
|
+
#{test_result.id}
|
24
|
+
</td>
|
25
|
+
</tr>
|
26
|
+
<tr>
|
27
|
+
<td>
|
28
|
+
Created At
|
29
|
+
</td>
|
30
|
+
<td>
|
31
|
+
#{test_result.id}
|
32
|
+
</td>
|
33
|
+
</tr>
|
34
|
+
<tr>
|
35
|
+
<td>
|
36
|
+
Passed
|
37
|
+
</td>
|
38
|
+
<td>
|
39
|
+
#{test_result.passed ? 'Yes' : 'No'}
|
40
|
+
</td>
|
41
|
+
</tr>
|
42
|
+
<tr>
|
43
|
+
<td>
|
44
|
+
Output
|
45
|
+
</td>
|
46
|
+
<td>
|
47
|
+
#{test_result.output.to_s.gsub("\n", '<br />')}
|
48
|
+
</td>
|
49
|
+
</tr>
|
50
|
+
</tbody>
|
51
|
+
</table>
|
52
|
+
EOF
|
53
|
+
)
|
13
54
|
end
|
14
55
|
|
15
56
|
get '/' do
|
57
|
+
CiInACan::WebContent.full_page_of(
|
16
58
|
<<EOF
|
17
|
-
<html>
|
18
|
-
<head>
|
19
|
-
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css">
|
20
|
-
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap-theme.min.css">
|
21
|
-
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
|
22
|
-
</head>
|
23
|
-
<body>
|
24
59
|
<table class="table table-bordered">
|
25
60
|
<tbody>
|
26
61
|
</tbody>
|
27
62
|
</table>
|
28
|
-
</body>
|
29
|
-
</html>
|
30
63
|
EOF
|
64
|
+
)
|
31
65
|
end
|
32
66
|
|
33
67
|
post '/' do
|
data/lib/ci_in_a_can/build.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
module CiInACan
|
2
2
|
|
3
3
|
class Build
|
4
|
-
|
4
|
+
|
5
|
+
params_constructor do
|
6
|
+
@created_at = Time.now unless @created_at
|
7
|
+
end
|
5
8
|
|
6
9
|
attr_accessor :id, :git_ssh, :sha,
|
7
|
-
:local_location, :repo
|
10
|
+
:local_location, :repo,
|
11
|
+
:created_at
|
8
12
|
|
9
13
|
def self.parse content
|
10
14
|
GithubBuildParser.new.parse content
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CiInACan
|
2
|
+
|
3
|
+
module LastRunList
|
4
|
+
|
5
|
+
def self.add build, test_result
|
6
|
+
data = { created_at: test_result.created_at, test_result_id: test_result.id }
|
7
|
+
CiInACan::Persistence.save("test_run_list", test_result.created_at, data)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.all
|
11
|
+
blah = CiInACan::Persistence.hash_for("test_run_list")
|
12
|
+
blah.sort_by { |x| x[0] }.reverse.map { |x| x[1] }
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -14,6 +14,13 @@ module CiInACan
|
|
14
14
|
store.transaction(true) { store[id] }
|
15
15
|
end
|
16
16
|
|
17
|
+
def self.hash_for type
|
18
|
+
store = store_for(type)
|
19
|
+
store.transaction do
|
20
|
+
store.roots.inject({}) { |t, i| t[i] = store[i]; t }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
17
24
|
private
|
18
25
|
|
19
26
|
def self.store_for type
|
@@ -1,12 +1,17 @@
|
|
1
|
+
require 'subtle'
|
2
|
+
|
1
3
|
module CiInACan
|
2
4
|
class TestResult
|
3
5
|
|
4
6
|
PERSISTENCE_TYPE = 'test_result'
|
5
7
|
|
6
|
-
params_constructor
|
8
|
+
params_constructor do
|
9
|
+
@created_at = Time.now unless @created_at
|
10
|
+
end
|
7
11
|
|
8
12
|
attr_accessor :id
|
9
13
|
attr_accessor :passed, :output
|
14
|
+
attr_accessor :created_at
|
10
15
|
|
11
16
|
def self.create values
|
12
17
|
test_result = create_the_test_result_from values
|
@@ -19,7 +24,12 @@ module CiInACan
|
|
19
24
|
end
|
20
25
|
|
21
26
|
def to_json
|
22
|
-
{
|
27
|
+
{
|
28
|
+
id: id,
|
29
|
+
passed: passed,
|
30
|
+
output: output,
|
31
|
+
created_at: created_at
|
32
|
+
}.to_json
|
23
33
|
end
|
24
34
|
|
25
35
|
private
|
data/lib/ci_in_a_can/version.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
module CiInACan
|
2
|
+
|
3
|
+
module WebContent
|
4
|
+
|
5
|
+
def self.full_page_of content
|
6
|
+
<<EOF
|
7
|
+
<html>
|
8
|
+
<head>
|
9
|
+
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css">
|
10
|
+
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap-theme.min.css">
|
11
|
+
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.0/js/bootstrap.min.js"></script>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
#{content}
|
15
|
+
</body>
|
16
|
+
</html>
|
17
|
+
EOF
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -2,6 +2,22 @@ require_relative '../spec_helper'
|
|
2
2
|
|
3
3
|
describe CiInACan::Build do
|
4
4
|
|
5
|
+
after do
|
6
|
+
Timecop.return
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should default created_at to the current date" do
|
10
|
+
now = Time.now
|
11
|
+
::Timecop.freeze now
|
12
|
+
CiInACan::Build.new.created_at.must_equal now
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should allow the created_at to be set" do
|
16
|
+
now = Object.new
|
17
|
+
build = CiInACan::Build.new(created_at: now)
|
18
|
+
build.created_at.must_be_same_as now
|
19
|
+
end
|
20
|
+
|
5
21
|
it "should default commands to the basic ruby conventions" do
|
6
22
|
result = CiInACan::Build.new.commands
|
7
23
|
result.count.must_equal 2
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe CiInACan::LastRunList do
|
4
|
+
|
5
|
+
before do
|
6
|
+
clear_all_persisted_data
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "add" do
|
10
|
+
|
11
|
+
let(:build) { CiInACan::Build.new }
|
12
|
+
let(:test_result) { CiInACan::TestResult.new }
|
13
|
+
|
14
|
+
it "should store information that we can pull out later" do
|
15
|
+
CiInACan::LastRunList.add build, test_result
|
16
|
+
|
17
|
+
results = CiInACan::LastRunList.all
|
18
|
+
results.count.must_equal 1
|
19
|
+
|
20
|
+
expected = { created_at: test_result.created_at }
|
21
|
+
results.first.contrast_with! expected
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "all" do
|
27
|
+
|
28
|
+
describe "sorting" do
|
29
|
+
|
30
|
+
let(:build) { CiInACan::Build.new }
|
31
|
+
it "should sort by created_at in DESC order" do
|
32
|
+
|
33
|
+
test_results = [CiInACan::TestResult.new(id: 'c', created_at: Time.parse('1/3/2014')),
|
34
|
+
CiInACan::TestResult.new(id: 'a', created_at: Time.parse('1/1/2014')),
|
35
|
+
CiInACan::TestResult.new(id: 'b', created_at: Time.parse('1/2/2014'))]
|
36
|
+
|
37
|
+
test_results.each { |t| CiInACan::LastRunList.add build, t }
|
38
|
+
|
39
|
+
results = CiInACan::LastRunList.all
|
40
|
+
results[0][:test_result_id].must_equal 'c'
|
41
|
+
results[1][:test_result_id].must_equal 'b'
|
42
|
+
results[2][:test_result_id].must_equal 'a'
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -7,6 +7,11 @@ describe CiInACan::TestResultNotifier do
|
|
7
7
|
let(:build) { CiInACan::Build.new }
|
8
8
|
let(:test_result) { CiInACan::TestResult.new }
|
9
9
|
|
10
|
+
before do
|
11
|
+
CiInACan::LastRunList.stubs(:add)
|
12
|
+
CiInACan::Github.stubs(:report_complete_status_for)
|
13
|
+
end
|
14
|
+
|
10
15
|
it "should mark the results in github" do
|
11
16
|
|
12
17
|
test_result.passed = true
|
@@ -19,6 +24,11 @@ describe CiInACan::TestResultNotifier do
|
|
19
24
|
CiInACan::TestResultNotifier.send_for build, test_result
|
20
25
|
end
|
21
26
|
|
27
|
+
it "should add the build and test result to the last run list" do
|
28
|
+
CiInACan::LastRunList.expects(:add).with build, test_result
|
29
|
+
CiInACan::TestResultNotifier.send_for build, test_result
|
30
|
+
end
|
31
|
+
|
22
32
|
end
|
23
33
|
|
24
34
|
end
|
@@ -2,6 +2,20 @@ require_relative '../spec_helper'
|
|
2
2
|
|
3
3
|
describe CiInACan::TestRunner do
|
4
4
|
|
5
|
+
after { ::Timecop.return }
|
6
|
+
|
7
|
+
it "should default created_at to now" do
|
8
|
+
now = Time.now
|
9
|
+
::Timecop.freeze now
|
10
|
+
CiInACan::TestResult.new.created_at.must_equal now
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should allow the created_at to be set" do
|
14
|
+
now = Object.new
|
15
|
+
test_result = CiInACan::TestResult.new(created_at: now)
|
16
|
+
test_result.created_at.must_be_same_as now
|
17
|
+
end
|
18
|
+
|
5
19
|
describe "create" do
|
6
20
|
it "should set a unique id" do
|
7
21
|
id = Object.new
|
@@ -60,6 +74,25 @@ describe CiInACan::TestRunner do
|
|
60
74
|
|
61
75
|
end
|
62
76
|
|
77
|
+
describe "to_json" do
|
78
|
+
|
79
|
+
let(:fields) do
|
80
|
+
[:id, :passed, :output, :created_at]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return json that contains the values" do
|
84
|
+
uuid = ::UUID.new
|
85
|
+
values = fields.reduce({}) { |t, i| t[i] = uuid.generate; t }
|
86
|
+
|
87
|
+
test_result = CiInACan::TestResult.new values
|
88
|
+
|
89
|
+
json = JSON.parse(test_result.to_json)
|
90
|
+
|
91
|
+
fields.each { |f| json[f.to_s].must_equal values[f] }
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
63
96
|
end
|
64
97
|
|
65
98
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,8 +4,15 @@ require 'minitest/spec'
|
|
4
4
|
require 'minitest/pride'
|
5
5
|
require 'subtle'
|
6
6
|
require 'contrast'
|
7
|
+
require 'timecop'
|
7
8
|
require 'mocha/setup'
|
8
9
|
|
9
10
|
def CiInACan.results_location
|
10
11
|
File.expand_path(File.dirname(__FILE__) + '/temp')
|
11
12
|
end
|
13
|
+
|
14
|
+
def clear_all_persisted_data
|
15
|
+
Dir["#{CiInACan.results_location}/*.yml"].each do |file|
|
16
|
+
File.delete file
|
17
|
+
end
|
18
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ci_in_a_can
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-02-
|
12
|
+
date: 2014-02-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -75,6 +75,22 @@ dependencies:
|
|
75
75
|
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: timecop
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
95
|
name: rake
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -227,6 +243,7 @@ files:
|
|
227
243
|
- lib/ci_in_a_can/daemon.rb
|
228
244
|
- lib/ci_in_a_can/github.rb
|
229
245
|
- lib/ci_in_a_can/github_build_parser.rb
|
246
|
+
- lib/ci_in_a_can/last_run_list.rb
|
230
247
|
- lib/ci_in_a_can/persistence.rb
|
231
248
|
- lib/ci_in_a_can/runner.rb
|
232
249
|
- lib/ci_in_a_can/test_result.rb
|
@@ -234,6 +251,7 @@ files:
|
|
234
251
|
- lib/ci_in_a_can/test_runner.rb
|
235
252
|
- lib/ci_in_a_can/version.rb
|
236
253
|
- lib/ci_in_a_can/watcher.rb
|
254
|
+
- lib/ci_in_a_can/web_content.rb
|
237
255
|
- sample.json
|
238
256
|
- spec/ci_in_a_can/bash_result_spec.rb
|
239
257
|
- spec/ci_in_a_can/bash_spec.rb
|
@@ -241,6 +259,7 @@ files:
|
|
241
259
|
- spec/ci_in_a_can/cloner_spec.rb
|
242
260
|
- spec/ci_in_a_can/github_build_parser_spec.rb
|
243
261
|
- spec/ci_in_a_can/github_spec.rb
|
262
|
+
- spec/ci_in_a_can/last_run_list_spec.rb
|
244
263
|
- spec/ci_in_a_can/runner_spec.rb
|
245
264
|
- spec/ci_in_a_can/test_result_notifier_spec.rb
|
246
265
|
- spec/ci_in_a_can/test_result_spec.rb
|
@@ -263,7 +282,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
263
282
|
version: '0'
|
264
283
|
segments:
|
265
284
|
- 0
|
266
|
-
hash:
|
285
|
+
hash: 2564814720268167254
|
267
286
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
268
287
|
none: false
|
269
288
|
requirements:
|
@@ -272,10 +291,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
291
|
version: '0'
|
273
292
|
segments:
|
274
293
|
- 0
|
275
|
-
hash:
|
294
|
+
hash: 2564814720268167254
|
276
295
|
requirements: []
|
277
296
|
rubyforge_project:
|
278
|
-
rubygems_version: 1.8.
|
297
|
+
rubygems_version: 1.8.25
|
279
298
|
signing_key:
|
280
299
|
specification_version: 3
|
281
300
|
summary: Fast CI. Still a WIP.
|
@@ -286,6 +305,7 @@ test_files:
|
|
286
305
|
- spec/ci_in_a_can/cloner_spec.rb
|
287
306
|
- spec/ci_in_a_can/github_build_parser_spec.rb
|
288
307
|
- spec/ci_in_a_can/github_spec.rb
|
308
|
+
- spec/ci_in_a_can/last_run_list_spec.rb
|
289
309
|
- spec/ci_in_a_can/runner_spec.rb
|
290
310
|
- spec/ci_in_a_can/test_result_notifier_spec.rb
|
291
311
|
- spec/ci_in_a_can/test_result_spec.rb
|