automate 0.1.0
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.
- 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: []
|