Skip to content

Commit

Permalink
Add timestamps to crontab comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Attila Horváth committed Feb 24, 2017
1 parent a53e620 commit 2c67944
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 43 deletions.
42 changes: 30 additions & 12 deletions lib/whenever/command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def initialize(options={})
exit(1)
end
@options[:cut] = @options[:cut].to_i

@timestamp = Time.now.to_s
end

def run
Expand Down Expand Up @@ -92,19 +94,19 @@ def write_crontab(contents)

def updated_crontab
# Check for unopened or unclosed identifier blocks
if read_crontab =~ Regexp.new("^#{comment_open}\s*$") && (read_crontab =~ Regexp.new("^#{comment_close}\s*$")).nil?
warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open}', but no '#{comment_close}'"
if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && (read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")).nil?
warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open(false)}', but no '#{comment_close(false)}'"
exit(1)
elsif (read_crontab =~ Regexp.new("^#{comment_open}\s*$")).nil? && read_crontab =~ Regexp.new("^#{comment_close}\s*$")
warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close}', but no '#{comment_open}'"
elsif (read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$")).nil? && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close(false)}', but no '#{comment_open(false)}'"
exit(1)
end

# If an existing identier block is found, replace it with the new cron entries
if read_crontab =~ Regexp.new("^#{comment_open}\s*$") && read_crontab =~ Regexp.new("^#{comment_close}\s*$")
if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
# If the existing crontab file contains backslashes they get lost going through gsub.
# .gsub('\\', '\\\\\\') preserves them. Go figure.
read_crontab.gsub(Regexp.new("^#{comment_open}\s*$.+^#{comment_close}\s*$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
read_crontab.gsub(Regexp.new("^#{comment_open_regex}\s*$.+^#{comment_close_regex}\s*$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
else # Otherwise, append the new cron entries after any existing ones
[read_crontab, whenever_cron].join("\n\n")
end.gsub(/\n{3,}/, "\n\n") # More than two newlines becomes just two.
Expand All @@ -122,16 +124,32 @@ def prepare(contents)
stripped_contents.gsub!(/\s+$/, $/)
end

def comment_base
"Whenever generated tasks for: #{@options[:identifier]}"
def comment_base(include_timestamp = true)
if include_timestamp
"Whenever generated tasks for: #{@options[:identifier]} at: #{@timestamp}"
else
"Whenever generated tasks for: #{@options[:identifier]}"
end
end

def comment_open(include_timestamp = true)
"# Begin #{comment_base(include_timestamp)}"
end

def comment_close(include_timestamp = true)
"# End #{comment_base(include_timestamp)}"
end

def comment_open_regex
"#{comment_open(false)}(#{timestamp_regex}|)"
end

def comment_open
"# Begin #{comment_base}"
def comment_close_regex
"#{comment_close(false)}(#{timestamp_regex}|)"
end

def comment_close
"# End #{comment_base}"
def timestamp_regex
" at: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [+-]\\d{4}"
end
end
end
128 changes: 97 additions & 31 deletions test/functional/command_line_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

class CommandLineWriteTest < Whenever::TestCase
setup do
Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+00:00'))
File.expects(:exist?).with('config/schedule.rb').returns(true)
@command = Whenever::CommandLine.new(:write => true, :identifier => 'My identifier')
@task = "#{two_hours} /my/command"
Expand All @@ -10,9 +11,9 @@ class CommandLineWriteTest < Whenever::TestCase

should "output the cron job with identifier blocks" do
output = <<-EXPECTED
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
#{@task}
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
EXPECTED

assert_equal output, @command.send(:whenever_cron)
Expand All @@ -26,6 +27,7 @@ class CommandLineWriteTest < Whenever::TestCase

class CommandLineUpdateTest < Whenever::TestCase
setup do
Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+00:00'))
File.expects(:exist?).with('config/schedule.rb').returns(true)
@command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
@task = "#{two_hours} /my/command"
Expand All @@ -39,9 +41,9 @@ class CommandLineUpdateTest < Whenever::TestCase
new_cron = <<-EXPECTED
#{existing}
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
#{@task}
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
EXPECTED

assert_equal new_cron, @command.send(:updated_crontab)
Expand All @@ -50,29 +52,61 @@ class CommandLineUpdateTest < Whenever::TestCase
assert @command.run
end

should "replace an existing block if the identifier matches" do
should "replace an existing block if the identifier matches and the timestamp doesn't" do
existing = <<-EXISTING_CRON
# Something
# Begin Whenever generated tasks for: My identifier at: 2017-01-03 08:02:22 +0500
My whenever job that was already here
# End Whenever generated tasks for: My identifier at: 2017-01-03 08:22:22 +0500
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
EXISTING_CRON

new_cron = <<-NEW_CRON
# Something
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
#{@task}
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
NEW_CRON

@command.expects(:read_crontab).at_least_once.returns(existing)
assert_equal new_cron, @command.send(:updated_crontab)

@command.expects(:write_crontab).with(new_cron).returns(true)
assert @command.run
end

should "replace an existing block if the identifier matches and it doesn't contain a timestamp" do
existing = <<-EXISTING_CRON
# Something
# Begin Whenever generated tasks for: My identifier
My whenever job that was already here
# End Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: Other identifier
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
EXISTING_CRON

new_cron = <<-NEW_CRON
# Something
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
#{@task}
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
# Begin Whenever generated tasks for: Other identifier
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
NEW_CRON

@command.expects(:read_crontab).at_least_once.returns(existing)
Expand All @@ -85,10 +119,11 @@ class CommandLineUpdateTest < Whenever::TestCase

class CommandLineUpdateWithBackslashesTest < Whenever::TestCase
setup do
Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+00:00'))
@existing = <<-EXISTING_CRON
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
script/runner -e production 'puts '\\''hello'\\'''
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
EXISTING_CRON
File.expects(:exist?).with('config/schedule.rb').returns(true)
@command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
Expand All @@ -104,12 +139,12 @@ class CommandLineUpdateWithBackslashesTest < Whenever::TestCase
class CommandLineUpdateToSimilarCrontabTest < Whenever::TestCase
setup do
@existing = <<-EXISTING_CRON
# Begin Whenever generated tasks for: WheneverExisting
# End Whenever generated tasks for: WheneverExisting
# Begin Whenever generated tasks for: WheneverExisting at: 2017-02-24 16:21:30 +0000
# End Whenever generated tasks for: WheneverExisting at: 2017-02-24 16:21:30 +0000
EXISTING_CRON
@new = <<-NEW_CRON
# Begin Whenever generated tasks for: Whenever
# End Whenever generated tasks for: Whenever
# Begin Whenever generated tasks for: Whenever at: 2017-02-24 16:21:30 +0000
# End Whenever generated tasks for: Whenever at: 2017-02-24 16:21:30 +0000
NEW_CRON
File.expects(:exist?).with('config/schedule.rb').returns(true)
@command = Whenever::CommandLine.new(:update => true, :identifier => 'Whenever')
Expand All @@ -124,32 +159,62 @@ class CommandLineUpdateToSimilarCrontabTest < Whenever::TestCase

class CommandLineClearTest < Whenever::TestCase
setup do
Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+00:00'))
File.expects(:exist?).with('config/schedule.rb').returns(true)
@command = Whenever::CommandLine.new(:clear => true, :identifier => 'My identifier')
@task = "#{two_hours} /my/command"
end

should "clear an existing block if the identifier matches" do
should "clear an existing block if the identifier matches and the timestamp doesn't" do
existing = <<-EXISTING_CRON
# Something
# Begin Whenever generated tasks for: My identifier at: 2017-01-03 08:20:02 +0500
My whenever job that was already here
# End Whenever generated tasks for: My identifier at: 2017-01-03 08:20:02 +0500
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
EXISTING_CRON

@command.expects(:read_crontab).at_least_once.returns(existing)

new_cron = <<-NEW_CRON
# Something
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
NEW_CRON

assert_equal new_cron, @command.send(:updated_crontab)

@command.expects(:write_crontab).with(new_cron).returns(true)
assert @command.run
end

should "clear an existing block if the identifier matches and it doesn't have a timestamp" do
existing = <<-EXISTING_CRON
# Something
# Begin Whenever generated tasks for: My identifier
My whenever job that was already here
# End Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: Other identifier
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
EXISTING_CRON

@command.expects(:read_crontab).at_least_once.returns(existing)

new_cron = <<-NEW_CRON
# Something
# Begin Whenever generated tasks for: Other identifier
# Begin Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
This shouldn't get replaced
# End Whenever generated tasks for: Other identifier
# End Whenever generated tasks for: Other identifier at: 2017-02-24 16:21:30 +0000
NEW_CRON

assert_equal new_cron, @command.send(:updated_crontab)
Expand All @@ -173,13 +238,14 @@ class CommandLineClearWithNoScheduleTest < Whenever::TestCase

class CommandLineUpdateWithNoIdentifierTest < Whenever::TestCase
setup do
Time.stubs(:now).returns(Time.new(2017, 2, 24, 16, 21, 30, '+00:00'))
File.expects(:exist?).with('config/schedule.rb').returns(true)
Whenever::CommandLine.any_instance.expects(:default_identifier).returns('DEFAULT')
@command = Whenever::CommandLine.new(:update => true)
end

should "use the default identifier" do
assert_equal "Whenever generated tasks for: DEFAULT", @command.send(:comment_base)
assert_equal "Whenever generated tasks for: DEFAULT at: 2017-02-24 16:21:30 +0000", @command.send(:comment_base)
end
end

Expand Down Expand Up @@ -287,9 +353,9 @@ class PreparingOutputTest < Whenever::TestCase
# Useless Comments
# at the top of the file
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
My whenever job that was already here
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
EXISTING_CRON

assert_equal existing, @command.send(:prepare, existing)
Expand All @@ -301,15 +367,15 @@ class PreparingOutputTest < Whenever::TestCase
# Useless Comments
# at the top of the file
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
My whenever job that was already here
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
EXISTING_CRON

new_cron = <<-NEW_CRON
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
My whenever job that was already here
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
NEW_CRON

assert_equal new_cron, @command.send(:prepare, existing)
Expand All @@ -318,9 +384,9 @@ class PreparingOutputTest < Whenever::TestCase
should "preserve terminating newlines in files" do
@command = Whenever::CommandLine.new(:update => true, :identifier => 'My identifier')
existing = <<-EXISTING_CRON
# Begin Whenever generated tasks for: My identifier
# Begin Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
My whenever job that was already here
# End Whenever generated tasks for: My identifier
# End Whenever generated tasks for: My identifier at: 2017-02-24 16:21:30 +0000
# A non-Whenever task
My non-whenever job that was already here
Expand Down

0 comments on commit 2c67944

Please sign in to comment.