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.
@@ -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
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubble/application'
3
+
4
+ # Run application
5
+ Rubble::Application.new.run
@@ -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
@@ -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
@@ -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')
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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