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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +1 -0
- data/.travis.yml +21 -0
- data/CONTRIBUTING.md +124 -0
- data/Gemfile +10 -0
- data/HISTORY.md +348 -0
- data/LICENSE +23 -0
- data/Makefile +29 -0
- data/Notes.md +70 -0
- data/README.md +1015 -0
- data/Rakefile +20 -0
- data/bin/mina +65 -0
- data/data/deploy.rb +80 -0
- data/data/deploy.sh.erb +106 -0
- data/lib/mina.rb +23 -0
- data/lib/mina/bundler.rb +49 -0
- data/lib/mina/chruby.rb +49 -0
- data/lib/mina/default.rb +145 -0
- data/lib/mina/deploy.rb +138 -0
- data/lib/mina/deploy_helpers.rb +34 -0
- data/lib/mina/exec_helpers.rb +111 -0
- data/lib/mina/foreman.rb +82 -0
- data/lib/mina/git.rb +62 -0
- data/lib/mina/helpers.rb +386 -0
- data/lib/mina/output_helpers.rb +95 -0
- data/lib/mina/rails.rb +206 -0
- data/lib/mina/rake.rb +9 -0
- data/lib/mina/rbenv.rb +47 -0
- data/lib/mina/rvm.rb +88 -0
- data/lib/mina/settings.rb +32 -0
- data/lib/mina/ssh_helpers.rb +123 -0
- data/lib/mina/tools.rb +20 -0
- data/lib/mina/version.rb +5 -0
- data/lib/mina/whenever.rb +27 -0
- data/manual/index.md +15 -0
- data/manual/modules.md +2 -0
- data/mina.gemspec +17 -0
- data/spec/command_helper.rb +52 -0
- data/spec/commands/cleanup_spec.rb +16 -0
- data/spec/commands/command_spec.rb +71 -0
- data/spec/commands/custom_config_spec.rb +20 -0
- data/spec/commands/deploy_spec.rb +36 -0
- data/spec/commands/outside_project_spec.rb +35 -0
- data/spec/commands/real_deploy_spec.rb +53 -0
- data/spec/commands/ssh_spec.rb +14 -0
- data/spec/commands/verbose_spec.rb +21 -0
- data/spec/dsl/invoke_spec.rb +48 -0
- data/spec/dsl/queue_spec.rb +49 -0
- data/spec/dsl/settings_in_rake_spec.rb +39 -0
- data/spec/dsl/settings_spec.rb +61 -0
- data/spec/dsl/to_spec.rb +20 -0
- data/spec/fixtures/custom_file_env/custom_deploy.rb +15 -0
- data/spec/fixtures/empty_env/config/deploy.rb +15 -0
- data/spec/helpers/exec_helper_spec.rb +19 -0
- data/spec/helpers/output_helper_spec.rb +24 -0
- data/spec/spec_helper.rb +27 -0
- data/support/Readme-footer.md +32 -0
- data/support/Readme-header.md +16 -0
- data/support/guide.md +297 -0
- data/support/index.html +53 -0
- data/support/to_md.rb +11 -0
- data/test_env/config/deploy.rb +69 -0
- 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
|
data/lib/mina/version.rb
ADDED
@@ -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
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
|