ci_in_a_can 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,24 +1,47 @@
1
- # CiInACan
1
+ # CI In a Can
2
2
 
3
- TODO: Write a gem description
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
- ## Installation
5
+ This currently only hooks to Github repos. More later.
6
+
7
+ ## Philosophy
6
8
 
7
- Add this line to your application's Gemfile:
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
- gem 'ci_in_a_can'
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 then execute:
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
- $ bundle
15
+ ## Installation
14
16
 
15
- Or install it yourself as:
17
+ Install with:
16
18
 
17
19
  $ gem install ci_in_a_can
18
20
 
19
21
  ## Usage
20
22
 
21
- TODO: Write usage instructions here
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"
@@ -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
@@ -1,10 +1,14 @@
1
1
  module CiInACan
2
2
 
3
3
  class Build
4
- params_constructor
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
- { id: id, passed: passed, output: output }.to_json
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
@@ -9,6 +9,7 @@ module CiInACan
9
9
  private
10
10
 
11
11
  def self.report_results_to_github build, test_result
12
+ CiInACan::LastRunList.add build, test_result
12
13
  CiInACan::Github.report_complete_status_for build, test_result
13
14
  end
14
15
 
@@ -1,3 +1,3 @@
1
1
  module CiInACan
2
- VERSION = "0.0.10"
2
+ VERSION = "0.0.11"
3
3
  end
@@ -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.10
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-11 00:00:00.000000000 Z
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: 673563719843692982
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: 673563719843692982
294
+ hash: 2564814720268167254
276
295
  requirements: []
277
296
  rubyforge_project:
278
- rubygems_version: 1.8.24
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