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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +24 -0
- data/Gemfile +0 -2
- data/README.md +268 -39
- data/Rakefile +41 -0
- data/kitchen-inspector.gemspec +21 -3
- data/lib/kitchen-inspector/inspector.rb +11 -4
- data/lib/kitchen-inspector/inspector/chef_inspector.rb +66 -0
- data/lib/kitchen-inspector/inspector/cli.rb +29 -3
- data/lib/kitchen-inspector/inspector/{error.rb → common.rb} +43 -1
- data/lib/kitchen-inspector/inspector/dependency.rb +26 -40
- data/lib/kitchen-inspector/inspector/health_bureau.rb +181 -0
- data/lib/kitchen-inspector/inspector/mixin/utils.rb +83 -0
- data/lib/kitchen-inspector/inspector/report/report.rb +182 -0
- data/lib/kitchen-inspector/inspector/report/status_reporter.rb +105 -0
- data/lib/kitchen-inspector/inspector/repository_inspector.rb +134 -0
- data/lib/kitchen-inspector/inspector/repository_managers/base.rb +110 -0
- data/lib/kitchen-inspector/inspector/repository_managers/github.rb +97 -0
- data/lib/kitchen-inspector/inspector/repository_managers/gitlab.rb +100 -0
- data/lib/kitchen-inspector/inspector/version.rb +1 -2
- data/spec/cli_spec.rb +46 -0
- data/spec/data/cookbook_deps/metadata.rb +10 -0
- data/spec/data/cookbook_no_deps/metadata.rb +7 -0
- data/spec/data/test_client.pem +27 -0
- data/spec/data/test_config_invalid.rb +4 -0
- data/spec/data/test_config_valid.rb +4 -0
- data/spec/dependency_inspector_spec.rb +296 -0
- data/spec/github_manager_spec.rb +79 -0
- data/spec/gitlab_manager_spec.rb +58 -0
- data/spec/report_spec.rb +237 -0
- data/spec/support/spec_helper.rb +81 -0
- data/spec/utils_spec.rb +29 -0
- metadata +129 -15
- data/INFO.md +0 -44
- data/info.css +0 -31
- data/lib/kitchen-inspector/inspector/dependency_inspector.rb +0 -153
- 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
|
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,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,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
|