clintegracon 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +158 -0
- data/Rakefile +60 -0
- data/clintegracon.gemspec +34 -0
- data/lib/CLIntegracon.rb +9 -0
- data/lib/CLIntegracon/adapter/bacon.rb +208 -0
- data/lib/CLIntegracon/configuration.rb +67 -0
- data/lib/CLIntegracon/diff.rb +81 -0
- data/lib/CLIntegracon/file_tree_spec.rb +213 -0
- data/lib/CLIntegracon/file_tree_spec_context.rb +180 -0
- data/lib/CLIntegracon/formatter.rb +77 -0
- data/lib/CLIntegracon/subject.rb +128 -0
- data/lib/CLIntegracon/version.rb +3 -0
- data/spec/bacon/execution_output.txt +72 -0
- data/spec/bacon/spec_helper.rb +60 -0
- data/spec/fixtures/bin/coffeemaker.rb +58 -0
- data/spec/integration/coffeemaker_help/after/execution_output.txt +23 -0
- data/spec/integration/coffeemaker_help/before/.gitkeep +0 -0
- data/spec/integration/coffeemaker_no_milk/after/BlackEye.brewed-coffee +1 -0
- data/spec/integration/coffeemaker_no_milk/after/CaPheSuaDa.brewed-coffee +1 -0
- data/spec/integration/coffeemaker_no_milk/after/Coffeemakerfile.yml +5 -0
- data/spec/integration/coffeemaker_no_milk/after/RedTux.brewed-coffee +1 -0
- data/spec/integration/coffeemaker_no_milk/after/execution_output.txt +6 -0
- data/spec/integration/coffeemaker_no_milk/before/Coffeemakerfile.yml +5 -0
- data/spec/integration/coffeemaker_sweetner_honey/after/Affogato.brewed-coffee +2 -0
- data/spec/integration/coffeemaker_sweetner_honey/after/BlackEye.brewed-coffee +2 -0
- data/spec/integration/coffeemaker_sweetner_honey/after/Coffeemakerfile.yml +3 -0
- data/spec/integration/coffeemaker_sweetner_honey/after/RedTux.brewed-coffee +2 -0
- data/spec/integration/coffeemaker_sweetner_honey/after/execution_output.txt +4 -0
- data/spec/integration/coffeemaker_sweetner_honey/before/Coffeemakerfile.yml +3 -0
- data/spec/unit/adapter/bacon_spec.rb +187 -0
- data/spec/unit/configuration_spec.rb +72 -0
- metadata +176 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'colored'
|
2
|
+
|
3
|
+
module CLIntegracon
|
4
|
+
class Formatter
|
5
|
+
|
6
|
+
# @return [FileTreeSpec]
|
7
|
+
# the spec
|
8
|
+
attr_reader :spec
|
9
|
+
|
10
|
+
# Initialize
|
11
|
+
#
|
12
|
+
# @param [FileTreeSpec] spec
|
13
|
+
# the spec
|
14
|
+
#
|
15
|
+
def initialize(spec)
|
16
|
+
super()
|
17
|
+
@spec = spec
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return a description text for an expectation that a file path
|
21
|
+
# was expected to exist, but is missing.
|
22
|
+
#
|
23
|
+
# @param [Pathname] file_path
|
24
|
+
# the file path which was expected to exist
|
25
|
+
#
|
26
|
+
# @return [String]
|
27
|
+
#
|
28
|
+
def describe_missing_file(file_path)
|
29
|
+
description = []
|
30
|
+
description << "Missing file for #{spec.spec_folder}:"
|
31
|
+
description << " * #{file_path.to_s.red}"
|
32
|
+
description * "\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return a description text for an expectation that certain file paths
|
36
|
+
# were unexpected.
|
37
|
+
#
|
38
|
+
# @param [Array<Pathname>] file_paths
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
#
|
42
|
+
def describe_unexpected_files(file_paths)
|
43
|
+
description = []
|
44
|
+
description << "Unexpected files for #{spec.spec_folder}:"
|
45
|
+
description += file_paths.map { |f| " * #{f.to_s.green}" }
|
46
|
+
description * "\n"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a description text for an expectation that two files were
|
50
|
+
# expected to be the same, but are not.
|
51
|
+
#
|
52
|
+
# @param [Diff] diff
|
53
|
+
# the diff which holds the difference
|
54
|
+
#
|
55
|
+
# @param [Integer] max_width
|
56
|
+
# the max width of the terminal to print matching separators
|
57
|
+
#
|
58
|
+
# @return [String]
|
59
|
+
#
|
60
|
+
def describe_file_diff(diff, max_width=80)
|
61
|
+
description = []
|
62
|
+
description << "File comparison error `#{diff.relative_path}` for #{spec.spec_folder}:"
|
63
|
+
description << "--- DIFF ".ljust(max_width, '-')
|
64
|
+
description += diff.map do |line|
|
65
|
+
case line
|
66
|
+
when /^\+/ then line.green
|
67
|
+
when /^-/ then line.red
|
68
|
+
else line
|
69
|
+
end.gsub("\n",'')
|
70
|
+
end
|
71
|
+
description << "--- END ".ljust(max_width, '-')
|
72
|
+
description << ''
|
73
|
+
description * "\n"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module CLIntegracon
|
2
|
+
class Subject
|
3
|
+
|
4
|
+
#-----------------------------------------------------------------------------#
|
5
|
+
|
6
|
+
# @!group Attributes
|
7
|
+
|
8
|
+
# @return [String]
|
9
|
+
# The name of the binary to use for the tests
|
10
|
+
attr_accessor :name
|
11
|
+
|
12
|
+
# @return [String]
|
13
|
+
# The executable statement to use for the tests
|
14
|
+
attr_accessor :executable
|
15
|
+
|
16
|
+
# @return [Hash<String,String>]
|
17
|
+
# The environment variables which will always been defined for the executable
|
18
|
+
# on launch should not been passed explicitly every time to the launch method.
|
19
|
+
attr_accessor :environment_vars
|
20
|
+
|
21
|
+
# @return [Array<String>]
|
22
|
+
# The arguments which will always passed to the executable on launch and
|
23
|
+
# should not been passed explicitly every time to the launch method.
|
24
|
+
# Those are added behind the arguments given on +launch+.
|
25
|
+
attr_accessor :default_args
|
26
|
+
|
27
|
+
# @return [Hash<String,String>]
|
28
|
+
# The special paths, which are not relative to the project, when the statement
|
29
|
+
# will be executed. These are paths were side-effects occur, like manipulation
|
30
|
+
# of user configurations in dot files or caching-specific directories.
|
31
|
+
attr_accessor :special_paths
|
32
|
+
|
33
|
+
# @return [String]
|
34
|
+
# The path where the output of the executable will be written to.
|
35
|
+
attr_accessor :output_path
|
36
|
+
|
37
|
+
|
38
|
+
#-----------------------------------------------------------------------------#
|
39
|
+
|
40
|
+
# @!group Initializer
|
41
|
+
|
42
|
+
# "Designated" initializer
|
43
|
+
#
|
44
|
+
# @param [String] name
|
45
|
+
# The name of the binary
|
46
|
+
#
|
47
|
+
# @param [String] executable
|
48
|
+
# The executable subject statement (optional)
|
49
|
+
#
|
50
|
+
def initialize(name='subject', executable=nil)
|
51
|
+
self.name = name
|
52
|
+
self.executable = executable || name
|
53
|
+
self.environment_vars = {}
|
54
|
+
self.default_args = []
|
55
|
+
self.special_paths = {}
|
56
|
+
self.output_path = 'execution_output.txt'
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
#-----------------------------------------------------------------------------#
|
61
|
+
|
62
|
+
# @!group DSL-like Setter
|
63
|
+
|
64
|
+
# Define a path in the user directory as special path
|
65
|
+
#
|
66
|
+
# @param [String] path
|
67
|
+
# The path
|
68
|
+
#
|
69
|
+
# @param [String] name
|
70
|
+
# The name of the path, or the basename of the given path
|
71
|
+
#
|
72
|
+
def has_special_path(path, name=nil)
|
73
|
+
name ||= File.basename path
|
74
|
+
self.special_paths[name] = path
|
75
|
+
end
|
76
|
+
|
77
|
+
# Define a path in the user directory as special path
|
78
|
+
#
|
79
|
+
# @param [String] path
|
80
|
+
# The path
|
81
|
+
#
|
82
|
+
# @param [String] name
|
83
|
+
# The name of the path, or the basename of the given path
|
84
|
+
#
|
85
|
+
def has_special_user_path(path, name=nil)
|
86
|
+
self.has_special_path %r[/Users/.*/#{path.to_s}], name
|
87
|
+
end
|
88
|
+
|
89
|
+
#-----------------------------------------------------------------------------#
|
90
|
+
|
91
|
+
# @!group Interaction
|
92
|
+
|
93
|
+
# Runs the executable with the given arguments in the temporary directory.
|
94
|
+
#
|
95
|
+
# @note: You can check by `$?.success?` if the execution succeeded.
|
96
|
+
#
|
97
|
+
# @param [String] head_arguments
|
98
|
+
# The arguments to pass to the executable before the default arguments.
|
99
|
+
#
|
100
|
+
# @param [String] tail_arguments
|
101
|
+
# The arguments to pass to the executable after the default arguments.
|
102
|
+
#
|
103
|
+
# @return [String]
|
104
|
+
# The output, which is emitted while execution from the binary.
|
105
|
+
#
|
106
|
+
def launch(head_arguments='', tail_arguments='')
|
107
|
+
vars = environment_vars.map { |key,value| "#{key}=#{value}" }.join ' '
|
108
|
+
args = [head_arguments, default_args, tail_arguments].flatten.compact.select { |s| s.length > 0 }.join ' '
|
109
|
+
command = "#{vars} #{executable} #{args} 2>&1"
|
110
|
+
|
111
|
+
output = `#{command}`
|
112
|
+
|
113
|
+
File.open(output_path, 'w') do |file|
|
114
|
+
file.write command.sub(executable, name)
|
115
|
+
file.write "\n"
|
116
|
+
|
117
|
+
special_paths.each do |key, path|
|
118
|
+
output.gsub!(path, key)
|
119
|
+
end
|
120
|
+
|
121
|
+
file.write output
|
122
|
+
end
|
123
|
+
|
124
|
+
output
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
CLIntegracon::Adapter::Bacon
|
2
|
+
coffee-maker
|
3
|
+
Brew recipes
|
4
|
+
without milk
|
5
|
+
- $ coffee-maker --no-milk
|
6
|
+
- BlackEye.brewed-coffee
|
7
|
+
- CaPheSuaDa.brewed-coffee
|
8
|
+
- Coffeemakerfile.yml
|
9
|
+
- execution_output.txt
|
10
|
+
- RedTux.brewed-coffee
|
11
|
+
- should not produce unexpected files [FAILED]
|
12
|
+
with honey as sweetner
|
13
|
+
- $ coffee-maker --sweetner=honey
|
14
|
+
- Affogato.brewed-coffee [FAILED]
|
15
|
+
- BlackEye.brewed-coffee [FAILED]
|
16
|
+
- Coffeemakerfile.yml
|
17
|
+
- execution_output.txt
|
18
|
+
- RedTux.brewed-coffee [FAILED]
|
19
|
+
- should not produce unexpected files
|
20
|
+
Get help
|
21
|
+
- $ coffee-maker --help
|
22
|
+
- execution_output.txt
|
23
|
+
- should not produce unexpected files
|
24
|
+
|
25
|
+
Bacon::Error: Unexpected files for coffeemaker_no_milk:
|
26
|
+
* [32mAffogato.brewed-coffee[0m
|
27
|
+
./spec/bacon/spec_helper.rb:45
|
28
|
+
./spec/bacon/spec_helper.rb:44
|
29
|
+
./spec/bacon/spec_helper.rb:42
|
30
|
+
./spec/bacon/spec_helper.rb:17
|
31
|
+
./spec/bacon/spec_helper.rb:15
|
32
|
+
$GEM_HOME/bin/ruby_executable_hooks:15
|
33
|
+
|
34
|
+
Bacon::Error: File comparison error `Affogato.brewed-coffee` for coffeemaker_sweetner_honey:
|
35
|
+
--- DIFF -----------------------------------------------------------------------
|
36
|
+
class Affogato < BrewedCoffee
|
37
|
+
[32m+ @milk = true[0m
|
38
|
+
@sweetner = honey
|
39
|
+
--- END ------------------------------------------------------------------------
|
40
|
+
|
41
|
+
./spec/bacon/spec_helper.rb:49
|
42
|
+
./spec/bacon/spec_helper.rb:48
|
43
|
+
./spec/bacon/spec_helper.rb:42
|
44
|
+
./spec/bacon/spec_helper.rb:17
|
45
|
+
./spec/bacon/spec_helper.rb:15
|
46
|
+
$GEM_HOME/bin/ruby_executable_hooks:15
|
47
|
+
|
48
|
+
Bacon::Error: Missing file for coffeemaker_sweetner_honey:
|
49
|
+
* [31mBlackEye.brewed-coffee[0m
|
50
|
+
./spec/bacon/spec_helper.rb:49
|
51
|
+
./spec/bacon/spec_helper.rb:48
|
52
|
+
./spec/bacon/spec_helper.rb:42
|
53
|
+
./spec/bacon/spec_helper.rb:17
|
54
|
+
./spec/bacon/spec_helper.rb:15
|
55
|
+
$GEM_HOME/bin/ruby_executable_hooks:15
|
56
|
+
|
57
|
+
Bacon::Error: File comparison error `RedTux.brewed-coffee` for coffeemaker_sweetner_honey:
|
58
|
+
--- DIFF -----------------------------------------------------------------------
|
59
|
+
class RedTux < BrewedCoffee
|
60
|
+
[31m- @sweetner = sugar[0m
|
61
|
+
[32m+ @milk = true[0m
|
62
|
+
[32m+ @sweetner = honey[0m
|
63
|
+
--- END ------------------------------------------------------------------------
|
64
|
+
|
65
|
+
./spec/bacon/spec_helper.rb:49
|
66
|
+
./spec/bacon/spec_helper.rb:48
|
67
|
+
./spec/bacon/spec_helper.rb:42
|
68
|
+
./spec/bacon/spec_helper.rb:17
|
69
|
+
./spec/bacon/spec_helper.rb:15
|
70
|
+
$GEM_HOME/bin/ruby_executable_hooks:15
|
71
|
+
|
72
|
+
17 specifications (27 requirements), 4 failures, 0 errors
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'bacon'
|
2
|
+
require 'CLIntegracon'
|
3
|
+
|
4
|
+
ROOT = Pathname.new(File.expand_path('../../../', __FILE__))
|
5
|
+
BIN = ROOT + 'spec/fixtures/bin'
|
6
|
+
|
7
|
+
CLIntegracon.configure do |c|
|
8
|
+
c.context.spec_path = ROOT + 'spec/integration'
|
9
|
+
c.context.temp_path = ROOT + 'tmp/bacon_specs'
|
10
|
+
|
11
|
+
c.hook_into :bacon
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
describe CLIntegracon::Adapter::Bacon do
|
16
|
+
|
17
|
+
describe_cli 'coffee-maker' do
|
18
|
+
|
19
|
+
subject do |s|
|
20
|
+
s.name = 'coffee-maker'
|
21
|
+
s.executable = "bundle exec ruby #{BIN}/coffeemaker.rb"
|
22
|
+
s.environment_vars = {
|
23
|
+
'COFFEE_MAKER_FILE' => 'Coffeemakerfile.yml'
|
24
|
+
}
|
25
|
+
s.default_args = [
|
26
|
+
'--verbose',
|
27
|
+
'--no-ansi'
|
28
|
+
]
|
29
|
+
s.has_special_path ROOT.to_s, 'ROOT'
|
30
|
+
s.has_special_path `bundle show claide`.rstrip, 'CLAIDE_SRC'
|
31
|
+
end
|
32
|
+
|
33
|
+
context do |c|
|
34
|
+
c.ignores '.DS_Store'
|
35
|
+
c.ignores '.gitkeep'
|
36
|
+
|
37
|
+
c.has_special_handling_for 'execution_output.txt' do |path|
|
38
|
+
File.read(path).gsub(/:in `<main>'$/, '') # workaround different stack trace format by ruby-1.8.7
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'Brew recipes' do
|
43
|
+
|
44
|
+
describe 'without milk' do
|
45
|
+
behaves_like cli_spec('coffeemaker_no_milk', '--no-milk')
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'with honey as sweetner' do
|
49
|
+
behaves_like cli_spec('coffeemaker_sweetner_honey', '--sweetner=honey')
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'Get help' do
|
55
|
+
behaves_like cli_spec('coffeemaker_help', '--help')
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'claide'
|
4
|
+
require 'colored'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
# Don’t worry, this makes no sense, just an example
|
8
|
+
# command which modifies the file system.
|
9
|
+
class CoffeeMaker < CLAide::Command
|
10
|
+
self.description = 'Make delicious coffee from the comfort of your terminal.'
|
11
|
+
|
12
|
+
def self.options
|
13
|
+
[
|
14
|
+
['--no-milk', 'Don’t add milk'],
|
15
|
+
['--sweetner=[sugar|honey]', 'Use one of the available sweetners'],
|
16
|
+
].concat(super)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(argv)
|
20
|
+
@add_milk = argv.flag?('milk', true)
|
21
|
+
@sweetner = argv.option('sweetner')
|
22
|
+
@config_file = ENV['COFFEE_MAKER_FILE'] || 'Coffeemakerfile'
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate!
|
27
|
+
super
|
28
|
+
if @sweetner && !%w(sugar honey).include?(@sweetner)
|
29
|
+
help! "'#{@sweetner}' is not a valid sweetner."
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def brew(recipe)
|
34
|
+
File.open recipe+'.brewed-coffee', 'w' do |f|
|
35
|
+
f.write "class #{recipe} < BrewedCoffee\n"
|
36
|
+
if @add_milk
|
37
|
+
f.write " @milk = true\n"
|
38
|
+
end
|
39
|
+
if @sweetner
|
40
|
+
f.write " @sweetner = #{@sweetner}\n"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def run
|
46
|
+
@config = YAML.load_file @config_file
|
47
|
+
if @config['recipes'] == nil
|
48
|
+
help! "Didn’t found any `recipes` in the Coffeemakerfile.yml."
|
49
|
+
end
|
50
|
+
@config['recipes'].each do |recipe|
|
51
|
+
puts "* Brewing #{recipe}"
|
52
|
+
brew(recipe)
|
53
|
+
end
|
54
|
+
puts '* Enjoy!'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
CoffeeMaker.run(ARGV)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
COFFEE_MAKER_FILE=Coffeemakerfile.yml coffee-maker --help --verbose --no-ansi 2>&1
|
2
|
+
Usage:
|
3
|
+
|
4
|
+
$ coffee-maker
|
5
|
+
|
6
|
+
Make delicious coffee from the comfort of your terminal.
|
7
|
+
|
8
|
+
Options:
|
9
|
+
|
10
|
+
--no-milk Don’t add milk
|
11
|
+
--sweetner=[sugar|honey] Use one of the available sweetners
|
12
|
+
--completion-script Print the auto-completion script
|
13
|
+
--version Show the version of the tool
|
14
|
+
--verbose Show more debugging information
|
15
|
+
--no-ansi Show output without ANSI codes
|
16
|
+
--help Show help banner of specified command
|
17
|
+
|
18
|
+
CLAIDE_SRC/lib/claide/command.rb:348:in `help!'
|
19
|
+
CLAIDE_SRC/lib/claide/command.rb:466:in `help!'
|
20
|
+
CLAIDE_SRC/lib/claide/command.rb:434:in `validate!'
|
21
|
+
ROOT/spec/fixtures/bin/coffeemaker.rb:27:in `validate!'
|
22
|
+
CLAIDE_SRC/lib/claide/command.rb:280:in `run'
|
23
|
+
ROOT/spec/fixtures/bin/coffeemaker.rb:58:in `<main>'
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
class BlackEye < BrewedCoffee
|
@@ -0,0 +1 @@
|
|
1
|
+
class CaPheSuaDa < BrewedCoffee
|
@@ -0,0 +1 @@
|
|
1
|
+
class RedTux < BrewedCoffee
|