rototiller 0.0.0.b → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1d55671811e2416321d690faed5b873e6656bb5a
4
- data.tar.gz: c6bd60e740eafc188f462997b429132752806a70
3
+ metadata.gz: c0293a5f48a1408895a06db0d68fc2c72f6b01f9
4
+ data.tar.gz: 618d7deee258cfabf05e3ce58444e1b8b5464978
5
5
  SHA512:
6
- metadata.gz: 2641a1a861d9f54b1218c6b718179ff985b9f2c77a2472729d2a0ba58907279e484e6c448506b83fe8c2234720a28df78e0fe2dfdfca6a823b0f7e2c3c3437b8
7
- data.tar.gz: 77a6855654474501fb1152b470e4e71d99c160065f0e46a0940e976f34fd1e9e01b139f7c336d677b8f933474978e210f751b5e41ab6b97e74232189895b83eb
6
+ metadata.gz: 55d4f136476b7486c36c2793fff8b92762dc04fe96a14654ac116e8cc2f3e96c9872f73ab102f473337d67f2a0609cb9caf88e0eb9f5a2d615b8a7b71973be37
7
+ data.tar.gz: 8780f143c25e5799bb1aa8a1cf36497d26b1c3778efb9deb7039e203646909cc2e0438b28319e70e0fe7cafcdba3a1c3202d3db1dedf7510d66df501fda24762
data/Gemfile CHANGED
@@ -2,6 +2,9 @@ source 'https://rubygems.org'
2
2
 
3
3
  # place all development, system_test, etc dependencies here
4
4
 
5
+ # in the Rakefile, so we require it in all groups
6
+ gem 'rspec' ,'~> 3.1.0'
7
+
5
8
  group :system_tests do
6
9
  #gem 'beaker', :path => "../../beaker/"
7
10
  gem 'beaker' ,'~> 2.22'
@@ -9,13 +12,13 @@ group :system_tests do
9
12
  end
10
13
 
11
14
  group :development do
12
- gem 'rspec' ,'~> 3.1.0'
13
15
  gem 'simplecov'
14
16
  #Documentation dependencies
15
17
  gem 'yard' ,'~> 0'
16
18
  gem 'markdown' ,'~> 0'
17
19
  # restrict version to enable ruby 1.9.3
18
20
  gem 'mime-types' ,'~> 2.0'
21
+ gem 'google-api-client' ,'<= 0.9.4'
19
22
  end
20
23
 
21
24
  local_gemfile = "#{__FILE__}.local"
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rototiller (0.0.0.b)
5
- rake
4
+ rototiller (0.1.0)
5
+ rake (>= 0.9.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -268,6 +268,7 @@ PLATFORMS
268
268
  DEPENDENCIES
269
269
  beaker (~> 2.22)
270
270
  beaker-hostgenerator
271
+ google-api-client (<= 0.9.4)
271
272
  markdown (~> 0)
272
273
  mime-types (~> 2.0)
273
274
  rototiller!
data/README.md CHANGED
@@ -1,57 +1,180 @@
1
- # rototiller
1
+ # Rototiller
2
2
 
3
- A shared rake task library for use at Puppet.
4
- Goals of Rototiller
3
+ A [Rake](https://github.com/ruby/rake) helper for command-oriented tasks.
5
4
 
6
- * Provide a tool that can house shared rake task code for Puppet Labs.
7
-
8
- * Reduce duplication in rakefiles across projects at Puppet Labs.
5
+ :warning: This version of Rototiller should be considered of _beta_ quality.
6
+ It is already known that the API will change quite a bit for the next release.
7
+ Please see the notes at the top of the [Write](#write) section.
9
8
 
9
+ * simplifies the building of command strings in :rototiller_task for task authors
10
+ * abstracts the overriding of command string components: commands, flags, arguments for task users
11
+ * unifies and standardizes messaging surrounding the use of environment variables for task operations
12
+ * Provides a tool that can house shared rake task code for Puppet.
13
+ * Reduce duplication in Rakefiles across projects at Puppet.
10
14
  * Reduce effort required to write first class rake tasks.
11
-
12
- * Reduce time and effort trying to understand requirement to run rake tasks.
13
-
15
+ * Reduce time and effort trying to understand requirement to run rake tasks.
14
16
  * Provide a standard interface for executing tests in a given test tier regardless of framework (Not MVP)
15
17
 
16
- ## Classes & Modules under development
17
- For more detailed documentation please refer to the yard docs.
18
-
19
- ####[EnvVar](lib/rototiller/utilities/env_var.rb)
20
-
21
- A class that tracks the state of an ENV variable.
22
- This class is responsible for formatting its own messaging, the value that should be used, and if a task should stop.
23
-
24
- ####[Flag](lib/rototiller/utilities/flag.rb)
25
-
26
- A class that tracks the desired state of command line flags used in test invocation.
27
- The desired state of these flags is determined by the user.
28
-
29
- ####[ParamCollection](lib/rototiller/utilities/param_collection.rb)
30
-
31
- A class to contain EnvVar and Flag classes.
32
- Behaves similar to an Array.
33
-
34
- ####[RototillerTask](lib/rototiller/task/rototiller_task.rb)
35
-
36
- A class used to build a rake task.
37
- Similar in approach to [RSpec::Core::RakeTask](https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/rake_task.rb)
38
-
39
- ####[CLIFlags](lib/rototiller/task/flags/cli_flags.rb)
40
-
41
- A class to contain the known CLI flags.
18
+ <a name="install"></a>
19
+ ## Install
20
+ gem install rototiller
21
+
22
+ <a name="write"></a>
23
+ ## Write
24
+ Rototiller provides a Rake DSL addition called 'rototiller_task' which is a fully featured Rake task with environment variable handling, messaging and command-string-building functionality.
25
+
26
+ :warning: The API below will change for the next release.
27
+ The known changes include (not comprehensive):
28
+ * moving `#add_flag` to `Command` and renaming it `#add_option`
29
+ * adding `#add_env` to `Command` and `#add_option`, so one can add multiple environment variables
30
+ * adding `#add_switch` to Command so one does not have to use the `:is_boolean` parameter for `#add_flag`
31
+ * adding some sort of env_var type so one does not have to use the `:required` parameter for `#add_flag`
32
+ * the above will allow for multiple commands in a task with independent option, switch, and environment variable tracking
33
+
34
+ Examples (see the [Use](#use) section for outputs):
35
+ require 'rototiller'
36
+
37
+ desc "task dependencies work. this one also uses an environment variable"
38
+ rototiller_task :parent_task do |task|
39
+ # most method initializers take either a hash, or block syntax (see next task)
40
+ task.add_env({:name => 'RANDOM_VAR', :default => 'default value'})
41
+ task.add_command({:name => "echo 'i am testing everything with $RANDOM_VAR = #{ENV['RANDOM_VAR']}'"})
42
+ end
43
+
44
+ desc "override command-name with environment variable"
45
+ rototiller_task :test => :parent_task do |task|
46
+ # block syntax here. We give up some lines for more readability
47
+ task.add_command do |cmd|
48
+ cmd.name = 'test'
49
+ cmd.override_env = 'ECHO_EXECUTABLE'
50
+ end
51
+ task.add_flag({:name => '-f', :default => 'Rakefile'})
52
+ end
53
+
54
+ desc "override flag values with environment variables"
55
+ rototiller_task :test_flag_env do |task|
56
+ task.add_command do |cmd|
57
+ cmd.name = 'test'
58
+ end
59
+ task.add_flag do |flag|
60
+ flag.name = '-f'
61
+ flag.default = 'Rakefile'
62
+ flag.override_env = 'FLAG_VALUE'
63
+ end
64
+ end
65
+
66
+ desc "do not include flag if the final value (either the default or override_env) is nil or empty and not required. add and control switches or boolean flags"
67
+ rototiller_task :test_flag_env do |task|
68
+ task.add_command do |cmd|
69
+ cmd.name = 'test'
70
+ end
71
+ task.add_flag do |flag|
72
+ flag.name = '-f'
73
+ flag.default = ''
74
+ flag.override_env = 'FLAG_VALUE'
75
+ flag.required = false
76
+ end
77
+ # examples:
78
+ # add a boolean option (switch)
79
+ #task.add_flag({:name => '--switch1', :is_boolean => true})
80
+ # add a switch which defaults to "off"
81
+ #task.add_flag({:name => '-s', :default => '', :is_boolean => true})
82
+ # add a switch with environment override
83
+ #task.add_flag({:name => '--switch3', :is_boolean => true, :override_env => 'TEST_FLAG_ENV_SWITCH3'})
84
+ end
85
+
86
+
87
+ desc "override command argument values with environment variables"
88
+ rototiller_task :test_arg_env do |task|
89
+ task.add_command do |cmd|
90
+ cmd.name = 'ls'
91
+ cmd.argument = 'Rakefile'
92
+ cmd.argument_override_env = 'FILENAME'
93
+ end
94
+ end
95
+
96
+ <a name="use"></a>
97
+ ## Use
98
+ (with the above sample Rakefile)
99
+
100
+ $) rake -T
101
+ rake parent_task # some parent task
102
+ rake test # test all the things
103
+
104
+ $) rake -D
105
+ rake parent_task
106
+ task dependencies work. this one also uses an environment variable
107
+ rake test
108
+ override command-name with environment variable
109
+
110
+ # added environment variable defaults are set, implicitly, if not found
111
+ # this way, their value can be used in the task
112
+ $) rake test
113
+ INFO: The environment variable: 'RANDOM_VAR' was found with value: 'default value':
114
+ i am testing everything with $RANDOM_VAR = default value
115
+ The CLI flag -f will be used with value Rakefile.
116
+
117
+ $) rake parent_task RANDOM_VAR=redrum
118
+ INFO: The environment variable: 'RANDOM_VAR' was found with value: 'redrum':
119
+ i am testing everything with $RANDOM_VAR = redrum
120
+
121
+ $) rake test ECHO_EXECUTABLE='ls' --verbose
122
+ INFO: The environment variable: 'RANDOM_VAR' was found with value: 'default value':
123
+ echo 'i am testing everything with $RANDOM_VAR = default value'
124
+ i am testing everything with $RANDOM_VAR = default value
125
+ The CLI flag -f will be used with value Rakefile.
126
+
127
+ ls -f Rakefile
128
+ Rakefile
129
+
130
+ $) rake test_flag_env
131
+ The CLI flag -f will be used with value Rakefile.
132
+ $) echo $?
133
+ 0
134
+
135
+ $) rake test_flag_env --verbose
136
+ The CLI flag -f will be used with value Rakefile.
137
+
138
+ test -f Rakefile
139
+
140
+ $) rake test_flag_env --verbose FLAG_VALUE='README.md'
141
+ The CLI flag -f will be used with value README.md.
142
+
143
+ test -f README.md
144
+
145
+ $) rake test_flag_env --verbose FLAG_VALUE='nonesuch'
146
+ The CLI flag -f will be used with value README.md.
147
+
148
+ test -f README.md
149
+ test -f nonesuch failed
150
+
151
+ $) rake test_arg_env
152
+ Rakefile
153
+
154
+ $) rake test_arg_env FILENAME=README.md
155
+ README.md
156
+
157
+ ## Issues
158
+
159
+ * none. it's perfect
160
+ * [Jira: Rototiller](https://tickets.puppetlabs.com/issues/?jql=project%20%3D%20QA)
42
161
 
43
162
  ## More Documentation
44
163
 
45
-
46
- Rototiller is documented using yard
47
- to view yard docs
164
+ Rototiller is documented using yard
165
+ to view yard docs, including internal Classes and Modules:
48
166
 
49
167
  First build a local copy of the gem
50
168
 
51
- $ bundle exec rake build
52
-
169
+ $) bundle exec rake build
170
+
53
171
  Next start the yard server
54
172
 
55
- $ bundle exec yard server
56
-
57
- Finally navigate to http://0.0.0.0:8808/ to view the documentation
173
+ $) bundle exec yard server
174
+
175
+ Finally navigate to http://0.0.0.0:8808/ to view the documentation
176
+
177
+ ## Maintainers
178
+ * [Zach Reichert](zach.reichert@puppetlabs.com), github:[zreichert](https://github.com/zreichert), jira:zach.reichert
179
+ * [Eric Thompson](erict@puppetlabs.com), github:[er0ck](https://github.com/er0ck), jira:erict
180
+ * [QA](qa-team@puppetlabs.com)
data/Rakefile CHANGED
@@ -1,56 +1,72 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rspec/core/rake_task'
3
+ require 'rototiller'
3
4
 
4
5
  task :default => :test
5
6
 
6
7
  desc "Run spec tests"
7
8
  RSpec::Core::RakeTask.new(:test) do |t|
8
9
  t.rspec_opts = ['--color']
9
- t.pattern = 'spec/'
10
+ t.pattern = ENV['SPEC_PATTERN']
10
11
  end
11
12
 
13
+ task :test => [:check_test]
14
+
12
15
  task :generate_host_config do |t, args|
13
- if ENV["BEAKER_CONFIG"]
14
- next
15
- end
16
16
 
17
17
  target = ENV["TEST_TARGET"] || 'centos7-64'
18
- generate = "bundle exec beaker-hostgenerator"
18
+ generate = "beaker-hostgenerator"
19
19
  generate += " #{target}"
20
20
  generate += " > acceptance/hosts.cfg"
21
21
  sh generate
22
22
  sh "cat acceptance/hosts.cfg"
23
23
  end
24
24
 
25
- task acceptance: :generate_host_config
26
-
27
- desc 'Run acceptance tests for Rototiller'
28
- task :acceptance do |t, args|
29
-
30
- config = ENV["BEAKER_CONFIG"] || 'acceptance/hosts.cfg'
31
-
32
- preserve_hosts = ENV["BEAKER_PRESERVEHOSTS"] || 'never'
33
- type = 'pe'
34
- keyfile = ENV["BEAKER_KEYFILE"] || "#{ENV['HOME']}/.ssh/id_rsa-acceptance"
35
- load_path = ENV["BEAKER_LOADPATH"] || 'acceptance/lib'
36
- pre_suite = ENV["BEAKER_PRESUITE"] || 'acceptance/pre-suite'
37
- post_suite = ENV["BEAKER_POSTSUITE"] || ''
38
- test_suite = ENV["BEAKER_TESTSUITE"] || 'acceptance/tests'
39
- opts = ENV["BEAKER_OPTS"] || ''
40
-
41
- beaker = "bundle exec beaker "
42
- beaker += " --xml"
43
- beaker += " --debug"
44
- beaker += " --root-keys"
45
- beaker += " --repo-proxy"
46
- beaker += " --preserve-hosts #{preserve_hosts}" if preserve_hosts != ''
47
- beaker += " --config #{config}" if config != ''
48
- beaker += " --type #{type}" if type != ''
49
- beaker += " --keyfile #{keyfile}" if keyfile != ''
50
- beaker += " --load-path #{load_path}" if load_path != ''
51
- beaker += " --pre-suite #{pre_suite}" if pre_suite != ''
52
- beaker += " --post-suite #{post_suite}" if post_suite != ''
53
- beaker += " --tests #{test_suite}" if test_suite != ''
54
- beaker += " #{opts}" if opts != ''
55
- sh beaker
25
+ rototiller_task :acceptance => [:generate_host_config] do |t|
26
+ # with a hash
27
+ t.add_env({:name => 'TEST_TARGET',:default => 'centos7-64', :message => 'The argument to pass to beaker-hostgenerator'})
28
+
29
+ # with new block syntax
30
+ t.add_flag do |flag|
31
+ flag.name = '--hosts'
32
+ flag.default = 'acceptance/hosts.cfg'
33
+ flag.message = 'The configuration file that Beaker will use'
34
+ flag.override_env = 'BEAKER_HOSTS'
35
+ end
36
+ t.add_flag do |flag|
37
+ flag.name = '--preserve-hosts'
38
+ flag.default = 'onfail'
39
+ flag.message = 'The beaker setting to preserve a provisioned host'
40
+ flag.override_env = 'BEAKER_PRESERVE-HOSTS'
41
+ end
42
+ t.add_flag do |flag|
43
+ flag.name = '--keyfile'
44
+ flag.default ="#{ENV['HOME']}/.ssh/id_rsa-acceptance"
45
+ flag.message = 'The SSH key used to access a SUT'
46
+ flag.override_env = 'BEAKER_KEYFILE'
47
+ end
48
+ t.add_flag do |flag|
49
+ flag.name = '--load-path'
50
+ flag.default = 'acceptance/lib'
51
+ flag.message = 'The load path Beaker will use'
52
+ flag.override_env = "BEAKER_LOAD-PATH"
53
+ end
54
+ t.add_flag do |flag|
55
+ flag.name = '--pre-suite'
56
+ flag.default = 'acceptance/pre-suite'
57
+ flag.message = 'THe path to a directory containing pre-suites'
58
+ flag.override_env = "BEAKER_PRE-SUITE"
59
+ end
60
+ t.add_flag do |flag|
61
+ flag.name = '--tests'
62
+ flag.default = 'acceptance/tests'
63
+ flag.message = 'The path to the tests you want beaker to run'
64
+ flag.override_env = 'BEAKER_TESTS'
65
+ end
66
+
67
+ t.add_command({:name => 'beaker --debug', :override_env => 'BEAKER_EXECUTABLE'})
68
+ end
69
+
70
+ Rototiller::Task::RototillerTask.define_task :check_test do |t|
71
+ t.add_env({:name => 'SPEC_PATTERN', :default => 'spec/', :message => 'The pattern RSpec will use to find tests'})
56
72
  end
data/Rakefile.bak ADDED
@@ -0,0 +1,72 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ require 'rototiller'
4
+
5
+ task :default => :test
6
+
7
+ desc "Run spec tests"
8
+ RSpec::Core::RakeTask.new(:test) do |t|
9
+ t.rspec_opts = ['--color']
10
+ t.pattern = ENV['SPEC_PATTERN']
11
+ end
12
+
13
+ task :test => [:check_test]
14
+
15
+ task :generate_host_config do |t, args|
16
+
17
+ target = ENV["TEST_TARGET"] || 'centos7-64'
18
+ generate = "beaker-hostgenerator"
19
+ generate += " #{target}"
20
+ generate += " > acceptance/hosts.cfg"
21
+ sh generate
22
+ sh "cat acceptance/hosts.cfg"
23
+ end
24
+
25
+ rototiller_task :acceptance => [:generate_host_config] do |t|
26
+ # with a hash
27
+ t.add_env({:name => 'TEST_TARGET',:default => 'centos7-64', :message => 'The argument to pass to beaker-hostgenerator'})
28
+
29
+ # with new block syntax
30
+ t.add_flag do |flag|
31
+ flag.name = '--hosts'
32
+ flag.default = 'acceptance/hosts.cfg'
33
+ flag.message = 'The configuration file that Beaker will use'
34
+ flag.override_env = 'BEAKER_HOSTS'
35
+ end
36
+ t.add_flag do |flag|
37
+ flag.name = '--preserve-hosts'
38
+ flag.default = 'onfail'
39
+ flag.message = 'The beaker setting to preserve a provisioned host'
40
+ flag.override_env = 'BEAKER_PRESERVE-HOSTS'
41
+ end
42
+ t.add_flag do |flag|
43
+ flag.name = '--keyfile'
44
+ flag.default ="#{ENV['HOME']}/.ssh/id_rsa-acceptance"
45
+ flag.message = 'The SSH key used to access a SUT'
46
+ flag.override_env = 'BEAKER_KEYFILE'
47
+ end
48
+ t.add_flag do |flag|
49
+ flag.name = '--load-path'
50
+ flag.default = 'acceptance/lib'
51
+ flag.message = 'The load path Beaker will use'
52
+ flag.override_env = "BEAKER_LOAD-PATH"
53
+ end
54
+ t.add_flag do |flag|
55
+ flag.name = '--pre-suite'
56
+ flag.default = 'acceptance/pre-suite'
57
+ flag.message = 'THe path to a directory containing pre-suites'
58
+ flag.override_env = "BEAKER_PRE-SUITE"
59
+ end
60
+ t.add_flag do |flag|
61
+ flag.name = '--tests'
62
+ flag.default = 'acceptance/tests'
63
+ flag.message = 'The path to the tests you want beaker to run'
64
+ flag.override_env = 'BEAKER_TESTS'
65
+ end
66
+
67
+ t.add_command({:name => 'beaker --debug', :override_env => 'BEAKER_EXECUTABLE'})
68
+ end
69
+
70
+ Rototiller::Task::RototillerTask.define_task :check_test do |t|
71
+ t.add_env({:name => 'SPEC_PATTERN', :default => 'spec/', :message => 'The pattern RSpec will use to find tests'})
72
+ end
@@ -3,12 +3,8 @@ require 'rototiller/task/rototiller_task'
3
3
  module Rake
4
4
  module DSL
5
5
 
6
- def acceptance_task(*args, &block)
7
- # Default task description
8
- # can be overridden with 'desc' method
9
- desc "Tests in the 'Acceptance' tier" unless ::Rake.application.last_comment
10
- Rototiller::Task::RototillerTask.define_task :acceptance, &block
6
+ def rototiller_task(*args, &block)
7
+ Rototiller::Task::RototillerTask.define_task(*args, &block)
11
8
  end
12
-
13
9
  end
14
10
  end
@@ -2,13 +2,17 @@ require 'rototiller/utilities/env_var'
2
2
  require 'rototiller/utilities/param_collection'
3
3
  require 'rototiller/utilities/env_collection'
4
4
  require 'rototiller/utilities/flag_collection'
5
+ require 'rototiller/utilities/command_flag'
6
+ require 'rototiller/utilities/command'
7
+ require 'rototiller/utilities/block_syntax_object'
5
8
  require 'rake/tasklib'
6
9
 
7
10
  module Rototiller
8
11
  module Task
9
12
  class RototillerTask < ::Rake::TaskLib
10
- attr_accessor :name
11
- attr_accessor :command
13
+ #TODO rename instance vars and methods to not match sub blocks
14
+ attr_reader :name
15
+ attr_reader :command
12
16
 
13
17
  # Whether or not to fail Rake when an error occurs (typically when
14
18
  # examples fail). Defaults to `true`.
@@ -20,7 +24,9 @@ module Rototiller
20
24
  def initialize(*args, &task_block)
21
25
  @name = args.shift
22
26
  @fail_on_error = true
23
- @command = 'echo empty RototillerTask. You should define a command, send a block, or EnvVar to track.'
27
+ #TODO refactor or remove
28
+ @command = Rototiller::Command.new
29
+ @command.name = 'echo empty RototillerTask. You should define a command, send a block, or EnvVar to track.'
24
30
  # rake's in-task implied method is true when using --verbose
25
31
  @verbose = verbose == true
26
32
  @env_vars = EnvCollection.new
@@ -35,29 +41,72 @@ module Rototiller
35
41
  self.new(*args, &task_block)
36
42
  end
37
43
 
38
- #TODO add arg validation to EnvVar and CommandFlag
39
- # add_env(EnvVar.new(), EnvVar.new(), EnvVar.new())
40
- # add_env('FOO', 'This is how you use FOO', 'default_value')
41
- def add_env(*args)
42
- args.all?{ |arg| arg.is_a?(EnvVar)} ? @env_vars.push(*args) : @env_vars.push(EnvVar.new(*args))
44
+ # adds environment variables to be tracked
45
+ # @param [Hash] args hashes of information about the environment variable
46
+ # @option args [String] :name The environment variable
47
+ # @option args [String] :default The default value for the environment variable
48
+ # @option args [String] :message A message describing the use of this variable
49
+ # @option args [Boolean] :required Is used internally by CommandFlag, ignored for a standalone EnvVar
50
+ #
51
+ # for block {|a| ... }
52
+ # @yield [a] Optional block syntax allows you to specify information about the environment variable, available methods track hash keys
53
+ def add_env(*args,&block)
54
+ raise ArgumentError.new("add_env takes a block or a hash") if !args.empty? && block_given?
55
+ attributes = [:name, :default, :message, :required]
56
+ add_param(@env_vars, EnvVar, attributes, args, {:set_env => true}, &block)
43
57
  end
44
58
 
45
- #TODO add arg validation to CommandFlag
46
- # add_flag(CommandFlag.new(), CommandFlag.new(), CommandFlag.new())
47
- # add_flag('--foo', 'This is how you use --foo', 'default_value')
48
- def add_flag(*args)
49
- args.all?{ |arg| arg.is_a?(CommandFlag)} ? @flags.push(*flags) : @flags.push(CommandFlag.new(*args))
59
+ # adds command line flags to be used in a command
60
+ # @param [Hash] args hashes of information about the command line flag
61
+ # @option args [String] :name The command line flag
62
+ # @option args [String] :value The value for the command line flag
63
+ # @option args [String] :message A message describing the use of this command line flag
64
+ # @option args [String] :override_env An environment variable used to override the flag value
65
+ # @option args [Boolean] :required Indicates whether an error should be raised
66
+ # if the value is nil or empty string, vs not including the flag.
67
+ # @option args [Boolean] :is_boolean Is the flag really a switch? Is it a boolean-flag?
68
+ #
69
+ # for block {|a| ... }
70
+ # @yield [a] Optional block syntax allows you to specify information about the command line flag, available methods track hash keys
71
+ def add_flag(*args, &block)
72
+ raise ArgumentError.new("add_flag takes a block or a hash") if !args.empty? && block_given?
73
+ attributes = [:name, :default, :message, :override_env, :required, :is_boolean]
74
+ add_param(@flags, CommandFlag, attributes, args, &block)
75
+ end
76
+
77
+ # adds command to be executed by task
78
+ # @param [Hash] args hash of information about the command to be executed
79
+ # @option arg [String] :name The command to be executed
80
+ # @option arg [String] :override_env An environment variable used to override the command to be executed by the task
81
+ #
82
+ # for block {|a| ... }
83
+ # @yield [a] Optional block syntax allows you to specify information about command, available methods track hash keys
84
+ def add_command(args={}, &block)
85
+ attributes = [:name, :override_env, :argument, :argument_override_env]
86
+ if block_given?
87
+ attribute_hash = pull_params_from_block(attributes, &block).to_h
88
+ else
89
+ attribute_hash = args
90
+ end
91
+ @command = Rototiller::Command.new(attribute_hash)
50
92
  end
51
93
 
52
94
  private
53
95
 
54
96
  # @private
55
- def run_task
97
+ def print_messages
56
98
  puts @flags.format_messages
57
99
  puts @env_vars.format_messages
58
- exit if @env_vars.stop?
100
+ exit_code = 1
101
+ exit exit_code if @env_vars.stop? || @flags.stop?
102
+ end
59
103
 
60
- command_str = @command << @flags.to_s
104
+ # @private
105
+ def run_task
106
+ print_messages
107
+ command_str = [
108
+ (@command.name if @command.name), @flags.to_s, (@command.argument if @command.argument)
109
+ ].delete_if{ |i| [nil, '', false].any?{|forbidden| i == forbidden}}.join(' ')
61
110
  puts command_str if @verbose
62
111
 
63
112
  return if system(command_str)
@@ -75,7 +124,7 @@ module Rototiller
75
124
  def define(args, &task_block)
76
125
  # Default task description
77
126
  # can be overridden with standard 'desc' DSL method
78
- desc "RototillerTask: A Task with optional environment variable and command flag tracking" unless ::Rake.application.last_comment
127
+ desc 'RototillerTask: A Task with optional environment-variable and command-flag tracking' unless ::Rake.application.last_description
79
128
 
80
129
  task(@name, *args) do |_, task_args|
81
130
  RakeFileUtils.__send__(:verbose, @verbose) do
@@ -90,6 +139,34 @@ module Rototiller
90
139
  def set_verbose(verbosity=true)
91
140
  @verbose = verbosity
92
141
  end
142
+
143
+ # @private
144
+ def add_param(collection, param_class, param_array, args, opts={}, &block)
145
+
146
+ if block_given?
147
+
148
+ param_hash = pull_params_from_block(param_array, &block).to_h
149
+ param_hash[:set_env] = true if opts[:set_env]
150
+ collection.push(param_class.new(param_hash))
151
+ else
152
+
153
+ args.each do |arg|
154
+
155
+ #FIXME: add a test for this
156
+ raise ArgumentError.new("Argument must be a Hash. Received: '#{arg.class}'") unless arg.is_a?(Hash)
157
+ arg[:set_env] = true if opts[:set_env]
158
+ collection.push(param_class.new(arg))
159
+ end
160
+ end
161
+ end
162
+
163
+ # @private
164
+ def pull_params_from_block(param_array, &block)
165
+
166
+ block_syntax_obj = Rototiller::Block_syntax.new(param_array)
167
+ yield(block_syntax_obj)
168
+ block_syntax_obj
169
+ end
93
170
  end
94
171
  end
95
172
  end
@@ -0,0 +1,16 @@
1
+ module Rototiller
2
+ class Block_syntax
3
+
4
+ def initialize(param_array)
5
+ self.class.class_eval { param_array.each { |i| attr_accessor i } }
6
+ end
7
+
8
+ def to_h
9
+ h = Hash.new
10
+ self.instance_variables.each do |var|
11
+ h[var.to_s.delete('@').to_sym] = self.instance_variable_get(var)
12
+ end
13
+ h
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ require 'rototiller/utilities/env_var'
2
+ module Rototiller
3
+ class Command
4
+
5
+ include ColorText
6
+
7
+ # @return [String] the command to be used, could be considered a default
8
+ attr_accessor :name
9
+
10
+ # @return [EnvVar] the ENV that is equal to this command
11
+ attr_reader :override_env
12
+
13
+ # @return [String, nil] the value that should be used as an argument to the given command
14
+ attr_reader :argument
15
+
16
+ # @return [EnvVar] the ENV that is equal to the argument to be used with this command
17
+ attr_reader :argument_override_env
18
+
19
+ # Creates a new instance of CommandFlag, holds information about desired state of a command
20
+ # @param [Hash] attribute_hash hashes of information about the command
21
+ # @option attribute_hash [String] :command The command
22
+ # @option attribute_hash [String] :override_env The environment variable that can override this command
23
+ def initialize(attribute_hash = {})
24
+
25
+ # check if an override_env is provided
26
+ if attribute_hash[:override_env]
27
+ @override_env = EnvVar.new({:name => attribute_hash[:override_env], :default => attribute_hash[:name]})
28
+ @name = @override_env.value
29
+ else
30
+ @name = attribute_hash[:name]
31
+ end
32
+
33
+ # check if an argument_override_env is provided
34
+ if attribute_hash[:argument_override_env]
35
+ @argument_override_env = EnvVar.new({:name => attribute_hash[:argument_override_env], :default => attribute_hash[:argument]})
36
+ @argument = @argument_override_env.value
37
+ else
38
+ @argument = attribute_hash[:argument]
39
+ end
40
+ end
41
+ end
42
+ end
43
+
@@ -1,4 +1,5 @@
1
1
  require 'rototiller/utilities/color_text'
2
+ require 'rototiller/utilities/env_var'
2
3
 
3
4
  class CommandFlag
4
5
 
@@ -10,26 +11,113 @@ class CommandFlag
10
11
  # @return [true, false, nil, String] the value if any of the flag
11
12
  attr_reader :value
12
13
 
14
+ # @return [EnvVar] the ENV that is equal to this flag
15
+ attr_reader :override_env
16
+
17
+ # @return [Boolean] whether the flag is required or not
18
+ attr_reader :required
19
+
20
+ # @return [true, nil] if the state of the EnvVar requires the task to stop
21
+ attr_reader :stop
22
+
23
+ # @return [true, nil] if this flag/option is really a switch (boolean flag)
24
+ attr_reader :is_boolean
25
+
13
26
  # Creates a new instance of CommandFlag, holds information about desired state of a CLI flag
14
- # @param flag [String] the flag to be set on a CLI '-v' or '--verbose'
15
- # @param message [String] the message describing the Flag
16
- # @param value [String] the value to use as the value if one is required
17
- def initialize(flag, value=nil, message)
18
- @flag = flag
19
- @message = message
20
- @value = value
27
+ # @param [Hash] attribute_hash hashes of information about the command line flag
28
+ # @option attribute_hash [String] :name The command line flag
29
+ # @option attribute_hash [String] :value The value for the command line flag
30
+ # @option attribute_hash [String] :message A message describing the use of this command line flag
31
+ # @option attribute_hash [String] :override_env The environment variable that can override this flags value
32
+ # @option attribute_hash [Boolean] :is_boolean Is the flag really a switch? Is it a boolean-flag?
33
+ # @option attribute_hash [Boolean] :required Indicates whether an error should be raised
34
+ # if the final value is nil or empty string, vs not including the flag.
35
+ def initialize(attribute_hash)
36
+ validate_attribute_hash(attribute_hash)
37
+
38
+ @original_name = attribute_hash[:name]
39
+ @message = attribute_hash[:message]
40
+ @is_boolean = attribute_hash[:is_boolean] || false
41
+
42
+ # handle :required
43
+ attribute_hash[:required].is_a?(String) ? attribute_hash[:required] = (attribute_hash[:required].downcase == 'true') : attribute_hash[:required]
44
+ @required = ( !!attribute_hash[:required] == attribute_hash[:required] ? attribute_hash[:required] : true)
45
+
46
+ # handle the flag/switch name
47
+ if attribute_hash[:name] && !attribute_hash[:is_boolean]
48
+ @flag = attribute_hash[:name]
49
+ else
50
+ # default takes precedence in case the default state is "off" aka: empty
51
+ default_value = attribute_hash[:default] || attribute_hash[:name]
52
+
53
+ # FIXME: whoa complexity. see fixme below
54
+ # this looks a lot like below. we need a method to handle override_env and the logic here for switches vs. options
55
+ # but we're just gonna rip all this out when CommandSwitch inherits from future CommandOption
56
+ if attribute_hash[:override_env]
57
+ # Create a new EnvVar instance and ask it what the value is
58
+ @override_env = EnvVar.new({:name => attribute_hash[:override_env], :default => default_value})
59
+ @flag = @override_env.value
60
+ else
61
+ @flag = default_value
62
+ end
63
+ end
64
+
65
+ # FIXME: this is getting complex. we should not be doing all these complex if/then in here
66
+ # we should inherit from CommandOption to form CommandSwitch which overrides is_boolean
67
+ # make is_boolean protected (private within a module, parent/child, or similar)
68
+ if @is_boolean
69
+ @value = ''
70
+ else
71
+ if attribute_hash[:default] && !attribute_hash[:override_env]
72
+ # the default is the implied hard coded value
73
+ @value = attribute_hash[:default]
74
+ else
75
+ # Create a new EnvVar instance and ask it what the value is
76
+ @override_env = EnvVar.new({:name => attribute_hash[:override_env], :default => attribute_hash[:default], :required => @required})
77
+
78
+ @value = @override_env.value
79
+ @stop = @override_env.stop
80
+ end
81
+ end
21
82
  end
22
83
 
23
84
  # The formatted message to be displayed to the user
24
85
  # @return [String] the CommandFlag's message, formatted with color
25
86
  def message
26
- green_text(@message) << "\n" << describe_flag_state
87
+ @message ? green_text(@message) << "\n" << describe_flag_state : describe_flag_state
27
88
  end
28
89
 
29
90
  private
30
91
  def describe_flag_state
31
- only_flag = "The CLI flag #{@flag} will be used, no value was provided."
32
- flag_with_value = "The CLI flag #{@flag} will be used with value #{@value}."
33
- green_text(@value.nil? ? only_flag : flag_with_value)
92
+ if @stop
93
+ required_env = "The CLI flag '#{@flag}' needs a value.\nYou can specify this value with the environment variable '#{override_env.var}'"
94
+ return red_text(required_env)
95
+ elsif !@required && (@value.nil? || @value.empty?)
96
+ flag_without_value = "The CLI flag #{@flag} has no value assigned and will not be included."
97
+ return yellow_text(flag_without_value)
98
+ else
99
+ if @is_boolean
100
+ has_flag_name = (@flag != '') && (@flag != nil)
101
+ if has_flag_name
102
+ flag_with_value = "The CLI switch '#{@flag}' will be used."
103
+ else
104
+ flag_with_value = "The CLI switch '#{@original_name}' will NOT be used."
105
+ return yellow_text(flag_with_value)
106
+ end
107
+ else
108
+ flag_with_value = "The CLI flag '#{@flag}' will be used with value '#{@value}'."
109
+ end
110
+ return green_text(flag_with_value)
111
+ end
112
+ end
113
+
114
+ def validate_attribute_hash(h)
115
+ # validate the contents of the hash
116
+ error = String.new
117
+ error << "A 'name' is required\n" unless h[:name]
118
+ error << "Cannot use 'required' with 'is_boolean'\n" unless !(h[:required] && h[:is_boolean])
119
+ error << "Must specify a 'default' or an 'override_env' unless 'is_boolean' is true\n" unless h[:default] || h[:override_env] || h[:is_boolean]
120
+
121
+ raise(ArgumentError, error) unless error.empty?
34
122
  end
35
123
  end
@@ -7,9 +7,4 @@ class EnvCollection < ParamCollection
7
7
  super
8
8
  end
9
9
 
10
- # Do any of the contents of this ParamCollection require the task to stop
11
- # @return [true, nil] should the values of this ParamCollection stop the task
12
- def stop?
13
- @collection.any?{ |param| param.stop }
14
- end
15
10
  end
@@ -1,10 +1,20 @@
1
1
  require 'rototiller/utilities/color_text'
2
2
 
3
3
  class EnvVar
4
-
4
+ MESSAGE_TYPES = {:nodefault_noexist=>0, :exist=>1, :default_noexist=>2, :not_required=>3}
5
5
  include ColorText
6
6
 
7
- attr_accessor :var, :message, :default
7
+ # @return [String] the value of the :name argument
8
+ attr_accessor :var
9
+
10
+ # @return [String] the value of the :message argument
11
+ attr_accessor :message
12
+
13
+ # @return [String] the value of the :default argument
14
+ attr_accessor :default
15
+
16
+ # @return [true, nil] If the env_var should error if no value is set. Used internally by CommandFlag, ignored for standalone EnvVar.
17
+ attr_reader :required
8
18
 
9
19
  # @return [Symbol] the debug level of the message, ':warning', ':error', ':info'
10
20
  attr_reader :message_level
@@ -12,51 +22,109 @@ class EnvVar
12
22
  # @return [true, nil] if the state of the EnvVar requires the task to stop
13
23
  attr_reader :stop
14
24
 
25
+ # @return [String] the value of the ENV based on specified default and environment state
26
+ attr_reader :value
27
+
15
28
  # Creates a new instance of EnvVar, holds information about the ENV in the environment
16
- # @param var [String] the ENV in the environment, 'HOME'
17
- # @param message [String] the message describing the ENV
18
- # @param default [String] the value to use as the default if the ENV is not present
19
- def initialize(var, default=false, message)
20
- @var = var
21
- @message = message
22
- @default = default
23
- set_message_level
24
- end
29
+ # @param [Hash] attribute_hash hash of information about the environment variable
30
+ # @option attribute_hash [String] :name The environment variable
31
+ # @option attribute_hash [String] :default The default value for the environment variable
32
+ # @option attribute_hash [String] :message A message describing the use of this variable
33
+ # @option attribute_hash [Boolean] :required Used internally by CommandFlag, ignored for a standalone EnvVar
34
+ def initialize(attribute_hash)
35
+ raise(ArgumentError, 'A name must be supplied to add_env') unless attribute_hash[:name]
36
+ @var = attribute_hash[:name]
37
+ @message = attribute_hash[:message]
38
+ @default = attribute_hash[:default]
39
+ @set_env = attribute_hash[:set_env] || false
40
+ attribute_hash[:required].is_a?(String) ? attribute_hash[:required] = (attribute_hash[:required].downcase == 'true') : attribute_hash[:required]
41
+ @required = ( !!attribute_hash[:required] == attribute_hash[:required] ? attribute_hash[:required] : true)
25
42
 
26
- # The value of the ENV determined by the EnvVar class
27
- # @return [String] the value determined by the EnvVar class
28
- def value
29
- ENV[@var] || @default
43
+ reset
30
44
  end
31
45
 
32
46
  # The formatted message to be displayed to the user
33
47
  # @return [String] the EnvVar's message, formatted for color and meaningful to the state of the EnvVAr
34
48
  def message
35
49
  if message_level == :error
36
- red_text("The ENV #{@var} is required, #{@message}")
50
+ level_str = 'ERROR:'
37
51
  elsif message_level == :info
38
- green_text("The ENV #{@var} was found in the environment with the value #{value}")
52
+ level_str = 'INFO:'
39
53
  elsif message_level == :warning
40
- yellow_text("WARNING: the ENV #{@var} is not set, proceeding with default value: #{@default}")
54
+ level_str = 'WARNING:'
55
+ end
56
+ message_prepend = "#{level_str} The environment variable: '#{@var}'"
57
+ if get_message_type == MESSAGE_TYPES[:default_noexist]
58
+ return yellow_text("#{message_prepend} is not set. Proceeding with default value: '#{@default}': #{@message}")
59
+ end
60
+ if get_message_type == MESSAGE_TYPES[:not_required]
61
+ return yellow_text("#{message_prepend} is not set, but is not required. Proceeding with no flag: #{@message}")
62
+ end
63
+ if get_message_type == MESSAGE_TYPES[:exist]
64
+ return green_text("#{message_prepend} was found with value: '#{ENV[@var]}': #{@message}")
41
65
  end
66
+ if get_message_type == MESSAGE_TYPES[:nodefault_noexist]
67
+ return red_text("#{message_prepend} is required: #{@message}")
68
+ end
69
+ end
70
+
71
+ # If any of these variables are assigned a new value after this object's creation, reset @value and @message_level.
72
+ def var=(var)
73
+ @var = var
74
+ reset
75
+ end
76
+
77
+ def default=(default)
78
+ @default = default
79
+ reset
80
+ end
81
+
82
+ def message=(message)
83
+ @message = message
84
+ reset
85
+ end
86
+
87
+ def required=(required)
88
+ @required = required
89
+ reset
42
90
  end
43
91
 
44
92
  private
93
+ def reset
94
+ # TODO should an env automatically set the ENV?
95
+ @value = ENV[@var] || @default
96
+ ENV[@var] = @value if @set_env
97
+ set_message_level
98
+ end
99
+
45
100
  def check
46
101
  ENV.key?(@var)
47
102
  end
48
103
 
49
- def set_message_level
50
- if !@default && !check
104
+ def get_message_type
105
+ if (value.nil? || value.empty?) && !required
106
+ MESSAGE_TYPES[:not_required]
107
+ elsif !@default && !check
51
108
  # ENV is not Present and it has no default value
52
- @message_level = :error
53
- @stop = true
54
- elsif !@default && check || @default && check
55
- # ENV is present and it has no default value
56
- @message_level = :info
109
+ MESSAGE_TYPES[:nodefault_noexist]
110
+ elsif check
111
+ # ENV is present; may or may not have default, who cares
112
+ MESSAGE_TYPES[:exist]
57
113
  elsif @default && !check
58
114
  # ENV is not present and it has default value
59
- @message_level = :warning
115
+ MESSAGE_TYPES[:default_noexist]
116
+ end
117
+ end
118
+
119
+ def set_message_level
120
+ case get_message_type
121
+ when MESSAGE_TYPES[:nodefault_noexist]
122
+ @message_level = :error
123
+ @stop = true
124
+ when MESSAGE_TYPES[:exist], MESSAGE_TYPES[:default_noexist], MESSAGE_TYPES[:not_required]
125
+ @message_level = :info
126
+ else
127
+ raise 'EnvVar: message type not supported'
60
128
  end
61
129
  end
62
130
  end
@@ -14,13 +14,15 @@ class FlagCollection < ParamCollection
14
14
  flag_str = String.new
15
15
 
16
16
  @collection.each do |flag|
17
- if flag.value.nil?
18
- flag_str << ' ' << flag.flag
17
+ if (flag.value.nil? || flag.value.empty?) && !flag.required
18
+ #do nothing
19
+ elsif flag.value.nil?
20
+ flag_str << flag.flag << ' '
19
21
  else
20
- flag_str << ' ' << flag.flag << ' ' << flag.value
22
+ flag_str << flag.flag << ' ' << flag.value << ' '
21
23
  end
22
24
  end
23
25
 
24
- flag_str
26
+ flag_str.rstrip
25
27
  end
26
28
  end
@@ -63,5 +63,11 @@ class ParamCollection
63
63
  end
64
64
  end
65
65
 
66
+ # Do any of the contents of this ParamCollection require the task to stop
67
+ # @return [true, nil] should the values of this ParamCollection stop the task
68
+ def stop?
69
+ @collection.any?{ |param| param.stop }
70
+ end
71
+
66
72
  private :filter_contents, :check_classes
67
73
  end
@@ -1,5 +1,5 @@
1
1
  module Rototiller
2
2
  module Version
3
- STRING = '0.0.0.b'
3
+ STRING = '0.1.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rototiller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0.b
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
- - Puppetlabs
7
+ - Puppet Labs
8
+ - Zach Reichert
9
+ - Eric Thompson
8
10
  autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2016-03-28 00:00:00.000000000 Z
13
+ date: 2016-05-16 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: rake
@@ -16,15 +18,15 @@ dependencies:
16
18
  requirements:
17
19
  - - '>='
18
20
  - !ruby/object:Gem::Version
19
- version: '0'
21
+ version: 0.9.0
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
23
25
  requirements:
24
26
  - - '>='
25
27
  - !ruby/object:Gem::Version
26
- version: '0'
27
- description: Puppetlabs tool for building rake tasks
28
+ version: 0.9.0
29
+ description: Puppet Labs tool for building rake tasks
28
30
  email:
29
31
  - qa@puppetlabs.com
30
32
  executables: []
@@ -36,11 +38,14 @@ files:
36
38
  - LICENSE.md
37
39
  - README.md
38
40
  - Rakefile
41
+ - Rakefile.bak
39
42
  - lib/rototiller.rb
40
43
  - lib/rototiller/rake/dsl/dsl_extention.rb
41
44
  - lib/rototiller/task/flags/cli_flags.rb
42
45
  - lib/rototiller/task/rototiller_task.rb
46
+ - lib/rototiller/utilities/block_syntax_object.rb
43
47
  - lib/rototiller/utilities/color_text.rb
48
+ - lib/rototiller/utilities/command.rb
44
49
  - lib/rototiller/utilities/command_flag.rb
45
50
  - lib/rototiller/utilities/env_collection.rb
46
51
  - lib/rototiller/utilities/env_var.rb
@@ -63,14 +68,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
63
68
  version: '0'
64
69
  required_rubygems_version: !ruby/object:Gem::Requirement
65
70
  requirements:
66
- - - '>'
71
+ - - '>='
67
72
  - !ruby/object:Gem::Version
68
- version: 1.3.1
73
+ version: '0'
69
74
  requirements: []
70
75
  rubyforge_project:
71
76
  rubygems_version: 2.6.2
72
77
  signing_key:
73
78
  specification_version: 4
74
- summary: Puppetlabs rake tool
79
+ summary: Puppet Labs rake tool
75
80
  test_files: []
76
81
  has_rdoc: