groundcontrol 0.0.1
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/bin/groundcontrol +27 -0
- data/lib/groundcontrol/build_report.rb +25 -0
- data/lib/groundcontrol/builder.rb +165 -0
- data/lib/groundcontrol/test_result.rb +46 -0
- data/lib/groundcontrol.rb +3 -0
- metadata +103 -0
data/bin/groundcontrol
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'yaml'
|
5
|
+
require 'groundcontrol'
|
6
|
+
|
7
|
+
module GroundControl
|
8
|
+
|
9
|
+
class Command
|
10
|
+
|
11
|
+
def self.run
|
12
|
+
repositories = YAML.load_file("config/projects.yml")['projects']
|
13
|
+
FileUtils.mkdir_p "builds"
|
14
|
+
|
15
|
+
repositories.each do |project, config|
|
16
|
+
|
17
|
+
build_task = GroundControl::Builder.new(project, config)
|
18
|
+
build_task.build
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
GroundControl::Command.run
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GroundControl
|
2
|
+
|
3
|
+
class BuildReport
|
4
|
+
|
5
|
+
attr_reader :project_name, :branch, :testunit_success, :cucumber_success, :commit
|
6
|
+
|
7
|
+
def initialize(project_name, branch, testunit_success, cucumber_success, commit)
|
8
|
+
@project_name = project_name
|
9
|
+
@branch = branch
|
10
|
+
@testunit_success = testunit_success
|
11
|
+
@cucumber_success = cucumber_success
|
12
|
+
@commit = commit
|
13
|
+
end
|
14
|
+
|
15
|
+
def success?
|
16
|
+
testunit_success && cucumber_success
|
17
|
+
end
|
18
|
+
|
19
|
+
def failed?
|
20
|
+
!success?
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'git'
|
3
|
+
require 'tinder'
|
4
|
+
require 'grit'
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
module GroundControl
|
8
|
+
|
9
|
+
class Builder
|
10
|
+
|
11
|
+
def initialize(project_name, config)
|
12
|
+
@project_name = project_name
|
13
|
+
@config = config
|
14
|
+
@workspace = File.join("builds", project_name)
|
15
|
+
@build_directory = File.join(@workspace, "build")
|
16
|
+
@reports_directory = File.join(@workspace, "reports")
|
17
|
+
@git_url = @config['git']
|
18
|
+
end
|
19
|
+
|
20
|
+
def build
|
21
|
+
create_workspace()
|
22
|
+
|
23
|
+
clone_repository()
|
24
|
+
|
25
|
+
prepare_build_environment()
|
26
|
+
|
27
|
+
test_report = run_tests_and_report()
|
28
|
+
|
29
|
+
notify_campfire_of_build_result(test_report, @project_name, @repository)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def notify_campfire_of_build_result(test_report, project_name, repository)
|
35
|
+
campfire_config = @config['campfire']
|
36
|
+
|
37
|
+
campfire = Tinder::Campfire.new campfire_config['subdomain'], :token => campfire_config['token']
|
38
|
+
room = campfire.find_room_by_name(campfire_config['room'])
|
39
|
+
|
40
|
+
last_commit = repository.commits.first
|
41
|
+
|
42
|
+
if test_report.success?
|
43
|
+
room.speak "Build SUCCEEDED. +1 for #{last_commit.author.name}."
|
44
|
+
else
|
45
|
+
room.speak "Build FAILED for #{project_name}/#{repository.head.name} #{@config['github']}/commit/#{test_report.commit.sha}. #{last_commit.author.name} is definitely not the best developer."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def start_virtual_screen
|
50
|
+
ENV['DISPLAY'] = ":5"
|
51
|
+
|
52
|
+
xvfb_pid = fork do
|
53
|
+
exec 'Xvfb :5 -ac -screen 0 1024x768x8'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def run_unit_tests()
|
58
|
+
ENV['CI_REPORTS'] = "../reports/testunit"
|
59
|
+
|
60
|
+
test_output = `cd #{@build_directory}; bundle exec rake ci:setup:testunit test`
|
61
|
+
return $?.to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def run_cucumber_tests()
|
65
|
+
screen_pid = start_virtual_screen()
|
66
|
+
|
67
|
+
ENV['CUCUMBER_OPTS'] = "--format junit --out ../reports/features"
|
68
|
+
|
69
|
+
cucumber_output = `cd #{@build_directory}; bundle exec rake cucumber`
|
70
|
+
cucumber_status = $?.to_i
|
71
|
+
|
72
|
+
Process.kill "TERM", screen_pid
|
73
|
+
|
74
|
+
return cucumber_status
|
75
|
+
end
|
76
|
+
|
77
|
+
def run_tests_and_report()
|
78
|
+
testunit_return_code = run_unit_tests()
|
79
|
+
cucumber_return_code = run_cucumber_tests()
|
80
|
+
|
81
|
+
return BuildReport.new(@project_name, @repository.head.name, testunit_return_code == 0, cucumber_return_code == 0, @repository.commits.first)
|
82
|
+
end
|
83
|
+
|
84
|
+
def clone_repository
|
85
|
+
Git.clone(@git_url, @build_directory)
|
86
|
+
@repository = Grit::Repo.new(@build_directory)
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_workspace
|
90
|
+
FileUtils.rm_rf @workspace
|
91
|
+
|
92
|
+
FileUtils.mkdir_p(@build_directory)
|
93
|
+
FileUtils.mkdir_p(@reports_directory)
|
94
|
+
end
|
95
|
+
|
96
|
+
def initialize_rvm
|
97
|
+
system "cd #{@build_directory}; rvm rvmrc trust"
|
98
|
+
system "cd #{@build_directory}; rvm reload"
|
99
|
+
end
|
100
|
+
|
101
|
+
def install_bundler_gems()
|
102
|
+
system "cd #{@build_directory}; bundle install --without production"
|
103
|
+
end
|
104
|
+
|
105
|
+
def inject_ci_reporter()
|
106
|
+
doc = <<EOF
|
107
|
+
require 'rubygems'
|
108
|
+
require 'ci/reporter/rake/test_unit' # use this if you're using Test::Unit
|
109
|
+
EOF
|
110
|
+
|
111
|
+
File.open("#{@build_directory}/lib/tasks/ci_reporter.rake", 'w') { |f| f.write(doc) }
|
112
|
+
end
|
113
|
+
|
114
|
+
def inject_database_config()
|
115
|
+
|
116
|
+
database = <<EOF
|
117
|
+
test: &test
|
118
|
+
adapter: mysql2
|
119
|
+
encoding: utf8
|
120
|
+
reconnect: false
|
121
|
+
database: #{@project_name}_test
|
122
|
+
pool: 5
|
123
|
+
username: root
|
124
|
+
password:
|
125
|
+
|
126
|
+
cucumber:
|
127
|
+
<<: *test
|
128
|
+
EOF
|
129
|
+
|
130
|
+
File.open("#{@build_directory}/config/database.yml", 'w') { |f| f.write(database) }
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def load_empty_schema()
|
135
|
+
system "cd #{@build_directory}; bundle exec rake db:schema:load"
|
136
|
+
end
|
137
|
+
|
138
|
+
def setup_database()
|
139
|
+
inject_database_config()
|
140
|
+
load_empty_schema()
|
141
|
+
end
|
142
|
+
|
143
|
+
def inject_thinking_sphinx_config
|
144
|
+
sphinx_config = <<EOF
|
145
|
+
test:
|
146
|
+
port: 9312
|
147
|
+
EOF
|
148
|
+
|
149
|
+
File.open("#{@build_directory}/config/sphinx.yml", 'w') { |f| f.write(sphinx_config) }
|
150
|
+
end
|
151
|
+
|
152
|
+
def prepare_build_environment
|
153
|
+
ENV['RAILS_ENV'] = "test"
|
154
|
+
|
155
|
+
initialize_rvm()
|
156
|
+
install_bundler_gems()
|
157
|
+
inject_ci_reporter()
|
158
|
+
|
159
|
+
setup_database()
|
160
|
+
inject_thinking_sphinx_config()
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module GroundControl
|
4
|
+
|
5
|
+
class TestResult
|
6
|
+
|
7
|
+
attr_reader :name, :message
|
8
|
+
|
9
|
+
def self.read_from_xml(xml_string)
|
10
|
+
doc = Nokogiri::XML.parse(xml_string)
|
11
|
+
tests = []
|
12
|
+
|
13
|
+
doc.xpath('//testcase').each do |testcase|
|
14
|
+
failure = testcase.xpath('//failure')
|
15
|
+
if failure.blank?
|
16
|
+
tests << TestResult.new(testcase['name'])
|
17
|
+
else
|
18
|
+
tests << TestResult.new(testcase['name'], failure.first.content)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
return tests
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(name, failure_message = nil)
|
27
|
+
@name = name
|
28
|
+
@failed = false
|
29
|
+
|
30
|
+
if failure_message
|
31
|
+
@failed = true
|
32
|
+
@message = failure_message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def failed?
|
37
|
+
return @failed
|
38
|
+
end
|
39
|
+
|
40
|
+
def success?
|
41
|
+
return true if not @failed
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: groundcontrol
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michiel Sikkes
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-15 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: grit
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: git
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: tinder
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: nokogiri
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id004
|
60
|
+
description: Groundcontrol powers test builds for Rails projects
|
61
|
+
email: michiel@firmhouse.com
|
62
|
+
executables:
|
63
|
+
- groundcontrol
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
extra_rdoc_files: []
|
67
|
+
|
68
|
+
files:
|
69
|
+
- lib/groundcontrol.rb
|
70
|
+
- lib/groundcontrol/builder.rb
|
71
|
+
- lib/groundcontrol/build_report.rb
|
72
|
+
- lib/groundcontrol/test_result.rb
|
73
|
+
- bin/groundcontrol
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: http://github.com/Firmhouse/groundcontrol
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.6.2
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Runs automated Rails tests and reports back.
|
102
|
+
test_files: []
|
103
|
+
|