servant 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/Gemfile +5 -0
- data/LICENSE +22 -0
- data/README.md +126 -0
- data/Rakefile +2 -0
- data/bin/servant +38 -0
- data/lib/servant/ci.rb +18 -0
- data/lib/servant/config.rb +52 -0
- data/lib/servant/environment.rb +110 -0
- data/lib/servant/jobcollections.rb +19 -0
- data/lib/servant/mixin/command/config.rb +121 -0
- data/lib/servant/mixin/command.rb +37 -0
- data/lib/servant/mixin/log_rotator.rb +37 -0
- data/lib/servant/mixin/trigger.rb +34 -0
- data/lib/servant/version.rb +3 -0
- data/lib/servant/writer/xmlwriter.rb +198 -0
- data/lib/servant.rb +5 -0
- data/servant.gemspec +18 -0
- data/servant.rb +15 -0
- metadata +81 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Shuhei Tanuma
|
|
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,126 @@
|
|
|
1
|
+
# Servant
|
|
2
|
+
|
|
3
|
+
Servant is a tool for management such a messy Jenkins jobs.
|
|
4
|
+
It provides simple, inheritable and powerful configuration file which represents Jenkins's job xml.
|
|
5
|
+
|
|
6
|
+
# Installation
|
|
7
|
+
|
|
8
|
+
````
|
|
9
|
+
gem install servant
|
|
10
|
+
````
|
|
11
|
+
|
|
12
|
+
# Requirements
|
|
13
|
+
|
|
14
|
+
* jenkins (1.440 higher as it supports update-job command)
|
|
15
|
+
* jenkins-cli
|
|
16
|
+
* log4r
|
|
17
|
+
* nokogiri
|
|
18
|
+
|
|
19
|
+
# Quick Setup
|
|
20
|
+
|
|
21
|
+
````
|
|
22
|
+
mkdir Jobs
|
|
23
|
+
cd Jobs
|
|
24
|
+
servant init
|
|
25
|
+
cat > recipes/first_job.rb <<EOF
|
|
26
|
+
name "first_job"
|
|
27
|
+
description "my first job for jenkins"
|
|
28
|
+
EOF
|
|
29
|
+
|
|
30
|
+
servant provision
|
|
31
|
+
# this will add first_job job to localhost jenkins and reload.
|
|
32
|
+
|
|
33
|
+
````
|
|
34
|
+
|
|
35
|
+
# Servant Configurations
|
|
36
|
+
|
|
37
|
+
Servant requires ServantFile on your project directory.
|
|
38
|
+
|
|
39
|
+
````ruby
|
|
40
|
+
Servant::Config.run do | config |
|
|
41
|
+
config.ci.url = "http://localhost:8080"
|
|
42
|
+
|
|
43
|
+
config.ci.cli = "/tmp/moe/servant/jenkins-cli.jar"
|
|
44
|
+
config.ci.cli_options = []
|
|
45
|
+
|
|
46
|
+
# optional (for update config.xml directly)
|
|
47
|
+
config.ci.user = 'daemon'
|
|
48
|
+
config.ci.home = "/home/Shared/Library/Jenkins"
|
|
49
|
+
|
|
50
|
+
config.ci.jobs :jobs do | jobs |
|
|
51
|
+
jobs.path = "recipes"
|
|
52
|
+
|
|
53
|
+
Dir::glob("./#{jobs.path}/*.rb").each {|name|
|
|
54
|
+
jobs.add File.basename(name,".rb")
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
````
|
|
59
|
+
|
|
60
|
+
# Commands
|
|
61
|
+
|
|
62
|
+
````
|
|
63
|
+
servant provision
|
|
64
|
+
servant reload
|
|
65
|
+
````
|
|
66
|
+
|
|
67
|
+
# job Configurations
|
|
68
|
+
|
|
69
|
+
````ruby
|
|
70
|
+
# meta data (required)
|
|
71
|
+
name "php-sundown-release-build"
|
|
72
|
+
description "php-sundown is a fast markdown parser & render"
|
|
73
|
+
enabled true
|
|
74
|
+
|
|
75
|
+
# abstract means: don't register job
|
|
76
|
+
abstract false
|
|
77
|
+
|
|
78
|
+
# extends means: inherit specified servant job
|
|
79
|
+
extends "parent_task"
|
|
80
|
+
|
|
81
|
+
# log_rotator (optional)
|
|
82
|
+
log_rotator.days_to_keep 5
|
|
83
|
+
log_rotator.num_to_keep 5
|
|
84
|
+
log_rotator.artifact_days_to_keep 5
|
|
85
|
+
log_rotator.artifact_num_to_keep 5
|
|
86
|
+
|
|
87
|
+
# triggers (optional)
|
|
88
|
+
trigger.poll "* * * * *"
|
|
89
|
+
trigger.periodical "* * * * *"
|
|
90
|
+
|
|
91
|
+
# build parameters (optional)
|
|
92
|
+
build_params [:text, "name","default", "description"]
|
|
93
|
+
build_params [:password, "name","default", "description"]
|
|
94
|
+
build_params [:file, "name","default", "description"]
|
|
95
|
+
build_params [:bool, "name","default", "description"]
|
|
96
|
+
build_params [:choice, "name","default", "description", ["choices..."]]
|
|
97
|
+
build_params [:string, "name","default", "description"]
|
|
98
|
+
|
|
99
|
+
# build steps (optional)
|
|
100
|
+
build_step :shell_script, <<-EOH
|
|
101
|
+
cd {$HOME}
|
|
102
|
+
phpunit
|
|
103
|
+
EOH
|
|
104
|
+
|
|
105
|
+
# repository definition (optional)
|
|
106
|
+
scm_type :git do | repositories |
|
|
107
|
+
repositories.add [
|
|
108
|
+
:config_version, 2,
|
|
109
|
+
:url , "https://github.com/chobie/php-sundown.git",
|
|
110
|
+
:name , "",
|
|
111
|
+
:refspec , "",
|
|
112
|
+
:branches, "",
|
|
113
|
+
]
|
|
114
|
+
end
|
|
115
|
+
````
|
|
116
|
+
# License
|
|
117
|
+
|
|
118
|
+
MIT License
|
|
119
|
+
|
|
120
|
+
# Supported features
|
|
121
|
+
|
|
122
|
+
* log rotator
|
|
123
|
+
* trigger
|
|
124
|
+
* build_params
|
|
125
|
+
* build step
|
|
126
|
+
* Git
|
data/Rakefile
ADDED
data/bin/servant
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
require 'pp'
|
|
3
|
+
|
|
4
|
+
require 'rubygems'
|
|
5
|
+
require 'bundler/setup'
|
|
6
|
+
require 'nokogiri'
|
|
7
|
+
require 'log4r'
|
|
8
|
+
|
|
9
|
+
require 'tempfile'
|
|
10
|
+
|
|
11
|
+
require 'servant/environment'
|
|
12
|
+
require 'servant/config'
|
|
13
|
+
require 'servant/ci'
|
|
14
|
+
require 'servant/jobcollections'
|
|
15
|
+
require 'servant/mixin/trigger'
|
|
16
|
+
require 'servant/mixin/command'
|
|
17
|
+
require 'servant/mixin/command/config'
|
|
18
|
+
require 'servant/mixin/log_rotator'
|
|
19
|
+
require 'servant/writer/xmlwriter'
|
|
20
|
+
|
|
21
|
+
require 'base64'
|
|
22
|
+
|
|
23
|
+
$stdout.sync = true
|
|
24
|
+
$stderr.sync = true
|
|
25
|
+
|
|
26
|
+
logger = Log4r::Logger.new("servant::bin::servant")
|
|
27
|
+
formatter = Log4r::PatternFormatter.new(
|
|
28
|
+
:pattern => "[%d] %C [%l]: %M",
|
|
29
|
+
:date_format => "%Y/%m/%d %H:%M:%S"
|
|
30
|
+
)
|
|
31
|
+
logger.add(Log4r::StdoutOutputter.new($stderr, :formatter => formatter))
|
|
32
|
+
#logger.debug("`servant` invoked: #{ARGV.inspect}")
|
|
33
|
+
|
|
34
|
+
opts = {}
|
|
35
|
+
opts[:logger] = logger
|
|
36
|
+
|
|
37
|
+
env = Servant::Environment.new(opts)
|
|
38
|
+
env.run()
|
data/lib/servant/ci.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
class CI
|
|
3
|
+
attr_accessor :home, :user, :cli, :url, :cli_options
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@home = ""
|
|
7
|
+
@user = ""
|
|
8
|
+
@cli = ""
|
|
9
|
+
@url = ""
|
|
10
|
+
@cli_options = []
|
|
11
|
+
@jobs = Servant::JobCollections.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def jobs(type)
|
|
15
|
+
yield(@jobs)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
class Config
|
|
3
|
+
attr_accessor :ci
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@ci = nil
|
|
7
|
+
@recipes = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def set_ci(ci)
|
|
11
|
+
@ci = ci
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get_recipe
|
|
15
|
+
@recipes
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def set_recipe(recipe)
|
|
19
|
+
@recipes = recipe
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def Config.run
|
|
23
|
+
ci = Servant::CI.new
|
|
24
|
+
|
|
25
|
+
config = Servant::Config.new
|
|
26
|
+
config.set_ci ci
|
|
27
|
+
yield(config) if block_given?
|
|
28
|
+
|
|
29
|
+
ci_configs = ::Servant::Mixin::Command.get_configs
|
|
30
|
+
|
|
31
|
+
recipes = {}
|
|
32
|
+
ci_configs.each do |name, cfg|
|
|
33
|
+
if cfg.fetch(:abstract,nil)
|
|
34
|
+
next
|
|
35
|
+
elsif cfg.fetch(:enabled,nil) == false
|
|
36
|
+
next
|
|
37
|
+
else
|
|
38
|
+
if cfg.fetch(:extends,nil)
|
|
39
|
+
parent = ci_configs.fetch(cfg.fetch(:extends))
|
|
40
|
+
cfg = parent.merge(cfg)
|
|
41
|
+
cfg[:abstract] = false
|
|
42
|
+
end
|
|
43
|
+
recipes[name] = cfg
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
config.set_recipe recipes
|
|
48
|
+
|
|
49
|
+
return config
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
class Environment
|
|
3
|
+
def initialize(opts)
|
|
4
|
+
@config = opts
|
|
5
|
+
@logger = opts[:logger]
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def show_help
|
|
9
|
+
print "useage: servant <command> [<args>]
|
|
10
|
+
|
|
11
|
+
list show loaded servant jobs
|
|
12
|
+
show show current ci information
|
|
13
|
+
provision add jobs to jenkins dir and reload it
|
|
14
|
+
reload reload jenkins
|
|
15
|
+
help this information
|
|
16
|
+
"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
|
|
21
|
+
if ARGV.size == 0
|
|
22
|
+
show_help
|
|
23
|
+
exit -1
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
command = ARGV.shift
|
|
27
|
+
|
|
28
|
+
case command
|
|
29
|
+
when "init"
|
|
30
|
+
if FileTest.exists?("ServantFile")
|
|
31
|
+
print "ServantFile exists."
|
|
32
|
+
exit(-1)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
file = open("ServantFile","w")
|
|
36
|
+
file.write <<'EOF'
|
|
37
|
+
Servant::Config.run do | config |
|
|
38
|
+
config.ci.url = "http://localhost:8080"
|
|
39
|
+
|
|
40
|
+
config.ci.user = 'daemon'
|
|
41
|
+
config.ci.cli = "/tmp/moe/servant/jenkins-cli.jar"
|
|
42
|
+
config.ci.home = "/home/Shared/Library/Jenkins"
|
|
43
|
+
config.ci.cli_options = []
|
|
44
|
+
|
|
45
|
+
config.ci.jobs :jobs do | jobs |
|
|
46
|
+
jobs.path = "recipes"
|
|
47
|
+
|
|
48
|
+
Dir::glob("./#{jobs.path}/*.rb").each {|name|
|
|
49
|
+
jobs.add File.basename(name,".rb")
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
EOF
|
|
54
|
+
file.close
|
|
55
|
+
|
|
56
|
+
Dir::mkdir("./recipes")
|
|
57
|
+
when "list"
|
|
58
|
+
config = eval IO.read(File.join(Dir.pwd, "ServantFile"))
|
|
59
|
+
recipes = config.get_recipe
|
|
60
|
+
print "loaded configurations:\n"
|
|
61
|
+
|
|
62
|
+
recipes.each do |name,cfg|
|
|
63
|
+
print " #{name}\n"
|
|
64
|
+
end
|
|
65
|
+
when "show"
|
|
66
|
+
config = eval IO.read(File.join(Dir.pwd, "ServantFile"))
|
|
67
|
+
|
|
68
|
+
print "HOME: " + config.ci.home + "\n"
|
|
69
|
+
print "USER: " + config.ci.user + "\n"
|
|
70
|
+
print "URL: " + config.ci.url + "\n"
|
|
71
|
+
print "CLI: " + config.ci.cli + "\n"
|
|
72
|
+
|
|
73
|
+
exit
|
|
74
|
+
when "provision"
|
|
75
|
+
config = eval IO.read(File.join(Dir.pwd, "ServantFile"))
|
|
76
|
+
recipes = config.get_recipe
|
|
77
|
+
recipes.each do |name, cfg|
|
|
78
|
+
@logger.info "processing `#{name}`..."
|
|
79
|
+
writer = ::Servant::Writer::XmlWriter.new cfg
|
|
80
|
+
xmldata = writer.get_xml
|
|
81
|
+
tmp = Tempfile.new("servant")
|
|
82
|
+
tmp.write xmldata
|
|
83
|
+
tmp.close()
|
|
84
|
+
|
|
85
|
+
`/usr/bin/java -jar #{config.ci.cli} -s #{config.ci.url} get-job #{name} 2>&1 > /dev/null`
|
|
86
|
+
if $?.exitstatus == 255
|
|
87
|
+
`/usr/bin/java -jar #{config.ci.cli} -s #{config.ci.url} create-job #{name} < #{tmp.path}`
|
|
88
|
+
else
|
|
89
|
+
`/usr/bin/java -jar #{config.ci.cli} -s #{config.ci.url} update-job #{name} < #{tmp.path}`
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if $?.exitstatus == 0
|
|
93
|
+
@logger.info "create / update job `#{name}` successfull"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
tmp.close!
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
when "reload"
|
|
100
|
+
config = eval IO.read(File.join(Dir.pwd, "ServantFile"))
|
|
101
|
+
system("/usr/bin/java -jar #{config.ci.cli} -s #{config.ci.url} reload-configuration")
|
|
102
|
+
else
|
|
103
|
+
show_help
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
exit(0)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
class JobCollections
|
|
3
|
+
attr_accessor :path
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@path = nil
|
|
7
|
+
@jobs = []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def add(job)
|
|
11
|
+
path = File.join(@path, job + ".rb")
|
|
12
|
+
data = IO.read(path)
|
|
13
|
+
|
|
14
|
+
eval(data, Mixin::Command.get_binding)
|
|
15
|
+
|
|
16
|
+
Mixin::Command.push_config(job)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
module Mixin
|
|
3
|
+
module Command
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def extends(file)
|
|
7
|
+
@@config[:extends] = file
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def abstract(bool)
|
|
11
|
+
@@config[:abstract] = bool
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def name(name)
|
|
15
|
+
@@config[:name] = name
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def description(description)
|
|
19
|
+
@@config[:description] = description
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def enabled(boolean)
|
|
23
|
+
@@config[:enabled] = boolean
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def build_params(param)
|
|
27
|
+
unless @@config.fetch(:build_params,nil)
|
|
28
|
+
@@config[:build_params] = []
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
@@config[:build_params] << param
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def build_step(type, command)
|
|
35
|
+
if defined? @@config[:build_steps]
|
|
36
|
+
@@config[:build_steps] = []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@@config[:build_steps] << {
|
|
40
|
+
:type => type,
|
|
41
|
+
:command => command
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def scm_type(specs)
|
|
46
|
+
repo = Repositories.new
|
|
47
|
+
yield(repo) if block_given?
|
|
48
|
+
|
|
49
|
+
@@config[:scm] = repo
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def post_hook
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class Repositories
|
|
56
|
+
def initialize
|
|
57
|
+
@repositories = {}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def fetch(key, default = nil)
|
|
61
|
+
return @repositories.fetch(key, default)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def add(a)
|
|
65
|
+
tmp = get_default_config
|
|
66
|
+
|
|
67
|
+
each2(a) do |key, value|
|
|
68
|
+
tmp[key] = value
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
@repositories = tmp
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
def each2(array)
|
|
76
|
+
i = 0
|
|
77
|
+
if array.size % 2 != 0
|
|
78
|
+
raise "array count error"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
while i < array.size
|
|
82
|
+
yield array[i], array[i+1]
|
|
83
|
+
i+=2
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def get_default_config
|
|
88
|
+
return {
|
|
89
|
+
:config_version => 2,
|
|
90
|
+
:url => "",
|
|
91
|
+
:name => "",
|
|
92
|
+
:refspec => "",
|
|
93
|
+
:branches => "",
|
|
94
|
+
:disable_submodules => false,
|
|
95
|
+
:recursive_submodules => false,
|
|
96
|
+
:do_generate_submodule_configurations => false,
|
|
97
|
+
:author_or_committer => false,
|
|
98
|
+
:clean => false,
|
|
99
|
+
:wipe_out_workspace => false,
|
|
100
|
+
:prune_branches => false,
|
|
101
|
+
:remote_poll => false,
|
|
102
|
+
:build_chooser => {:class => "hudson.plugins.git.util.DefaultBuildChooser"},
|
|
103
|
+
:gitTool => "default",
|
|
104
|
+
:submodule_config => {:class=>"list"},
|
|
105
|
+
:relative_target_dir => nil,
|
|
106
|
+
:reference => nil,
|
|
107
|
+
:exclude_regions => nil,
|
|
108
|
+
:exclude_users => nil,
|
|
109
|
+
:git_config_name => nil,
|
|
110
|
+
:git_config_email => nil,
|
|
111
|
+
:skip_tag => false,
|
|
112
|
+
:included_regions => nil,
|
|
113
|
+
:scm_name => nil
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
module Mixin
|
|
3
|
+
module Command
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
@@config = {}
|
|
7
|
+
@@configs = {}
|
|
8
|
+
|
|
9
|
+
def get_binding
|
|
10
|
+
trigger = Trigger.new
|
|
11
|
+
log_rotator = LogRotator.new
|
|
12
|
+
|
|
13
|
+
@trigger = trigger
|
|
14
|
+
@log_rotator = log_rotator
|
|
15
|
+
|
|
16
|
+
binding
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get_configs
|
|
20
|
+
@@configs
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def push_config(name)
|
|
24
|
+
if @trigger.has_config
|
|
25
|
+
@@config[:trigger] = @trigger
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if @log_rotator.has_config
|
|
29
|
+
@@config[:log_rotator] = @log_rotator
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
@@configs[name] = @@config
|
|
33
|
+
@@config = {}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
module Mixin
|
|
3
|
+
class LogRotator
|
|
4
|
+
attr_accessor :config
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@has = false
|
|
8
|
+
@config = Hash.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def has_config
|
|
12
|
+
return @has
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def days_to_keep(days)
|
|
16
|
+
@has = true
|
|
17
|
+
@config[:days_to_keep] = days
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def num_to_keep(nums)
|
|
21
|
+
@has = true
|
|
22
|
+
@config[:num_to_keep] = nums
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def artifact_days_to_keep(days)
|
|
26
|
+
@has = true
|
|
27
|
+
@config[:artifact_days_to_keep] = days
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def artifact_num_to_keep(nums)
|
|
31
|
+
@has = true
|
|
32
|
+
@config[:artifact_num_to_keep] = nums
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
module Mixin
|
|
3
|
+
class Trigger
|
|
4
|
+
|
|
5
|
+
def has_config
|
|
6
|
+
return @has
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def get_poll
|
|
10
|
+
@poll
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def get_periodical
|
|
14
|
+
@periodical
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@has = false
|
|
19
|
+
@poll
|
|
20
|
+
@periodical
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def poll(sched)
|
|
24
|
+
@has = true
|
|
25
|
+
@poll = sched
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def periodical(sched)
|
|
29
|
+
@has = true
|
|
30
|
+
@periodical = sched
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
module Servant
|
|
2
|
+
module Writer
|
|
3
|
+
class XmlWriter
|
|
4
|
+
def initialize(config)
|
|
5
|
+
@config = config
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def get_xml()
|
|
9
|
+
name = @config.fetch(:name)
|
|
10
|
+
|
|
11
|
+
write_impl name, @config
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def write()
|
|
15
|
+
name = @config.fetch(:name)
|
|
16
|
+
|
|
17
|
+
print write_impl name, @config
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def write_impl(name, config)
|
|
21
|
+
obj = ::Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
|
22
|
+
xml.project do |project|
|
|
23
|
+
project.actions
|
|
24
|
+
project.description config.fetch(:description,nil)
|
|
25
|
+
# log rotator
|
|
26
|
+
|
|
27
|
+
if config.fetch(:log_rotator,nil) && config.fetch(:log_rotator).config.length > 0
|
|
28
|
+
project.logRotator do |rotator|
|
|
29
|
+
cfg = config.fetch(:log_rotator).config
|
|
30
|
+
rotator.daysToKeep cfg.fetch(:days_to_keep, 5)
|
|
31
|
+
rotator.numToKeep cfg.fetch(:num_to_keep, 5)
|
|
32
|
+
rotator.artifactDaysToKeep cfg.fetch(:artifact_days_to_keep, -1)
|
|
33
|
+
rotator.artifactNumToKeep cfg.fetch(:artifact_num_to_keep, -1)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
project.keepDependencies false
|
|
38
|
+
|
|
39
|
+
if config.fetch(:build_params,nil)
|
|
40
|
+
project.properties do |properties|
|
|
41
|
+
properties.send(:"hudson.model.ParametersDefinitionProperty") do |defi|
|
|
42
|
+
|
|
43
|
+
defi.parameterDefinitions do |pm|
|
|
44
|
+
# BooleanParameterDefinition
|
|
45
|
+
# PasswordParameterDefinition
|
|
46
|
+
|
|
47
|
+
# ChoiceParameterDefinition
|
|
48
|
+
# choices class="java.util.Arrays$AllayList"
|
|
49
|
+
# <name> class="string-array"
|
|
50
|
+
# string
|
|
51
|
+
config.fetch(:build_params, nil).each do |parameter|
|
|
52
|
+
|
|
53
|
+
key = ""
|
|
54
|
+
|
|
55
|
+
case parameter[0]
|
|
56
|
+
when :bool
|
|
57
|
+
key = :"hudson.model.BooleanParameterDefinition"
|
|
58
|
+
when :string
|
|
59
|
+
key = :"hudson.model.StringParameterDefinition"
|
|
60
|
+
when :text
|
|
61
|
+
key = :"hudson.model.TextParameterDefinition"
|
|
62
|
+
when :file
|
|
63
|
+
key = :"hudson.model.FileParameterDefinition"
|
|
64
|
+
when :password
|
|
65
|
+
key = :"hudson.model.PasswordParameterDefinition"
|
|
66
|
+
when :choice
|
|
67
|
+
key = :"hudson.model.ChoiseParameterDefinition"
|
|
68
|
+
else
|
|
69
|
+
raise "does not supprot #{parameter[0]}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
pm.send(key) do |para|
|
|
73
|
+
para.name parameter[1]
|
|
74
|
+
para.description parameter[3]
|
|
75
|
+
|
|
76
|
+
if key == :"hudson.model.ChoiseParameterDefinition"
|
|
77
|
+
else
|
|
78
|
+
if parameter[0] == :password
|
|
79
|
+
para.defaultValue Base64.encode64(parameter[2])
|
|
80
|
+
else
|
|
81
|
+
para.defaultValue parameter[2]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# scm
|
|
93
|
+
if config.fetch(:scm, nil)
|
|
94
|
+
git_config = config.fetch(:scm)
|
|
95
|
+
|
|
96
|
+
# for git plugin
|
|
97
|
+
project.scm(:class => "hudson.plugins.git.GitSCM") do | git |
|
|
98
|
+
git.configVersion git_config.fetch(:config_version)
|
|
99
|
+
git.userRemoteConfigs do | r_config |
|
|
100
|
+
r_config.send(:"hudson.plugins.git.UserRemoteConfig") do | urc |
|
|
101
|
+
urc.name git_config.fetch(:name)
|
|
102
|
+
urc.refspec git_config.fetch(:refspec)
|
|
103
|
+
urc.url git_config.fetch(:url)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
git.branches do |branches|
|
|
108
|
+
branches.send(:"hudson.plugins.git.BranchSpec") do |branch|
|
|
109
|
+
branch.name "**"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
git.disableSubmodules false
|
|
113
|
+
git.recursiveSubmodules false
|
|
114
|
+
git.doGenerateSubmoduleConfigurations false
|
|
115
|
+
git.authorOrCommitter false
|
|
116
|
+
git.clean false
|
|
117
|
+
git.wipeOutWorkspace false
|
|
118
|
+
git.pruneBranches false
|
|
119
|
+
git.remotePoll false
|
|
120
|
+
git.buildChooser(:class => "hudson.plugins.git.util.DefaultBuildChooser")
|
|
121
|
+
git.gitTool "Default"
|
|
122
|
+
git.submoduleCfg(:class => "list")
|
|
123
|
+
git.relativeTargetDir nil
|
|
124
|
+
git.reference nil
|
|
125
|
+
git.excludedRegions nil
|
|
126
|
+
git.excludedUsers nil
|
|
127
|
+
git.gitConfigName nil
|
|
128
|
+
git.gitConfigEmail nil
|
|
129
|
+
git.skipTag false
|
|
130
|
+
git.includedRegions nil
|
|
131
|
+
git.scmName nil
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
else
|
|
135
|
+
project.scm(:class => "hudson.scm.NullSCM")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
=begin
|
|
139
|
+
<scm class="hudson.scm.SubversionSCM">
|
|
140
|
+
<locations/>
|
|
141
|
+
<excludedRegions></excludedRegions>
|
|
142
|
+
<includedRegions></includedRegions>
|
|
143
|
+
<excludedUsers></excludedUsers>
|
|
144
|
+
<excludedRevprop></excludedRevprop>
|
|
145
|
+
<excludedCommitMessages></excludedCommitMessages>
|
|
146
|
+
<workspaceUpdater class="hudson.scm.subversion.UpdateUpdater"/>
|
|
147
|
+
</scm>
|
|
148
|
+
=end
|
|
149
|
+
|
|
150
|
+
project.canRoam "true"
|
|
151
|
+
project.disabled "false"
|
|
152
|
+
project.blockBuildWhenDownstreamBuilding "false"
|
|
153
|
+
project.blockBuildWhenUpstreamBuilding "false"
|
|
154
|
+
|
|
155
|
+
project.triggers(:class => "vector") { |trigger|
|
|
156
|
+
trigger.send(:"hudson.triggers.TimerTrigger") { |elm|
|
|
157
|
+
t = config.fetch(:trigger,nil)
|
|
158
|
+
if t
|
|
159
|
+
elm.spec t.get_periodical
|
|
160
|
+
else
|
|
161
|
+
elm.spec nil
|
|
162
|
+
end
|
|
163
|
+
}
|
|
164
|
+
trigger.send(:"hudson.triggers.SCMTrigger") { |elm|
|
|
165
|
+
t = config.fetch(:trigger,nil)
|
|
166
|
+
if t
|
|
167
|
+
elm.spec t.get_poll
|
|
168
|
+
else
|
|
169
|
+
elm.spec nil
|
|
170
|
+
end
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
project.concurrentBuild "false"
|
|
176
|
+
|
|
177
|
+
project.builders do |builder|
|
|
178
|
+
if config.fetch(:build_steps,nil)
|
|
179
|
+
builder.send(:"hudson.tasks.Shell") do |shell|
|
|
180
|
+
config.fetch(:build_steps,[]).each do |step|
|
|
181
|
+
shell.command step.fetch(:command)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
project.publishers nil
|
|
188
|
+
project.buildWrappers nil
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
return obj.to_xml
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
data/lib/servant.rb
ADDED
data/servant.gemspec
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
|
3
|
+
require File.expand_path('../lib/servant/version', __FILE__)
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |gem|
|
|
6
|
+
gem.authors = ["Shuhei Tanuma"]
|
|
7
|
+
gem.email = ["chobieee@gmail.com"]
|
|
8
|
+
gem.description = "Jenkins job management tool"
|
|
9
|
+
gem.summary = "Servant is a tool for applying jenkins job"
|
|
10
|
+
gem.homepage = ""
|
|
11
|
+
|
|
12
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
13
|
+
gem.files = `git ls-files`.split("\n")
|
|
14
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
15
|
+
gem.name = "servant"
|
|
16
|
+
gem.require_paths = ["lib"]
|
|
17
|
+
gem.version = Servant::VERSION
|
|
18
|
+
end
|
data/servant.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Servant::Config.run do | config |
|
|
2
|
+
config.ci.home = "/home/Shared/Library/Jenkins"
|
|
3
|
+
config.ci.user = 'daemon'
|
|
4
|
+
config.ci.url = "http://localhost:8080"
|
|
5
|
+
config.ci.cli = "/tmp/moe/servant/jenkins-cli.jar"
|
|
6
|
+
config.ci.cli_options = []
|
|
7
|
+
|
|
8
|
+
config.ci.jobs :jobs do | jobs |
|
|
9
|
+
jobs.path = "recipes"
|
|
10
|
+
|
|
11
|
+
Dir::glob("./#{jobs.path}/*.rb").each {|name|
|
|
12
|
+
jobs.add File.basename(name,".rb")
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: servant
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease: false
|
|
5
|
+
segments:
|
|
6
|
+
- 0
|
|
7
|
+
- 0
|
|
8
|
+
- 1
|
|
9
|
+
version: 0.0.1
|
|
10
|
+
platform: ruby
|
|
11
|
+
authors:
|
|
12
|
+
- Shuhei Tanuma
|
|
13
|
+
autorequire:
|
|
14
|
+
bindir: bin
|
|
15
|
+
cert_chain: []
|
|
16
|
+
|
|
17
|
+
date: 2012-03-11 00:00:00 +09:00
|
|
18
|
+
default_executable:
|
|
19
|
+
dependencies: []
|
|
20
|
+
|
|
21
|
+
description: Jenkins job management tool
|
|
22
|
+
email:
|
|
23
|
+
- chobieee@gmail.com
|
|
24
|
+
executables:
|
|
25
|
+
- servant
|
|
26
|
+
extensions: []
|
|
27
|
+
|
|
28
|
+
extra_rdoc_files: []
|
|
29
|
+
|
|
30
|
+
files:
|
|
31
|
+
- .gitignore
|
|
32
|
+
- Gemfile
|
|
33
|
+
- LICENSE
|
|
34
|
+
- README.md
|
|
35
|
+
- Rakefile
|
|
36
|
+
- bin/servant
|
|
37
|
+
- lib/servant.rb
|
|
38
|
+
- lib/servant/ci.rb
|
|
39
|
+
- lib/servant/config.rb
|
|
40
|
+
- lib/servant/environment.rb
|
|
41
|
+
- lib/servant/jobcollections.rb
|
|
42
|
+
- lib/servant/mixin/command.rb
|
|
43
|
+
- lib/servant/mixin/command/config.rb
|
|
44
|
+
- lib/servant/mixin/log_rotator.rb
|
|
45
|
+
- lib/servant/mixin/trigger.rb
|
|
46
|
+
- lib/servant/version.rb
|
|
47
|
+
- lib/servant/writer/xmlwriter.rb
|
|
48
|
+
- servant.gemspec
|
|
49
|
+
- servant.rb
|
|
50
|
+
has_rdoc: true
|
|
51
|
+
homepage: ""
|
|
52
|
+
licenses: []
|
|
53
|
+
|
|
54
|
+
post_install_message:
|
|
55
|
+
rdoc_options: []
|
|
56
|
+
|
|
57
|
+
require_paths:
|
|
58
|
+
- lib
|
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
segments:
|
|
64
|
+
- 0
|
|
65
|
+
version: "0"
|
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
|
+
requirements:
|
|
68
|
+
- - ">="
|
|
69
|
+
- !ruby/object:Gem::Version
|
|
70
|
+
segments:
|
|
71
|
+
- 0
|
|
72
|
+
version: "0"
|
|
73
|
+
requirements: []
|
|
74
|
+
|
|
75
|
+
rubyforge_project:
|
|
76
|
+
rubygems_version: 1.3.6
|
|
77
|
+
signing_key:
|
|
78
|
+
specification_version: 3
|
|
79
|
+
summary: Servant is a tool for applying jenkins job
|
|
80
|
+
test_files: []
|
|
81
|
+
|