sbfaulkner-astrovan 0.5.0
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.
- data/README.rdoc +46 -0
- data/VERSION.yml +4 -0
- data/lib/astrovan.rb +17 -0
- data/lib/astrovan/deploy.rb +53 -0
- data/lib/astrovan/exec.rb +37 -0
- data/lib/astrovan/rake.rb +24 -0
- data/lib/astrovan/session.rb +87 -0
- data/lib/astrovan/update.rb +29 -0
- data/lib/astrovan/util.rb +40 -0
- data/test/astrovan_test.rb +67 -0
- data/test/deploy_test.rb +33 -0
- data/test/deployment/github/TODO +0 -0
- data/test/deployment/heroku/TODO +0 -0
- data/test/deployment/jekyll/TODO +0 -0
- data/test/deployment/rails/TODO +0 -0
- data/test/deployment/sinatra/TODO +0 -0
- data/test/deployment/static/TODO +0 -0
- data/test/exec_test.rb +17 -0
- data/test/rake_test.rake +6 -0
- data/test/rake_test.rb +47 -0
- data/test/session_test.rb +40 -0
- data/test/test_helper.rb +39 -0
- data/test/update_test.rb +11 -0
- data/test/util_test.rb +72 -0
- metadata +85 -0
data/README.rdoc
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
= astrovan
|
2
|
+
|
3
|
+
simple, lightweight deployment tasks
|
4
|
+
|
5
|
+
== WHY?
|
6
|
+
|
7
|
+
First, I want to say that I'm *not* doing this because I don't like
|
8
|
+
capistrano.
|
9
|
+
|
10
|
+
I do like (ok, love) capistrano, but think that it can maybe be done
|
11
|
+
a bit more simply.
|
12
|
+
|
13
|
+
This is my attempt.
|
14
|
+
|
15
|
+
== Installation
|
16
|
+
|
17
|
+
$ script/plugin install git://github.com/sbfaulkner/astrovan.git
|
18
|
+
|
19
|
+
== Sample recipes
|
20
|
+
|
21
|
+
=== Update only
|
22
|
+
|
23
|
+
require 'astrovan'
|
24
|
+
|
25
|
+
using 'www.example.com' do
|
26
|
+
deploy 'git://github.com/sbfaulkner/scanty.git'
|
27
|
+
end
|
28
|
+
|
29
|
+
== NOTES
|
30
|
+
|
31
|
+
- no block for deploy implies mkdir && update
|
32
|
+
|
33
|
+
== TODO
|
34
|
+
|
35
|
+
- stdin handling for exec
|
36
|
+
- stdout/stderr handling for exec
|
37
|
+
- other commands (all using exec)
|
38
|
+
- share (smart wrapper arouncd symlink?)
|
39
|
+
- cp ?
|
40
|
+
- mv ?
|
41
|
+
- documentation
|
42
|
+
|
43
|
+
== Legal
|
44
|
+
|
45
|
+
*Author*:: S. Brent Faulkner <brentf@unwwwired.net>
|
46
|
+
*License*:: Copyright (c) 2009 unwwwired.net, released under the MIT license
|
data/VERSION.yml
ADDED
data/lib/astrovan.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'astrovan/session'
|
2
|
+
|
3
|
+
module Astrovan
|
4
|
+
# Create a deployment session for the specified remote hosts.
|
5
|
+
#
|
6
|
+
# The provided block will execute within the context of the newly created session.
|
7
|
+
def using(*hosts, &block)
|
8
|
+
raise ArgumentError, "Missing block" unless block_given?
|
9
|
+
env = hosts.last.is_a?(Hash) ? hosts.pop : {}
|
10
|
+
raise ArgumentError, "Missing host" unless hosts.any?
|
11
|
+
session = Session.new(hosts.flatten, env)
|
12
|
+
session.instance_eval(&block)
|
13
|
+
session.close
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
include Astrovan
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Astrovan
|
2
|
+
module Deploy
|
3
|
+
# Deploy an application to the remote servers.
|
4
|
+
#
|
5
|
+
# Options:
|
6
|
+
# * +application+ - a name for the application. If not provided, the application name is taken from the last component of the path to the source repository.
|
7
|
+
# * +deploy_to+ - the path of the directory for application deployment. Defaults to '/u/apps/:application'
|
8
|
+
#
|
9
|
+
# If a block is provided, the block is run to deploy the application in the specified environment.
|
10
|
+
#
|
11
|
+
# If no block is provided, a default deployment recipe is applied. The default recipe is:
|
12
|
+
# * create the deployment, release and shared directories
|
13
|
+
# * update the application from the repository into the release directory
|
14
|
+
# * symlink to the current application
|
15
|
+
#
|
16
|
+
# Due to differences in application environments, no provision is made to restart the application in the default
|
17
|
+
# recipe.
|
18
|
+
def deploy(repository, options = {})
|
19
|
+
original_environment = self.environment.dup
|
20
|
+
|
21
|
+
self.repository = repository
|
22
|
+
self.application = application = options[:application] || self.application || File.basename(URI.parse(repository).path.split('/').last,".git")
|
23
|
+
self.deploy_to = deploy_to = options[:deploy_to] || self.deploy_to || "/u/apps/#{application}"
|
24
|
+
self.shared_path = shared_path = File.join(deploy_to, 'shared')
|
25
|
+
self.shared_repository = shared_repository = File.join(shared_path, "#{application}.git")
|
26
|
+
self.release_name = release_name = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
27
|
+
self.releases_path = releases_path = File.join(deploy_to, 'releases')
|
28
|
+
self.release_path = release_path = File.join(releases_path, release_name)
|
29
|
+
self.env = options[:env] || self.env
|
30
|
+
self.rakefile = options[:rakefile] || self.rakefile
|
31
|
+
|
32
|
+
if block_given?
|
33
|
+
yield
|
34
|
+
else
|
35
|
+
# TODO: consider moving directory setup outside of update
|
36
|
+
dirs = [deploy_to, releases_path, shared_path]
|
37
|
+
# TODO: these shared children are rails specific... come up with another plan
|
38
|
+
# shared_children = %w(system log pids)
|
39
|
+
# dirs += shared_children.map { |d| File.join(shared_path, d) }
|
40
|
+
mkdir(dirs, options)
|
41
|
+
|
42
|
+
update options
|
43
|
+
|
44
|
+
end
|
45
|
+
rescue => e
|
46
|
+
# TODO: rollback
|
47
|
+
# rollback
|
48
|
+
raise
|
49
|
+
ensure
|
50
|
+
self.environment.replace original_environment
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'net/ssh/multi'
|
2
|
+
|
3
|
+
module Astrovan
|
4
|
+
module Exec
|
5
|
+
# Executes a command on the remote servers.
|
6
|
+
#
|
7
|
+
# Options:
|
8
|
+
# * +on+ - specifies a subset of servers to run the command on.
|
9
|
+
def exec(command, options = {})
|
10
|
+
session = session_for(options.delete(:on))
|
11
|
+
begin
|
12
|
+
command = command.gsub(/[\$\\"`]/) { |m| "\\#{m}" }
|
13
|
+
command = %Q(sh -c "#{command}")
|
14
|
+
if env = options[:env] || self.env
|
15
|
+
env = env.collect { |var,value| %Q(#{var}=#{value.gsub(/[ "]/) { |m| "\\#{m}" }}) }.join(' ') unless env.is_a?(String)
|
16
|
+
command = "env #{env} #{command}"
|
17
|
+
end
|
18
|
+
channel = session.exec command do |ch, stream, data|
|
19
|
+
STDERR.puts "[#{ch[:host]}] #{stream}: #{data}"
|
20
|
+
end
|
21
|
+
channel.wait
|
22
|
+
errors = 0
|
23
|
+
channel.each do |c|
|
24
|
+
if c[:exit_status] != 0
|
25
|
+
STDERR.puts "[#{c[:host]}] ERROR: terminated with non-zero exit status (#{c[:exit_status]})"
|
26
|
+
errors += 1
|
27
|
+
else
|
28
|
+
STDERR.puts "[#{c[:host]}] terminated with exit status of zero"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
raise "#{errors} remote command(s) failed" if errors > 0
|
32
|
+
ensure
|
33
|
+
session.close if session != self.session
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Astrovan
|
2
|
+
module Rake
|
3
|
+
# Execute a rake task on the remote servers.
|
4
|
+
#
|
5
|
+
# Options:
|
6
|
+
# * +rakefile+ - specify the path to a rakefile (if not in the default location)
|
7
|
+
def rake(*tasks)
|
8
|
+
options = tasks.last.is_a?(Hash) ? tasks.pop : {}
|
9
|
+
rake = 'rake'
|
10
|
+
rakefile = options.delete(:rakefile) || self.rakefile
|
11
|
+
rake << ' -f ' << rakefile if rakefile
|
12
|
+
exec "#{rake} #{tasks.join(' ')}", options
|
13
|
+
end
|
14
|
+
|
15
|
+
# Map one or more rake tasks to deployment methods.
|
16
|
+
def surrogate(map)
|
17
|
+
map.each do |method,task|
|
18
|
+
raise ArgumentError, "Method <#{method}> already defined" if methods.include?(method.to_s)
|
19
|
+
instance_eval "def #{method}; rake '#{task}'; end"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
alias_method :surrogates, :surrogate
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'astrovan/deploy'
|
2
|
+
require 'astrovan/exec'
|
3
|
+
require 'astrovan/util'
|
4
|
+
require 'astrovan/rake'
|
5
|
+
require 'astrovan/update'
|
6
|
+
|
7
|
+
module Astrovan
|
8
|
+
# Created by the using method, this is the context within which all other deployment methods run.
|
9
|
+
class Session
|
10
|
+
include Astrovan::Deploy
|
11
|
+
include Astrovan::Exec
|
12
|
+
include Astrovan::Util
|
13
|
+
include Astrovan::Rake
|
14
|
+
include Astrovan::Update
|
15
|
+
|
16
|
+
#:stopdoc:
|
17
|
+
DEFAULTS = {
|
18
|
+
:application => nil,
|
19
|
+
:deploy_to => nil,
|
20
|
+
:env => nil,
|
21
|
+
:password => nil,
|
22
|
+
:rakefile => nil,
|
23
|
+
:username => nil
|
24
|
+
}
|
25
|
+
#:startdoc:
|
26
|
+
|
27
|
+
# array of names of the hosts for the deployment session
|
28
|
+
attr_reader :hosts
|
29
|
+
|
30
|
+
def initialize(hosts, environment = {}) #:nodoc:
|
31
|
+
surrogates :disable => 'web:disable',
|
32
|
+
:enable => 'web:enable',
|
33
|
+
:migrate => 'db:migrate'
|
34
|
+
|
35
|
+
@hosts = hosts
|
36
|
+
@environment = DEFAULTS.merge environment
|
37
|
+
|
38
|
+
options = {}
|
39
|
+
options[:username] = environment[:username] if environment[:username]
|
40
|
+
options[:password] = environment[:password] if environment[:password]
|
41
|
+
|
42
|
+
@session = Net::SSH::Multi.start
|
43
|
+
@servers = hosts.inject({}) { |servers,host| servers[host] = @session.use(host, options); servers }
|
44
|
+
end
|
45
|
+
|
46
|
+
def close #:nodoc:
|
47
|
+
@session, session = nil, @session
|
48
|
+
session.close if session
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
def environment # :nodoc:
|
53
|
+
@environment
|
54
|
+
end
|
55
|
+
|
56
|
+
def session # :nodoc:
|
57
|
+
@session
|
58
|
+
end
|
59
|
+
|
60
|
+
def servers # :nodoc:
|
61
|
+
@servers
|
62
|
+
end
|
63
|
+
|
64
|
+
def session_for(hosts) # :nodoc:
|
65
|
+
if hosts
|
66
|
+
@session.on(servers_for(hosts))
|
67
|
+
else
|
68
|
+
@session
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def servers_for(hosts) # :nodoc:
|
73
|
+
@servers.values_at(*hosts)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def method_missing(symbol, *args)
|
78
|
+
if @environment.include?(symbol)
|
79
|
+
@environment[symbol]
|
80
|
+
elsif symbol.to_s =~ /^(.+)=$/ && !methods.include?($1)
|
81
|
+
@environment[$1.to_sym] = args.first
|
82
|
+
else
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Astrovan
|
4
|
+
module Update
|
5
|
+
def update(options = {})
|
6
|
+
shared_repository = self.shared_repository
|
7
|
+
repository = self.repository
|
8
|
+
release_path = self.release_path
|
9
|
+
|
10
|
+
# TODO: do we need branch support, submodule config, etc?
|
11
|
+
exec <<-END, options
|
12
|
+
if [ -d '#{shared_repository}' ]
|
13
|
+
then
|
14
|
+
cd #{shared_repository} &&
|
15
|
+
git fetch #{repository}
|
16
|
+
else
|
17
|
+
git clone --bare #{repository} #{shared_repository}
|
18
|
+
fi &&
|
19
|
+
git clone #{shared_repository} #{release_path}
|
20
|
+
END
|
21
|
+
|
22
|
+
yield if block_given?
|
23
|
+
rescue => e
|
24
|
+
# TODO: rollback
|
25
|
+
# rollback
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Astrovan
|
2
|
+
module Util
|
3
|
+
# Create one or more directories on the remote servers. Intermediate directories will be created
|
4
|
+
# as required.
|
5
|
+
def mkdir(*paths)
|
6
|
+
options = paths.last.is_a?(Hash) ? paths.pop : {}
|
7
|
+
# flatten, so that arrays of paths can be passed as arguments
|
8
|
+
paths = paths.flatten.join(' ')
|
9
|
+
# TODO: consider using sudo?
|
10
|
+
exec "mkdir -p #{paths} && chmod g+w #{paths}", options
|
11
|
+
end
|
12
|
+
|
13
|
+
# Remove files or directories on the remote servers.
|
14
|
+
#
|
15
|
+
# Options:
|
16
|
+
# * +recursive+ - set to true to attempt to recursively remove a directory
|
17
|
+
def rm(*paths)
|
18
|
+
options = paths.last.is_a?(Hash) ? paths.pop : {}
|
19
|
+
# flatten, so that arrays of paths can be passed as arguments
|
20
|
+
paths = paths.flatten.join(' ')
|
21
|
+
# TODO: consider using sudo?
|
22
|
+
rm = 'rm'
|
23
|
+
rm << ' -r' if options.delete(:recursive)
|
24
|
+
exec "#{rm} #{paths}", options
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a sylink on the remote servers. Any existing symlink will be removed first.
|
28
|
+
#
|
29
|
+
# Options:
|
30
|
+
# * +to+ - the path to the new symlink
|
31
|
+
def symlink(*paths)
|
32
|
+
options = paths.last.is_a?(Hash) ? paths.pop : {}
|
33
|
+
raise ArgumentError, "You must provide a target using the :to option" unless to = options.delete(:to)
|
34
|
+
# flatten, so that arrays of paths can be passed as arguments
|
35
|
+
paths = paths.flatten.join(' ')
|
36
|
+
# TODO: consider using sudo?
|
37
|
+
exec "ln -sf #{path} #{to}", options
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class AstrovanTest < Test::Unit::TestCase
|
4
|
+
def test_using_should_require_block
|
5
|
+
assert_raise ArgumentError do
|
6
|
+
using 'one.astrovan.local'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_using_should_require_at_least_one_host
|
11
|
+
assert_raise ArgumentError do
|
12
|
+
using do
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_using_should_setup_session_for_specified_host
|
18
|
+
assert_nothing_raised do
|
19
|
+
using 'one.astrovan.local' do
|
20
|
+
raise StandardError if hosts != %w(one.astrovan.local)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_using_should_setup_session_for_multiple_hosts
|
26
|
+
assert_nothing_raised do
|
27
|
+
using 'one.astrovan.local', 'two.astrovan.local', 'three.astrovan.local' do
|
28
|
+
raise StandardError if hosts != %w(one.astrovan.local two.astrovan.local three.astrovan.local)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_using_should_setup_session_for_array_of_hosts
|
34
|
+
assert_nothing_raised do
|
35
|
+
using %w(one.astrovan.local two.astrovan.local three.astrovan.local) do
|
36
|
+
raise StandardError if hosts != %w(one.astrovan.local two.astrovan.local three.astrovan.local)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_using_should_setup_session_for_mixed_host_arguments
|
42
|
+
assert_nothing_raised do
|
43
|
+
using %w(one.astrovan.local two.astrovan.local), 'three.astrovan.local' do
|
44
|
+
raise StandardError if hosts != %w(one.astrovan.local two.astrovan.local three.astrovan.local)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_using_should_create_session
|
50
|
+
assert_nothing_raised do
|
51
|
+
using %w(one.astrovan.local two.astrovan.local) do
|
52
|
+
raise TypeError unless session.is_a?(Net::SSH::Multi::Session)
|
53
|
+
raise StandardError if servers.size != hosts.size
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_using_should_create_subsession
|
59
|
+
assert_nothing_raised do
|
60
|
+
using %w(one.astrovan.local two.astrovan.local) do
|
61
|
+
session = session_for(%w(one.astrovan.local))
|
62
|
+
raise TypeError unless session.is_a?(Net::SSH::Multi::Subsession)
|
63
|
+
raise StandardError if servers.size != hosts.size
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/test/deploy_test.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class DeployTest < Test::Unit::TestCase
|
4
|
+
def test_should_deploy
|
5
|
+
using 'astrovan.local', :password => ENV['PASSWORD'] do
|
6
|
+
deploy 'git://github.com/adamwiggins/scanty.git', :env => { :PATH => '$PATH:/usr/local/git/bin' }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_should_deploy_static_site
|
11
|
+
flunk
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_deploy_rails_application
|
15
|
+
flunk
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_deploy_sinatra_application
|
19
|
+
flunk
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_should_deploy_heroku_application
|
23
|
+
flunk
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_should_deploy_github_application
|
27
|
+
flunk
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_deploy_jekyll_site
|
31
|
+
flunk
|
32
|
+
end
|
33
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/test/exec_test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class SessionTest < Test::Unit::TestCase
|
4
|
+
def test_should_exec
|
5
|
+
using 'astrovan.local', :password => ENV['PASSWORD'] do
|
6
|
+
exec 'hostname'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_should_fail_to_exec
|
11
|
+
assert_raise RuntimeError do
|
12
|
+
using 'astrovan.local', :password => ENV['PASSWORD'] do
|
13
|
+
exec 'kjasdhfkjahsdf'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/test/rake_test.rake
ADDED
data/test/rake_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class RakeTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@rakefile = File.expand_path(File.join(File.dirname(__FILE__),'rake_test.rake'))
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_run_rake_task
|
9
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :rakefile => @rakefile do
|
10
|
+
rake 'succeed'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_fail_when_rake_task_fails
|
15
|
+
assert_raise(RuntimeError) do
|
16
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :rakefile => @rakefile do
|
17
|
+
rake 'fail'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_should_fail_when_rake_task_not_defined
|
23
|
+
assert_raise(RuntimeError) do
|
24
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :rakefile => @rakefile do
|
25
|
+
rake 'undefined'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_define_methods_to_run_rake_task
|
31
|
+
using 'astrovan.local', :password => ENV['PASSWORD'] do
|
32
|
+
raise "succeed method should not be defined" if methods.include?('succeed')
|
33
|
+
raise "fail method should not be defined" if methods.include?('fail')
|
34
|
+
surrogates :succeed => 'success', :fail => 'failure'
|
35
|
+
raise "succeed method should be defined" unless methods.include?('succeed')
|
36
|
+
raise "fail method should be defined" unless methods.include?('fail')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_should_fail_to_define_method_if_already_defined
|
41
|
+
assert_raise(ArgumentError) do
|
42
|
+
using 'astrovan.local', :password => ENV['PASSWORD'] do
|
43
|
+
surrogate :freeze => 'rails:freeze:edge'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class SessionTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@session = Session.new(%w(one.astrovan.local), :user => 'admin')
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_should_initialize_hosts
|
10
|
+
assert_equal %w(one.astrovan.local), @session.hosts
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_hosts_should_be_readonly
|
14
|
+
assert_raise(NoMethodError) { @session.hosts = %w(two.astrovan.local) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_should_fail_for_undefined_value
|
18
|
+
assert_raise(NoMethodError) { @session.unknown }
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_initialize_value
|
22
|
+
assert_equal 'admin', @session.user
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_set_value
|
26
|
+
@session.password = 'Passw0rd'
|
27
|
+
assert_equal 'Passw0rd', @session.password
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_overwrite_value
|
31
|
+
@session.user = 'marc.garneau'
|
32
|
+
assert_equal 'marc.garneau', @session.user
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_have_predefined_methods_to_run_standard_rake_tasks
|
36
|
+
assert_method :migrate, @session
|
37
|
+
assert_method :enable, @session
|
38
|
+
assert_method :disable, @session
|
39
|
+
end
|
40
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
require 'astrovan'
|
7
|
+
|
8
|
+
require 'socket'
|
9
|
+
require 'resolv-replace'
|
10
|
+
|
11
|
+
class IPSocket
|
12
|
+
class << self
|
13
|
+
def getaddress_with_trace(name)
|
14
|
+
return getaddress_without_trace('127.0.0.1') if name =~ /^(.*\.)?astrovan\.local$/
|
15
|
+
getaddress_without_trace(name)
|
16
|
+
end
|
17
|
+
alias_method :getaddress_without_trace, :getaddress
|
18
|
+
alias_method :getaddress, :getaddress_with_trace
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Test::Unit::TestCase
|
23
|
+
def self.ask_for(text)
|
24
|
+
STDOUT.print text
|
25
|
+
STDIN.gets.chomp
|
26
|
+
end
|
27
|
+
|
28
|
+
ENV['PASSWORD'] ||= ask_for('Password: ')
|
29
|
+
protected
|
30
|
+
def assert_method(name, object = nil)
|
31
|
+
object ||= self
|
32
|
+
assert object.methods.include?(name.to_s), "Expected <#{name}> method to be defined"
|
33
|
+
end
|
34
|
+
|
35
|
+
def assert_no_method(name, object = nil)
|
36
|
+
object ||= self
|
37
|
+
assert ! object.methods.include?(name.to_s), "Expected <#{name}> method to be undefined"
|
38
|
+
end
|
39
|
+
end
|
data/test/update_test.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class UpdateTest < Test::Unit::TestCase
|
4
|
+
def test_should_update
|
5
|
+
using 'astrovan.local', :password => ENV['PASSWORD'] do
|
6
|
+
deploy 'git://github.com/adamwiggins/scanty.git', :env => { :PATH => '$PATH:/usr/local/git/bin' } do
|
7
|
+
update
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/test/util_test.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class UtilTest < Test::Unit::TestCase
|
4
|
+
include
|
5
|
+
def setup
|
6
|
+
@path = "/tmp/astrovan.#{Time.now.to_i}"
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
system "rm -rf #{@path} #{@path}.lnk"
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_should_mkdir
|
16
|
+
assert !File.exist?(@path)
|
17
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :path => @path do
|
18
|
+
mkdir path
|
19
|
+
end
|
20
|
+
assert File.exist?(@path)
|
21
|
+
assert File.directory?(@path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_rm_file
|
25
|
+
create_file
|
26
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :path => @path do
|
27
|
+
rm path
|
28
|
+
end
|
29
|
+
assert !File.exist?(@path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_not_rm_directory
|
33
|
+
system "mkdir -p #{@path}"
|
34
|
+
assert File.exist?(@path)
|
35
|
+
assert File.directory?(@path)
|
36
|
+
assert_raise(RuntimeError) do
|
37
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :path => @path do
|
38
|
+
rm path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
assert File.exist?(@path)
|
42
|
+
assert File.directory?(@path)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_rm_directory_with_recursive_option
|
46
|
+
system "mkdir -p #{@path}"
|
47
|
+
assert File.exist?(@path)
|
48
|
+
assert File.directory?(@path)
|
49
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :path => @path do
|
50
|
+
rm path, :recursive => true
|
51
|
+
end
|
52
|
+
assert !File.exist?(@path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_should_symlink
|
56
|
+
data = create_file
|
57
|
+
target = @path + ".lnk"
|
58
|
+
using 'astrovan.local', :password => ENV['PASSWORD'], :path => @path, :target => target do
|
59
|
+
symlink path, :to => target
|
60
|
+
end
|
61
|
+
assert_equal data, File.open(target) { |f| f.gets.chomp }
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
def create_file
|
66
|
+
data = Time.now.utc.to_s
|
67
|
+
File.open(@path,'w') { |f| f.puts data }
|
68
|
+
assert File.exist?(@path)
|
69
|
+
assert !File.directory?(@path)
|
70
|
+
data
|
71
|
+
end
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sbfaulkner-astrovan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- S. Brent Faulkner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-21 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: simple, lightweight deployment tasks
|
17
|
+
email: brentf@unwwwired.net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README.rdoc
|
26
|
+
- VERSION.yml
|
27
|
+
- lib/astrovan
|
28
|
+
- lib/astrovan/deploy.rb
|
29
|
+
- lib/astrovan/exec.rb
|
30
|
+
- lib/astrovan/rake.rb
|
31
|
+
- lib/astrovan/session.rb
|
32
|
+
- lib/astrovan/update.rb
|
33
|
+
- lib/astrovan/util.rb
|
34
|
+
- lib/astrovan.rb
|
35
|
+
- test/astrovan_test.rb
|
36
|
+
- test/deploy_test.rb
|
37
|
+
- test/deployment
|
38
|
+
- test/deployment/github
|
39
|
+
- test/deployment/github/TODO
|
40
|
+
- test/deployment/heroku
|
41
|
+
- test/deployment/heroku/TODO
|
42
|
+
- test/deployment/jekyll
|
43
|
+
- test/deployment/jekyll/TODO
|
44
|
+
- test/deployment/rails
|
45
|
+
- test/deployment/rails/TODO
|
46
|
+
- test/deployment/sinatra
|
47
|
+
- test/deployment/sinatra/TODO
|
48
|
+
- test/deployment/static
|
49
|
+
- test/deployment/static/TODO
|
50
|
+
- test/exec_test.rb
|
51
|
+
- test/rake_test.rake
|
52
|
+
- test/rake_test.rb
|
53
|
+
- test/session_test.rb
|
54
|
+
- test/test_helper.rb
|
55
|
+
- test/update_test.rb
|
56
|
+
- test/util_test.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://sbfaulkner.github.com/astrovan
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --inline-source
|
62
|
+
- --charset=UTF-8
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.2.0
|
81
|
+
signing_key:
|
82
|
+
specification_version: 2
|
83
|
+
summary: simple, lightweight deployment tasks
|
84
|
+
test_files: []
|
85
|
+
|