whenever 0.9.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/whenever/cron.rb CHANGED
@@ -3,16 +3,20 @@ require 'chronic'
3
3
  module Whenever
4
4
  module Output
5
5
  class Cron
6
+ DAYS = %w(sun mon tue wed thu fri sat)
7
+ MONTHS = %w(jan feb mar apr may jun jul aug sep oct nov dec)
6
8
  KEYWORDS = [:reboot, :yearly, :annually, :monthly, :weekly, :daily, :midnight, :hourly]
7
- REGEX = /^(@(#{KEYWORDS.join '|'})|((\*?[\d\/,\-]*)\s*){5})$/
9
+ REGEX = /^(@(#{KEYWORDS.join '|'})|((\*?[\d\/,\-]*)\s){3}(\*?([\d\/,\-]|(#{MONTHS.join '|'}))*\s)(\*?([\d\/,\-]|(#{DAYS.join '|'}))*))$/i
8
10
 
9
11
  attr_accessor :time, :task
10
12
 
11
- def initialize(time = nil, task = nil, at = nil)
13
+ def initialize(time = nil, task = nil, at = nil, options = {})
14
+ chronic_options = options[:chronic_options] || {}
15
+
12
16
  @at_given = at
13
17
  @time = time
14
18
  @task = task
15
- @at = at.is_a?(String) ? (Chronic.parse(at) || 0) : (at || 0)
19
+ @at = at.is_a?(String) ? (Chronic.parse(at, chronic_options) || 0) : (at || 0)
16
20
  end
17
21
 
18
22
  def self.enumerate(item, detect_cron = true)
@@ -30,10 +34,10 @@ module Whenever
30
34
  items
31
35
  end
32
36
 
33
- def self.output(times, job)
37
+ def self.output(times, job, options = {})
34
38
  enumerate(times).each do |time|
35
39
  enumerate(job.at, false).each do |at|
36
- yield new(time, job.output, at).output
40
+ yield new(time, job.output, at, options).output
37
41
  end
38
42
  end
39
43
  end
@@ -54,18 +58,18 @@ module Whenever
54
58
 
55
59
  protected
56
60
  def day_given?
57
- months = %w(jan feb mar apr may jun jul aug sep oct nov dec)
58
- @at_given.is_a?(String) && months.any? { |m| @at_given.downcase.index(m) }
61
+ @at_given.is_a?(String) && (MONTHS.any? { |m| @at_given.downcase.index(m) } || @at_given[/\d\/\d/])
59
62
  end
60
63
 
61
64
  def parse_symbol
62
65
  shortcut = case @time
63
66
  when *KEYWORDS then "@#{@time}" # :reboot => '@reboot'
64
- when :year then Whenever.seconds(12, :months)
67
+ when :year then Whenever.seconds(1, :year)
65
68
  when :day then Whenever.seconds(1, :day)
66
69
  when :month then Whenever.seconds(1, :month)
67
70
  when :week then Whenever.seconds(1, :week)
68
71
  when :hour then Whenever.seconds(1, :hour)
72
+ when :minute then Whenever.seconds(1, :minute)
69
73
  end
70
74
 
71
75
  if shortcut.is_a?(Numeric)
@@ -92,23 +96,36 @@ module Whenever
92
96
  timing[0] = comma_separated_timing(minute_frequency, 59, @at || 0)
93
97
  when Whenever.seconds(1, :hour)...Whenever.seconds(1, :day)
94
98
  hour_frequency = (@time / 60 / 60).round
95
- timing[0] = @at.is_a?(Time) ? @at.min : @at
99
+ timing[0] = @at.is_a?(Time) ? @at.min : range_or_integer(@at, 0..59, 'Minute')
96
100
  timing[1] = comma_separated_timing(hour_frequency, 23)
97
101
  when Whenever.seconds(1, :day)...Whenever.seconds(1, :month)
98
102
  day_frequency = (@time / 24 / 60 / 60).round
99
103
  timing[0] = @at.is_a?(Time) ? @at.min : 0
100
- timing[1] = @at.is_a?(Time) ? @at.hour : @at
104
+ timing[1] = @at.is_a?(Time) ? @at.hour : range_or_integer(@at, 0..23, 'Hour')
101
105
  timing[2] = comma_separated_timing(day_frequency, 31, 1)
102
- when Whenever.seconds(1, :month)..Whenever.seconds(12, :months)
103
- month_frequency = (@time / 30 / 24 / 60 / 60).round
106
+ when Whenever.seconds(1, :month)...Whenever.seconds(1, :year)
107
+ month_frequency = (@time / 30 / 24 / 60 / 60).round
104
108
  timing[0] = @at.is_a?(Time) ? @at.min : 0
105
109
  timing[1] = @at.is_a?(Time) ? @at.hour : 0
106
110
  timing[2] = if @at.is_a?(Time)
107
111
  day_given? ? @at.day : 1
108
112
  else
109
- @at.zero? ? 1 : @at
113
+ @at == 0 ? 1 : range_or_integer(@at, 1..31, 'Day')
110
114
  end
111
115
  timing[3] = comma_separated_timing(month_frequency, 12, 1)
116
+ when Whenever.seconds(1, :year)
117
+ timing[0] = @at.is_a?(Time) ? @at.min : 0
118
+ timing[1] = @at.is_a?(Time) ? @at.hour : 0
119
+ timing[2] = if @at.is_a?(Time)
120
+ day_given? ? @at.day : 1
121
+ else
122
+ 1
123
+ end
124
+ timing[3] = if @at.is_a?(Time)
125
+ day_given? ? @at.month : 1
126
+ else
127
+ @at == 0 ? 1 : range_or_integer(@at, 1..12, 'Month')
128
+ end
112
129
  else
113
130
  return parse_as_string
114
131
  end
@@ -126,11 +143,22 @@ module Whenever
126
143
  return (timing << '1-5') * " " if string.downcase.index('weekday')
127
144
  return (timing << '6,0') * " " if string.downcase.index('weekend')
128
145
 
129
- %w(sun mon tue wed thu fri sat).each_with_index do |day, i|
146
+ DAYS.each_with_index do |day, i|
130
147
  return (timing << i) * " " if string.downcase.index(day)
131
148
  end
132
149
 
133
- raise ArgumentError, "Couldn't parse: #{@time}"
150
+ raise ArgumentError, "Couldn't parse: #{@time.inspect}"
151
+ end
152
+
153
+ def range_or_integer(at, valid_range, name)
154
+ must_be_between = "#{name} must be between #{valid_range.min}-#{valid_range.max}"
155
+ if at.is_a?(Range)
156
+ raise ArgumentError, "#{must_be_between}, #{at.min} given" unless valid_range.include?(at.min)
157
+ raise ArgumentError, "#{must_be_between}, #{at.max} given" unless valid_range.include?(at.max)
158
+ return "#{at.min}-#{at.max}"
159
+ end
160
+ raise ArgumentError, "#{must_be_between}, #{at} given" unless valid_range.include?(at)
161
+ at
134
162
  end
135
163
 
136
164
  def comma_separated_timing(frequency, max, start = 0)
data/lib/whenever/job.rb CHANGED
@@ -2,12 +2,13 @@ require 'shellwords'
2
2
 
3
3
  module Whenever
4
4
  class Job
5
- attr_reader :at, :roles
5
+ attr_reader :at, :roles, :mailto
6
6
 
7
7
  def initialize(options = {})
8
8
  @options = options
9
9
  @at = options.delete(:at)
10
10
  @template = options.delete(:template)
11
+ @mailto = options.fetch(:mailto, :default_mailto)
11
12
  @job_template = options.delete(:job_template) || ":job"
12
13
  @roles = Array(options.delete(:roles))
13
14
  @options[:output] = options.has_key?(:output) ? Whenever::Output::Redirection.new(options[:output]).to_s : ''
@@ -30,10 +30,17 @@ module Whenever
30
30
  return if @pre_set_variables[variable]
31
31
 
32
32
  instance_variable_set("@#{variable}".to_sym, value)
33
- self.class.send(:attr_reader, variable.to_sym)
34
33
  @set_variables[variable] = value
35
34
  end
36
35
 
36
+ def method_missing(name, *args, &block)
37
+ @set_variables.has_key?(name) ? @set_variables[name] : super
38
+ end
39
+
40
+ def self.respond_to?(name, include_private = false)
41
+ @set_variables.has_key?(name) || super
42
+ end
43
+
37
44
  def env(variable, value)
38
45
  @env[variable.to_s] = value
39
46
  end
@@ -50,13 +57,16 @@ module Whenever
50
57
  options = { :task => task, :template => template }
51
58
  options.merge!(args[0]) if args[0].is_a? Hash
52
59
 
60
+ options[:mailto] ||= @options.fetch(:mailto, :default_mailto)
61
+
53
62
  # :cron_log was an old option for output redirection, it remains for backwards compatibility
54
63
  options[:output] = (options[:cron_log] || @cron_log) if defined?(@cron_log) || options.has_key?(:cron_log)
55
64
  # :output is the newer, more flexible option.
56
65
  options[:output] = @output if defined?(@output) && !options.has_key?(:output)
57
66
 
58
- @jobs[@current_time_scope] ||= []
59
- @jobs[@current_time_scope] << Whenever::Job.new(@options.merge(@set_variables).merge(options))
67
+ @jobs[options.fetch(:mailto)] ||= {}
68
+ @jobs[options.fetch(:mailto)][@current_time_scope] ||= []
69
+ @jobs[options.fetch(:mailto)][@current_time_scope] << Whenever::Job.new(@options.merge(@set_variables).merge(options))
60
70
  end
61
71
  end
62
72
  end
@@ -125,31 +135,51 @@ module Whenever
125
135
  entries.map { |entry| entry.join(' ') }
126
136
  end
127
137
 
138
+ def cron_jobs_of_time(time, jobs)
139
+ shortcut_jobs, regular_jobs = [], []
140
+
141
+ jobs.each do |job|
142
+ next unless roles.empty? || roles.any? do |r|
143
+ job.has_role?(r)
144
+ end
145
+ Whenever::Output::Cron.output(time, job, :chronic_options => @chronic_options) do |cron|
146
+ cron << "\n\n"
147
+
148
+ if cron[0,1] == "@"
149
+ shortcut_jobs << cron
150
+ else
151
+ regular_jobs << cron
152
+ end
153
+ end
154
+ end
155
+
156
+ shortcut_jobs.join + combine(regular_jobs).join
157
+ end
158
+
128
159
  def cron_jobs
129
160
  return if @jobs.empty?
130
161
 
131
- shortcut_jobs = []
132
- regular_jobs = []
162
+ output = []
133
163
 
134
- output_all = roles.empty?
135
- @jobs.each do |time, jobs|
136
- jobs.each do |job|
137
- next unless output_all || roles.any? do |r|
138
- job.has_role?(r)
139
- end
140
- Whenever::Output::Cron.output(time, job) do |cron|
141
- cron << "\n\n"
164
+ # jobs with default mailto's must be output before the ones with non-default mailto's.
165
+ @jobs.delete(:default_mailto) { Hash.new }.each do |time, jobs|
166
+ output << cron_jobs_of_time(time, jobs)
167
+ end
142
168
 
143
- if cron[0,1] == "@"
144
- shortcut_jobs << cron
145
- else
146
- regular_jobs << cron
147
- end
148
- end
169
+ @jobs.each do |mailto, time_and_jobs|
170
+ output_jobs = []
171
+
172
+ time_and_jobs.each do |time, jobs|
173
+ output_jobs << cron_jobs_of_time(time, jobs)
149
174
  end
175
+
176
+ output_jobs.reject! { |output_job| output_job.empty? }
177
+
178
+ output << "MAILTO=#{mailto}\n\n" unless output_jobs.empty?
179
+ output << output_jobs
150
180
  end
151
181
 
152
- shortcut_jobs.join + combine(regular_jobs).join
182
+ output.join
153
183
  end
154
184
  end
155
185
  end
@@ -1,4 +1,4 @@
1
- class Numeric
1
+ Numeric.class_eval do
2
2
  def respond_to?(method, include_private = false)
3
3
  super || Whenever::NumericSeconds.public_method_defined?(method)
4
4
  end
@@ -5,6 +5,10 @@ set :environment, "production"
5
5
  # Path defaults to the directory `whenever` was run from
6
6
  set :path, Whenever.path
7
7
 
8
+ # Custom Chronic configuration for time parsing, empty by default
9
+ # Full list of options at: https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
10
+ set :chronic_options, {}
11
+
8
12
  # All jobs are wrapped in this template.
9
13
  # http://blog.scoutapp.com/articles/2010/09/07/rvm-and-cron-in-production
10
14
  set :job_template, "/bin/bash -l -c ':job'"
@@ -1,3 +1,3 @@
1
1
  module Whenever
2
- VERSION = '0.9.7'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -2,6 +2,7 @@ require 'test_helper'
2
2
 
3
3
  class CommandLineWriteTest < Whenever::TestCase
4
4
  setup do
5
+ Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+01:00'))
5
6
  File.expects(:exist?).with('config/schedule.rb').returns(true)
6
7
  @command = Whenever::CommandLine.new(:write => true, :identifier => 'My identifier')
7
8
  @task = "#{two_hours} /my/command"
@@ -10,9 +11,9 @@ class CommandLineWriteTest < Whenever::TestCase
10
11
 
11
12
  should "output the cron job with identifier blocks" do
12
13
  output = <<-EXPECTED
13
- # Begin Whenever generated tasks for: My identifier
14
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
14
15
  #{@task}
15
- # End Whenever generated tasks for: My identifier
16
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
16
17
  EXPECTED
17
18
 
18
19
  assert_equal output, @command.send(:whenever_cron)
@@ -26,6 +27,7 @@ end
26
27
 
27
28
  class CommandLineUpdateTest < Whenever::TestCase
28
29
  setup do
30
+ Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+01:00'))
29
31
  File.expects(:exist?).with('config/schedule.rb').returns(true)
30
32
  @command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
31
33
  @task = "#{two_hours} /my/command"
@@ -39,9 +41,9 @@ class CommandLineUpdateTest < Whenever::TestCase
39
41
  new_cron = <<-EXPECTED
40
42
  #{existing}
41
43
 
42
- # Begin Whenever generated tasks for: My identifier
44
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
43
45
  #{@task}
44
- # End Whenever generated tasks for: My identifier
46
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
45
47
  EXPECTED
46
48
 
47
49
  assert_equal new_cron, @command.send(:updated_crontab)
@@ -50,7 +52,71 @@ EXPECTED
50
52
  assert @command.run
51
53
  end
52
54
 
53
- should "replace an existing block if the identifier matches" do
55
+ should "replace an existing block if the identifier matches and the timestamp doesn't" do
56
+ existing = <<-EXISTING_CRON
57
+ # Something
58
+
59
+ # Begin Whenever generated tasks for: My identifier at: 2017-01-03 08:02:22 +0500
60
+ My whenever job that was already here
61
+ # End Whenever generated tasks for: My identifier at: 2017-01-03 08:22:22 +0500
62
+
63
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
64
+ This shouldn't get replaced
65
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
66
+ EXISTING_CRON
67
+
68
+ new_cron = <<-NEW_CRON
69
+ # Something
70
+
71
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
72
+ #{@task}
73
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
74
+
75
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
76
+ This shouldn't get replaced
77
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
78
+ NEW_CRON
79
+
80
+ @command.expects(:read_crontab).at_least_once.returns(existing)
81
+ assert_equal new_cron, @command.send(:updated_crontab)
82
+
83
+ @command.expects(:write_crontab).with(new_cron).returns(true)
84
+ assert @command.run
85
+ end
86
+
87
+ should "replace an existing block if the identifier matches and the UTC timestamp doesn't" do
88
+ existing = <<-EXISTING_CRON
89
+ # Something
90
+
91
+ # Begin Whenever generated tasks for: My identifier at: 2017-01-03 08:02:22 UTC
92
+ My whenever job that was already here
93
+ # End Whenever generated tasks for: My identifier at: 2017-01-03 08:22:22 UTC
94
+
95
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
96
+ This shouldn't get replaced
97
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
98
+ EXISTING_CRON
99
+
100
+ new_cron = <<-NEW_CRON
101
+ # Something
102
+
103
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
104
+ #{@task}
105
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
106
+
107
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
108
+ This shouldn't get replaced
109
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
110
+ NEW_CRON
111
+
112
+ @command.expects(:read_crontab).at_least_once.returns(existing)
113
+ assert_equal new_cron, @command.send(:updated_crontab)
114
+
115
+ @command.expects(:write_crontab).with(new_cron).returns(true)
116
+ assert @command.run
117
+ end
118
+
119
+ should "replace an existing block if the identifier matches and it doesn't contain a timestamp" do
54
120
  existing = <<-EXISTING_CRON
55
121
  # Something
56
122
 
@@ -58,21 +124,21 @@ EXPECTED
58
124
  My whenever job that was already here
59
125
  # End Whenever generated tasks for: My identifier
60
126
 
61
- # Begin Whenever generated tasks for: Other identifier
127
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
62
128
  This shouldn't get replaced
63
- # End Whenever generated tasks for: Other identifier
129
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
64
130
  EXISTING_CRON
65
131
 
66
132
  new_cron = <<-NEW_CRON
67
133
  # Something
68
134
 
69
- # Begin Whenever generated tasks for: My identifier
135
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
70
136
  #{@task}
71
- # End Whenever generated tasks for: My identifier
137
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
72
138
 
73
- # Begin Whenever generated tasks for: Other identifier
139
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
74
140
  This shouldn't get replaced
75
- # End Whenever generated tasks for: Other identifier
141
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
76
142
  NEW_CRON
77
143
 
78
144
  @command.expects(:read_crontab).at_least_once.returns(existing)
@@ -85,10 +151,11 @@ end
85
151
 
86
152
  class CommandLineUpdateWithBackslashesTest < Whenever::TestCase
87
153
  setup do
154
+ Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+01:00'))
88
155
  @existing = <<-EXISTING_CRON
89
- # Begin Whenever generated tasks for: My identifier
156
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
90
157
  script/runner -e production 'puts '\\''hello'\\'''
91
- # End Whenever generated tasks for: My identifier
158
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
92
159
  EXISTING_CRON
93
160
  File.expects(:exist?).with('config/schedule.rb').returns(true)
94
161
  @command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
@@ -104,12 +171,12 @@ end
104
171
  class CommandLineUpdateToSimilarCrontabTest < Whenever::TestCase
105
172
  setup do
106
173
  @existing = <<-EXISTING_CRON
107
- # Begin Whenever generated tasks for: WheneverExisting
108
- # End Whenever generated tasks for: WheneverExisting
174
+ # Begin Whenever generated tasks for: WheneverExisting at: 2017-02-24 16:21:30 +0100
175
+ # End Whenever generated tasks for: WheneverExisting at: 2017-02-24 16:21:30 +0100
109
176
  EXISTING_CRON
110
177
  @new = <<-NEW_CRON
111
- # Begin Whenever generated tasks for: Whenever
112
- # End Whenever generated tasks for: Whenever
178
+ # Begin Whenever generated tasks for: Whenever at: 2017-02-24 16:21:30 +0100
179
+ # End Whenever generated tasks for: Whenever at: 2017-02-24 16:21:30 +0100
113
180
  NEW_CRON
114
181
  File.expects(:exist?).with('config/schedule.rb').returns(true)
115
182
  @command = Whenever::CommandLine.new(:update => true, :identifier => 'Whenever')
@@ -124,12 +191,71 @@ end
124
191
 
125
192
  class CommandLineClearTest < Whenever::TestCase
126
193
  setup do
194
+ Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+01:00'))
127
195
  File.expects(:exist?).with('config/schedule.rb').returns(true)
128
196
  @command = Whenever::CommandLine.new(:clear => true, :identifier => 'My identifier')
129
197
  @task = "#{two_hours} /my/command"
130
198
  end
131
199
 
132
- should "clear an existing block if the identifier matches" do
200
+ should "clear an existing block if the identifier matches and the timestamp doesn't" do
201
+ existing = <<-EXISTING_CRON
202
+ # Something
203
+
204
+ # Begin Whenever generated tasks for: My identifier at: 2017-01-03 08:20:02 +0500
205
+ My whenever job that was already here
206
+ # End Whenever generated tasks for: My identifier at: 2017-01-03 08:20:02 +0500
207
+
208
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
209
+ This shouldn't get replaced
210
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
211
+ EXISTING_CRON
212
+
213
+ @command.expects(:read_crontab).at_least_once.returns(existing)
214
+
215
+ new_cron = <<-NEW_CRON
216
+ # Something
217
+
218
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
219
+ This shouldn't get replaced
220
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
221
+ NEW_CRON
222
+
223
+ assert_equal new_cron, @command.send(:updated_crontab)
224
+
225
+ @command.expects(:write_crontab).with(new_cron).returns(true)
226
+ assert @command.run
227
+ end
228
+
229
+ should "clear an existing block if the identifier matches and the UTC timestamp doesn't" do
230
+ existing = <<-EXISTING_CRON
231
+ # Something
232
+
233
+ # Begin Whenever generated tasks for: My identifier at: 2017-01-03 08:20:02 UTC
234
+ My whenever job that was already here
235
+ # End Whenever generated tasks for: My identifier at: 2017-01-03 08:20:02 UTC
236
+
237
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
238
+ This shouldn't get replaced
239
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
240
+ EXISTING_CRON
241
+
242
+ @command.expects(:read_crontab).at_least_once.returns(existing)
243
+
244
+ new_cron = <<-NEW_CRON
245
+ # Something
246
+
247
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
248
+ This shouldn't get replaced
249
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
250
+ NEW_CRON
251
+
252
+ assert_equal new_cron, @command.send(:updated_crontab)
253
+
254
+ @command.expects(:write_crontab).with(new_cron).returns(true)
255
+ assert @command.run
256
+ end
257
+
258
+ should "clear an existing block if the identifier matches and it doesn't have a timestamp" do
133
259
  existing = <<-EXISTING_CRON
134
260
  # Something
135
261
 
@@ -137,9 +263,9 @@ class CommandLineClearTest < Whenever::TestCase
137
263
  My whenever job that was already here
138
264
  # End Whenever generated tasks for: My identifier
139
265
 
140
- # Begin Whenever generated tasks for: Other identifier
266
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
141
267
  This shouldn't get replaced
142
- # End Whenever generated tasks for: Other identifier
268
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
143
269
  EXISTING_CRON
144
270
 
145
271
  @command.expects(:read_crontab).at_least_once.returns(existing)
@@ -147,9 +273,9 @@ EXISTING_CRON
147
273
  new_cron = <<-NEW_CRON
148
274
  # Something
149
275
 
150
- # Begin Whenever generated tasks for: Other identifier
276
+ # Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
151
277
  This shouldn't get replaced
152
- # End Whenever generated tasks for: Other identifier
278
+ # End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0100
153
279
  NEW_CRON
154
280
 
155
281
  assert_equal new_cron, @command.send(:updated_crontab)
@@ -173,13 +299,14 @@ end
173
299
 
174
300
  class CommandLineUpdateWithNoIdentifierTest < Whenever::TestCase
175
301
  setup do
302
+ Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+01:00'))
176
303
  File.expects(:exist?).with('config/schedule.rb').returns(true)
177
304
  Whenever::CommandLine.any_instance.expects(:default_identifier).returns('DEFAULT')
178
- @command = Whenever::CommandLine.new(:update => true, :file => @file)
305
+ @command = Whenever::CommandLine.new(:update => true)
179
306
  end
180
307
 
181
308
  should "use the default identifier" do
182
- assert_equal "Whenever generated tasks for: DEFAULT", @command.send(:comment_base)
309
+ assert_equal "Whenever generated tasks for: DEFAULT at: 2017-02-24 16:21:30 +0100", @command.send(:comment_base)
183
310
  end
184
311
  end
185
312
 
@@ -287,9 +414,9 @@ class PreparingOutputTest < Whenever::TestCase
287
414
  # Useless Comments
288
415
  # at the top of the file
289
416
 
290
- # Begin Whenever generated tasks for: My identifier
417
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
291
418
  My whenever job that was already here
292
- # End Whenever generated tasks for: My identifier
419
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
293
420
  EXISTING_CRON
294
421
 
295
422
  assert_equal existing, @command.send(:prepare, existing)
@@ -301,15 +428,15 @@ EXISTING_CRON
301
428
  # Useless Comments
302
429
  # at the top of the file
303
430
 
304
- # Begin Whenever generated tasks for: My identifier
431
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
305
432
  My whenever job that was already here
306
- # End Whenever generated tasks for: My identifier
433
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
307
434
  EXISTING_CRON
308
435
 
309
436
  new_cron = <<-NEW_CRON
310
- # Begin Whenever generated tasks for: My identifier
437
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
311
438
  My whenever job that was already here
312
- # End Whenever generated tasks for: My identifier
439
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
313
440
  NEW_CRON
314
441
 
315
442
  assert_equal new_cron, @command.send(:prepare, existing)
@@ -318,9 +445,9 @@ NEW_CRON
318
445
  should "preserve terminating newlines in files" do
319
446
  @command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
320
447
  existing = <<-EXISTING_CRON
321
- # Begin Whenever generated tasks for: My identifier
448
+ # Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
322
449
  My whenever job that was already here
323
- # End Whenever generated tasks for: My identifier
450
+ # End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0100
324
451
 
325
452
  # A non-Whenever task
326
453
  My non-whenever job that was already here
@@ -204,4 +204,43 @@ class OutputAtTest < Whenever::TestCase
204
204
 
205
205
  assert_match '0 0 27,31 * * blahblah', output
206
206
  end
207
+
208
+ test "using custom Chronic configuration to specify time using 24 hour clock" do
209
+ output = Whenever.cron \
210
+ <<-file
211
+ set :job_template, nil
212
+ set :chronic_options, :hours24 => true
213
+ every 1.day, :at => '03:00' do
214
+ command "blahblah"
215
+ end
216
+ file
217
+
218
+ assert_match '0 3 * * * blahblah', output
219
+ end
220
+
221
+ test "using custom Chronic configuration to specify date using little endian preference" do
222
+ output = Whenever.cron \
223
+ <<-file
224
+ set :job_template, nil
225
+ set :chronic_options, :endian_precedence => :little
226
+ every 1.month, :at => '02/03 10:15' do
227
+ command "blahblah"
228
+ end
229
+ file
230
+
231
+ assert_match '15 10 2 * * blahblah', output
232
+ end
233
+
234
+ test "using custom Chronic configuration to specify time using 24 hour clock and date using little endian preference" do
235
+ output = Whenever.cron \
236
+ <<-file
237
+ set :job_template, nil
238
+ set :chronic_options, :hours24 => true, :endian_precedence => :little
239
+ every 1.month, :at => '01/02 04:30' do
240
+ command "blahblah"
241
+ end
242
+ file
243
+
244
+ assert_match '30 4 1 * * blahblah', output
245
+ end
207
246
  end