hercules 0.1.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.
Files changed (58) hide show
  1. data/.gitignore +10 -0
  2. data/Gemfile +11 -0
  3. data/Gemfile.lock +36 -0
  4. data/LICENSE +20 -0
  5. data/README.md +71 -0
  6. data/Rakefile +76 -0
  7. data/VERSION +1 -0
  8. data/bin/hercules +6 -0
  9. data/hdi/README.md +4 -0
  10. data/hdi/config.rb +7 -0
  11. data/hdi/site/index.html +267 -0
  12. data/hdi/site/stylesheets/style.css +1 -0
  13. data/hdi/src/configuration.rb +5 -0
  14. data/hdi/src/layouts/application.haml +12 -0
  15. data/hdi/src/pages/_hdi.haml +71 -0
  16. data/hdi/src/pages/_header.haml +8 -0
  17. data/hdi/src/pages/_jquery.haml +155 -0
  18. data/hdi/src/pages/index.haml +10 -0
  19. data/hdi/src/stylesheets/style.sass +173 -0
  20. data/hercules.gemspec +120 -0
  21. data/lib/command_runner.rb +73 -0
  22. data/lib/config.rb +82 -0
  23. data/lib/deployer.rb +95 -0
  24. data/lib/git_handler.rb +78 -0
  25. data/lib/hercules.rb +167 -0
  26. data/lib/http_handler.rb +41 -0
  27. data/lib/request_handler.rb +142 -0
  28. data/tests/command_runner_test.rb +35 -0
  29. data/tests/config_test.rb +39 -0
  30. data/tests/fixtures/Gemfile +1 -0
  31. data/tests/fixtures/Gemfile.lock +8 -0
  32. data/tests/fixtures/Gemfile.with_git_gem +2 -0
  33. data/tests/fixtures/Gemfile.with_git_gem.lock +10 -0
  34. data/tests/fixtures/bogus_config.yml +9 -0
  35. data/tests/fixtures/bogus_deployer.rb +2 -0
  36. data/tests/fixtures/config.yml +12 -0
  37. data/tests/fixtures/config_empty.yml +1 -0
  38. data/tests/fixtures/config_empty_branches.yml +8 -0
  39. data/tests/fixtures/config_empty_projects.yml +2 -0
  40. data/tests/fixtures/config_global.yml +14 -0
  41. data/tests/fixtures/config_partial_1.yml +7 -0
  42. data/tests/fixtures/config_partial_2.yml +7 -0
  43. data/tests/fixtures/config_partial_3.yml +7 -0
  44. data/tests/fixtures/deployer_branch.rb +11 -0
  45. data/tests/fixtures/deployer_exception.rb +11 -0
  46. data/tests/fixtures/deployer_false.rb +11 -0
  47. data/tests/fixtures/deployer_path.rb +11 -0
  48. data/tests/fixtures/deployer_true.rb +11 -0
  49. data/tests/fixtures/deployer_undefined_variable.rb +11 -0
  50. data/tests/fixtures/startup_checkout_config.yml +12 -0
  51. data/tests/fixtures/startup_checkout_error_config.yml +12 -0
  52. data/tests/git_handler_test.rb +95 -0
  53. data/tests/git_setup.rb +70 -0
  54. data/tests/hercules_test.rb +128 -0
  55. data/tests/http_handler_test.rb +88 -0
  56. data/tests/request_handler_test.rb +242 -0
  57. data/tests/startup.rb +36 -0
  58. metadata +251 -0
@@ -0,0 +1,10 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+
6
+ PLATFORMS
7
+ ruby
8
+
9
+ DEPENDENCIES
10
+ git
@@ -0,0 +1,9 @@
1
+ $%#$%
2
+ token-> abc
3
+ repository: file:///tmp/hercules_test_repository
4
+ target_directory: /tmp/hercules_test_checkout
5
+ master:
6
+ checkouts_to_keep: 1
7
+ test:
8
+ checkouts_to_keep: 3
9
+
@@ -0,0 +1,2 @@
1
+ class Deployer
2
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ test_project:
3
+ token: abc
4
+ repository: file:///tmp/hercules_test_repository
5
+ target_directory: /tmp/hercules_test_checkout
6
+ master:
7
+ checkout_on_startup: false
8
+ checkouts_to_keep: 1
9
+ test:
10
+ checkout_on_startup: false
11
+ checkouts_to_keep: 3
12
+
@@ -0,0 +1 @@
1
+ ---
@@ -0,0 +1,8 @@
1
+ ---
2
+ test_project:
3
+ token: abc
4
+ repository: file:///tmp/hercules_test_repository
5
+ target_directory: /tmp/hercules_test_checkout
6
+ master:
7
+ test:
8
+
@@ -0,0 +1,2 @@
1
+ ---
2
+ test_project:
@@ -0,0 +1,14 @@
1
+ ---
2
+ host: "127.0.0.1"
3
+ port: 8081
4
+ test_project:
5
+ token: abc
6
+ repository: file:///tmp/hercules_test_repository
7
+ target_directory: /tmp/hercules_test_checkout
8
+ master:
9
+ checkout_on_startup: false
10
+ checkouts_to_keep: 1
11
+ test:
12
+ checkout_on_startup: false
13
+ checkouts_to_keep: 3
14
+
@@ -0,0 +1,7 @@
1
+ ---
2
+ test_project:
3
+ repository: file:///tmp/hercules_test_repository
4
+ target_directory: /tmp/hercules_test_checkout
5
+ master:
6
+ test:
7
+
@@ -0,0 +1,7 @@
1
+ ---
2
+ test_project:
3
+ token: abc
4
+ target_directory: /tmp/hercules_test_checkout
5
+ master:
6
+ test:
7
+
@@ -0,0 +1,7 @@
1
+ ---
2
+ test_project:
3
+ token: abc
4
+ repository: file:///tmp/hercules_test_repository
5
+ master:
6
+ test:
7
+
@@ -0,0 +1,11 @@
1
+ module Hercules
2
+ class Triggers
3
+ def self.before_deploy(options)
4
+ true
5
+ end
6
+
7
+ def self.after_deploy(options)
8
+ FileUtils.touch "./branch_name_#{options[:branch]}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Hercules
2
+ class Triggers
3
+ def self.before_deploy(options)
4
+ raise "test exception"
5
+ end
6
+
7
+ def self.after_deploy(options)
8
+ FileUtils.touch "./after_deploy"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Hercules
2
+ class Triggers
3
+ def self.before_deploy(options)
4
+ false
5
+ end
6
+
7
+ def self.after_deploy(options)
8
+ FileUtils.touch "#{options[:path]}/after_deploy"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Hercules
2
+ class Triggers
3
+ def self.before_deploy(options)
4
+ true
5
+ end
6
+
7
+ def self.after_deploy(options)
8
+ FileUtils.touch "./after_deploy"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Hercules
2
+ class Triggers
3
+ def self.before_deploy(options)
4
+ true
5
+ end
6
+
7
+ def self.after_deploy(options)
8
+ FileUtils.touch "#{options[:path]}/after_deploy"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Hercules
2
+ class Triggers
3
+ def self.before_deploy(options)
4
+ puts "test with #{undefined_variable}"
5
+ end
6
+
7
+ def self.after_deploy(options)
8
+ FileUtils.touch "./after_deploy"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ ---
2
+ test_project:
3
+ token: abc
4
+ repository: file:///tmp/hercules_test_repository
5
+ target_directory: /tmp/hercules_test_checkout
6
+ master:
7
+ checkout_on_startup: true
8
+ checkouts_to_keep: 1
9
+ test:
10
+ checkout_on_startup: false
11
+ checkouts_to_keep: 3
12
+
@@ -0,0 +1,12 @@
1
+ ---
2
+ test_project:
3
+ token: abc
4
+ repository: file:///tmp/hercules_test_repository
5
+ target_directory: /tmp/hercules_test_checkout
6
+ master:
7
+ checkout_on_startup: true
8
+ checkouts_to_keep: 1
9
+ test:
10
+ checkout_on_startup: true
11
+ checkouts_to_keep: 3
12
+
@@ -0,0 +1,95 @@
1
+ # coding: utf-8
2
+ require 'tests/git_setup'
3
+ require 'lib/git_handler'
4
+ require 'test/unit'
5
+
6
+ class GitHandlerTest < Test::Unit::TestCase
7
+ include GitSetup
8
+ def setup
9
+ git_setup
10
+ end
11
+
12
+ def test_get_last_commit
13
+ g = Hercules::GitHandler.new(@config['test_project'])
14
+ g.export_branch('master')
15
+ assert_equal @head_sha, g.last_commit
16
+ end
17
+
18
+ def test_export_branch
19
+ g = Hercules::GitHandler.new(@config['test_project'])
20
+ g.export_branch('master')
21
+ assert_is_checkout @config['test_project']['target_directory'] + '/checkouts/master/' + @head_sha
22
+ end
23
+
24
+ def test_export_non_existent_branch
25
+ g = Hercules::GitHandler.new(@config['test_project'])
26
+ g.export_branch('branch_that_will_not_exist') rescue nil
27
+ assert !File.exists?(@config['test_project']['target_directory'] + '/checkouts/branch_that_will_not_exist/' + @head_sha)
28
+ assert_equal 2, Dir.glob(@config['test_project']['target_directory'] + '/checkouts/branch_that_will_not_exist/.*').size
29
+ assert_equal 0, Dir.glob(@config['test_project']['target_directory'] + '/checkouts/branch_that_will_not_exist/*').size
30
+ end
31
+
32
+ def test_export_non_existent_or_invalid_repository
33
+ @config['test_project']['repository'] = 'repository_that_does_not_exist_or_is_invalid'
34
+ g = Hercules::GitHandler.new(@config['test_project'])
35
+ begin
36
+ g.export_branch('branch_that_will_not_exist')
37
+ assert false
38
+ rescue Exception => e
39
+ assert_match /Error while cloning/, e.message
40
+ end
41
+
42
+ end
43
+
44
+ def test_create_branches_dir
45
+ g = Hercules::GitHandler.new(@config['test_project'])
46
+ g.create_branches_dir
47
+ assert (File.exists?(@config['test_project']['target_directory'] + '/branches'))
48
+ end
49
+
50
+ def test_branches_dir
51
+ g = Hercules::GitHandler.new(@config['test_project'])
52
+ assert_equal @config['test_project']['target_directory'] + '/branches', g.branches_path
53
+ end
54
+
55
+ def test_deploy_branch
56
+ g = Hercules::GitHandler.new(@config['test_project'])
57
+ g.deploy_branch('master')
58
+ assert_is_checkout @config['test_project']['target_directory'] + '/branches/master'
59
+ end
60
+
61
+ def test_should_deploy_test_branch
62
+ @g.branch('test').checkout
63
+ g = Hercules::GitHandler.new(@config['test_project'])
64
+ g.deploy_branch('test')
65
+ assert_is_checkout @config['test_project']['target_directory'] + '/branches/test'
66
+ end
67
+
68
+ def test_should_maintain_at_most_three_test_checkouts
69
+ @g.branch('test').checkout
70
+ g = Hercules::GitHandler.new(@config['test_project'])
71
+ FileUtils.mkdir_p(@config['test_project']['target_directory'] + '/logs')
72
+ 4.times do |t|
73
+ sha1 = generate_commit "new_commit#{t}"
74
+ g.deploy_branch('test')
75
+ # Here we must simulate the log creating which will be done by the deployer
76
+ FileUtils.touch("#{@config['test_project']['target_directory']}/logs/#{sha1}.log")
77
+ assert File.exists?(@config['test_project']['target_directory'] + "/logs")
78
+ assert File.exists?(@config['test_project']['target_directory'] + "/branches/test/new_commit#{t}")
79
+ # The checkouts_to_keep in config.yml is set to 3 (so 5 is the maximum: 3 + '.' + '..')
80
+ assert_equal (3+t > 5 ? 5 : 3+t), Dir.entries(@config['test_project']['target_directory'] + '/checkouts/test').size
81
+ assert_equal (3+t > 5 ? 5 : 3+t), Dir.entries(@config['test_project']['target_directory'] + '/logs').size
82
+ end
83
+ end
84
+
85
+ def test_should_maintain_only_one_master_checkout
86
+ g = Hercules::GitHandler.new(@config['test_project'])
87
+ g.deploy_branch('master')
88
+ generate_commit 'new_commit'
89
+ g.deploy_branch('master')
90
+ assert File.exists?(@config['test_project']['target_directory'] + '/branches/master/new_commit')
91
+ assert_equal 3, Dir.entries(@config['test_project']['target_directory'] + '/checkouts/master').size
92
+ end
93
+
94
+ end
95
+
@@ -0,0 +1,70 @@
1
+ # coding: utf-8
2
+ require 'rubygems'
3
+ require 'git'
4
+ require 'lib/git_handler'
5
+ require 'yaml'
6
+
7
+ module GitSetup
8
+ def git_setup
9
+ @config = YAML.load_file(File.dirname(__FILE__) + '/fixtures/config.yml')
10
+ dir = @config['test_project']['repository'].gsub(/file:\/\//, '')
11
+ FileUtils.rm_rf(dir)
12
+ FileUtils.rm_rf(@config['test_project']['target_directory'])
13
+ FileUtils.mkdir_p(dir)
14
+ FileUtils.cp(File.dirname(__FILE__) + '/fixtures/config.yml', "#{dir}/config.yml")
15
+ FileUtils.cp(File.dirname(__FILE__) + '/fixtures/Gemfile', "#{dir}/Gemfile")
16
+ FileUtils.cp(File.dirname(__FILE__) + '/fixtures/Gemfile.lock', "#{dir}/Gemfile.lock")
17
+ @g = Git.init(dir)
18
+ @g.chdir do
19
+ @g.config('user.name', 'Test User')
20
+ @g.config('user.email', 'email@email.com')
21
+ @g.add("./config.yml")
22
+ @g.add("./Gemfile")
23
+ @g.add("./Gemfile.lock")
24
+ @g.commit_all('message')
25
+ @head_sha = @g.gcommit('HEAD').sha
26
+ end
27
+ end
28
+
29
+ def generate_bogus_gemfile
30
+ change_repository do
31
+ File.open('./Gemfile', 'a'){|f| f.write('gem syntax error "Gem_That_Does_Not_Exist", "0.0.0", - % $ ') }
32
+ end
33
+ end
34
+
35
+ def generate_gemfile_with_gem
36
+ path = File.expand_path( File.dirname(__FILE__) )
37
+ change_repository do
38
+ FileUtils.cp("#{path}/fixtures/Gemfile.with_git_gem", "./Gemfile")
39
+ FileUtils.cp("#{path}/fixtures/Gemfile.with_git_gem.lock", "./Gemfile.lock")
40
+ end
41
+ end
42
+
43
+ def generate_deployer(deployer_name)
44
+ path = File.expand_path( File.dirname(__FILE__) )
45
+ change_repository do
46
+ FileUtils.mkdir_p("./lib")
47
+ FileUtils.cp("#{path}/fixtures/#{deployer_name}.rb", "./lib/hercules_triggers.rb")
48
+ end
49
+ end
50
+
51
+ def generate_commit file_name
52
+ change_repository{ FileUtils.touch file_name }
53
+ end
54
+
55
+ def change_repository
56
+ head_sha = @head_sha
57
+ @g.chdir do
58
+ yield
59
+ @g.add("./*")
60
+ @g.commit_all("added files")
61
+ head_sha = @g.gcommit('HEAD').sha
62
+ end
63
+ return head_sha
64
+ end
65
+
66
+ def assert_is_checkout(dir)
67
+ assert_equal File.open(File.dirname(__FILE__) + '/fixtures/config.yml').read, File.open(dir + '/config.yml').read
68
+ assert !File.exists?(dir + '/.git')
69
+ end
70
+ end
@@ -0,0 +1,128 @@
1
+ # coding: utf-8
2
+ require 'tests/startup'
3
+ require 'tests/git_setup'
4
+ require 'test/unit'
5
+
6
+ class HerculesTest < Test::Unit::TestCase
7
+ include Startup
8
+ include GitSetup
9
+
10
+ def setup
11
+ prepare_startup
12
+ end
13
+
14
+ def test_startup_validations
15
+ verbose(false) do
16
+ # Here we test for config file require
17
+ sh "src/hercules.rb -l /dev/null > /dev/null 2>&1" rescue nil
18
+ sleep 1
19
+ assert !File.exist?(@pidfile)
20
+
21
+ # Test with an invalid yaml
22
+ sh "src/hercules.rb -c src/hercules.rb -l /dev/null > /dev/null 2>&1" rescue nil
23
+ sleep 1
24
+ assert !File.exist?(@pidfile)
25
+ end
26
+ end
27
+
28
+ def test_logfile_and_piddir
29
+ start_hercules do |pid,log|
30
+ assert File.exist?(@logfile)
31
+ assert_match /Start/, log.read()
32
+ assert File.exist?(@pidfile)
33
+ assert_match /\d+/, pid
34
+ end
35
+ end
36
+
37
+ def test_send_term
38
+ start_hercules do |pid,log|
39
+ Process.kill("TERM", pid.to_i)
40
+ sleep 1
41
+ assert !File.exist?(@pidfile)
42
+ assert_match /Terminating hercules/, log.read
43
+ end
44
+ end
45
+
46
+ def test_send_hup
47
+ start_hercules do |pid,log|
48
+ Process.kill("HUP", pid.to_i)
49
+ sleep 1
50
+ assert File.exist?(@pidfile)
51
+ log_content = log.read
52
+ assert_match /Reloading config/, log_content
53
+ assert_no_match /Error reading/, log_content
54
+ end
55
+ end
56
+
57
+ def test_send_hup_with_bad_config_file
58
+ start_hercules do |pid,log|
59
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/config.old.yml"
60
+ FileUtils.mv "tests/fixtures/bogus_config.yml", "tests/fixtures/config.yml"
61
+ Process.kill("HUP", pid.to_i)
62
+ sleep 1
63
+ assert File.exist?(@pidfile)
64
+ log_content = log.read
65
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/bogus_config.yml"
66
+ FileUtils.mv "tests/fixtures/config.old.yml", "tests/fixtures/config.yml"
67
+ assert_match /Reloading config/, log_content
68
+ assert_match /Error reading/, log_content
69
+ end
70
+ end
71
+
72
+ def test_checkouts_on_startup_with_errors
73
+ git_setup
74
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/config.old.yml"
75
+ FileUtils.mv "tests/fixtures/startup_checkout_error_config.yml", "tests/fixtures/config.yml"
76
+ begin
77
+ log_content = ""
78
+ start_hercules do |pid,log|
79
+ sleep 5
80
+ log_content = log.read
81
+ assert_match /Branch master deployed/, log_content
82
+ assert File.exist?(@pidfile)
83
+ end
84
+ ensure
85
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/startup_checkout_error_config.yml"
86
+ FileUtils.mv "tests/fixtures/config.old.yml", "tests/fixtures/config.yml"
87
+ end
88
+ end
89
+
90
+ def test_checkouts_on_startup
91
+ git_setup
92
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/config.old.yml"
93
+ FileUtils.mv "tests/fixtures/startup_checkout_config.yml", "tests/fixtures/config.yml"
94
+ start_hercules do |pid,log|
95
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/startup_checkout_config.yml"
96
+ FileUtils.mv "tests/fixtures/config.old.yml", "tests/fixtures/config.yml"
97
+ sleep 5
98
+ log_content = log.read
99
+ assert_match /Branch master deployed/, log_content
100
+ assert_is_checkout @config['test_project']['target_directory'] + '/branches/master'
101
+ end
102
+ end
103
+
104
+ def test_no_checkouts_on_startups_with_default_config
105
+ git_setup
106
+ start_hercules do |pid,log|
107
+ sleep 5
108
+ log_content = log.read
109
+ assert_no_match /Branch master deployed/, log_content
110
+ assert !File.exist?(@config['test_project']['target_directory'] + '/branches/master')
111
+ end
112
+ end
113
+
114
+ def test_checkouts_on_startup_with_hidden_tmp
115
+ git_setup
116
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/config.old.yml"
117
+ FileUtils.mv "tests/fixtures/startup_checkout_config.yml", "tests/fixtures/config.yml"
118
+ FileUtils.mkdir_p @config['test_project']['target_directory'] + '/checkouts/master/.tmp'
119
+ start_hercules do |pid,log|
120
+ FileUtils.mv "tests/fixtures/config.yml", "tests/fixtures/startup_checkout_config.yml"
121
+ FileUtils.mv "tests/fixtures/config.old.yml", "tests/fixtures/config.yml"
122
+ sleep 20
123
+ log_content = log.read
124
+ assert_match /Branch master deployed/, log_content
125
+ assert_is_checkout @config['test_project']['target_directory'] + '/branches/master'
126
+ end
127
+ end
128
+ end