trooper 0.6.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +96 -0
- data/Rakefile +44 -0
- data/bin/trooper +9 -0
- data/lib/trooper/action.rb +56 -0
- data/lib/trooper/actions/clone_repository_action.rb +31 -0
- data/lib/trooper/actions/install_gems_action.rb +31 -0
- data/lib/trooper/actions/migrate_database_action.rb +31 -0
- data/lib/trooper/actions/restart_server_action.rb +33 -0
- data/lib/trooper/actions/rollback_migrate_action.rb +31 -0
- data/lib/trooper/actions/setup_database_action.rb +31 -0
- data/lib/trooper/actions/update_repository_action.rb +33 -0
- data/lib/trooper/arsenal.rb +51 -0
- data/lib/trooper/cli.rb +67 -0
- data/lib/trooper/config/action.rb +34 -0
- data/lib/trooper/config/environment.rb +36 -0
- data/lib/trooper/config/strategy.rb +14 -0
- data/lib/trooper/configuration.rb +88 -0
- data/lib/trooper/dsl/bundler.rb +26 -0
- data/lib/trooper/dsl/folders.rb +24 -0
- data/lib/trooper/dsl/rake.rb +11 -0
- data/lib/trooper/logger.rb +86 -0
- data/lib/trooper/runner.rb +57 -0
- data/lib/trooper/strategy.rb +104 -0
- data/lib/trooper/template/troopfile.rb +34 -0
- data/lib/trooper/version.rb +9 -0
- data/lib/trooper.rb +29 -0
- metadata +220 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 Richard Adams
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Trooper [![Build Status](https://secure.travis-ci.org/madwire/trooper.png?branch=master)](http://travis-ci.org/madwire/trooper)
|
2
|
+
|
3
|
+
Trooper is designed to give you the flexibility to deploy your code to any server in any way you like.
|
4
|
+
You design your deployment strategy to best fit your application and its needs.
|
5
|
+
Trooper comes with some built in actions that you can use in your own strategies or come up with entirely new ones.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
1. Super easy! `gem install trooper` or add it to your Gemfile `gem 'trooper'`
|
10
|
+
2. Pop into your terminal and run `=> trooper init`
|
11
|
+
3. Start building you deployment strategy :)
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
`=> trooper deploy -e staging` or `=> trooper update`
|
16
|
+
|
17
|
+
#### Define your own strategies and actions
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
action :restart_server, 'Restarting the server' do
|
21
|
+
run 'touch tmp/restart.txt'
|
22
|
+
run "echo 'Restarted'"
|
23
|
+
end
|
24
|
+
|
25
|
+
strategy :restart, 'Restart application' do
|
26
|
+
actions :restart_server
|
27
|
+
end
|
28
|
+
|
29
|
+
strategy :update, 'Update the code base on the server' do
|
30
|
+
actions :update_repository, :install_gems
|
31
|
+
call :restart # call another strategy
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
#### Example Troopfile
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
user 'my_user'
|
39
|
+
hosts 'production1.example.com', 'production2.example.com'
|
40
|
+
repository 'git@git.foo.co.uk:bar.git'
|
41
|
+
path "/fullpath/to/data/folder"
|
42
|
+
|
43
|
+
set :my_value => 'something'
|
44
|
+
|
45
|
+
env :stage do
|
46
|
+
hosts 'stage.example.com',
|
47
|
+
set :my_value => 'something_else'
|
48
|
+
|
49
|
+
action :restart do
|
50
|
+
run 'touch tmp/restert.txt'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
action :restart do
|
55
|
+
run 'touch tmp/restert.txt'
|
56
|
+
run "echo 'Restarted'"
|
57
|
+
end
|
58
|
+
|
59
|
+
strategy :update, 'Update the code base on the server' do
|
60
|
+
actions :update_repository, :install_gems
|
61
|
+
call :restart
|
62
|
+
end
|
63
|
+
|
64
|
+
strategy :deploy, 'Full deployment to the server' do
|
65
|
+
call :update
|
66
|
+
actions :migrate_database
|
67
|
+
call :restart
|
68
|
+
end
|
69
|
+
|
70
|
+
strategy :restart, 'Restart application' do
|
71
|
+
actions :restart
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
## LICENSE
|
76
|
+
|
77
|
+
Copyright 2011 Richard Adams
|
78
|
+
|
79
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
80
|
+
a copy of this software and associated documentation files (the
|
81
|
+
"Software"), to deal in the Software without restriction, including
|
82
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
83
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
84
|
+
permit persons to whom the Software is furnished to do so, subject to
|
85
|
+
the following conditions:
|
86
|
+
|
87
|
+
The above copyright notice and this permission notice shall be
|
88
|
+
included in all copies or substantial portions of the Software.
|
89
|
+
|
90
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
91
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
92
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
93
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
94
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
95
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
96
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'rdoc/task'
|
10
|
+
require 'sdoc'
|
11
|
+
rescue LoadError
|
12
|
+
require 'rdoc/rdoc'
|
13
|
+
require 'rake/rdoctask'
|
14
|
+
RDoc::Task = Rake::RDocTask
|
15
|
+
end
|
16
|
+
|
17
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'Trooper'
|
20
|
+
rdoc.options << '--line-numbers'
|
21
|
+
rdoc.options << '-f' << 'sdoc'
|
22
|
+
rdoc.options << '-c' << 'utf-8'
|
23
|
+
rdoc.options << '-t' << 'rails'
|
24
|
+
#rdoc.options << '-g' # SDoc flag, link methods to GitHub
|
25
|
+
rdoc.rdoc_files.include('README.md')
|
26
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
Bundler::GemHelper.install_tasks
|
31
|
+
|
32
|
+
|
33
|
+
ENV["COVERAGE"] = "true"
|
34
|
+
|
35
|
+
require 'rspec/core'
|
36
|
+
require 'rspec/core/rake_task'
|
37
|
+
|
38
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
39
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'Default: Run all specs.'
|
43
|
+
task :default => :spec
|
44
|
+
|
data/bin/trooper
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'trooper/dsl/folders'
|
2
|
+
require 'trooper/dsl/rake'
|
3
|
+
require 'trooper/dsl/bundler'
|
4
|
+
|
5
|
+
module Trooper
|
6
|
+
class Action
|
7
|
+
include Trooper::DSL::Folders
|
8
|
+
include Trooper::DSL::Rake
|
9
|
+
include Trooper::DSL::Bundler
|
10
|
+
|
11
|
+
attr_reader :name, :description, :config, :block
|
12
|
+
attr_accessor :commands
|
13
|
+
|
14
|
+
# expects a name, description and a block
|
15
|
+
# Action.new(:my_action, 'Does great things') { run 'touch file' }
|
16
|
+
def initialize(name, description, &block)
|
17
|
+
@name, @description, @config = name, description, {}
|
18
|
+
@commands, @block = [], block
|
19
|
+
end
|
20
|
+
|
21
|
+
# eval's the block passed on initialize and returns the command array
|
22
|
+
def call(configuration)
|
23
|
+
@config = configuration
|
24
|
+
eval_block(&block)
|
25
|
+
commands
|
26
|
+
end
|
27
|
+
alias :execute :call
|
28
|
+
|
29
|
+
# validates the action
|
30
|
+
def ok?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
# run is the base run command used by the dsl
|
35
|
+
def run(command)
|
36
|
+
commands << command if command != ''
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(method_sym, *arguments, &block) # :nodoc:
|
40
|
+
config[method_sym] || super
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def eval_block(&block) # :nodoc:
|
46
|
+
if block_given?
|
47
|
+
if block.arity == 1
|
48
|
+
block.call self
|
49
|
+
else
|
50
|
+
instance_eval &block
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
class CloneRepositoryAction < Action
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@name = :clone_repository
|
10
|
+
@description = "Cloning repository as 'application'"
|
11
|
+
@config = config
|
12
|
+
@commands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(configuration)
|
16
|
+
@config = configuration
|
17
|
+
build_commands
|
18
|
+
commands
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_commands
|
24
|
+
cd path
|
25
|
+
run "git clone #{repository} application"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
class InstallGemsAction < Action
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@name = :install_gems
|
10
|
+
@description = "Installing Gems with Bundler"
|
11
|
+
@config = config
|
12
|
+
@commands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(configuration)
|
16
|
+
@config = configuration
|
17
|
+
build_commands
|
18
|
+
commands
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_commands
|
24
|
+
cd application_path
|
25
|
+
bundle_install
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
class MigrateDatabaseAction < Action
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@name = :migrate_database
|
10
|
+
@description = "Migrating database"
|
11
|
+
@config = config
|
12
|
+
@commands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(configuration)
|
16
|
+
@config = configuration
|
17
|
+
build_commands
|
18
|
+
commands
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_commands
|
24
|
+
cd application_path
|
25
|
+
rake "db:migrate RAILS_ENV=#{environment}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
class RestartServerAction < Action
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@name = :restart_server
|
10
|
+
@description = "Restart server"
|
11
|
+
@config = config
|
12
|
+
@commands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(configuration)
|
16
|
+
@config = configuration
|
17
|
+
build_commands
|
18
|
+
commands
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_commands
|
24
|
+
cd application_path
|
25
|
+
create_folder 'tmp'
|
26
|
+
run 'touch tmp/restart.txt'
|
27
|
+
run 'echo "Server restarted!"'
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
class RollbackMigrateAction < Action
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@name = :rollback_migrate
|
10
|
+
@description = "Rollback database"
|
11
|
+
@config = config
|
12
|
+
@commands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(configuration)
|
16
|
+
@config = configuration
|
17
|
+
build_commands
|
18
|
+
commands
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_commands
|
24
|
+
cd application_path
|
25
|
+
rake "db:rollback RAILS_ENV=#{environment}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
class SetupDatabaseAction < Action
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@name = :setup_database
|
10
|
+
@description = "Setting up database"
|
11
|
+
@config = config
|
12
|
+
@commands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(configuration)
|
16
|
+
@config = configuration
|
17
|
+
build_commands
|
18
|
+
commands
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_commands
|
24
|
+
cd application_path
|
25
|
+
rake "db:setup RAILS_ENV=#{environment}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Actions
|
5
|
+
|
6
|
+
class UpdateRepositoryAction < Action
|
7
|
+
|
8
|
+
def initialize(config = {})
|
9
|
+
@name = :update_repository
|
10
|
+
@description = "Updating repository"
|
11
|
+
@config = config
|
12
|
+
@commands = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(configuration)
|
16
|
+
@config = configuration
|
17
|
+
build_commands
|
18
|
+
commands
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_commands
|
24
|
+
cd application_path
|
25
|
+
run "git checkout #{branch} -q"
|
26
|
+
run "git pull origin #{branch} -q"
|
27
|
+
run "git gc --aggressive"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Trooper
|
2
|
+
|
3
|
+
class Arsenal < Array
|
4
|
+
|
5
|
+
# find an arsenal by its name
|
6
|
+
def find_by_name(name)
|
7
|
+
detect { |weapon| weapon.name == name }
|
8
|
+
end
|
9
|
+
alias :[] :find_by_name
|
10
|
+
|
11
|
+
# add a weapon to the arsenal
|
12
|
+
def add(weapon)
|
13
|
+
if weapon.ok?
|
14
|
+
remove weapon.name
|
15
|
+
self << weapon
|
16
|
+
end
|
17
|
+
weapon
|
18
|
+
end
|
19
|
+
|
20
|
+
# remove a weapon from the arsenal
|
21
|
+
def remove(name)
|
22
|
+
self.delete_if {|w| w.name == name}
|
23
|
+
end
|
24
|
+
|
25
|
+
# clears arsenal
|
26
|
+
def clear!
|
27
|
+
self.clear
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
|
32
|
+
# returns the strategies arsenal
|
33
|
+
def strategies
|
34
|
+
@strategies ||= new
|
35
|
+
end
|
36
|
+
|
37
|
+
# returns the strategies arsenal
|
38
|
+
def actions
|
39
|
+
@actions ||= new
|
40
|
+
end
|
41
|
+
|
42
|
+
# clears all default arsenal
|
43
|
+
def reset!
|
44
|
+
@strategies, @actions = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/trooper/cli.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'trooper/configuration'
|
3
|
+
|
4
|
+
module Trooper
|
5
|
+
class CLI
|
6
|
+
|
7
|
+
def self.start(argv = ARGV)
|
8
|
+
cli = self.new(argv)
|
9
|
+
cli.execute
|
10
|
+
cli
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :command, :options, :argv
|
14
|
+
attr_accessor :config
|
15
|
+
|
16
|
+
def initialize(argv)
|
17
|
+
@argv = argv
|
18
|
+
@options = { :environment => :production }
|
19
|
+
|
20
|
+
@command = option_parser.parse!(@argv)[0]
|
21
|
+
raise CliArgumentError, "You didnt pass an action" if @command == nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute
|
25
|
+
case command.to_sym
|
26
|
+
when :init
|
27
|
+
Configuration.init
|
28
|
+
else
|
29
|
+
config = Configuration.new(options)
|
30
|
+
config.execute action
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def option_parser
|
37
|
+
@option_parser ||= ::OptionParser.new do |op|
|
38
|
+
op.banner = 'Usage: trooper <command> [options]'
|
39
|
+
op.separator ''
|
40
|
+
|
41
|
+
op.on "-d", "--debug", "Debuy" do
|
42
|
+
@options[:debug] = true
|
43
|
+
end
|
44
|
+
|
45
|
+
op.on "-e", "--env ENV", "Environment" do |e|
|
46
|
+
@options[:environment] = e.to_sym
|
47
|
+
end
|
48
|
+
|
49
|
+
op.on "-f", "--file TROOPFILE", "Load a different Troopfile" do |f|
|
50
|
+
@options[:file_name] = f || 'Troopfile'
|
51
|
+
end
|
52
|
+
|
53
|
+
op.on_tail "-h", "--help", "Help" do
|
54
|
+
puts @option_parser
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
|
58
|
+
op.on_tail "-v", "--version", "Show version" do
|
59
|
+
puts "Trooper v#{Trooper::Version::STRING}"
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'trooper/action'
|
2
|
+
|
3
|
+
require 'trooper/actions/clone_repository_action'
|
4
|
+
require 'trooper/actions/install_gems_action'
|
5
|
+
require 'trooper/actions/migrate_database_action'
|
6
|
+
require 'trooper/actions/restart_server_action'
|
7
|
+
require 'trooper/actions/rollback_migrate_action'
|
8
|
+
require 'trooper/actions/setup_database_action'
|
9
|
+
require 'trooper/actions/update_repository_action'
|
10
|
+
|
11
|
+
module Trooper
|
12
|
+
module Config
|
13
|
+
module Action
|
14
|
+
|
15
|
+
DEFAULT_ACTIONS = [Actions::CloneRepositoryAction, Actions::InstallGemsAction,
|
16
|
+
Actions::MigrateDatabaseAction, Actions::RestartServerAction,
|
17
|
+
Actions::RollbackMigrateAction, Actions::SetupDatabaseAction,
|
18
|
+
Actions::UpdateRepositoryAction]
|
19
|
+
|
20
|
+
def action(name, description = "No Description", &block)
|
21
|
+
action = Trooper::Action.new name, description, &block
|
22
|
+
Trooper::Arsenal.actions.add action
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def load_default_actions!
|
27
|
+
DEFAULT_ACTIONS.each do |klass|
|
28
|
+
Trooper::Arsenal.actions.add klass.new
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Trooper
|
2
|
+
module Config
|
3
|
+
module Environment
|
4
|
+
|
5
|
+
def load_environment!
|
6
|
+
instance_variable = instance_variable_get("@#{self[:environment].to_s}_configuration")
|
7
|
+
unless instance_variable.nil?
|
8
|
+
instance_eval(&instance_variable)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def env(environment_name, &block)
|
13
|
+
instance_variable_set "@#{environment_name.to_s}_configuration", block
|
14
|
+
end
|
15
|
+
|
16
|
+
def user(arg)
|
17
|
+
set :user => arg
|
18
|
+
end
|
19
|
+
|
20
|
+
def hosts(*arg)
|
21
|
+
set :hosts => [*arg]
|
22
|
+
end
|
23
|
+
|
24
|
+
def repository(arg)
|
25
|
+
set :repository => arg
|
26
|
+
end
|
27
|
+
|
28
|
+
def path(arg)
|
29
|
+
set :application_path => "#{arg}/application"
|
30
|
+
set :trooper_path => "#{arg}/trooper"
|
31
|
+
set :path => arg
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'trooper/strategy'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
module Config
|
5
|
+
module Strategy
|
6
|
+
|
7
|
+
def strategy(name, description = "No Description", &block)
|
8
|
+
strategy = Trooper::Strategy.new name, description, self, &block
|
9
|
+
Trooper::Arsenal.strategies.add strategy
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'trooper/arsenal'
|
4
|
+
|
5
|
+
require 'trooper/config/environment'
|
6
|
+
require 'trooper/config/strategy'
|
7
|
+
require 'trooper/config/action'
|
8
|
+
|
9
|
+
module Trooper
|
10
|
+
class Configuration < Hash
|
11
|
+
FILE_NAME = "Troopfile"
|
12
|
+
|
13
|
+
include Trooper::Config::Environment
|
14
|
+
include Trooper::Config::Strategy
|
15
|
+
include Trooper::Config::Action
|
16
|
+
|
17
|
+
def self.init
|
18
|
+
gem_dir = File.dirname(__FILE__)
|
19
|
+
|
20
|
+
if RUBY_VERSION == /1.8/
|
21
|
+
require 'ftools'
|
22
|
+
File.copy("#{gem_dir}/template/troopfile.rb", "./Troopfile")
|
23
|
+
else
|
24
|
+
require 'fileutils'
|
25
|
+
::FileUtils.copy("#{gem_dir}/template/troopfile.rb", "./Troopfile")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# initialize a new configuration object, will parse the given troopfile.
|
30
|
+
# Configuration.new({:my_override => 'settings'})
|
31
|
+
def initialize(options = {})
|
32
|
+
@loaded = false
|
33
|
+
@file_name = options[:file_name] || FILE_NAME
|
34
|
+
self[:environment] = options[:environment] || :production
|
35
|
+
|
36
|
+
load_default_actions!
|
37
|
+
load_troopfile! options
|
38
|
+
end
|
39
|
+
|
40
|
+
# returns a terminal friendly version of the configuration
|
41
|
+
def to_s
|
42
|
+
self.map {|k,v| "#{k}: #{v}" }.join("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
# will find and execute the strategy name passed
|
46
|
+
# @config.execute(:my_strategy_name)
|
47
|
+
def execute(strategy_name)
|
48
|
+
Arsenal.strategies[strategy_name].execute self
|
49
|
+
end
|
50
|
+
|
51
|
+
# a way to set variables that will be available to all actions
|
52
|
+
# set(:my_variable => 'sdsd') # => available as method in an action
|
53
|
+
def set(hash)
|
54
|
+
self.merge! hash
|
55
|
+
end
|
56
|
+
|
57
|
+
# returns true if the troopfile was loaded
|
58
|
+
def loaded?
|
59
|
+
@loaded
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# loads the troopfile and sets the environment up
|
65
|
+
def load_troopfile!(options)
|
66
|
+
if troopfile?
|
67
|
+
eval troopfile.read
|
68
|
+
@loaded = true
|
69
|
+
|
70
|
+
load_environment!
|
71
|
+
set options
|
72
|
+
else
|
73
|
+
raise Trooper::NoConfigurationFileError, "No Configuration file (#{@file_name}) can be found!"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# returns the troopfile file object
|
78
|
+
def troopfile
|
79
|
+
File.open(@file_name)
|
80
|
+
end
|
81
|
+
|
82
|
+
# returns true if the troopfile exists
|
83
|
+
def troopfile?
|
84
|
+
File.exists?(@file_name)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Trooper
|
2
|
+
module DSL
|
3
|
+
module Bundler
|
4
|
+
|
5
|
+
def bundle_exec(command)
|
6
|
+
use_bundle = using_bundler? ? "bundle exec " : ""
|
7
|
+
run use_bundle + command
|
8
|
+
end
|
9
|
+
|
10
|
+
def bundle_install
|
11
|
+
run "bundle install --path #{trooper_path}/bundle --deployment --without development test" if using_bundler?
|
12
|
+
end
|
13
|
+
|
14
|
+
def rake(command)
|
15
|
+
bundle_exec "rake #{command}"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def using_bundler?
|
21
|
+
File.exists? "Gemfile"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Trooper
|
2
|
+
module DSL
|
3
|
+
module Folders
|
4
|
+
|
5
|
+
def cd(path)
|
6
|
+
run "cd #{path}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_folder(path)
|
10
|
+
run "mkdir -p #{path}"
|
11
|
+
end
|
12
|
+
alias :mkdir :create_folder
|
13
|
+
|
14
|
+
def delete_folder(path)
|
15
|
+
run "rm -rf #{path}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_folders(*folders)
|
19
|
+
folders.each { |folder| create_folder folder }
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Trooper
|
6
|
+
|
7
|
+
class Logger < ::Logger
|
8
|
+
ACTION = 6
|
9
|
+
SUCCESS = 7
|
10
|
+
|
11
|
+
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN < ACTION < SUCCESS
|
12
|
+
LABELS = %w(DEBUG INFO WARN ERROR FATAL ANY ACTION SUCCESS)
|
13
|
+
|
14
|
+
def action(progname = nil, &block)
|
15
|
+
add(ACTION, nil, progname, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def success(progname = nil, &block)
|
19
|
+
add(SUCCESS, nil, progname, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def format_severity(severity)
|
25
|
+
LABELS[severity] || 'ANY'
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
class LogFormat
|
32
|
+
|
33
|
+
COLOURS = {
|
34
|
+
:black => 30,
|
35
|
+
:red => 31,
|
36
|
+
:green => 32,
|
37
|
+
:yellow => 33,
|
38
|
+
:blue => 34,
|
39
|
+
:magenta => 35,
|
40
|
+
:cyan => 36,
|
41
|
+
:white => 37
|
42
|
+
}
|
43
|
+
|
44
|
+
def call(severity, datetime, progname, message)
|
45
|
+
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN < ACTION < SUCCESS
|
46
|
+
case severity
|
47
|
+
when "DEBUG"
|
48
|
+
colour("#{progname} => [#{severity}] #{message}\n", :yellow)
|
49
|
+
when "WARN"
|
50
|
+
colour("#{progname} => [#{severity}] #{message}\n", :yellow)
|
51
|
+
when "ACTION"
|
52
|
+
colour("#{progname} => [#{severity}] #{message}\n", :magenta)
|
53
|
+
when "SUCCESS"
|
54
|
+
colour("#{progname} => [#{severity}] #{message}\n", :green)
|
55
|
+
when "ERROR", "FATAL"
|
56
|
+
colour("#{progname} => [#{severity}] #{message}\n", :red)
|
57
|
+
else
|
58
|
+
"#{progname} => [#{severity}] #{message}\n"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def colour(msg, clr = :black)
|
65
|
+
"\e[#{COLOURS[clr]}m#{msg}\e[0m"
|
66
|
+
end
|
67
|
+
|
68
|
+
def underline
|
69
|
+
"\e[4m"
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def self.logger
|
76
|
+
@logger ||= begin
|
77
|
+
logger = Logger.new($stdout)
|
78
|
+
logger.level = ::Logger::DEBUG
|
79
|
+
logger.progname = 'Trooper'
|
80
|
+
logger.formatter = LogFormat.new
|
81
|
+
logger
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "net/ssh"
|
4
|
+
|
5
|
+
module Trooper
|
6
|
+
class Runner
|
7
|
+
|
8
|
+
attr_reader :host, :user, :connection
|
9
|
+
|
10
|
+
# pass the host, user and any net/ssh config options
|
11
|
+
# Runner.new('my.example.com', 'admin', :forward_agent => false)
|
12
|
+
def initialize(host, user, options = { :forward_agent => true })
|
13
|
+
@host = host
|
14
|
+
@user = user
|
15
|
+
@connection = Net::SSH.start(host, user, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# returns user@host as a string
|
19
|
+
def to_s
|
20
|
+
"#{user}@#{host}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# execute a set of commands via net/ssh, returns and array or raises an exception
|
24
|
+
# runner.execute(['cd to/path', 'touch file']) # => ['cd to/path && touch file', :stdout, '']
|
25
|
+
# runner.execute('cat file') # => ['cat file', :stdout, 'file content']
|
26
|
+
def execute(command, options = {})
|
27
|
+
commands = parse command
|
28
|
+
Trooper.logger.debug commands
|
29
|
+
connection.exec! commands do |ch, stream, data|
|
30
|
+
raise Trooper::StdError, "#{data}\n[ERROR INFO] #{commands}" if stream == :stderr
|
31
|
+
ch.wait
|
32
|
+
return [commands, stream, data]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# close net/ssh connection
|
37
|
+
def close
|
38
|
+
connection.close
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# parse command, expects a string or array
|
44
|
+
# parse(['cd to/path', 'touch file']) # => 'cd to/path && touch file'
|
45
|
+
def parse(command)
|
46
|
+
case command.class.name.downcase.to_sym #Array => :array
|
47
|
+
when :array
|
48
|
+
command.compact.join(' && ')
|
49
|
+
when :string
|
50
|
+
command.chomp
|
51
|
+
else
|
52
|
+
raise Trooper::MalformedCommandError, "Command Not a String or Array: #{command.inspect}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'trooper/runner'
|
2
|
+
|
3
|
+
module Trooper
|
4
|
+
class Strategy
|
5
|
+
|
6
|
+
attr_reader :name, :description, :config, :run_list
|
7
|
+
|
8
|
+
def initialize(name, description, config = {}, &block)
|
9
|
+
@name, @description, @config = name, description, config
|
10
|
+
@run_list = []
|
11
|
+
eval_block(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(config = {})
|
15
|
+
@config = config
|
16
|
+
Trooper.logger.debug "Configuration\n#{config}"
|
17
|
+
successful = nil
|
18
|
+
|
19
|
+
runners.each do |runner|
|
20
|
+
begin
|
21
|
+
Trooper.logger.info "\e[4mRunning on #{runner}\n"
|
22
|
+
|
23
|
+
run_list.each do |item, name|
|
24
|
+
self.send("#{item}_execute", runner, name)
|
25
|
+
end
|
26
|
+
|
27
|
+
successful = true
|
28
|
+
Trooper.logger.success "\e[4mAll Actions Completed\n"
|
29
|
+
rescue Exception => e
|
30
|
+
Trooper.logger.error "#{e.class.to_s} : #{e.message}\n\n#{e.backtrace.join("\n")}"
|
31
|
+
|
32
|
+
successful = false
|
33
|
+
break #stop commands running on other servers
|
34
|
+
ensure
|
35
|
+
runner.close
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
successful
|
40
|
+
end
|
41
|
+
|
42
|
+
def ok?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def call(strategy_name)
|
47
|
+
if Arsenal.strategies[strategy_name]
|
48
|
+
Arsenal.strategies[strategy_name].run_list.each do |action|
|
49
|
+
@run_list << action
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def actions(*action_names)
|
55
|
+
[*action_names].each do |name|
|
56
|
+
@run_list << [:action, name]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def method_missing(method_sym, *arguments, &block)
|
61
|
+
config[method_sym] || super
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def eval_block(&block)
|
67
|
+
if block_given?
|
68
|
+
if block.arity == 1
|
69
|
+
block.call self
|
70
|
+
else
|
71
|
+
instance_eval &block
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def action_execute(runner, name)
|
77
|
+
action = Arsenal.actions[name]
|
78
|
+
|
79
|
+
if action
|
80
|
+
commands = action.execute config
|
81
|
+
Trooper.logger.action action.description
|
82
|
+
runner_execute!(runner, commands)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def runners
|
87
|
+
@runners ||= begin
|
88
|
+
r, h, u = [], (hosts rescue nil), (user rescue nil)
|
89
|
+
h.each {|host| r << Runner.new(host, user) } if h && u; r
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def runner_execute!(runner, commands, options = {})
|
94
|
+
result = runner.execute commands, options
|
95
|
+
if result && result[1] == :stdout
|
96
|
+
Trooper.logger.info "#{result[2]}\n"
|
97
|
+
true
|
98
|
+
else
|
99
|
+
false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
user 'my_user'
|
2
|
+
hosts 'stage.example.com'
|
3
|
+
repository 'git@git.bar.co.uk:whatever.git'
|
4
|
+
path "/path/to/data/folder"
|
5
|
+
|
6
|
+
set :my_value => 'something'
|
7
|
+
|
8
|
+
env :production do
|
9
|
+
hosts 'production1.example.com', 'production2.example.com'
|
10
|
+
set :my_value => 'something_else'
|
11
|
+
|
12
|
+
action :restart do
|
13
|
+
run 'touch tmp/restert.txt'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
action :restart do
|
18
|
+
run 'touch tmp/restert.txt'
|
19
|
+
end
|
20
|
+
|
21
|
+
strategy :update, 'Update the code base on the server' do
|
22
|
+
actions :update_repository, :install_gems
|
23
|
+
call :restart
|
24
|
+
end
|
25
|
+
|
26
|
+
strategy :deploy, 'Full deployment to the server' do
|
27
|
+
call :update
|
28
|
+
actions :migrate_database
|
29
|
+
call :restart
|
30
|
+
end
|
31
|
+
|
32
|
+
strategy :restart, 'Restart application' do
|
33
|
+
actions :restart
|
34
|
+
end
|
data/lib/trooper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'trooper/version'
|
2
|
+
require 'trooper/logger'
|
3
|
+
|
4
|
+
module Trooper
|
5
|
+
|
6
|
+
# Base class for all Trooper exceptions
|
7
|
+
class TrooperError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
# When a strategy is not defined
|
11
|
+
class MissingStrategyError < TrooperError
|
12
|
+
end
|
13
|
+
|
14
|
+
# When a CLI argument is missing or badly formed
|
15
|
+
class CliArgumentError < TrooperError
|
16
|
+
end
|
17
|
+
|
18
|
+
# When a command(s) return a stderr stream
|
19
|
+
class StdError < TrooperError
|
20
|
+
end
|
21
|
+
|
22
|
+
# When a command is not formed corrently arrays or strings are exceptal commands
|
23
|
+
class MalformedCommandError < TrooperError
|
24
|
+
end
|
25
|
+
|
26
|
+
class NoConfigurationFileError < TrooperError
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trooper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0.alpha1
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Richard Adams
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: net-ssh
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.3.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.3.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.8'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.8'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard-rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.6'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.6'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rb-fsevent
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: yard
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0.7'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.7'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: pry
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.9'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0.9'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: sdoc
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.3.16
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.3.16
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: simplecov
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.5.4
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 0.5.4
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: rake
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 0.9.2
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 0.9.2
|
158
|
+
description: Simple but powerful deployment
|
159
|
+
email:
|
160
|
+
- richard@madwire.co.uk
|
161
|
+
executables: []
|
162
|
+
extensions: []
|
163
|
+
extra_rdoc_files: []
|
164
|
+
files:
|
165
|
+
- bin/trooper
|
166
|
+
- lib/trooper/action.rb
|
167
|
+
- lib/trooper/actions/clone_repository_action.rb
|
168
|
+
- lib/trooper/actions/install_gems_action.rb
|
169
|
+
- lib/trooper/actions/migrate_database_action.rb
|
170
|
+
- lib/trooper/actions/restart_server_action.rb
|
171
|
+
- lib/trooper/actions/rollback_migrate_action.rb
|
172
|
+
- lib/trooper/actions/setup_database_action.rb
|
173
|
+
- lib/trooper/actions/update_repository_action.rb
|
174
|
+
- lib/trooper/arsenal.rb
|
175
|
+
- lib/trooper/cli.rb
|
176
|
+
- lib/trooper/config/action.rb
|
177
|
+
- lib/trooper/config/environment.rb
|
178
|
+
- lib/trooper/config/strategy.rb
|
179
|
+
- lib/trooper/configuration.rb
|
180
|
+
- lib/trooper/dsl/bundler.rb
|
181
|
+
- lib/trooper/dsl/folders.rb
|
182
|
+
- lib/trooper/dsl/rake.rb
|
183
|
+
- lib/trooper/logger.rb
|
184
|
+
- lib/trooper/runner.rb
|
185
|
+
- lib/trooper/strategy.rb
|
186
|
+
- lib/trooper/template/troopfile.rb
|
187
|
+
- lib/trooper/version.rb
|
188
|
+
- lib/trooper.rb
|
189
|
+
- LICENSE
|
190
|
+
- Rakefile
|
191
|
+
- README.md
|
192
|
+
homepage: http://www.madwire.co.uk
|
193
|
+
licenses: []
|
194
|
+
post_install_message:
|
195
|
+
rdoc_options: []
|
196
|
+
require_paths:
|
197
|
+
- lib
|
198
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
199
|
+
none: false
|
200
|
+
requirements:
|
201
|
+
- - ! '>='
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
segments:
|
205
|
+
- 0
|
206
|
+
hash: 3543094362386461389
|
207
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
|
+
none: false
|
209
|
+
requirements:
|
210
|
+
- - ! '>'
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: 1.3.1
|
213
|
+
requirements: []
|
214
|
+
rubyforge_project:
|
215
|
+
rubygems_version: 1.8.22
|
216
|
+
signing_key:
|
217
|
+
specification_version: 3
|
218
|
+
summary: Deploy like a 'Trooper'
|
219
|
+
test_files: []
|
220
|
+
has_rdoc:
|