rubble 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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