automate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +48 -0
- data/LICENSE.txt +20 -0
- data/README.md +70 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/examples/git-copy-repo.rb +63 -0
- data/examples/simple.rb +27 -0
- data/lib/automate.rb +6 -0
- data/lib/automate/chain.rb +87 -0
- data/lib/automate/chain_link.rb +105 -0
- data/lib/automate/errors.rb +21 -0
- data/lib/automate/messenger.rb +28 -0
- data/test/helper.rb +40 -0
- data/test/test_automate.rb +115 -0
- metadata +212 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
group :development do
|
4
|
+
gem "minitest", ">= 0"
|
5
|
+
gem "yard", "~> 0.8.5"
|
6
|
+
gem "redcarpet" # For YARD Markdown formatting
|
7
|
+
gem "bundler", "~> 1.2.3"
|
8
|
+
gem "jeweler", "~> 1.8.4"
|
9
|
+
gem "simplecov", ">= 0"
|
10
|
+
gem "minitest-reporters"
|
11
|
+
gem "psych"
|
12
|
+
end
|
13
|
+
|
14
|
+
gem "rainbow"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
ansi (1.4.3)
|
5
|
+
builder (3.2.0)
|
6
|
+
git (1.2.5)
|
7
|
+
hashie (2.0.0)
|
8
|
+
jeweler (1.8.4)
|
9
|
+
bundler (~> 1.0)
|
10
|
+
git (>= 1.2.5)
|
11
|
+
rake
|
12
|
+
rdoc
|
13
|
+
json (1.7.7)
|
14
|
+
minitest (4.6.1)
|
15
|
+
minitest-reporters (0.14.7)
|
16
|
+
ansi
|
17
|
+
builder
|
18
|
+
minitest (>= 2.12, < 5.0)
|
19
|
+
powerbar
|
20
|
+
multi_json (1.6.1)
|
21
|
+
powerbar (1.0.11)
|
22
|
+
ansi (~> 1.4.0)
|
23
|
+
hashie (>= 1.1.0)
|
24
|
+
psych (1.3.4)
|
25
|
+
rainbow (1.1.4)
|
26
|
+
rake (10.0.3)
|
27
|
+
rdoc (4.0.0)
|
28
|
+
json (~> 1.4)
|
29
|
+
redcarpet (2.2.2)
|
30
|
+
simplecov (0.7.1)
|
31
|
+
multi_json (~> 1.0)
|
32
|
+
simplecov-html (~> 0.7.1)
|
33
|
+
simplecov-html (0.7.1)
|
34
|
+
yard (0.8.5)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
bundler (~> 1.2.3)
|
41
|
+
jeweler (~> 1.8.4)
|
42
|
+
minitest
|
43
|
+
minitest-reporters
|
44
|
+
psych
|
45
|
+
rainbow
|
46
|
+
redcarpet
|
47
|
+
simplecov
|
48
|
+
yard (~> 0.8.5)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Lucas Jenß
|
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,70 @@
|
|
1
|
+
# automate
|
2
|
+
|
3
|
+
Automate is a Gem which intends to make writing shell-level automations easier by providing functionality such as:
|
4
|
+
|
5
|
+
1. Shell command error handling
|
6
|
+
1. Displaying all executed shell commands
|
7
|
+
1. Nicely formatted output
|
8
|
+
1. Makes it easy to write self-documenting, re-usable automations
|
9
|
+
|
10
|
+
These functionalities will improve as "automate" is being used, so if you see something missing or broken, just open an issue or a pull request.
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
## Example
|
15
|
+
|
16
|
+
Here's a very short example which creates a file and writes a random number into it (also to be found in `examples/simple.rb`):
|
17
|
+
|
18
|
+
c = Automate::Chain.which("Serves as an example") do
|
19
|
+
|
20
|
+
go "Create a file in the working directory" do
|
21
|
+
demand :filename
|
22
|
+
run "touch #{_filename}"
|
23
|
+
end
|
24
|
+
|
25
|
+
go "Write a random number into the file" do
|
26
|
+
pass :number, Random.rand(100)
|
27
|
+
run "echo #{_number} > #{_filename}"
|
28
|
+
end
|
29
|
+
|
30
|
+
go "Demonstrate a failed chain link" do
|
31
|
+
run "this_command_doesnt_even_exist #{_number}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
## Usage
|
39
|
+
|
40
|
+
To begin with, `Automate::Chain.which("Description of command chain") creates a new command chain, which is defined by the block passed to it.
|
41
|
+
|
42
|
+
Inside said block, "chain links" are defined using the `go` method. Each chain link should consist of an action which can be described in a few words, thus making the entire chain a series of atomic, or close to atomic operations:
|
43
|
+
|
44
|
+
# good
|
45
|
+
go "Clone the git repository"
|
46
|
+
|
47
|
+
# bad
|
48
|
+
go "Download, compile and install the linux kernel"
|
49
|
+
|
50
|
+
The chain link block defines its behavior, and the following methods are available within:
|
51
|
+
|
52
|
+
* `demand :parameter1, :parameter2` - Demand one or more parameters from the previous chain link (or if there is none, from the initial run command).
|
53
|
+
|
54
|
+
* `pass :parameter, value` - Pass a parameter to the next chain link.
|
55
|
+
|
56
|
+
* `run "some shell command"` - Invokes a shell command, returning its result (including everything written to stderr! If you don't want to capture stderr, pass "false" as `run's` second parameter)
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
## Future features
|
62
|
+
|
63
|
+
* Stepping through the script, i.e. execute link by link (especially useful for debugging)
|
64
|
+
* Add roll back actions for a link, which are only executed if said link fails.
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
## Boring legal stuff
|
69
|
+
|
70
|
+
See LICENSE.txt
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "automate"
|
18
|
+
gem.homepage = "http://github.com/x3ro/automate"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Automate helps you automating all your favorite shell tasks}
|
21
|
+
gem.description = %Q{The automate Gem provides a very simple DSL for writing command line automations, providing nice-to-have features such as error handling so that you don't have to implement it over and over again :)}
|
22
|
+
gem.email = "public@x3ro.de"
|
23
|
+
gem.authors = ["Lucas Jenß"]
|
24
|
+
end
|
25
|
+
Jeweler::RubygemsDotOrgTasks.new
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
Rake::TestTask.new(:test) do |test|
|
29
|
+
test.libs << 'lib' << 'test'
|
30
|
+
test.pattern = 'test/**/test_*.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :default => :test
|
35
|
+
|
36
|
+
require 'yard'
|
37
|
+
YARD::Rake::YardocTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'automate'
|
7
|
+
|
8
|
+
c = Automate::Chain.which("copies a git repository") do
|
9
|
+
|
10
|
+
go "Clone git repository" do
|
11
|
+
demand :source, :tmpdir
|
12
|
+
run "git clone #{_source} #{_tmpdir}"
|
13
|
+
end
|
14
|
+
|
15
|
+
go "Chdir to temporary directory" do
|
16
|
+
demand :tmpdir
|
17
|
+
pass :old_dir, Dir.pwd
|
18
|
+
Dir.chdir _tmpdir
|
19
|
+
end
|
20
|
+
|
21
|
+
go "Find out which remote branches need to be checked out" do
|
22
|
+
branches = run "git branch -r"
|
23
|
+
branches = branches.split("\n")
|
24
|
+
.select { |x| !x.include? "->" }
|
25
|
+
.select { |x| !x.include? "/master" }
|
26
|
+
.select { |x| x.include? 'origin/' }
|
27
|
+
.map { |x| x.strip }
|
28
|
+
|
29
|
+
notice "Will check out these branches:", " #{branches.join(" ")}"
|
30
|
+
pass :branches, branches
|
31
|
+
end
|
32
|
+
|
33
|
+
go "Check out the remote branches" do
|
34
|
+
_branches.each do |branch|
|
35
|
+
run "git checkout --track #{branch}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
go "Add target remote to repository" do
|
40
|
+
demand :target
|
41
|
+
run "git remote add new #{_target}"
|
42
|
+
end
|
43
|
+
|
44
|
+
go "Push data to target repository" do
|
45
|
+
run "git push --all new"
|
46
|
+
end
|
47
|
+
|
48
|
+
go "Push tags to target repository" do
|
49
|
+
run "git push --tags new"
|
50
|
+
end
|
51
|
+
|
52
|
+
go "Delete temporary directory" do
|
53
|
+
demand :old_dir, :tmpdir
|
54
|
+
Dir.chdir _old_dir
|
55
|
+
run "rm -rf #{Dir.pwd}/#{_tmpdir}"
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
abort("Usage: git-copy-repo <source repo> <target repo>") if ARGV.length != 2
|
63
|
+
c.run({:source => ARGV[0], :target => ARGV[1], :tmpdir => "tmp/"})
|
data/examples/simple.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'automate'
|
7
|
+
|
8
|
+
c = Automate::Chain.which("Serves as an example") do
|
9
|
+
|
10
|
+
go "Create a file in the working directory" do
|
11
|
+
demand :filename
|
12
|
+
run "touch #{_filename}"
|
13
|
+
end
|
14
|
+
|
15
|
+
go "Write a random number into the file" do
|
16
|
+
pass :number, Random.rand(100)
|
17
|
+
run "echo #{_number} > #{_filename}"
|
18
|
+
end
|
19
|
+
|
20
|
+
go "Demonstrate a failed chain link" do
|
21
|
+
run "this_command_doesnt_even_exist #{_number}"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
abort "Usage: simple.rb <filename>" if ARGV.length != 1
|
27
|
+
c.run({:filename => ARGV[0]})
|
data/lib/automate.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
module Automate
|
2
|
+
|
3
|
+
# Captures the entire command chain to be executed. Thus, the main objective of this
|
4
|
+
# class is to capture and execute the `ChainLinks`. All the capturing happens in the
|
5
|
+
# `go` method, and the executing in the `run` method.
|
6
|
+
#
|
7
|
+
class Chain
|
8
|
+
include Messenger
|
9
|
+
|
10
|
+
# Factory method that creates a new command chain.
|
11
|
+
#
|
12
|
+
def self.which(task, &block)
|
13
|
+
c = new(task)
|
14
|
+
c.instance_exec(&block)
|
15
|
+
c
|
16
|
+
end
|
17
|
+
|
18
|
+
# Add a new link to the command chain
|
19
|
+
def go(desc, &block)
|
20
|
+
add_command(desc, block)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Run _all_ the command chain links. Will abort the command chain if any chain link
|
24
|
+
# should fail.
|
25
|
+
#
|
26
|
+
def run(args = {})
|
27
|
+
notice "About to run command chain which '#{@task}'"
|
28
|
+
|
29
|
+
@cmd_list.each_with_index do |cmd, index|
|
30
|
+
desc, proc = cmd
|
31
|
+
success "#{timestamp} // Running link ##{index+1} - #{desc}"
|
32
|
+
|
33
|
+
error = false
|
34
|
+
begin
|
35
|
+
ret, out = ChainLink.invoke(proc, args)
|
36
|
+
rescue ChainFailedError, ChainLinkFailedError => e
|
37
|
+
error = true
|
38
|
+
end
|
39
|
+
raise ChainFailedError.new(index + 1, desc) if ret == false || error == true
|
40
|
+
|
41
|
+
|
42
|
+
# Pass the arguments from the last iteration, overwriting everything that
|
43
|
+
# was passed from the current one.
|
44
|
+
args.merge! out
|
45
|
+
end
|
46
|
+
|
47
|
+
args
|
48
|
+
|
49
|
+
rescue ChainFailedError => e
|
50
|
+
fail("Chain link ##{e.chain} (#{e.description}) failed. Aborting.")
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Private constructor. Instance creation is only allowed through `#which`.
|
59
|
+
#
|
60
|
+
private_class_method :new
|
61
|
+
|
62
|
+
def initialize(task)
|
63
|
+
@task = task
|
64
|
+
@cmd_list = []
|
65
|
+
end
|
66
|
+
|
67
|
+
def timestamp
|
68
|
+
Time.now.strftime('%H:%M:%S.%L')
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_command(desc, cmd)
|
72
|
+
raise "Parameter must be a Proc/Lambda" if !cmd.is_a?(Proc)
|
73
|
+
@cmd_list.push [desc, cmd]
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
# ========================
|
79
|
+
# Messenger module related
|
80
|
+
# ========================
|
81
|
+
|
82
|
+
def prefix
|
83
|
+
"=> "
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Automate
|
2
|
+
|
3
|
+
# Represents a single link of a command chain, which takes a number
|
4
|
+
# of input parameters (`@in_args`), does some magic, returning a
|
5
|
+
# number of output arguments (`@out_args`).
|
6
|
+
#
|
7
|
+
# A chain link is created by the `Chain#go` method. The block passed to
|
8
|
+
# said method contains the logic which is later executed within this
|
9
|
+
# class (by #invoke).
|
10
|
+
#
|
11
|
+
class ChainLink
|
12
|
+
include Messenger
|
13
|
+
|
14
|
+
def self.invoke(proc, args)
|
15
|
+
new(args).invoke(proc)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Invokes the block passed to the `#go` method. Said block will be able to call the
|
19
|
+
# methods listed in the "Public API" section.
|
20
|
+
#
|
21
|
+
def invoke(proc)
|
22
|
+
ret = instance_exec(&proc)
|
23
|
+
[ret, @out_args]
|
24
|
+
|
25
|
+
rescue UnmetDemandError => e
|
26
|
+
fail "Required argument '#{e.demand}', but was not given."
|
27
|
+
raise ChainLinkFailedError.new
|
28
|
+
rescue CmdFailedError => e
|
29
|
+
fail e.message
|
30
|
+
raise ChainLinkFailedError.new
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
# ==========
|
36
|
+
# Public API
|
37
|
+
# ==========
|
38
|
+
|
39
|
+
# Runs a given shell command, aborting the command chain if there is an error.
|
40
|
+
#
|
41
|
+
def run(cmd, capture_stderr=true)
|
42
|
+
notice "Running: " + cmd.color(:white)
|
43
|
+
cmd += " 2>&1" if capture_stderr
|
44
|
+
|
45
|
+
out = ""
|
46
|
+
IO.popen(cmd) do |f|
|
47
|
+
while l = f.gets
|
48
|
+
out += l
|
49
|
+
msg " " + l
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
raise CmdFailedError.new("Command '#{cmd}' had exit status != 0.") if $? != 0
|
54
|
+
out
|
55
|
+
end
|
56
|
+
|
57
|
+
# Passes an argument onto the next link of the chain
|
58
|
+
def pass(key, value)
|
59
|
+
@out_args[key] = value
|
60
|
+
end
|
61
|
+
|
62
|
+
# Requires that an argument must be present before proceeding in the current
|
63
|
+
# chain
|
64
|
+
def demand(*keys)
|
65
|
+
keys.each do |key|
|
66
|
+
raise UnmetDemandError.new(key) if !@in_args.has_key? key
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Implement method_missing so that we can address passed variables using the
|
71
|
+
# `_variablename` shorthand within a chain link.
|
72
|
+
def method_missing(method, *args, &block)
|
73
|
+
if method.to_s =~ /^_(.+)$/
|
74
|
+
arg = @in_args[$1.to_sym] || @out_args[$1.to_sym]
|
75
|
+
return arg if !arg.nil?
|
76
|
+
end
|
77
|
+
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
# ========================
|
84
|
+
# Messenger module related
|
85
|
+
# ========================
|
86
|
+
|
87
|
+
def prefix
|
88
|
+
" => "
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Private constructor. Instance creation is only allowed through `#invoke`.
|
95
|
+
#
|
96
|
+
private_class_method :new
|
97
|
+
|
98
|
+
def initialize(args)
|
99
|
+
@in_args = args
|
100
|
+
@out_args = {}
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Automate
|
2
|
+
|
3
|
+
class ChainLinkFailedError < Exception; end
|
4
|
+
class CmdFailedError < Exception; end
|
5
|
+
|
6
|
+
class ChainFailedError < Exception
|
7
|
+
attr_reader :chain, :description
|
8
|
+
def initialize(chain, description)
|
9
|
+
@chain = chain
|
10
|
+
@description = description
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class UnmetDemandError < Exception;
|
15
|
+
attr_reader :demand
|
16
|
+
def initialize(demand)
|
17
|
+
@demand = demand
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Automate
|
2
|
+
|
3
|
+
module Messenger
|
4
|
+
def format(x)
|
5
|
+
"#{prefix}#{x}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def msg(x)
|
9
|
+
puts format(x)
|
10
|
+
end
|
11
|
+
|
12
|
+
def success(x, y="")
|
13
|
+
puts format(x).color(:green) + y
|
14
|
+
end
|
15
|
+
|
16
|
+
def notice(x, y="")
|
17
|
+
puts format(x).color(:yellow) + y
|
18
|
+
end
|
19
|
+
|
20
|
+
def fail(x, y="")
|
21
|
+
puts format(x).color(:red) + y
|
22
|
+
end
|
23
|
+
|
24
|
+
# Overwrite these in your importing class
|
25
|
+
def prefix; raise NotImplementedError; end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
require 'minitest/unit'
|
15
|
+
require "minitest/reporters"
|
16
|
+
MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new
|
17
|
+
|
18
|
+
|
19
|
+
require 'simplecov'
|
20
|
+
SimpleCov.start
|
21
|
+
|
22
|
+
|
23
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
24
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
25
|
+
require 'automate'
|
26
|
+
|
27
|
+
|
28
|
+
class MiniTest::Unit::TestCase
|
29
|
+
def setup
|
30
|
+
@original_stdout = $stdout
|
31
|
+
$stdout = StringIO.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def teardown
|
35
|
+
$stdout = @original_stdout
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
MiniTest::Unit.autorun
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestAutomate < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_single_element_chain
|
6
|
+
c = Automate::Chain.which("Has a single element") do
|
7
|
+
go "Set some variable" do
|
8
|
+
pass :foo, 42
|
9
|
+
end
|
10
|
+
end
|
11
|
+
assert_equal({:foo => 42}, c.run)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def test_multiple_element_chain
|
16
|
+
c = Automate::Chain.which("Has multiple elements") do
|
17
|
+
go "Link #1" do
|
18
|
+
pass :out, [1]
|
19
|
+
end
|
20
|
+
|
21
|
+
go "Link #2" do
|
22
|
+
_out.push(2)
|
23
|
+
pass :out, _out
|
24
|
+
end
|
25
|
+
|
26
|
+
go "Link #3" do
|
27
|
+
_out.push(3)
|
28
|
+
pass :out, _out
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
result = c.run({:in => 42})
|
33
|
+
assert_equal([1,2,3], result[:out])
|
34
|
+
assert_equal(42, result[:in])
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def test_command_error
|
39
|
+
c = Automate::Chain.which("Has an error") do
|
40
|
+
go "Fail" do
|
41
|
+
run "this_doesnt_even_exist___"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
assert_equal false, c.run
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def test_unmet_demand_error
|
50
|
+
c = Automate::Chain.which("Has an error") do
|
51
|
+
go "Fail" do
|
52
|
+
demand :not_given
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_equal false, c.run
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def test_met_demand
|
61
|
+
c = Automate::Chain.which("Met demand") do
|
62
|
+
go "Pass arg" do
|
63
|
+
demand :input
|
64
|
+
pass :output, _input + 1
|
65
|
+
end
|
66
|
+
|
67
|
+
go "Check args" do
|
68
|
+
demand :output
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
result = c.run({:input => 42})
|
73
|
+
assert_equal 42, result[:input]
|
74
|
+
assert_equal 43, result[:output]
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def test_method_missing_in_chain_link
|
79
|
+
assert_raises(NameError) do
|
80
|
+
c = Automate::Chain.which("checks method missing") do
|
81
|
+
go "Raise name error" do
|
82
|
+
wobblewobble
|
83
|
+
end
|
84
|
+
end
|
85
|
+
c.run
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def test_run_successful_command
|
91
|
+
c = Automate::Chain.which("Run shell command") do
|
92
|
+
go "run the command" do
|
93
|
+
demand :input
|
94
|
+
pass :output, run("echo -n #{_input}#{_input}", false)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
result = c.run({:input => 42})
|
99
|
+
assert_equal "4242", result[:output]
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def test_access_variables_just_passed
|
104
|
+
c = Automate::Chain.which("Run shell command") do
|
105
|
+
go "run the command" do
|
106
|
+
pass :output, 42
|
107
|
+
pass :output, (_output + 1)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
result = c.run
|
112
|
+
assert_equal 43, result[:output]
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
metadata
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: automate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Lucas Jenß
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rainbow
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '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: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: minitest
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
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: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: yard
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.8.5
|
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.8.5
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: redcarpet
|
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: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.2.3
|
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: 1.2.3
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: jeweler
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.8.4
|
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: 1.8.4
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: simplecov
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
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'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: minitest-reporters
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
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'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: psych
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
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'
|
158
|
+
description: The automate Gem provides a very simple DSL for writing command line
|
159
|
+
automations, providing nice-to-have features such as error handling so that you
|
160
|
+
don't have to implement it over and over again :)
|
161
|
+
email: public@x3ro.de
|
162
|
+
executables: []
|
163
|
+
extensions: []
|
164
|
+
extra_rdoc_files:
|
165
|
+
- LICENSE.txt
|
166
|
+
- README.md
|
167
|
+
files:
|
168
|
+
- .document
|
169
|
+
- Gemfile
|
170
|
+
- Gemfile.lock
|
171
|
+
- LICENSE.txt
|
172
|
+
- README.md
|
173
|
+
- Rakefile
|
174
|
+
- VERSION
|
175
|
+
- examples/git-copy-repo.rb
|
176
|
+
- examples/simple.rb
|
177
|
+
- lib/automate.rb
|
178
|
+
- lib/automate/chain.rb
|
179
|
+
- lib/automate/chain_link.rb
|
180
|
+
- lib/automate/errors.rb
|
181
|
+
- lib/automate/messenger.rb
|
182
|
+
- test/helper.rb
|
183
|
+
- test/test_automate.rb
|
184
|
+
homepage: http://github.com/x3ro/automate
|
185
|
+
licenses:
|
186
|
+
- MIT
|
187
|
+
post_install_message:
|
188
|
+
rdoc_options: []
|
189
|
+
require_paths:
|
190
|
+
- lib
|
191
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
192
|
+
none: false
|
193
|
+
requirements:
|
194
|
+
- - ! '>='
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '0'
|
197
|
+
segments:
|
198
|
+
- 0
|
199
|
+
hash: 3608312016429537767
|
200
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ! '>='
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
requirements: []
|
207
|
+
rubyforge_project:
|
208
|
+
rubygems_version: 1.8.24
|
209
|
+
signing_key:
|
210
|
+
specification_version: 3
|
211
|
+
summary: Automate helps you automating all your favorite shell tasks
|
212
|
+
test_files: []
|