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,110 @@
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
+ module BaseManager
29
+ include Utils
30
+
31
+ attr_reader :type
32
+
33
+ def initialize
34
+ # Cache metadata and tags to reduce calls against the Repository Manager
35
+ @metadata_cache = {}
36
+ @tags_cache = {}
37
+ @changelogs_cache = {}
38
+ @type = "BaseManager"
39
+ end
40
+
41
+ # Return the full URL for a given project
42
+ def source_url(project)
43
+ raise NotImplementedError
44
+ end
45
+
46
+ # Retrieve projects by name
47
+ def projects_by_name(name)
48
+ raise NotImplementedError
49
+ end
50
+
51
+ # Retrieve project's metadata
52
+ def retrieve_metadata(project)
53
+ raise NotImplementedError
54
+ end
55
+
56
+ # Given a project return its tags
57
+ def retrieve_tags(project)
58
+ raise NotImplementedError
59
+ end
60
+
61
+ # Given a project and a revision retrieve its dependencies from metadata.rb
62
+ def project_dependencies(project, revId)
63
+ return nil unless project && revId
64
+
65
+ metadata = project_metadata(project, revId)
66
+
67
+ if metadata
68
+ metadata.dependencies.collect{|dep, constraint| Dependency.new(dep, constraint)}
69
+ end
70
+ end
71
+
72
+ # Given a project and a revision retrieve its metadata's version
73
+ def project_metadata_version(project, revId)
74
+ return nil unless project && revId
75
+
76
+ metadata = project_metadata(project, revId)
77
+
78
+ if metadata
79
+ fix_version_name(metadata.version)
80
+ end
81
+ end
82
+
83
+ # Given a project and a revision retrieve its metadata
84
+ def project_metadata(project, revId)
85
+ cache_key = "#{project.id}-#{revId}"
86
+ @metadata_cache[cache_key] ||=
87
+ begin
88
+ retrieve_metadata(project, revId)
89
+ end
90
+ end
91
+
92
+ # Given a project return the tags on the Repository Manager
93
+ def tags(project)
94
+ cache_key = project.id
95
+ @tags_cache[cache_key] ||= retrieve_tags(project)
96
+ end
97
+
98
+ # Return a shortened url to the commits between two revisions
99
+ def changelog(project_url, revId, otherRevId)
100
+ return unless project_url && revId && otherRevId
101
+ cache_key = "#{project_url}-#{revId}-otherRevId"
102
+
103
+ @changelogs_cache[cache_key] ||=
104
+ begin
105
+ Googl.shorten("#{project_url}/compare/#{revId}...#{otherRevId}").short_url.gsub(/^http:\/\//, '')
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,97 @@
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
+ begin
26
+ require 'octokit'
27
+ rescue LoadError
28
+ raise KitchenInspector::Inspector::RepositoryManagerError,
29
+ "GitHub support requires 'octokit'. Please install it with 'gem install octokit'."
30
+ end
31
+
32
+ module KitchenInspector
33
+ module Inspector
34
+ class GitHubManager
35
+ include BaseManager
36
+
37
+ class GitHubUsersNotConfiguredError < StandardError; end
38
+
39
+ def initialize(config)
40
+ super()
41
+ raise GitHubUsersNotConfiguredError, config_msg("GitHub allowed users", "allowed_users") unless config[:allowed_users]
42
+
43
+ @type = "GitHub"
44
+ @allowed_users = config[:allowed_users]
45
+ @projects_cache = {}
46
+
47
+ Octokit.configure do |c|
48
+ c.access_token = config[:token]
49
+ c.auto_paginate = true
50
+ end
51
+ end
52
+
53
+ # Given a project and a revision retrieve its metadata
54
+ def retrieve_metadata(project, revId)
55
+ response = Octokit.contents(project.full_name,
56
+ {:ref => revId, :path => "metadata.rb" })
57
+
58
+ if response && response.respond_to?(:content)
59
+ eval_metadata Base64.decode64(response.content)
60
+ else
61
+ nil
62
+ end
63
+ end
64
+
65
+ # Return the full URL for a given project
66
+ def source_url(project)
67
+ "github.com/#{project.full_name}"
68
+ end
69
+
70
+ # Retrieve projects by name
71
+ # Filter by allowed users
72
+ def projects_by_name(name, opts={})
73
+ @projects_cache[name] ||= begin
74
+ user_query = @allowed_users.collect{|user| "user:#{user}"}.join(' ')
75
+ repos = Octokit.search_repos "#{name} in:name language:ruby #{user_query}"
76
+ repos = repos.items.select do |repo|
77
+ repo.name == name
78
+ end
79
+ repos
80
+ end
81
+ end
82
+
83
+ # Given a project return the tags on GitHub
84
+ def retrieve_tags(project)
85
+ tags = {}
86
+ Octokit.tags(project.full_name).collect do |tag|
87
+ tags[fix_version_name(tag.name)] = tag.commit.sha
88
+ end
89
+ tags
90
+ end
91
+
92
+ def to_s
93
+ "#{@type} instance"
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,100 @@
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
+ begin
26
+ require 'gitlab'
27
+ rescue LoadError
28
+ raise KitchenInspector::Inspector::RepositoryManagerError,
29
+ "GitLab support requires 'gitlab'. Please install it with 'gem install gitlab'."
30
+ end
31
+
32
+ module KitchenInspector
33
+ module Inspector
34
+ class GitLabAccessNotConfiguredError < StandardError; end
35
+
36
+ class GitLabManager
37
+ include BaseManager
38
+
39
+ REPO_PER_PAGE = 1000
40
+
41
+ def initialize(config)
42
+ super()
43
+
44
+ raise GitLabAccessNotConfiguredError, config_msg("GitLab base url", "base_url") unless config[:base_url]
45
+ raise GitLabAccessNotConfiguredError, config_msg("GitLab Private Token", "token") unless config[:token]
46
+
47
+ @type = "GitLab"
48
+ @gitlab_token = config[:token]
49
+ @gitlab_base_url = config[:base_url]
50
+ @gitlab_api_url = "#{@gitlab_base_url}/api/v3"
51
+
52
+ Gitlab.configure do |gitlab|
53
+ gitlab.endpoint = @gitlab_api_url
54
+ gitlab.private_token = @gitlab_token
55
+ gitlab.user_agent = 'Kitchen Inspector'
56
+ end
57
+ end
58
+
59
+ # Return the full URL for a given project
60
+ def source_url(project)
61
+ "#{@gitlab_base_url}/#{project.path_with_namespace}"
62
+ end
63
+
64
+ # Retrieve projects by name
65
+ def projects_by_name(name)
66
+ projects.select{|prj| prj.path == name }
67
+ end
68
+
69
+ # Given a project and a revision retrieve its metadata
70
+ def retrieve_metadata(project, revId)
71
+ response = HTTParty.get("#{Gitlab.endpoint}/projects/#{project.id}/repository/blobs/#{revId}?filepath=metadata.rb",
72
+ headers: {"PRIVATE-TOKEN" => Gitlab.private_token})
73
+
74
+ if response.code == 200
75
+ eval_metadata response.body
76
+ else
77
+ nil
78
+ end
79
+ end
80
+
81
+ # Given a project return the tags on GitLab
82
+ def retrieve_tags(project)
83
+ tags = {}
84
+ Gitlab.tags(project.id).collect do |tag|
85
+ tags[fix_version_name(tag.name)] = tag.commit.id
86
+ end
87
+ tags
88
+ end
89
+
90
+ def to_s
91
+ "#{@type} instance: #{@gitlab_base_url}"
92
+ end
93
+
94
+ private
95
+ def projects
96
+ @projects ||= Gitlab.projects(:per_page => REPO_PER_PAGE)
97
+ end
98
+ end
99
+ end
100
+ end
@@ -24,7 +24,6 @@
24
24
  #
25
25
  module KitchenInspector
26
26
  module Inspector
27
- # The version string
28
- VERSION = '1.0.1'
27
+ VERSION = '1.1.0'
29
28
  end
30
29
  end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,46 @@
1
+ require_relative 'support/spec_helper'
2
+
3
+ describe Cli do
4
+ before(:all) do
5
+ # Disable stdout and stderr
6
+ @original_stderr = $stderr
7
+ @original_stdout = $stdout
8
+
9
+ # Redirect stderr and stdout
10
+ $stderr = File.open(File::NULL, 'w')
11
+ $stdout = File.open(File::NULL, 'w')
12
+ end
13
+
14
+ after(:all) do
15
+ $stderr = @original_stderr
16
+ $stdout = @original_stdout
17
+ end
18
+
19
+ describe ".investigate" do
20
+ let(:cli) { Cli.new }
21
+
22
+ it "raises a warning for cookbook without dependencies" do
23
+ cli.options = { :config => File.new("#{File.dirname(__FILE__)}/data/test_config_valid.rb", 'r') }
24
+
25
+ expect do
26
+ cli.investigate("#{File.dirname(__FILE__)}/data/cookbook_no_deps")
27
+ end.to exit_with_code(STATUS_TO_RETURN_CODES[:'warning-nodependencies'])
28
+ end
29
+
30
+ it "raises an error for missing configuration" do
31
+ cli.options = { :config => 'notexisting.rb' }
32
+
33
+ expect do
34
+ cli.investigate
35
+ end.to exit_with_code(STATUS_TO_RETURN_CODES[:'error-config'])
36
+ end
37
+
38
+ it "raises an error for missing cookbook" do
39
+ cli.options = { :config => File.new("#{File.dirname(__FILE__)}/data/test_config_valid.rb", 'r') }
40
+
41
+ expect do
42
+ cli.investigate
43
+ end.to exit_with_code(STATUS_TO_RETURN_CODES[:'error-notacookbook'])
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,10 @@
1
+ name 'cookbook-deps'
2
+ maintainer 'YOUR_NAME'
3
+ maintainer_email 'YOUR_EMAIL'
4
+ license 'All rights reserved'
5
+ description 'Installs/Configures cookbook-no-deps'
6
+ long_description 'Test cookbook with dependencies'
7
+ version '0.1.0'
8
+
9
+ depends 'test', '~> 1.0.0'
10
+ depends 'dep1', '~> 1.0.0'
@@ -0,0 +1,7 @@
1
+ name 'cookbook-no-deps'
2
+ maintainer 'YOUR_NAME'
3
+ maintainer_email 'YOUR_EMAIL'
4
+ license 'All rights reserved'
5
+ description 'Installs/Configures cookbook-no-deps'
6
+ long_description 'Test cookbook without dependencies'
7
+ version '0.1.0'
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEowIBAAKCAQELxLCL+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7
+ GzjTlL/klBMJeIZWDKSN+VOcNcpFrOgN5tkdLwIDAQABAoIBAA781AWjLbcfYqeG
8
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
9
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13
+ 7fA8h7ECgYEA7zAiEYZvzLkLtW+VoKzVoGsFzdSLSG5mj81mTL0z1WxKKkSLm7Ly
14
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15
+ Z4fhXGLbZ0icHuWeLWjH1AyVrbu4bLZOMLeL90A70m2HtMIP0t0vbqkCgYEA0gvm
16
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
17
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
18
+ gnzuk7x3jRIdsagPgRp0OaQ12HTm2wJV135cTBcCgYBdHDem6taKv9P+VTnCGoXu
19
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
20
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
21
+ XXXXXXXXXXXXXXX/6KqWQQKBgGQGaI09c8Sn/XXXXXXXXXXXXXXXXXXXXXXXXXXX
22
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
23
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
24
+ 8KYHAoGBAI6piP8115Muj2esVLX2faavvzZbMQlaX3EG0fAjyl6gHAb9q64XXpMV
25
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
26
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'
2
+ chef_server_url 'http://localhost:4000'
3
+ chef_client_pem 'testclient.pem'
4
+ chef_username 'test_user'
@@ -0,0 +1,4 @@
1
+ repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'
2
+ chef_server_url 'http://localhost:4000'
3
+ chef_client_pem 'testclient.pem'
4
+ chef_username 'test_user'
@@ -0,0 +1,296 @@
1
+ require_relative 'support/spec_helper'
2
+
3
+ describe HealthBureau do
4
+ let(:health_bureau) { generate_health_bureau }
5
+
6
+ let(:repomanager_info) do
7
+ {:tags =>{"1.0.0" => "a", "1.0.1" => "b"},
8
+ :latest_metadata => Solve::Version.new("1.0.1"),
9
+ :latest_tag => Solve::Version.new("1.0.1")}
10
+ end
11
+
12
+ let(:chef_info) do
13
+ {:latest_version => Solve::Version.new("1.0.1"),
14
+ :version_used => "1.0.1",
15
+ :versions => ["1.0.0", "1.0.1"]}
16
+ end
17
+
18
+ describe "#initialize" do
19
+ context "Repository Manager" do
20
+ it "raises an error if an unsupported Repository Manager is specified" do
21
+ config = StringIO.new
22
+ config.puts "repository_manager :type => 'Unknown', :base_url => 'http://localhost:8080', :token =>'test_token'"
23
+ config.puts "chef_server :url => 'http://localhost:4000', :client_pem => 'testclient.pem', :username => 'test_user'"
24
+
25
+ expect do
26
+ HealthBureau.new config
27
+ end.to raise_error(RepositoryManagerError)
28
+ end
29
+
30
+ it "raises an error if an unsupported field is specified" do
31
+ config = StringIO.new
32
+ config.puts "repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'"
33
+ config.puts "chef_server :url => 'http://localhost:4000', :client_pem => 'testclient.pem', :username => 'test_user'"
34
+ config.puts "invalid_field 'test'"
35
+
36
+ expect do
37
+ HealthBureau.new config
38
+ end.to raise_error(ConfigurationError)
39
+ end
40
+
41
+ context "GitLab" do
42
+ context "with a full configuration" do
43
+ it "creates a valid Inspector" do
44
+ config = StringIO.new
45
+ config.puts "repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'"
46
+ config.puts "chef_server :url => 'http://localhost:4000', :client_pem => 'testclient.pem', :username => 'test_user'"
47
+
48
+ inspector = HealthBureau.new config
49
+ inspector
50
+ end
51
+ end
52
+
53
+ context "with invalid configuration" do
54
+ it "raises an error when GitLab Token is not configured" do
55
+ config = StringIO.new
56
+ config.puts "repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080'"
57
+ config.puts "chef_server :url => 'http://localhost:4000', :client_pem => 'testclient.pem', :username => 'test_user'"
58
+
59
+ expect do
60
+ HealthBureau.new config
61
+ end.to raise_error(GitLabAccessNotConfiguredError)
62
+ end
63
+
64
+ it "raises an error when GitLab Base Url is not configured" do
65
+ config = StringIO.new
66
+ config.puts "repository_manager :type => 'GitLab', :token =>'test_token'"
67
+ config.puts "chef_server :url => 'http://localhost:4000', :client_pem => 'testclient.pem', :username => 'test_user'"
68
+
69
+ expect do
70
+ HealthBureau.new config
71
+ end.to raise_error(GitLabAccessNotConfiguredError)
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ context "Chef Server" do
78
+ it "raises an error when Server Url is not configured" do
79
+ config = StringIO.new
80
+ config.puts "repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'"
81
+ config.puts "chef_server :client_pem => 'testclient.pem', :username => 'test_user'"
82
+
83
+ expect do
84
+ HealthBureau.new config
85
+ end.to raise_error(ChefAccessNotConfiguredError)
86
+ end
87
+
88
+ it "raises an error when Client PEM is not configured" do
89
+ config = StringIO.new
90
+ config.puts "repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'"
91
+ config.puts "chef_server :url => 'http://localhost:4000', :username => 'test_user'"
92
+
93
+ expect do
94
+ HealthBureau.new config
95
+ end.to raise_error(ChefAccessNotConfiguredError)
96
+ end
97
+
98
+ it "raises an error when Username is not configured" do
99
+ config = StringIO.new
100
+ config.puts "repository_manager :type => 'GitLab', :base_url => 'http://localhost:8080', :token =>'test_token'"
101
+ config.puts "chef_server :url => 'http://localhost:4000', :client_pem => 'testclient.pem'"
102
+
103
+ expect do
104
+ HealthBureau.new config
105
+ end.to raise_error(ChefAccessNotConfiguredError)
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#update_dependency" do
111
+ before(:each) do
112
+ @dep = Dependency.new("test", ">= 0")
113
+ end
114
+
115
+ it "returns a success for correct versions on both servers" do
116
+ health_bureau.update_dependency(@dep, chef_info, repomanager_info)
117
+ expect(@dep.repomanager[:status]).to eq(:up_to_date)
118
+ expect(@dep.chef[:status]).to eq(:up_to_date)
119
+ expect(@dep.status).to eq(:up_to_date)
120
+ end
121
+
122
+ context "error statuses" do
123
+ it "when a valid version cannot be found" do
124
+ chef = {:version_used => nil}
125
+
126
+ health_bureau.update_dependency(@dep, chef, repomanager_info)
127
+ expect(@dep.status).to eq(:err_req)
128
+ end
129
+
130
+ it "missing version on Chef Server" do
131
+ chef = {:versions => [],
132
+ :latest_version => nil}
133
+
134
+ health_bureau.update_dependency(@dep, chef, repomanager_info)
135
+ expect(@dep.chef[:status]).to eq(:err_chef)
136
+ end
137
+
138
+ it "missing version on the Repository Manager" do
139
+ repomanager = {:tags =>[],
140
+ :latest_metadata => nil}
141
+
142
+
143
+ health_bureau.update_dependency(@dep, chef_info, repomanager)
144
+ expect(@dep.repomanager[:status]).to eq(:err_repo)
145
+ end
146
+ end
147
+
148
+ context "warning statuses" do
149
+ it "a newer version could be used" do
150
+ chef_info[:version_used] = "1.0.0"
151
+
152
+ health_bureau.update_dependency(@dep, chef_info, repomanager_info)
153
+ expect(@dep.status).to eq(:warn_req)
154
+ end
155
+
156
+ it "a newer version exists on the Repository Manager" do
157
+ chef_info = {:versions => ["1.0.0"],
158
+ :latest_version => Solve::Version.new("1.0.0")}
159
+
160
+ health_bureau.update_dependency(@dep, chef_info, repomanager_info)
161
+ expect(@dep.chef[:status]).to eq(:warn_chef)
162
+ end
163
+
164
+ it "a newer version exists on Chef Server" do
165
+ repomanager_info = {:tags => {"1.0.0" => "a"},
166
+ :latest_metadata => Solve::Version.new("1.0.0"),
167
+ :latest_tag => Solve::Version.new("1.0.0")}
168
+
169
+ health_bureau.update_dependency(@dep, chef_info, repomanager_info)
170
+ expect(@dep.repomanager[:status]).to eq(:warn_outofdate_repo)
171
+ end
172
+
173
+ it "last tag on Repository Manager doesn't match last metadata's version" do
174
+ repomanager = {:tags =>{"1.0.0" => "a", "1.0.1" => "b"},
175
+ :latest_metadata => Solve::Version.new("1.0.0"),
176
+ :latest_tag => Solve::Version.new("1.0.1")}
177
+
178
+ health_bureau.update_dependency(@dep, chef_info, repomanager)
179
+ expect(@dep.repomanager[:status]).to eq(:warn_mismatch_repo)
180
+ end
181
+
182
+ it "warns when project is not unique on Repository Manager" do
183
+ repomanager = {:tags =>{"1.0.0" => "a", "1.0.1" => "b"},
184
+ :latest_metadata => Solve::Version.new("1.0.1"),
185
+ :latest_tag => Solve::Version.new("1.0.1"),
186
+ :not_unique => true
187
+ }
188
+
189
+ health_bureau.update_dependency(@dep, chef_info, repomanager)
190
+ expect(@dep.repomanager[:status]).to eq(:warn_notunique_repo)
191
+ end
192
+ end
193
+ end
194
+
195
+ describe "#satisfy" do
196
+ it "returns the correct version when existing" do
197
+ version = health_bureau.satisfy("~> 1.0.1", ["1.0.0", "1.0.1"])
198
+ expect(version).to eq("1.0.1")
199
+ end
200
+
201
+ it "returns nil when a satisfying version doesn't exist" do
202
+ version = health_bureau.satisfy("~> 1.0.1", ["1.0.0"])
203
+ expect(version).to eq(nil)
204
+ end
205
+ end
206
+
207
+ describe "#find_versions" do
208
+ it "retrieves versions using a valid project" do
209
+ data = {"cookbooks" =>
210
+ {
211
+ "test-1.0.1" => {"metadata.rb" => "depends \"mysql\""}
212
+ }
213
+ }
214
+ @chef_server.load_data data
215
+
216
+ versions = health_bureau.chef_inspector.find_versions('test')
217
+ expect(versions).to eq(["1.0.1"])
218
+ end
219
+
220
+ it "doesn't retrieve any versions using a missing project" do
221
+ versions = health_bureau.chef_inspector.find_versions('test')
222
+ expect(versions).to eq([])
223
+ end
224
+ end
225
+
226
+ describe "#investigate" do
227
+ before(:each) do
228
+ GitLabManager.any_instance.stub(:projects_by_name).and_return([])
229
+
230
+ data = {"cookbooks" =>
231
+ {
232
+ "test-1.0.1" => {"metadata.rb" => "depends \"dep1 ~> 1.0.0\""},
233
+ "dep1-1.0.0" => {"metadata.rb" => "depends \"dep2 ~> 1.0.0\""},
234
+ "dep2-1.0.0" => {"metadata.rb" => ""},
235
+ }
236
+ }
237
+ @chef_server.load_data data
238
+ end
239
+
240
+ context "dependencies on Chef Server but not on Repository Manager" do
241
+ it "doesn't fail" do
242
+ dependencies = health_bureau.investigate("#{File.dirname(__FILE__)}/data/cookbook_deps")
243
+ expect(dependencies.count).to eq(2)
244
+ expect(dependencies.first.repomanager).not_to be_nil
245
+ end
246
+
247
+ it "sets correct remarks" do
248
+ dependencies = health_bureau.investigate("#{File.dirname(__FILE__)}/data/cookbook_deps")
249
+ expect(dependencies.first.remarks).to eq(["GitLab doesn't contain any versions."])
250
+ end
251
+
252
+ it "sets correct chef info" do
253
+ dependencies = health_bureau.investigate("#{File.dirname(__FILE__)}/data/cookbook_deps")
254
+ dep1 = dependencies.first
255
+
256
+ expect(dep1.chef).not_to be_empty
257
+ expect(dep1.chef[:versions]).to eq(["1.0.1"])
258
+ expect(dep1.chef[:latest_version]).to eq(Solve::Version.new("1.0.1"))
259
+ expect(dep1.chef[:version_used]).to eq("1.0.1")
260
+ end
261
+ end
262
+
263
+ context "dependencies on Repository Manager" do
264
+ before(:each) do
265
+ project = double()
266
+
267
+ allow(project).to receive(:id).and_return(1)
268
+ allow(project).to receive(:path_with_namespace).and_return("group/project")
269
+
270
+ GitLabManager.any_instance.stub(:projects_by_name).and_return([
271
+ project
272
+ ])
273
+
274
+ GitLabManager.any_instance.stub(:tags).with(project).and_return(
275
+ { "1.0.1" => "fake_sha1" }
276
+ )
277
+
278
+ GitLabManager.any_instance.stub(:project_metadata_version).with(project, "fake_sha1").and_return(
279
+ "1.0.1"
280
+ )
281
+ end
282
+
283
+ it "sets correct repomanager info without recursing" do
284
+ dependencies = health_bureau.investigate("#{File.dirname(__FILE__)}/data/cookbook_deps", recursive=false)
285
+ dep1 = dependencies.first
286
+
287
+ expect(dependencies.count).to eq(2)
288
+ expect(dep1.repomanager).not_to be_nil
289
+ expect(dep1.repomanager[:tags]).to eq({"1.0.1"=>"fake_sha1"})
290
+ expect(dep1.repomanager[:latest_metadata]).to eq(Solve::Version.new("1.0.1"))
291
+ expect(dep1.repomanager[:latest_tag]).to eq(Solve::Version.new("1.0.1"))
292
+ expect(dep1.repomanager[:source_url]).to eq("http://localhost:8080/group/project")
293
+ end
294
+ end
295
+ end
296
+ end