cerberus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,7 @@
1
+ = Cerberus Changelog
2
+
3
+ == Version 0.1.0
4
+
5
+ Initial version of Cerberus tool
6
+
7
+ * Implemented basic functionality required by Continuous Integration.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2006 Anatol Pomozov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README ADDED
@@ -0,0 +1,57 @@
1
+ Cerberus developed by Anatol Pomozov (anatol.pomozov@gmail.com) and shared under MIT license.
2
+
3
+ Cerberus is continuous integration (CI) software. Cerberus could be periodically run from scheduler
4
+ and check if application tests are broken. If it happend then Cerberus sends notification to developers.
5
+
6
+ For more CI theory read this document from Martin Fowler
7
+ http://www.martinfowler.com/articles/continuousIntegration.html.
8
+
9
+ Requirements:
10
+ ruby - 1.8.2 or higher
11
+ rake - 0.7 or higher
12
+ svn client - 1.2 or higher
13
+
14
+
15
+ What 'Cerberus' name means?
16
+ Quote from Wikipedia (http://en.wikipedia.org/wiki/Cerberus)
17
+
18
+ Cerberus or Kerberos (Kerberos, demon of the pit), was the hound of Hades-a monstrous three-headed dog (sometimes said to have 50 or 100 heads) with a snake for a tail and innumerable snake heads on his back.
19
+ He guarded the gate to Hades (the Greek underworld) and ensured that the dead could not leave and the living could not enter. His brother was Orthrus. He is the offspring of Echidna and Typhon.
20
+
21
+
22
+ So Cerberus will guard your tests and not allow your project to go to the world of dead.
23
+
24
+
25
+ To use Cerberus it is very easy. First install it. Easiest way to do it through RubyGems package manager.
26
+
27
+ 'gem install cerberus'
28
+
29
+ then you need to add project that will be watched by Cerberus. Do it by
30
+
31
+ cerberus add (DIR|SVN_URL)? #Adds project to list of watched applications
32
+
33
+ as second parameted you could pass URL to subversion repository or directory with working SVN folder.
34
+ If this parameted absent then would be added project from current directory
35
+
36
+ Go to ~./cerberus and edit config.yml file (only once after installing Cerberus). Enter your configuration options here
37
+ like email server, password, user_name and other options. See ActiveMailer description - Cerberus uses it as notification
38
+ layer. Mine config file looks like this
39
+ mail:
40
+ address: mail.somesever.com
41
+ user_name: anatol
42
+ password: anatol
43
+ domain: somesever.com
44
+ authentication: login
45
+
46
+ Also go to ~/.cerberus/config/<PROJECT_NAME>.yml and add comma-separated list of recipients for this project
47
+ You could also change <PROJECT_NAME> to any other name. This name what Cerberus will use.
48
+
49
+ And then run Cerberus
50
+
51
+ cerberus build PROJECT_NAME #Run project
52
+
53
+ It will check out latest sources and run tests for your app. If tests are broken - recipients will recieve notifications.
54
+
55
+ But of course better run Cerberus automatically from Cron. Run it each 10 minutes for project will be ok.
56
+
57
+ Well, thats all. If you have any questions, proposals - just let me know.
data/Rakefile ADDED
@@ -0,0 +1,129 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/packagetask'
5
+ require 'rake/gempackagetask'
6
+ require 'rake/contrib/rubyforgepublisher'
7
+
8
+ require "./lib/cerberus/version"
9
+
10
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
11
+ PKG_NAME = 'cerberus'
12
+ PKG_VERSION = Cerberus::VERSION::STRING + PKG_BUILD
13
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
+
15
+ RELEASE_NAME = "REL #{PKG_VERSION}"
16
+
17
+ RUBY_FORGE_PROJECT = "cerberus"
18
+ RUBY_FORGE_USER = "anatol"
19
+
20
+ task :default => [:test, :clean]
21
+
22
+ desc "Run the unit tests in test/unit"
23
+ Rake::TestTask.new(:test) do |t|
24
+ t.libs << "test"
25
+ t.pattern = 'test/*_test.rb'
26
+ t.verbose = true
27
+ end
28
+
29
+ desc "Clean all generated files"
30
+ task :clean => :clobber_package do
31
+ rm_rf './test/__workdir'
32
+ end
33
+
34
+
35
+ GEM_SPEC = Gem::Specification.new do |s|
36
+ s.name = PKG_NAME
37
+ s.version = PKG_VERSION
38
+ s.platform = Gem::Platform::RUBY
39
+ s.required_ruby_version = ">=1.8.2"
40
+
41
+ s.summary = "Cerberus is a Continuous Integration tool that could be easily run from Cron."
42
+ s.description = <<-DESC.strip.gsub(/\n\s+/, " ")
43
+ Cerberus is a Continuous Integration software for Ruby projects. CI helps you keep your project
44
+ in a good shape.
45
+
46
+ For now Cerberus only work with projects that use Subversion but in the future it would be provided
47
+ support for other VCS.
48
+
49
+ Cerberus could be easily invoked from Cron (for Unix) or nnCron (for Windows) utilities.
50
+ DESC
51
+
52
+ s.add_dependency 'actionmailer', '>= 1.2.1'
53
+ s.add_dependency 'rake', '>= 0.7.1'
54
+
55
+ s.files = Dir.glob("{bin,doc,lib,test}/**/*").delete_if { |item| item.include?('__workdir') }
56
+ s.files += %w(LICENSE README CHANGES Rakefile)
57
+
58
+ s.bindir = "bin"
59
+ s.executables = ["cerberus"]
60
+ s.default_executable = "cerberus"
61
+
62
+ s.require_path = 'lib'
63
+
64
+ s.has_rdoc = true
65
+ s.extra_rdoc_files = [ "README" ]
66
+ s.rdoc_options = [ "--main", "README" ]
67
+
68
+ s.test_suite_file = "test/integration_test.rb"
69
+
70
+ s.author = "Anatol Pomozov"
71
+ s.email = "anatol.pomozov@gmail.com"
72
+ s.homepage = "http://rubyforge.org/projects/cerberus"
73
+ s.rubyforge_project = "cerberus"
74
+ end
75
+
76
+
77
+ Rake::GemPackageTask.new(GEM_SPEC) do |p|
78
+ p.gem_spec = GEM_SPEC
79
+ p.need_tar = true
80
+ p.need_zip = true
81
+ end
82
+
83
+ task :install => [:clean, :test, :package] do
84
+ system "gem install pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
85
+ end
86
+
87
+ task :uninstall => [:clean] do
88
+ system "gem uninstall #{PKG_NAME}"
89
+ end
90
+
91
+ desc "Look for TODO and FIXME tags in the code"
92
+ task :todo do
93
+ Pathname.new(File.dirname(__FILE__)).egrep(/#.*(FIXME|TODO|TBD|DEPRECATED)/) do |match|
94
+ puts match
95
+ end
96
+ end
97
+
98
+ task :reinstall => [:uninstall, :install] do
99
+ end
100
+
101
+ task :release_files => [:clean, :package] do
102
+ require 'meta_project'
103
+ project = MetaProject::Project::XForge::RubyForge.new(RUBY_FORGE_PROJECT)
104
+
105
+ release_files = FileList[
106
+ "pkg/#{PKG_FILE_NAME}.gem",
107
+ "pkg/#{PKG_FILE_NAME}.zip",
108
+ "pkg/#{PKG_FILE_NAME}.tgz"
109
+ ]
110
+
111
+ Rake::XForge::Release.new(project) do |release|
112
+ release.user_name = RUBY_FORGE_USER
113
+ release.password = ENV['RUBYFORGE_PASSWORD']
114
+ release.files = release_files.to_a
115
+ release.package_name = PKG_NAME
116
+ release.release_name = "Cerberus #{PKG_VERSION}"
117
+ end
118
+
119
+ end
120
+
121
+ task :publish_news do
122
+ require 'meta_project'
123
+ Rake::XForge::NewsPublisher.new(project) do |publisher|
124
+ publisher.user_name = RUBY_FORGE_USER
125
+ publisher.password = ENV['RUBYFORGE_PASSWORD']
126
+ publisher.subject = "Cerberus #{PKG_VERSION} Released"
127
+ publisher.details = "I am glad to announce first public release of Cerberus tool. Version #{PKG_VERSION} is out. Cerberus is a simple command-line Continuous integration tool for Ruby project. Install Cerberus with 'gem install cerberus' then add project 'cerberus add SVN_URL' and then build it 'cerberus build YOUR_PROJECT_NAME'"
128
+ end
129
+ end
data/bin/cerberus ADDED
@@ -0,0 +1,3 @@
1
+ require 'cerberus/cli'
2
+
3
+ Cerberus::CLI.new(*ARGV)
data/doc/FAQ ADDED
File without changes
@@ -0,0 +1,68 @@
1
+ require 'cerberus/manager'
2
+ require 'cerberus/utils'
3
+ require 'cerberus/version'
4
+ require 'cerberus/constants'
5
+
6
+ module Cerberus
7
+ class CLI
8
+ include Cerberus::Utils
9
+
10
+ def initialize(*args)
11
+ say HELP if args.empty?
12
+
13
+ command = args.shift
14
+ say HELP unless %w(add build).include?(command)
15
+
16
+ cli_options = extract_options(args)
17
+
18
+ case command
19
+ when 'add'
20
+ path = args.shift || Dir.pwd
21
+
22
+ command = Cerberus::Add.new(path, cli_options)
23
+ command.run
24
+ when 'build'
25
+ say HELP if args.empty?
26
+
27
+ application_name = args.shift
28
+
29
+ command = Cerberus::Build.new(application_name, cli_options)
30
+ begin
31
+ command.run
32
+ rescue Exception => e
33
+ File.open("#{HOME}/work/#{application_name}/error.log", File::WRONLY|File::APPEND|File::CREAT) do |f|
34
+ f.puts Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")
35
+ f.puts e.message
36
+ f.puts e.backtrace.collect{|line| ' '*5 + line}
37
+ f.puts "\n"
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ private
44
+ def extract_options(args)
45
+ result = {}
46
+ args_copy = args.dup
47
+ args_copy.each do |arg|
48
+ if arg =~ /^(\w+)=(.*)$/
49
+ result[$1.downcase.to_sym] = $2
50
+ args.delete(arg)
51
+ end
52
+ end
53
+
54
+ result
55
+ end
56
+ end
57
+
58
+ HELP = %{
59
+ Cerberus is a Continuous Integration tool that could be run from commad line.
60
+
61
+ Usage:
62
+ cerberus add <URL> --- add project from svn repository to list watched of applications
63
+ cerberus add <PATH> --- add project from local path to list of watched applications
64
+ cerberus build <APPLICATION_NAME> --- build watched application
65
+
66
+ Version #{Cerberus::VERSION::STRING}
67
+ }.gsub("\n ","\n")
68
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+
4
+ require 'cerberus/constants'
5
+
6
+ module Cerberus
7
+ class Config
8
+ def initialize(app_name, cli_options = {})
9
+ @config = HashWithIndifferentAccess.new
10
+ if app_name
11
+ @config.merge!(YAML.load(IO.read(CONFIG_FILE))) if test(?f, CONFIG_FILE)
12
+ @config.merge!(YAML.load(IO.read(HOME + "/config/#{app_name}.yml")))
13
+ end
14
+ @config.merge!(cli_options)
15
+ end
16
+
17
+ def [](name)
18
+ @config[name]
19
+ end
20
+
21
+ private
22
+ def symbolize_hash(hash)
23
+ hash.each_pair{|k,v|
24
+ if v === Hash
25
+ hash[k] = HashWithIndifferentAccess.new(symbolize_hash(v))
26
+ end
27
+ }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ module Cerberus
2
+ HOME = File.expand_path(ENV['CERBERUS_HOME'] || '~/.cerberus')
3
+ CONFIG_FILE = "#{HOME}/config.yml"
4
+ end
@@ -0,0 +1,22 @@
1
+ module Cerberus
2
+ module FSLatch
3
+ #Emulate File.flock
4
+ def self.lock(lock_file, wait_for_unlock=true)
5
+ counter = 0
6
+ while File.exists?(lock_file)
7
+ return unless wait_for_unlock #if file exists then return
8
+
9
+ sleep(10) #sleep for 10 seconds
10
+ counter += 1
11
+ raise "Could not wait anymore file unlocking '#{lock_file}'" if counter > 20 #if we are waiting more than 200 secs then raise exception
12
+ end
13
+
14
+ begin
15
+ File.new(lock_file, 'w')
16
+ yield
17
+ ensure
18
+ File.rm(lockfile)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,246 @@
1
+ require 'rubygems'
2
+ require 'action_mailer'
3
+ require 'fileutils'
4
+
5
+ require 'cerberus/utils'
6
+ require 'cerberus/constants'
7
+ require 'cerberus/config'
8
+
9
+ module Cerberus
10
+ class Add
11
+ include Cerberus::Utils
12
+
13
+ def initialize(path, cli_options = {})
14
+ @path, @config = path, Config.new(nil, cli_options)
15
+ end
16
+
17
+ def run
18
+ checkout = Checkout.new(@path, @config)
19
+ say "Can't find any svn application under #{@path}" unless checkout.url
20
+
21
+ application_name = @config[:application_name] || File.basename(File.expand_path(@path)).strip
22
+
23
+ create_default_config
24
+
25
+ config_name = "#{HOME}/config/#{application_name}.yml"
26
+ say "Application #{application_name} already present in Cerberus" if File.exists?(config_name)
27
+
28
+ app_config = {
29
+ 'url' => checkout.url,
30
+ 'recipients' => @config[:recipients]
31
+ }
32
+ dump_yml(config_name, app_config)
33
+ puts "Application '#{application_name}' was successfully added to Cerberus" unless @config[:quiet]
34
+ end
35
+
36
+ private
37
+ def create_default_config
38
+ default_mail_config =
39
+ {'mail'=>
40
+ { 'delivery_method'=>'smtp',
41
+ 'address'=>'somserver.com',
42
+ 'port' => 25,
43
+ 'domain'=>'somserver.com',
44
+ 'user_name'=>'secret_user',
45
+ 'password'=>'secret_password',
46
+ 'authentication' => 'plain'
47
+ },
48
+ 'sender' => "'Cerberus' <cerberus@example.com>"}
49
+ dump_yml(CONFIG_FILE, default_mail_config, false)
50
+ end
51
+ end
52
+
53
+ class Build
54
+ include Cerberus::Utils
55
+ attr_reader :output, :success, :checkout, :status
56
+
57
+ def initialize(application_name, cli_options = {})
58
+ unless File.exists?("#{HOME}/config/#{application_name}.yml")
59
+ say "Project #{application_name} does not present in Cerberus"
60
+ end
61
+
62
+ app_root = "#{HOME}/work/#{application_name}"
63
+
64
+ def_options = {:application_root => app_root + '/sources', :application_name => application_name} #pseudo options that stored in config. Could not be set in any config file not through CLI
65
+ @config = Config.new(application_name, cli_options.merge(def_options))
66
+
67
+ @status = Status.new("#{app_root}/status.log")
68
+
69
+ @checkout = Checkout.new(@config[:application_root], @config)
70
+ end
71
+
72
+ def run
73
+ @checkout.update!
74
+
75
+ previous_status = @status.recall
76
+
77
+ state =
78
+ if @checkout.has_changes? or not previous_status
79
+ if status = make
80
+ @status.keep(:succesful)
81
+ previous_status == :failed ? :revived : :succesful
82
+ else
83
+ @status.keep(:failed)
84
+ previous_status == :failed ? :broken : :failed
85
+ end
86
+ else
87
+ :unchanged
88
+ end
89
+
90
+ case state
91
+ when :failed
92
+ Notifier.deliver_failure(self, @config)
93
+ when :revived
94
+ Notifier.deliver_revival(self, @config)
95
+ when :broken
96
+ Notifier.deliver_broken(self, @config)
97
+ when :unchanged, :succesful
98
+ unless previous_status #If it first time we build application then let everyone to know that we have Cerberus now
99
+ Notifier.deliver_setup(self, @config)
100
+ end
101
+
102
+ # Smile, be happy, it's all good
103
+ end
104
+ end
105
+
106
+ private
107
+ def make
108
+ Dir.chdir @config[:application_root]
109
+
110
+ @output = `#{@config[:bin_path]}#{choose_rake_exec()} #{@config[:rake_task]} 2>&1`
111
+
112
+ make_successful?
113
+ end
114
+
115
+ def make_successful?
116
+ $?.exitstatus == 0 and not @output.include?('rake aborted!')
117
+ end
118
+
119
+ def choose_rake_exec
120
+ ext = ['']
121
+
122
+ if os() == :windows
123
+ ext << '.bat' << '.cmd'
124
+ end
125
+
126
+ ext.each{|e|
127
+ begin
128
+ out = `rake#{e} --version`
129
+ return "rake#{e}" if out =~ /rake/
130
+ rescue
131
+ end
132
+ }
133
+ end
134
+ end
135
+
136
+ class Checkout
137
+ def initialize(path, options = {})
138
+ raise "Path can't be nil" unless path
139
+
140
+ @path, @options = path.strip, options
141
+ @encoded_path = (@path.include?(' ') ? "\"#{@path}\"" : @path)
142
+ end
143
+
144
+ def update!
145
+ if test(?d, @path + '/.svn')
146
+ @status = execute("svn update")
147
+ else
148
+ FileUtils.mkpath(@path) unless test(?d,@path)
149
+ @status = execute("svn checkout", nil, @options[:url])
150
+ end
151
+ end
152
+
153
+ def has_changes?
154
+ @status =~ /[A-Z]\s+[\w\/]+/
155
+ end
156
+
157
+ def current_revision
158
+ info['Revision'].to_i
159
+ end
160
+
161
+ def url
162
+ info['URL']
163
+ end
164
+
165
+ def last_commit_message
166
+ message = execute("svn log", "--limit 1 -v")
167
+ #strip first line that contains command line itself (svn log --limit ...)
168
+ if ((idx = message.index('-'*72)) != 0 )
169
+ message[idx..-1]
170
+ else
171
+ message
172
+ end
173
+ end
174
+
175
+ def last_author
176
+ info['Last Changed Author']
177
+ end
178
+
179
+ private
180
+ def info
181
+ @info ||= YAML.load(execute("svn info"))
182
+ end
183
+
184
+ def execute(command, parameters = nil, pre_parameters = nil)
185
+ `#{@options[:bin_path]}#{command} #{pre_parameters} #{@encoded_path} #{parameters}`
186
+ end
187
+ end
188
+
189
+ class Status
190
+ def initialize(path)
191
+ @path = path
192
+ end
193
+
194
+ def keep(status)
195
+ File.open(@path, "w+", 0777) { |file| file.write(status.to_s) }
196
+ end
197
+
198
+ def recall
199
+ value = File.exists?(@path) ? File.read(@path) : false
200
+ value.blank? ? false : value.to_sym
201
+ end
202
+ end
203
+
204
+ class Notifier < ActionMailer::Base
205
+ include Cerberus::Utils
206
+
207
+ def failure(build, options)
208
+ @subject = "Build broken by #{build.checkout.last_author} (##{build.checkout.current_revision})"
209
+ send_message(build, options)
210
+ end
211
+
212
+ def broken(build, options)
213
+ @subject = "Build still broken (##{build.checkout.current_revision})"
214
+ send_message(build, options)
215
+ end
216
+
217
+ def revival(build, options)
218
+ @subject = "Build fixed by #{build.checkout.last_author} (##{build.checkout.current_revision})"
219
+ send_message(build, options)
220
+ end
221
+
222
+ def setup(build, options)
223
+ @subject = "Cerberus set up for project (##{build.checkout.current_revision})"
224
+ send_message(build, options)
225
+ end
226
+
227
+ private
228
+ def send_message(build, options)
229
+ mail_config = options[:mail] || {}
230
+ [:authentication, :delivery_method].each do |k|
231
+ mail_config[k] = mail_config[k].to_sym if mail_config[k]
232
+ end
233
+
234
+ ActionMailer::Base.delivery_method = mail_config[:delivery_method] if mail_config[:delivery_method]
235
+ ActionMailer::Base.server_settings = mail_config
236
+
237
+ @subject = "[#{options[:application_name]}] " + @subject
238
+ @body = [ build.checkout.last_commit_message, build.output ].join("\n\n")
239
+
240
+ @recipients, @sent_on = options[:recipients], Time.now
241
+
242
+ @from = options[:sender] || "'Cerberus' <cerberus@example.com>"
243
+ raise "Please specify recipient addresses for application '#{options[:application_name]}'" unless options[:recipients]
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,30 @@
1
+ require 'yaml'
2
+
3
+ module Cerberus
4
+ module Utils
5
+ def say(info)
6
+ puts info
7
+ exit 1
8
+ end
9
+
10
+ def os
11
+ case RUBY_PLATFORM
12
+ when /mswin/
13
+ :windows
14
+ else
15
+ :unix
16
+ end
17
+ end
18
+
19
+ def dump_yml(file, what, overwrite = true)
20
+ if overwrite or not File.exists?(file)
21
+ FileUtils.mkpath(File.dirname(file))
22
+ File.open(file, 'w') {|f| YAML::dump(what, f) }
23
+ end
24
+ end
25
+
26
+ def load_yml(file_name, default = {})
27
+ File.exists?(file_name) ? YAML::load(IO.read(file_name)) : default
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ module Cerberus
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+ require 'cerberus/config'
3
+
4
+ class ConfigTest < Test::Unit::TestCase
5
+ def test_config
6
+ dump_yml(HOME + "/config.yml", {'a'=>'conf', 'd'=>'conf', 'm' => 'conf'})
7
+ dump_yml(HOME + "/config/abra.yml", {'a'=>'app', 'd'=>'app', 'g' => 'app'})
8
+ cfg = Cerberus::Config.new('abra', :a => 'cli', :b=>'cli', :e=>'cli')
9
+
10
+ assert_equal nil, cfg[:mamba]
11
+ assert_equal 'cli', cfg[:a]
12
+ assert_equal 'cli', cfg[:b]
13
+ assert_equal 'app', cfg[:d]
14
+ assert_equal 'app', cfg[:g]
15
+ assert_equal 'conf', cfg[:m]
16
+
17
+
18
+ assert_equal nil, cfg['mamba']
19
+ assert_equal 'cli', cfg['a']
20
+ assert_equal 'cli', cfg['b']
21
+ assert_equal 'app', cfg['d']
22
+ assert_equal 'app', cfg['g']
23
+ assert_equal 'conf', cfg['m']
24
+ end
25
+ end
@@ -0,0 +1,80 @@
1
+ SVN-fs-dump-format-version: 2
2
+
3
+ UUID: 3ede5f56-4031-f743-bcde-a87e4ff3590e
4
+
5
+ Revision-number: 0
6
+ Prop-content-length: 56
7
+ Content-length: 56
8
+
9
+ K 8
10
+ svn:date
11
+ V 27
12
+ 2006-06-29T09:59:06.497680Z
13
+ PROPS-END
14
+
15
+ Revision-number: 1
16
+ Prop-content-length: 113
17
+ Content-length: 113
18
+
19
+ K 7
20
+ svn:log
21
+ V 10
22
+ Added test
23
+ K 10
24
+ svn:author
25
+ V 8
26
+ Apomozov
27
+ K 8
28
+ svn:date
29
+ V 27
30
+ 2006-06-29T10:48:02.581619Z
31
+ PROPS-END
32
+
33
+ Node-path: Rakefile
34
+ Node-kind: file
35
+ Node-action: add
36
+ Prop-content-length: 10
37
+ Text-content-length: 220
38
+ Text-content-md5: b3f8886d55aca8f73578c7a896d1779a
39
+ Content-length: 230
40
+
41
+ PROPS-END
42
+ require 'rake'
43
+ require 'rake/testtask'
44
+
45
+ task :default => :test
46
+
47
+ desc "Run the unit tests in test/unit"
48
+ Rake::TestTask.new(:test) do |t|
49
+ t.libs << "test"
50
+ t.pattern = 'test/*_test.rb'
51
+ t.verbose = true
52
+ end
53
+
54
+
55
+ Node-path: test
56
+ Node-kind: dir
57
+ Node-action: add
58
+ Prop-content-length: 10
59
+ Content-length: 10
60
+
61
+ PROPS-END
62
+
63
+
64
+ Node-path: test/a_test.rb
65
+ Node-kind: file
66
+ Node-action: add
67
+ Prop-content-length: 10
68
+ Text-content-length: 101
69
+ Text-content-md5: 566f0fba7037bdfe73a4dc77368dabdc
70
+ Content-length: 111
71
+
72
+ PROPS-END
73
+ require 'test/unit'
74
+
75
+ class ATest < Test::Unit::TestCase
76
+ def test_ok
77
+ assert true
78
+ end
79
+ end
80
+
@@ -0,0 +1,95 @@
1
+ require 'test_helper'
2
+
3
+ require 'cerberus/cli'
4
+
5
+ #require 'mocks/notifier'
6
+
7
+ class FunctionalTest < Test::Unit::TestCase
8
+ def setup
9
+ FileUtils.rm_rf HOME
10
+ end
11
+
12
+ def teardown
13
+ FileUtils.rm_rf HOME
14
+ end
15
+
16
+ def test_add_by_url
17
+ assert !File.exists?(HOME + '/config/svn_repo.yml')
18
+
19
+ command = Cerberus::Add.new(" #{SVN_URL} ", :quiet => true)
20
+ command.run
21
+
22
+ assert File.exists?(HOME + '/config/svn_repo.yml')
23
+ assert_equal SVN_URL, load_yml(HOME + '/config/svn_repo.yml')['url']
24
+
25
+ assert File.exists?(HOME + '/config.yml')
26
+ end
27
+
28
+ def test_add_by_dir
29
+ sources_dir = File.dirname(__FILE__) + '/..'
30
+
31
+ command = Cerberus::Add.new(sources_dir, :quiet => true)
32
+ command.run
33
+
34
+ project_config = HOME + "/config/#{File.basename(File.expand_path(sources_dir))}.yml" #name of added application should be calculated from File System path
35
+
36
+ assert File.exists?(project_config)
37
+ assert_match %r{svn(\+ssh)?://(\w+@)?rubyforge.org/var/svn/cerberus}, load_yml(project_config)['url']
38
+
39
+ assert File.exists?(HOME + '/config.yml')
40
+ end
41
+
42
+ def test_build
43
+ add_application('myapp', SVN_URL)
44
+
45
+ build = Cerberus::Build.new('myapp')
46
+ build.run
47
+ assert_equal 1, ActionMailer::Base.deliveries.size #first email that project was setup
48
+
49
+ status_file = HOME + '/work/myapp/status.log'
50
+ assert File.exists?(status_file)
51
+ assert_equal 'succesful', IO.read(status_file)
52
+
53
+ FileUtils.rm status_file
54
+ build = Cerberus::Build.new('myapp')
55
+ build.run
56
+ assert File.exists?(status_file)
57
+
58
+ assert_equal 2, ActionMailer::Base.deliveries.size #first email that project was setup
59
+
60
+ build = Cerberus::Build.new('myapp')
61
+ build.run
62
+ assert_equal 2, ActionMailer::Base.deliveries.size #Number of mails not changed
63
+
64
+
65
+ #remove status file to run project again
66
+ FileUtils.rm status_file
67
+ add_test_case_to_project('myapp', 'assert false') { #if assertion failed
68
+ build = Cerberus::Build.new('myapp')
69
+ build.run
70
+
71
+ assert_equal 'failed', IO.read(status_file)
72
+ }
73
+ assert_equal 3, ActionMailer::Base.deliveries.size #We should receive mail if project fails
74
+
75
+
76
+ #remove status file to run project again
77
+ FileUtils.rm status_file
78
+ add_test_case_to_project('myapp', 'raise "Some exception here"') { #if we have exception
79
+ build = Cerberus::Build.new('myapp')
80
+ build.run
81
+
82
+ assert_equal 'failed', IO.read(status_file)
83
+ }
84
+ end
85
+
86
+ def test_have_no_awkward_header
87
+ add_application('myapp', SVN_URL)
88
+
89
+ build = Cerberus::Build.new('myapp')
90
+ build.run
91
+
92
+ assert build.checkout.last_commit_message !~ /-rHEAD -v/
93
+ assert_equal 0, build.checkout.last_commit_message.index('-' * 72)
94
+ end
95
+ end
@@ -0,0 +1,51 @@
1
+ require 'test_helper'
2
+
3
+ require 'yaml'
4
+
5
+ class IntegrationTest < Test::Unit::TestCase
6
+ def setup
7
+ FileUtils.rm_rf HOME
8
+ end
9
+
10
+ def teardown
11
+ FileUtils.rm_rf HOME
12
+ end
13
+
14
+ def test_add_project_as_url
15
+ output = run_cerb(" add #{SVN_URL} ")
16
+ assert_match /was successfully added/, output
17
+ assert File.exists?(HOME + '/config/svn_repo.yml')
18
+ assert_equal SVN_URL, load_yml(HOME + '/config/svn_repo.yml')['url']
19
+
20
+ #try to add second time
21
+ output = run_cerb("add #{SVN_URL}")
22
+ assert_match /already present/, output
23
+ assert File.exists?(HOME + '/config/svn_repo.yml')
24
+ assert_equal SVN_URL, load_yml(HOME + '/config/svn_repo.yml')['url']
25
+ end
26
+
27
+ def test_add_project_with_parameters
28
+ output = run_cerb(" add #{SVN_URL} APPLICATION_NAME=hello_world RECIPIENTS=aa@gmail.com")
29
+ assert_match /was successfully added/, output
30
+
31
+ assert File.exists?(HOME + '/config/hello_world.yml')
32
+ cfg = load_yml(HOME + '/config/hello_world.yml')
33
+
34
+ assert_equal SVN_URL, cfg['url']
35
+ assert_equal 'aa@gmail.com', cfg['recipients']
36
+ end
37
+
38
+ def test_run_project
39
+ add_application('svn_repo', SVN_URL, 'quiet' => true)
40
+
41
+ run_cerb("build svn_repo")
42
+ assert File.exists?(HOME + '/work/svn_repo/status.log')
43
+ assert_equal 'succesful', IO.read(HOME + '/work/svn_repo/status.log')
44
+ end
45
+
46
+ def test_run_unexist_project
47
+ output = run_cerb("build some_project")
48
+ assert_equal 'Project some_project does not present in Cerberus', output.strip
49
+ assert !test(?d, HOME + '/work/some_project')
50
+ end
51
+ end
@@ -0,0 +1,56 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'test/unit'
3
+ require 'fileutils'
4
+
5
+ require 'cerberus/utils'
6
+
7
+ class Test::Unit::TestCase
8
+ include Cerberus::Utils
9
+
10
+ TEMP_DIR = File.expand_path(File.dirname(__FILE__)) + '/__workdir'
11
+
12
+ SVN_REPO = TEMP_DIR + '/svn_repo'
13
+ SVN_URL = 'file:///' + SVN_REPO.gsub(/\\/,'/').gsub(/^\//,'').gsub(' ', '%20')
14
+
15
+ HOME = TEMP_DIR + '/home'
16
+ ENV['CERBERUS_HOME'] = HOME
17
+
18
+ def self.refresh_subversion
19
+ FileUtils.rm_rf TEMP_DIR
20
+ FileUtils.mkpath SVN_REPO
21
+ `svnadmin create "#{SVN_REPO}"`
22
+ `svnadmin load "#{SVN_REPO}" < "#{File.dirname(__FILE__)}/data/application.dump"`
23
+ end
24
+
25
+ refresh_subversion
26
+
27
+ CERBERUS_PATH = File.expand_path(File.dirname(__FILE__) + '/../')
28
+ def run_cerb(args)
29
+ `ruby -I"#{CERBERUS_PATH}/lib" "#{CERBERUS_PATH}/bin/cerberus" #{args}`
30
+ end
31
+
32
+ def add_test_case_to_project(project_name, content)
33
+ test_case_name = "#{HOME}/work/#{project_name}/sources/test/#{rand(10000)}_test.rb"
34
+ File.open(test_case_name, 'w') { |f|
35
+ f << "require 'test/unit'
36
+
37
+ class A#{rand(10000)}Test < Test::Unit::TestCase
38
+ def test_ok
39
+ #{content}
40
+ end
41
+ end"
42
+ }
43
+
44
+ yield
45
+
46
+ FileUtils.rm test_case_name
47
+ end
48
+
49
+ def add_application(app_name, url, options = {})
50
+ opt = options.dup
51
+ opt['url'] = url
52
+ opt['recipients'] = 'somebody@com.com'
53
+ opt['mail'] = {'delivery_method' => 'test'}
54
+ dump_yml(HOME + "/config/#{app_name}.yml", opt)
55
+ end
56
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: cerberus
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2006-07-16 00:00:00 +04:00
8
+ summary: Cerberus is a Continuous Integration tool that could be easily run from Cron.
9
+ require_paths:
10
+ - lib
11
+ email: anatol.pomozov@gmail.com
12
+ homepage: http://rubyforge.org/projects/cerberus
13
+ rubyforge_project: cerberus
14
+ description: Cerberus is a Continuous Integration software for Ruby projects. CI helps you keep your project in a good shape. For now Cerberus only work with projects that use Subversion but in the future it would be provided support for other VCS. Cerberus could be easily invoked from Cron (for Unix) or nnCron (for Windows) utilities.
15
+ autorequire:
16
+ default_executable: cerberus
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.8.2
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Anatol Pomozov
31
+ files:
32
+ - bin/cerberus
33
+ - doc/FAQ
34
+ - lib/cerberus
35
+ - lib/cerberus/cli.rb
36
+ - lib/cerberus/config.rb
37
+ - lib/cerberus/constants.rb
38
+ - lib/cerberus/latch.rb
39
+ - lib/cerberus/manager.rb
40
+ - lib/cerberus/utils.rb
41
+ - lib/cerberus/version.rb
42
+ - test/config_test.rb
43
+ - test/data
44
+ - test/functional_test.rb
45
+ - test/integration_test.rb
46
+ - test/test_helper.rb
47
+ - test/data/application.dump
48
+ - LICENSE
49
+ - README
50
+ - CHANGES
51
+ - Rakefile
52
+ test_files:
53
+ - test/integration_test.rb
54
+ rdoc_options:
55
+ - --main
56
+ - README
57
+ extra_rdoc_files:
58
+ - README
59
+ executables:
60
+ - cerberus
61
+ extensions: []
62
+
63
+ requirements: []
64
+
65
+ dependencies:
66
+ - !ruby/object:Gem::Dependency
67
+ name: actionmailer
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Version::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 1.2.1
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ version_requirement:
78
+ version_requirements: !ruby/object:Gem::Version::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.7.1
83
+ version: