leeroy_jenkins 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +24 -0
- data/.rubocop_todo.yml +18 -0
- data/README.md +37 -5
- data/Rakefile +19 -4
- data/Vagrantfile +14 -10
- data/bin/console +3 -3
- data/exe/leeroy +1 -1
- data/leeroy_jenkins.gemspec +6 -6
- data/lib/leeroy_jenkins.rb +14 -13
- data/lib/leeroy_jenkins/cli.rb +63 -69
- data/lib/leeroy_jenkins/jenkins_client_builder.rb +1 -0
- data/lib/leeroy_jenkins/job_backupper.rb +20 -17
- data/lib/leeroy_jenkins/job_finder.rb +2 -2
- data/lib/leeroy_jenkins/job_restorer.rb +27 -10
- data/lib/leeroy_jenkins/job_updater.rb +21 -13
- data/lib/leeroy_jenkins/result.rb +19 -0
- data/lib/leeroy_jenkins/version.rb +1 -1
- metadata +39 -37
- data/.travis.yml +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7250c26ddbb7688160d7f465e969a04a31384d9
|
4
|
+
data.tar.gz: 4232370b71230e292664ccdb2d4845b9333c2533
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f4da81497645190fd871ccfc9eea476e57ea6e3b9867ec7ef71333f9408c4872ef58ab25368345053f1cb99554a64fb66a932d9049362470985b28ea960dc46
|
7
|
+
data.tar.gz: ac7db9f73e29117082e41dfdfed0fa05e1db14f0f9caa68fdf7f71ae6c4d72f048b47df801863338382ae648856f702dae1036630a726142db8a786cd4c157b3
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
Style/WordArray:
|
4
|
+
Enabled: false
|
5
|
+
|
6
|
+
Style/HashSyntax:
|
7
|
+
Exclude:
|
8
|
+
- 'Rakefile'
|
9
|
+
|
10
|
+
Metrics/LineLength:
|
11
|
+
Exclude:
|
12
|
+
- 'lib/leeroy_jenkins/cli.rb'
|
13
|
+
|
14
|
+
Metrics/AbcSize:
|
15
|
+
Max: 25
|
16
|
+
|
17
|
+
Metrics/MethodLength:
|
18
|
+
Max: 20
|
19
|
+
|
20
|
+
Style/Documentation:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Metrics/ParameterLists:
|
24
|
+
Max: 6
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2016-08-09 13:57:32 -0500 using RuboCop version 0.42.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 3
|
10
|
+
Lint/AmbiguousRegexpLiteral:
|
11
|
+
Exclude:
|
12
|
+
- 'features/step_definitions/jenkins.rb'
|
13
|
+
|
14
|
+
# Offense count: 49
|
15
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
|
16
|
+
# URISchemes: http, https
|
17
|
+
Metrics/LineLength:
|
18
|
+
Max: 172
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# leeroy_jenkins
|
2
2
|
|
3
|
+
[![Gem](https://img.shields.io/gem/v/leeroy_jenkins.svg)](https://rubygems.org/gems/leeroy_jenkins)
|
4
|
+
|
3
5
|
## Description
|
4
6
|
A CLI tool for managing Jenkins job configurations: bulk update, backup, and restore your Jenkins job configurations
|
5
7
|
|
@@ -21,14 +23,44 @@ Or install it yourself as:
|
|
21
23
|
|
22
24
|
## Usage
|
23
25
|
|
24
|
-
Set your `LEEROY_JENKINS_USERNAME`, `LEEROY_JENKINS_PASSWORD`, and `LEEROY_JENKINS_SERVER_URL` appropriately for your Jenkins. These can also be overridden with command line options.
|
26
|
+
Set your `LEEROY_JENKINS_USERNAME`, `LEEROY_JENKINS_PASSWORD`, and `LEEROY_JENKINS_SERVER_URL` environment variables appropriately for your Jenkins. These can also be overridden with command line options. Run `leeroy --help` to see the available sub-commands and options:
|
25
27
|
|
26
28
|
$ leeroy --help
|
27
|
-
|
29
|
+
Commands:
|
30
|
+
leeroy append NEW_NODE.xml # Append to XML nodes in jenkins jobs' config.xml
|
31
|
+
leeroy backup BACKUP_DIR_PATH # Save the config.xml of Jenkins jobs to disk, BACKUP_DIR created if it does not exist
|
32
|
+
leeroy delete # Delete XML nodes in jenkins jobs' config.xml
|
33
|
+
leeroy help [COMMAND] # Describe available commands or one specific command
|
34
|
+
leeroy replace NEW_NODE.xml # Replace XML nodes in jenkins jobs' config.xml
|
35
|
+
leeroy restore BACKUP_DIR_PATH # Restore config.xml files to Jenkins jobs from backups
|
28
36
|
|
29
|
-
|
37
|
+
Options:
|
38
|
+
[--dry-run], [--no-dry-run] # Show what leeroy would do, without doing it
|
39
|
+
# Default: true
|
40
|
+
[--jenkins-log-level=N] # Detail of the messages logged by the Jenkins API client: DEBUG (0), INFO (1), WARN (2), FATAL (3)
|
41
|
+
# Default: 3
|
42
|
+
# Possible values: 0, 1, 2, 3
|
43
|
+
[--jenkins-log-location=JENKINS_LOG_LOCATION] # Path to write messages logged by the Jenkins API client
|
44
|
+
# Default: /dev/stdout
|
45
|
+
[--job-regex=JOB_REGEX] # Regular expression to select jobs by name
|
46
|
+
# Default: .*
|
47
|
+
[--jobs=JOBS] # Path to a file containing a job name on each line
|
48
|
+
[--password=PASSWORD] # Override LEEROY_JENKINS_PASSWORD
|
49
|
+
[--server-url=SERVER_URL] # Override LEEROY_JENKINS_SERVER_URL
|
50
|
+
[--threads=N] # Number of threads to use for network and disk IO
|
51
|
+
# Default: 4
|
52
|
+
[--username=USERNAME] # Override LEEROY_JENKINS_USERNAME
|
53
|
+
|
54
|
+
For more specific examples and documentation of features, take a look in the `features` directory (the fixtures referenced there are [here](https://github.com/Jellyvision/leeroy_jenkins/tree/master/features/fixtures)):
|
30
55
|
|
31
|
-
|
56
|
+
* [append](https://github.com/Jellyvision/leeroy_jenkins/blob/master/features/append.feature)
|
57
|
+
* [backup](https://github.com/Jellyvision/leeroy_jenkins/blob/master/features/backup.feature)
|
58
|
+
* [delete](https://github.com/Jellyvision/leeroy_jenkins/blob/master/features/delete.feature)
|
59
|
+
* [replace](https://github.com/Jellyvision/leeroy_jenkins/blob/master/features/replace.feature)
|
60
|
+
* [restore](https://github.com/Jellyvision/leeroy_jenkins/blob/master/features/restore.feature)
|
61
|
+
|
62
|
+
## Development
|
32
63
|
|
33
|
-
|
64
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake rspec` to run the unit tests. Run `bundle exec rake rubocop` to lint. You can also run `bundle exec bin/console` to launch a pry session with all code and dependencies loaded. Run `bundle exec exe/leeroy` to use the gem in this directory, ignoring other installed copies of this gem.
|
34
65
|
|
66
|
+
To run the acceptance tests, run `vagrant up` to start your own Jenkins instance. This may take 5-10 minutes, but when finished you'll be able to access Jenkins at `192.168.50.33:8080` in your web browser. Then run `bundle exec rake cucumber`. `bundle exec rake verify` will lint, run unit tests, and run acceptance tests. This is also the default rake task.
|
data/Rakefile
CHANGED
@@ -1,6 +1,21 @@
|
|
1
|
-
require
|
2
|
-
require "rspec/core/rake_task"
|
1
|
+
require 'bundler/gem_tasks'
|
3
2
|
|
4
|
-
|
3
|
+
desc 'Lint, run unit tests, and run acceptance tests.'
|
4
|
+
task :verify => [:rubocop, :rspec, :cucumber]
|
5
5
|
|
6
|
-
|
6
|
+
desc 'Lint.'
|
7
|
+
task :rubocop do
|
8
|
+
sh 'bundle exec rubocop'
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Run unit tests.'
|
12
|
+
task :rspec do
|
13
|
+
sh 'bundle exec rspec'
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Run acceptance tests.'
|
17
|
+
task :cucumber do
|
18
|
+
sh 'bundle exec cucumber'
|
19
|
+
end
|
20
|
+
|
21
|
+
task :default => :verify
|
data/Vagrantfile
CHANGED
@@ -1,16 +1,20 @@
|
|
1
1
|
Vagrant.configure 2 do |config|
|
2
|
-
config.vm.box =
|
3
|
-
config.vm.network
|
2
|
+
config.vm.box = 'ubuntu/trusty64'
|
3
|
+
config.vm.network 'private_network', ip: '192.168.50.33'
|
4
4
|
|
5
|
-
config.vm.provision
|
6
|
-
|
7
|
-
apt-get upgrade -y
|
5
|
+
config.vm.provision 'shell', inline: <<EOF
|
6
|
+
set -ex
|
8
7
|
|
9
|
-
|
8
|
+
JENKINS_VERSION=1.658
|
10
9
|
|
11
|
-
wget -q -O - https://jenkins-ci.org/debian/jenkins-ci.org.key | apt-key add -
|
12
|
-
sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
|
13
10
|
apt-get update
|
14
|
-
|
15
|
-
|
11
|
+
|
12
|
+
curl -sL \
|
13
|
+
-o /tmp/jenkins_${JENKINS_VERSION}_all.deb \
|
14
|
+
http://pkg.jenkins-ci.org/debian/binary/jenkins_${JENKINS_VERSION}_all.deb
|
15
|
+
|
16
|
+
apt-get install openjdk-7-jre-headless daemon -y
|
17
|
+
dpkg -i /tmp/jenkins_${JENKINS_VERSION}_all.deb
|
18
|
+
|
19
|
+
EOF
|
16
20
|
end
|
data/bin/console
CHANGED
data/exe/leeroy
CHANGED
data/leeroy_jenkins.gemspec
CHANGED
@@ -19,17 +19,17 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_dependency 'jenkins_api_client', '~> 1.4'
|
22
|
-
spec.add_dependency 'thor', '~> 0.19.1'
|
23
22
|
spec.add_dependency 'nokogiri', '~> 1.6'
|
24
23
|
spec.add_dependency 'parallel', '~> 1.6'
|
24
|
+
spec.add_dependency 'thor', '~> 0.19.1'
|
25
25
|
|
26
|
+
spec.add_development_dependency 'aruba', '~> 0.14.1'
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.10'
|
27
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
-
spec.add_development_dependency 'rspec', '~> 3.3'
|
29
|
-
spec.add_development_dependency 'aruba', '~> 0.9.0'
|
30
|
-
spec.add_development_dependency 'cucumber', '~> 2.1'
|
31
28
|
spec.add_development_dependency 'pry', '~> 0.10.1'
|
32
29
|
spec.add_development_dependency 'pry-doc', '~> 0.8.0'
|
33
30
|
spec.add_development_dependency 'pry-stack_explorer', '~> 0.4.9'
|
34
|
-
spec.add_development_dependency '
|
31
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
32
|
+
spec.add_development_dependency 'rspec', '~> 3.3'
|
33
|
+
spec.add_development_dependency 'rubocop', '~> 0.42.0'
|
34
|
+
spec.add_development_dependency 'simplecov', '~> 0.12.0'
|
35
35
|
end
|
data/lib/leeroy_jenkins.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'jenkins_api_client'
|
2
|
+
require 'thor'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'parallel'
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
6
|
+
require 'leeroy_jenkins/version'
|
7
|
+
require 'leeroy_jenkins/cli'
|
8
|
+
require 'leeroy_jenkins/result'
|
9
|
+
require 'leeroy_jenkins/job_finder'
|
10
|
+
require 'leeroy_jenkins/jenkins_client_builder'
|
11
|
+
require 'leeroy_jenkins/job_updater'
|
12
|
+
require 'leeroy_jenkins/job_backupper'
|
13
|
+
require 'leeroy_jenkins/job_restorer'
|
13
14
|
|
14
15
|
module LeeroyJenkins
|
15
|
-
def self.invalid_xml_document?
|
16
|
+
def self.invalid_xml_document?(raw_xml)
|
16
17
|
begin
|
17
|
-
Nokogiri::XML(raw_xml
|
18
|
+
Nokogiri::XML(raw_xml, &:strict)
|
18
19
|
rescue Nokogiri::XML::SyntaxError => e
|
19
20
|
return e
|
20
21
|
end
|
data/lib/leeroy_jenkins/cli.rb
CHANGED
@@ -1,93 +1,87 @@
|
|
1
1
|
module LeeroyJenkins
|
2
2
|
class Cli < Thor
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class_option :threads, required: false, type: :numeric, desc: 'Number of threads to use for network and disk IO', default: 4
|
9
|
-
|
10
|
-
desc 'update-config', 'Modify jobs\' config.xml'
|
11
|
-
option :job_regex, required: false, type: :string, desc: 'Regular expression to select jobs by name', default: '.*'
|
12
|
-
option :new_xml, required: true, type: :string, desc: 'Path to an XML file'
|
13
|
-
option :xpath, required: false, type: :string, desc: 'XPath of node(s) to modify in the config.xml of the specified job(s)', default: '/'
|
14
|
-
option :dry_run, type: :boolean, desc: 'Write XML to STDOUT instead of to Jenkins', default: true
|
15
|
-
option :at_xpath, required: false, type: :string, desc: 'Replace, append to, or delete the XML node(s) specified by the given XPath', enum: ['replace', 'append', 'delete'], default: 'replace'
|
16
|
-
option :jobs, required: false, type: :string, desc: 'Path to a file containing a job name on each line'
|
17
|
-
def update_config
|
18
|
-
raw_xml_string = File.read options[:new_xml]
|
19
|
-
if error = LeeroyJenkins.invalid_xml_document?(raw_xml_string)
|
20
|
-
error "#{options[:new_xml]}} is not well-formed XML: #{error}"
|
21
|
-
exit 1
|
22
|
-
end
|
3
|
+
# exit non-zero on failure
|
4
|
+
# https://github.com/erikhuda/thor/issues/244
|
5
|
+
def self.exit_on_failure?
|
6
|
+
true
|
7
|
+
end
|
23
8
|
|
24
|
-
|
9
|
+
class_option :dry_run, type: :boolean, default: true, desc: 'Show what leeroy would do, without doing it'
|
10
|
+
class_option :jenkins_log_level, type: :numeric, default: 3, desc: 'Detail of the messages logged by the Jenkins API client: DEBUG (0), INFO (1), WARN (2), FATAL (3)', enum: [0, 1, 2, 3]
|
11
|
+
class_option :jenkins_log_location, type: :string, default: '/dev/stdout', desc: 'Path to write messages logged by the Jenkins API client'
|
12
|
+
class_option :job_regex, type: :string, default: '.*', desc: 'Regular expression to select jobs by name'
|
13
|
+
class_option :jobs, type: :string, desc: 'Path to a file containing a job name on each line'
|
14
|
+
class_option :password, type: :string, desc: 'Override LEEROY_JENKINS_PASSWORD'
|
15
|
+
class_option :server_url, type: :string, desc: 'Override LEEROY_JENKINS_SERVER_URL'
|
16
|
+
class_option :threads, type: :numeric, default: 4, desc: 'Number of threads to use for network and disk IO'
|
17
|
+
class_option :username, type: :string, desc: 'Override LEEROY_JENKINS_USERNAME'
|
25
18
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
19
|
+
desc 'append NEW_NODE.xml', 'Append to XML nodes in jenkins jobs\' config.xml'
|
20
|
+
option :xpath, type: :string, default: '/', desc: 'XPath of node(s) to modify in the config.xml of the specified job(s)'
|
21
|
+
def append(xml_file_path)
|
22
|
+
puts update_jobs(read_and_validate_xml_file(xml_file_path), __method__)
|
23
|
+
end
|
32
24
|
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
desc 'replace NEW_NODE.xml', 'Replace XML nodes in jenkins jobs\' config.xml'
|
26
|
+
option :xpath, type: :string, default: '/', desc: 'XPath of node(s) to modify in the config.xml of the specified job(s)'
|
27
|
+
def replace(xml_file_path)
|
28
|
+
puts update_jobs(read_and_validate_xml_file(xml_file_path), __method__)
|
29
|
+
end
|
36
30
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
puts value
|
42
|
-
end
|
43
|
-
else
|
44
|
-
result.each do |key, value|
|
45
|
-
puts "#{key}: #{value}"
|
46
|
-
end
|
47
|
-
end
|
31
|
+
desc 'delete', 'Delete XML nodes in jenkins jobs\' config.xml'
|
32
|
+
option :xpath, type: :string, default: '/', desc: 'XPath of node(s) to modify in the config.xml of the specified job(s)'
|
33
|
+
def delete
|
34
|
+
puts update_jobs('', __method__)
|
48
35
|
end
|
49
36
|
|
50
|
-
desc 'backup', 'Save the config.xml of Jenkins jobs to disk'
|
51
|
-
|
52
|
-
|
53
|
-
def backup
|
54
|
-
jenkins_client = build_jenkins_client options
|
55
|
-
job_names_to_backup = JobFinder.new(jenkins_client).find_jobs(options[:job_regex])
|
56
|
-
JobBackupper.new(job_names_to_backup, jenkins_client, options[:backup_dir], options[:threads]).backup
|
37
|
+
desc 'backup BACKUP_DIR_PATH', 'Save the config.xml of Jenkins jobs to disk, BACKUP_DIR created if it does not exist'
|
38
|
+
def backup(backup_dir)
|
39
|
+
puts JobBackupper.new(job_names, jenkins_client, backup_dir, options[:threads]).backup(options[:dry_run])
|
57
40
|
end
|
58
41
|
|
59
|
-
desc 'restore', 'Restore config.xml files to Jenkins jobs from backups'
|
60
|
-
|
61
|
-
|
62
|
-
def restore
|
63
|
-
jenkins_client = build_jenkins_client options
|
64
|
-
job_restorer = JobRestorer.new jenkins_client, options[:backup_dir], options[:threads]
|
42
|
+
desc 'restore BACKUP_DIR_PATH', 'Restore config.xml files to Jenkins jobs from backups'
|
43
|
+
def restore(backup_dir)
|
44
|
+
job_restorer = JobRestorer.new(jenkins_client, backup_dir, options[:threads], job_rows, options[:job_regex])
|
65
45
|
result = options[:dry_run] ? job_restorer.dry_run : job_restorer.restore!
|
66
46
|
|
67
|
-
|
68
|
-
result.each do |key, value|
|
69
|
-
puts "#{key}:"
|
70
|
-
puts
|
71
|
-
puts value
|
72
|
-
end
|
73
|
-
else
|
74
|
-
result.each do |key, value|
|
75
|
-
puts "#{key}: #{value}"
|
76
|
-
end
|
77
|
-
end
|
47
|
+
puts result
|
78
48
|
end
|
79
49
|
|
80
50
|
private
|
81
51
|
|
82
|
-
def
|
83
|
-
|
52
|
+
def read_and_validate_xml_file(xml_file_path)
|
53
|
+
raw_xml_string = File.read(xml_file_path)
|
54
|
+
xml_parse_error = LeeroyJenkins.invalid_xml_document?(raw_xml_string)
|
55
|
+
die("#{xml_file_path} does not contain well-formed XML: #{xml_parse_error}") if xml_parse_error
|
56
|
+
raw_xml_string
|
57
|
+
end
|
58
|
+
|
59
|
+
def update_jobs(raw_xml_string, command_name)
|
60
|
+
job_updater = JobUpdater.new(job_names, raw_xml_string, jenkins_client, options[:xpath], command_name, options[:threads])
|
61
|
+
job_updater.update_jobs(options[:dry_run])
|
62
|
+
end
|
63
|
+
|
64
|
+
def jenkins_client
|
65
|
+
@jenkins_client ||= JenkinsClientBuilder.new(
|
84
66
|
server_url: options[:server_url],
|
85
67
|
username: options[:username],
|
86
68
|
password: options[:password],
|
87
|
-
log_level: options[:
|
88
|
-
log_location: options[:
|
69
|
+
log_level: options[:jenkins_log_level],
|
70
|
+
log_location: options[:jenkins_log_location]
|
89
71
|
).build
|
90
72
|
end
|
91
73
|
|
74
|
+
def job_names
|
75
|
+
JobFinder.new(jenkins_client).find_jobs(options[:job_regex], job_rows)
|
76
|
+
end
|
77
|
+
|
78
|
+
def job_rows
|
79
|
+
options[:jobs] ? File.read(options[:jobs]).split("\n") : []
|
80
|
+
end
|
81
|
+
|
82
|
+
def die(error_message)
|
83
|
+
error error_message
|
84
|
+
exit 1
|
85
|
+
end
|
92
86
|
end
|
93
87
|
end
|
@@ -9,32 +9,35 @@ module LeeroyJenkins
|
|
9
9
|
@threads = threads
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
12
|
+
def backup(dry = true)
|
13
|
+
Result.new(dry ? dry_run : backup!)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def backup!
|
19
|
+
FileUtils.mkdir_p(backup_dir) unless Dir.exist?(backup_dir)
|
20
|
+
|
21
|
+
pairs = Parallel.map(job_names_to_backup, in_threads: threads) do |job_name|
|
22
|
+
job_config = jenkins_client.job.get_config(job_name)
|
23
|
+
path = xml_file_path(job_name)
|
24
|
+
File.write(path, job_config)
|
25
|
+
[job_name, path]
|
15
26
|
end
|
16
27
|
|
17
28
|
Hash[pairs]
|
18
29
|
end
|
19
30
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
31
|
+
def dry_run
|
32
|
+
pairs = job_names_to_backup.map do |job_name|
|
33
|
+
[job_name, xml_file_path(job_name)]
|
23
34
|
end
|
24
35
|
|
25
|
-
|
26
|
-
File.write "#{backup_dir}/#{job_name}.xml", job_config
|
27
|
-
end
|
36
|
+
Hash[pairs]
|
28
37
|
end
|
29
38
|
|
30
|
-
|
31
|
-
|
32
|
-
def map_job_configs &block
|
33
|
-
Parallel.map(job_names_to_backup, in_threads: threads) do |job_name|
|
34
|
-
job_config = jenkins_client.job.get_config job_name
|
35
|
-
yield job_name, job_config
|
36
|
-
end
|
39
|
+
def xml_file_path(job_name)
|
40
|
+
"#{backup_dir}/#{job_name}.xml"
|
37
41
|
end
|
38
|
-
|
39
42
|
end
|
40
43
|
end
|
@@ -6,10 +6,10 @@ module LeeroyJenkins
|
|
6
6
|
@jenkins_client = jenkins_client
|
7
7
|
end
|
8
8
|
|
9
|
-
def find_jobs(regex, job_names =
|
9
|
+
def find_jobs(regex, job_names = [])
|
10
10
|
jobs_matching_regex = jenkins_client.job.list(regex)
|
11
11
|
|
12
|
-
if job_names
|
12
|
+
if job_names.any?
|
13
13
|
jobs_matching_regex.select do |job|
|
14
14
|
job_names.include? job
|
15
15
|
end
|
@@ -1,39 +1,56 @@
|
|
1
1
|
module LeeroyJenkins
|
2
2
|
class JobRestorer
|
3
|
-
attr_reader :backup_dir, :jenkins_client, :threads
|
3
|
+
attr_reader :backup_dir, :jenkins_client, :threads, :job_names, :job_regex
|
4
4
|
|
5
|
-
def initialize(jenkins_client, backup_dir, threads)
|
5
|
+
def initialize(jenkins_client, backup_dir, threads, job_names, job_regex)
|
6
6
|
@jenkins_client = jenkins_client
|
7
7
|
@backup_dir = backup_dir
|
8
8
|
@threads = threads
|
9
|
+
@job_names = job_names
|
10
|
+
@job_regex = Regexp.new(job_regex)
|
9
11
|
end
|
10
12
|
|
11
13
|
def dry_run
|
12
14
|
pairs = Parallel.map(config_xml_file_paths, in_threads: threads) do |xml_path|
|
13
|
-
job_name = File.basename
|
15
|
+
job_name = File.basename(xml_path, '.*')
|
14
16
|
[job_name, File.read(xml_path)]
|
15
17
|
end
|
16
18
|
|
17
|
-
Hash[pairs]
|
19
|
+
Result.new(Hash[pairs])
|
18
20
|
end
|
19
21
|
|
20
22
|
def restore!
|
21
23
|
pairs = Parallel.map(config_xml_file_paths, in_threads: threads) do |xml_path|
|
22
|
-
job_name = File.basename
|
23
|
-
|
24
|
+
job_name = File.basename(xml_path, '.*')
|
25
|
+
|
26
|
+
http_status_code = jenkins_client.job.create_or_update(
|
27
|
+
job_name, File.read(xml_path)
|
28
|
+
)
|
29
|
+
|
24
30
|
[job_name, http_status_code]
|
25
31
|
end
|
26
32
|
|
27
|
-
Hash[pairs]
|
33
|
+
Result.new(Hash[pairs])
|
28
34
|
end
|
29
35
|
|
30
36
|
private
|
31
37
|
|
32
38
|
def config_xml_file_paths
|
33
|
-
Dir.entries(backup_dir)
|
34
|
-
|
35
|
-
|
39
|
+
Dir.entries(backup_dir)
|
40
|
+
.select { |file_name| file_name.end_with? '.xml' }
|
41
|
+
.select { |file_name| restore_job?(file_name) }
|
42
|
+
.map { |file_name| "#{backup_dir}/#{file_name}" }
|
36
43
|
end
|
37
44
|
|
45
|
+
def restore_job?(file_name)
|
46
|
+
# http://rubular.com/r/UxTupLRyg4
|
47
|
+
job_name = file_name.match(/^(?<job_name>[^.]+)\.xml$/)['job_name']
|
48
|
+
|
49
|
+
if job_names.any?
|
50
|
+
job_names.include?(job_name) && job_name =~ job_regex
|
51
|
+
else
|
52
|
+
job_name =~ job_regex
|
53
|
+
end
|
54
|
+
end
|
38
55
|
end
|
39
56
|
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module LeeroyJenkins
|
2
2
|
class JobUpdater
|
3
|
-
attr_reader :job_names_to_update,
|
3
|
+
attr_reader :job_names_to_update,
|
4
|
+
:new_xml,
|
5
|
+
:jenkins_client,
|
6
|
+
:xpath,
|
7
|
+
:at_xpath,
|
8
|
+
:threads
|
4
9
|
|
5
10
|
def initialize(job_names_to_update, new_xml, jenkins_client, xpath, at_xpath, threads)
|
6
11
|
@job_names_to_update = job_names_to_update
|
@@ -11,9 +16,15 @@ module LeeroyJenkins
|
|
11
16
|
@threads = threads
|
12
17
|
end
|
13
18
|
|
19
|
+
def update_jobs(dry = true)
|
20
|
+
Result.new(dry ? dry_run : update_jobs!)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
14
25
|
def update_jobs!
|
15
26
|
pairs = Parallel.map(job_names_to_update, in_threads: threads) do |job_name|
|
16
|
-
http_status_code = jenkins_client.job.post_config job_name,
|
27
|
+
http_status_code = jenkins_client.job.post_config job_name, build_xml(job_name)
|
17
28
|
[job_name, http_status_code]
|
18
29
|
end
|
19
30
|
|
@@ -22,28 +33,26 @@ module LeeroyJenkins
|
|
22
33
|
|
23
34
|
def dry_run
|
24
35
|
pairs = Parallel.map(job_names_to_update, in_threads: threads) do |job_name|
|
25
|
-
[job_name,
|
36
|
+
[job_name, build_xml(job_name)]
|
26
37
|
end
|
27
38
|
|
28
39
|
Hash[pairs]
|
29
40
|
end
|
30
41
|
|
31
|
-
|
32
|
-
|
33
|
-
def construct_xml job_name
|
42
|
+
def build_xml(job_name)
|
34
43
|
element_to_insert = Nokogiri.XML(new_xml).root
|
35
|
-
document_to_modify = Nokogiri.XML
|
44
|
+
document_to_modify = Nokogiri.XML(current_xml(job_name), &:noblanks)
|
36
45
|
elements_to_modify = document_to_modify.xpath(xpath).map do |node|
|
37
46
|
node.document? ? node.root : node
|
38
47
|
end
|
39
48
|
|
40
49
|
elements_to_modify.each do |node|
|
41
50
|
case at_xpath
|
42
|
-
when
|
51
|
+
when :replace
|
43
52
|
node.replace element_to_insert
|
44
|
-
when
|
53
|
+
when :append
|
45
54
|
node << element_to_insert
|
46
|
-
when
|
55
|
+
when :delete
|
47
56
|
node.remove
|
48
57
|
end
|
49
58
|
end
|
@@ -51,9 +60,8 @@ module LeeroyJenkins
|
|
51
60
|
document_to_modify.canonicalize
|
52
61
|
end
|
53
62
|
|
54
|
-
def current_xml
|
55
|
-
jenkins_client.job.get_config
|
63
|
+
def current_xml(job_name)
|
64
|
+
jenkins_client.job.get_config(job_name)
|
56
65
|
end
|
57
|
-
|
58
66
|
end
|
59
67
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module LeeroyJenkins
|
2
|
+
class Result
|
3
|
+
def initialize(result_hashes)
|
4
|
+
@result_hashes = result_hashes
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
JSON.pretty_generate(result_hashes)
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
other.class == self.class && result_hashes == other.result_hashes
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
attr_reader :result_hashes
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: leeroy_jenkins
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Rabovsky
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jenkins_api_client
|
@@ -25,21 +25,21 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: nokogiri
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '1.6'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '1.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: parallel
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
@@ -53,145 +53,145 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.6'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: thor
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.19.1
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.19.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: aruba
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 0.14.1
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 0.14.1
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: bundler
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '10
|
89
|
+
version: '1.10'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '10
|
96
|
+
version: '1.10'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: pry
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 0.10.1
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 0.10.1
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: pry-doc
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.
|
117
|
+
version: 0.8.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
124
|
+
version: 0.8.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: pry-stack_explorer
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
131
|
+
version: 0.4.9
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
138
|
+
version: 0.4.9
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: rake
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
145
|
+
version: '10.0'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version:
|
152
|
+
version: '10.0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
154
|
+
name: rspec
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version:
|
159
|
+
version: '3.3'
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
166
|
+
version: '3.3'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
|
-
name:
|
168
|
+
name: rubocop
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
171
|
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: 0.
|
173
|
+
version: 0.42.0
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: 0.
|
180
|
+
version: 0.42.0
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
|
-
name:
|
182
|
+
name: simplecov
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 0.
|
187
|
+
version: 0.12.0
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: 0.
|
194
|
+
version: 0.12.0
|
195
195
|
description:
|
196
196
|
email:
|
197
197
|
- jeffr@jellyvision.com
|
@@ -202,7 +202,8 @@ extra_rdoc_files: []
|
|
202
202
|
files:
|
203
203
|
- ".gitignore"
|
204
204
|
- ".rspec"
|
205
|
-
- ".
|
205
|
+
- ".rubocop.yml"
|
206
|
+
- ".rubocop_todo.yml"
|
206
207
|
- Gemfile
|
207
208
|
- LICENSE.txt
|
208
209
|
- README.md
|
@@ -218,6 +219,7 @@ files:
|
|
218
219
|
- lib/leeroy_jenkins/job_finder.rb
|
219
220
|
- lib/leeroy_jenkins/job_restorer.rb
|
220
221
|
- lib/leeroy_jenkins/job_updater.rb
|
222
|
+
- lib/leeroy_jenkins/result.rb
|
221
223
|
- lib/leeroy_jenkins/version.rb
|
222
224
|
homepage: https://github.com/Jellyvision/leeroy_jenkins
|
223
225
|
licenses:
|
data/.travis.yml
DELETED