dependency_checker 0.2.0 → 1.0.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +42 -18
- data/bin/dependency-checker +64 -15
- data/lib/dependency_checker/forge_helper.rb +64 -41
- data/lib/dependency_checker/metadata_checker.rb +28 -24
- data/lib/dependency_checker/runner.rb +154 -152
- data/lib/dependency_checker/version.rb +5 -0
- data/lib/dependency_checker.rb +2 -0
- metadata +34 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a912b3208a333f3f4ab015a010f20792216e86dc0c510138f68eb7a0a0130d7e
|
4
|
+
data.tar.gz: bab5dd61e4b3eecbd0f1b0b5b56e15f2210a9e66c4d9dced5f337417b203281e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 985c43c4a59ad41082caa48c6bf221b130f33a33ea398669d70ceb9e8b4fd2fc1d61d3f84d8a23be91297d067bb028ea1511862625201181656a76cbfcb4172e
|
7
|
+
data.tar.gz: ac10b8572dfcede807454d7d6a89fcff83f5718f2c150ef5fedc47c7fd56712a12fec72442180ca8d434c7be7725c4ff686bd0bb351d1b1d9a5c86d9fdbeb1fa
|
data/README.md
CHANGED
@@ -1,52 +1,74 @@
|
|
1
1
|
# dependency-checker
|
2
2
|
|
3
|
-
The dependency-checker tool validates dependencies in
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
dependency-checker is compatible with Ruby versions 2.0.0 and newer.
|
3
|
+
The dependency-checker tool validates dependencies in Puppet modules against the
|
4
|
+
latest published versions on the [Puppet Forge](https://forge.puppet.com/). This
|
5
|
+
means that it will ensure that a module supports the latest version of all the
|
6
|
+
dependencies it declares.
|
8
7
|
|
9
8
|
## Installation
|
10
9
|
|
11
|
-
via
|
10
|
+
Install via RubyGems:
|
12
11
|
|
13
|
-
|
12
|
+
$ gem install dependency_checker
|
14
13
|
|
15
|
-
|
14
|
+
Or add it to your `Gemfile`:
|
16
15
|
|
17
|
-
|
16
|
+
gem 'dependency_checker'
|
18
17
|
|
19
18
|
## Usage
|
20
19
|
|
21
|
-
Run against a single Puppet module metadata.json file
|
20
|
+
Run against a single Puppet module `metadata.json` file to ensure that the module
|
21
|
+
supports the current versions of all the dependencies it declares:
|
22
22
|
|
23
23
|
$ dependency-checker /path/to/metadata.json
|
24
24
|
|
25
|
-
|
25
|
+
Run against a whole list of modules to ensure that each module supports the current
|
26
|
+
version of the dependencies it declares. You can use a YAML or JSON file containing
|
27
|
+
an array of modules (`namespace-module`). The file can be local or remote:
|
26
28
|
|
27
29
|
$ dependency-checker managed_modules.yaml
|
30
|
+
$ dependency-checker https://my.webserver.com/path/to/managed_modules.json
|
31
|
+
|
32
|
+
Run against many modules on your filesystem with a path wildcard:
|
33
|
+
|
34
|
+
$ dependency-checker modules/*/metadata.json
|
28
35
|
|
29
|
-
|
36
|
+
Run against all modules in an author's Forge namespace, optionally filtering to
|
37
|
+
only supported/approved/partner endorsements:
|
30
38
|
|
31
|
-
$ dependency-checker
|
39
|
+
$ dependency-checker --namespace puppetlabs
|
40
|
+
$ dependency-checker --namespace puppetlabs --supported
|
41
|
+
$ dependency-checker --namespace puppet --approved
|
32
42
|
|
33
|
-
|
43
|
+
Run it inside a module or group of modules during a pre-release to determine the
|
44
|
+
effect of version bumps in the `metadata.json` file(s):
|
34
45
|
|
46
|
+
$ dependency-checker -c
|
35
47
|
$ dependency-checker -c ../*/metadata.json
|
36
48
|
|
37
|
-
Or you can supply an override value
|
49
|
+
Or you can supply an override value directly:
|
38
50
|
|
39
51
|
$ dependency-checker ../*/metadata.json -o puppetlabs/stdlib,10.0.0
|
40
52
|
|
53
|
+
The tool defaults to validating all modules supported by the Puppet IAC team if
|
54
|
+
no module specification arguments are provided.
|
55
|
+
|
41
56
|
The following optional parameters are available:
|
42
|
-
|
57
|
+
|
58
|
+
```text
|
59
|
+
Usage: dependency-checker [options]
|
43
60
|
-o, --override module,version Forge name of module and semantic version to override
|
44
61
|
-c, --current Extract override version from metadata.json inside current working directory
|
62
|
+
-n, --namespace namespace Check all modules in a given namespace (filter with endorsements).
|
63
|
+
--endorsement endorsement Filter a namespace search by endorsement (supported/approved/partner).
|
64
|
+
--es, --supported Shorthand for `--endorsement supported`
|
65
|
+
--ea, --approved Shorthand for `--endorsement approved`
|
66
|
+
--ep, --partner Shorthand for `--endorsement partner`
|
45
67
|
-v, --[no-]verbose Run verbosely
|
46
68
|
-h, --help Display help
|
47
69
|
```
|
48
70
|
|
49
|
-
|
71
|
+
The `-o` and `-c` arguments are exclusive, as are the endorsement filtering options.
|
50
72
|
|
51
73
|
### Testing with dependency-checker as a Rake task
|
52
74
|
|
@@ -58,6 +80,8 @@ require 'dependency_checker'
|
|
58
80
|
desc 'Run dependency-checker'
|
59
81
|
task :metadata_deps do
|
60
82
|
files = FileList['modules/*/metadata.json']
|
61
|
-
DependencyChecker::Runner.
|
83
|
+
runner = DependencyChecker::Runner.new
|
84
|
+
runner.resolve_from_files(files)
|
85
|
+
runner.run
|
62
86
|
end
|
63
87
|
```
|
data/bin/dependency-checker
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'optparse'
|
4
5
|
require 'dependency_checker'
|
5
6
|
require 'json'
|
6
7
|
|
7
8
|
options = {}
|
8
|
-
OptionParser.new
|
9
|
+
OptionParser.new do |opts|
|
9
10
|
opts.on('-o module,version', '--override module,version', Array, 'Forge name of module and semantic version to override') do |override|
|
10
11
|
options[:override] = override
|
11
12
|
end
|
@@ -14,27 +15,56 @@ OptionParser.new { |opts|
|
|
14
15
|
options[:current_override] = current_override
|
15
16
|
end
|
16
17
|
|
17
|
-
opts.on('-
|
18
|
-
options[:
|
18
|
+
opts.on('-n', '--namespace namespace', 'Check all modules in a given namespace (filter with endorsements).') do |namespace|
|
19
|
+
options[:namespace] = namespace
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on('--endorsement endorsement', 'Filter a namespace search by endorsement (supported/approved/partner).') do |endorsement|
|
23
|
+
raise 'You may only filter by one endorsement at a time' if options[:endorsement]
|
24
|
+
|
25
|
+
options[:endorsement] = endorsement
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on('--es', '--supported', 'Shorthand for `--endorsement supported`') do
|
29
|
+
raise 'You may only filter by one endorsement at a time' if options[:endorsement]
|
30
|
+
|
31
|
+
options[:endorsement] = 'supported'
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on('--ea', '--approved', 'Shorthand for `--endorsement approved`') do
|
35
|
+
raise 'You may only filter by one endorsement at a time' if options[:endorsement]
|
36
|
+
|
37
|
+
options[:endorsement] = 'approved'
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on('--ep', '--partner', 'Shorthand for `--endorsement partner`') do
|
41
|
+
raise 'You may only filter by one endorsement at a time' if options[:endorsement]
|
42
|
+
|
43
|
+
options[:endorsement] = 'partner'
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on('--ft forge_token', '--forge-token forge_token', 'The API token to authenticate the Forge connection with') do |forge_token|
|
47
|
+
options[:forge_token] = forge_token
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on('--fh forge_hostname', '--forge-hostname forge_hostname', 'Specify a specific Forge hostname to overwrite the default of https://forgeapi.puppet.com') do |forge_hostname|
|
51
|
+
raise 'Forge host must be specified in the format https://your-own-api.url/' unless forge_hostname.start_with? 'http'
|
52
|
+
|
53
|
+
options[:forge_hostname] = forge_hostname
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on('-v', '--[no-]verbose', 'Run verbosely') do
|
57
|
+
options[:verbose] = true
|
19
58
|
end
|
20
59
|
|
21
60
|
opts.on('-h', '--help', 'Display help') do
|
22
61
|
puts opts
|
23
62
|
exit
|
24
63
|
end
|
25
|
-
|
26
|
-
|
27
|
-
# Determine which modules to pass on to runner
|
28
|
-
managed_modules = nil
|
29
|
-
unless ARGV.empty?
|
30
|
-
# If length == 1, only pass first argument, else pass the array of metadata.json files
|
31
|
-
managed_modules = ((ARGV.length == 1) ? ARGV[0] : ARGV)
|
32
|
-
end
|
64
|
+
end.parse!
|
33
65
|
|
34
66
|
# Raise error if both :override and :current_override are specified
|
35
|
-
if options[:override] && options[:current_override]
|
36
|
-
raise OptionParser::InvalidOption, 'You can not select both override and current override options'
|
37
|
-
end
|
67
|
+
raise OptionParser::InvalidOption, 'You can not select both override and current override options' if options[:override] && options[:current_override]
|
38
68
|
|
39
69
|
# If :current_override is specified, retrieve name and version of module in current working directory
|
40
70
|
if options[:current_override]
|
@@ -50,4 +80,23 @@ end
|
|
50
80
|
# Default :verbose to false
|
51
81
|
options[:verbose] ||= false
|
52
82
|
|
53
|
-
DependencyChecker::Runner.
|
83
|
+
runner = DependencyChecker::Runner.new(options[:verbose], options[:forge_hostname], options[:forge_token])
|
84
|
+
|
85
|
+
if options[:namespace]
|
86
|
+
runner.resolve_from_namespace(options[:namespace], options[:endorsement])
|
87
|
+
|
88
|
+
elsif ARGV.empty?
|
89
|
+
puts "No module criteria specified. Defaulting to IAC supported modules.\n\n"
|
90
|
+
runner.resolve_from_path('https://puppetlabs.github.io/iac/modules.json')
|
91
|
+
|
92
|
+
elsif ARGV.map { |arg| File.basename arg } != ['metadata.json']
|
93
|
+
runner.resolve_from_path(ARGV.first)
|
94
|
+
|
95
|
+
else
|
96
|
+
runner.resolve_from_files(ARGV)
|
97
|
+
end
|
98
|
+
|
99
|
+
runner.override = options[:override]
|
100
|
+
runner.run
|
101
|
+
|
102
|
+
exit(runner.problems.zero? ? 0 : 1)
|
@@ -1,58 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puppet_forge'
|
2
4
|
require 'semantic_puppet'
|
3
5
|
|
4
6
|
# Helper class for fetching data from the Forge and perform some basic operations
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
module DependencyChecker
|
8
|
+
class ForgeHelper
|
9
|
+
def initialize(cache = {}, forge_hostname = nil, forge_token = nil)
|
10
|
+
@cache = cache
|
11
|
+
PuppetForge.host = forge_hostname unless forge_hostname.nil?
|
12
|
+
PuppetForge::Connection.authorization = forge_token unless forge_token.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
# Retrieve current version of module
|
16
|
+
# @return [SemanticPuppet::Version]
|
17
|
+
def get_current_version(module_name)
|
18
|
+
module_name = module_name.sub('/', '-')
|
19
|
+
version = nil
|
20
|
+
version = get_version(@cache[module_name]) if @cache.key?(module_name)
|
9
21
|
|
10
|
-
|
11
|
-
# @return [SemanticPuppet::Version]
|
12
|
-
def get_current_version(module_name)
|
13
|
-
module_name = module_name.sub('/', '-')
|
14
|
-
version = nil
|
15
|
-
version = get_version(@cache[module_name]) if @cache.key?(module_name)
|
22
|
+
version = get_version(get_module_data(module_name)) if !version && check_module_exists(module_name)
|
16
23
|
|
17
|
-
|
18
|
-
version = get_version(get_module_data(module_name)) if check_module_exists(module_name)
|
24
|
+
version
|
19
25
|
end
|
20
26
|
|
21
|
-
|
22
|
-
|
27
|
+
# Retrieve module data from Forge
|
28
|
+
# @return [Hash] Hash containing JSON response from Forge
|
29
|
+
def get_module_data(module_name)
|
30
|
+
module_name = module_name.sub('/', '-')
|
31
|
+
module_data = @cache[module_name]
|
32
|
+
begin
|
33
|
+
@cache[module_name] = module_data = PuppetForge::Module.find(module_name) unless module_data
|
34
|
+
rescue Faraday::ClientError
|
35
|
+
return nil
|
36
|
+
end
|
23
37
|
|
24
|
-
|
25
|
-
# @return [Hash] Hash containing JSON response from Forge
|
26
|
-
def get_module_data(module_name)
|
27
|
-
module_name = module_name.sub('/', '-')
|
28
|
-
module_data = @cache[module_name]
|
29
|
-
begin
|
30
|
-
@cache[module_name] = module_data = PuppetForge::Module.find(module_name) unless module_data
|
31
|
-
rescue Faraday::ClientError
|
32
|
-
return nil
|
38
|
+
module_data
|
33
39
|
end
|
34
40
|
|
35
|
-
|
36
|
-
|
41
|
+
# Retrieve module from Forge
|
42
|
+
# @return [PuppetForge::Module]
|
43
|
+
def check_module_exists(module_name)
|
44
|
+
!get_module_data(module_name).nil?
|
45
|
+
end
|
37
46
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
47
|
+
# Check if a module is deprecated from data fetched from the Forge
|
48
|
+
# @return [Boolean] boolean result stating whether module is deprecated
|
49
|
+
def check_module_deprecated(module_name)
|
50
|
+
module_name = module_name.sub('/', '-')
|
51
|
+
module_data = get_module_data(module_name)
|
52
|
+
version = get_current_version(module_name)
|
53
|
+
version.to_s.eql?('999.999.999') || version.to_s.eql?('99.99.99') || !module_data.attribute('deprecated_at').nil?
|
54
|
+
end
|
43
55
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
56
|
+
# Gets a list of all modules in a namespace, optionally filtered by endorsement.
|
57
|
+
# @param [String] namespace The namespace to search
|
58
|
+
# @param [String] endorsement to filter by (supported/approved/partner)
|
59
|
+
# @return [Array] list of modules
|
60
|
+
def modules_in_namespace(namespace, endorsement = nil)
|
61
|
+
modules = PuppetForge::Module.where(
|
62
|
+
owner: namespace, # rubocop:disable Layout/FirstArgumentIndentation
|
63
|
+
hide_deprecated: true,
|
64
|
+
module_groups: 'base pe_only',
|
65
|
+
endorsements: endorsement
|
66
|
+
)
|
52
67
|
|
53
|
-
|
68
|
+
raise "No modules found for #{namespace}." if modules.total.zero?
|
69
|
+
|
70
|
+
modules.unpaginated.map(&:slug)
|
71
|
+
end
|
54
72
|
|
55
|
-
|
56
|
-
|
73
|
+
private
|
74
|
+
|
75
|
+
def get_version(module_data)
|
76
|
+
return SemanticPuppet::Version.parse('999.999.999') unless module_data.current_release
|
77
|
+
|
78
|
+
SemanticPuppet::Version.parse(module_data.current_release.version)
|
79
|
+
end
|
57
80
|
end
|
58
81
|
end
|
@@ -1,35 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'semantic_puppet'
|
2
4
|
|
3
5
|
# Checks dependencies of passed in metadata and performs checks to verify constraints
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
module DependencyChecker
|
7
|
+
class MetadataChecker
|
8
|
+
def initialize(metadata, forge, updated_module, updated_module_version)
|
9
|
+
@metadata = metadata
|
10
|
+
@forge = forge
|
11
|
+
@updated_module = updated_module.sub('-', '/') if updated_module
|
12
|
+
@updated_module_version = updated_module_version if updated_module_version
|
13
|
+
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
# Perform constraint comparisons of dependencies based on their latest version, and also
|
16
|
+
# override any occurance of @updated_module with @updated_module_version
|
17
|
+
# @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
|
18
|
+
def check_dependencies
|
19
|
+
fetch_module_dependencies.map do |dependency, constraint|
|
20
|
+
dependency = dependency.sub('-', '/')
|
21
|
+
current = dependency == @updated_module ? SemanticPuppet::Version.parse(@updated_module_version) : @forge.get_current_version(dependency)
|
22
|
+
[dependency, constraint, current, constraint.include?(current)]
|
23
|
+
end
|
20
24
|
end
|
21
|
-
end
|
22
25
|
|
23
|
-
|
26
|
+
private
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
# Retrieve dependencies from @metedata
|
29
|
+
# @return [Map] a map with the name of the dependency and its constraint
|
30
|
+
def fetch_module_dependencies
|
31
|
+
return [] unless @metadata[:dependencies]
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
@metadata[:dependencies].map do |dep|
|
34
|
+
constraint = dep[:version_requirement] || '>= 0'
|
35
|
+
[dep[:name], SemanticPuppet::VersionRange.parse(constraint)]
|
36
|
+
end
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -1,197 +1,199 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'yaml'
|
3
|
-
require '
|
4
|
-
require 'uri'
|
5
|
+
require 'open-uri'
|
5
6
|
require 'logger'
|
6
7
|
require 'parallel'
|
7
8
|
|
8
9
|
# Main runner for DependencyChecker
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@override = !override.nil?
|
13
|
-
@updated_module = override[0] if @override
|
14
|
-
@updated_module_version = override[1] if @override
|
15
|
-
@verbose = verbose
|
16
|
-
@forge = DependencyChecker::ForgeHelper.new
|
17
|
-
end
|
18
|
-
|
19
|
-
def run
|
20
|
-
validate_override if @override
|
10
|
+
module DependencyChecker
|
11
|
+
class Runner
|
12
|
+
attr_reader :problems
|
21
13
|
|
22
|
-
|
14
|
+
def initialize(verbose = false, forge_hostname = nil, forge_token = nil)
|
15
|
+
@forge = DependencyChecker::ForgeHelper.new({}, forge_hostname, forge_token)
|
16
|
+
@verbose = verbose
|
17
|
+
end
|
23
18
|
|
24
|
-
|
25
|
-
|
19
|
+
def resolve_from_namespace(namespace, endorsement)
|
20
|
+
@modules = @forge.modules_in_namespace(namespace, endorsement)
|
21
|
+
end
|
26
22
|
|
27
|
-
|
28
|
-
|
23
|
+
def resolve_from_path(path)
|
24
|
+
@modules = return_modules(path)
|
25
|
+
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@managed_modules_arg = 'https://gist.githubusercontent.com/eimlav/6df50eda0b1c57c1ab8c33b64c82c336/raw/managed_modules.yaml'
|
27
|
+
def resolve_from_files(metadata_files)
|
28
|
+
@use_local_files = true
|
29
|
+
@modules = Array(metadata_files) # should already be an array, but just in case
|
34
30
|
end
|
35
31
|
|
36
|
-
|
32
|
+
def override=(override)
|
33
|
+
return unless override.is_a? Array
|
37
34
|
|
38
|
-
|
35
|
+
@updated_module, @updated_module_version = override
|
39
36
|
|
40
|
-
|
41
|
-
|
42
|
-
|
37
|
+
raise '*Error:* Pass an override in the form `--override module,version`' unless override.size == 2
|
38
|
+
raise "*Error:* Could not find *#{@updated_module}* on Puppet Forge! Ensure updated_module argument is valid." unless check_module_exists(@updated_module)
|
39
|
+
unless SemanticPuppet::Version.valid?(@updated_module_version)
|
40
|
+
raise "*Error:* Verify semantic versioning syntax *#{@updated_module_version}* of updated_module_version argument."
|
41
|
+
end
|
43
42
|
|
44
|
-
|
45
|
-
|
43
|
+
puts "Overriding *#{@updated_module}* version with *#{@updated_module_version}*\n\n"
|
44
|
+
puts "The module you are comparing against *#{@updated_module}* is *deprecated*.\n\n" if @forge.check_module_deprecated(@updated_module)
|
45
|
+
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
raise "*Error:* Could not find *#{@updated_module}* on Puppet Forge! Ensure updated_module argument is valid." unless check_module_exists(@updated_module)
|
50
|
-
raise "*Error:* Verify semantic versioning syntax *#{@updated_module_version}* of updated_module_version argument." unless SemanticPuppet::Version.valid?(@updated_module_version)
|
51
|
-
end
|
47
|
+
def run
|
48
|
+
puts "_*Starting dependency checks...*_\n\n"
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
@forge.check_module_exists(module_name)
|
58
|
-
end
|
50
|
+
# Post results of dependency checks
|
51
|
+
message = run_dependency_checks
|
52
|
+
@problems = message.size
|
53
|
+
message = 'All modules have valid dependencies.' if message.empty?
|
59
54
|
|
60
|
-
|
61
|
-
|
62
|
-
# Cross reference dependencies from managed_modules file with @updated_module and @updated_module_version
|
63
|
-
messages = Parallel.map(@modules) do |module_path|
|
64
|
-
module_name = @use_local_files ? get_name_from_metadata(module_path) : module_path
|
65
|
-
mod_message = "Checking *#{module_path}* dependencies.\n"
|
66
|
-
exists_on_forge = true
|
67
|
-
|
68
|
-
# Check module_path is valid
|
69
|
-
unless check_module_exists(module_name)
|
70
|
-
if @use_local_files
|
71
|
-
exists_on_forge = false
|
72
|
-
else
|
73
|
-
mod_message += "\t*Error:* Could not find *#{module_name}* on Puppet Forge! Ensure the module exists.\n\n"
|
74
|
-
next mod_message
|
75
|
-
end
|
76
|
-
end
|
55
|
+
post(message)
|
56
|
+
end
|
77
57
|
|
78
|
-
|
58
|
+
# Check with forge if a specified module exists
|
59
|
+
# @param module_name [String]
|
60
|
+
# @return [Boolean] boolean based on whether the module exists or not
|
61
|
+
def check_module_exists(module_name)
|
62
|
+
@forge.check_module_exists(module_name)
|
63
|
+
end
|
79
64
|
|
80
|
-
|
65
|
+
# Perform dependency checks on modules supplied by @modules
|
66
|
+
def run_dependency_checks
|
67
|
+
# Cross reference dependencies from managed_modules file with @updated_module and @updated_module_version
|
68
|
+
messages = Parallel.map(@modules) do |module_path|
|
69
|
+
module_name = @use_local_files ? get_name_from_metadata(module_path) : module_path
|
70
|
+
mod_message = "Checking *#{module_path}* dependencies.\n"
|
71
|
+
exists_on_forge = true
|
72
|
+
|
73
|
+
# Check module_path is valid
|
74
|
+
unless check_module_exists(module_name)
|
75
|
+
if @use_local_files
|
76
|
+
exists_on_forge = false
|
77
|
+
else
|
78
|
+
mod_message += "\t*Error:* Could not find *#{module_name}* on Puppet Forge! Ensure the module exists.\n\n"
|
79
|
+
next mod_message
|
80
|
+
end
|
81
|
+
end
|
81
82
|
|
82
|
-
|
83
|
-
mod_deprecated = exists_on_forge ? @forge.check_module_deprecated(module_name) : false
|
84
|
-
mod_message += "\t*Warning:* *#{module_name}* is *deprecated*.\n" if mod_deprecated
|
83
|
+
# Fetch module dependencies
|
85
84
|
|
86
|
-
|
87
|
-
mod_message += "\tNo dependencies listed\n\n"
|
88
|
-
next mod_message if @verbose && !mod_deprecated
|
89
|
-
end
|
85
|
+
dependencies = @use_local_files ? get_dependencies_from_path(module_path) : get_dependencies(module_name)
|
90
86
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
mod_message += "\t#{dependency} (#{constraint}) *doesn't match* #{current}\n"
|
87
|
+
# Post warning if module_path is deprecated
|
88
|
+
mod_deprecated = exists_on_forge ? @forge.check_module_deprecated(module_name) : false
|
89
|
+
mod_message += "\t*Warning:* *#{module_name}* is *deprecated*.\n" if mod_deprecated
|
90
|
+
|
91
|
+
if dependencies.empty?
|
92
|
+
mod_message += "\tNo dependencies listed\n\n"
|
93
|
+
next mod_message if @verbose && !mod_deprecated
|
99
94
|
end
|
100
95
|
|
101
|
-
if
|
102
|
-
|
103
|
-
|
96
|
+
# Check each dependency to see if the latest version matchs the current modules' dependency constraints
|
97
|
+
all_match = true
|
98
|
+
dependencies.each do |dependency, constraint, current, satisfied|
|
99
|
+
if satisfied && @verbose
|
100
|
+
mod_message += "\t#{dependency} (#{constraint}) *matches* #{current}\n"
|
101
|
+
elsif !satisfied
|
102
|
+
all_match = false
|
103
|
+
mod_message += "\t#{dependency} (#{constraint}) *doesn't match* #{current}\n"
|
104
|
+
end
|
105
|
+
|
106
|
+
if @forge.check_module_deprecated(dependency)
|
107
|
+
all_match = false
|
108
|
+
mod_message += "\t\t*Warning:* *#{dependency}* is *deprecated*.\n"
|
109
|
+
end
|
110
|
+
|
111
|
+
found_deprecation = true if @forge.check_module_deprecated(dependency)
|
112
|
+
|
113
|
+
# Post warning if dependency is deprecated
|
114
|
+
mod_message += "\tThe dependency module *#{dependency}* is *deprecated*.\n" if found_deprecation
|
104
115
|
end
|
105
116
|
|
106
|
-
|
117
|
+
mod_message += "\tAll dependencies match\n" if all_match
|
118
|
+
mod_message += "\n"
|
107
119
|
|
108
|
-
#
|
109
|
-
|
120
|
+
# If @verbose is true, always post message
|
121
|
+
# If @verbose is false, only post if all dependencies don't match and/or if a dependency is deprecated
|
122
|
+
all_match && !@verbose ? '' : mod_message
|
110
123
|
end
|
111
124
|
|
112
|
-
|
113
|
-
|
125
|
+
message = ''
|
126
|
+
messages.each do |result|
|
127
|
+
message += result
|
128
|
+
end
|
114
129
|
|
115
|
-
|
116
|
-
# If @verbose is false, only post if all dependencies don't match and/or if a dependency is deprecated
|
117
|
-
(all_match && !@verbose) ? '' : mod_message
|
130
|
+
message
|
118
131
|
end
|
119
132
|
|
120
|
-
|
121
|
-
|
122
|
-
|
133
|
+
# Get dependencies of a supplied module name to verify if the depedencies are satisfied
|
134
|
+
# @param module_name [String] name of module
|
135
|
+
# @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
|
136
|
+
def get_dependencies(module_name)
|
137
|
+
module_data = @forge.get_module_data(module_name)
|
138
|
+
metadata = module_data.current_release.metadata
|
139
|
+
get_dependencies_from_metadata(metadata)
|
123
140
|
end
|
124
141
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
def get_dependencies(module_name)
|
133
|
-
module_data = @forge.get_module_data(module_name)
|
134
|
-
|
135
|
-
metadata = module_data.current_release.metadata
|
136
|
-
checker = DependencyChecker::MetadataChecker.new(metadata, @forge, @updated_module, @updated_module_version)
|
137
|
-
checker.check_dependencies
|
138
|
-
end
|
139
|
-
|
140
|
-
# Get dependencies of a supplied module from a metadata.json file to verify if the depedencies are satisfied
|
141
|
-
# @param module_name [String]
|
142
|
-
# @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
|
143
|
-
def get_dependencies_from_metadata(metadata_path)
|
144
|
-
metadata = JSON.parse(File.read(metadata_path), symbolize_names: true)
|
145
|
-
checker = DependencyChecker::MetadataChecker.new(metadata, @forge, @updated_module, @updated_module_version)
|
146
|
-
checker.check_dependencies
|
147
|
-
end
|
148
|
-
|
149
|
-
# Get dependencies of a supplied module from a metadata.json file to verify if the depedencies are satisfied
|
150
|
-
# @param module_name [String]
|
151
|
-
# @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
|
152
|
-
def get_name_from_metadata(metadata_path)
|
153
|
-
metadata = JSON.parse(File.read(metadata_path), symbolize_names: true)
|
154
|
-
metadata[:name]
|
155
|
-
end
|
142
|
+
# Get dependencies of a supplied module from a metadata.json file to verify if the depedencies are satisfied
|
143
|
+
# @param metadata_path [String] path to metadata.json
|
144
|
+
# @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
|
145
|
+
def get_dependencies_from_path(metadata_path)
|
146
|
+
metadata = JSON.parse(File.read(metadata_path), symbolize_names: true)
|
147
|
+
get_dependencies_from_metadata(metadata)
|
148
|
+
end
|
156
149
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
begin
|
164
|
-
if managed_modules_path =~ URI::DEFAULT_PARSER.make_regexp
|
165
|
-
managed_modules = Net::HTTP.get(URI.parse(managed_modules_path))
|
166
|
-
elsif File.file?(managed_modules_path)
|
167
|
-
managed_modules = File.read(managed_modules_path)
|
168
|
-
else
|
169
|
-
raise 'Error'
|
170
|
-
end
|
171
|
-
rescue StandardError
|
172
|
-
raise "*Error:* Ensure *#{managed_modules_path}* is a valid file path or URL"
|
150
|
+
# Get dependencies of supplied module metadata. Takes module ovveride into account.
|
151
|
+
# @param metadata [Hash] module metadata
|
152
|
+
# @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
|
153
|
+
def get_dependencies_from_metadata(metadata)
|
154
|
+
checker = DependencyChecker::MetadataChecker.new(metadata, @forge, @updated_module, @updated_module_version)
|
155
|
+
checker.check_dependencies
|
173
156
|
end
|
174
157
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
158
|
+
# Get dependencies of a supplied module from a metadata.json file to verify if the depedencies are satisfied
|
159
|
+
# @param metadata_path [String] path to metadata.json
|
160
|
+
# @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
|
161
|
+
def get_name_from_metadata(metadata_path)
|
162
|
+
metadata = JSON.parse(File.read(metadata_path), symbolize_names: true)
|
163
|
+
metadata[:name]
|
179
164
|
end
|
180
165
|
|
181
|
-
|
182
|
-
|
166
|
+
# Retrieve the array of module names from the supplied filename/URL
|
167
|
+
# @return [Array] an array of module names
|
168
|
+
def return_modules(path)
|
169
|
+
begin
|
170
|
+
# We use URI#open because it can handle file or URI paths.
|
171
|
+
# This usage does not expose a security risk
|
172
|
+
contents = URI.open(path).read # rubocop:disable Security/Open
|
173
|
+
rescue Errno::ENOENT, SocketError
|
174
|
+
raise "*Error:* Ensure *#{path}* is a valid file path or URL"
|
175
|
+
end
|
183
176
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
177
|
+
begin
|
178
|
+
modules = if path.end_with? '.json'
|
179
|
+
JSON.parse(contents)
|
180
|
+
else
|
181
|
+
YAML.safe_load(contents)
|
182
|
+
end
|
183
|
+
rescue StandardError
|
184
|
+
raise "*Error:* Ensure syntax of #{path} file is valid YAML or JSON"
|
185
|
+
end
|
189
186
|
|
190
|
-
|
191
|
-
|
192
|
-
|
187
|
+
# transform from IAC supported module hash to simple list
|
188
|
+
modules = modules.filter_map { |_key, val| val['puppet_module'] } if modules.is_a? Hash
|
189
|
+
|
190
|
+
modules
|
191
|
+
end
|
193
192
|
|
194
|
-
|
195
|
-
|
193
|
+
# Post message to terminal
|
194
|
+
# @param message [String]
|
195
|
+
def post(message)
|
196
|
+
puts message
|
197
|
+
end
|
196
198
|
end
|
197
199
|
end
|
data/lib/dependency_checker.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependency_checker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ewoud Kohl van Wijngaarden
|
@@ -9,94 +9,73 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-04-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: parallel
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - "
|
25
|
+
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: puppet_forge
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '2.2'
|
35
|
+
- - "<"
|
33
36
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
37
|
+
version: '4.0'
|
35
38
|
type: :runtime
|
36
39
|
prerelease: false
|
37
40
|
version_requirements: !ruby/object:Gem::Requirement
|
38
41
|
requirements:
|
39
|
-
- - "
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '2.2'
|
45
|
+
- - "<"
|
40
46
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
47
|
+
version: '4.0'
|
42
48
|
- !ruby/object:Gem::Dependency
|
43
|
-
name:
|
49
|
+
name: rake
|
44
50
|
requirement: !ruby/object:Gem::Requirement
|
45
51
|
requirements:
|
46
52
|
- - "~>"
|
47
53
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
54
|
+
version: '13.0'
|
49
55
|
type: :runtime
|
50
56
|
prerelease: false
|
51
57
|
version_requirements: !ruby/object:Gem::Requirement
|
52
58
|
requirements:
|
53
59
|
- - "~>"
|
54
60
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
61
|
+
version: '13.0'
|
56
62
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
63
|
+
name: semantic_puppet
|
58
64
|
requirement: !ruby/object:Gem::Requirement
|
59
65
|
requirements:
|
60
|
-
- - "
|
66
|
+
- - "~>"
|
61
67
|
- !ruby/object:Gem::Version
|
62
|
-
version: '0'
|
68
|
+
version: '1.0'
|
63
69
|
type: :runtime
|
64
70
|
prerelease: false
|
65
71
|
version_requirements: !ruby/object:Gem::Requirement
|
66
72
|
requirements:
|
67
|
-
- - "
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: rspec
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '0'
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
name: rubocop
|
86
|
-
requirement: !ruby/object:Gem::Requirement
|
87
|
-
requirements:
|
88
|
-
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: '0'
|
91
|
-
type: :development
|
92
|
-
prerelease: false
|
93
|
-
version_requirements: !ruby/object:Gem::Requirement
|
94
|
-
requirements:
|
95
|
-
- - ">="
|
73
|
+
- - "~>"
|
96
74
|
- !ruby/object:Gem::Version
|
97
|
-
version: '0'
|
98
|
-
description:
|
99
|
-
|
75
|
+
version: '1.0'
|
76
|
+
description: |2
|
77
|
+
Verify all your dependencies allow the latest versions on Puppet Forge.
|
78
|
+
Based on https://github.com/ekohl/metadata_json_deps
|
100
79
|
email:
|
101
80
|
- info@puppet.com
|
102
81
|
executables:
|
@@ -111,6 +90,7 @@ files:
|
|
111
90
|
- lib/dependency_checker/forge_helper.rb
|
112
91
|
- lib/dependency_checker/metadata_checker.rb
|
113
92
|
- lib/dependency_checker/runner.rb
|
93
|
+
- lib/dependency_checker/version.rb
|
114
94
|
homepage: https://github.com/puppetlabs/dependency_checker
|
115
95
|
licenses:
|
116
96
|
- MIT
|
@@ -124,15 +104,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
124
104
|
requirements:
|
125
105
|
- - ">="
|
126
106
|
- !ruby/object:Gem::Version
|
127
|
-
version: 2.
|
107
|
+
version: 2.7.0
|
128
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
109
|
requirements:
|
130
|
-
- - "
|
110
|
+
- - ">"
|
131
111
|
- !ruby/object:Gem::Version
|
132
|
-
version:
|
112
|
+
version: 1.3.1
|
133
113
|
requirements: []
|
134
|
-
|
135
|
-
rubygems_version: 2.7.7
|
114
|
+
rubygems_version: 3.1.6
|
136
115
|
signing_key:
|
137
116
|
specification_version: 4
|
138
117
|
summary: Check your Puppet metadata dependencies
|