colorful-mina 0.3.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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +21 -0
  5. data/CONTRIBUTING.md +124 -0
  6. data/Gemfile +10 -0
  7. data/HISTORY.md +348 -0
  8. data/LICENSE +23 -0
  9. data/Makefile +29 -0
  10. data/Notes.md +70 -0
  11. data/README.md +1015 -0
  12. data/Rakefile +20 -0
  13. data/bin/mina +65 -0
  14. data/data/deploy.rb +80 -0
  15. data/data/deploy.sh.erb +106 -0
  16. data/lib/mina.rb +23 -0
  17. data/lib/mina/bundler.rb +49 -0
  18. data/lib/mina/chruby.rb +49 -0
  19. data/lib/mina/default.rb +145 -0
  20. data/lib/mina/deploy.rb +138 -0
  21. data/lib/mina/deploy_helpers.rb +34 -0
  22. data/lib/mina/exec_helpers.rb +111 -0
  23. data/lib/mina/foreman.rb +82 -0
  24. data/lib/mina/git.rb +62 -0
  25. data/lib/mina/helpers.rb +386 -0
  26. data/lib/mina/output_helpers.rb +95 -0
  27. data/lib/mina/rails.rb +206 -0
  28. data/lib/mina/rake.rb +9 -0
  29. data/lib/mina/rbenv.rb +47 -0
  30. data/lib/mina/rvm.rb +88 -0
  31. data/lib/mina/settings.rb +32 -0
  32. data/lib/mina/ssh_helpers.rb +123 -0
  33. data/lib/mina/tools.rb +20 -0
  34. data/lib/mina/version.rb +5 -0
  35. data/lib/mina/whenever.rb +27 -0
  36. data/manual/index.md +15 -0
  37. data/manual/modules.md +2 -0
  38. data/mina.gemspec +17 -0
  39. data/spec/command_helper.rb +52 -0
  40. data/spec/commands/cleanup_spec.rb +16 -0
  41. data/spec/commands/command_spec.rb +71 -0
  42. data/spec/commands/custom_config_spec.rb +20 -0
  43. data/spec/commands/deploy_spec.rb +36 -0
  44. data/spec/commands/outside_project_spec.rb +35 -0
  45. data/spec/commands/real_deploy_spec.rb +53 -0
  46. data/spec/commands/ssh_spec.rb +14 -0
  47. data/spec/commands/verbose_spec.rb +21 -0
  48. data/spec/dsl/invoke_spec.rb +48 -0
  49. data/spec/dsl/queue_spec.rb +49 -0
  50. data/spec/dsl/settings_in_rake_spec.rb +39 -0
  51. data/spec/dsl/settings_spec.rb +61 -0
  52. data/spec/dsl/to_spec.rb +20 -0
  53. data/spec/fixtures/custom_file_env/custom_deploy.rb +15 -0
  54. data/spec/fixtures/empty_env/config/deploy.rb +15 -0
  55. data/spec/helpers/exec_helper_spec.rb +19 -0
  56. data/spec/helpers/output_helper_spec.rb +24 -0
  57. data/spec/spec_helper.rb +27 -0
  58. data/support/Readme-footer.md +32 -0
  59. data/support/Readme-header.md +16 -0
  60. data/support/guide.md +297 -0
  61. data/support/index.html +53 -0
  62. data/support/to_md.rb +11 -0
  63. data/test_env/config/deploy.rb +69 -0
  64. metadata +150 -0
@@ -0,0 +1,32 @@
1
+ module Mina
2
+ class Settings < Hash
3
+ def method_missing(meth, *args, &blk)
4
+ name = meth.to_s
5
+
6
+ return evaluate(self[meth]) if name.size == 1
7
+
8
+ # Ruby 1.8.7 doesn't let you do string[-1]
9
+ key, suffix = name[0..-2].to_sym, name[-1..-1]
10
+
11
+ case suffix
12
+ when '='
13
+ self[key] = args.first
14
+ when '?'
15
+ include? key
16
+ when '!'
17
+ raise Error, "Setting :#{key} is not set" unless include?(key)
18
+ evaluate self[key]
19
+ else
20
+ evaluate self[meth]
21
+ end
22
+ end
23
+
24
+ def evaluate(value)
25
+ if value.is_a?(Proc)
26
+ value.call
27
+ else
28
+ value
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,123 @@
1
+ # # Helpers: SSH helpers
2
+ # You don't need to invoke these helpers, they're already invoked automatically.
3
+
4
+ module Mina
5
+ module SshHelpers
6
+
7
+ # ### ssh
8
+ # Executes a command via SSH.
9
+ #
10
+ # Returns nothing usually, but if `{ return: true }` is given, returns the
11
+ # STDOUT output of the SSH session.
12
+ #
13
+ # `options` is a hash of options:
14
+ #
15
+ # - `:pretty` - Prettify the output if true.
16
+ # - `:return` - If set to true, returns the output.
17
+ #
18
+ # Example
19
+ #
20
+ # ssh("ls", return: true)
21
+
22
+ def ssh(cmd, options={})
23
+ require 'shellwords'
24
+
25
+ cmd = cmd.join("\n") if cmd.is_a?(Array)
26
+ script = Shellwords.escape(cmd)
27
+
28
+ if options[:return] == true
29
+ `#{ssh_command} -- #{script}`
30
+
31
+ elsif simulate_mode?
32
+ Ssh.simulate(cmd, ssh_command)
33
+
34
+ else
35
+ result = Ssh.invoke(script, self)
36
+ Ssh.ensure_successful result, self
37
+ end
38
+ end
39
+
40
+ # ### ssh_command
41
+ # Returns the SSH command to be executed.
42
+ #
43
+ # set :domain, 'foo.com'
44
+ # set :user, 'diggity'
45
+ #
46
+ # puts ssh_command
47
+ # #=> 'ssh diggity@foo.com'
48
+
49
+ def ssh_command
50
+ args = domain!.dup
51
+ args = "#{user}@#{args}" if user?
52
+ args << " -i #{identity_file}" if identity_file?
53
+ args << " -p #{port}" if port?
54
+ args << " -A" if forward_agent?
55
+ args << " #{ssh_options}" if ssh_options?
56
+ args << " -t"
57
+ "ssh #{args}"
58
+ end
59
+
60
+ # ## Private methods
61
+ # `ssh` delegates to these.
62
+
63
+ module Ssh
64
+
65
+ extend self
66
+
67
+ # ### Ssh.simulate
68
+ # __Internal:__ Prints SSH command. Called by `ssh`.
69
+
70
+ def simulate(cmd, ssh_command)
71
+ str = "Executing the following via '#{ssh_command}':"
72
+ puts "#!/usr/bin/env bash"
73
+ puts "# #{str}"
74
+ puts "#"
75
+
76
+ puts cmd
77
+
78
+ 0
79
+ end
80
+
81
+ # ### Ssh.invoke
82
+ # __Internal:__ Initiates an SSH session with script `script` with given
83
+ # `term_mode`. Called by `ssh`.
84
+
85
+ def invoke(script, this)
86
+ # Ruby 1.8.7 doesn't let you have empty symbols
87
+ term_mode = :"#{this.settings.term_mode}" if this.settings.term_mode
88
+ code = "#{this.ssh_command} -- #{script}"
89
+
90
+ # Certain environments can't do :pretty mode.
91
+ term_mode = :exec if term_mode == :pretty && !pretty_supported?
92
+
93
+ case term_mode
94
+ when :pretty
95
+ this.pretty_system(code)
96
+ when :exec
97
+ exec code
98
+ else
99
+ system code
100
+ $?.to_i
101
+ end
102
+ end
103
+
104
+ def pretty_supported?
105
+ # open4 is not supported under Windows.
106
+ # https://github.com/nadarei/mina/issues/58
107
+ require 'rbconfig'
108
+ ! (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/)
109
+ end
110
+
111
+ # ### Ssh.ensure_successful
112
+ # __Internal:__ Halts the execution if the given result code is not
113
+ # successful (non-zero).
114
+
115
+ def ensure_successful(result, this)
116
+ this.die result if result.is_a?(Fixnum) && result > 0
117
+ result
118
+ end
119
+
120
+ end
121
+
122
+ end
123
+ end
data/lib/mina/tools.rb ADDED
@@ -0,0 +1,20 @@
1
+ module Mina
2
+ module Tools
3
+ if IO.respond_to?(:popen4)
4
+ def self.popen4(*cmd, &blk)
5
+ IO.popen4 *cmd, &blk
6
+ $?
7
+ end
8
+ else
9
+ def self.popen4(*cmd, &blk)
10
+ require 'open4'
11
+ Open4.popen4 *cmd, &blk
12
+ end
13
+ end
14
+
15
+ def self.pfork4(*cmd, &blk)
16
+ require 'open4'
17
+ Open4.pfork4 *cmd, &blk
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Mina
2
+ def self.version
3
+ "0.3.1"
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ # # Modules: Whenever
2
+ # Adds settings and tasks for managing projects with [whenever].
3
+ # [whenever]: http://rubygems.org/gems/whenever
4
+
5
+ namespace :whenever do
6
+ desc "Clear crontab"
7
+ task :clear do
8
+ queue %{
9
+ echo "-----> Clear crontab for #{domain}_#{rails_env}"
10
+ #{echo_cmd %[cd #{deploy_to!}/#{current_path!} ; #{bundle_bin} exec whenever --clear-crontab #{domain}_#{rails_env} --set 'environment=#{rails_env}&path=#{deploy_to!}/#{current_path!}']}
11
+ }
12
+ end
13
+ desc "Update crontab"
14
+ task :update do
15
+ queue %{
16
+ echo "-----> Update crontab for #{domain}_#{rails_env}"
17
+ #{echo_cmd %[cd #{deploy_to!}/#{current_path!} ; #{bundle_bin} exec whenever --update-crontab #{domain}_#{rails_env} --set 'environment=#{rails_env}&path=#{deploy_to!}/#{current_path!}']}
18
+ }
19
+ end
20
+ desc "Write crontab"
21
+ task :write do
22
+ queue %{
23
+ echo "-----> Update crontab for #{domain}_#{rails_env}"
24
+ #{echo_cmd %[cd #{deploy_to!}/#{current_path!} ; #{bundle_bin} exec whenever --write-crontab #{domain}_#{rails_env} --set 'environment=#{rails_env}&path=#{deploy_to!}/#{current_path!}']}
25
+ }
26
+ end
27
+ end
data/manual/index.md ADDED
@@ -0,0 +1,15 @@
1
+ # Welcome to Mina
2
+
3
+ Really fast deployer and server automation tool.
4
+
5
+ Mina works really fast because it's a deploy Bash script generator. It
6
+ generates an entire procedure as a Bash script and runs it remotely in the
7
+ server.
8
+
9
+ Compare this to the likes of Vlad or Capistrano, where each command
10
+ is ran separately on their own SSH sessions. Mina only creates *one* SSH
11
+ session per deploy, minimizing the SSH connection overhead.
12
+
13
+ $ gem install mina
14
+ $ mina
15
+
data/manual/modules.md ADDED
@@ -0,0 +1,2 @@
1
+ Modules
2
+ =======
data/mina.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ require './lib/mina/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "colorful-mina"
5
+ s.version = Mina.version
6
+ s.summary = %{Really fast deployer and server automation tool.}
7
+ s.description = %Q{Really fast deployer and server automation tool.}
8
+ s.authors = ["Rico Sta. Cruz", "Michael Galero", "Weverton Timoteo"]
9
+ s.email = ["weverton.ct@gmail.com"]
10
+ s.homepage = "http://github.com/wevtimoteo/colorful-mina"
11
+ s.files = `git ls-files`.strip.split("\n")
12
+ s.executables = Dir["bin/*"].map { |f| File.basename(f) }
13
+
14
+ s.add_dependency "rake"
15
+ s.add_dependency "open4", "~> 1.3.4"
16
+ s.add_development_dependency "rspec", "~> 3.0.0"
17
+ end
@@ -0,0 +1,52 @@
1
+ # Invokes the main 'mina' command.
2
+ def run_command(*args)
3
+ out = ''
4
+ err = ''
5
+ @result = nil
6
+
7
+ if ENV['rake']
8
+ rake_version = "~> #{ENV['rake'] || '0.9'}.0"
9
+ script = %[require 'rubygems' unless Object.const_defined?(:Gem);]
10
+ script += %[gem 'rake', '#{rake_version}';]
11
+ script += %[load '#{root('bin/mina')}']
12
+ cmd = ['ruby', '-e', "#{script}", "--", *args]
13
+ else
14
+ cmd = [root('bin/mina'), *args]
15
+ end
16
+
17
+ status =
18
+ Mina::Tools.popen4(*cmd) do |pid, i, o, e|
19
+ out = o.read
20
+ err = e.read
21
+ end
22
+
23
+ @result = status.exitstatus
24
+
25
+ @out = out
26
+ @err = err
27
+
28
+ @result
29
+ end
30
+
31
+ # Invokes the main 'mina' command and ensures the exit status is success.
32
+ def mina(*args)
33
+ run_command *args
34
+ if exitstatus != 0 && ENV['verbose']
35
+ puts stdout
36
+ puts stderr
37
+ end
38
+
39
+ expect(exitstatus).to eq(0)
40
+ end
41
+
42
+ def stdout
43
+ @out
44
+ end
45
+
46
+ def stderr
47
+ @err
48
+ end
49
+
50
+ def exitstatus
51
+ @result
52
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ require 'command_helper'
3
+
4
+ describe "Invoking the 'mina deploy:cleanup' command" do
5
+ before :each do
6
+ Dir.chdir root('test_env')
7
+ end
8
+
9
+ it "should cleanup old deployments", :ssh => true do
10
+ 3.times { mina 'deploy' }
11
+
12
+ mina 'deploy:cleanup'
13
+
14
+ expect(Dir["deploy/releases/*"].length).to eq(2)
15
+ end
16
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ require 'command_helper'
3
+
4
+ describe "Invoking the 'mina' command in a project" do
5
+ before :each do
6
+ Dir.chdir root('test_env')
7
+ end
8
+
9
+ it "should think it's 'mina', not 'rake' (1)" do
10
+ run_command 'pinkledills'
11
+ expect(exitstatus).not_to eq(0)
12
+ expect(stderr).to include 'mina aborted'
13
+ end
14
+
15
+ it "should think it's 'mina', not 'rake' (1)" do
16
+ mina '-T'
17
+ expect(stdout).to include 'mina help'
18
+ expect(stdout).to include 'mina git:clone'
19
+ end
20
+
21
+ it 'with --version should print the version' do
22
+ mina '--version'
23
+ expect(stdout).to include Mina.version
24
+ end
25
+
26
+ it 'with -V should print the version' do
27
+ mina '-V'
28
+ expect(stdout).to include Mina.version
29
+ end
30
+
31
+ describe 'without arguments' do
32
+ before :each do
33
+ mina
34
+ end
35
+
36
+ it 'should print standard help tasks' do
37
+ mina
38
+ expect(stdout).to include 'mina help'
39
+ expect(stdout).to include 'mina init'
40
+ expect(stdout).to include 'mina tasks'
41
+ end
42
+
43
+ it 'should print project-specific tasks' do
44
+ mina
45
+ expect(stdout).to include 'mina deploy'
46
+ expect(stdout).to include 'mina restart'
47
+ expect(stdout).to include 'mina setup'
48
+ end
49
+
50
+ it "should be the same as running 'help'" do
51
+ previous_out = stdout
52
+
53
+ mina 'help'
54
+ expect(stdout).to eq(previous_out)
55
+ end
56
+ end
57
+
58
+ it "with 'mina -f' on a non-existing file should fail" do
59
+ run_command '-f', 'foobar'
60
+ expect(stderr).to include 'mina aborted'
61
+ expect(stderr).to include 'No Rakefile found'
62
+ end
63
+
64
+ it "with 'mina tasks' should print tasks" do
65
+ mina 'tasks'
66
+
67
+ expect(stdout).to include('bundle:install')
68
+ expect(stdout).to include('Install gem dependencies using Bundler')
69
+ expect(stdout).to include('passenger:restart')
70
+ end
71
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'command_helper'
3
+
4
+ describe "Invoking the 'mina' command in a project without a deploy.rb" do
5
+ before :each do
6
+ Dir.chdir root('spec/fixtures/custom_file_env')
7
+ FileUtils.rm_rf 'deploy'
8
+ end
9
+
10
+ it 'should fail' do
11
+ run_command 'deploy', '--simulate'
12
+ expect(exitstatus).to be > 0
13
+ end
14
+
15
+ it 'should pass if you provide a new rakefile' do
16
+ mina 'deploy', '--simulate', '-f', 'custom_deploy.rb'
17
+ expect(stdout).to include 'Creating a temporary build path'
18
+ end
19
+ end
20
+
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'command_helper'
3
+
4
+ describe "Invoking the 'mina' command in a project" do
5
+ before :each do
6
+ Dir.chdir root('test_env')
7
+ end
8
+
9
+ describe "to do a simulated deploy" do
10
+ before :each do
11
+ mina 'deploy', 'simulate=1'
12
+ end
13
+
14
+ it "should take care of the lockfile" do
15
+ expect(stdout).to match(/ERROR: another deployment is ongoing/)
16
+ expect(stdout).to match(/touch ".*deploy\.lock"/)
17
+ expect(stdout).to match(/rm -f ".*deploy\.lock"/)
18
+ end
19
+
20
+ it "should honor releases_path" do
21
+ expect(stdout).to include "releases/"
22
+ end
23
+
24
+ it "should symlink the current_path" do
25
+ expect(stdout).to match(/ln .*current/)
26
+ end
27
+
28
+ it "should include deploy directives" do
29
+ expect(stdout).to include "bundle exec rake db:migrate"
30
+ end
31
+
32
+ it "should include 'to :launch' directives" do
33
+ expect(stdout).to include "touch tmp/restart.txt"
34
+ end
35
+ end
36
+ end