whenever 0.9.2 → 0.10.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +17 -7
- data/CHANGELOG.md +63 -0
- data/Gemfile +0 -5
- data/LICENSE +1 -1
- data/README.md +101 -18
- data/Rakefile +3 -10
- data/bin/whenever +3 -0
- data/bin/wheneverize +8 -5
- data/gemfiles/activesupport4.1.gemfile +5 -0
- data/gemfiles/activesupport4.2.gemfile +5 -0
- data/lib/whenever/capistrano/v2/recipes.rb +4 -3
- data/lib/whenever/capistrano/v3/tasks/whenever.rake +20 -7
- data/lib/whenever/capistrano.rb +1 -1
- data/lib/whenever/command_line.rb +49 -28
- data/lib/whenever/cron.rb +43 -21
- data/lib/whenever/job.rb +4 -3
- data/lib/whenever/job_list.rb +54 -24
- data/lib/whenever/numeric.rb +13 -0
- data/lib/whenever/numeric_seconds.rb +48 -0
- data/lib/whenever/os.rb +7 -0
- data/lib/whenever/setup.rb +5 -1
- data/lib/whenever/version.rb +1 -1
- data/lib/whenever.rb +15 -14
- data/test/functional/command_line_test.rb +379 -255
- data/test/functional/output_at_test.rb +227 -249
- data/test/functional/output_default_defined_jobs_test.rb +239 -288
- data/test/functional/output_defined_job_test.rb +65 -91
- data/test/functional/output_env_test.rb +22 -26
- data/test/functional/output_jobs_for_roles_test.rb +46 -66
- data/test/functional/output_jobs_with_mailto_test.rb +168 -0
- data/test/functional/output_redirection_test.rb +231 -309
- data/test/test_case.rb +32 -0
- data/test/test_helper.rb +44 -15
- data/test/unit/capistrano_support_test.rb +126 -148
- data/test/unit/cron_test.rb +327 -210
- data/test/unit/executable_test.rb +142 -0
- data/test/unit/job_test.rb +111 -121
- data/whenever.gemspec +5 -4
- metadata +37 -28
- data/lib/whenever/tasks/whenever.rake +0 -43
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c8fe56b21ffa57026a2b944ae208bea62a9d7e9
|
|
4
|
+
data.tar.gz: 543d704698ab03d944679daa1e85bee1b3936286
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d0bd440a4beab5ecde93ccb91fad7cf5b2bf2ffe14a376ad24392fe5b4a3d53ba1d7ce15a53d2debc3b639a35f609436d21ab78de16b99a857fe1e16ed8bed1
|
|
7
|
+
data.tar.gz: 4bb8692d2f7130e45d80fc05a6a54609fd160155014eae330da8f0fc9ed97e9338d523282cd4f8ec197531231493bd04d2409a3d7a6bbc57761ff6ad0ff7f422
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
language: ruby
|
|
2
|
+
|
|
3
|
+
before_install:
|
|
4
|
+
- gem install bundler
|
|
5
|
+
|
|
2
6
|
rvm:
|
|
3
|
-
- 1.8.7
|
|
4
|
-
- 1.9.2
|
|
5
7
|
- 1.9.3
|
|
6
8
|
- 2.0.0
|
|
7
|
-
- 2.1.
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
- jruby-
|
|
9
|
+
- 2.1.10
|
|
10
|
+
- 2.2.6
|
|
11
|
+
- 2.3.3
|
|
12
|
+
- 2.4.0
|
|
13
|
+
- jruby-9.1.9.0
|
|
14
|
+
|
|
15
|
+
gemfile:
|
|
16
|
+
- Gemfile
|
|
17
|
+
- gemfiles/activesupport4.1.gemfile
|
|
18
|
+
- gemfiles/activesupport4.2.gemfile
|
|
19
|
+
env:
|
|
20
|
+
global:
|
|
21
|
+
- JRUBY_OPTS=--debug
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,66 @@
|
|
|
1
|
+
### develop
|
|
2
|
+
|
|
3
|
+
### 0.10.0 / November 19, 2017
|
|
4
|
+
|
|
5
|
+
* Modify wheneverize to allow for the creating of 'config' directory when not present
|
|
6
|
+
|
|
7
|
+
* Add --crontab-command to whenever binary for overriding the crontab command. [Martin Grandrath]
|
|
8
|
+
|
|
9
|
+
* Allow setting the path within which Capistrano will execute whenever. [Samuel Johnson](https://github.com/javan/whenever/pull/619)
|
|
10
|
+
|
|
11
|
+
* Allow the use of string literals for month and day-of-week in raw cron syntax.. [Potamianos Gregory](https://github.com/javan/whenever/pull/711)
|
|
12
|
+
|
|
13
|
+
* Include Capistrano default environment variables when executing Whenever. [Karl Li](https://github.com/javan/whenever/pull/719)
|
|
14
|
+
|
|
15
|
+
* Allow configuring an alternative schedule file in Capistrano. [Shinichi Okamoto](https://github.com/javan/whenever/pull/666)
|
|
16
|
+
|
|
17
|
+
### 0.9.7 / June 14, 2016
|
|
18
|
+
|
|
19
|
+
* Restore compatibility with Capistrano v3; it has a bug which we have to work around [Ben Langfeld, Chris Gunther, Shohei Yamasaki]
|
|
20
|
+
|
|
21
|
+
### 0.9.6 / June 13, 2016
|
|
22
|
+
|
|
23
|
+
* Bypass symlinks when loading Capistrano v3 code, since these symlinks don't work in recent gem releases [Justin Ramos]
|
|
24
|
+
|
|
25
|
+
### 0.9.5 / June 12, 2016
|
|
26
|
+
|
|
27
|
+
* Improve documentation [Ben Langfeld, Spencer Fry]
|
|
28
|
+
|
|
29
|
+
* Properly support Solaris / SmartOS [Steven Williamson]
|
|
30
|
+
|
|
31
|
+
* Drop support for Ruby < 1.9.3. Test newer Ruby versions. [Javan Makhmali, Bartłomiej Kozal]
|
|
32
|
+
|
|
33
|
+
* Suport Ruby 2.3.0 and Rails 4 [Vincent Boisard]
|
|
34
|
+
|
|
35
|
+
* Set `RAILS_ENV` correctly in schedule when writing crontab from Capistrano [Ben Langfeld, Lorenzo Manacorda]
|
|
36
|
+
|
|
37
|
+
* Minor refactoring, avoidance of Ruby warnings, etc [Ben Langfeld, DV Dasari]
|
|
38
|
+
|
|
39
|
+
* Correctly pass through date expressions (e.g. `1.day`) inside job definitions [Rafael Sales]
|
|
40
|
+
|
|
41
|
+
* Prevent writing invalid cron strings [Danny Fallon, Ben Langfeld]
|
|
42
|
+
|
|
43
|
+
* Execute runner with `bundle exec` to ensure presence of app dependencies [Judith Roth]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### 0.9.4 / October 24, 2014
|
|
47
|
+
|
|
48
|
+
* Fix duplicated command line arguments when deploying to multiple servers with Cap 3. [betesh]
|
|
49
|
+
|
|
50
|
+
* Set `whenever_environment` to the current stage before defaulting to production in Cap 3 tasks. [Karthik T]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
### 0.9.3 / October 5, 2014
|
|
54
|
+
|
|
55
|
+
* Drop ActiveSupport dependency [James Healy, Javan Makhmali]
|
|
56
|
+
|
|
57
|
+
* Drop shoulda for tests
|
|
58
|
+
|
|
59
|
+
* Fix `whenever:clear_crontab` Cap 3 task [Javan Makhmali]
|
|
60
|
+
|
|
61
|
+
* Avoid using tempfiles [ahoward]
|
|
62
|
+
|
|
63
|
+
|
|
1
64
|
### 0.9.2 / March 4, 2014
|
|
2
65
|
|
|
3
66
|
* Fix issues generating arguments for `execute` in Capistrano 3 tasks. [Javan Makhmali]
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -19,12 +19,36 @@ $ cd /apps/my-great-project
|
|
|
19
19
|
$ wheneverize .
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
This will create an initial `config/schedule.rb` file for you.
|
|
22
|
+
This will create an initial `config/schedule.rb` file for you (as long as the config folder is already present in your project).
|
|
23
|
+
|
|
24
|
+
### The `whenever` command
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
$ cd /apps/my-great-project
|
|
28
|
+
$ whenever
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This will simply show you your `schedule.rb` file converted to cron syntax. It does not read or write your crontab file; you'll need to do this in order for your jobs to execute:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
$ whenever --update-crontab
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Other commonly used options include:
|
|
38
|
+
```sh
|
|
39
|
+
$ whenever --user app # set a user as which to install the crontab
|
|
40
|
+
$ whenever --load-file config/my_schedule.rb # set the schedule file
|
|
41
|
+
$ whenever --crontab-command 'sudo crontab` # override the crontab command
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
You can list installed cron jobs using `crontab -l`.
|
|
45
|
+
|
|
46
|
+
Run `whenever --help` for a complete list of options for selecting the schedule to use, setting variables in the schedule, etc.
|
|
23
47
|
|
|
24
48
|
### Example schedule.rb file
|
|
25
49
|
|
|
26
50
|
```ruby
|
|
27
|
-
every 3.hours do
|
|
51
|
+
every 3.hours do # 1.minute 1.day 1.week 1.month 1.year is also supported
|
|
28
52
|
runner "MyModel.some_process"
|
|
29
53
|
rake "my:rake:task"
|
|
30
54
|
command "/usr/bin/my_great_command"
|
|
@@ -74,7 +98,7 @@ The default job types that ship with Whenever are defined like so:
|
|
|
74
98
|
```ruby
|
|
75
99
|
job_type :command, ":task :output"
|
|
76
100
|
job_type :rake, "cd :path && :environment_variable=:environment bundle exec rake :task --silent :output"
|
|
77
|
-
job_type :runner, "cd :path &&
|
|
101
|
+
job_type :runner, "cd :path && bin/rails runner -e :environment ':task' :output"
|
|
78
102
|
job_type :script, "cd :path && :environment_variable=:environment bundle exec script/:task :output"
|
|
79
103
|
```
|
|
80
104
|
|
|
@@ -96,6 +120,57 @@ Or set the job_template to nil to have your jobs execute normally.
|
|
|
96
120
|
set :job_template, nil
|
|
97
121
|
```
|
|
98
122
|
|
|
123
|
+
### Parsing dates and times
|
|
124
|
+
|
|
125
|
+
Whenever uses the [Chronic](https://github.com/mojombo/chronic) gem to parse the specified dates and times.
|
|
126
|
+
|
|
127
|
+
You can set your custom Chronic configuration if the defaults don't fit you.
|
|
128
|
+
|
|
129
|
+
For example, to assume a 24 hour clock instead of the default 12 hour clock:
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
set :chronic_options, :hours24 => true
|
|
133
|
+
|
|
134
|
+
# By default this would run the job every day at 3am
|
|
135
|
+
every 1.day, :at => '3:00' do
|
|
136
|
+
runner "MyModel.nightly_archive_job"
|
|
137
|
+
end
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
You can see a list of all available options here: <https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb>
|
|
141
|
+
|
|
142
|
+
### Customize email recipient with the `MAILTO` environment variable
|
|
143
|
+
|
|
144
|
+
Output from the jobs is sent to the email address configured in the `MAILTO` environment variable.
|
|
145
|
+
|
|
146
|
+
There are many ways to further configure the recipient.
|
|
147
|
+
|
|
148
|
+
Example: A global configuration, overriding the environment's value:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
env 'MAILTO', 'output_of_cron@example.com'
|
|
152
|
+
|
|
153
|
+
every 3.hours do
|
|
154
|
+
command "/usr/bin/my_great_command"
|
|
155
|
+
end
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Example: A `MAILTO` configured for all the jobs in an interval block:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
every 3.hours, mailto: 'my_super_command@example.com' do
|
|
162
|
+
command "/usr/bin/my_super_command"
|
|
163
|
+
end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Example: A `MAILTO` configured for a single job:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
every 3.hours do
|
|
170
|
+
command "/usr/bin/my_super_command", mailto: 'my_super_command_output@example.com'
|
|
171
|
+
end
|
|
172
|
+
```
|
|
173
|
+
|
|
99
174
|
### Capistrano integration
|
|
100
175
|
|
|
101
176
|
Use the built-in Capistrano recipe for easy crontab updates with deploys. For Capistrano V3, see the next section.
|
|
@@ -123,7 +198,7 @@ require "whenever/capistrano"
|
|
|
123
198
|
|
|
124
199
|
The capistrano variable `:stage` should be the one holding your environment name. This will make the correct `:environment` available in your `schedule.rb`.
|
|
125
200
|
|
|
126
|
-
If both your environments are on the same server you'll want to namespace them or they'll overwrite each other when you deploy:
|
|
201
|
+
If both your environments are on the same server you'll want to namespace them, or they'll overwrite each other when you deploy:
|
|
127
202
|
|
|
128
203
|
```ruby
|
|
129
204
|
set :whenever_environment, defer { stage }
|
|
@@ -131,6 +206,13 @@ set :whenever_identifier, defer { "#{application}_#{stage}" }
|
|
|
131
206
|
require "whenever/capistrano"
|
|
132
207
|
```
|
|
133
208
|
|
|
209
|
+
If you use a schedule at an alternative path, you may configure it like so:
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
set :whenever_load_file, defer { "#{release_path}/somewhere/else/schedule.rb" }
|
|
213
|
+
require "whenever/capistrano"
|
|
214
|
+
```
|
|
215
|
+
|
|
134
216
|
### Capistrano V3 Integration
|
|
135
217
|
|
|
136
218
|
In your "Capfile" file:
|
|
@@ -139,12 +221,14 @@ In your "Capfile" file:
|
|
|
139
221
|
require "whenever/capistrano"
|
|
140
222
|
```
|
|
141
223
|
|
|
142
|
-
Take a look at the load:defaults (
|
|
224
|
+
Take a look at the [load:defaults task](https://github.com/javan/whenever/blob/master/lib/whenever/capistrano/v3/tasks/whenever.rake) (bottom of file) for options you can set. For example, to namespace the crontab entries by application and stage do this in your "config/deploy.rb" file:
|
|
143
225
|
|
|
144
226
|
```ruby
|
|
145
227
|
set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }
|
|
146
228
|
```
|
|
147
229
|
|
|
230
|
+
The Capistrano integration by default expects the `:application` variable to be set in order to scope jobs in the crontab.
|
|
231
|
+
|
|
148
232
|
### Capistrano roles
|
|
149
233
|
|
|
150
234
|
The first thing to know about the new roles support is that it is entirely
|
|
@@ -153,10 +237,10 @@ different servers in your capistrano deployment, then you can safely stop readin
|
|
|
153
237
|
now and everything should just work the same way it always has.
|
|
154
238
|
|
|
155
239
|
When you define a job in your schedule.rb file, by default it will be deployed to
|
|
156
|
-
all servers in the whenever_roles list (which defaults to [:db]).
|
|
240
|
+
all servers in the whenever_roles list (which defaults to `[:db]`).
|
|
157
241
|
|
|
158
242
|
However, if you want to restrict certain jobs to only run on subset of servers,
|
|
159
|
-
you can add a
|
|
243
|
+
you can add a `:roles => [...]` argument to their definitions. **Make sure to add
|
|
160
244
|
that role to the whenever_roles list in your deploy.rb.**
|
|
161
245
|
|
|
162
246
|
When you run `cap deploy`, jobs with a :roles list specified will only be added to
|
|
@@ -165,8 +249,8 @@ the crontabs on servers with one or more of the roles in that list.
|
|
|
165
249
|
Jobs with no :roles argument will be deployed to all servers in the whenever_roles
|
|
166
250
|
list. This is to maintain backward compatibility with previous releases of whenever.
|
|
167
251
|
|
|
168
|
-
So, for example, with the default whenever_roles of [:db]
|
|
169
|
-
deployed to all servers with the
|
|
252
|
+
So, for example, with the default whenever_roles of `[:db]`, a job like this would be
|
|
253
|
+
deployed to all servers with the `:db` role:
|
|
170
254
|
|
|
171
255
|
```ruby
|
|
172
256
|
every :day, :at => '12:20am' do
|
|
@@ -174,7 +258,7 @@ every :day, :at => '12:20am' do
|
|
|
174
258
|
end
|
|
175
259
|
```
|
|
176
260
|
|
|
177
|
-
If we set whenever_roles to [:db, :app] in deploy.rb, and have the following
|
|
261
|
+
If we set whenever_roles to `[:db, :app]` in deploy.rb, and have the following
|
|
178
262
|
jobs in schedule.rb:
|
|
179
263
|
|
|
180
264
|
```ruby
|
|
@@ -209,14 +293,13 @@ If your production environment uses RVM (Ruby Version Manager) you will run into
|
|
|
209
293
|
|
|
210
294
|
This tells rvm to trust all rvmrc files.
|
|
211
295
|
|
|
212
|
-
###
|
|
296
|
+
### Heroku?
|
|
213
297
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
```
|
|
298
|
+
No. Heroku does not support cron, instead providing [Heroku Scheduler](https://devcenter.heroku.com/articles/scheduler). If you deploy to Heroku, you should use that rather than Whenever.
|
|
299
|
+
|
|
300
|
+
### Testing
|
|
218
301
|
|
|
219
|
-
|
|
302
|
+
[whenever-test](https://github.com/heartbits/whenever-test) is an extension to Whenever for testing a Whenever schedule.
|
|
220
303
|
|
|
221
304
|
### Credit
|
|
222
305
|
|
|
@@ -235,8 +318,8 @@ It's a little bit dated now, but remains a good introduction.
|
|
|
235
318
|
|
|
236
319
|
----
|
|
237
320
|
|
|
238
|
-
|
|
321
|
+
[](http://travis-ci.org/javan/whenever)
|
|
239
322
|
|
|
240
323
|
----
|
|
241
324
|
|
|
242
|
-
Copyright ©
|
|
325
|
+
Copyright © 2017 Javan Makhmali
|
data/Rakefile
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
require 'bundler'
|
|
3
|
-
rescue LoadError => e
|
|
4
|
-
warn("warning: Could not load bundler: #{e}")
|
|
5
|
-
warn(" Some rake tasks will not be defined")
|
|
6
|
-
else
|
|
7
|
-
Bundler::GemHelper.install_tasks
|
|
8
|
-
end
|
|
9
|
-
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
10
2
|
require 'rake/testtask'
|
|
3
|
+
|
|
11
4
|
Rake::TestTask.new(:test) do |test|
|
|
12
5
|
test.libs << 'lib' << 'test'
|
|
13
6
|
test.pattern = 'test/{functional,unit}/**/*_test.rb'
|
|
14
7
|
test.verbose = true
|
|
15
8
|
end
|
|
16
9
|
|
|
17
|
-
task :default => :test
|
|
10
|
+
task :default => :test
|
data/bin/whenever
CHANGED
|
@@ -35,6 +35,9 @@ OptionParser.new do |opts|
|
|
|
35
35
|
opts.on('-r', '--roles [role1,role2]', 'Comma-separated list of server roles to generate cron jobs for') do |roles|
|
|
36
36
|
options[:roles] = roles.split(',').map(&:to_sym) if roles
|
|
37
37
|
end
|
|
38
|
+
opts.on('-x', '--crontab-command [command]', 'Default: crontab') do |crontab_command|
|
|
39
|
+
options[:crontab_command] = crontab_command if crontab_command
|
|
40
|
+
end
|
|
38
41
|
opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION}"; exit(0) }
|
|
39
42
|
end.parse!
|
|
40
43
|
|
data/bin/wheneverize
CHANGED
|
@@ -18,7 +18,7 @@ OptionParser.new do |opts|
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
unless ARGV.empty?
|
|
21
|
-
if !File.
|
|
21
|
+
if !File.exist?(ARGV.first)
|
|
22
22
|
abort "`#{ARGV.first}' does not exist."
|
|
23
23
|
elsif !File.directory?(ARGV.first)
|
|
24
24
|
abort "`#{ARGV.first}' is not a directory."
|
|
@@ -54,13 +54,16 @@ file = 'config/schedule.rb'
|
|
|
54
54
|
base = ARGV.empty? ? '.' : ARGV.shift
|
|
55
55
|
|
|
56
56
|
file = File.join(base, file)
|
|
57
|
-
if File.
|
|
57
|
+
if File.exist?(file)
|
|
58
58
|
warn "[skip] `#{file}' already exists"
|
|
59
|
-
elsif File.
|
|
59
|
+
elsif File.exist?(file.downcase)
|
|
60
60
|
warn "[skip] `#{file.downcase}' exists, which could conflict with `#{file}'"
|
|
61
|
-
elsif !File.exists?(File.dirname(file))
|
|
62
|
-
warn "[skip] directory `#{File.dirname(file)}' does not exist"
|
|
63
61
|
else
|
|
62
|
+
dir = File.dirname(file)
|
|
63
|
+
if !File.exist?(dir)
|
|
64
|
+
warn "[add] creating `#{dir}'"
|
|
65
|
+
FileUtils.mkdir_p(dir)
|
|
66
|
+
end
|
|
64
67
|
puts "[add] writing `#{file}'"
|
|
65
68
|
File.open(file, "w") { |f| f.write(content) }
|
|
66
69
|
end
|
|
@@ -7,10 +7,11 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
|
7
7
|
_cset(:whenever_options) { {:roles => fetch(:whenever_roles)} }
|
|
8
8
|
_cset(:whenever_command) { "whenever" }
|
|
9
9
|
_cset(:whenever_identifier) { fetch :application }
|
|
10
|
-
_cset(:whenever_environment) { fetch :rails_env, "production" }
|
|
10
|
+
_cset(:whenever_environment) { fetch :rails_env, fetch(:stage, "production") }
|
|
11
11
|
_cset(:whenever_variables) { "environment=#{fetch :whenever_environment}" }
|
|
12
12
|
_cset(:whenever_update_flags) { "--update-crontab #{fetch :whenever_identifier} --set #{fetch :whenever_variables}" }
|
|
13
13
|
_cset(:whenever_clear_flags) { "--clear-crontab #{fetch :whenever_identifier}" }
|
|
14
|
+
_cset(:whenever_path) { fetch :latest_release }
|
|
14
15
|
|
|
15
16
|
namespace :whenever do
|
|
16
17
|
desc "Update application's crontab entries using Whenever"
|
|
@@ -18,7 +19,7 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
|
18
19
|
args = {
|
|
19
20
|
:command => fetch(:whenever_command),
|
|
20
21
|
:flags => fetch(:whenever_update_flags),
|
|
21
|
-
:path => fetch(:
|
|
22
|
+
:path => fetch(:whenever_path)
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
if whenever_servers.any?
|
|
@@ -38,7 +39,7 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
|
38
39
|
args = {
|
|
39
40
|
:command => fetch(:whenever_command),
|
|
40
41
|
:flags => fetch(:whenever_clear_flags),
|
|
41
|
-
:path => fetch(:
|
|
42
|
+
:path => fetch(:whenever_path)
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
whenever_run_commands(args)
|
|
@@ -3,26 +3,37 @@ namespace :whenever do
|
|
|
3
3
|
args = Array(fetch(:whenever_command)) + args
|
|
4
4
|
|
|
5
5
|
on roles fetch(:whenever_roles) do |host|
|
|
6
|
-
|
|
7
|
-
within
|
|
6
|
+
args_for_host = block_given? ? args + Array(yield(host)) : args
|
|
7
|
+
within fetch(:whenever_path) do
|
|
8
8
|
with fetch(:whenever_command_environment_variables) do
|
|
9
|
-
execute
|
|
9
|
+
execute(*args_for_host)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
def load_file
|
|
16
|
+
file = fetch(:whenever_load_file)
|
|
17
|
+
if file
|
|
18
|
+
"-f #{file}"
|
|
19
|
+
else
|
|
20
|
+
''
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
15
24
|
desc "Update application's crontab entries using Whenever"
|
|
16
25
|
task :update_crontab do
|
|
17
26
|
setup_whenever_task do |host|
|
|
18
27
|
roles = host.roles_array.join(",")
|
|
19
|
-
[fetch(:whenever_update_flags),
|
|
28
|
+
[fetch(:whenever_update_flags), "--roles=#{roles}", load_file]
|
|
20
29
|
end
|
|
21
30
|
end
|
|
22
31
|
|
|
23
32
|
desc "Clear application's crontab entries using Whenever"
|
|
24
33
|
task :clear_crontab do
|
|
25
|
-
setup_whenever_task
|
|
34
|
+
setup_whenever_task do |host|
|
|
35
|
+
[fetch(:whenever_clear_flags), load_file]
|
|
36
|
+
end
|
|
26
37
|
end
|
|
27
38
|
|
|
28
39
|
after "deploy:updated", "whenever:update_crontab"
|
|
@@ -33,11 +44,13 @@ namespace :load do
|
|
|
33
44
|
task :defaults do
|
|
34
45
|
set :whenever_roles, ->{ :db }
|
|
35
46
|
set :whenever_command, ->{ [:bundle, :exec, :whenever] }
|
|
36
|
-
set :whenever_command_environment_variables, ->{
|
|
47
|
+
set :whenever_command_environment_variables, ->{ fetch(:default_env).merge!(rails_env: fetch(:whenever_environment)) }
|
|
37
48
|
set :whenever_identifier, ->{ fetch :application }
|
|
38
|
-
set :whenever_environment, ->{ fetch :rails_env, "production" }
|
|
49
|
+
set :whenever_environment, ->{ fetch :rails_env, fetch(:stage, "production") }
|
|
39
50
|
set :whenever_variables, ->{ "environment=#{fetch :whenever_environment}" }
|
|
51
|
+
set :whenever_load_file, ->{ nil }
|
|
40
52
|
set :whenever_update_flags, ->{ "--update-crontab #{fetch :whenever_identifier} --set #{fetch :whenever_variables}" }
|
|
41
53
|
set :whenever_clear_flags, ->{ "--clear-crontab #{fetch :whenever_identifier}" }
|
|
54
|
+
set :whenever_path, ->{ fetch :release_path }
|
|
42
55
|
end
|
|
43
56
|
end
|
data/lib/whenever/capistrano.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'capistrano/version'
|
|
2
2
|
|
|
3
3
|
if defined?(Capistrano::VERSION) && Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
|
|
4
|
-
load File.expand_path("../tasks/whenever.rake", __FILE__)
|
|
4
|
+
load File.expand_path("../capistrano/v3/tasks/whenever.rake", __FILE__)
|
|
5
5
|
else
|
|
6
6
|
require 'whenever/capistrano/v2/hooks'
|
|
7
7
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'fileutils'
|
|
2
|
-
require 'tempfile'
|
|
3
2
|
|
|
4
3
|
module Whenever
|
|
5
4
|
class CommandLine
|
|
@@ -10,11 +9,12 @@ module Whenever
|
|
|
10
9
|
def initialize(options={})
|
|
11
10
|
@options = options
|
|
12
11
|
|
|
13
|
-
@options[:
|
|
14
|
-
@options[:
|
|
15
|
-
@options[:
|
|
12
|
+
@options[:crontab_command] ||= 'crontab'
|
|
13
|
+
@options[:file] ||= 'config/schedule.rb'
|
|
14
|
+
@options[:cut] ||= 0
|
|
15
|
+
@options[:identifier] ||= default_identifier
|
|
16
16
|
|
|
17
|
-
if !File.
|
|
17
|
+
if !File.exist?(@options[:file]) && @options[:clear].nil?
|
|
18
18
|
warn("[fail] Can't find file: #{@options[:file]}")
|
|
19
19
|
exit(1)
|
|
20
20
|
end
|
|
@@ -29,6 +29,8 @@ module Whenever
|
|
|
29
29
|
exit(1)
|
|
30
30
|
end
|
|
31
31
|
@options[:cut] = @options[:cut].to_i
|
|
32
|
+
|
|
33
|
+
@timestamp = Time.now.to_s
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
def run
|
|
@@ -56,9 +58,10 @@ module Whenever
|
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
def read_crontab
|
|
59
|
-
return @current_crontab if
|
|
61
|
+
return @current_crontab if instance_variable_defined?(:@current_crontab)
|
|
60
62
|
|
|
61
|
-
command = [
|
|
63
|
+
command = [@options[:crontab_command]]
|
|
64
|
+
command << '-l'
|
|
62
65
|
command << "-u #{@options[:user]}" if @options[:user]
|
|
63
66
|
|
|
64
67
|
command_results = %x[#{command.join(' ')} 2> /dev/null]
|
|
@@ -66,42 +69,44 @@ module Whenever
|
|
|
66
69
|
end
|
|
67
70
|
|
|
68
71
|
def write_crontab(contents)
|
|
69
|
-
|
|
70
|
-
tmp_cron_file << contents
|
|
71
|
-
tmp_cron_file.fsync
|
|
72
|
-
|
|
73
|
-
command = ['crontab']
|
|
72
|
+
command = [@options[:crontab_command]]
|
|
74
73
|
command << "-u #{@options[:user]}" if @options[:user]
|
|
75
|
-
|
|
74
|
+
# Solaris/SmartOS cron does not support the - option to read from stdin.
|
|
75
|
+
command << "-" unless OS.solaris?
|
|
76
|
+
|
|
77
|
+
IO.popen(command.join(' '), 'r+') do |crontab|
|
|
78
|
+
crontab.write(contents)
|
|
79
|
+
crontab.close_write
|
|
80
|
+
end
|
|
76
81
|
|
|
77
|
-
|
|
82
|
+
success = $?.exitstatus.zero?
|
|
83
|
+
|
|
84
|
+
if success
|
|
78
85
|
action = 'written' if @options[:write]
|
|
79
86
|
action = 'updated' if @options[:update]
|
|
80
87
|
puts "[write] crontab file #{action}"
|
|
81
|
-
tmp_cron_file.close!
|
|
82
88
|
exit(0)
|
|
83
89
|
else
|
|
84
90
|
warn "[fail] Couldn't write crontab; try running `whenever' with no options to ensure your schedule file is valid."
|
|
85
|
-
tmp_cron_file.close!
|
|
86
91
|
exit(1)
|
|
87
92
|
end
|
|
88
93
|
end
|
|
89
94
|
|
|
90
95
|
def updated_crontab
|
|
91
96
|
# Check for unopened or unclosed identifier blocks
|
|
92
|
-
if read_crontab =~ Regexp.new("^#{
|
|
93
|
-
warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open}', but no '#{comment_close}'"
|
|
97
|
+
if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && (read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")).nil?
|
|
98
|
+
warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open(false)}', but no '#{comment_close(false)}'"
|
|
94
99
|
exit(1)
|
|
95
|
-
elsif (read_crontab =~ Regexp.new("^#{
|
|
96
|
-
warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close}', but no '#{comment_open}'"
|
|
100
|
+
elsif (read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$")).nil? && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
|
|
101
|
+
warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close(false)}', but no '#{comment_open(false)}'"
|
|
97
102
|
exit(1)
|
|
98
103
|
end
|
|
99
104
|
|
|
100
105
|
# If an existing identier block is found, replace it with the new cron entries
|
|
101
|
-
if read_crontab =~ Regexp.new("^#{
|
|
106
|
+
if read_crontab =~ Regexp.new("^#{comment_open_regex}\s*$") && read_crontab =~ Regexp.new("^#{comment_close_regex}\s*$")
|
|
102
107
|
# If the existing crontab file contains backslashes they get lost going through gsub.
|
|
103
108
|
# .gsub('\\', '\\\\\\') preserves them. Go figure.
|
|
104
|
-
read_crontab.gsub(Regexp.new("^#{
|
|
109
|
+
read_crontab.gsub(Regexp.new("^#{comment_open_regex}\s*$.+^#{comment_close_regex}\s*$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
|
|
105
110
|
else # Otherwise, append the new cron entries after any existing ones
|
|
106
111
|
[read_crontab, whenever_cron].join("\n\n")
|
|
107
112
|
end.gsub(/\n{3,}/, "\n\n") # More than two newlines becomes just two.
|
|
@@ -119,16 +124,32 @@ module Whenever
|
|
|
119
124
|
stripped_contents.gsub!(/\s+$/, $/)
|
|
120
125
|
end
|
|
121
126
|
|
|
122
|
-
def comment_base
|
|
123
|
-
|
|
127
|
+
def comment_base(include_timestamp = true)
|
|
128
|
+
if include_timestamp
|
|
129
|
+
"Whenever generated tasks for: #{@options[:identifier]} at: #{@timestamp}"
|
|
130
|
+
else
|
|
131
|
+
"Whenever generated tasks for: #{@options[:identifier]}"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def comment_open(include_timestamp = true)
|
|
136
|
+
"# Begin #{comment_base(include_timestamp)}"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def comment_close(include_timestamp = true)
|
|
140
|
+
"# End #{comment_base(include_timestamp)}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def comment_open_regex
|
|
144
|
+
"#{comment_open(false)}(#{timestamp_regex}|)"
|
|
124
145
|
end
|
|
125
146
|
|
|
126
|
-
def
|
|
127
|
-
"#
|
|
147
|
+
def comment_close_regex
|
|
148
|
+
"#{comment_close(false)}(#{timestamp_regex}|)"
|
|
128
149
|
end
|
|
129
150
|
|
|
130
|
-
def
|
|
131
|
-
"
|
|
151
|
+
def timestamp_regex
|
|
152
|
+
" at: \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} ([+-]\\d{4}|UTC)"
|
|
132
153
|
end
|
|
133
154
|
end
|
|
134
155
|
end
|