gitpusshuten 0.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.
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