reagan 0.6.1 → 0.7.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 +38 -0
- data/.rubocop.yml +22 -0
- data/Gemfile +6 -0
- data/README.md +3 -3
- data/bin/reagan +2 -27
- data/lib/application.rb +96 -0
- data/lib/change.rb +77 -59
- data/lib/config.rb +56 -28
- data/lib/test_json.rb +20 -17
- data/lib/test_knife.rb +16 -13
- data/lib/test_reagan.rb +27 -23
- data/lib/test_version.rb +44 -41
- data/reagan.gemspec +25 -0
- metadata +25 -17
- data/lib/reagan.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15ec9f842a5eb1a06dd654d4f461da338026c746
|
4
|
+
data.tar.gz: 45f46483cf968a1df4fc629c0243a785860fe4fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a8ff757808d472928da7a48c2dd08acffad84bfc4515bb0067db1d4018947253e5248cf2dd2aadf50b4492c8e5cde4cb28ad90f6adede0caa8025dd17d4550f
|
7
|
+
data.tar.gz: 0b6c0efd5e6f93a94075130c75705a6c5ce2cb4ea18d9fb6f41f56b8bfc168c53f12302a3fcb2448348509ae048b59485141e476a32632f01f92a9493fe8da00
|
data/.gitignore
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/test/tmp/
|
9
|
+
/test/version_tmp/
|
10
|
+
/tmp/
|
11
|
+
|
12
|
+
## Specific to RubyMotion:
|
13
|
+
.dat*
|
14
|
+
.repl_history
|
15
|
+
build/
|
16
|
+
|
17
|
+
## Documentation cache and generated files:
|
18
|
+
/.yardoc/
|
19
|
+
/_yardoc/
|
20
|
+
/doc/
|
21
|
+
/rdoc/
|
22
|
+
|
23
|
+
## Environment normalisation:
|
24
|
+
/.bundle/
|
25
|
+
/lib/bundler/man/
|
26
|
+
|
27
|
+
# for a library or gem, you might want to ignore these files since the code is
|
28
|
+
# intended to run in multiple environments; otherwise, check them in:
|
29
|
+
Gemfile.lock
|
30
|
+
# .ruby-version
|
31
|
+
# .ruby-gemset
|
32
|
+
|
33
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
|
+
.rvmrc
|
35
|
+
|
36
|
+
.DS_Store
|
37
|
+
config.yml
|
38
|
+
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- vendor/**
|
4
|
+
|
5
|
+
AlignParameters:
|
6
|
+
Enabled: false
|
7
|
+
CyclomaticComplexity:
|
8
|
+
Enabled: false
|
9
|
+
Encoding:
|
10
|
+
Enabled: false
|
11
|
+
HashSyntax:
|
12
|
+
Enabled: false
|
13
|
+
LineLength:
|
14
|
+
Enabled: false
|
15
|
+
MethodLength:
|
16
|
+
Max: 30
|
17
|
+
NumericLiterals:
|
18
|
+
Enabled: false
|
19
|
+
SingleSpaceBeforeFirstArg:
|
20
|
+
Enabled: false
|
21
|
+
PerceivedComplexity:
|
22
|
+
Enabled: false
|
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -31,11 +31,11 @@ While this app is written to be run as a Jenkins job it can also be run locally.
|
|
31
31
|
source 'https://rubygems.org'
|
32
32
|
|
33
33
|
gem 'chef', '~> 11.0'
|
34
|
-
gem 'berkshelf', '~> 3.
|
34
|
+
gem 'berkshelf', '~> 3.2'
|
35
35
|
|
36
36
|
group :test do
|
37
|
-
gem 'reagan', '~> 0.
|
38
|
-
gem 'rubocop', '~> 0.
|
37
|
+
gem 'reagan', '~> 0.6'
|
38
|
+
gem 'rubocop', '~> 0.27'
|
39
39
|
gem 'foodcritic', '~> 4.0'
|
40
40
|
end
|
41
41
|
```
|
data/bin/reagan
CHANGED
@@ -19,31 +19,6 @@
|
|
19
19
|
# load the libs
|
20
20
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
21
21
|
|
22
|
-
require '
|
23
|
-
require 'optparse'
|
22
|
+
require 'application'
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
parser = OptionParser.new do |opts|
|
28
|
-
opts.banner = 'Usage: reagan [options]'
|
29
|
-
opts.on('-o', '--override cb1,cb2', 'Comma separated list of cookbooks to test') do |cookbooks|
|
30
|
-
flags[:override_cookbooks] = cookbooks.split(',')
|
31
|
-
end
|
32
|
-
|
33
|
-
opts.on('-p', '--pull_num 123', 'Github pull number to test') do |pull|
|
34
|
-
flags[:pull] = pull
|
35
|
-
end
|
36
|
-
|
37
|
-
opts.on('-c', '--config reagan.yml', 'Path to config file (defaults to /etc/reagan.yml)') do |config|
|
38
|
-
flags[:config] = config
|
39
|
-
end
|
40
|
-
|
41
|
-
opts.on('-h', '--help', 'Displays Help') do
|
42
|
-
puts opts
|
43
|
-
exit
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
parser.parse!
|
48
|
-
|
49
|
-
Reagan.new(flags).run
|
24
|
+
Reagan::Application.new.run
|
data/lib/application.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Tim Smith (<tim@cozy.co>)
|
4
|
+
# Copyright:: Copyright (c) 2014 Tim Smith
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Reagan
|
20
|
+
# the main class for the reagan app. gets called by the reagan bin
|
21
|
+
class Application
|
22
|
+
require 'config'
|
23
|
+
require 'change'
|
24
|
+
require 'test_json'
|
25
|
+
require 'test_knife'
|
26
|
+
require 'test_reagan'
|
27
|
+
require 'test_version'
|
28
|
+
|
29
|
+
attr_accessor :config
|
30
|
+
def initialize
|
31
|
+
@@config = Reagan::Config.new.settings
|
32
|
+
@changes = Reagan::Change.new.files
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.config
|
36
|
+
@@config
|
37
|
+
end
|
38
|
+
|
39
|
+
# nicely prints marques
|
40
|
+
def pretty_print(string)
|
41
|
+
puts "\n#{string}"
|
42
|
+
string.length.times { printf '-' }
|
43
|
+
puts "\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
# exit with a friendly message if nothing we test has been changed
|
47
|
+
def check_empty_update
|
48
|
+
objects_updated = false
|
49
|
+
%w(cookbooks roles environments data_bags).each do |object|
|
50
|
+
objects_updated = true unless @changes[object].empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
unless objects_updated
|
54
|
+
pretty_print('No objects to test. Exiting')
|
55
|
+
exit 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# run tests on each changed cookbook
|
60
|
+
def run
|
61
|
+
check_empty_update
|
62
|
+
|
63
|
+
# print objects that will be tested
|
64
|
+
pretty_print('The following chef objects will be tested')
|
65
|
+
%w(cookbooks roles environments data_bags).each do |type|
|
66
|
+
unless @changes[type].empty?
|
67
|
+
puts "#{type}:"
|
68
|
+
@changes[type].each { |obj| puts ' ' + obj }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
results = []
|
73
|
+
@changes['cookbooks'].each do |cookbook|
|
74
|
+
pretty_print("Testing cookbook #{cookbook}")
|
75
|
+
results << Reagan::TestKnife.new(cookbook).test
|
76
|
+
results << Reagan::TestVersion.new(cookbook).test
|
77
|
+
results << Reagan::TestReagan.new(cookbook).test
|
78
|
+
end
|
79
|
+
|
80
|
+
%w(data_bags roles environments).each do |type|
|
81
|
+
@changes[type].each do |file|
|
82
|
+
pretty_print("Testing #{type} file #{file}")
|
83
|
+
results << TestJSON.new(file).test
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# print success or failure
|
88
|
+
failure = results.include?(false)
|
89
|
+
text = failure ? 'Reagan testing has failed' : 'All Reagan tests have suceeded'
|
90
|
+
pretty_print(text)
|
91
|
+
|
92
|
+
# if any test failed then exit 1 so jenkins can pick up the failure
|
93
|
+
exit 1 if failure
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/change.rb
CHANGED
@@ -17,81 +17,99 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
19
|
begin
|
20
|
-
require 'reagan'
|
21
20
|
require 'rubygems'
|
22
21
|
require 'octokit'
|
23
22
|
rescue LoadError => e
|
24
23
|
raise "Missing gem or lib #{e}"
|
25
24
|
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
module Reagan
|
27
|
+
# determines changed files in the commit
|
28
|
+
class Change < Application
|
29
|
+
attr_accessor :files
|
30
|
+
def initialize
|
31
|
+
@config = Reagan::Change.config
|
32
|
+
@files = changed_files
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
# return hash of chef objects that have been changed
|
36
|
+
def changed_files
|
37
|
+
if @config['flags']['override_cookbooks']
|
38
|
+
files_from_override
|
39
|
+
else
|
40
|
+
pull = pull_num
|
41
|
+
puts "Grabbing contents of pull request #{pull}\n"
|
42
|
+
hash_builder(query_gh(pull))
|
43
|
+
end
|
42
44
|
end
|
43
|
-
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
files['cookbooks'] = @@config['flags']['override_cookbooks']
|
50
|
-
files
|
51
|
-
end
|
46
|
+
# build a files hash based on the override cookbooks passed by the user
|
47
|
+
def files_from_override
|
48
|
+
files = {}
|
49
|
+
%w(environments roles data_bags).each { |object| files[object] = {} }
|
52
50
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
51
|
+
# ensure that the passed cookbooks exist in the workspace first
|
52
|
+
cookbooks = []
|
53
|
+
@config['flags']['override_cookbooks'] .each do |cb|
|
54
|
+
if object_still_exists(::File.join('cookbooks/', cb))
|
55
|
+
cookbooks << cb
|
56
|
+
else
|
57
|
+
puts "Skipping override cookbook #{cb} as it does not exist in the workspace"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
files['cookbooks'] = cookbooks
|
62
|
+
files
|
62
63
|
end
|
63
|
-
pull
|
64
|
-
end
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
# fetch pull num from either ENV or CLI param
|
66
|
+
def pull_num
|
67
|
+
if @config['flags']['pull']
|
68
|
+
pull = @config['flags']['pull']
|
69
|
+
elsif ENV['ghprbPullId']
|
70
|
+
pull = ENV['ghprbPullId']
|
71
|
+
else
|
72
|
+
puts 'Jenkins ghprbPullId environmental variable not set or --pull option not used. Cannot continue'
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
pull
|
76
|
+
end
|
71
77
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
78
|
+
# queries github for the files that have changed
|
79
|
+
def query_gh(pull_num)
|
80
|
+
gh = Octokit::Client.new(:access_token => @config['github']['auth_token'])
|
81
|
+
files_from_pull(gh.pull_request_files(@config ['github']['repo'], pull_num))
|
82
|
+
end
|
83
|
+
|
84
|
+
# convert pull request response to array of changed files
|
85
|
+
def files_from_pull(pull_changes)
|
86
|
+
files = []
|
87
|
+
pull_changes.each do |file|
|
88
|
+
files << file[:filename]
|
89
|
+
end
|
90
|
+
files
|
91
|
+
end
|
92
|
+
|
93
|
+
# check to see if the file exists in the workspace so we don't test deleted objects
|
94
|
+
def object_still_exists(file)
|
95
|
+
::File.exist?(::File.join(@config['jenkins']['workspace_dir'],file))
|
77
96
|
end
|
78
|
-
files
|
79
|
-
end
|
80
97
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
98
|
+
# builds a hash of files / cookbooks that changed based on the pull data from GH
|
99
|
+
def hash_builder(pull_files)
|
100
|
+
files = {}
|
101
|
+
%w(environments roles data_bags cookbooks).each { |object| files[object] = [] }
|
102
|
+
cookbooks = []
|
86
103
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
104
|
+
pull_files.each do |file|
|
105
|
+
files['environments'] << file && next if file.match('^environments') && object_still_exists(file)
|
106
|
+
files['roles'] << file && next if file.match('^roles') && object_still_exists(file)
|
107
|
+
files['data_bags'] << file && next if file.match('^data_bags') && object_still_exists(file)
|
108
|
+
cookbooks << file.split('/')[1] if file.match('^cookbooks') && object_still_exists(::File.join('cookbooks/', file.split('/')[1]))
|
109
|
+
end
|
110
|
+
# set cookbooks array to set to dedupe list of cookbooks
|
111
|
+
files['cookbooks'] = cookbooks.to_set
|
112
|
+
files
|
92
113
|
end
|
93
|
-
# set cookbooks array to set to dedupe list of cookbooks
|
94
|
-
files['cookbooks'] = cookbooks.to_set
|
95
|
-
files
|
96
114
|
end
|
97
115
|
end
|
data/lib/config.rb
CHANGED
@@ -18,41 +18,69 @@
|
|
18
18
|
|
19
19
|
begin
|
20
20
|
require 'yaml'
|
21
|
+
require 'optparse'
|
21
22
|
rescue LoadError => e
|
22
23
|
raise "Missing gem or lib #{e}"
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
module Reagan
|
27
|
+
# builds a single config from passed flags, yaml config, and knife.rb
|
28
|
+
class Config
|
29
|
+
attr_accessor :settings
|
30
|
+
def initialize
|
31
|
+
@flags = flag_parser
|
32
|
+
@config_file = load_config_file
|
33
|
+
@settings = build_config
|
34
|
+
end
|
35
|
+
|
36
|
+
# grabs the flags passed in via command line
|
37
|
+
def flag_parser
|
38
|
+
flags = { :pull => nil, :override_cookbooks => nil, :config => '/etc/reagan.yml' }
|
39
|
+
OptionParser.new do |opts|
|
40
|
+
opts.banner = 'Usage: reagan [options]'
|
41
|
+
opts.on('-o', '--override cb1,cb2', 'Comma separated list of cookbooks to test') do |cookbooks|
|
42
|
+
flags[:override_cookbooks] = cookbooks.split(',')
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on('-p', '--pull_num 123', 'Github pull number to test') do |pull|
|
46
|
+
flags[:pull] = pull
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('-c', '--config reagan.yml', 'Path to config file (defaults to /etc/reagan.yml)') do |config|
|
50
|
+
flags[:config] = config
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on('-h', '--help', 'Displays Help') do
|
54
|
+
puts opts
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
end.parse!
|
33
58
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
59
|
+
flags
|
60
|
+
end
|
61
|
+
|
62
|
+
# loads the reagan.yml config file from /etc/reagan.yml or the passed location
|
63
|
+
def load_config_file
|
64
|
+
config = YAML.load_file(@flags[:config])
|
65
|
+
if config == false
|
66
|
+
puts "ERROR: Reagan config at #{@flags[:config]} does not contain any configuration data"
|
67
|
+
exit 1
|
68
|
+
end
|
69
|
+
config
|
70
|
+
rescue Errno::ENOENT
|
71
|
+
puts "ERROR: Cannot load Reagan config file at #{@flags[:config]}"
|
72
|
+
exit 1
|
73
|
+
rescue Psych::SyntaxError
|
74
|
+
puts "ERROR: Syntax error in Reagan config file at #{@flags[:config]}"
|
39
75
|
exit 1
|
40
76
|
end
|
41
|
-
config
|
42
|
-
rescue Errno::ENOENT
|
43
|
-
puts "ERROR: Cannot load Reagan config file at #{@flags[:config]}"
|
44
|
-
exit 1
|
45
|
-
rescue Psych::SyntaxError
|
46
|
-
puts "ERROR: Syntax error in Reagan config file at #{@flags[:config]}"
|
47
|
-
exit 1
|
48
|
-
end
|
49
77
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
78
|
+
# join the config file with the passed flags into a single object
|
79
|
+
def build_config
|
80
|
+
config = @config_file
|
81
|
+
config['flags'] = {}
|
82
|
+
@flags.each { |k, v| config['flags'][k.to_s] = v }
|
83
|
+
config
|
84
|
+
end
|
56
85
|
end
|
57
|
-
|
58
86
|
end
|
data/lib/test_json.rb
CHANGED
@@ -22,24 +22,27 @@ rescue LoadError => e
|
|
22
22
|
raise "Missing gem or lib #{e}"
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
module Reagan
|
26
|
+
# tests to make sure the version has been updated on the cookbook
|
27
|
+
class TestJSON < Application
|
28
|
+
def initialize(file)
|
29
|
+
@config = Reagan::TestJSON.config
|
30
|
+
@file = file
|
31
|
+
end
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
# performs JSON format test
|
34
|
+
# returns true if json can be parsed and false if it cannot
|
35
|
+
def test
|
36
|
+
puts 'Running JSON parsing test:'
|
37
|
+
begin
|
38
|
+
json_file = File.read(File.join(@config['jenkins']['workspace_dir'], @file))
|
39
|
+
JSON.parse(json_file)
|
40
|
+
success = true
|
41
|
+
rescue JSON::JSONError
|
42
|
+
success = false
|
43
|
+
end
|
44
|
+
puts success ? ' PASS: JSON parses' : ' FAIL: JSON does NOT parse'
|
45
|
+
success
|
41
46
|
end
|
42
|
-
puts success ? " PASS: JSON parses" : " FAIL: JSON does NOT parse"
|
43
|
-
success
|
44
47
|
end
|
45
48
|
end
|
data/lib/test_knife.rb
CHANGED
@@ -16,20 +16,23 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
module Reagan
|
20
|
+
# tests cookbooks using knife cookbook test functionality
|
21
|
+
class TestKnife < Application
|
22
|
+
def initialize(cookbook)
|
23
|
+
@config = Reagan::TestKnife.config
|
24
|
+
@cookbook = cookbook
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
# performs knife cookbook test
|
28
|
+
# returns true if cookbook passed or false if it failed
|
29
|
+
def test
|
30
|
+
# grab the version of the cookbook in the local metadata
|
31
|
+
result = system "knife cookbook test -o #{File.join(@@config['jenkins']['workspace_dir'], 'cookbooks')} #{@cookbook} > /dev/null 2>&1"
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
puts 'Running knife cookbook test:'
|
34
|
+
puts result ? ' PASS: Knife cookbook test was successful' : ' FAIL: Knife cookbookk test was NOT successful'
|
35
|
+
result
|
36
|
+
end
|
34
37
|
end
|
35
38
|
end
|
data/lib/test_reagan.rb
CHANGED
@@ -16,34 +16,38 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
module Reagan
|
20
|
+
# tests cookbooks using tests defined in reagan_test.yml files
|
21
|
+
class TestReagan < Application
|
22
|
+
def initialize(cookbook)
|
23
|
+
@config = Reagan::TestReagan.config
|
24
|
+
@cookbook = cookbook
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
# returns true if tests defined in reagan_test.yml passed/don't exist or false if it failed
|
28
|
+
def test
|
29
|
+
puts 'Running reagan_test.yml defined tests:'
|
30
|
+
# check to see if a reagan_test.yml file exists
|
31
|
+
if File.exist?(File.join(@config['jenkins']['workspace_dir'], 'cookbooks', @cookbook, 'reagan_test.yml'))
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
+
# load the reagan config file
|
34
|
+
reagan_def = YAML.load_file(File.join(@config['jenkins']['workspace_dir'], 'cookbooks', @cookbook, 'reagan_test.yml'))
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
# change into the cookbook dir so rake tests run locally
|
37
|
+
Dir.chdir(File.join(@config['jenkins']['workspace_dir'], 'cookbooks', @cookbook))
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
status = true
|
40
|
+
reagan_def['tests'].each do |test|
|
41
|
+
puts " reagan_test.yml test: '#{test}'"
|
42
|
+
result = system test
|
43
|
+
status = false if result == false
|
44
|
+
end
|
45
|
+
puts status ? ' PASS: reagan_test.yml test was successful' : ' FAIL: reagan_test.yml test was NOT successful'
|
46
|
+
status
|
47
|
+
else
|
48
|
+
puts ' SKIP: No reagan_test.yml file found in the cookbook path. Skipping test'
|
49
|
+
status
|
41
50
|
end
|
42
|
-
puts status ? ' PASS: reagan_test.yml test was successful' : ' FAIL: reagan_test.yml test was NOT successful'
|
43
|
-
status
|
44
|
-
else
|
45
|
-
puts ' SKIP: No reagan_test.yml file found in the cookbook path. Skipping test'
|
46
|
-
status
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
data/lib/test_version.rb
CHANGED
@@ -24,52 +24,55 @@ rescue LoadError => e
|
|
24
24
|
raise "Missing gem or lib #{e}"
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
module Reagan
|
28
|
+
# tests to make sure the version has been updated on the cookbook
|
29
|
+
class TestVersion < Application
|
30
|
+
def initialize(cookbook)
|
31
|
+
@config = Reagan::TestVersion.config
|
32
|
+
@cookbook = cookbook
|
33
|
+
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
# grab the version of the cookbook in the local metadata
|
36
|
+
def check_commit_version
|
37
|
+
metadata = Chef::Cookbook::Metadata.new
|
38
|
+
metadata.from_file(File.join(@config['jenkins']['workspace_dir'], 'cookbooks', @cookbook, 'metadata.rb'))
|
39
|
+
metadata.version
|
40
|
+
end
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
# grab the most recent version of the cookbook on the chef server
|
43
|
+
def check_server_version
|
44
|
+
Ridley::Logging.logger.level = Logger.const_get 'ERROR'
|
45
|
+
begin
|
46
|
+
server_con = Ridley.new(
|
47
|
+
server_url: @config['chef']['server_url'],
|
48
|
+
client_name: @config['chef']['client_name'],
|
49
|
+
client_key: @config['chef']['pem_path'],
|
50
|
+
ssl: { verify: false }
|
51
|
+
)
|
52
|
+
# return the version if the cookbook exists or return 0.0.0 if it's a new coobook not yet on the server
|
53
|
+
if server_con.cookbook.all[@cookbook]
|
54
|
+
server_con.cookbook.all[@cookbook][0]
|
55
|
+
else
|
56
|
+
'0.0.0'
|
57
|
+
end
|
58
|
+
rescue Ridley::Errors::ConnectionFailed
|
59
|
+
puts ' ERROR: Failed to connect to the Chef server. Cannot continue'
|
60
|
+
exit 1
|
55
61
|
end
|
56
|
-
rescue Ridley::Errors::ConnectionFailed
|
57
|
-
puts ' ERROR: Failed to connect to the Chef server. Cannot continue'
|
58
|
-
exit 1
|
59
62
|
end
|
60
|
-
end
|
61
63
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
# performs version update test
|
65
|
+
# returns true if version has been rev'd and false if not
|
66
|
+
def test
|
67
|
+
commit_v = check_commit_version
|
68
|
+
serv_v = check_server_version
|
69
|
+
updated = Gem::Version.new(serv_v) < Gem::Version.new(commit_v) ? true : false
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
puts "Running cookbook version rev'd test:"
|
72
|
+
puts " Server version: #{serv_v}"
|
73
|
+
puts " Commit version: #{commit_v}"
|
74
|
+
puts updated ? " PASS: Metadata version has been rev'd" : " FAIL: Metadata version has NOT been rev'd"
|
75
|
+
updated
|
76
|
+
end
|
74
77
|
end
|
75
78
|
end
|
data/reagan.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'reagan'
|
3
|
+
s.version = '0.7.0'
|
4
|
+
s.date = Date.today.to_s
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.extra_rdoc_files = ['README.md', 'LICENSE']
|
7
|
+
s.summary = 'Trust But Verify - Ruby build script for Jenkins that automates the testing of Chef cookbooks'
|
8
|
+
s.description = s.summary
|
9
|
+
s.authors = ['Tim Smith']
|
10
|
+
s.email = 'tim@cozy.co'
|
11
|
+
s.homepage = 'http://www.github.com/tas50/reagan'
|
12
|
+
s.license = 'Apache-2.0'
|
13
|
+
|
14
|
+
s.required_ruby_version = '>= 1.9.3'
|
15
|
+
s.add_dependency 'octokit', '~> 3.0'
|
16
|
+
s.add_dependency 'chef', '~> 11.0'
|
17
|
+
s.add_dependency 'ridley', '~> 4.0'
|
18
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
19
|
+
|
20
|
+
s.files = `git ls-files -z`.split("\x0")
|
21
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
s.require_paths = ['lib']
|
23
|
+
s.extra_rdoc_files = ['README.md']
|
24
|
+
s.rdoc_options = ['--line-numbers', '--inline-source', '--title', 'reagan', '--main', 'README.md']
|
25
|
+
end
|
metadata
CHANGED
@@ -1,69 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reagan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: octokit
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: chef
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '11.0'
|
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
40
|
version: '11.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: ridley
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '4.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '4.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '10.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '10.0'
|
69
69
|
description: Trust But Verify - Ruby build script for Jenkins that automates the testing
|
@@ -74,19 +74,22 @@ executables:
|
|
74
74
|
extensions: []
|
75
75
|
extra_rdoc_files:
|
76
76
|
- README.md
|
77
|
-
- LICENSE
|
78
77
|
files:
|
78
|
+
- .gitignore
|
79
|
+
- .rubocop.yml
|
80
|
+
- Gemfile
|
79
81
|
- LICENSE
|
80
82
|
- README.md
|
81
83
|
- Rakefile
|
82
84
|
- bin/reagan
|
85
|
+
- lib/application.rb
|
83
86
|
- lib/change.rb
|
84
87
|
- lib/config.rb
|
85
|
-
- lib/reagan.rb
|
86
88
|
- lib/test_json.rb
|
87
89
|
- lib/test_knife.rb
|
88
90
|
- lib/test_reagan.rb
|
89
91
|
- lib/test_version.rb
|
92
|
+
- reagan.gemspec
|
90
93
|
- reagan.yml.EXAMPLE
|
91
94
|
- reagan_test.yml.EXAMPLE
|
92
95
|
homepage: http://www.github.com/tas50/reagan
|
@@ -94,25 +97,30 @@ licenses:
|
|
94
97
|
- Apache-2.0
|
95
98
|
metadata: {}
|
96
99
|
post_install_message:
|
97
|
-
rdoc_options:
|
100
|
+
rdoc_options:
|
101
|
+
- --line-numbers
|
102
|
+
- --inline-source
|
103
|
+
- --title
|
104
|
+
- reagan
|
105
|
+
- --main
|
106
|
+
- README.md
|
98
107
|
require_paths:
|
99
108
|
- lib
|
100
109
|
required_ruby_version: !ruby/object:Gem::Requirement
|
101
110
|
requirements:
|
102
|
-
- -
|
111
|
+
- - '>='
|
103
112
|
- !ruby/object:Gem::Version
|
104
113
|
version: 1.9.3
|
105
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
115
|
requirements:
|
107
|
-
- -
|
116
|
+
- - '>='
|
108
117
|
- !ruby/object:Gem::Version
|
109
118
|
version: '0'
|
110
119
|
requirements: []
|
111
120
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.4.
|
121
|
+
rubygems_version: 2.4.2
|
113
122
|
signing_key:
|
114
123
|
specification_version: 4
|
115
124
|
summary: Trust But Verify - Ruby build script for Jenkins that automates the testing
|
116
125
|
of Chef cookbooks
|
117
126
|
test_files: []
|
118
|
-
has_rdoc:
|
data/lib/reagan.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
#
|
3
|
-
# Author:: Tim Smith (<tim@cozy.co>)
|
4
|
-
# Copyright:: Copyright (c) 2014 Tim Smith
|
5
|
-
# License:: Apache License, Version 2.0
|
6
|
-
#
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
-
# you may not use this file except in compliance with the License.
|
9
|
-
# You may obtain a copy of the License at
|
10
|
-
#
|
11
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
-
#
|
13
|
-
# Unless required by applicable law or agreed to in writing, software
|
14
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
-
# See the License for the specific language governing permissions and
|
17
|
-
# limitations under the License.
|
18
|
-
|
19
|
-
# the main class for the reagan app. gets called by the reagan bin
|
20
|
-
class Reagan
|
21
|
-
require 'config'
|
22
|
-
require 'change'
|
23
|
-
require 'test_knife'
|
24
|
-
require 'test_version'
|
25
|
-
require 'test_reagan'
|
26
|
-
require 'test_json'
|
27
|
-
|
28
|
-
attr_accessor :config
|
29
|
-
def initialize(flags)
|
30
|
-
@@config = ReaganConfig.new(flags).settings
|
31
|
-
@changes = Change.new.files
|
32
|
-
end
|
33
|
-
|
34
|
-
# nicely prints marques
|
35
|
-
def pretty_print(string)
|
36
|
-
puts "\n#{string}"
|
37
|
-
string.length.times { printf '-' }
|
38
|
-
puts "\n"
|
39
|
-
end
|
40
|
-
|
41
|
-
# exit with a friendly message if nothing we test has been changed
|
42
|
-
def check_empty_update
|
43
|
-
objects_updated = false
|
44
|
-
%w(cookbooks roles environments data_bags).each do |object|
|
45
|
-
objects_updated = true unless @changes[object].empty?
|
46
|
-
end
|
47
|
-
|
48
|
-
unless objects_updated
|
49
|
-
pretty_print('No objects to test. Exiting')
|
50
|
-
exit 0
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# run tests on each changed cookbook
|
55
|
-
def run
|
56
|
-
check_empty_update
|
57
|
-
|
58
|
-
# print objects that will be tested
|
59
|
-
pretty_print('The following chef objects will be tested')
|
60
|
-
%w(cookbooks roles environments data_bags).each do |type|
|
61
|
-
unless @changes[type].empty?
|
62
|
-
puts "#{type}:"
|
63
|
-
@changes[type].each { |obj| puts ' ' + obj }
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
results = []
|
68
|
-
@changes['cookbooks'].each do |cookbook|
|
69
|
-
pretty_print("Testing cookbook #{cookbook}")
|
70
|
-
results << TestKnife.new(cookbook).test
|
71
|
-
results << TestVersion.new(cookbook).test
|
72
|
-
results << TestReagan.new(cookbook).test
|
73
|
-
end
|
74
|
-
|
75
|
-
%w(data_bags roles environments).each do |type|
|
76
|
-
@changes[type].each do |file|
|
77
|
-
pretty_print("Testing #{type} file #{file}")
|
78
|
-
results << TestJSON.new(file).test
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# print success or failure
|
83
|
-
failure = results.include?(false)
|
84
|
-
text = failure ? 'Reagan testing has failed' : 'All Reagan tests have suceeded'
|
85
|
-
pretty_print(text)
|
86
|
-
|
87
|
-
# if any test failed then exit 1 so jenkins can pick up the failure
|
88
|
-
exit 1 if failure
|
89
|
-
end
|
90
|
-
end
|