cuke_ci_workers 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
4
+ require 'cuke_ci_workers/runner'
5
+
6
+ CukeCIWorkers::Runner.parse!(ARGV).run
7
+
@@ -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,9 @@
1
+ #!/usr/bin/ruby
2
+
3
+ server_url = 'http://localhost:3000/project/1/receipt'
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_reveice(*ARGV)
@@ -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
+