rubble 0.0.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 +15 -0
- data/LICENSE.txt +674 -0
- data/README.md +29 -0
- data/bin/rubble +5 -0
- data/demo/applique/qed_test.rb +82 -0
- data/demo/applique/rubble_test.rb +33 -0
- data/demo/environment.md +32 -0
- data/demo/file_set.md +65 -0
- data/demo/logging.md +11 -0
- data/demo/server.md +53 -0
- data/demo/snapshot.md +32 -0
- data/demo/tool.md +36 -0
- data/lib/rubble.rb +15 -0
- data/lib/rubble/application.rb +82 -0
- data/lib/rubble/command/activate.rb +13 -0
- data/lib/rubble/command/base.rb +57 -0
- data/lib/rubble/command/upload.rb +28 -0
- data/lib/rubble/context.rb +33 -0
- data/lib/rubble/dsl.rb +31 -0
- data/lib/rubble/environment.rb +38 -0
- data/lib/rubble/executor/base.rb +134 -0
- data/lib/rubble/executor/local.rb +113 -0
- data/lib/rubble/executor/remote.rb +81 -0
- data/lib/rubble/file_set.rb +41 -0
- data/lib/rubble/logging.rb +23 -0
- data/lib/rubble/plan/base.rb +21 -0
- data/lib/rubble/plan/deploy.rb +11 -0
- data/lib/rubble/resource/base.rb +43 -0
- data/lib/rubble/resource/database.rb +8 -0
- data/lib/rubble/resource/fileset.rb +93 -0
- data/lib/rubble/resource/webapp.rb +22 -0
- data/lib/rubble/scope.rb +44 -0
- data/lib/rubble/server.rb +61 -0
- data/lib/rubble/snapshot.rb +21 -0
- data/lib/rubble/target/base.rb +24 -0
- data/lib/rubble/target/directory.rb +11 -0
- data/lib/rubble/target/mysql.rb +8 -0
- data/lib/rubble/target/tomcat.rb +20 -0
- data/lib/rubble/tool.rb +138 -0
- data/lib/rubble/version.rb +3 -0
- metadata +244 -0
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Rubble
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'rubble'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install rubble
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( https://github.com/[my-github-username]/deploy_tool/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create a new Pull Request
|
data/bin/rubble
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'ae'
|
2
|
+
|
3
|
+
# Add bin directory to path
|
4
|
+
ENV['PATH'] = File.join(QED::Utils.root, 'bin') + ":" + ENV['PATH']
|
5
|
+
|
6
|
+
# Redirect stdout and return output
|
7
|
+
#
|
8
|
+
# @yield Execute block with redirected stdout
|
9
|
+
# @return [String] Output
|
10
|
+
def redirect
|
11
|
+
begin
|
12
|
+
old_stdout = $stdout
|
13
|
+
old_stderr = $stderr
|
14
|
+
$stdout = StringIO.new('', 'w')
|
15
|
+
$stderr = $stdout
|
16
|
+
yield
|
17
|
+
$stdout.string
|
18
|
+
ensure
|
19
|
+
$stdout = old_stdout
|
20
|
+
$stderr = old_stderr
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Execute a registered command
|
25
|
+
#
|
26
|
+
# @param command [String] Command string
|
27
|
+
# @return [String] Command output
|
28
|
+
def execute_command(command)
|
29
|
+
if command.nil? then
|
30
|
+
raise(ArgumentError, 'Please supply a block with the command to run')
|
31
|
+
end
|
32
|
+
|
33
|
+
command.gsub!(/^#\s*/, '')
|
34
|
+
arguments = Shellwords.shellsplit(command)
|
35
|
+
method_name = "run_#{arguments[0]}_command".to_sym
|
36
|
+
method = method(method_name)
|
37
|
+
|
38
|
+
if method.nil? then
|
39
|
+
raise(ArgumentError, "Please define a method named #{method_name} to test running the #{command[0]} command.")
|
40
|
+
end
|
41
|
+
|
42
|
+
@output = redirect do
|
43
|
+
method.call(arguments[1..-1])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Remove empty lines and leading and trailing spaces from text
|
48
|
+
#
|
49
|
+
# @param text [String] Text to clean
|
50
|
+
# @return [String] cleaned text
|
51
|
+
def clean(text)
|
52
|
+
raise(ArgumentError, 'Text must not be nil.') if text.nil?
|
53
|
+
|
54
|
+
text.gsub(/\n+/, "\n").gsub(/^\s+|\s+$/, '')
|
55
|
+
end
|
56
|
+
|
57
|
+
# Save the following block as script
|
58
|
+
When /\buse\b[^.]+\bscript in (?:file )?`([a-z]+\.[a-z]+)`/i do |file_name, text|
|
59
|
+
raise(ArgumentError, 'Please supply a block with a script.') if text.nil?
|
60
|
+
|
61
|
+
File.open(file_name, 'w') do |f|
|
62
|
+
f.write(text)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Expect the following block as text output
|
67
|
+
When /\bproduces\b[^.]+\btext output\b/i do |text|
|
68
|
+
raise(ArgumentError, 'Please supply a block with the text') if text.nil?
|
69
|
+
clean(@output).assert == clean(text)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Execute the command in the following block
|
73
|
+
When /\bexecute\b[^.]+\bcommand\b/i do |command|
|
74
|
+
execute_command(command)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Execute the command in the following block and expect it to fail
|
78
|
+
When /\bexecuting\b[^.]+\bfails\b/i do |command|
|
79
|
+
SystemExit.expect do
|
80
|
+
execute_command(command)
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubble/application'
|
2
|
+
|
3
|
+
include Rubble
|
4
|
+
|
5
|
+
def run_rubble_command(arguments)
|
6
|
+
Commander::Runner.instance_variable_set :"@singleton", Commander::Runner.new(arguments)
|
7
|
+
app = Rubble::Application.new
|
8
|
+
app.run
|
9
|
+
end
|
10
|
+
|
11
|
+
# Create a Tool object for testing
|
12
|
+
When /create a new test tool/i do |configuration|
|
13
|
+
raise(ArgumentError, 'Please supply a block with configuration.') if configuration.nil?
|
14
|
+
|
15
|
+
@tool = Tool.new
|
16
|
+
@tool.instance_eval(configuration)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create an Environment object for testing
|
20
|
+
When /create a new test environment/i do |configuration|
|
21
|
+
raise(ArgumentError, 'Please supply a block with configuration.') if configuration.nil?
|
22
|
+
|
23
|
+
@environment = Environment.new(Tool.new, 'test')
|
24
|
+
@environment.instance_eval(configuration)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a Server object for testing
|
28
|
+
When /create a new test server/i do |configuration|
|
29
|
+
raise(ArgumentError, 'Please supply a block with configuration.') if configuration.nil?
|
30
|
+
|
31
|
+
@server = Server.new(Tool.new, 'test')
|
32
|
+
@server.instance_eval(configuration)
|
33
|
+
end
|
data/demo/environment.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Environment
|
2
|
+
|
3
|
+
## Configure plans
|
4
|
+
|
5
|
+
An environment allows the configuration of plans.
|
6
|
+
|
7
|
+
Create a new test environment and configure it as follows:
|
8
|
+
|
9
|
+
server 'test' do
|
10
|
+
deploy fileset('test') => directory('test')
|
11
|
+
end
|
12
|
+
|
13
|
+
Now check the configuration.
|
14
|
+
|
15
|
+
@environment.plans.size.assert == 1
|
16
|
+
@environment.plans[0].assert.is_a? Plan::Deploy
|
17
|
+
|
18
|
+
## Configure plans for multiple servers at once
|
19
|
+
|
20
|
+
An environment allows the configuration of multiple servers.
|
21
|
+
|
22
|
+
Create a new test environment and configure it as follows:
|
23
|
+
|
24
|
+
server 'test1', 'test2' do
|
25
|
+
deploy fileset('test') => directory('test')
|
26
|
+
end
|
27
|
+
|
28
|
+
Now check the configuration.
|
29
|
+
|
30
|
+
@environment.plans.size.assert == 2
|
31
|
+
@environment.plans[0].assert.is_a? Plan::Deploy
|
32
|
+
@environment.plans[1].assert.is_a? Plan::Deploy
|
data/demo/file_set.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# File Set
|
2
|
+
|
3
|
+
## Converts paths to Pathname
|
4
|
+
|
5
|
+
A file set converts the base directory to a pathname.
|
6
|
+
|
7
|
+
fileset = FileSet.new('/tmp')
|
8
|
+
fileset.dir.assert.is_a? Pathname
|
9
|
+
|
10
|
+
A file set converts the files to pathnames.
|
11
|
+
|
12
|
+
fileset = FileSet.new('/tmp', 'test.txt')
|
13
|
+
fileset.files[0].assert.is_a? Pathname
|
14
|
+
|
15
|
+
## Reports when it is empty
|
16
|
+
|
17
|
+
A file set reports when it is empty
|
18
|
+
|
19
|
+
fileset = FileSet.new('/tmp')
|
20
|
+
fileset.assert.empty?
|
21
|
+
|
22
|
+
A file set reports when it is not empty
|
23
|
+
|
24
|
+
fileset = FileSet.new('/tmp', 'test.txt')
|
25
|
+
fileset.assert.not.empty?
|
26
|
+
|
27
|
+
## Readonly
|
28
|
+
|
29
|
+
A file set freezes its files
|
30
|
+
|
31
|
+
fileset = FileSet.new('/tmp')
|
32
|
+
RuntimeError.assert.raised? do
|
33
|
+
fileset.files << 'test.txt'
|
34
|
+
end
|
35
|
+
|
36
|
+
## Sorts content
|
37
|
+
|
38
|
+
A file set sorts the contained files
|
39
|
+
|
40
|
+
fileset = FileSet.new('/tmp', 'b.txt', 'a.txt')
|
41
|
+
fileset.files.assert == [Pathname('a.txt'), Pathname('b.txt')]
|
42
|
+
|
43
|
+
## Ensures files are relative
|
44
|
+
|
45
|
+
A file set ensures all files are in the base directory
|
46
|
+
|
47
|
+
FileSet.new('/tmp', 'test.txt').assert != nil
|
48
|
+
FileSet.new('/tmp', '../tmp/test.txt').assert != nil
|
49
|
+
|
50
|
+
ArgumentError.assert.raised? do
|
51
|
+
FileSet.new('/tmp', '.')
|
52
|
+
end
|
53
|
+
|
54
|
+
ArgumentError.assert.raised? do
|
55
|
+
FileSet.new('/tmp', '../usr/test.txt')
|
56
|
+
end
|
57
|
+
|
58
|
+
ArgumentError.assert.raised? do
|
59
|
+
FileSet.new('/tmp', '/test.txt')
|
60
|
+
end
|
61
|
+
|
62
|
+
A file set can return the full paths of the files
|
63
|
+
|
64
|
+
fileset = FileSet.new('/tmp', 'test.txt')
|
65
|
+
fileset.paths.first.assert == Pathname('/tmp/test.txt')
|
data/demo/logging.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Logging
|
2
|
+
|
3
|
+
## Set the MDC
|
4
|
+
|
5
|
+
The context method allows code to be executed with specific values in the MDC.
|
6
|
+
|
7
|
+
Logging.mdc['test'].assert == nil
|
8
|
+
Logging.context(:test => 'test') do
|
9
|
+
Logging.mdc['test'].assert == 'test'
|
10
|
+
end
|
11
|
+
Logging.mdc['test'].assert == nil
|
data/demo/server.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Server
|
2
|
+
|
3
|
+
## Configure the Rubble directory
|
4
|
+
|
5
|
+
Create a new test server and configure it as follows:
|
6
|
+
|
7
|
+
rubble_dir '/var/test'
|
8
|
+
|
9
|
+
Now check the configuration.
|
10
|
+
|
11
|
+
@server.rubble_dir.assert == '/var/test'
|
12
|
+
|
13
|
+
## Configure the deploy directory
|
14
|
+
|
15
|
+
Create a new test server and configure it as follows:
|
16
|
+
|
17
|
+
deploy_dir '/var/test'
|
18
|
+
|
19
|
+
Now check the configuration.
|
20
|
+
|
21
|
+
@server.deploy_dir.assert == '/var/test'
|
22
|
+
|
23
|
+
## Configure the user
|
24
|
+
|
25
|
+
Create a new test server and configure it as follows:
|
26
|
+
|
27
|
+
user 'test'
|
28
|
+
|
29
|
+
Now check the configuration.
|
30
|
+
|
31
|
+
@server.user.assert == 'test'
|
32
|
+
|
33
|
+
## Configure the group
|
34
|
+
|
35
|
+
Create a new test server and configure it as follows:
|
36
|
+
|
37
|
+
group 'test'
|
38
|
+
|
39
|
+
Now check the configuration.
|
40
|
+
|
41
|
+
@server.group.assert == 'test'
|
42
|
+
|
43
|
+
## Configure the targets
|
44
|
+
|
45
|
+
Create a new test server and configure it as follows:
|
46
|
+
|
47
|
+
directory 'test'
|
48
|
+
|
49
|
+
Now check the configuration.
|
50
|
+
|
51
|
+
@server.targets.size.assert == 1
|
52
|
+
@server.targets[:directory].size.assert == 1
|
53
|
+
@server.targets[:directory]['test'].assert.is_a? Target::Directory
|
data/demo/snapshot.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
## Reports when it is empty
|
2
|
+
|
3
|
+
A snapshot reports when it is empty because it does not contain any file sets.
|
4
|
+
|
5
|
+
snapshot = Snapshot.new('1')
|
6
|
+
snapshot.assert.empty?
|
7
|
+
|
8
|
+
A snapshot reports when it is empty because all its file sets are empty.
|
9
|
+
|
10
|
+
snapshot = Snapshot.new('1', FileSet.new('/tmp'))
|
11
|
+
snapshot.assert.empty?
|
12
|
+
|
13
|
+
A snapshot reports when it is not empty.
|
14
|
+
|
15
|
+
snapshot = Snapshot.new('1', FileSet.new('/tmp', 'a.txt'))
|
16
|
+
snapshot.assert.not.empty?
|
17
|
+
|
18
|
+
## Read only
|
19
|
+
|
20
|
+
A snapshot prevents modification of its version.
|
21
|
+
|
22
|
+
snapshot = Snapshot.new('1')
|
23
|
+
RuntimeError.assert.raised? do
|
24
|
+
snapshot.version << 'test'
|
25
|
+
end
|
26
|
+
|
27
|
+
A snapshot prevents modification of its filesets.
|
28
|
+
|
29
|
+
snapshot = Snapshot.new('1')
|
30
|
+
RuntimeError.assert.raised? do
|
31
|
+
snapshot.filesets << FileSet.new('/tmp')
|
32
|
+
end
|
data/demo/tool.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Tool
|
2
|
+
|
3
|
+
## Configures the resources
|
4
|
+
|
5
|
+
A tool allows the configuration of resources.
|
6
|
+
|
7
|
+
Create a new test tool and configure it as follows:
|
8
|
+
|
9
|
+
fileset 'test'
|
10
|
+
|
11
|
+
Now check the configuration.
|
12
|
+
|
13
|
+
@tool.resources.size.assert == 1
|
14
|
+
@tool.resources[:fileset]['test'].assert.is_a? Resource::Fileset
|
15
|
+
|
16
|
+
## Configures the servers
|
17
|
+
|
18
|
+
Create a new test tool and configure it as follows:
|
19
|
+
|
20
|
+
server 'test'
|
21
|
+
|
22
|
+
Now check the configuration.
|
23
|
+
|
24
|
+
@tool.servers.size.assert == 1
|
25
|
+
@tool.servers['test'].assert.is_a? Server
|
26
|
+
|
27
|
+
## Configures the environments
|
28
|
+
|
29
|
+
Create a new test tool and configure it as follows:
|
30
|
+
|
31
|
+
environment 'test'
|
32
|
+
|
33
|
+
Now check the configuration.
|
34
|
+
|
35
|
+
@tool.environments.size.assert == 1
|
36
|
+
@tool.environments['test'].assert.is_a? Environment
|
data/lib/rubble.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubble/version'
|
2
|
+
require 'rubble/tool'
|
3
|
+
require 'rubble/file_set'
|
4
|
+
require 'rubble/resource/database'
|
5
|
+
require 'rubble/resource/webapp'
|
6
|
+
require 'rubble/resource/fileset'
|
7
|
+
require 'rubble/target/tomcat'
|
8
|
+
require 'rubble/target/mysql'
|
9
|
+
require 'rubble/target/directory'
|
10
|
+
require 'rubble/plan/deploy'
|
11
|
+
require 'rubble/command/upload'
|
12
|
+
require 'rubble/command/activate'
|
13
|
+
|
14
|
+
module Rubble
|
15
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'commander'
|
3
|
+
require 'rubble'
|
4
|
+
require 'yaml'
|
5
|
+
require 'logging'
|
6
|
+
|
7
|
+
module Rubble
|
8
|
+
# Rubble application class
|
9
|
+
class Application
|
10
|
+
include Commander::Methods
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@config_file = 'config/deploy.rubble'
|
14
|
+
end
|
15
|
+
|
16
|
+
def tool
|
17
|
+
if @tool.nil? then
|
18
|
+
@tool = Rubble::Tool.new
|
19
|
+
@tool.read_config(@config_file)
|
20
|
+
end
|
21
|
+
|
22
|
+
@tool
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
program :name, 'Rubble'
|
27
|
+
program :version, Rubble::VERSION
|
28
|
+
program :description, 'Rubble Deployment Tool'
|
29
|
+
|
30
|
+
Logging.color_scheme('bright',
|
31
|
+
:lines => {
|
32
|
+
:debug => :blue,
|
33
|
+
:warn => :yellow,
|
34
|
+
:error => :orange,
|
35
|
+
:fatal => :red
|
36
|
+
},
|
37
|
+
)
|
38
|
+
|
39
|
+
Logging.logger.root.level = :info
|
40
|
+
Logging.logger.root.appenders = Logging.appenders.stdout(
|
41
|
+
'stdout',
|
42
|
+
:layout => Logging.layouts.pattern(
|
43
|
+
:pattern => '==> %m %X{server}\n',
|
44
|
+
:color_scheme => 'bright'
|
45
|
+
)
|
46
|
+
)
|
47
|
+
|
48
|
+
log = Logging.logger[self]
|
49
|
+
|
50
|
+
global_option('-l', '--loglevel STRING', 'Log level') do |level|
|
51
|
+
Logging.logger.root.level = level.to_sym
|
52
|
+
end
|
53
|
+
|
54
|
+
global_option('-f', '--file FILE', 'Configuration file') do |file|
|
55
|
+
@config_file = file
|
56
|
+
@tool = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
command :upload do |c|
|
60
|
+
c.description = 'Upload a release'
|
61
|
+
c.action do |args, options|
|
62
|
+
tool.execute(args) do |plan, context|
|
63
|
+
command = Rubble::Command::Upload.new(plan, context)
|
64
|
+
command.execute
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
command :activate do |c|
|
70
|
+
c.description = 'Activate a release'
|
71
|
+
c.action do |args, options|
|
72
|
+
tool.execute(args) do |plan, context|
|
73
|
+
command = Rubble::Command::Activate.new(plan, context)
|
74
|
+
command.execute
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
run!
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|