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
@@ -0,0 +1,79 @@
1
+ require_relative 'support/spec_helper'
2
+
3
+ describe GitHubManager do
4
+ let(:manager) do
5
+ config = {:type => "GitHub", :allowed_users => ["astratto"]}
6
+
7
+ manager = GitHubManager.new config
8
+ manager
9
+ end
10
+
11
+ context "API" do
12
+ [:project_dependencies, :tags, :source_url, :projects_by_name,
13
+ :project_metadata, :project_metadata_version].each do |method|
14
+ it "responds to #{method}" do
15
+ expect(manager.respond_to?(method)).to be_true
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "#initialize" do
21
+ context "full configuration" do
22
+ it "creates a valid Manager" do
23
+ config = {:type => "GitHub",
24
+ :token => ENV['GITHUB_TOKEN'],
25
+ :allowed_users => ["astratto"]
26
+ }
27
+
28
+ manager = GitHubManager.new config
29
+ manager
30
+ end
31
+ end
32
+
33
+ context "invalid configuration" do
34
+ it "raise an error when users are not configured" do
35
+ config = {:type => "GitHub",
36
+ :token => ENV['GITHUB_TOKEN']
37
+ }
38
+
39
+ expect{GitHubManager.new(config)}.to raise_error(GitHubManager::GitHubUsersNotConfiguredError)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#projects_by_name" do
45
+ it "returns the correct project for astratto/kitchen-inspector", :type => :external do
46
+ projects = manager.projects_by_name "kitchen-inspector"
47
+ expect(projects).not_to eq(nil)
48
+ end
49
+ end
50
+
51
+ describe "#tags" do
52
+ let(:project) { manager.projects_by_name("kitchen-inspector").first }
53
+
54
+ it "returns the correct tags for astratto/kitchen-inspector", :type => :external do
55
+
56
+ expect(manager.tags(project)["1.0.1"]).to eq("b935719a532c8042b51de560db09881803fbb511")
57
+ end
58
+ end
59
+
60
+ describe "#project_metadata" do
61
+ let(:project) { manager.projects_by_name("cook-test").first }
62
+ it "returns the correct metadata for github.com/astratto/cook-test v.1.0.0", :type => :external do
63
+
64
+ metadata = manager.project_metadata(project, "689dcf42e0cc0710fd337ebd1fee3d2ee8e7dca4")
65
+ expect(metadata.name).to eq("cook-test")
66
+ end
67
+
68
+ it "returns the correct version for github.com/astratto/cook-test v.1.0.0", :type => :external do
69
+ version = manager.project_metadata_version(project, "689dcf42e0cc0710fd337ebd1fee3d2ee8e7dca4")
70
+ expect(version).to eq("1.0.0")
71
+ end
72
+
73
+ it "returns the correct dependencies for github.com/astratto/cook-test v.1.0.0", :type => :external do
74
+ dependencies = manager.project_dependencies(project, "689dcf42e0cc0710fd337ebd1fee3d2ee8e7dca4")
75
+
76
+ expect(dependencies.collect(&:name)).to eq(["openssl", "build-essential"])
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'support/spec_helper'
2
+
3
+ describe GitLabManager do
4
+ describe "API" do
5
+ let(:manager) do
6
+ config = {:base_url => "Test url",
7
+ :token => "token",
8
+ :type => "GitLab"
9
+ }
10
+
11
+ manager = GitLabManager.new config
12
+ manager
13
+ end
14
+
15
+ [:project_dependencies, :tags, :source_url, :projects_by_name,
16
+ :project_metadata, :project_metadata_version].each do |method|
17
+ it "responds to #{method}" do
18
+ expect(manager.respond_to?(method)).to be_true
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "#initialize" do
24
+ context "full configuration" do
25
+ it "creates a valid Manager" do
26
+ config = {:base_url => "Test url",
27
+ :token => "token",
28
+ :type => "GitLab"
29
+ }
30
+
31
+ manager = GitLabManager.new config
32
+ manager
33
+ end
34
+ end
35
+
36
+ context "invalid configuration" do
37
+ it "raises an error when GitLab Token is not configured" do
38
+ config = {:base_url => "Test url",
39
+ :type => "GitLab"
40
+ }
41
+
42
+ expect do
43
+ GitLabManager.new config
44
+ end.to raise_error(GitLabAccessNotConfiguredError)
45
+ end
46
+
47
+ it "raises an error when GitLab Base Url is not configured" do
48
+ config = {:token => "token",
49
+ :type => "GitLab"
50
+ }
51
+
52
+ expect do
53
+ GitLabManager.new config
54
+ end.to raise_error(GitLabAccessNotConfiguredError)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,237 @@
1
+ require_relative 'support/spec_helper'
2
+
3
+ describe Report do
4
+ let(:health_bureau) { generate_health_bureau }
5
+
6
+ let(:chef_info) {
7
+ chef = {:versions => ["1.0.0", "1.0.1"],
8
+ :latest_version => Solve::Version.new("1.0.1"),
9
+ :version_used => "1.0.1"}
10
+ }
11
+
12
+ let(:repomanager_info) {
13
+ repomanager = {:tags => {"1.0.0" => "a", "1.0.1" => "b"},
14
+ :latest_metadata => Solve::Version.new("1.0.1"),
15
+ :latest_tag => Solve::Version.new("1.0.1")}
16
+ }
17
+
18
+ describe ".generate" do
19
+ context "global status" do
20
+ before(:each) do
21
+ dep1 = Dependency.new("Test", "~> 1.0.0")
22
+ health_bureau.update_dependency(dep1, chef_info, repomanager_info)
23
+
24
+ @dependencies = [dep1]
25
+ end
26
+
27
+ it "up_to_date" do
28
+ output, code = Report.generate(@dependencies, 'table', {})
29
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
30
+ "| Test | ~> 1.0.0 | 1.0.1 | 1.0.1 | 1.0.1 | #{TICK_MARK.green} | #{TICK_MARK.green} | #{TICK_MARK.green} |\n" \
31
+ "#{'Status: up_to_date (%s)'.green}" % TICK_MARK
32
+ )
33
+ expect(code).to eq(:up_to_date)
34
+ end
35
+
36
+ it "err_repo" do
37
+ dep1 = @dependencies.first
38
+ repomanager = {:tags => [],
39
+ :latest_metadata => nil,
40
+ :latest_tag => nil}
41
+
42
+ health_bureau.update_dependency(dep1, dep1.chef, repomanager)
43
+
44
+ output, code = Report.generate(@dependencies, 'table', {})
45
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
46
+ "| Test | ~> 1.0.0 | 1.0.1 | 1.0.1 | | #{TICK_MARK.green} | #{TICK_MARK.green} | #{X_MARK.yellow} |\n" \
47
+ "#{'Status: err_repo (%s)'.yellow}" % X_MARK
48
+ )
49
+ expect(code).to eq(:err_repo)
50
+ end
51
+
52
+ it "warn_mismatch_repo" do
53
+ dep1 = @dependencies.first
54
+ repomanager = {:tags => {"1.0.0" => "a"},
55
+ :latest_metadata => Solve::Version.new("1.0.0"),
56
+ :latest_tag => Solve::Version.new("1.0.1")}
57
+ health_bureau.update_dependency(dep1, dep1.chef, repomanager)
58
+
59
+ output, code = Report.generate(@dependencies, 'table', {})
60
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
61
+ "| Test | ~> 1.0.0 | 1.0.1 | 1.0.1 | 1.0.0 | #{TICK_MARK.green} | #{TICK_MARK.green} | #{ESCLAMATION_MARK.bold.light_red} |\n" \
62
+ "#{'Status: warn_mismatch_repo (!)'.light_red}"
63
+ )
64
+ expect(code).to eq(:warn_mismatch_repo)
65
+ end
66
+
67
+ it "warn_outofdate_repo" do
68
+ dep1 = @dependencies.first
69
+ repomanager = {:tags => {"1.0.0" => "a"},
70
+ :latest_metadata => Solve::Version.new("1.0.0"),
71
+ :latest_tag => Solve::Version.new("1.0.0")}
72
+ health_bureau.update_dependency(dep1, dep1.chef, repomanager)
73
+
74
+ output, code = Report.generate(@dependencies, 'table', {})
75
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
76
+ "| Test | ~> 1.0.0 | 1.0.1 | 1.0.1 | 1.0.0 | #{TICK_MARK.green} | #{TICK_MARK.green} | #{(ESCLAMATION_MARK * 2).bold.light_red} |\n" \
77
+ "#{'Status: warn_outofdate_repo (!!)'.light_red}"
78
+ )
79
+ expect(code).to eq(:warn_outofdate_repo)
80
+ end
81
+
82
+ it "warn_notunique_repo" do
83
+ dep1 = @dependencies.first
84
+ repomanager = {:tags => {"1.0.1" => "b"},
85
+ :latest_metadata => Solve::Version.new("1.0.1"),
86
+ :latest_tag => Solve::Version.new("1.0.1"),
87
+ :not_unique => true}
88
+ health_bureau.update_dependency(dep1, dep1.chef, repomanager)
89
+
90
+ output, code = Report.generate(@dependencies, 'table', {})
91
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
92
+ "| Test | ~> 1.0.0 | 1.0.1 | 1.0.1 | 1.0.1 | #{TICK_MARK.green} | #{TICK_MARK.green} | #{QUESTION_MARK.light_red} |\n" \
93
+ "#{'Status: warn_notunique_repo (?)'.light_red}"
94
+ )
95
+ expect(code).to eq(:warn_notunique_repo)
96
+ end
97
+
98
+ it "warn_chef" do
99
+ dep1 = @dependencies.first
100
+ chef = {:versions => ["1.0.0"],
101
+ :latest_version => Solve::Version.new("1.0.0"),
102
+ :version_used => "1.0.0"}
103
+ health_bureau.update_dependency(dep1, chef, dep1.repomanager)
104
+
105
+ output, code = Report.generate(@dependencies, 'table', {})
106
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
107
+ "| Test | ~> 1.0.0 | 1.0.0 | 1.0.0 | 1.0.1 | #{TICK_MARK.green} | #{INFO_MARK.bold.blue} | #{TICK_MARK.green} |\n" \
108
+ "#{'Status: warn_chef (i)'.blue}"
109
+ )
110
+ expect(code).to eq(:warn_chef)
111
+ end
112
+
113
+ it "warn_req" do
114
+ dep1 = Dependency.new("Test", "= 1.0.0")
115
+ chef = {:versions => ["1.0.0", "1.0.1"],
116
+ :latest_version => Solve::Version.new("1.0.1"),
117
+ :version_used => "1.0.0"}
118
+ repomanager = {:tags => {"1.0.0" => "a", "1.0.1" => "b"},
119
+ :latest_metadata => Solve::Version.new("1.0.1"),
120
+ :latest_tag => Solve::Version.new("1.0.1")}
121
+ health_bureau.update_dependency(dep1, chef, repomanager)
122
+
123
+ output, code = Report.generate([dep1], 'table', {})
124
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
125
+ "| Test | = 1.0.0 | 1.0.0 | 1.0.1 | 1.0.1 | #{ESCLAMATION_MARK.bold.yellow} | #{TICK_MARK.green} | #{TICK_MARK.green} |\n" \
126
+ "#{'Status: warn_req (!)'.yellow}"
127
+ )
128
+ expect(code).to eq(:warn_req)
129
+ end
130
+
131
+ it "err due to wrong metadata" do
132
+ dep1 = @dependencies.first
133
+ chef = {:versions => ["1.1.0"],
134
+ :latest_version => Solve::Version.new("1.1.0"),
135
+ :version_used => nil}
136
+ repomanager = {:tags => {"1.1.0" => "c"},
137
+ :latest_metadata => Solve::Version.new("1.1.0"),
138
+ :latest_tag => Solve::Version.new("1.1.0")}
139
+ health_bureau.update_dependency(dep1, chef, repomanager)
140
+
141
+ output, code = Report.generate([dep1], 'table', {})
142
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
143
+ "| #{'Test'.red} | ~> 1.0.0 | | 1.1.0 | 1.1.0 | #{X_MARK.red} | #{TICK_MARK.green} | #{TICK_MARK.green} |\n" \
144
+ "#{'Status: err_req (%s)'.red}" % X_MARK
145
+ )
146
+ expect(code).to eq(:err_req)
147
+ end
148
+
149
+ it "err due to Chef Server" do
150
+ dep1 = @dependencies.first
151
+ chef = {:versions => [],
152
+ :latest_version => nil,
153
+ :version_used => nil}
154
+ health_bureau.update_dependency(dep1, chef, dep1.repomanager)
155
+
156
+ output, code = Report.generate([dep1], 'table', {})
157
+ expect(output.split("\n").grep(/Test|Status:/).join("\n")).to eq( \
158
+ "| #{'Test'.red} | ~> 1.0.0 | | | 1.0.1 | #{X_MARK.red} | #{X_MARK.red} | #{TICK_MARK.green} |\n" \
159
+ "#{'Status: err_req (%s)'.red}" % X_MARK
160
+ )
161
+ expect(code).to eq(:err_req)
162
+ end
163
+
164
+ it "shows remarks" do
165
+ dep1 = @dependencies.first
166
+ chef = {:versions => ["1.1.0"],
167
+ :latest_version => Solve::Version.new("1.1.0"),
168
+ :version_used => nil}
169
+ repomanager = {:tags => {"1.1.0" => "c"},
170
+ :latest_metadata => Solve::Version.new("1.1.0"),
171
+ :latest_tag => Solve::Version.new("1.1.0")}
172
+ health_bureau.update_dependency(dep1, chef, repomanager)
173
+
174
+ output, code = Report.generate([dep1, dep1], 'table', {:remarks => true})
175
+ expect(output).to eq( \
176
+ "+------+-------------+------+--------+------------+-------------+-------------+------------+---------+\n" \
177
+ "| Name | Requirement | Used | Chef | Repository | Requirement | Chef Server | Repository | Remarks |\n" \
178
+ "| | | | Latest | Latest | Status | Status | Status | |\n" \
179
+ "+------+-------------+------+--------+------------+-------------+-------------+------------+---------+\n" \
180
+ "| #{'Test'.red} | ~> 1.0.0 | | 1.1.0 | 1.1.0 | #{X_MARK.red} | #{TICK_MARK.green} | #{TICK_MARK.green} | 1 |\n" \
181
+ "| #{'Test'.red} | ~> 1.0.0 | | 1.1.0 | 1.1.0 | #{X_MARK.red} | #{TICK_MARK.green} | #{TICK_MARK.green} | 2 |\n" \
182
+ "+------+-------------+------+--------+------------+-------------+-------------+------------+---------+\n" \
183
+ "#{'Status: err_req (%s)'.red}\n\n" \
184
+ "Remarks:\n" \
185
+ "[1]: No versions found, using 1.1.0 for recursive analysis\n" \
186
+ "[2]: No versions found, using 1.1.0 for recursive analysis" % X_MARK)
187
+ expect(code).to eq(:err_req)
188
+ end
189
+
190
+ it "shows remarks with changelog" do
191
+ health_bureau.repo_inspector.stub(:get_changelog).and_return(
192
+ "Changelog: test_url.short"
193
+ )
194
+
195
+ dep1 = @dependencies.first
196
+ chef = {:versions => ["1.0.0"],
197
+ :latest_version => Solve::Version.new("1.0.0"),
198
+ :version_used => "1.0.0"}
199
+ health_bureau.update_dependency(dep1, chef, dep1.repomanager)
200
+
201
+ output, code = Report.generate(@dependencies, 'table', {:remarks => true})
202
+ expect(output).to eq( \
203
+ "+------+-------------+-------+--------+------------+-------------+-------------+------------+---------+\n" \
204
+ "| Name | Requirement | Used | Chef | Repository | Requirement | Chef Server | Repository | Remarks |\n" \
205
+ "| | | | Latest | Latest | Status | Status | Status | |\n" \
206
+ "+------+-------------+-------+--------+------------+-------------+-------------+------------+---------+\n" \
207
+ "| Test | ~> 1.0.0 | 1.0.0 | 1.0.0 | 1.0.1 | #{TICK_MARK.green} | #{INFO_MARK.bold.blue} | #{TICK_MARK.green} | 1 |\n" \
208
+ "+------+-------------+-------+--------+------------+-------------+-------------+------------+---------+\n" \
209
+ "#{'Status: warn_chef (i)'.blue}\n\n" \
210
+ "Remarks:\n" \
211
+ "[1]: A new version might appear on Chef server. Changelog: test_url.short")
212
+ expect(code).to eq(:warn_chef)
213
+ end
214
+
215
+ it "shows nested dependencies" do
216
+ dep1 = @dependencies.first
217
+ dep2 = Dependency.new("Nested", "~> 1.0.0")
218
+ dep2.parents << dep1
219
+ dep1.dependencies << dep2
220
+ health_bureau.update_dependency(dep2, chef_info, repomanager_info)
221
+
222
+ output, code = Report.generate([dep1, dep2], 'table', {:remarks => true})
223
+ expect(output).to eq( \
224
+ "+-----------+-------------+-------+--------+------------+-------------+-------------+------------+---------+\n" \
225
+ "| Name | Requirement | Used | Chef | Repository | Requirement | Chef Server | Repository | Remarks |\n" \
226
+ "| | | | Latest | Latest | Status | Status | Status | |\n" \
227
+ "+-----------+-------------+-------+--------+------------+-------------+-------------+------------+---------+\n" \
228
+ "| Test | ~> 1.0.0 | 1.0.1 | 1.0.1 | 1.0.1 | #{TICK_MARK.green} | #{TICK_MARK.green} | #{TICK_MARK.green} | |\n" \
229
+ "| #{INDENT_MARK} Nested | ~> 1.0.0 | 1.0.1 | 1.0.1 | 1.0.1 | #{TICK_MARK.green} | #{TICK_MARK.green} | #{TICK_MARK.green} | |\n" \
230
+ "+-----------+-------------+-------+--------+------------+-------------+-------------+------------+---------+\n" \
231
+ "#{'Status: up_to_date (%s)'.green}\n\n" \
232
+ "Remarks:\n" % TICK_MARK)
233
+ expect(code).to eq(:up_to_date)
234
+ end
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,81 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ require 'kitchen-inspector/inspector'
5
+ require 'kitchen-inspector/inspector/repository_managers/github'
6
+ require 'kitchen-inspector/inspector/repository_managers/gitlab'
7
+
8
+ require 'chef_zero/server'
9
+
10
+ include KitchenInspector::Inspector
11
+
12
+ RSpec.configure do |config|
13
+ config.before(:all) do
14
+ @chef_server = ChefZero::Server.new(port: 4000)
15
+ @chef_server.start_background
16
+ end
17
+
18
+ config.after(:each) do
19
+ @chef_server.clear_data
20
+ end
21
+
22
+ config.after(:all) do
23
+ @chef_server.stop
24
+ end
25
+
26
+ config.expect_with :rspec do |c|
27
+ c.syntax = :expect
28
+ end
29
+ end
30
+
31
+ def generate_health_bureau
32
+ config = StringIO.new
33
+ config.puts "repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'"
34
+ config.puts "chef_server :url => 'http://localhost:4000', :client_pem => '%s', :username => 'test_user'" % "#{File.dirname(__FILE__)}/../data/test_client.pem"
35
+
36
+ inspector = HealthBureau.new config
37
+ inspector
38
+ end
39
+
40
+ RSpec::Matchers.define :exit_with_code do |exp_code|
41
+ actual = nil
42
+ match do |block|
43
+ begin
44
+ block.call
45
+ rescue SystemExit => e
46
+ actual = e.status
47
+ end
48
+ actual and actual == exp_code
49
+ end
50
+ failure_message_for_should do |block|
51
+ "expected block to call exit(#{exp_code}) but exit" +
52
+ (actual.nil? ? " not called" : "(#{actual}) was called")
53
+ end
54
+ failure_message_for_should_not do |block|
55
+ "expected block not to call exit(#{exp_code})"
56
+ end
57
+ description do
58
+ "expect block to call exit(#{exp_code})"
59
+ end
60
+ end
61
+
62
+ ## Define File::NULL for ruby < 1.9.3
63
+ #
64
+ # Shamelessly stolen from backports
65
+ # https://github.com/marcandre/backports/blob/master/lib/backports/1.9.3/file/null.rb
66
+ unless File.const_defined? :NULL
67
+ module File::Constants
68
+ platform = RUBY_PLATFORM
69
+ platform = RbConfig::CONFIG['host_os'] if platform == 'java'
70
+ NULL = case platform
71
+ when /mswin|mingw/i
72
+ 'NUL'
73
+ when /amiga/i
74
+ 'NIL:'
75
+ when /openvms/i
76
+ 'NL:'
77
+ else
78
+ '/dev/null'
79
+ end
80
+ end
81
+ end