Skip to content

Commit 130335e

Browse files
authored
Merge pull request #107 from bastelfreak/check
Validate module dependencies & puppetlabs/puppet_agent: Add missing deps
2 parents ba787bf + 6c3101f commit 130335e

File tree

5 files changed

+195
-8
lines changed

5 files changed

+195
-8
lines changed

.github/workflows/tests.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,28 @@ jobs:
245245
if: runner.os == 'Linux'
246246
run: bundle exec rake ci:boltspec:linux
247247

248+
check_dependencies:
249+
name: Check mod deps
250+
needs:
251+
- cache_modules
252+
runs-on: ubuntu-24.04
253+
steps:
254+
- name: Checkout repository
255+
uses: actions/checkout@v5
256+
- name: Setup Ruby
257+
uses: ruby/setup-ruby@v1
258+
with:
259+
ruby-version: '3.4'
260+
bundler-cache: true
261+
- name: Cache modules
262+
id: modules
263+
uses: actions/cache@v4
264+
with:
265+
path: modules
266+
key: ${{ runner.os }}-modules-${{ hashFiles('**/Puppetfile') }}
267+
- name: Validate all module dependencies
268+
run: bundle exec ./scripts/check_dependencies.rb
269+
248270
tests:
249271
needs:
250272
- rubocop_and_matrix
@@ -255,6 +277,7 @@ jobs:
255277
- winrm_transport
256278
- apply
257279
- boltspec
280+
- check_dependencies
258281
runs-on: ubuntu-24.04
259282
name: Test suite
260283
steps:

.rubocop_todo.yml

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ Lint/HashCompareByIdentity:
6060
Exclude:
6161
- 'lib/bolt/util.rb'
6262

63-
# Offense count: 3
63+
# Offense count: 5
6464
# Configuration parameters: AllowedParentClasses.
6565
Lint/MissingSuper:
6666
Exclude:
6767
- 'lib/bolt/apply_result.rb'
6868
- 'lib/bolt/transport/podman/connection.rb'
69+
- 'scripts/check_dependencies.rb'
6970
- 'spec/unit/logger_spec.rb'
7071

7172
# Offense count: 2
@@ -89,6 +90,12 @@ Lint/RedundantCopDisableDirective:
8990
Exclude:
9091
- 'lib/bolt/apply_inventory.rb'
9192

93+
# Offense count: 1
94+
# This cop supports unsafe autocorrection (--autocorrect-all).
95+
Lint/RedundantDirGlobSort:
96+
Exclude:
97+
- 'scripts/check_dependencies.rb'
98+
9299
# Offense count: 7
93100
# This cop supports safe autocorrection (--autocorrect).
94101
Lint/RedundantRequireStatement:
@@ -241,7 +248,7 @@ Performance/RedundantStringChars:
241248
Exclude:
242249
- 'lib/bolt/config/transport/base.rb'
243250

244-
# Offense count: 35
251+
# Offense count: 36
245252
# This cop supports safe autocorrection (--autocorrect).
246253
Performance/RegexpMatch:
247254
Enabled: false
@@ -388,7 +395,7 @@ RSpec/DescribeSymbol:
388395
RSpec/DescribedClass:
389396
Enabled: false
390397

391-
# Offense count: 655
398+
# Offense count: 656
392399
# Configuration parameters: CountAsOne.
393400
RSpec/ExampleLength:
394401
Max: 42
@@ -728,7 +735,7 @@ Style/ConcatArrayLiterals:
728735
- 'spec/integration/cli/cli_spec.rb'
729736
- 'spec/unit/module_installer_spec.rb'
730737

731-
# Offense count: 181
738+
# Offense count: 183
732739
# Configuration parameters: AllowedConstants.
733740
Style/Documentation:
734741
Enabled: false
@@ -804,6 +811,15 @@ Style/FileWrite:
804811
Exclude:
805812
- 'spec/lib/bolt_spec/pal.rb'
806813

814+
# Offense count: 1
815+
# This cop supports unsafe autocorrection (--autocorrect-all).
816+
# Configuration parameters: EnforcedStyle.
817+
# SupportedStyles: always, always_true, never
818+
Style/FrozenStringLiteralComment:
819+
Exclude:
820+
- '**/*.arb'
821+
- 'scripts/check_dependencies.rb'
822+
807823
# Offense count: 97
808824
# This cop supports safe autocorrection (--autocorrect).
809825
# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals.
@@ -822,14 +838,15 @@ Style/HashAsLastArrayItem:
822838
- 'spec/unit/applicator_spec.rb'
823839
- 'spec/unit/pal/yaml_plan/evaluator_spec.rb'
824840

825-
# Offense count: 2
841+
# Offense count: 3
826842
# This cop supports unsafe autocorrection (--autocorrect-all).
827843
# Configuration parameters: AllowSplatArgument.
828844
Style/HashConversion:
829845
Exclude:
830846
- 'lib/bolt/cli.rb'
847+
- 'scripts/check_dependencies.rb'
831848

832-
# Offense count: 4
849+
# Offense count: 5
833850
# This cop supports unsafe autocorrection (--autocorrect-all).
834851
# Configuration parameters: AllowedReceivers.
835852
# AllowedReceivers: Thread.current
@@ -838,6 +855,7 @@ Style/HashEachMethods:
838855
- 'acceptance/Rakefile'
839856
- 'lib/bolt/plugin/module.rb'
840857
- 'lib/bolt/shell/bash.rb'
858+
- 'scripts/check_dependencies.rb'
841859
- 'spec/unit/executor_spec.rb'
842860

843861
# Offense count: 5
@@ -848,6 +866,12 @@ Style/HashExcept:
848866
- 'lib/bolt/plugin/cache.rb'
849867
- 'lib/bolt/result.rb'
850868

869+
# Offense count: 1
870+
# This cop supports unsafe autocorrection (--autocorrect-all).
871+
Style/HashTransformValues:
872+
Exclude:
873+
- 'scripts/check_dependencies.rb'
874+
851875
# Offense count: 160
852876
# This cop supports safe autocorrection (--autocorrect).
853877
Style/IfUnlessModifier:
@@ -1054,7 +1078,7 @@ Style/StderrPuts:
10541078
Style/StringConcatenation:
10551079
Enabled: false
10561080

1057-
# Offense count: 3271
1081+
# Offense count: 3277
10581082
# This cop supports safe autocorrection (--autocorrect).
10591083
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
10601084
# SupportedStyles: single_quotes, double_quotes
@@ -1070,6 +1094,14 @@ Style/SuperArguments:
10701094
- 'lib/bolt/error.rb'
10711095
- 'lib/bolt_spec/plans/action_stubs/plan_stub.rb'
10721096

1097+
# Offense count: 1
1098+
# This cop supports unsafe autocorrection (--autocorrect-all).
1099+
# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments.
1100+
# AllowedMethods: define_method
1101+
Style/SymbolProc:
1102+
Exclude:
1103+
- 'scripts/check_dependencies.rb'
1104+
10731105
# Offense count: 29
10741106
# This cop supports safe autocorrection (--autocorrect).
10751107
# Configuration parameters: EnforcedStyle, AllowSafeAssignment.
@@ -1104,7 +1136,7 @@ Style/YAMLFileRead:
11041136
Exclude:
11051137
- 'spec/unit/module_installer_spec.rb'
11061138

1107-
# Offense count: 2
1139+
# Offense count: 3
11081140
# This cop supports safe autocorrection (--autocorrect).
11091141
# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
11101142
# URISchemes: http, https

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@ end
3636

3737
# https://github.com/OpenVoxProject/puppet/issues/90
3838
gem 'syslog', '~> 0.3' if RUBY_VERSION >= '3.4'
39+
40+
gem 'puppet_metadata', '~> 5.3'

Puppetfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ mod 'puppetlabs-service', '3.0.0'
99
mod 'puppetlabs-puppet_agent', '4.21.0'
1010
mod 'puppetlabs-facts', '1.6.0'
1111

12+
# puppetlabs-puppet_agent deps
13+
mod 'puppetlabs-inifile', '6.2.0'
14+
mod 'puppetlabs-apt', '9.4.0'
15+
1216
# Core types and providers for Puppet 6
1317
mod 'puppetlabs-augeas_core', '1.5.0'
1418
mod 'puppetlabs-host_core', '1.3.0'

scripts/check_dependencies.rb

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'puppet_metadata'
4+
require 'semantic_puppet'
5+
6+
def normalize_name(name)
7+
name.tr('-', '/')
8+
end
9+
10+
class LocalModules < SemanticPuppet::Dependency::Source
11+
attr_reader :modules
12+
13+
def initialize(module_dirs)
14+
@modules = {}
15+
16+
module_dirs.each do |module_dir|
17+
Dir[File.join(module_dir, '*', 'metadata.json')].sort.map do |metadata|
18+
mod = PuppetMetadata.read(metadata)
19+
dependencies = mod.dependencies.map { |name, requirement| [normalize_name(name), requirement.to_s] }
20+
name = normalize_name(mod.name)
21+
@modules[name] = create_release(name, mod.version, dependencies)
22+
rescue PuppetMetadata::InvalidMetadataException => e
23+
raise "#{metadata}: #{e}"
24+
end
25+
end
26+
27+
@modules.freeze
28+
end
29+
30+
def fetch(name)
31+
if @modules.key?(name)
32+
[@modules[name]]
33+
else
34+
[]
35+
end
36+
end
37+
end
38+
39+
class ProvidedModules < SemanticPuppet::Dependency::Source
40+
attr_reader :modules
41+
42+
def initialize(modules)
43+
@modules = {}
44+
45+
modules.each do |name, version|
46+
name = normalize_name(name)
47+
@modules[name] = create_release(name, version)
48+
end
49+
50+
@modules.freeze
51+
end
52+
53+
def fetch(name)
54+
if @modules.key?(name)
55+
[@modules[name]]
56+
else
57+
[]
58+
end
59+
end
60+
end
61+
62+
# TODO: read this from environment.conf
63+
local_source = LocalModules.new(['modules'])
64+
SemanticPuppet::Dependency.add_source(local_source)
65+
66+
modules = Hash[local_source.modules.map { |name, mod| [name, mod.version.to_s] }]
67+
68+
graph = SemanticPuppet::Dependency.query(modules)
69+
begin
70+
releases = SemanticPuppet::Dependency.resolve(graph)
71+
puts "Satisfied all dependencies:"
72+
releases.each do |release|
73+
# TODO: print source
74+
puts " #{release.name} #{release.version}"
75+
end
76+
rescue SemanticPuppet::Dependency::UnsatisfiableGraph => e
77+
# There was some dependency that wasn't matched. We know its name and that
78+
# it's a dependency we requested previously. Now to investigate why to
79+
# provide useful hints
80+
81+
# TODO: it's *very* weird to store unsatisfiable in a module
82+
# Strange API
83+
unsatisfiable = SemanticPuppet::Dependency.unsatisfiable
84+
85+
unless unsatisfiable
86+
# In older semantic_puppet unsatisfiable was unreliable
87+
# Needs https://github.com/puppetlabs/semantic_puppet/pull/37
88+
warn e
89+
warn "semantic_puppet provides insufficient information to hint why"
90+
exit 1
91+
end
92+
93+
warn "Unable to satisfy #{unsatisfiable}"
94+
95+
releases = graph.dependencies[unsatisfiable]
96+
if releases.empty?
97+
# This should never happen
98+
warn "No releases found for #{unsatisfiable}"
99+
exit 2
100+
end
101+
102+
releases.each do |release|
103+
warn "Investigating version #{release.version}"
104+
unsatisfied = release.dependencies.select { |_, candidates| candidates.empty? }
105+
if unsatisfied.empty?
106+
# Is this ever the case, did we miss anything else?
107+
warn " All dependencies satisfied"
108+
else
109+
unsatisfied.each do |dependency, _|
110+
constraint = release.constraints_for(dependency).find { |constraint| constraint[:source] == 'initialize' }
111+
warn " Dependency #{dependency} (#{constraint[:description]}) can't be satified"
112+
113+
constraint_graph = SemanticPuppet::Dependency.query(dependency => '>= 0')
114+
begin
115+
releases = SemanticPuppet::Dependency.resolve(constraint_graph)
116+
mod_releases = releases.select { |release| release.name == dependency }
117+
warn " Available versions: #{mod_releases.map { |r| r.version }.join(', ')}"
118+
rescue SemanticPuppet::Dependency::UnsatisfiableGraph
119+
warn " Unable to find any release"
120+
end
121+
end
122+
end
123+
end
124+
125+
exit 3
126+
end

0 commit comments

Comments
 (0)