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 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