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 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
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 5
4
+ :patch: 0
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
@@ -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
@@ -0,0 +1,6 @@
1
+ task :succeed do
2
+ end
3
+
4
+ task :fail do
5
+ raise "failed"
6
+ end
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
@@ -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
@@ -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
+