cuke_ci_workers 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/cuke_ci_install +75 -0
- data/bin/cuke_ci_runner +7 -0
- data/lib/cuke_ci_workers/notifier.rb +80 -0
- data/lib/cuke_ci_workers/runner.rb +167 -0
- data/lib/cuke_ci_workers/worker.rb +47 -0
- data/templates/post-commit +11 -0
- data/templates/post-commit.erb +10 -0
- data/templates/post-receive +9 -0
- data/templates/runner_config.yml.erb +10 -0
- metadata +80 -0
data/bin/cuke_ci_install
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
def file_from_template(name, dest, project_id, api_key)
|
7
|
+
File.open(dest, 'w') do |f|
|
8
|
+
f.puts(render_template(name, project_id, api_key))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_template(name, project_id, api_key)
|
13
|
+
file_name = File.expand_path("../../templates/#{name}.erb", __FILE__)
|
14
|
+
erb = ERB.new(File.read(file_name))
|
15
|
+
erb.result(binding)
|
16
|
+
end
|
17
|
+
|
18
|
+
options = {}
|
19
|
+
options[:hook] = nil
|
20
|
+
options[:runner] = false
|
21
|
+
|
22
|
+
opts = OptionParser.new do |opts|
|
23
|
+
opts.banner = "Usage: [options] PROJECT_ID API_KEY"
|
24
|
+
|
25
|
+
opts.on "--runner-config", "Install runner config" do
|
26
|
+
options[:runner_config] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on "--post-commit", "Install post commit hook" do
|
30
|
+
options[:hook] = 'post-commit'
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on "--post-receive", "Install post receive hook" do
|
34
|
+
options[:hook] = 'post-receive'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
opts.parse!
|
40
|
+
rescue
|
41
|
+
puts opts.help
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
|
45
|
+
if ARGV.length != 2
|
46
|
+
puts opts.help
|
47
|
+
else
|
48
|
+
api_key = ARGV.pop
|
49
|
+
project_id = ARGV.pop
|
50
|
+
|
51
|
+
if options[:hook]
|
52
|
+
performed = false
|
53
|
+
|
54
|
+
%w(.git/hooks hooks).each do |dir|
|
55
|
+
hook_file_name = File.join(dir, options[:hook])
|
56
|
+
|
57
|
+
if File.exists?(dir)
|
58
|
+
file_from_template(options[:hook], hook_file_name, project_id, api_key)
|
59
|
+
File.chmod(0770, hook_file_name)
|
60
|
+
|
61
|
+
puts "Hook installed in '#{hook_file_name}'."
|
62
|
+
performed = true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
unless performed
|
67
|
+
puts 'Not in a git direcotry. Hook not installed.'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
if options[:runner_config]
|
72
|
+
file_from_template('runner_config.yml', 'cuke_ci_runner_config.yml', project_id, api_key)
|
73
|
+
puts 'Runner config installed.'
|
74
|
+
end
|
75
|
+
end
|
data/bin/cuke_ci_runner
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'grit'
|
7
|
+
|
8
|
+
require 'cuke_ci_workers/worker'
|
9
|
+
|
10
|
+
module CukeCIWorkers
|
11
|
+
class Notifier < Worker
|
12
|
+
def initialize(server_url, log_file_name, log_level = nil)
|
13
|
+
super(log_file_name, log_level)
|
14
|
+
@server_uri = URI.parse(server_url)
|
15
|
+
end
|
16
|
+
|
17
|
+
def post_commit
|
18
|
+
json = generate_json_for_head
|
19
|
+
push_json(json)
|
20
|
+
rescue Exception => e
|
21
|
+
log_exception(e)
|
22
|
+
end
|
23
|
+
|
24
|
+
def post_reveive(before_rev, after_rev, ref)
|
25
|
+
json = generate_json(before_rev, after_rev, ref)
|
26
|
+
push_json(json)
|
27
|
+
rescue Exception => e
|
28
|
+
log_exception(e)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def push_json(json)
|
34
|
+
Net::HTTP.start(@server_uri.host, @server_uri.port) do |http|
|
35
|
+
http.post("#{@server_uri.path}?#{@server_uri.query}", json, 'Content-Type' => 'application/json')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_json_for_head
|
40
|
+
generate_json('HEAD^', 'HEAD', repository.head.name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate_json(before_rev, after_rev, ref)
|
44
|
+
before = repository.commit(before_rev)
|
45
|
+
after = repository.commit(after_rev)
|
46
|
+
|
47
|
+
{:payload => {
|
48
|
+
:before => before.sha,
|
49
|
+
:after => after.sha,
|
50
|
+
:ref => ref,
|
51
|
+
:commits => repository.commits_between(before, after).collect do |commit|
|
52
|
+
{
|
53
|
+
:id => commit.sha,
|
54
|
+
:message => commit.message,
|
55
|
+
:timestamp => commit.committed_date.xmlschema,
|
56
|
+
:url => '',
|
57
|
+
:added => [],
|
58
|
+
:removed => [],
|
59
|
+
:modified => [],
|
60
|
+
:author => {
|
61
|
+
:name => commit.author.name,
|
62
|
+
:email => commit.author.email
|
63
|
+
}
|
64
|
+
}
|
65
|
+
end,
|
66
|
+
}
|
67
|
+
}.to_json
|
68
|
+
end
|
69
|
+
|
70
|
+
def repository
|
71
|
+
Grit::Repo.new(".")
|
72
|
+
end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
def parse!(args)
|
76
|
+
Notifier.new(*args)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'optparse'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'yaml'
|
9
|
+
require 'logger'
|
10
|
+
|
11
|
+
require 'cuke_ci_workers/worker'
|
12
|
+
|
13
|
+
module CukeCIWorkers
|
14
|
+
class Runner < Worker
|
15
|
+
def initialize(options)
|
16
|
+
@configuration_file_name = options[:configuration_file_name]
|
17
|
+
@configuration = YAML.load_file(@configuration_file_name)
|
18
|
+
|
19
|
+
@poll_uri = URI.parse(@configuration['poll_url'])
|
20
|
+
@push_url = @configuration['push_url']
|
21
|
+
|
22
|
+
@verbose = options[:verbose]
|
23
|
+
|
24
|
+
super(@configuration['log_file_name'], @configuration['log_level'])
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
$running = true
|
29
|
+
Signal.trap('INT') { $running = false }
|
30
|
+
|
31
|
+
while($running) do
|
32
|
+
begin
|
33
|
+
run_present = poll_for_run
|
34
|
+
#rescue Exception => e
|
35
|
+
# log_exception(e)
|
36
|
+
end
|
37
|
+
|
38
|
+
if run_present
|
39
|
+
begin
|
40
|
+
pull_repo
|
41
|
+
checkout_commit
|
42
|
+
prepare
|
43
|
+
|
44
|
+
if result = cucumber
|
45
|
+
push_result(result)
|
46
|
+
else
|
47
|
+
push_error
|
48
|
+
end
|
49
|
+
#rescue Exception => e
|
50
|
+
# log_exception(e)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
sleep 5
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def poll_for_run
|
61
|
+
message('Polling for run')
|
62
|
+
result = Net::HTTP.get(@poll_uri)
|
63
|
+
|
64
|
+
begin
|
65
|
+
hash = JSON.parse(result)
|
66
|
+
rescue JSON::ParserError
|
67
|
+
hash = {}
|
68
|
+
end
|
69
|
+
|
70
|
+
@commit_hash = hash['commit_hash']
|
71
|
+
@run_id = hash['id']
|
72
|
+
|
73
|
+
@commit_hash
|
74
|
+
end
|
75
|
+
|
76
|
+
def pull_repo
|
77
|
+
message("Pulling repository")
|
78
|
+
run_command(:pull)
|
79
|
+
end
|
80
|
+
|
81
|
+
def checkout_commit
|
82
|
+
message("Checking out #{@commit_hash}")
|
83
|
+
run_command(:check_out, @commit_hash)
|
84
|
+
end
|
85
|
+
|
86
|
+
def prepare
|
87
|
+
message('Preparing working directory')
|
88
|
+
return
|
89
|
+
run_command(:prepare)
|
90
|
+
end
|
91
|
+
|
92
|
+
def cucumber
|
93
|
+
message('Running Cucumber')
|
94
|
+
output = run_command(:cucumber, temp_file_name)
|
95
|
+
|
96
|
+
if $?.success?
|
97
|
+
File.read(temp_file_name)
|
98
|
+
else
|
99
|
+
logger.error("Cucumber failed: #{output}")
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def push_result(result)
|
105
|
+
message('Pushing results')
|
106
|
+
logger.info "Pushing result: #{result}"
|
107
|
+
|
108
|
+
json = "{'payload': #{result}}"
|
109
|
+
|
110
|
+
push_json(json)
|
111
|
+
end
|
112
|
+
|
113
|
+
def push_error
|
114
|
+
message('Pushing error')
|
115
|
+
json = "{'error': 'Cucumber did not complete successfully.'}"
|
116
|
+
logger.info "Pushing error: #{json}"
|
117
|
+
|
118
|
+
push_json(json)
|
119
|
+
end
|
120
|
+
|
121
|
+
def push_json(json)
|
122
|
+
url = @push_url % @run_id
|
123
|
+
@push_uri = URI.parse(url)
|
124
|
+
|
125
|
+
message "Pushing json to #{url}"
|
126
|
+
|
127
|
+
Net::HTTP.start(@push_uri.host, @push_uri.port) do |http|
|
128
|
+
http.post("#{@push_uri.path}?#{@push_uri.query}", json, 'Content-Type' => 'application/json')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def temp_file_name
|
133
|
+
@configuration['temp_file_name']
|
134
|
+
end
|
135
|
+
|
136
|
+
class << self
|
137
|
+
def parse!(args)
|
138
|
+
default_runner_config_file_name = './cuke_ci_runner_config.yml'
|
139
|
+
options = {}
|
140
|
+
|
141
|
+
opts = OptionParser.new do |opts|
|
142
|
+
opts.banner = 'Usage: ...'
|
143
|
+
|
144
|
+
opts.on("-c", "--configuration CONFIGURATION_FILE_NAME", "Path to configuration file. Defaults to '#{default_runner_config_file_name}'.") do |file_name|
|
145
|
+
options[:configuration_file_name] = file_name
|
146
|
+
end
|
147
|
+
|
148
|
+
opts.on("-v", "--verbose", "Be verbose") do |v|
|
149
|
+
options[:verbose] = true
|
150
|
+
end
|
151
|
+
|
152
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
153
|
+
puts opts
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
end
|
157
|
+
opts.parse!
|
158
|
+
|
159
|
+
options[:configuration_file_name] ||= default_runner_config_file_name
|
160
|
+
self.new(options)
|
161
|
+
rescue OptionParser::ParseError
|
162
|
+
puts opts
|
163
|
+
exit
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
require 'yaml'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
module CukeCIWorkers
|
9
|
+
class Worker
|
10
|
+
attr_accessor :logger
|
11
|
+
|
12
|
+
def initialize(log_file_name, log_level = nil)
|
13
|
+
@logger = Logger.new(log_file_name)
|
14
|
+
@logger.level = Logger.const_get(log_level) rescue Logger::INFO
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def log_exception(e)
|
20
|
+
logger.error(e.message + "\n " + e.backtrace * "\n ")
|
21
|
+
end
|
22
|
+
|
23
|
+
def message(text)
|
24
|
+
logger.info text
|
25
|
+
if @verbose
|
26
|
+
puts("========= #{text} =========")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_command(key, *args)
|
31
|
+
command = interpolate_command(key, args)
|
32
|
+
logger.info " #{command}"
|
33
|
+
|
34
|
+
if @verbose
|
35
|
+
puts command
|
36
|
+
`#{command}`
|
37
|
+
else
|
38
|
+
`#{command} 2> /dev/null`
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def interpolate_command(key, args)
|
43
|
+
command = @configuration['commands'][key.to_s]
|
44
|
+
command % args
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
server_url = 'http://localhost:3000/projects/1/receipt?api_key=3d177538439c92c8d278208ff1ae098f'
|
4
|
+
log_file_name = 'cuke_ci_notifier.log'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'cuke_ci_workers/notifier'
|
8
|
+
# require '/home/tim/code/rr10/rr10-team-179/cucumber-ci-workers/lib/cuke_ci_workers/notifier'
|
9
|
+
|
10
|
+
CukeCIWorkers::Notifier.new(server_url, log_file_name).post_commit
|
11
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
server_url = 'http://localhost:3000/projects/<%= project_id %>/receipt?api_key=<%= api_key %>'
|
4
|
+
log_file_name = 'cuke_ci_notifier.log'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'cuke_ci_workers/notifier'
|
8
|
+
|
9
|
+
CukeCIWorkers::Notifier.new(server_url, log_file_name).post_commit
|
10
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
temp_file_name: "cucumber.out"
|
2
|
+
log_file_name: "cuke_ci_runner.log"
|
3
|
+
log_level: "WARN"
|
4
|
+
poll_url: "http://localhost:3000/projects/<%= project_id %>/runs/next?api_key=<%= api_key %>"
|
5
|
+
push_url: "http://localhost:3000/projects/<%= project_id %>/runs/%s/results?api_key=<%= api_key %>"
|
6
|
+
commands:
|
7
|
+
pull: "git pull origin master"
|
8
|
+
check_out: "git reset --hard %s"
|
9
|
+
prepare: "rake db:reset"
|
10
|
+
cucumber: "cucumber --format json --out %s"
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cuke_ci_workers
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Gregor Weckbecker
|
13
|
+
- Vangelis Tsoumenis
|
14
|
+
- Tim Fischbach
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-10-17 00:00:00 +02:00
|
20
|
+
default_executable:
|
21
|
+
dependencies: []
|
22
|
+
|
23
|
+
description: Cucumber based continuous integration.
|
24
|
+
email:
|
25
|
+
- info@timfischbach.de
|
26
|
+
executables:
|
27
|
+
- cuke_ci_runner
|
28
|
+
- cuke_ci_install
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- bin/cuke_ci_runner
|
35
|
+
- bin/cuke_ci_install
|
36
|
+
- lib/cuke_ci_workers/worker.rb
|
37
|
+
- lib/cuke_ci_workers/runner.rb
|
38
|
+
- lib/cuke_ci_workers/notifier.rb
|
39
|
+
- templates/post-commit
|
40
|
+
- templates/runner_config.yml.erb
|
41
|
+
- templates/post-commit.erb
|
42
|
+
- templates/post-receive
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://whiteboard.r10.railsrumble.com/
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
hash: 23
|
67
|
+
segments:
|
68
|
+
- 1
|
69
|
+
- 3
|
70
|
+
- 6
|
71
|
+
version: 1.3.6
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.7
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Runner and notifier tool for CukeCI.
|
79
|
+
test_files: []
|
80
|
+
|