jenkins_cron 0.0.2
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/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +49 -0
- data/Rakefile +10 -0
- data/bin/jenkins_cron +7 -0
- data/jenkins_cron.gemspec +27 -0
- data/lib/jenkins_cron.rb +13 -0
- data/lib/jenkins_cron/cli.rb +51 -0
- data/lib/jenkins_cron/extentions/jenkins_api_client/job.rb +137 -0
- data/lib/jenkins_cron/jenkins.rb +18 -0
- data/lib/jenkins_cron/job.rb +31 -0
- data/lib/jenkins_cron/job/command.rb +43 -0
- data/lib/jenkins_cron/job/timer.rb +177 -0
- data/lib/jenkins_cron/schedule.rb +31 -0
- data/lib/jenkins_cron/version.rb +3 -0
- data/spec/jenkins_cron/job/command_spec.rb +15 -0
- data/spec/jenkins_cron/job/timer_spec.rb +85 -0
- data/spec/jenkins_cron/job_spec.rb +15 -0
- data/spec/jenkins_cron/schedule_spec.rb +24 -0
- data/spec/jenkins_cron_spec.rb +6 -0
- data/spec/spec_helper.rb +2 -0
- metadata +155 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ryosuke IWANAGA
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# JenkinsCron
|
2
|
+
|
3
|
+
Simple DSL to define Jenkins scheduled jobs.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'jenkins_cron'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install jenkins_cron
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
$ cat config/jenkins.yml
|
22
|
+
server_url: "http://jenkins.dev"
|
23
|
+
|
24
|
+
$ cat config/schedule/foo.rb
|
25
|
+
job :test1 do
|
26
|
+
command "whoami", user: "riywo"
|
27
|
+
timer every: 3.minute
|
28
|
+
end
|
29
|
+
|
30
|
+
$ jenkins_cron update foo
|
31
|
+
I, [2013-07-25T04:33:41.887344 #52816] INFO -- : Obtaining jobs matching filter 'foo-test1'
|
32
|
+
I, [2013-07-25T04:33:41.887470 #52816] INFO -- : GET /api/json
|
33
|
+
I, [2013-07-25T04:33:42.205541 #52816] INFO -- : Posting the config.xml of 'foo-test1'
|
34
|
+
I, [2013-07-25T04:33:42.205642 #52816] INFO -- : GET /api/json
|
35
|
+
I, [2013-07-25T04:33:42.228267 #52816] INFO -- : POST /job/foo-test1/config.xml
|
36
|
+
I, [2013-07-25T04:33:42.955815 #52816] INFO -- : Obtaining views based on filter 'foo'
|
37
|
+
I, [2013-07-25T04:33:42.955938 #52816] INFO -- : GET /api/json
|
38
|
+
|
39
|
+
## DSL
|
40
|
+
|
41
|
+
TODO: Write documentation
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
1. Fork it
|
46
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
47
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
48
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
49
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/jenkins_cron
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'jenkins_cron/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "jenkins_cron"
|
8
|
+
spec.version = JenkinsCron::VERSION
|
9
|
+
spec.authors = ["Ryosuke IWANAGA"]
|
10
|
+
spec.email = ["riywo.jp@gmail.com"]
|
11
|
+
spec.description = %q{A DSL for Jenkins cron job}
|
12
|
+
spec.summary = %q{Simple DSL to define Jenkins scheduled jobs}
|
13
|
+
spec.homepage = "https://github.com/riywo/jenkins_cron"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "thor"
|
22
|
+
spec.add_dependency "jenkins_api_client", "~> 0.13.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
end
|
data/lib/jenkins_cron.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "jenkins_cron/version"
|
2
|
+
require "jenkins_cron/cli"
|
3
|
+
require "jenkins_cron/jenkins"
|
4
|
+
require "jenkins_cron/schedule"
|
5
|
+
require "jenkins_cron/job"
|
6
|
+
require "jenkins_cron/job/command"
|
7
|
+
require "jenkins_cron/job/timer"
|
8
|
+
|
9
|
+
require "jenkins_cron/extentions/jenkins_api_client/job"
|
10
|
+
|
11
|
+
module JenkinsCron
|
12
|
+
# Your code goes here...
|
13
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
class JenkinsCron::CLI < Thor
|
5
|
+
class_option :config, type: :string, aliases: "-c", default: "config/jenkins.yml", desc: "Jenkins config file"
|
6
|
+
|
7
|
+
desc "update NAME", "Update Jenkins using config/schedule/NAME.rb"
|
8
|
+
def update(name)
|
9
|
+
schedule = JenkinsCron::Schedule.load(name, schedule_file(name))
|
10
|
+
jenkins.update(schedule)
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "version", "Display jenkins_cron version"
|
14
|
+
map ["-v", "--version"] => :version
|
15
|
+
def version
|
16
|
+
puts JenkinsCron::VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def jenkins
|
22
|
+
@jenkins ||= JenkinsCron::Jenkins.new(config)
|
23
|
+
end
|
24
|
+
|
25
|
+
def config
|
26
|
+
@config ||= YAML.load_file(config_file)
|
27
|
+
rescue SyntaxError
|
28
|
+
error("Can't parse config file: #{config_file}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def config_file
|
32
|
+
@config_file ||= options[:config]
|
33
|
+
unless File.exists? @config_file
|
34
|
+
error("Can't find config file: #{@config_file}")
|
35
|
+
end
|
36
|
+
@config_file
|
37
|
+
end
|
38
|
+
|
39
|
+
def schedule_file(name)
|
40
|
+
file = "config/schedule/#{name}.rb"
|
41
|
+
unless File.exists? file
|
42
|
+
error("Can't find schedule file: #{file}")
|
43
|
+
end
|
44
|
+
file
|
45
|
+
end
|
46
|
+
|
47
|
+
def error(message)
|
48
|
+
puts "ERROR: #{message}"
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "jenkins_api_client"
|
2
|
+
|
3
|
+
module JenkinsApi
|
4
|
+
class Client
|
5
|
+
class Job
|
6
|
+
def build_freestyle_config(params)
|
7
|
+
# Supported SCM providers
|
8
|
+
supported_scm = ["git", "subversion", "cvs"]
|
9
|
+
|
10
|
+
# Set default values for params that are not specified.
|
11
|
+
raise ArgumentError, "Job name must be specified" \
|
12
|
+
unless params.is_a?(Hash) && params[:name]
|
13
|
+
if params[:keep_dependencies].nil?
|
14
|
+
params[:keep_dependencies] = false
|
15
|
+
end
|
16
|
+
if params[:block_build_when_downstream_building].nil?
|
17
|
+
params[:block_build_when_downstream_building] = false
|
18
|
+
end
|
19
|
+
if params[:block_build_when_upstream_building].nil?
|
20
|
+
params[:block_build_when_upstream_building] = false
|
21
|
+
end
|
22
|
+
params[:concurrent_build] = false if params[:concurrent_build].nil?
|
23
|
+
if params[:notification_email]
|
24
|
+
if params[:notification_email_for_every_unstable].nil?
|
25
|
+
params[:notification_email_for_every_unstable] = false
|
26
|
+
end
|
27
|
+
if params[:notification_email_send_to_individuals].nil?
|
28
|
+
params[:notification_email_send_to_individuals] ||= false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
# SCM configurations and Error handling.
|
32
|
+
unless supported_scm.include?(params[:scm_provider]) ||
|
33
|
+
params[:scm_provider].nil?
|
34
|
+
raise "SCM #{params[:scm_provider]} is currently not supported"
|
35
|
+
end
|
36
|
+
if params[:scm_url].nil? && !params[:scm_provider].nil?
|
37
|
+
raise 'SCM URL must be specified'
|
38
|
+
end
|
39
|
+
if params[:scm_branch].nil? && !params[:scm_provider].nil?
|
40
|
+
params[:scm_branch] = "master"
|
41
|
+
end
|
42
|
+
if params[:scm_use_head_if_tag_not_found].nil?
|
43
|
+
params[:scm_use_head_if_tag_not_found] = false
|
44
|
+
end
|
45
|
+
|
46
|
+
# Child projects configuration and Error handling
|
47
|
+
if params[:child_threshold].nil? && !params[:child_projects].nil?
|
48
|
+
params[:child_threshold] = 'failure'
|
49
|
+
end
|
50
|
+
|
51
|
+
@logger.debug "Creating a freestyle job with params: #{params.inspect}"
|
52
|
+
|
53
|
+
# Build the Job xml file based on the parameters given
|
54
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') { |xml|
|
55
|
+
xml.project {
|
56
|
+
xml.actions
|
57
|
+
xml.description
|
58
|
+
xml.keepDependencies "#{params[:keep_dependencies]}"
|
59
|
+
xml.properties
|
60
|
+
# SCM related stuff
|
61
|
+
if params[:scm_provider] == 'subversion'
|
62
|
+
# Build subversion related XML portion
|
63
|
+
scm_subversion(params, xml)
|
64
|
+
elsif params[:scm_provider] == "cvs"
|
65
|
+
# Build CVS related XML portion
|
66
|
+
scm_cvs(params, xml)
|
67
|
+
elsif params[:scm_provider] == "git"
|
68
|
+
# Build Git related XML portion
|
69
|
+
scm_git(params, xml)
|
70
|
+
else
|
71
|
+
xml.scm(:class => "hudson.scm.NullSCM")
|
72
|
+
end
|
73
|
+
# Restrict job to run in a specified node
|
74
|
+
if params[:restricted_node]
|
75
|
+
xml.assignedNode "#{params[:restricted_node]}"
|
76
|
+
xml.canRoam "false"
|
77
|
+
else
|
78
|
+
xml.canRoam "true"
|
79
|
+
end
|
80
|
+
xml.disabled "false"
|
81
|
+
xml.blockBuildWhenDownstreamBuilding(
|
82
|
+
"#{params[:block_build_when_downstream_building]}")
|
83
|
+
xml.blockBuildWhenUpstreamBuilding(
|
84
|
+
"#{params[:block_build_when_upstream_building]}")
|
85
|
+
if params[:timer]
|
86
|
+
xml.triggers.vector {
|
87
|
+
xml.send("hudson.triggers.TimerTrigger") {
|
88
|
+
xml.spec params[:timer]
|
89
|
+
}
|
90
|
+
}
|
91
|
+
else
|
92
|
+
xml.triggers.vector
|
93
|
+
end
|
94
|
+
xml.concurrentBuild "#{params[:concurrent_build]}"
|
95
|
+
# Shell command stuff
|
96
|
+
xml.builders {
|
97
|
+
if params[:shell_command]
|
98
|
+
xml.send("hudson.tasks.Shell") {
|
99
|
+
xml.command "#{params[:shell_command]}"
|
100
|
+
}
|
101
|
+
end
|
102
|
+
}
|
103
|
+
# Adding Downstream projects
|
104
|
+
xml.publishers {
|
105
|
+
# Build portion of XML that adds child projects
|
106
|
+
child_projects(params, xml) if params[:child_projects]
|
107
|
+
# Build portion of XML that adds email notification
|
108
|
+
notification_email(params, xml) if params[:notification_email]
|
109
|
+
# Build portion of XML that adds skype notification
|
110
|
+
skype_notification(params, xml) if params[:skype_targets]
|
111
|
+
}
|
112
|
+
xml.buildWrappers
|
113
|
+
}
|
114
|
+
}
|
115
|
+
builder.to_xml
|
116
|
+
end
|
117
|
+
|
118
|
+
def create_freestyle(params)
|
119
|
+
xml = build_freestyle_config(params)
|
120
|
+
create(params[:name], xml)
|
121
|
+
end
|
122
|
+
|
123
|
+
def update_freestyle(params)
|
124
|
+
xml = build_freestyle_config(params)
|
125
|
+
post_config(params[:name], xml)
|
126
|
+
end
|
127
|
+
|
128
|
+
def create_or_update_freestyle(params)
|
129
|
+
if exists?(params[:name])
|
130
|
+
update_freestyle(params)
|
131
|
+
else
|
132
|
+
create_freestyle(params)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "jenkins_api_client"
|
2
|
+
|
3
|
+
class JenkinsCron::Jenkins
|
4
|
+
def initialize(config)
|
5
|
+
@client = JenkinsApi::Client.new(config)
|
6
|
+
end
|
7
|
+
|
8
|
+
def update(schedule)
|
9
|
+
schedule.each_jobs do |job|
|
10
|
+
@client.job.create_or_update_freestyle(job.params.dup)
|
11
|
+
end
|
12
|
+
|
13
|
+
@client.view.create_list_view(
|
14
|
+
name: schedule.name,
|
15
|
+
regex: "^#{schedule.name}-.+",
|
16
|
+
) unless @client.view.exists?(schedule.name)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class JenkinsCron::Job
|
2
|
+
attr_reader :name, :params
|
3
|
+
|
4
|
+
def initialize(schedule, name, &block)
|
5
|
+
@schedule = schedule
|
6
|
+
@name = name
|
7
|
+
@params = { name: "#{@schedule.name}-#{@name}" }
|
8
|
+
instance_eval(&block)
|
9
|
+
@params.freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def command(command, opts = {})
|
15
|
+
cmd = JenkinsCron::Job::Command.new(command, opts)
|
16
|
+
@params[:shell_command] = cmd.shell_command
|
17
|
+
end
|
18
|
+
|
19
|
+
def timer(opts = {}, &block)
|
20
|
+
timer = JenkinsCron::Job::Timer.new(opts, &block)
|
21
|
+
if @params[:timer].nil?
|
22
|
+
@params[:timer] = timer.to_s
|
23
|
+
else
|
24
|
+
@params[:timer] += "\n" + timer.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def options(key, value)
|
29
|
+
@params[key] = value
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class JenkinsCron::Job::Command
|
2
|
+
def initialize(command, opts = {})
|
3
|
+
@command = command
|
4
|
+
@opts = opts
|
5
|
+
end
|
6
|
+
|
7
|
+
def shell_command
|
8
|
+
script = export_env
|
9
|
+
script += "#{sh} -c '#{command}'\n"
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def export_env
|
15
|
+
env = @opts[:env] || {}
|
16
|
+
export = ""
|
17
|
+
env.each do |key, value|
|
18
|
+
export += "export #{key}=#{value}\n"
|
19
|
+
end
|
20
|
+
export
|
21
|
+
end
|
22
|
+
|
23
|
+
def sh
|
24
|
+
if @opts[:user]
|
25
|
+
#TODO use each user's shell
|
26
|
+
"sudo -u #{@opts[:user]} -H bash -l"
|
27
|
+
else
|
28
|
+
"bash"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def cd
|
33
|
+
if @opts[:cwd]
|
34
|
+
"cd #{@opts[:cwd].shellescape} && "
|
35
|
+
else
|
36
|
+
""
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def command
|
41
|
+
"#{cd}#{@command}"
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require "active_support/all"
|
2
|
+
require "chronic"
|
3
|
+
|
4
|
+
class JenkinsCron::Job::Timer
|
5
|
+
OPTS = [:every, :at, :min, :hour, :day, :month, :day_w, :once_an_hour, :once_a_day, :once_a_month, :once_a_day_w]
|
6
|
+
DAYS_W = [:Sunday, :Monday, :Tuesday, :Wednesday, :Thursday, :Friday, :Saturday]
|
7
|
+
WEEKDAY = [:Monday, :Tuesday, :Wednesday, :Thursday, :Friday]
|
8
|
+
WEEKEND = [:Sunday, :Saturday]
|
9
|
+
def initialize(opts = {}, &block)
|
10
|
+
initialize_with_opts(opts) if opts.size > 0
|
11
|
+
instance_eval(&block) if block_given?
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"#{min} #{hour} #{day} #{month} #{day_w}"
|
16
|
+
end
|
17
|
+
alias :inspect :to_s
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def initialize_with_opts(opts)
|
22
|
+
opts.each do |opt, value|
|
23
|
+
next unless OPTS.include?(opt)
|
24
|
+
send("initialize_#{opt}", value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize_every(time)
|
29
|
+
case time
|
30
|
+
when 0.seconds...1.minute
|
31
|
+
raise ArgumentError, "Must be in minutes or higher"
|
32
|
+
when 1.minute...1.hour
|
33
|
+
min every: time/60
|
34
|
+
when 1.hour...1.day
|
35
|
+
min :once
|
36
|
+
hour every: (time/60/60).round
|
37
|
+
when 1.day...1.month
|
38
|
+
min :once
|
39
|
+
hour :once
|
40
|
+
day every: (time/60/60/24).round
|
41
|
+
when 1.month..12.months
|
42
|
+
min :once
|
43
|
+
hour :once
|
44
|
+
day :once
|
45
|
+
month every: (time/60/60/24/30).round
|
46
|
+
when *DAYS_W
|
47
|
+
min :once
|
48
|
+
hour :once
|
49
|
+
day_w DAYS_W.index(time)
|
50
|
+
when :Weekday
|
51
|
+
min :once
|
52
|
+
hour :once
|
53
|
+
day_w WEEKDAY.map {|d| DAYS_W.index(d) }
|
54
|
+
when :Weekend
|
55
|
+
min :once
|
56
|
+
hour :once
|
57
|
+
day_w WEEKEND.map {|d| DAYS_W.index(d) }
|
58
|
+
else
|
59
|
+
raise ArgumentError, "Invalid every option '#{time}'"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize_at(time)
|
64
|
+
at = time.is_a?(String) ? Chronic.parse(time) : time
|
65
|
+
raise ArgumentError, "Invalid at option '#{time}'" if at.nil?
|
66
|
+
hour at.hour
|
67
|
+
min at.min
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize_min(time)
|
71
|
+
min time
|
72
|
+
end
|
73
|
+
|
74
|
+
def initialize_hour(time)
|
75
|
+
hour time
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize_day(time)
|
79
|
+
day time
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize_month(time)
|
83
|
+
month time
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize_day_w(time)
|
87
|
+
day_w time
|
88
|
+
end
|
89
|
+
|
90
|
+
def initialize_once_an_hour(time)
|
91
|
+
min :once
|
92
|
+
hour time
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize_once_a_day(time)
|
96
|
+
min :once
|
97
|
+
hour :once
|
98
|
+
day time
|
99
|
+
end
|
100
|
+
|
101
|
+
def initialize_once_a_month(time)
|
102
|
+
min :once
|
103
|
+
hour :once
|
104
|
+
day :once
|
105
|
+
month time
|
106
|
+
end
|
107
|
+
|
108
|
+
def initialize_once_a_day_w(time)
|
109
|
+
min :once
|
110
|
+
hour :once
|
111
|
+
time = case time
|
112
|
+
when Array
|
113
|
+
time.map { |d| DAYS_W.include?(d) ? DAYS_W.index(d) : d }
|
114
|
+
else
|
115
|
+
DAYS_W.include?(time) ? DAYS_W.index(time) : time
|
116
|
+
end
|
117
|
+
day_w time
|
118
|
+
end
|
119
|
+
|
120
|
+
def min(*args)
|
121
|
+
@min = Field.new(*args) if(@min.nil? or args.length > 0)
|
122
|
+
@min
|
123
|
+
end
|
124
|
+
|
125
|
+
def hour(*args)
|
126
|
+
@hour = Field.new(*args) if(@hour.nil? or args.length > 0)
|
127
|
+
@hour
|
128
|
+
end
|
129
|
+
|
130
|
+
def day(*args)
|
131
|
+
@day = Field.new(*args) if(@day.nil? or args.length > 0)
|
132
|
+
@day
|
133
|
+
end
|
134
|
+
|
135
|
+
def month(*args)
|
136
|
+
@month = Field.new(*args) if(@month.nil? or args.length > 0)
|
137
|
+
@month
|
138
|
+
end
|
139
|
+
|
140
|
+
def day_w(*args)
|
141
|
+
@day_w = Field.new(*args) if(@day_w.nil? or args.length > 0)
|
142
|
+
@day_w
|
143
|
+
end
|
144
|
+
|
145
|
+
class Field
|
146
|
+
def initialize(*args)
|
147
|
+
@opts = args.last.is_a?(Hash) ? args.pop : {}
|
148
|
+
@every = @opts[:every] if @opts.has_key? :every
|
149
|
+
|
150
|
+
case args.length
|
151
|
+
when 0
|
152
|
+
@value = (@every.nil? or @every == 1) ? "*" : "H"
|
153
|
+
when 1
|
154
|
+
@value = args[0] == :once ? "H" : args[0]
|
155
|
+
else
|
156
|
+
@value = args
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def to_s
|
161
|
+
unless @string
|
162
|
+
@string = case @value
|
163
|
+
when Range
|
164
|
+
"H(#{@value.first}-#{@value.last})"
|
165
|
+
when Array
|
166
|
+
@value.join(",")
|
167
|
+
when Fixnum
|
168
|
+
@value.to_s
|
169
|
+
when "H","*"
|
170
|
+
@value
|
171
|
+
end
|
172
|
+
@string += "/#{@every}" if (!@every.nil? and @every != 1)
|
173
|
+
end
|
174
|
+
@string
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class JenkinsCron::Schedule
|
2
|
+
attr_reader :name
|
3
|
+
|
4
|
+
def initialize(name, &block)
|
5
|
+
@name = name
|
6
|
+
@jobs = {}
|
7
|
+
instance_eval(&block) if block_given?
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.load(name, file_path)
|
11
|
+
block = File.read(file_path)
|
12
|
+
new(name) { eval(block) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def each_jobs
|
16
|
+
@jobs.each do |name, job|
|
17
|
+
yield job
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def job(job_name, &block)
|
22
|
+
if block_given? # initialize
|
23
|
+
@jobs[job_name] = JenkinsCron::Job.new(self, job_name, &block)
|
24
|
+
else
|
25
|
+
@jobs[job_name]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe JenkinsCron::Job::Command do
|
2
|
+
it "create a simple example of job/command" do
|
3
|
+
cmd = JenkinsCron::Job::Command.new "env | sort"
|
4
|
+
expect(cmd.shell_command).to eq(<<-EOF)
|
5
|
+
bash -c 'env | sort'
|
6
|
+
EOF
|
7
|
+
end
|
8
|
+
it "create an example of job/command with options" do
|
9
|
+
cmd = JenkinsCron::Job::Command.new "env | sort", env: {PORT: 5000}, user: "app", cwd: "/var/app"
|
10
|
+
expect(cmd.shell_command).to eq(<<-EOF)
|
11
|
+
export PORT=5000
|
12
|
+
sudo -u app -H bash -l -c 'cd /var/app && env | sort'
|
13
|
+
EOF
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
describe JenkinsCron::Job::Timer do
|
2
|
+
it "is a first test" do
|
3
|
+
timer = JenkinsCron::Job::Timer.new do
|
4
|
+
hour every: 3
|
5
|
+
min :once
|
6
|
+
end
|
7
|
+
expect(timer.to_s).to eq("H H/3 * * *")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "is a second test" do
|
11
|
+
timer = JenkinsCron::Job::Timer.new do
|
12
|
+
month every: 3
|
13
|
+
day (1..15), every: 2
|
14
|
+
day_w 1,5
|
15
|
+
hour 1
|
16
|
+
min :once
|
17
|
+
end
|
18
|
+
expect(timer.to_s).to eq("H 1 H(1-15)/2 H/3 1,5")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "is a third test" do
|
22
|
+
timer = JenkinsCron::Job::Timer.new every: 3.hours
|
23
|
+
expect(timer.to_s).to eq("H H/3 * * *")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "is a forth test" do
|
27
|
+
timer = JenkinsCron::Job::Timer.new every: 2.weeks
|
28
|
+
expect(timer.to_s).to eq("H H H/14 * *")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "is a fifth test" do
|
32
|
+
timer = JenkinsCron::Job::Timer.new every: 3.hours, min: 29
|
33
|
+
expect(timer.to_s).to eq("29 H/3 * * *")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is a sixth test" do
|
37
|
+
timer = JenkinsCron::Job::Timer.new every: 2.days, at: "10:00 pm"
|
38
|
+
expect(timer.to_s).to eq("0 22 H/2 * *")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "is a seventh test" do
|
42
|
+
timer = JenkinsCron::Job::Timer.new every: :Monday
|
43
|
+
expect(timer.to_s).to eq("H H * * 1")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "is a eightth test" do
|
47
|
+
timer = JenkinsCron::Job::Timer.new every: :Weekday
|
48
|
+
expect(timer.to_s).to eq("H H * * 1,2,3,4,5")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "is a nineth test" do
|
52
|
+
timer = JenkinsCron::Job::Timer.new every: :Weekend, at: "7:00 pm"
|
53
|
+
expect(timer.to_s).to eq("0 19 * * 0,6")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "is a tenth test" do
|
57
|
+
timer = JenkinsCron::Job::Timer.new every: 1.day, month: 4
|
58
|
+
expect(timer.to_s).to eq("H H * 4 *")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "is a eleventh test" do
|
62
|
+
timer = JenkinsCron::Job::Timer.new once_an_hour: 10
|
63
|
+
expect(timer.to_s).to eq("H 10 * * *")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "is a twelfth test" do
|
67
|
+
timer = JenkinsCron::Job::Timer.new once_an_hour: [3,6,12]
|
68
|
+
expect(timer.to_s).to eq("H 3,6,12 * * *")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "is a thirteenth test" do
|
72
|
+
timer = JenkinsCron::Job::Timer.new once_a_day: [3,6,12], hour: 10
|
73
|
+
expect(timer.to_s).to eq("H 10 3,6,12 * *")
|
74
|
+
end
|
75
|
+
|
76
|
+
it "is a fourteenth test" do
|
77
|
+
timer = JenkinsCron::Job::Timer.new once_a_month: [3,6,12], day: 15
|
78
|
+
expect(timer.to_s).to eq("H H 15 3,6,12 *")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "is a fifteenth test" do
|
82
|
+
timer = JenkinsCron::Job::Timer.new once_a_day_w: [:Monday, :Friday]
|
83
|
+
expect(timer.to_s).to eq("H H * * 1,5")
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe JenkinsCron::Job do
|
2
|
+
it "create a simple example of job" do
|
3
|
+
schedule = JenkinsCron::Schedule.new :schedule1
|
4
|
+
job = JenkinsCron::Job.new schedule, :test1 do
|
5
|
+
command "echo test1"
|
6
|
+
timer every: 5.minute
|
7
|
+
timer every: :Monday
|
8
|
+
end
|
9
|
+
|
10
|
+
expect(job.name).to be(:test1)
|
11
|
+
expect(job.params[:name]).to eq("schedule1-test1")
|
12
|
+
expect(job.params[:shell_command]).to eq("bash -c 'echo test1'\n")
|
13
|
+
expect(job.params[:timer]).to eq("H/5 * * * *\nH H * * 1")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
describe JenkinsCron::Schedule do
|
2
|
+
it "create a simple example of schedule" do
|
3
|
+
schedule = JenkinsCron::Schedule.new :group1 do
|
4
|
+
job :test1 do
|
5
|
+
options :shell_command, "echo test1"
|
6
|
+
options :timer, "* * * * *"
|
7
|
+
end
|
8
|
+
|
9
|
+
job :test2 do
|
10
|
+
options :shell_command, "echo test2"
|
11
|
+
options :timer, "* * * * *"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(schedule.name).to eq(:group1)
|
16
|
+
|
17
|
+
expect(schedule.job(:test1)).to be_true
|
18
|
+
expect(schedule.job(:test2)).to be_true
|
19
|
+
expect(schedule.job(:test3)).to be_false
|
20
|
+
|
21
|
+
expect(schedule.job(:test1).params[:shell_command]).to eq("echo test1")
|
22
|
+
expect(schedule.job(:test2).params[:shell_command]).to eq("echo test2")
|
23
|
+
end
|
24
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jenkins_cron
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryosuke IWANAGA
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: jenkins_api_client
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.13.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.13.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: A DSL for Jenkins cron job
|
95
|
+
email:
|
96
|
+
- riywo.jp@gmail.com
|
97
|
+
executables:
|
98
|
+
- jenkins_cron
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/jenkins_cron
|
108
|
+
- jenkins_cron.gemspec
|
109
|
+
- lib/jenkins_cron.rb
|
110
|
+
- lib/jenkins_cron/cli.rb
|
111
|
+
- lib/jenkins_cron/extentions/jenkins_api_client/job.rb
|
112
|
+
- lib/jenkins_cron/jenkins.rb
|
113
|
+
- lib/jenkins_cron/job.rb
|
114
|
+
- lib/jenkins_cron/job/command.rb
|
115
|
+
- lib/jenkins_cron/job/timer.rb
|
116
|
+
- lib/jenkins_cron/schedule.rb
|
117
|
+
- lib/jenkins_cron/version.rb
|
118
|
+
- spec/jenkins_cron/job/command_spec.rb
|
119
|
+
- spec/jenkins_cron/job/timer_spec.rb
|
120
|
+
- spec/jenkins_cron/job_spec.rb
|
121
|
+
- spec/jenkins_cron/schedule_spec.rb
|
122
|
+
- spec/jenkins_cron_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
homepage: https://github.com/riywo/jenkins_cron
|
125
|
+
licenses:
|
126
|
+
- MIT
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ! '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubyforge_project:
|
145
|
+
rubygems_version: 1.8.23
|
146
|
+
signing_key:
|
147
|
+
specification_version: 3
|
148
|
+
summary: Simple DSL to define Jenkins scheduled jobs
|
149
|
+
test_files:
|
150
|
+
- spec/jenkins_cron/job/command_spec.rb
|
151
|
+
- spec/jenkins_cron/job/timer_spec.rb
|
152
|
+
- spec/jenkins_cron/job_spec.rb
|
153
|
+
- spec/jenkins_cron/schedule_spec.rb
|
154
|
+
- spec/jenkins_cron_spec.rb
|
155
|
+
- spec/spec_helper.rb
|