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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e51ad69dd9620d0bdf8edc59856b9c1ca489eb1cc259c03b7e230ad8e38bdaa
4
- data.tar.gz: ca995ece8099855978f71fecb2b80e930528e62ad6790bce650fc75fe8bf2889
3
+ metadata.gz: a912b3208a333f3f4ab015a010f20792216e86dc0c510138f68eb7a0a0130d7e
4
+ data.tar.gz: bab5dd61e4b3eecbd0f1b0b5b56e15f2210a9e66c4d9dced5f337417b203281e
5
5
  SHA512:
6
- metadata.gz: 9d447cba1d6b93e9faff062534241b79df938d9ea520076e1adcaf25cb7d4295e68cc7cc8ce10593a06854a3b7c64073b819380d82bd8b55d85eef290b930518
7
- data.tar.gz: f364be7088d1a4ad70895cc13df206d2b5eef11eb6a32582d8d747c23f3c6bc80a92a4f4b39b5d3cf0cbab767e64304f60da86af04246c397097d310ed65aba7
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 `metadata.json` files in Puppet modules or YAML files containing arrays of Puppet modules against the latest published versions on the [Puppet Forge](https://forge.puppet.com/).
4
-
5
- ## Compatibility
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 `gem` command:
10
+ Install via RubyGems:
12
11
 
13
- `gem install metadata_json_deps`
12
+ $ gem install dependency_checker
14
13
 
15
- via Gemfile:
14
+ Or add it to your `Gemfile`:
16
15
 
17
- `gem 'metadata_json_deps`
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
- You can use a local/remote YAML file containing an array of modules (using syntax `namespace/module`)
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
- It can also be run verbosely to show valid dependencies:
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 -v modules/*/metadata.json
39
+ $ dependency-checker --namespace puppetlabs
40
+ $ dependency-checker --namespace puppetlabs --supported
41
+ $ dependency-checker --namespace puppet --approved
32
42
 
33
- You can also run it inside a module during a pre-release to determine the effect of a version bump in the metadata.json:
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
- If attempting to use both `-o` and `-c`, an error will be thrown as these can only be used exclusively.
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.run(files)
83
+ runner = DependencyChecker::Runner.new
84
+ runner.resolve_from_files(files)
85
+ runner.run
62
86
  end
63
87
  ```
@@ -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 { |opts|
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('-v', '--[no-]verbose', 'Run verbosely') do |verbose|
18
- options[:verbose] = verbose
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
- }.parse!
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.run_with_args(managed_modules, options[:override], options[:verbose])
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
- class DependencyChecker::ForgeHelper
6
- def initialize(cache = {})
7
- @cache = cache
8
- end
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
- # Retrieve current version of module
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
- unless version
18
- version = get_version(get_module_data(module_name)) if check_module_exists(module_name)
24
+ version
19
25
  end
20
26
 
21
- version
22
- end
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
- # Retrieve module data from Forge
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
- module_data
36
- end
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
- # Retrieve module from Forge
39
- # @return [PuppetForge::Module]
40
- def check_module_exists(module_name)
41
- !get_module_data(module_name).nil?
42
- end
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
- # Check if a module is deprecated from data fetched from the Forge
45
- # @return [Boolean] boolean result stating whether module is deprecated
46
- def check_module_deprecated(module_name)
47
- module_name = module_name.sub('/', '-')
48
- module_data = get_module_data(module_name)
49
- version = get_current_version(module_name)
50
- version.to_s.eql?('999.999.999') || version.to_s.eql?('99.99.99') || !module_data.attribute('deprecated_at').nil?
51
- end
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
- private
68
+ raise "No modules found for #{namespace}." if modules.total.zero?
69
+
70
+ modules.unpaginated.map(&:slug)
71
+ end
54
72
 
55
- def get_version(module_data)
56
- SemanticPuppet::Version.parse(module_data.current_release.version)
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
- class DependencyChecker::MetadataChecker
5
- def initialize(metadata, forge, updated_module, updated_module_version)
6
- @metadata = metadata
7
- @forge = forge
8
- @updated_module = updated_module.sub('-', '/') if updated_module
9
- @updated_module_version = updated_module_version if updated_module_version
10
- end
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
- # Perform constraint comparisons of dependencies based on their latest version, and also
13
- # override any occurance of @updated_module with @updated_module_version
14
- # @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
15
- def check_dependencies
16
- fetch_module_dependencies.map do |dependency, constraint|
17
- dependency = dependency.sub('-', '/')
18
- current = (dependency == @updated_module) ? SemanticPuppet::Version.parse(@updated_module_version) : @forge.get_current_version(dependency)
19
- [dependency, constraint, current, constraint.include?(current)]
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
- private
26
+ private
24
27
 
25
- # Retrieve dependencies from @metedata
26
- # @return [Map] a map with the name of the dependency and its constraint
27
- def fetch_module_dependencies
28
- return [] unless @metadata[:dependencies]
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
- @metadata[:dependencies].map do |dep|
31
- constraint = dep[:version_requirement] || '>= 0'
32
- [dep[:name], SemanticPuppet::VersionRange.parse(constraint)]
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 'net/http'
4
- require 'uri'
5
+ require 'open-uri'
5
6
  require 'logger'
6
7
  require 'parallel'
7
8
 
8
9
  # Main runner for DependencyChecker
9
- class DependencyChecker::Runner
10
- def initialize(managed_modules_arg, override, verbose)
11
- @managed_modules_arg = managed_modules_arg
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
- message = "_*Starting dependency checks...*_\n\n"
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
- # If override is enabled
25
- message += "Overriding *#{@updated_module}* version with *#{@updated_module_version}*\n\n" if @override
19
+ def resolve_from_namespace(namespace, endorsement)
20
+ @modules = @forge.modules_in_namespace(namespace, endorsement)
21
+ end
26
22
 
27
- # Post warning if @updated_module is deprecated
28
- message += "The module you are comparing against *#{@updated_module}* is *deprecated*.\n\n" if @override && @forge.check_module_deprecated(@updated_module)
23
+ def resolve_from_path(path)
24
+ @modules = return_modules(path)
25
+ end
29
26
 
30
- # Post message if using default managed_modules
31
- if @managed_modules_arg.nil?
32
- message += "No local path(s) to metadata.json or file argument specified. Defaulting to Puppet supported modules.\n\n"
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
- @use_local_files = @managed_modules_arg.instance_of?(Array) || @managed_modules_arg.end_with?('.json')
32
+ def override=(override)
33
+ return unless override.is_a? Array
37
34
 
38
- @modules = @use_local_files ? Array(@managed_modules_arg) : return_modules(@managed_modules_arg)
35
+ @updated_module, @updated_module_version = override
39
36
 
40
- # Post results of dependency checks
41
- message += run_dependency_checks
42
- message += 'All modules have valid dependencies.' if run_dependency_checks.empty?
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
- post(message)
45
- end
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
- # Validate override from runner and return an error if any issues are encountered
48
- def validate_override
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
- # Check with forge if a specified module exists
54
- # @param module_name [String]
55
- # @return [Boolean] boolean based on whether the module exists or not
56
- def check_module_exists(module_name)
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
- # Perform dependency checks on modules supplied by @modules
61
- def run_dependency_checks
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
- # Fetch module dependencies
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
- dependencies = @use_local_files ? get_dependencies_from_metadata(module_path) : get_dependencies(module_name)
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
- # Post warning if module_path is deprecated
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
- if dependencies.empty?
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
- # Check each dependency to see if the latest version matchs the current modules' dependency constraints
92
- all_match = true
93
- dependencies.each do |dependency, constraint, current, satisfied|
94
- if satisfied && @verbose
95
- mod_message += "\t#{dependency} (#{constraint}) *matches* #{current}\n"
96
- elsif !satisfied
97
- all_match = false
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 @forge.check_module_deprecated(dependency)
102
- all_match = false
103
- mod_message += "\t\t*Warning:* *#{dependency}* is *deprecated*.\n"
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
- found_deprecation = true if @forge.check_module_deprecated(dependency)
117
+ mod_message += "\tAll dependencies match\n" if all_match
118
+ mod_message += "\n"
107
119
 
108
- # Post warning if dependency is deprecated
109
- mod_message += "\tThe dependency module *#{dependency}* is *deprecated*.\n" if found_deprecation
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
- mod_message += "\tAll dependencies match\n" if all_match
113
- mod_message += "\n"
125
+ message = ''
126
+ messages.each do |result|
127
+ message += result
128
+ end
114
129
 
115
- # If @verbose is true, always post message
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
- message = ''
121
- messages.each do |result|
122
- message += result
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
- message
126
- end
127
-
128
- # Get dependencies of a supplied module and use the override values from @updated_module and @updated_module_version
129
- # to verify if the depedencies are satisfied
130
- # @param module_name [String]
131
- # @return [Map] a map of dependencies along with their constraint, current version and whether they satisfy the constraint
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
- # Retrieve the array of module names from the supplied filename/URL
158
- # @return [Array] an array of module names
159
- def return_modules(managed_modules_path)
160
- managed_modules = {}
161
- managed_modules_yaml = {}
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
- begin
176
- managed_modules_yaml = YAML.safe_load(managed_modules)
177
- rescue StandardError
178
- raise '*Error:* Ensure syntax of managed_modules file is a valid YAML array'
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
- managed_modules_yaml
182
- end
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
- # Post message to terminal
185
- # @param message [String]
186
- def post(message)
187
- puts message
188
- end
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
- def self.run_with_args(managed_modules_path, override, verbose)
191
- new(managed_modules_path, override, verbose).run
192
- end
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
- def self.run(managed_modules_path)
195
- new(managed_modules_path, nil, false, nil).run
193
+ # Post message to terminal
194
+ # @param message [String]
195
+ def post(message)
196
+ puts message
197
+ end
196
198
  end
197
199
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DependencyChecker
4
+ VERSION = '1.0.0.rc.1'
5
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Module for checking the dependencies of Puppet Module using data retrieved from the Puppet Forge.
2
4
  module DependencyChecker
3
5
  autoload :ForgeHelper, 'dependency_checker/forge_helper'
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.2.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: 2019-03-22 00:00:00.000000000 Z
12
+ date: 2023-04-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: puppet_forge
15
+ name: parallel
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '2.2'
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: '2.2'
27
+ version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
- name: rake
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: '12.3'
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: '12.3'
47
+ version: '4.0'
42
48
  - !ruby/object:Gem::Dependency
43
- name: semantic_puppet
49
+ name: rake
44
50
  requirement: !ruby/object:Gem::Requirement
45
51
  requirements:
46
52
  - - "~>"
47
53
  - !ruby/object:Gem::Version
48
- version: '1.0'
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: '1.0'
61
+ version: '13.0'
56
62
  - !ruby/object:Gem::Dependency
57
- name: parallel
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: " Verify all your dependencies allow the latest versions on Puppet
99
- Forge. \n Based on https://github.com/ekohl/metadata_json_deps\n"
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.0.0
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: '0'
112
+ version: 1.3.1
133
113
  requirements: []
134
- rubyforge_project:
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