dependency_checker 0.2.0 → 1.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
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