whenever 0.8.0 → 0.8.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.
data/CHANGELOG.md CHANGED
@@ -3,6 +3,19 @@
3
3
  * Time zone support
4
4
 
5
5
 
6
+ ### 0.8.1 / December 22nd, 2012
7
+
8
+ * Fix multiserver roles bug. [Wes Morgan]
9
+
10
+ * Refactor Cap recipes and add tests for them. [Wes Morgan]
11
+
12
+ * Fix file not found error when running under JRuby. [Wes Morgan]
13
+
14
+ * Stop interpolating template attributes with no corresponding value. [Vincent Boisard]
15
+
16
+ * Support for raw cron separated by tabs. [Étienne Barrié]
17
+
18
+
6
19
  ### 0.8.0 / November 8th, 2012
7
20
 
8
21
  * Separate Capistrano recipes to allow custom execution. [Bogdan Gusiev]
data/lib/whenever.rb CHANGED
@@ -2,19 +2,19 @@ require 'thread'
2
2
  require 'active_support/all'
3
3
 
4
4
  module Whenever
5
- autoload :JobList, 'whenever/job_list'
6
- autoload :Job, 'whenever/job'
7
- autoload :CommandLine, 'whenever/command_line'
8
-
5
+ autoload :JobList, 'whenever/job_list'
6
+ autoload :Job, 'whenever/job'
7
+ autoload :CommandLine, 'whenever/command_line'
8
+
9
9
  module Output
10
10
  autoload :Cron, 'whenever/cron'
11
11
  autoload :Redirection, 'whenever/output_redirection'
12
12
  end
13
-
13
+
14
14
  def self.cron(options)
15
15
  Whenever::JobList.new(options).generate_cron_output
16
16
  end
17
-
17
+
18
18
  def self.path
19
19
  Dir.pwd
20
20
  end
@@ -1,4 +1,8 @@
1
+ require 'whenever/capistrano/support'
2
+
1
3
  Capistrano::Configuration.instance(:must_exist).load do
4
+ Whenever::CapistranoSupport.load_into(self)
5
+
2
6
  _cset(:whenever_roles) { :db }
3
7
  _cset(:whenever_options) { {:roles => fetch(:whenever_roles)} }
4
8
  _cset(:whenever_command) { "whenever" }
@@ -9,63 +13,42 @@ Capistrano::Configuration.instance(:must_exist).load do
9
13
  _cset(:whenever_clear_flags) { "--clear-crontab #{fetch :whenever_identifier}" }
10
14
 
11
15
  namespace :whenever do
12
- desc <<-DESC
13
- Update application's crontab entries using Whenever. You can configure \
14
- the command used to invoke Whenever by setting the :whenever_command \
15
- variable, which can be used with Bundler to set the command to \
16
- "bundle exec whenever". You can configure the identifier used by setting \
17
- the :whenever_identifier variable, which defaults to the same value configured \
18
- for the :application variable. You can configure the environment by setting \
19
- the :whenever_environment variable, which defaults to the same value \
20
- configured for the :rails_env variable which itself defaults to "production". \
21
- Finally, you can completely override all arguments to the Whenever command \
22
- by setting the :whenever_update_flags variable. Additionally you can configure \
23
- which servers the crontab is updated on by setting the :whenever_roles variable.
24
- DESC
16
+ desc "Update application's crontab entries using Whenever"
25
17
  task :update_crontab do
26
- options = fetch(:whenever_options)
27
- roles = [options[:roles]].flatten if options[:roles]
18
+ args = {
19
+ :command => fetch(:whenever_command),
20
+ :flags => fetch(:whenever_update_flags),
21
+ :path => fetch(:release_path)
22
+ }
28
23
 
29
- if find_servers(options).any?
30
- # make sure we go through the roles.each loop at least once
31
- roles << :__none if roles.empty?
24
+ if whenever_servers.any?
25
+ whenever_run_commands(args)
32
26
 
33
- roles.each do |role|
34
- if role == :__none
35
- role_arg = ''
27
+ on_rollback do
28
+ if fetch(:previous_release)
29
+ # rollback to the previous release's crontab
30
+ args[:path] = fetch(:previous_release)
36
31
  else
37
- options[:roles] = role
38
- role_arg = " --roles #{role}"
39
- end
40
-
41
- on_rollback do
42
- if fetch :previous_release
43
- run "cd #{fetch :previous_release} && #{fetch :whenever_command} #{fetch :whenever_update_flags}#{role_arg}", options
44
- else
45
- run "cd #{fetch :release_path} && #{fetch :whenever_command} #{fetch :whenever_clear_flags}", options
46
- end
32
+ # clear the crontab if no previous release
33
+ args[:flags] = fetch(:whenever_clear_flags)
47
34
  end
48
35
 
49
- run "cd #{fetch :latest_release} && #{fetch :whenever_command} #{fetch :whenever_update_flags}#{role_arg}", options
36
+ whenever_run_commands(args)
50
37
  end
51
38
  end
52
39
  end
53
40
 
54
- desc <<-DESC
55
- Clear application's crontab entries using Whenever. You can configure \
56
- the command used to invoke Whenever by setting the :whenever_command \
57
- variable, which can be used with Bundler to set the command to \
58
- "bundle exec whenever". You can configure the identifier used by setting \
59
- the :whenever_identifier variable, which defaults to the same value configured \
60
- for the :application variable. Finally, you can completely override all \
61
- arguments to the Whenever command by setting the :whenever_clear_flags variable. \
62
- Additionally you can configure which servers the crontab is cleared on by setting \
63
- the :whenever_roles variable.
64
- DESC
65
-
41
+ desc "Clear application's crontab entries using Whenever"
66
42
  task :clear_crontab do
67
- options = fetch(:whenever_options)
68
- run "cd #{fetch :latest_release} && #{fetch :whenever_command} #{fetch :whenever_clear_flags}", options if find_servers(options).any?
43
+ if whenever_servers.any?
44
+ args = {
45
+ :command => fetch(:whenever_command),
46
+ :flags => fetch(:whenever_clear_flags),
47
+ :path => fetch(:latest_release)
48
+ }
49
+
50
+ whenever_run_commands(args)
51
+ end
69
52
  end
70
53
  end
71
54
  end
@@ -0,0 +1,41 @@
1
+ module Whenever
2
+ module CapistranoSupport
3
+ def self.load_into(capistrano_configuration)
4
+ capistrano_configuration.load do
5
+
6
+ def whenever_options
7
+ fetch(:whenever_options)
8
+ end
9
+
10
+ def whenever_roles
11
+ Array(whenever_options[:roles])
12
+ end
13
+
14
+ def whenever_servers
15
+ find_servers(whenever_options)
16
+ end
17
+
18
+ def whenever_server_roles
19
+ whenever_servers.inject({}) do |map, server|
20
+ map[server] = role_names_for_host(server) & whenever_roles
21
+ map
22
+ end
23
+ end
24
+
25
+ def whenever_run_commands(args)
26
+ unless [:command, :path, :flags].all? { |a| args.include?(a) }
27
+ raise ArgumentError, ":command, :path, & :flags are required"
28
+ end
29
+
30
+ whenever_server_roles.each do |server, roles|
31
+ roles_arg = roles.empty? ? "" : " --roles #{roles.join(',')}"
32
+
33
+ command = "cd #{args[:path]} && #{args[:command]} #{args[:flags]}#{roles_arg}"
34
+ run command, whenever_options.merge(:hosts => server.host)
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
@@ -66,22 +66,23 @@ module Whenever
66
66
  end
67
67
 
68
68
  def write_crontab(contents)
69
- tmp_cron_file = Tempfile.new('whenever_tmp_cron').path
70
- File.open(tmp_cron_file, File::WRONLY | File::APPEND) do |file|
71
- file << contents
72
- end
69
+ tmp_cron_file = Tempfile.open('whenever_tmp_cron')
70
+ tmp_cron_file << contents
71
+ tmp_cron_file.fsync
73
72
 
74
73
  command = ['crontab']
75
74
  command << "-u #{@options[:user]}" if @options[:user]
76
- command << tmp_cron_file
75
+ command << tmp_cron_file.path
77
76
 
78
77
  if system(command.join(' '))
79
78
  action = 'written' if @options[:write]
80
79
  action = 'updated' if @options[:update]
81
80
  puts "[write] crontab file #{action}"
81
+ tmp_cron_file.close!
82
82
  exit(0)
83
83
  else
84
84
  warn "[fail] Couldn't write crontab; try running `whenever' with no options to ensure your schedule file is valid."
85
+ tmp_cron_file.close!
85
86
  exit(1)
86
87
  end
87
88
  end
data/lib/whenever/cron.rb CHANGED
@@ -4,7 +4,7 @@ module Whenever
4
4
  module Output
5
5
  class Cron
6
6
  KEYWORDS = [:reboot, :yearly, :annually, :monthly, :weekly, :daily, :midnight, :hourly]
7
- REGEX = /^(@(#{KEYWORDS.join '|'})|.+ .+ .+ .+ .+.?)$/
7
+ REGEX = /^(@(#{KEYWORDS.join '|'})|.+\s+.+\s+.+\s+.+\s+.+.?)$/
8
8
 
9
9
  attr_accessor :time, :task
10
10
 
data/lib/whenever/job.rb CHANGED
@@ -10,7 +10,7 @@ module Whenever
10
10
  @template = options.delete(:template)
11
11
  @job_template = options.delete(:job_template) || ":job"
12
12
  @roles = Array.wrap(options.delete(:roles))
13
- @options[:output] = Whenever::Output::Redirection.new(options[:output]).to_s if options.has_key?(:output)
13
+ @options[:output] = options.has_key?(:output) ? Whenever::Output::Redirection.new(options[:output]).to_s : ''
14
14
  @options[:environment] ||= :production
15
15
  @options[:path] = Shellwords.shellescape(@options[:path] || Whenever.path)
16
16
  end
@@ -33,7 +33,7 @@ module Whenever
33
33
  def process_template(template, options)
34
34
  template.gsub(/:\w+/) do |key|
35
35
  before_and_after = [$`[-1..-1], $'[0..0]]
36
- option = options[key.sub(':', '').to_sym]
36
+ option = options[key.sub(':', '').to_sym] || key
37
37
 
38
38
  if before_and_after.all? { |c| c == "'" }
39
39
  escape_single_quotes(option)
@@ -1,3 +1,3 @@
1
1
  module Whenever
2
- VERSION = '0.8.0'
2
+ VERSION = '0.8.1'
3
3
  end
@@ -1,7 +1,7 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
2
 
3
3
  class CommandLineTest < Test::Unit::TestCase
4
-
4
+
5
5
  context "A command line write" do
6
6
  setup do
7
7
  File.expects(:exists?).with('config/schedule.rb').returns(true)
@@ -16,16 +16,16 @@ class CommandLineTest < Test::Unit::TestCase
16
16
  #{@task}
17
17
  # End Whenever generated tasks for: My identifier
18
18
  EXPECTED
19
-
19
+
20
20
  assert_equal output, @command.send(:whenever_cron)
21
21
  end
22
-
22
+
23
23
  should "write the crontab when run" do
24
24
  @command.expects(:write_crontab).returns(true)
25
25
  assert @command.run
26
26
  end
27
27
  end
28
-
28
+
29
29
  context "A command line update" do
30
30
  setup do
31
31
  File.expects(:exists?).with('config/schedule.rb').returns(true)
@@ -37,7 +37,7 @@ EXPECTED
37
37
  should "add the cron to the end of the file if there is no existing identifier block" do
38
38
  existing = '# Existing crontab'
39
39
  @command.expects(:read_crontab).at_least_once.returns(existing)
40
-
40
+
41
41
  new_cron = <<-EXPECTED
42
42
  #{existing}
43
43
 
@@ -45,13 +45,13 @@ EXPECTED
45
45
  #{@task}
46
46
  # End Whenever generated tasks for: My identifier
47
47
  EXPECTED
48
-
48
+
49
49
  assert_equal new_cron, @command.send(:updated_crontab)
50
-
50
+
51
51
  @command.expects(:write_crontab).with(new_cron).returns(true)
52
52
  assert @command.run
53
53
  end
54
-
54
+
55
55
  should "replace an existing block if the identifier matches" do
56
56
  existing = <<-EXISTING_CRON
57
57
  # Something
@@ -76,15 +76,15 @@ EXISTING_CRON
76
76
  This shouldn't get replaced
77
77
  # End Whenever generated tasks for: Other identifier
78
78
  NEW_CRON
79
-
79
+
80
80
  @command.expects(:read_crontab).at_least_once.returns(existing)
81
81
  assert_equal new_cron, @command.send(:updated_crontab)
82
-
82
+
83
83
  @command.expects(:write_crontab).with(new_cron).returns(true)
84
84
  assert @command.run
85
85
  end
86
86
  end
87
-
87
+
88
88
  context "A command line update that contains backslashes" do
89
89
  setup do
90
90
  @existing = <<-EXISTING_CRON
@@ -97,12 +97,12 @@ EXISTING_CRON
97
97
  @command.expects(:read_crontab).at_least_once.returns(@existing)
98
98
  @command.expects(:whenever_cron).returns(@existing)
99
99
  end
100
-
100
+
101
101
  should "replace the existing block with the backslashes in tact" do
102
102
  assert_equal @existing, @command.send(:updated_crontab)
103
103
  end
104
104
  end
105
-
105
+
106
106
  context "A command line update with an identifier similar to an existing one in the crontab already" do
107
107
  setup do
108
108
  @existing = <<-EXISTING_CRON
@@ -118,7 +118,7 @@ NEW_CRON
118
118
  @command.expects(:read_crontab).at_least_once.returns(@existing)
119
119
  @command.expects(:whenever_cron).returns(@new)
120
120
  end
121
-
121
+
122
122
  should "append the similarly named command" do
123
123
  assert_equal @existing + "\n" + @new, @command.send(:updated_crontab)
124
124
  end
@@ -160,7 +160,7 @@ NEW_CRON
160
160
  assert @command.run
161
161
  end
162
162
  end
163
-
163
+
164
164
  context "A command line update with no identifier" do
165
165
  setup do
166
166
  File.expects(:exists?).with('config/schedule.rb').returns(true)
@@ -183,7 +183,7 @@ NEW_CRON
183
183
  should "exit with write and clear" do
184
184
  @command = Whenever::CommandLine.new(:write => true, :clear => true)
185
185
  end
186
-
186
+
187
187
  should "exit with write and update" do
188
188
  @command = Whenever::CommandLine.new(:write => true, :update => true)
189
189
  end
@@ -192,7 +192,7 @@ NEW_CRON
192
192
  @command = Whenever::CommandLine.new(:update => true, :clear => true)
193
193
  end
194
194
  end
195
-
195
+
196
196
  context "A runner where the environment is overridden using the :set option" do
197
197
  setup do
198
198
  @output = Whenever.cron :set => 'environment=serious', :string => \
@@ -205,12 +205,12 @@ NEW_CRON
205
205
  end
206
206
  file
207
207
  end
208
-
208
+
209
209
  should "output the runner using the override environment" do
210
210
  assert_match two_hours + %( cd /my/path && script/runner -e serious 'blahblah'), @output
211
211
  end
212
212
  end
213
-
213
+
214
214
  context "A runner where the environment and path are overridden using the :set option" do
215
215
  setup do
216
216
  @output = Whenever.cron :set => 'environment=serious&path=/serious/path', :string => \
@@ -223,12 +223,12 @@ NEW_CRON
223
223
  end
224
224
  file
225
225
  end
226
-
226
+
227
227
  should "output the runner using the overridden path and environment" do
228
228
  assert_match two_hours + %( cd /serious/path && script/runner -e serious 'blahblah'), @output
229
229
  end
230
230
  end
231
-
231
+
232
232
  context "A runner where the environment and path are overridden using the :set option with spaces in the string" do
233
233
  setup do
234
234
  @output = Whenever.cron :set => ' environment = serious& path =/serious/path', :string => \
@@ -241,12 +241,12 @@ NEW_CRON
241
241
  end
242
242
  file
243
243
  end
244
-
244
+
245
245
  should "output the runner using the overridden path and environment" do
246
246
  assert_match two_hours + %( cd /serious/path && script/runner -e serious 'blahblah'), @output
247
247
  end
248
248
  end
249
-
249
+
250
250
  context "A runner where the environment is overridden using the :set option but no value is given" do
251
251
  setup do
252
252
  @output = Whenever.cron :set => ' environment=', :string => \
@@ -259,7 +259,7 @@ NEW_CRON
259
259
  end
260
260
  file
261
261
  end
262
-
262
+
263
263
  should "output the runner using the original environmnet" do
264
264
  assert_match two_hours + %( cd /silly/path && script/runner -e silly 'blahblah'), @output
265
265
  end
@@ -283,7 +283,7 @@ EXISTING_CRON
283
283
 
284
284
  assert_equal existing, @command.send(:prepare, existing)
285
285
  end
286
-
286
+
287
287
  should "trim off the top lines of the file" do
288
288
  @command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier', :cut => '3')
289
289
  existing = <<-EXISTING_CRON
@@ -303,7 +303,7 @@ NEW_CRON
303
303
 
304
304
  assert_equal new_cron, @command.send(:prepare, existing)
305
305
  end
306
-
306
+
307
307
  should "preserve terminating newlines in files" do
308
308
  @command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
309
309
  existing = <<-EXISTING_CRON
@@ -1,7 +1,7 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
2
 
3
3
  class OutputDefinedJobTest < Test::Unit::TestCase
4
-
4
+
5
5
  context "A defined job with a :task" do
6
6
  setup do
7
7
  @output = Whenever.cron \
@@ -13,12 +13,12 @@ class OutputDefinedJobTest < Test::Unit::TestCase
13
13
  end
14
14
  file
15
15
  end
16
-
16
+
17
17
  should "output the defined job with the task" do
18
18
  assert_match /^.+ .+ .+ .+ before during after$/, @output
19
19
  end
20
20
  end
21
-
21
+
22
22
  context "A defined job with a :task and some options" do
23
23
  setup do
24
24
  @output = Whenever.cron \
@@ -30,12 +30,12 @@ class OutputDefinedJobTest < Test::Unit::TestCase
30
30
  end
31
31
  file
32
32
  end
33
-
33
+
34
34
  should "output the defined job with the task and options" do
35
35
  assert_match /^.+ .+ .+ .+ before during after happy birthday$/, @output
36
36
  end
37
37
  end
38
-
38
+
39
39
  context "A defined job with a :task and an option where the option is set globally" do
40
40
  setup do
41
41
  @output = Whenever.cron \
@@ -48,12 +48,12 @@ class OutputDefinedJobTest < Test::Unit::TestCase
48
48
  end
49
49
  file
50
50
  end
51
-
51
+
52
52
  should "output the defined job with the task and options" do
53
53
  assert_match /^.+ .+ .+ .+ before during after happy$/, @output
54
54
  end
55
55
  end
56
-
56
+
57
57
  context "A defined job with a :task and an option where the option is set globally and locally" do
58
58
  setup do
59
59
  @output = Whenever.cron \
@@ -66,12 +66,12 @@ class OutputDefinedJobTest < Test::Unit::TestCase
66
66
  end
67
67
  file
68
68
  end
69
-
69
+
70
70
  should "output the defined job using the local option" do
71
71
  assert_match /^.+ .+ .+ .+ before during after local$/, @output
72
72
  end
73
73
  end
74
-
74
+
75
75
  context "A defined job with a :task and an option that is not set" do
76
76
  setup do
77
77
  @output = Whenever.cron \
@@ -83,16 +83,16 @@ class OutputDefinedJobTest < Test::Unit::TestCase
83
83
  end
84
84
  file
85
85
  end
86
-
87
- should "output the defined job with that option removed" do
88
- assert_match /^.+ .+ .+ .+ before during after$/, @output
86
+
87
+ should "output the defined job with that option left untouched" do
88
+ assert_match /^.+ .+ .+ .+ before during after :option1$/, @output
89
89
  end
90
90
  end
91
-
91
+
92
92
  context "A defined job that uses a :path where none is explicitly set" do
93
93
  setup do
94
94
  Whenever.stubs(:path).returns('/my/path')
95
-
95
+
96
96
  @output = Whenever.cron \
97
97
  <<-file
98
98
  set :job_template, nil
@@ -102,10 +102,10 @@ class OutputDefinedJobTest < Test::Unit::TestCase
102
102
  end
103
103
  file
104
104
  end
105
-
105
+
106
106
  should "default to using the Whenever.path" do
107
107
  assert_match two_hours + %( cd /my/path && blahblah), @output
108
108
  end
109
109
  end
110
110
 
111
- end
111
+ end
@@ -0,0 +1,84 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+
3
+ class OutputJobsForRolesTest < Test::Unit::TestCase
4
+ context "with one role requested and specified on the job" do
5
+ setup do
6
+ @output = Whenever.cron :roles => [:role1], :string => \
7
+ <<-file
8
+ every 2.hours, :roles => [:role1] do
9
+ command "blahblah"
10
+ end
11
+ file
12
+ end
13
+
14
+ should "output the cron job" do
15
+ assert_equal two_hours + " /bin/bash -l -c 'blahblah'\n\n", @output
16
+ end
17
+ end
18
+
19
+ context "with one role requested but none specified on the job" do
20
+ setup do
21
+ @output = Whenever.cron :roles => [:role1], :string => \
22
+ <<-file
23
+ every 2.hours do
24
+ command "blahblah"
25
+ end
26
+ file
27
+ end
28
+
29
+ # this should output the job because not specifying a role means "all roles"
30
+ should "output the cron job" do
31
+ assert_equal two_hours + " /bin/bash -l -c 'blahblah'\n\n", @output
32
+ end
33
+ end
34
+
35
+ context "with no roles requested but one specified on the job" do
36
+ setup do
37
+ @output = Whenever.cron \
38
+ <<-file
39
+ every 2.hours, :roles => [:role1] do
40
+ command "blahblah"
41
+ end
42
+ file
43
+ end
44
+
45
+ # this should output the job because not requesting roles means "all roles"
46
+ should "output the cron job" do
47
+ assert_equal two_hours + " /bin/bash -l -c 'blahblah'\n\n", @output
48
+ end
49
+ end
50
+
51
+ context "with a different role requested than the one specified on the job" do
52
+ setup do
53
+ @output = Whenever.cron :roles => [:role1], :string => \
54
+ <<-file
55
+ every 2.hours, :roles => [:role2] do
56
+ command "blahblah"
57
+ end
58
+ file
59
+ end
60
+
61
+ should "not output the cron job" do
62
+ assert_equal "", @output
63
+ end
64
+ end
65
+
66
+ context "with 2 roles requested and a job defined for each" do
67
+ setup do
68
+ @output = Whenever.cron :roles => [:role1, :role2], :string => \
69
+ <<-file
70
+ every 2.hours, :roles => [:role1] do
71
+ command "role1_cmd"
72
+ end
73
+
74
+ every :hour, :roles => [:role2] do
75
+ command "role2_cmd"
76
+ end
77
+ file
78
+ end
79
+
80
+ should "output both jobs" do
81
+ assert_equal two_hours + " /bin/bash -l -c 'role1_cmd'\n\n0 * * * * /bin/bash -l -c 'role2_cmd'\n\n", @output
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,138 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require File.expand_path(File.dirname(__FILE__) + "/../../lib/whenever/capistrano/support")
3
+
4
+ class CapistranoSupportTestSubject
5
+ include Whenever::CapistranoSupport
6
+ end
7
+
8
+ class CapistranoSupportTest < Test::Unit::TestCase
9
+ context "when using capistrano support module" do
10
+ setup do
11
+ @capistrano = CapistranoSupportTestSubject.new
12
+ configuration = mock
13
+ configuration.stubs(:load).yields(@capistrano)
14
+ Whenever::CapistranoSupport.load_into(configuration)
15
+ end
16
+
17
+ context "#whenever_options" do
18
+ should "return fetch(:whenever_options)" do
19
+ @capistrano.expects(:fetch).with(:whenever_options)
20
+ @capistrano.whenever_options
21
+ end
22
+ end
23
+
24
+ context "#whenever_roles with one role" do
25
+ setup do
26
+ @capistrano.stubs(:whenever_options).returns({:roles => :role1})
27
+ end
28
+
29
+ should "return whenever_options[:roles] as an array" do
30
+ assert_equal [:role1], @capistrano.whenever_roles
31
+ end
32
+ end
33
+
34
+ context "#whenever_roles with no defined roles" do
35
+ setup do
36
+ @capistrano.stubs(:whenever_options).returns({})
37
+ end
38
+
39
+ should "return an empty array" do
40
+ assert_equal [], @capistrano.whenever_roles
41
+ end
42
+ end
43
+
44
+ context "#whenever_servers" do
45
+ should "return the list of servers returned by find_servers" do
46
+ @capistrano.stubs(:whenever_options).returns({})
47
+ @capistrano.stubs(:find_servers).returns([:server1, :server2])
48
+
49
+ assert_equal [:server1, :server2], @capistrano.whenever_servers
50
+ end
51
+ end
52
+
53
+ context "#whenever_server_roles" do
54
+ setup do
55
+ @mock_servers = ["foo", "bar"]
56
+ @capistrano.stubs(:whenever_servers).returns(@mock_servers)
57
+ end
58
+
59
+ should "return a map of servers to their role(s)" do
60
+ @capistrano.stubs(:whenever_roles).returns([:role1, :role2])
61
+ @capistrano.stubs(:role_names_for_host).with("foo").returns([:role1])
62
+ @capistrano.stubs(:role_names_for_host).with("bar").returns([:role2])
63
+ assert_equal({"foo" => [:role1], "bar" => [:role2]}, @capistrano.whenever_server_roles)
64
+ end
65
+
66
+ should "exclude non-requested roles" do
67
+ @capistrano.stubs(:whenever_roles).returns([:role1, :role2])
68
+ @capistrano.stubs(:role_names_for_host).with("foo").returns([:role1, :role3])
69
+ @capistrano.stubs(:role_names_for_host).with("bar").returns([:role2])
70
+ assert_equal({"foo" => [:role1], "bar" => [:role2]}, @capistrano.whenever_server_roles)
71
+ end
72
+
73
+ should "include all roles for servers w/ >1 when they're requested" do
74
+ @capistrano.stubs(:whenever_roles).returns([:role1, :role2, :role3])
75
+ @capistrano.stubs(:role_names_for_host).with("foo").returns([:role1, :role3])
76
+ @capistrano.stubs(:role_names_for_host).with("bar").returns([:role2])
77
+ assert_equal({"foo" => [:role1, :role3], "bar" => [:role2]}, @capistrano.whenever_server_roles)
78
+ end
79
+ end
80
+
81
+ context "#whenever_run_commands" do
82
+ should "require :command arg" do
83
+ assert_raise ArgumentError do
84
+ @capistrano.whenever_run_commands(:options => {}, :path => {}, :flags => {})
85
+ end
86
+ end
87
+
88
+ should "require :path arg" do
89
+ assert_raise ArgumentError do
90
+ @capistrano.whenever_run_commands(:options => {}, :command => {}, :flags => {})
91
+ end
92
+ end
93
+
94
+ should "require :flags arg" do
95
+ assert_raise ArgumentError do
96
+ @capistrano.whenever_run_commands(:options => {}, :path => {}, :command => {})
97
+ end
98
+ end
99
+
100
+ context "with some servers defined" do
101
+ setup do
102
+ @mock_server1, @mock_server2 = mock(), mock()
103
+ @mock_server1.stubs(:host).returns("server1.foo.com")
104
+ @mock_server2.stubs(:host).returns("server2.foo.com")
105
+ @mock_servers = [@mock_server1, @mock_server2]
106
+ end
107
+
108
+ should "call run for each host w/ appropriate role args" do
109
+ @capistrano.stubs(:role_names_for_host).with(@mock_server1).returns([:role1])
110
+ @capistrano.stubs(:role_names_for_host).with(@mock_server2).returns([:role2])
111
+ @capistrano.stubs(:whenever_servers).returns(@mock_servers)
112
+ roles = [:role1, :role2]
113
+ @capistrano.stubs(:whenever_options).returns({:roles => roles})
114
+
115
+ @capistrano.expects(:run).once.with('cd /foo/bar && whenever --flag1 --flag2 --roles role1', {:roles => [:role1, :role2], :hosts => 'server1.foo.com'})
116
+ @capistrano.expects(:run).once.with('cd /foo/bar && whenever --flag1 --flag2 --roles role2', {:roles => [:role1, :role2], :hosts => 'server2.foo.com'})
117
+
118
+ @capistrano.whenever_run_commands(:command => "whenever",
119
+ :path => "/foo/bar",
120
+ :flags => "--flag1 --flag2")
121
+ end
122
+
123
+ should "call run w/ all role args for servers w/ >1 role" do
124
+ @capistrano.stubs(:role_names_for_host).with(@mock_server1).returns([:role1, :role3])
125
+ @capistrano.stubs(:whenever_servers).returns([@mock_servers.first])
126
+ roles = [:role1, :role2, :role3]
127
+ @capistrano.stubs(:whenever_options).returns({:roles => roles})
128
+
129
+ @capistrano.expects(:run).once.with('cd /foo/bar && whenever --flag1 --flag2 --roles role1,role3', {:roles => [:role1, :role2, :role3], :hosts => 'server1.foo.com'})
130
+
131
+ @capistrano.whenever_run_commands(:command => "whenever",
132
+ :path => "/foo/bar",
133
+ :flags => "--flag1 --flag2")
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -218,6 +218,7 @@ class CronTest < Test::Unit::TestCase
218
218
  context "When given raw cron sytax" do
219
219
  should "return the same cron sytax" do
220
220
  crons = ['0 0 27-31 * *', '* * * * *', '2/3 1,9,22 11-26 1-6 *',
221
+ "*\t*\t*\t*\t*",
221
222
  '@reboot', '@yearly', '@annually', '@monthly', '@weekly',
222
223
  '@daily', '@midnight', '@hourly']
223
224
  crons.each do |cron|
@@ -30,6 +30,10 @@ class JobTest < Test::Unit::TestCase
30
30
  assert_equal '/my/path', new_job(:template => ':path').output
31
31
  end
32
32
 
33
+ should "not substitute parameters for which no value is set" do
34
+ assert_equal 'Hello :world', new_job(:template => ':matching :world', :matching => 'Hello').output
35
+ end
36
+
33
37
  should "escape the :path" do
34
38
  assert_equal '/my/spacey\ path', new_job(:template => ':path', :path => '/my/spacey path').output
35
39
  end
data/whenever.gemspec CHANGED
@@ -15,17 +15,11 @@ Gem::Specification.new do |s|
15
15
  s.test_files = `git ls-files -- test/{functional,unit}/*`.split("\n")
16
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
17
  s.require_paths = ["lib"]
18
-
18
+
19
19
  s.add_dependency "chronic", ">= 0.6.3"
20
20
  s.add_dependency "activesupport", ">= 2.3.4"
21
-
21
+
22
22
  s.add_development_dependency "shoulda", ">= 2.1.1"
23
23
  s.add_development_dependency "mocha", ">= 0.9.5"
24
24
  s.add_development_dependency "rake"
25
-
26
- # I'm not sure why this isn't installed along with activesupport,
27
- # but for whatever reason running `bundle install` doesn't install
28
- # i18n so I'm adding it here for now.
29
- # https://github.com/rails/rails/blob/master/activesupport/activesupport.gemspec#L19 ?
30
- s.add_development_dependency "i18n"
31
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whenever
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-08 00:00:00.000000000 Z
12
+ date: 2012-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: chronic
@@ -91,22 +91,6 @@ dependencies:
91
91
  - - ! '>='
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
- - !ruby/object:Gem::Dependency
95
- name: i18n
96
- requirement: !ruby/object:Gem::Requirement
97
- none: false
98
- requirements:
99
- - - ! '>='
100
- - !ruby/object:Gem::Version
101
- version: '0'
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: '0'
110
94
  description: Clean ruby syntax for writing and deploying cron jobs.
111
95
  email:
112
96
  - javan@javan.us
@@ -128,6 +112,7 @@ files:
128
112
  - lib/whenever.rb
129
113
  - lib/whenever/capistrano.rb
130
114
  - lib/whenever/capistrano/recipes.rb
115
+ - lib/whenever/capistrano/support.rb
131
116
  - lib/whenever/command_line.rb
132
117
  - lib/whenever/cron.rb
133
118
  - lib/whenever/job.rb
@@ -140,8 +125,10 @@ files:
140
125
  - test/functional/output_default_defined_jobs_test.rb
141
126
  - test/functional/output_defined_job_test.rb
142
127
  - test/functional/output_env_test.rb
128
+ - test/functional/output_jobs_for_roles_test.rb
143
129
  - test/functional/output_redirection_test.rb
144
130
  - test/test_helper.rb
131
+ - test/unit/capistrano_support_test.rb
145
132
  - test/unit/cron_test.rb
146
133
  - test/unit/job_test.rb
147
134
  - whenever.gemspec
@@ -175,6 +162,8 @@ test_files:
175
162
  - test/functional/output_default_defined_jobs_test.rb
176
163
  - test/functional/output_defined_job_test.rb
177
164
  - test/functional/output_env_test.rb
165
+ - test/functional/output_jobs_for_roles_test.rb
178
166
  - test/functional/output_redirection_test.rb
167
+ - test/unit/capistrano_support_test.rb
179
168
  - test/unit/cron_test.rb
180
169
  - test/unit/job_test.rb