kitchen-inspector 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG.md +24 -0
  5. data/Gemfile +0 -2
  6. data/README.md +268 -39
  7. data/Rakefile +41 -0
  8. data/kitchen-inspector.gemspec +21 -3
  9. data/lib/kitchen-inspector/inspector.rb +11 -4
  10. data/lib/kitchen-inspector/inspector/chef_inspector.rb +66 -0
  11. data/lib/kitchen-inspector/inspector/cli.rb +29 -3
  12. data/lib/kitchen-inspector/inspector/{error.rb → common.rb} +43 -1
  13. data/lib/kitchen-inspector/inspector/dependency.rb +26 -40
  14. data/lib/kitchen-inspector/inspector/health_bureau.rb +181 -0
  15. data/lib/kitchen-inspector/inspector/mixin/utils.rb +83 -0
  16. data/lib/kitchen-inspector/inspector/report/report.rb +182 -0
  17. data/lib/kitchen-inspector/inspector/report/status_reporter.rb +105 -0
  18. data/lib/kitchen-inspector/inspector/repository_inspector.rb +134 -0
  19. data/lib/kitchen-inspector/inspector/repository_managers/base.rb +110 -0
  20. data/lib/kitchen-inspector/inspector/repository_managers/github.rb +97 -0
  21. data/lib/kitchen-inspector/inspector/repository_managers/gitlab.rb +100 -0
  22. data/lib/kitchen-inspector/inspector/version.rb +1 -2
  23. data/spec/cli_spec.rb +46 -0
  24. data/spec/data/cookbook_deps/metadata.rb +10 -0
  25. data/spec/data/cookbook_no_deps/metadata.rb +7 -0
  26. data/spec/data/test_client.pem +27 -0
  27. data/spec/data/test_config_invalid.rb +4 -0
  28. data/spec/data/test_config_valid.rb +4 -0
  29. data/spec/dependency_inspector_spec.rb +296 -0
  30. data/spec/github_manager_spec.rb +79 -0
  31. data/spec/gitlab_manager_spec.rb +58 -0
  32. data/spec/report_spec.rb +237 -0
  33. data/spec/support/spec_helper.rb +81 -0
  34. data/spec/utils_spec.rb +29 -0
  35. metadata +129 -15
  36. data/INFO.md +0 -44
  37. data/info.css +0 -31
  38. data/lib/kitchen-inspector/inspector/dependency_inspector.rb +0 -153
  39. data/lib/kitchen-inspector/inspector/report.rb +0 -148
@@ -3,12 +3,24 @@ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'kitchen-inspector/inspector/version'
5
5
 
6
+ # Generate pre-release versions for non tagged releases
7
+ git_version = begin
8
+ describe = `git describe`
9
+ if $?.success?
10
+ stripped = describe.strip
11
+ /^([^-]+)-([0-9]+)-[^-]+$/.match(stripped) ? "#{$1}.#{$2}" : stripped
12
+ else
13
+ git_raw = `git log --pretty=format:%h | head -n1`
14
+ $?.success? ? '0.0.0.%d' % git_raw.strip.to_i(16) : '0.0.0'
15
+ end
16
+ end
17
+
6
18
  Gem::Specification.new do |spec|
7
19
  spec.name = "kitchen-inspector"
8
- spec.version = KitchenInspector::Inspector::VERSION
20
+ spec.version = git_version
9
21
  spec.authors = ["Stefano Tortarolo"]
10
22
  spec.email = ["stefano.tortarolo@gmail.com"]
11
- spec.description = %q{Given an Opscode Chef cookbook, verifies its dependencies against a Chef Server and a Gitlab instance}
23
+ spec.description = %q{Given a Chef cookbook, verifies its dependencies against a Chef Server and a Repository Manager instance (i.e., GitHub/GitLab)}
12
24
  spec.summary = %q{Kitchen integrity checker}
13
25
  spec.homepage = "https://github.com/astratto/kitchen-inspector"
14
26
  spec.license = "MIT"
@@ -21,12 +33,18 @@ Gem::Specification.new do |spec|
21
33
  spec.add_development_dependency "bundler", "~> 1.3"
22
34
  spec.add_development_dependency "rubocop", "~> 0.14"
23
35
  spec.add_development_dependency "rake"
36
+ spec.add_development_dependency 'chef-zero'
37
+ spec.add_development_dependency 'rspec'
38
+ spec.add_development_dependency 'coveralls'
39
+ spec.add_development_dependency "gitlab", "~> 3.0"
40
+ spec.add_development_dependency "octokit", "~> 2.6"
24
41
 
25
42
  spec.add_dependency "solve", "~> 0.8.0"
26
43
  spec.add_dependency "berkshelf", "~> 2.0.10"
27
44
  spec.add_dependency "thor", "~> 0.18.0"
28
45
  spec.add_dependency "terminal-table", "~> 1.4.5"
29
46
  spec.add_dependency "colorize", "~> 0.6.0"
30
- spec.add_dependency "gitlab"
47
+ spec.add_dependency "httparty", "~> 0.10.0"
48
+ spec.add_dependency "googl", "~> 0.6.3"
31
49
  spec.add_dependency "chef", ">= 11.0.0"
32
50
  end
@@ -29,11 +29,18 @@ require 'colorize'
29
29
  require 'ridley'
30
30
  require 'terminal-table'
31
31
  require 'thor'
32
- require 'gitlab'
32
+ require 'googl'
33
33
 
34
+ require 'kitchen-inspector/inspector/common'
35
+ require 'kitchen-inspector/inspector/mixin/utils'
34
36
  require 'kitchen-inspector/inspector/cli'
35
- require 'kitchen-inspector/inspector/error'
36
37
  require 'kitchen-inspector/inspector/dependency'
37
- require 'kitchen-inspector/inspector/dependency_inspector'
38
- require 'kitchen-inspector/inspector/report'
38
+
39
+ require 'kitchen-inspector/inspector/chef_inspector'
40
+ require 'kitchen-inspector/inspector/repository_inspector'
41
+ require 'kitchen-inspector/inspector/health_bureau'
42
+
43
+ require 'kitchen-inspector/inspector/repository_managers/base'
44
+ require 'kitchen-inspector/inspector/report/report'
45
+ require 'kitchen-inspector/inspector/report/status_reporter'
39
46
  require 'kitchen-inspector/inspector/version'
@@ -0,0 +1,66 @@
1
+ #
2
+ # Copyright (c) 2013 Stefano Tortarolo <stefano.tortarolo@gmail.com>
3
+ #
4
+ # MIT License
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #
25
+
26
+ module KitchenInspector
27
+ module Inspector
28
+ class ChefInspector
29
+ include Utils
30
+
31
+ def initialize(config)
32
+ @chef_server_url = config[:url]
33
+ @chef_username = config[:username]
34
+ @chef_client_pem = config[:client_pem]
35
+
36
+ raise ChefAccessNotConfiguredError, config_msg("Chef Server url", ":url") unless @chef_server_url
37
+ raise ChefAccessNotConfiguredError, config_msg("Chef username", ":username") unless @chef_username
38
+ raise ChefAccessNotConfiguredError, config_msg("Chef client PEM", ":client_pem") unless @chef_client_pem
39
+
40
+ @chef_info_cache = {}
41
+ end
42
+
43
+ def investigate(dependency)
44
+ cache_key = "#{dependency.name}, #{dependency.requirement}"
45
+ @chef_info_cache[cache_key] ||= begin
46
+ chef_info = {}
47
+ chef_info[:versions] = find_versions(dependency.name)
48
+ chef_info[:latest_version] = get_latest_version(chef_info[:versions])
49
+ chef_info[:version_used] = satisfy(dependency.requirement, chef_info[:versions])
50
+ chef_info
51
+ end
52
+ end
53
+
54
+ # Given a project return the versions on the Chef Server
55
+ def find_versions(project)
56
+ rest = Chef::REST.new(@chef_server_url, @chef_username, @chef_client_pem)
57
+ cookbook = rest.get("cookbooks/#{project}")
58
+ versions = []
59
+ versions = cookbook[project]["versions"].collect{|c| fix_version_name(c["version"])} if cookbook
60
+ versions
61
+ rescue Net::HTTPServerException
62
+ []
63
+ end
64
+ end
65
+ end
66
+ end
@@ -34,20 +34,46 @@ module KitchenInspector
34
34
  default: 'table',
35
35
  aliases: '-t'
36
36
 
37
- desc 'investigate (COOKBOOK_PATH)', 'Check Gitlab/Chef status of dependent cookbooks'
37
+ method_option :recursive, type: :boolean,
38
+ desc: 'Specify whether recursive dependencies must be analyzed',
39
+ default: true,
40
+ aliases: '-r'
41
+
42
+ method_option :config, type: :string,
43
+ desc: 'The configuration to use',
44
+ default: File.join("#{Dir.home}", ".chef", "kitchen_inspector.rb"),
45
+ aliases: '-c'
46
+
47
+ method_option :remarks, type: :boolean,
48
+ desc: 'Show remarks (useful to provide more descriptive information)',
49
+ default: false,
50
+ aliases: '--remarks'
51
+
52
+ desc 'investigate (COOKBOOK_PATH)', 'Check Repository Manager/Chef Server status of dependent cookbooks'
38
53
 
39
54
  map 'inspect' => :investigate
40
55
  def investigate(path=Dir.pwd)
41
- dependencies = DependencyInspector.investigate path
56
+ inspector = HealthBureau.new options[:config]
57
+
58
+ dependencies = inspector.investigate(path, options[:recursive])
59
+
42
60
  if dependencies.empty?
43
61
  puts 'No dependent cookbooks'.yellow
62
+ status_code = :'warning-nodependencies'
44
63
  else
45
- puts Report.generate(dependencies, options[:format])
64
+ output, status_code = Report.generate(dependencies, options[:format], options)
65
+ puts output
46
66
  end
67
+ exit STATUS_TO_RETURN_CODES[status_code]
68
+ rescue ConfigurationError => e
69
+ puts e.message.red
70
+ exit STATUS_TO_RETURN_CODES[:'error-config']
47
71
  rescue NotACookbookError
48
72
  puts 'The path is not a cookbook path'.red
73
+ exit STATUS_TO_RETURN_CODES[:'error-notacookbook']
49
74
  rescue UnsupportedReportFormatError
50
75
  puts "The report format #{options[:format]} is not supported".red
76
+ exit STATUS_TO_RETURN_CODES[:'error-reportformat']
51
77
  end
52
78
  end
53
79
  end
@@ -25,10 +25,52 @@
25
25
 
26
26
  module KitchenInspector
27
27
  module Inspector
28
- class GitlabAccessNotConfiguredError < StandardError; end
28
+ class ConfigurationError < StandardError; end
29
+ class RepositoryManagerError < ConfigurationError; end
30
+
29
31
  class ChefAccessNotConfiguredError < StandardError; end
30
32
  class NotACookbookError < StandardError; end
31
33
  class DuplicateCookbookError < StandardError; end
32
34
  class UnsupportedReportFormatError < ArgumentError; end
35
+
36
+ # Graphical marks
37
+ TICK_MARK = "\u2714"
38
+ X_MARK = "\u2716"
39
+ ESCLAMATION_MARK = "!"
40
+ INFO_MARK = "i"
41
+ INDENT_MARK = "\u203A"
42
+ QUESTION_MARK = "?"
43
+
44
+ # Dependency statuses
45
+ STATUSES = {
46
+ :up_to_date => TICK_MARK,
47
+ :err_req => X_MARK,
48
+ :err_repo => X_MARK,
49
+ :err_chef => X_MARK,
50
+ :warn_req => ESCLAMATION_MARK,
51
+ :warn_chef => INFO_MARK,
52
+ :warn_mismatch_repo => ESCLAMATION_MARK,
53
+ :warn_outofdate_repo => (ESCLAMATION_MARK * 2),
54
+ :warn_notunique_repo => QUESTION_MARK
55
+ }
56
+ STATUSES.default = ' '
57
+
58
+ # Possible return codes
59
+ #
60
+ # Note that global :err_chef is not possible since there would
61
+ # be at least one :err_req that takes precedence
62
+ STATUS_TO_RETURN_CODES = {
63
+ :up_to_date => 0,
64
+ :err_req => 100,
65
+ :err_repo => 101,
66
+ :err_config => 102,
67
+ :err_notacookbook => 103,
68
+ :err_reportformat => 104,
69
+ :warn_req => 200,
70
+ :warn_mismatch_repo => 201,
71
+ :warn_outofdate_repo => 202,
72
+ :warn_chef => 203
73
+ }
74
+ STATUS_TO_RETURN_CODES.default = 1
33
75
  end
34
76
  end
@@ -27,73 +27,59 @@ module KitchenInspector
27
27
  module Inspector
28
28
  # The class that contains information about a dependent cookbook
29
29
  class Dependency
30
+ include Comparable
31
+
30
32
  # The name of the dependency
31
33
  attr_reader :name
32
34
 
33
35
  # The requirement for the dependency
34
36
  attr_reader :requirement
35
37
 
36
- # The version of cookbook used after applying the version constraint
37
- attr_accessor :version_used
38
-
39
- # The versions available on Chef Server
40
- attr_accessor :chef_versions
41
-
42
- # The latest version available on Chef Server
43
- attr_accessor :latest_chef
38
+ # Info from Chef Server
39
+ attr_accessor :chef
44
40
 
45
- # The versions available on Gitlab
46
- attr_accessor :gitlab_versions
47
-
48
- # The latest version available on Gitlab
49
- attr_accessor :latest_gitlab
41
+ # Info from the Repository Manager
42
+ attr_accessor :repomanager
50
43
 
51
44
  # The status of the dependency
52
45
  attr_accessor :status
53
46
 
54
- # The status of Gitlab
55
- attr_accessor :gitlab_status
56
-
57
- # The status of Chef Server
58
- attr_accessor :chef_status
59
-
60
- # The source URL for a cookbook
61
- attr_accessor :source_url
62
-
63
- # The changelog link for the dependency if available
64
- attr_accessor :changelog
47
+ # The dependencies of a cookbook
48
+ attr_accessor :dependencies
65
49
 
66
50
  # Remarks field
67
51
  attr_accessor :remarks
68
52
 
53
+ # Dependency's parents (if transitive)
54
+ attr_accessor :parents
55
+
69
56
  def initialize(name, requirement)
70
57
  @name = name
71
58
  @requirement = requirement
72
- @version_used = nil
73
- @chef_versions = []
74
- @latest_chef = nil
75
- @gitlab_versions = []
76
- @latest_gitlab = nil
59
+ @chef = {}
60
+ @repomanager = {}
77
61
  @status = nil
78
- @gitlab_status = nil
79
- @chef_status = nil
80
- @source_url = nil
81
62
  @remarks = []
63
+ @dependencies = []
64
+ @parents = []
65
+ end
66
+
67
+ def ==(anOther)
68
+ name == anOther.name && requirement == anOther.requirement
82
69
  end
83
70
 
84
71
  def to_hash
85
72
  {}.tap do |hash|
73
+ hash[:name] = name
86
74
  hash[:requirement] = requirement
87
- hash[:used] = version_used
88
- hash[:chef_versions] = chef_versions
89
- hash[:latest_chef] = latest_chef
90
- hash[:gitlab_versions] = gitlab_versions
91
- hash[:latest_gitlab] = latest_gitlab
92
75
  hash[:status] = status
93
- hash[:gitlab_status] = gitlab_status
94
- hash[:chef_status] = chef_status
95
- hash[:source_url] = source_url
96
76
  hash[:remarks] = remarks
77
+ hash[:dependencies] = dependencies
78
+ hash[:chef] = chef
79
+ hash[:chef][:latest_version] = hash[:chef][:latest_version].to_s if hash[:chef][:latest_version]
80
+ hash[:repomanager] = repomanager
81
+ hash[:repomanager][:latest_tag] = hash[:repomanager][:latest_tag].to_s if hash[:repomanager][:latest_tag]
82
+ hash[:repomanager][:latest_metadata] = hash[:repomanager][:latest_metadata].to_s if hash[:repomanager][:latest_metadata]
97
83
  end
98
84
  end
99
85
  end
@@ -0,0 +1,181 @@
1
+ #
2
+ # Copyright (c) 2013 Stefano Tortarolo <stefano.tortarolo@gmail.com>
3
+ #
4
+ # MIT License
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #
25
+
26
+ module KitchenInspector
27
+ module Inspector
28
+ # Main class that, starting from a cookbook, analyzes its dependencies
29
+ # using its "inspectors" and returns a collection of analyzed dependencies
30
+ class HealthBureau
31
+ include Utils
32
+
33
+ attr_reader :chef_inspector, :repo_inspector
34
+
35
+ def initialize(config)
36
+ configuration = read_config(config)
37
+
38
+ begin
39
+ self.instance_eval configuration
40
+ rescue NoMethodError => e
41
+ raise ConfigurationError, "Unsupported configuration: #{e.name}"
42
+ end
43
+ end
44
+
45
+ # Inspect your kitchen!
46
+ #
47
+ # If recursive is specified, dependencies' metadata are downloaded and recursively analyzed
48
+ #
49
+ # @param path [String] path to the cookbook to be analyzed
50
+ # @param recursive [Boolean] whether transitive dependencies should be analyzed
51
+ # @return [Array<Dependency>] analyzed dependency and its transitive dependencies
52
+ def investigate(path, recursive=true)
53
+ raise NotACookbookError, 'Path is not a cookbook' unless File.exists?(File.join(path, 'metadata.rb'))
54
+
55
+ metadata = Ridley::Chef::Cookbook::Metadata.from_file(File.join(path, 'metadata.rb'))
56
+ metadata.dependencies.collect do |name, version|
57
+ analyze_dependency(Dependency.new(name, version), recursive)
58
+ end.flatten
59
+ end
60
+
61
+ # Analyze Chef repo and Repository manager in order to find more information
62
+ # about a given dependency
63
+ #
64
+ # @param dependency [Dependency] dependency to be analyzed
65
+ # @param recursive [Boolean] whether transitive dependencies should be analyzed
66
+ # @return [Array<Dependency>] analyzed dependency and its transitive dependencies
67
+ def analyze_dependency(dependency, recursive)
68
+ chef_info = @chef_inspector.investigate(dependency)
69
+
70
+ # Grab information from the Repository Manager
71
+ info_repo = @repo_inspector.investigate(dependency, chef_info[:version_used], recursive)
72
+ deps = info_repo.collect do |dep, repo_info|
73
+ dep_chef_info = @chef_inspector.investigate(dep)
74
+ update_dependency(dep, dep_chef_info, repo_info)
75
+ dep
76
+ end
77
+ deps
78
+ end
79
+
80
+ # Update in-place a dependency based on information retrieved from
81
+ # Chef Server and Repository Manager
82
+ #
83
+ # @param dependency [Dependency] dependency to be updated
84
+ # @param chef_info [Hash] information from Chef Server
85
+ # @param repo_info [Hash] information from Repository Manager
86
+ def update_dependency(dependency, chef_info, repo_info)
87
+ dependency.status = :up_to_date
88
+
89
+ if !chef_info[:version_used]
90
+ dependency.status = :err_req
91
+ msg = 'No versions found'
92
+ reference_version = @repo_inspector.get_reference_version(nil, repo_info)
93
+ msg << ", using #{reference_version} for recursive analysis" if reference_version
94
+
95
+ dependency.remarks << msg
96
+ else
97
+ relaxed_version = satisfy("~> #{chef_info[:version_used]}", chef_info[:versions])
98
+ if relaxed_version != chef_info[:version_used]
99
+ dependency.status = :warn_req
100
+ changelog_url = @repo_inspector.get_changelog(repo_info,
101
+ chef_info[:version_used],
102
+ relaxed_version)
103
+ dependency.remarks << "#{relaxed_version} is available. #{changelog_url}"
104
+ end
105
+ end
106
+
107
+ # Compare Chef and Repository Manager versions
108
+ comparison = compare_repo_chef(chef_info, repo_info)
109
+ chef_info[:status] = comparison[:chef]
110
+ repo_info[:status] = comparison[:repo]
111
+ dependency.remarks.push(*comparison[:remarks]) if comparison[:remarks]
112
+
113
+ if repo_info[:not_unique]
114
+ repo_info[:status] = :warn_notunique_repo
115
+ dependency.remarks << "Not unique on #{@repo_inspector.manager.type} (this is #{repo_info[:source_url]})"
116
+ end
117
+
118
+ # Check whether latest tag and metadata version in Repository Manager are
119
+ # consistent
120
+ unless @repo_inspector.consistent_version?(repo_info)
121
+ repo_info[:status] = :warn_mismatch_repo
122
+ dependency.remarks << "#{@repo_inspector.manager.type}'s last tag is #{repo_info[:latest_tag]} " \
123
+ "but found #{repo_info[:latest_metadata]} in metadata.rb"
124
+ end
125
+
126
+ dependency.repomanager = repo_info
127
+ dependency.chef = chef_info
128
+ end
129
+
130
+ # Compare Repository Manager and Chef Server
131
+ #
132
+ # @param chef_info [Hash] information from Chef Server
133
+ # @param repo_info [Hash] information from Repository Manager
134
+ # @return [Hash] containing servers statuses and remarks
135
+ def compare_repo_chef(chef_info, repo_info)
136
+ comparison = {:chef => :up_to_date, :repo => :up_to_date,
137
+ :remarks => []}
138
+
139
+ if chef_info[:latest_version] && repo_info[:latest_metadata]
140
+ if chef_info[:latest_version] > repo_info[:latest_metadata]
141
+ comparison[:repo] = :warn_outofdate_repo
142
+ changelog_url = @repo_inspector.get_changelog(repo_info,
143
+ repo_info[:latest_metadata].to_s,
144
+ chef_info[:latest_version].to_s)
145
+ comparison[:remarks] << "#{@repo_inspector.manager.type} out-of-date! #{changelog_url}"
146
+ return comparison
147
+ elsif chef_info[:latest_version] < repo_info[:latest_metadata]
148
+ comparison[:chef] = :warn_chef
149
+ changelog_url = @repo_inspector.get_changelog(repo_info,
150
+ chef_info[:latest_version].to_s,
151
+ repo_info[:latest_metadata].to_s)
152
+ comparison[:remarks] << "A new version might appear on Chef server. #{changelog_url}"
153
+ return comparison
154
+ end
155
+ end
156
+
157
+ unless repo_info[:latest_metadata]
158
+ comparison[:repo] = :err_repo
159
+ comparison[:remarks] << "#{@repo_inspector.manager.type} doesn't contain any versions."
160
+ end
161
+
162
+ unless chef_info[:latest_version]
163
+ comparison[:chef] = :err_chef
164
+ comparison[:remarks] << "Chef Server doesn't contain any versions."
165
+ end
166
+
167
+ comparison
168
+ end
169
+
170
+ # Initialize the Chef Server configuration
171
+ def chef_server(config)
172
+ @chef_inspector = ChefInspector.new config
173
+ end
174
+
175
+ # Initialize the Repository Manager
176
+ def repository_manager(config)
177
+ @repo_inspector = RepositoryInspector.new config
178
+ end
179
+ end
180
+ end
181
+ end