gitpusshuten 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.bundle/config +2 -0
  2. data/.gitignore +4 -0
  3. data/Gemfile +9 -0
  4. data/Gemfile.lock +53 -0
  5. data/README.md +7 -0
  6. data/bin/gitpusshuten +4 -0
  7. data/bin/heavenly +4 -0
  8. data/bin/ten +4 -0
  9. data/gitpusshuten.gemspec +26 -0
  10. data/lib/gitpusshuten/cli.rb +78 -0
  11. data/lib/gitpusshuten/command.rb +147 -0
  12. data/lib/gitpusshuten/commands/base.rb +246 -0
  13. data/lib/gitpusshuten/commands/delete.rb +27 -0
  14. data/lib/gitpusshuten/commands/help.rb +36 -0
  15. data/lib/gitpusshuten/commands/initialize.rb +61 -0
  16. data/lib/gitpusshuten/commands/push.rb +54 -0
  17. data/lib/gitpusshuten/commands/remote.rb +29 -0
  18. data/lib/gitpusshuten/commands/user.rb +252 -0
  19. data/lib/gitpusshuten/commands/version.rb +21 -0
  20. data/lib/gitpusshuten/configuration.rb +122 -0
  21. data/lib/gitpusshuten/environment.rb +70 -0
  22. data/lib/gitpusshuten/gem.rb +33 -0
  23. data/lib/gitpusshuten/git.rb +111 -0
  24. data/lib/gitpusshuten/helpers/environment/installers.rb +59 -0
  25. data/lib/gitpusshuten/helpers/environment/packages.rb +21 -0
  26. data/lib/gitpusshuten/helpers/environment/scp.rb +57 -0
  27. data/lib/gitpusshuten/helpers/environment/ssh.rb +77 -0
  28. data/lib/gitpusshuten/helpers/environment/ssh_key.rb +79 -0
  29. data/lib/gitpusshuten/helpers/environment/user.rb +70 -0
  30. data/lib/gitpusshuten/helpers/spinner.rb +98 -0
  31. data/lib/gitpusshuten/hook.rb +26 -0
  32. data/lib/gitpusshuten/hooks.rb +147 -0
  33. data/lib/gitpusshuten/initializer.rb +95 -0
  34. data/lib/gitpusshuten/local.rb +35 -0
  35. data/lib/gitpusshuten/log.rb +83 -0
  36. data/lib/gitpusshuten/modules/active_record/hooks.rb +19 -0
  37. data/lib/gitpusshuten/modules/apache/command.rb +354 -0
  38. data/lib/gitpusshuten/modules/bundler/command.rb +43 -0
  39. data/lib/gitpusshuten/modules/bundler/hooks.rb +8 -0
  40. data/lib/gitpusshuten/modules/mysql/command.rb +192 -0
  41. data/lib/gitpusshuten/modules/nanoc/hooks.rb +9 -0
  42. data/lib/gitpusshuten/modules/nginx/command.rb +447 -0
  43. data/lib/gitpusshuten/modules/passenger/command.rb +310 -0
  44. data/lib/gitpusshuten/modules/passenger/hooks.rb +4 -0
  45. data/lib/gitpusshuten/modules/rvm/command.rb +277 -0
  46. data/lib/gitpusshuten.rb +21 -0
  47. data/lib/templates/config.rb +37 -0
  48. data/lib/templates/hooks.rb +40 -0
  49. data/spec/cli_spec.rb +83 -0
  50. data/spec/command_spec.rb +76 -0
  51. data/spec/configuration_spec.rb +45 -0
  52. data/spec/environment_spec.rb +64 -0
  53. data/spec/fixtures/combined_hooks.rb +23 -0
  54. data/spec/fixtures/config.rb +23 -0
  55. data/spec/fixtures/hooks.rb +37 -0
  56. data/spec/fixtures/passenger.json +1 -0
  57. data/spec/gem_spec.rb +28 -0
  58. data/spec/git_spec.rb +59 -0
  59. data/spec/gitpusshuten_spec.rb +9 -0
  60. data/spec/hook_spec.rb +48 -0
  61. data/spec/hooks_spec.rb +150 -0
  62. data/spec/initializer_spec.rb +26 -0
  63. data/spec/log_spec.rb +20 -0
  64. data/spec/spec_helper.rb +43 -0
  65. metadata +220 -0
@@ -0,0 +1,111 @@
1
+ module GitPusshuTen
2
+ class Git
3
+
4
+ ##
5
+ # Push-To Chain
6
+ # "type" represents either "tag", "branch" or "ref"
7
+ # "value" represents the value of the "type"
8
+ attr_accessor :type, :value
9
+
10
+ ##
11
+ # Pushing
12
+ # a boolean that determines whether git is currently busy pushing
13
+ attr_accessor :pushing
14
+ alias :pushing? :pushing
15
+
16
+ ##
17
+ # Determines whether the repository has the specified remote defined
18
+ def has_remote?(remote)
19
+ git('remote') =~ /#{remote}/
20
+ end
21
+
22
+ ##
23
+ # Adds the specified remote with the specified url to the git repository
24
+ def add_remote(remote, url)
25
+ git("remote add #{remote} #{url}")
26
+ end
27
+
28
+ ##
29
+ # Removes the specified remote from the git repository
30
+ def remove_remote(remote)
31
+ git("remote rm #{remote}")
32
+ end
33
+
34
+ ##
35
+ # Determines whether Git has been initialized
36
+ def initialized?
37
+ File.directory?(File.join(Dir.pwd, '.git'))
38
+ end
39
+
40
+ ##
41
+ # Initializes Git
42
+ def initialize!
43
+ %x[git init]
44
+ end
45
+
46
+ ##
47
+ # Adds ignore line to the gitignore.
48
+ def ignore!
49
+ if File.exist?('.gitignore')
50
+ if not File.read('.gitignore').include?('.gitpusshuten/**/*')
51
+ %x[echo '.gitpusshuten/**/*' >> .gitignore]
52
+ end
53
+ else
54
+ %x[echo '.gitpusshuten/**/*' >> .gitignore]
55
+ end
56
+ end
57
+
58
+ ##
59
+ # Push
60
+ # Begin of the push(type, value).to(remote) chain
61
+ # Pass in the type ("tag", "branch" or "ref") as the first argument
62
+ # followed by the value of the type (e.g. "1.4.2", "develop", or "9fb5c3201186")
63
+ def push(type, value)
64
+ @type = type
65
+ @value = value
66
+ self
67
+ end
68
+
69
+ ##
70
+ # To
71
+ # End of the push(type, value).to(remote) chain
72
+ # Pass in the remote (e.g. "staging") as the first argument
73
+ def to(remote)
74
+ @pushing = true
75
+ send("push_#{type}", value, remote)
76
+ @pushing = false
77
+ @type = nil
78
+ @value = nil
79
+ end
80
+
81
+ private
82
+
83
+ ##
84
+ # Wrapper for the git unix utility command
85
+ def git(command)
86
+ %x(git #{command})
87
+ end
88
+
89
+ ##
90
+ # Pushes the local git repository "tag" to the
91
+ # specified remote repository's master branch (forced)
92
+ def push_tag(tag, remote)
93
+ git("push #{remote} #{tag}~0:refs/heads/master --force")
94
+ end
95
+
96
+ ##
97
+ # Pushes the local git repository "branch" to the
98
+ # specified remote repository's master branch (forced)
99
+ def push_branch(branch, remote)
100
+ git("push #{remote} #{branch}:refs/heads/master --force")
101
+ end
102
+
103
+ ##
104
+ # Pushes the local git repository "ref" to the
105
+ # specified remote repository's master branch (forced)
106
+ def push_ref(ref, remote)
107
+ git("push #{remote} #{ref}:refs/heads/master --force")
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,59 @@
1
+ module GitPusshuTen
2
+ module Helpers
3
+ module Environment
4
+ module Installers
5
+
6
+ ##
7
+ # Installs the specified package(s)
8
+ def install!(utility)
9
+ ensure_aptitude_installed!
10
+ execute_as_root("aptitude update; aptitude install -y #{utility}")
11
+ end
12
+
13
+ ##
14
+ # Uninstalls the specified package(s)
15
+ def uninstall!(utility)
16
+ ensure_aptitude_installed!
17
+ execute_as_root("aptitude remove -y #{utility}")
18
+ end
19
+
20
+ ##
21
+ # Installs PushAnd
22
+ def install_pushand!
23
+ download_packages!(home_dir)
24
+ command = "cd #{home_dir}; cp -R gitpusshuten-packages/pushand/ .; chown -R #{c.user}:#{c.user} pushand;"
25
+ command += "'#{home_dir}/pushand/pushand_server_uninstall'; '#{home_dir}/pushand/pushand_server_install'"
26
+ execute_as_root(command)
27
+ clean_up_packages!(home_dir)
28
+ end
29
+
30
+ ##
31
+ # Installs a generated .gitconfig
32
+ def install_gitconfig!
33
+ command = "cd #{home_dir}; echo -e \"[receive]\ndenyCurrentBranch = ignore\" > .gitconfig;"
34
+ command += "chown #{c.user}:#{c.user} .gitconfig"
35
+ execute_as_root(command)
36
+ end
37
+
38
+ ##
39
+ # Determines whether the specified utility has been installed or not
40
+ def installed?(utility)
41
+ return false if execute_as_root("which #{utility}").nil?
42
+ true
43
+ end
44
+
45
+ ##
46
+ # Ensures that the aptitude package manager is installed
47
+ def ensure_aptitude_installed!
48
+ if not installed?('aptitude')
49
+ Spinner.return :message => "Ensuring package manager is installed and up to date.." do
50
+ execute_as_root!('apt-get update; apt-get install -y aptitude')
51
+ g('Done!')
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,21 @@
1
+ module GitPusshuTen
2
+ module Helpers
3
+ module Environment
4
+ module Packages
5
+
6
+ ##
7
+ # Downloads the gitpusshuten packages
8
+ def download_packages!(path, user = 'user')
9
+ send("execute_as_#{user}", "cd #{path}; git clone git://github.com/meskyanichi/gitpusshuten-packages.git")
10
+ end
11
+
12
+ ##
13
+ # Cleans up the gitpusshuten-packages git repository
14
+ def clean_up_packages!(path, user = 'user')
15
+ send("execute_as_#{user}", "cd #{path}; rm -rf gitpusshuten-packages")
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ module GitPusshuTen
2
+ module Helpers
3
+ module Environment
4
+ module SCP
5
+
6
+ ##
7
+ # Establishes a SCP session for "root"
8
+ def scp_as_user(direction, from, to)
9
+ while true
10
+ begin
11
+ Net::SCP.start(c.ip, 'root', {
12
+ :password => @user_password,
13
+ :passphrase => c.passphrase,
14
+ :port => c.port
15
+ }) do |scp|
16
+ return scp.send("#{direction}!", from, to)
17
+ end
18
+ rescue Net::SCP::AuthenticationFailed
19
+ if @user_attempted
20
+ GitPusshuTen::Log.error "Password incorrect. Please retry."
21
+ else
22
+ GitPusshuTen::Log.message "Please provide the password for #{c.user.to_s.color(:yellow)}."
23
+ @user_attempted = true
24
+ end
25
+ @user_password = ask('') { |q| q.echo = false }
26
+ end
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Establishes a SCP session for "root"
32
+ def scp_as_root(direction, from, to)
33
+ while true
34
+ begin
35
+ Net::SCP.start(c.ip, 'root', {
36
+ :password => @root_password,
37
+ :passphrase => c.passphrase,
38
+ :port => c.port
39
+ }) do |scp|
40
+ return scp.send("#{direction}!", from, to)
41
+ end
42
+ rescue Net::SSH::AuthenticationFailed
43
+ if @root_attempted
44
+ GitPusshuTen::Log.error "Password incorrect. Please retry."
45
+ else
46
+ GitPusshuTen::Log.message "Please provide the password for #{"root".color(:yellow)}."
47
+ @root_attempted = true
48
+ end
49
+ @root_password = ask('') { |q| q.echo = false }
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,77 @@
1
+ module GitPusshuTen
2
+ module Helpers
3
+ module Environment
4
+ module SSH
5
+
6
+ ##
7
+ # Tests if the specified directory exists
8
+ def directory?(path)
9
+ return true if execute_as_root("if [[ -d '#{path}' ]]; then exit; else echo 1; fi").nil?
10
+ false
11
+ end
12
+
13
+ ##
14
+ # Tests if the specified file exists
15
+ def file?(path)
16
+ return true if execute_as_root("if [[ -f '#{path}' ]]; then exit; else echo 1; fi").nil?
17
+ false
18
+ end
19
+
20
+ ##
21
+ # Performs a single command on the remote environment as a user
22
+ def execute_as_user(command)
23
+ @user_password ||= c.password
24
+
25
+ while true
26
+ begin
27
+ Net::SSH.start(c.ip, c.user, {
28
+ :password => @user_password,
29
+ :passphrase => c.passphrase,
30
+ :port => c.port
31
+ }) do |ssh|
32
+ response = ssh.exec!(command)
33
+ GitPusshuTen::Log.silent response
34
+ return response
35
+ end
36
+ rescue Net::SSH::AuthenticationFailed
37
+ if @user_attempted
38
+ GitPusshuTen::Log.error "Password incorrect. Please retry."
39
+ else
40
+ GitPusshuTen::Log.message "Please provide the password for #{c.user.to_s.color(:yellow)} (#{c.ip.color(:yellow)})."
41
+ @user_attempted = true
42
+ end
43
+ @user_password = ask('') { |q| q.echo = false }
44
+ end
45
+ end
46
+ end
47
+
48
+ ##
49
+ # Performs a command as root
50
+ def execute_as_root(command)
51
+ while true
52
+ begin
53
+ Net::SSH.start(c.ip, 'root', {
54
+ :password => @root_password,
55
+ :passphrase => c.passphrase,
56
+ :port => c.port
57
+ }) do |ssh|
58
+ response = ssh.exec!(command)
59
+ GitPusshuTen::Log.silent response
60
+ return response
61
+ end
62
+ rescue Net::SSH::AuthenticationFailed
63
+ if @root_attempted
64
+ GitPusshuTen::Log.error "Password incorrect. Please retry."
65
+ else
66
+ GitPusshuTen::Log.message "Please provide the password for #{'root'.color(:yellow)} (#{c.ip.color(:yellow)})."
67
+ @root_attempted = true
68
+ end
69
+ @root_password = ask('') { |q| q.echo = false }
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,79 @@
1
+ module GitPusshuTen
2
+ module Helpers
3
+ module Environment
4
+ module SSHKeys
5
+
6
+ ##
7
+ # USERS
8
+ ##
9
+ # Returns true or false, based on whether the (local) ssh
10
+ # key has been installed on the remote server or not
11
+ def ssh_key_installed?
12
+ return false unless has_ssh_key?
13
+ return true if authorized_ssh_keys.include?(ssh_key)
14
+ false
15
+ end
16
+
17
+ ##
18
+ # Returns true or false, based on whether the (local) ssh key exists
19
+ def has_ssh_key?
20
+ File.exist?(ssh_key_path)
21
+ end
22
+
23
+ ##
24
+ # Reads out the ssh key file contents
25
+ def ssh_key
26
+ File.read(ssh_key_path)
27
+ end
28
+
29
+ ##
30
+ # Connects to the server to read out the ~/.ssh/authorized_keys
31
+ def authorized_ssh_keys
32
+ execute_as_root("cat '#{File.join(home_dir, '.ssh', 'authorized_keys')}'")
33
+ end
34
+
35
+ ##
36
+ # Returns the default (local) SSH key path
37
+ def ssh_key_path
38
+ File.join(ENV['HOME'], '.ssh', 'id_rsa.pub')
39
+ end
40
+
41
+ ##
42
+ # Installs the ssh key on the remote server
43
+ def install_ssh_key!
44
+ command = "mkdir -p '#{File.join(home_dir, '.ssh')}';"
45
+ command += "echo '#{ssh_key}' >> '#{File.join(home_dir, '.ssh', 'authorized_keys')}';"
46
+ command += "chown -R #{c.user}:#{c.user} '#{File.join(home_dir, '.ssh')}';"
47
+ command += "chmod 700 '#{File.join(home_dir, '.ssh')}'; chmod 600 '#{File.join(home_dir, '.ssh', 'authorized_keys')}'"
48
+ execute_as_root(command)
49
+ end
50
+
51
+ ##
52
+ # ROOT
53
+ ##
54
+ # Checks to see if the user's key is already installed in the authorized keys
55
+ # of the root user on the remote server
56
+ def root_ssh_key_installed?
57
+ return false unless has_ssh_key?
58
+ return true if authorized_root_ssh_keys.include?(ssh_key)
59
+ false
60
+ end
61
+
62
+ ##
63
+ # Returns a list of authorized keys for the root user
64
+ def authorized_root_ssh_keys
65
+ execute_as_root("cat $HOME/.ssh/authorized_keys")
66
+ end
67
+
68
+ ##
69
+ # Installs the user's SSH key in root's authorized keys file
70
+ def install_root_ssh_key!
71
+ command = "mkdir -p $HOME/.ssh; echo '#{ssh_key}' >> $HOME/.ssh/authorized_keys;"
72
+ command += "chmod 700 $HOME/.ssh; chmod 600 $HOME/.ssh/authorized_keys"
73
+ execute_as_root(command)
74
+ end
75
+
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,70 @@
1
+ module GitPusshuTen
2
+ module Helpers
3
+ module Environment
4
+ module User
5
+
6
+ ##
7
+ # Removes a user from the remote server but does not remove
8
+ # the user's home directory since it might contain applications
9
+ def remove_user!
10
+ response = execute_as_root("userdel -f '#{c.user}'")
11
+ return true if response.nil? or response =~ /userdel: user .+ is currently logged in/
12
+ false
13
+ end
14
+
15
+ ##
16
+ # Adds the user to the sudoers file
17
+ def add_user_to_sudoers!
18
+ execute_as_root("echo '#{c.user} ALL=(ALL) ALL' >> /etc/sudoers")
19
+ end
20
+
21
+ ##
22
+ # Checks the remote server to see if the provided user exists
23
+ def user_exists?
24
+ return false if execute_as_root("grep '#{c.user}' /etc/passwd").nil?
25
+ true
26
+ end
27
+
28
+ ##
29
+ # Checks to see if the user is already in the sudoers file or not
30
+ def user_in_sudoers?
31
+ return true if execute_as_root("cat /etc/sudoers").include?("#{c.user} ALL=(ALL) ALL")
32
+ false
33
+ end
34
+
35
+ ##
36
+ # Adds a user to the remote server and sets the home directory
37
+ # to the path specified in the config.rb. This is the location
38
+ # to where applications will be deployed
39
+ #
40
+ # If a password is not specified in the configuration, it will prompt
41
+ # the user to fill one in here in the CLI.
42
+ def add_user!
43
+ if c.password.nil?
44
+ GitPusshuTen::Log.message "What password would you like to give #{c.user.to_s.color(:yellow)}?"
45
+ while @new_password.nil?
46
+ new_password = ask('Fill in a password.') { |q| q.echo = false }
47
+ new_password_verification = ask('Verify password.') { |q| q.echo = false }
48
+ if not new_password.empty? and (new_password == new_password_verification)
49
+ @new_password = new_password
50
+ else
51
+ if new_password.empty?
52
+ GitPusshuTen::Log.error "Please provide a password."
53
+ else
54
+ GitPusshuTen::Log.error "Verification failed, please try again."
55
+ end
56
+ end
57
+ end
58
+ else
59
+ @new_password = c.password
60
+ end
61
+
62
+ response = execute_as_root("useradd -m --home='#{home_dir}' -s '/bin/bash' --password='" + %x[openssl passwd #{@new_password}].chomp + "' '#{c.user}'")
63
+ return true if response.nil? or response =~ /useradd\: warning\: the home directory already exists\./
64
+ false
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,98 @@
1
+ STDOUT.sync = true
2
+
3
+ class Spinner
4
+
5
+ ##
6
+ # Loadify Method
7
+ # * block of code you want to provide a loader for
8
+ #
9
+ # Options
10
+ # * :message => 'Message to be displayed while processing'
11
+ # * :complete => 'Message to be displayed after processing, regardless of the returned value'
12
+ # * :return => 'When set to true, it will display the returned value of the executed code'
13
+ def initialize(options = {}, &code)
14
+
15
+ ##
16
+ # Character to loop through (loader)
17
+ characters = %w[| / - \\ | / - \\]
18
+
19
+ ##
20
+ # Create a new thread to run the provided block of code in
21
+ thread = Thread.new do
22
+ code.call
23
+ end
24
+
25
+ ##
26
+ # Enter a while loop and stay in it until the thread
27
+ # finished processing the provided code. This will display
28
+ # and animate the loader meanwhile.
29
+ while thread.alive?
30
+ next_character = characters.shift
31
+ message = "#{next_character} #{options[:message] || ''}"
32
+ print message
33
+ characters << next_character
34
+ sleep 0.065
35
+ print "\b" * message.length
36
+ end
37
+
38
+ ##
39
+ # Extract the value from the dead thread
40
+ returned_value = thread.value
41
+
42
+ ##
43
+ # Print Final Message
44
+ print "#{options[:message]} "
45
+
46
+ ##
47
+ # Print On Complete Message if options is set to true
48
+ unless options[:complete].nil?
49
+ print options[:complete]
50
+ print " "
51
+ end
52
+
53
+ ##
54
+ # Prints the returned value from the code block
55
+ # that was executed if set to true
56
+ if options[:return]
57
+ if options[:put]
58
+ puts "\n" + returned_value
59
+ else
60
+ print returned_value
61
+ end
62
+ end
63
+
64
+ ##
65
+ # Add a new line
66
+ print "\n"
67
+
68
+ ##
69
+ # Return the value from the dead thread
70
+ returned_value
71
+
72
+ end
73
+
74
+ def self.return(options = {}, &code)
75
+ Spinner.new({:return => true}.merge(options), &code)
76
+ end
77
+
78
+ def self.installing(options = {}, &code)
79
+ Spinner.new({:message => "Installing..", :complete => 'Done!'.color(:green)}.merge(options), &code)
80
+ end
81
+
82
+ def self.installing_a_while(options = {}, &code)
83
+ Spinner.new({:message => "Installing, this may take a while..", :complete => 'Done!'.color(:green)}.merge(options), &code)
84
+ end
85
+
86
+ def self.configuring(options = {}, &code)
87
+ Spinner.new({:message => "Configuring..", :complete => 'Done!'.color(:green)}.merge(options), &code)
88
+ end
89
+
90
+ def self.updating(options = {}, &code)
91
+ Spinner.new({:message => "Updating..", :complete => 'Done!'.color(:green)}.merge(options), &code)
92
+ end
93
+
94
+ def self.loading(options = {}, &code)
95
+ Spinner.new({:message => "Loading..", :complete => 'Done!'.color(:green)}.merge(options), &code)
96
+ end
97
+
98
+ end
@@ -0,0 +1,26 @@
1
+ module GitPusshuTen
2
+ class Hook
3
+
4
+ ##
5
+ # Stores the name of the performed hook
6
+ attr_accessor :name
7
+
8
+ ##
9
+ # Stores the type of hook (pre or post)
10
+ attr_accessor :type
11
+
12
+ ##
13
+ # Stores the (parsed) commands that need to be run
14
+ attr_accessor :commands
15
+
16
+ ##
17
+ # Initializes a new hook
18
+ # Takes a hash of parameters
19
+ def initialize(options)
20
+ @name = options[:name]
21
+ @type = options[:type]
22
+ @commands = options[:commands]
23
+ end
24
+
25
+ end
26
+ end