automate 0.1.0 → 0.2.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.
- checksums.yaml +7 -0
- data/Gemfile +5 -5
- data/Gemfile.lock +61 -29
- data/README.md +50 -27
- data/VERSION +1 -1
- data/automate.gemspec +81 -0
- data/examples/simple.rb +21 -1
- data/lib/automate/chain.rb +50 -8
- data/lib/automate/chain_link.rb +17 -6
- data/lib/automate/errors.rb +8 -1
- data/lib/automate/messenger.rb +2 -0
- data/test/helper.rb +6 -9
- data/test/test_automate.rb +105 -8
- metadata +35 -57
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e38bf3bffda93393bdb00339a81883bb36d87609
|
4
|
+
data.tar.gz: 53250b0b10806d1ba84a17953b3a905206e9b679
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a824fcb818a73a39bafd3dd59c3c2f7fedd1af800d925dcaf0a6d56301134f256775ce47e354e273d3a294d336438605f19493b5bc9749e285cfc3db7d81d1fb
|
7
|
+
data.tar.gz: 9650cbef76835f99b082aeab526273186cbae3768eee91a1ed4729da9065005330bc16ae9977950e65a82e52f8e7d0e8349cc370aab7275b31da41a930b836cc
|
data/Gemfile
CHANGED
@@ -2,13 +2,13 @@ source "http://rubygems.org"
|
|
2
2
|
|
3
3
|
group :development do
|
4
4
|
gem "minitest", ">= 0"
|
5
|
-
gem "yard"
|
5
|
+
gem "yard"
|
6
6
|
gem "redcarpet" # For YARD Markdown formatting
|
7
|
-
gem "bundler"
|
8
|
-
gem "jeweler"
|
9
|
-
gem "simplecov"
|
7
|
+
gem "bundler"
|
8
|
+
gem "jeweler"
|
9
|
+
gem "simplecov"
|
10
10
|
gem "minitest-reporters"
|
11
11
|
gem "psych"
|
12
12
|
end
|
13
13
|
|
14
|
-
gem "rainbow"
|
14
|
+
gem "rainbow", "~> 2.0.0"
|
data/Gemfile.lock
CHANGED
@@ -1,48 +1,80 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
addressable (2.3.8)
|
5
|
+
ansi (1.5.0)
|
6
|
+
builder (3.2.2)
|
7
|
+
descendants_tracker (0.0.4)
|
8
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
9
|
+
docile (1.1.5)
|
10
|
+
faraday (0.9.1)
|
11
|
+
multipart-post (>= 1.2, < 3)
|
12
|
+
git (1.2.9.1)
|
13
|
+
github_api (0.12.3)
|
14
|
+
addressable (~> 2.3)
|
15
|
+
descendants_tracker (~> 0.0.4)
|
16
|
+
faraday (~> 0.8, < 0.10)
|
17
|
+
hashie (>= 3.3)
|
18
|
+
multi_json (>= 1.7.5, < 2.0)
|
19
|
+
nokogiri (~> 1.6.3)
|
20
|
+
oauth2
|
21
|
+
hashie (3.4.1)
|
22
|
+
highline (1.7.2)
|
23
|
+
jeweler (2.0.1)
|
24
|
+
builder
|
25
|
+
bundler (>= 1.0)
|
10
26
|
git (>= 1.2.5)
|
27
|
+
github_api
|
28
|
+
highline (>= 1.6.15)
|
29
|
+
nokogiri (>= 1.5.10)
|
11
30
|
rake
|
12
31
|
rdoc
|
13
|
-
json (1.
|
14
|
-
|
15
|
-
|
32
|
+
json (1.8.2)
|
33
|
+
jwt (1.5.0)
|
34
|
+
mini_portile (0.6.2)
|
35
|
+
minitest (5.6.1)
|
36
|
+
minitest-reporters (1.0.16)
|
16
37
|
ansi
|
17
38
|
builder
|
18
|
-
minitest (>=
|
19
|
-
|
20
|
-
multi_json (1.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
39
|
+
minitest (>= 5.0)
|
40
|
+
ruby-progressbar
|
41
|
+
multi_json (1.11.0)
|
42
|
+
multi_xml (0.5.5)
|
43
|
+
multipart-post (2.0.0)
|
44
|
+
nokogiri (1.6.6.2)
|
45
|
+
mini_portile (~> 0.6.0)
|
46
|
+
oauth2 (1.0.0)
|
47
|
+
faraday (>= 0.8, < 0.10)
|
48
|
+
jwt (~> 1.0)
|
49
|
+
multi_json (~> 1.3)
|
50
|
+
multi_xml (~> 0.5)
|
51
|
+
rack (~> 1.2)
|
52
|
+
psych (2.0.13)
|
53
|
+
rack (1.6.1)
|
54
|
+
rainbow (2.0.0)
|
55
|
+
rake (10.4.2)
|
56
|
+
rdoc (4.2.0)
|
28
57
|
json (~> 1.4)
|
29
|
-
redcarpet (
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
58
|
+
redcarpet (3.2.3)
|
59
|
+
ruby-progressbar (1.7.5)
|
60
|
+
simplecov (0.10.0)
|
61
|
+
docile (~> 1.1.0)
|
62
|
+
json (~> 1.8)
|
63
|
+
simplecov-html (~> 0.10.0)
|
64
|
+
simplecov-html (0.10.0)
|
65
|
+
thread_safe (0.3.5)
|
66
|
+
yard (0.8.7.6)
|
35
67
|
|
36
68
|
PLATFORMS
|
37
69
|
ruby
|
38
70
|
|
39
71
|
DEPENDENCIES
|
40
|
-
bundler
|
41
|
-
jeweler
|
72
|
+
bundler
|
73
|
+
jeweler
|
42
74
|
minitest
|
43
75
|
minitest-reporters
|
44
76
|
psych
|
45
|
-
rainbow
|
77
|
+
rainbow (~> 2.0.0)
|
46
78
|
redcarpet
|
47
79
|
simplecov
|
48
|
-
yard
|
80
|
+
yard
|
data/README.md
CHANGED
@@ -11,35 +11,17 @@ These functionalities will improve as "automate" is being used, so if you see so
|
|
11
11
|
|
12
12
|
|
13
13
|
|
14
|
-
##
|
14
|
+
## Examples
|
15
15
|
|
16
|
-
|
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
|
16
|
+
Some simple examples can be found in the `examples/` directory.
|
35
17
|
|
36
18
|
|
37
19
|
|
38
20
|
## Usage
|
39
21
|
|
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.
|
22
|
+
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
23
|
|
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
|
24
|
+
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 small operations:
|
43
25
|
|
44
26
|
# good
|
45
27
|
go "Clone the git repository"
|
@@ -47,21 +29,62 @@ Inside said block, "chain links" are defined using the `go` method. Each chain l
|
|
47
29
|
# bad
|
48
30
|
go "Download, compile and install the linux kernel"
|
49
31
|
|
50
|
-
The chain link block defines its behavior, and the following methods are available within:
|
32
|
+
The chain link block defines its behavior, and the following methods are available within (and should be used in this order):
|
51
33
|
|
52
34
|
* `demand :parameter1, :parameter2` - Demand one or more parameters from the previous chain link (or if there is none, from the initial run command).
|
53
35
|
|
54
|
-
* `pass :parameter, value
|
36
|
+
* `pass :parameter, <value>` - Pass a parameter to the next chain link.
|
37
|
+
|
38
|
+
* `error <msg>` - Abort the chain with the specified error message.
|
55
39
|
|
56
40
|
* `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
41
|
|
42
|
+
One can also create "deferred" chain links. These are executed (in reverse order) as soon as all regular commands have been executed, but also if any of them fails:
|
43
|
+
|
44
|
+
go "Create temporary file" do
|
45
|
+
demand :tmpfile
|
46
|
+
|
47
|
+
defer "Delete temporary file" do
|
48
|
+
run "rm #{_tmpfile}"
|
49
|
+
end
|
50
|
+
|
51
|
+
run "touch #{_tmpfile}"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
### Running a command chain
|
56
|
+
|
57
|
+
After creation, a chain can be run like so:
|
58
|
+
|
59
|
+
c = Automate::Chain.which("...") do
|
60
|
+
[...]
|
61
|
+
end
|
62
|
+
|
63
|
+
result = c.run({:param1 => 123, :param2 => "foobar"})
|
64
|
+
|
65
|
+
The result will be a hash containing all parameters passed to the initial chain or passed by any of the chain links, or `false` in case of an error in the chain.
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
## Other features
|
70
|
+
|
71
|
+
* You can step through all chain links by setting the `AUTOMATE_STEP` environment variable
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
## Caveats
|
76
|
+
|
77
|
+
* `defer` blocks MUST be defined before any command that might fail. This is a result of the current implementation of `automate`, and might be improved in a future version. Until then, the way is to put any `defer` block right at the start of a command, after any `demand` invocations.
|
78
|
+
|
79
|
+
|
58
80
|
|
81
|
+
## Feature ideas
|
59
82
|
|
83
|
+
* "Literate automate", e.g. generating a automate-based ruby script from a markdown (or similar) file to properly self-documenting scripts.
|
60
84
|
|
61
|
-
|
85
|
+
* make it possible to write "plugins" that provide pre-defined commands, e.g. "create_file" could automatically run "touch file", check if the file has actually been crated and create a defer for "rm file".
|
62
86
|
|
63
|
-
*
|
64
|
-
* Add roll back actions for a link, which are only executed if said link fails.
|
87
|
+
* `run` should not return `false` on error. Perhaps a `:chain_error` element in the hash should be set or something.
|
65
88
|
|
66
89
|
|
67
90
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/automate.gemspec
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: automate 0.2.0 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "automate"
|
9
|
+
s.version = "0.2.0"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Lucas Jen\u{df}"]
|
14
|
+
s.date = "2015-05-22"
|
15
|
+
s.description = "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 :)"
|
16
|
+
s.email = "public@x3ro.de"
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.md"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"automate.gemspec",
|
30
|
+
"examples/git-copy-repo.rb",
|
31
|
+
"examples/simple.rb",
|
32
|
+
"lib/automate.rb",
|
33
|
+
"lib/automate/chain.rb",
|
34
|
+
"lib/automate/chain_link.rb",
|
35
|
+
"lib/automate/errors.rb",
|
36
|
+
"lib/automate/messenger.rb",
|
37
|
+
"test/helper.rb",
|
38
|
+
"test/test_automate.rb"
|
39
|
+
]
|
40
|
+
s.homepage = "http://github.com/x3ro/automate"
|
41
|
+
s.licenses = ["MIT"]
|
42
|
+
s.rubygems_version = "2.2.2"
|
43
|
+
s.summary = "Automate helps you automating all your favorite shell tasks"
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
s.specification_version = 4
|
47
|
+
|
48
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_runtime_dependency(%q<rainbow>, ["~> 2.0.0"])
|
50
|
+
s.add_development_dependency(%q<minitest>, [">= 0"])
|
51
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<minitest-reporters>, [">= 0"])
|
57
|
+
s.add_development_dependency(%q<psych>, [">= 0"])
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<rainbow>, ["~> 2.0.0"])
|
60
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
61
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
62
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
63
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
64
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
65
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
66
|
+
s.add_dependency(%q<minitest-reporters>, [">= 0"])
|
67
|
+
s.add_dependency(%q<psych>, [">= 0"])
|
68
|
+
end
|
69
|
+
else
|
70
|
+
s.add_dependency(%q<rainbow>, ["~> 2.0.0"])
|
71
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
72
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
73
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
74
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
75
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
76
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
77
|
+
s.add_dependency(%q<minitest-reporters>, [">= 0"])
|
78
|
+
s.add_dependency(%q<psych>, [">= 0"])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/examples/simple.rb
CHANGED
@@ -7,17 +7,37 @@ require 'automate'
|
|
7
7
|
|
8
8
|
c = Automate::Chain.which("Serves as an example") do
|
9
9
|
|
10
|
+
go "Make sure the target does not exist yet" do
|
11
|
+
run "[[ ! -e #{_filename} ]]"
|
12
|
+
end
|
13
|
+
|
10
14
|
go "Create a file in the working directory" do
|
11
15
|
demand :filename
|
16
|
+
defer "Clean up temporary file" do
|
17
|
+
run "rm #{_filename}"
|
18
|
+
end
|
19
|
+
|
12
20
|
run "touch #{_filename}"
|
13
21
|
end
|
14
22
|
|
15
|
-
go "
|
23
|
+
go "Generate random number" do
|
16
24
|
pass :number, Random.rand(100)
|
25
|
+
end
|
26
|
+
|
27
|
+
go "Write a random number into the file" do
|
17
28
|
run "echo #{_number} > #{_filename}"
|
18
29
|
end
|
19
30
|
|
31
|
+
# A raised exception will also be caught, letting the chain fail.
|
32
|
+
# go "raise something" do
|
33
|
+
# raise "oh noes"
|
34
|
+
# end
|
35
|
+
|
20
36
|
go "Demonstrate a failed chain link" do
|
37
|
+
defer "Demonstrate defer" do
|
38
|
+
run "echo 'Look ma, defer'"
|
39
|
+
end
|
40
|
+
|
21
41
|
run "this_command_doesnt_even_exist #{_number}"
|
22
42
|
end
|
23
43
|
|
data/lib/automate/chain.rb
CHANGED
@@ -26,29 +26,70 @@ module Automate
|
|
26
26
|
def run(args = {})
|
27
27
|
notice "About to run command chain which '#{@task}'"
|
28
28
|
|
29
|
-
|
29
|
+
success = true
|
30
|
+
begin
|
31
|
+
args = run_command_list(@cmd_list, args)
|
32
|
+
rescue ChainFailedError => e
|
33
|
+
fail("Chain link ##{e.chain} (#{e.description}) failed.")
|
34
|
+
success = false
|
35
|
+
end
|
36
|
+
|
37
|
+
notice "Running deferred commands"
|
38
|
+
|
39
|
+
# Note that deferred commands are executed in reverse order, so that
|
40
|
+
# the cleanup actions for the last command is executed first.
|
41
|
+
# E.g. if the definition order is as follows:
|
42
|
+
#
|
43
|
+
# C1, C1_defer, C2, C3, C4, C4_defer
|
44
|
+
#
|
45
|
+
# The execution order will be
|
46
|
+
#
|
47
|
+
# C1, C2, C3, C4, C4_defer, C1_defer
|
48
|
+
#
|
49
|
+
args = run_command_list(@defer_list.reverse, args)
|
50
|
+
if !success
|
51
|
+
false
|
52
|
+
else
|
53
|
+
args
|
54
|
+
end
|
55
|
+
|
56
|
+
rescue ChainFailedError => e
|
57
|
+
fail("Defer command ##{e.chain} (#{e.description}) failed.")
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def run_command_list(list, args)
|
63
|
+
list.each_with_index do |cmd, index|
|
30
64
|
desc, proc = cmd
|
31
65
|
success "#{timestamp} // Running link ##{index+1} - #{desc}"
|
32
66
|
|
33
67
|
error = false
|
34
68
|
begin
|
35
|
-
ret, out = ChainLink.invoke(proc, args)
|
36
|
-
|
69
|
+
ret, out, chain_link_defer = ChainLink.invoke(proc, args)
|
70
|
+
@defer_list += chain_link_defer
|
71
|
+
rescue ChainLinkFailedError => e
|
72
|
+
# TODO: Storing the defer_list in the ChainLinkFailedError is awful,
|
73
|
+
# and shall be fixed when there's time to remove this entire exception-based
|
74
|
+
# "communication" between chain and chain link.
|
75
|
+
@defer_list += e.defer_list
|
37
76
|
error = true
|
38
77
|
end
|
39
78
|
raise ChainFailedError.new(index + 1, desc) if ret == false || error == true
|
40
79
|
|
41
|
-
|
42
80
|
# Pass the arguments from the last iteration, overwriting everything that
|
43
81
|
# was passed from the current one.
|
44
82
|
args.merge! out
|
83
|
+
|
84
|
+
# Make it possible to run commands step by step
|
85
|
+
if !ENV["AUTOMATE_STEP"].nil?
|
86
|
+
puts "Press a key to continue..."
|
87
|
+
$stdin.gets
|
88
|
+
puts "\n"
|
89
|
+
end
|
45
90
|
end
|
46
91
|
|
47
92
|
args
|
48
|
-
|
49
|
-
rescue ChainFailedError => e
|
50
|
-
fail("Chain link ##{e.chain} (#{e.description}) failed. Aborting.")
|
51
|
-
false
|
52
93
|
end
|
53
94
|
|
54
95
|
|
@@ -62,6 +103,7 @@ module Automate
|
|
62
103
|
def initialize(task)
|
63
104
|
@task = task
|
64
105
|
@cmd_list = []
|
106
|
+
@defer_list = []
|
65
107
|
end
|
66
108
|
|
67
109
|
def timestamp
|
data/lib/automate/chain_link.rb
CHANGED
@@ -20,18 +20,19 @@ module Automate
|
|
20
20
|
#
|
21
21
|
def invoke(proc)
|
22
22
|
ret = instance_exec(&proc)
|
23
|
-
[ret, @out_args]
|
23
|
+
[ret, @out_args, @defer_list]
|
24
24
|
|
25
25
|
rescue UnmetDemandError => e
|
26
26
|
fail "Required argument '#{e.demand}', but was not given."
|
27
|
-
raise ChainLinkFailedError.new
|
27
|
+
raise ChainLinkFailedError.new(@defer_list)
|
28
28
|
rescue CmdFailedError => e
|
29
29
|
fail e.message
|
30
|
-
raise ChainLinkFailedError.new
|
30
|
+
raise ChainLinkFailedError.new(@defer_list)
|
31
|
+
rescue => e
|
32
|
+
fail "Chain link raised an exception: \n #{e} \n #{e.backtrace.join("\n")}"
|
33
|
+
raise ChainLinkFailedError.new(@defer_list)
|
31
34
|
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
36
|
# ==========
|
36
37
|
# Public API
|
37
38
|
# ==========
|
@@ -50,7 +51,7 @@ module Automate
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
|
-
raise CmdFailedError.new("Command '#{cmd}' had exit status
|
54
|
+
raise CmdFailedError.new("Command '#{cmd}' had exit status #{$?.to_i}") if $? != 0
|
54
55
|
out
|
55
56
|
end
|
56
57
|
|
@@ -67,6 +68,15 @@ module Automate
|
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
71
|
+
# Manually abort a chain because of an error
|
72
|
+
def error(msg)
|
73
|
+
raise CmdFailedError.new(msg)
|
74
|
+
end
|
75
|
+
|
76
|
+
def defer(desc, &block)
|
77
|
+
@defer_list.push [desc, block]
|
78
|
+
end
|
79
|
+
|
70
80
|
# Implement method_missing so that we can address passed variables using the
|
71
81
|
# `_variablename` shorthand within a chain link.
|
72
82
|
def method_missing(method, *args, &block)
|
@@ -98,6 +108,7 @@ module Automate
|
|
98
108
|
def initialize(args)
|
99
109
|
@in_args = args
|
100
110
|
@out_args = {}
|
111
|
+
@defer_list = []
|
101
112
|
end
|
102
113
|
|
103
114
|
end
|
data/lib/automate/errors.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
module Automate
|
2
2
|
|
3
|
-
class ChainLinkFailedError < Exception
|
3
|
+
class ChainLinkFailedError < Exception
|
4
|
+
attr_reader :defer_list
|
5
|
+
def initialize(defer_list)
|
6
|
+
super
|
7
|
+
@defer_list = defer_list
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
class CmdFailedError < Exception; end
|
5
12
|
|
6
13
|
class ChainFailedError < Exception
|
data/lib/automate/messenger.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
3
|
|
4
|
+
require 'rubygems'
|
4
5
|
require 'bundler'
|
5
6
|
begin
|
6
7
|
Bundler.setup(:default, :development)
|
@@ -11,21 +12,17 @@ rescue Bundler::BundlerError => e
|
|
11
12
|
end
|
12
13
|
|
13
14
|
|
14
|
-
require 'minitest/
|
15
|
+
require 'minitest/autorun'
|
15
16
|
require "minitest/reporters"
|
16
17
|
MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new
|
17
18
|
|
18
19
|
|
19
|
-
require 'simplecov'
|
20
|
-
SimpleCov.start
|
21
|
-
|
22
|
-
|
23
20
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
24
21
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
25
22
|
require 'automate'
|
26
23
|
|
27
24
|
|
28
|
-
class MiniTest::
|
25
|
+
class MiniTest::Test
|
29
26
|
def setup
|
30
27
|
@original_stdout = $stdout
|
31
28
|
$stdout = StringIO.new
|
@@ -37,4 +34,4 @@ class MiniTest::Unit::TestCase
|
|
37
34
|
end
|
38
35
|
|
39
36
|
|
40
|
-
MiniTest
|
37
|
+
MiniTest.autorun
|
data/test/test_automate.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
class TestAutomate < MiniTest::
|
3
|
+
class TestAutomate < MiniTest::Test
|
4
4
|
|
5
5
|
def test_single_element_chain
|
6
6
|
c = Automate::Chain.which("Has a single element") do
|
@@ -75,15 +75,13 @@ class TestAutomate < MiniTest::Unit::TestCase
|
|
75
75
|
end
|
76
76
|
|
77
77
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
wobblewobble
|
83
|
-
end
|
78
|
+
def test_exception_in_chain_link
|
79
|
+
c = Automate::Chain.which("checks method missing") do
|
80
|
+
go "Raise name error" do
|
81
|
+
wobblewobble
|
84
82
|
end
|
85
|
-
c.run
|
86
83
|
end
|
84
|
+
assert_equal false, c.run
|
87
85
|
end
|
88
86
|
|
89
87
|
|
@@ -99,6 +97,17 @@ class TestAutomate < MiniTest::Unit::TestCase
|
|
99
97
|
assert_equal "4242", result[:output]
|
100
98
|
end
|
101
99
|
|
100
|
+
def test_parameter_passed_through
|
101
|
+
c = Automate::Chain.which("...") do
|
102
|
+
go "..." do
|
103
|
+
demand :input
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
result = c.run({:input => 42})
|
108
|
+
assert_equal({:input => 42}, result)
|
109
|
+
end
|
110
|
+
|
102
111
|
|
103
112
|
def test_access_variables_just_passed
|
104
113
|
c = Automate::Chain.which("Run shell command") do
|
@@ -112,4 +121,92 @@ class TestAutomate < MiniTest::Unit::TestCase
|
|
112
121
|
assert_equal 43, result[:output]
|
113
122
|
end
|
114
123
|
|
124
|
+
|
125
|
+
def test_manually_abort_chain_with_error
|
126
|
+
proc = lambda { error "test" }
|
127
|
+
assert_raises(Automate::ChainLinkFailedError) do
|
128
|
+
Automate::ChainLink.invoke(proc, [])
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def test_defer_invocation
|
134
|
+
c = Automate::Chain.which("Has a single element + defer") do
|
135
|
+
go "Set some variable" do
|
136
|
+
defer "Alter the variable" do
|
137
|
+
pass :foo, 24
|
138
|
+
end
|
139
|
+
|
140
|
+
pass :foo, 42
|
141
|
+
end
|
142
|
+
end
|
143
|
+
assert_equal({:foo => 24}, c.run)
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def test_defer_invocation_order
|
148
|
+
c = Automate::Chain.which("Test chain") do
|
149
|
+
go "Set some variable" do
|
150
|
+
defer "Change that variable, this should run last" do
|
151
|
+
pass :foo, 1000
|
152
|
+
end
|
153
|
+
|
154
|
+
pass :foo, 42
|
155
|
+
end
|
156
|
+
|
157
|
+
go "This sets the variable too" do
|
158
|
+
defer "This should have no effect on foo's return" do
|
159
|
+
pass :foo, 9999
|
160
|
+
end
|
161
|
+
|
162
|
+
pass :foo, 24
|
163
|
+
end
|
164
|
+
end
|
165
|
+
assert_equal({:foo => 1000}, c.run)
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
def test_failing_defer_command
|
170
|
+
c = Automate::Chain.which("Has an error") do
|
171
|
+
go "This works" do
|
172
|
+
defer "But this doesn't" do
|
173
|
+
run "this_doesnt_even_exist___"
|
174
|
+
end
|
175
|
+
|
176
|
+
run "echo -n 'hi'"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
assert_equal false, c.run
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
def test_dont_execute_defer_for_untouched_chain
|
185
|
+
should_be_invoked = nil
|
186
|
+
should_not_be_invoked = false
|
187
|
+
|
188
|
+
c = Automate::Chain.which("Test chain") do
|
189
|
+
go "Set some variable" do
|
190
|
+
defer "this should run last" do
|
191
|
+
should_be_invoked = true
|
192
|
+
end
|
193
|
+
|
194
|
+
run "this_doesnt_even_exist___"
|
195
|
+
end
|
196
|
+
|
197
|
+
go "Chain that is never executed" do
|
198
|
+
defer "This should have no effect on foo's return" do
|
199
|
+
should_not_be_invoked = true
|
200
|
+
pass :ohnoes, true
|
201
|
+
end
|
202
|
+
|
203
|
+
pass :foo, 42
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
assert_equal(false, c.run)
|
208
|
+
assert_equal(false, should_not_be_invoked)
|
209
|
+
assert_equal(true, should_be_invoked)
|
210
|
+
end
|
211
|
+
|
115
212
|
end
|
metadata
CHANGED
@@ -1,158 +1,139 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: automate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Lucas Jenß
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-05-22 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rainbow
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
19
|
+
version: 2.0.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
26
|
+
version: 2.0.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: minitest
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: yard
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0
|
47
|
+
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0
|
54
|
+
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: redcarpet
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - ">="
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: '0'
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - ">="
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: bundler
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - ">="
|
84
74
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
75
|
+
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - ">="
|
92
81
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
82
|
+
version: '0'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: jeweler
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - ">="
|
100
88
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
89
|
+
version: '0'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
|
-
- -
|
94
|
+
- - ">="
|
108
95
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
96
|
+
version: '0'
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: simplecov
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
|
-
- -
|
101
|
+
- - ">="
|
116
102
|
- !ruby/object:Gem::Version
|
117
103
|
version: '0'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
|
-
- -
|
108
|
+
- - ">="
|
124
109
|
- !ruby/object:Gem::Version
|
125
110
|
version: '0'
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: minitest-reporters
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
|
-
- -
|
115
|
+
- - ">="
|
132
116
|
- !ruby/object:Gem::Version
|
133
117
|
version: '0'
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
|
-
- -
|
122
|
+
- - ">="
|
140
123
|
- !ruby/object:Gem::Version
|
141
124
|
version: '0'
|
142
125
|
- !ruby/object:Gem::Dependency
|
143
126
|
name: psych
|
144
127
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
128
|
requirements:
|
147
|
-
- -
|
129
|
+
- - ">="
|
148
130
|
- !ruby/object:Gem::Version
|
149
131
|
version: '0'
|
150
132
|
type: :development
|
151
133
|
prerelease: false
|
152
134
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
135
|
requirements:
|
155
|
-
- -
|
136
|
+
- - ">="
|
156
137
|
- !ruby/object:Gem::Version
|
157
138
|
version: '0'
|
158
139
|
description: The automate Gem provides a very simple DSL for writing command line
|
@@ -165,13 +146,14 @@ extra_rdoc_files:
|
|
165
146
|
- LICENSE.txt
|
166
147
|
- README.md
|
167
148
|
files:
|
168
|
-
- .document
|
149
|
+
- ".document"
|
169
150
|
- Gemfile
|
170
151
|
- Gemfile.lock
|
171
152
|
- LICENSE.txt
|
172
153
|
- README.md
|
173
154
|
- Rakefile
|
174
155
|
- VERSION
|
156
|
+
- automate.gemspec
|
175
157
|
- examples/git-copy-repo.rb
|
176
158
|
- examples/simple.rb
|
177
159
|
- lib/automate.rb
|
@@ -184,29 +166,25 @@ files:
|
|
184
166
|
homepage: http://github.com/x3ro/automate
|
185
167
|
licenses:
|
186
168
|
- MIT
|
169
|
+
metadata: {}
|
187
170
|
post_install_message:
|
188
171
|
rdoc_options: []
|
189
172
|
require_paths:
|
190
173
|
- lib
|
191
174
|
required_ruby_version: !ruby/object:Gem::Requirement
|
192
|
-
none: false
|
193
175
|
requirements:
|
194
|
-
- -
|
176
|
+
- - ">="
|
195
177
|
- !ruby/object:Gem::Version
|
196
178
|
version: '0'
|
197
|
-
segments:
|
198
|
-
- 0
|
199
|
-
hash: 3608312016429537767
|
200
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
|
-
none: false
|
202
180
|
requirements:
|
203
|
-
- -
|
181
|
+
- - ">="
|
204
182
|
- !ruby/object:Gem::Version
|
205
183
|
version: '0'
|
206
184
|
requirements: []
|
207
185
|
rubyforge_project:
|
208
|
-
rubygems_version:
|
186
|
+
rubygems_version: 2.2.2
|
209
187
|
signing_key:
|
210
|
-
specification_version:
|
188
|
+
specification_version: 4
|
211
189
|
summary: Automate helps you automating all your favorite shell tasks
|
212
190
|
test_files: []
|