bolt 2.31.0 → 2.32.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +1 -1
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +44 -1
- data/bolt-modules/prompt/lib/puppet/functions/prompt.rb +3 -0
- data/guides/module.txt +19 -0
- data/guides/modulepath.txt +25 -0
- data/lib/bolt/config/options.rb +31 -13
- data/lib/bolt/module_installer.rb +70 -115
- data/lib/bolt/{puppetfile → module_installer}/installer.rb +3 -2
- data/lib/bolt/module_installer/puppetfile.rb +117 -0
- data/lib/bolt/module_installer/puppetfile/forge_module.rb +54 -0
- data/lib/bolt/module_installer/puppetfile/git_module.rb +37 -0
- data/lib/bolt/module_installer/puppetfile/module.rb +26 -0
- data/lib/bolt/module_installer/resolver.rb +76 -0
- data/lib/bolt/module_installer/specs.rb +93 -0
- data/lib/bolt/module_installer/specs/forge_spec.rb +84 -0
- data/lib/bolt/module_installer/specs/git_spec.rb +178 -0
- data/lib/bolt/outputter.rb +0 -47
- data/lib/bolt/outputter/human.rb +2 -2
- data/lib/bolt/outputter/json.rb +1 -1
- data/lib/bolt/project.rb +3 -8
- data/lib/bolt/project_migrator/modules.rb +10 -8
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/schemas/partials/task.json +17 -2
- metadata +21 -7
- data/lib/bolt/puppetfile.rb +0 -149
- data/lib/bolt/puppetfile/module.rb +0 -93
data/lib/bolt/puppetfile.rb
DELETED
@@ -1,149 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bolt/error'
|
4
|
-
require 'bolt/puppetfile/module'
|
5
|
-
|
6
|
-
# This class manages the logical contents of a Puppetfile. It includes methods
|
7
|
-
# for parsing a Puppetfile and its modules, resolving module dependencies,
|
8
|
-
# and writing a Puppetfile.
|
9
|
-
#
|
10
|
-
module Bolt
|
11
|
-
class Puppetfile
|
12
|
-
attr_reader :modules
|
13
|
-
|
14
|
-
def initialize(modules = [])
|
15
|
-
@modules = Set.new
|
16
|
-
add_modules(modules)
|
17
|
-
end
|
18
|
-
|
19
|
-
# Loads a Puppetfile and parses its module specifications, returning a
|
20
|
-
# Bolt::Puppetfile object with the modules set.
|
21
|
-
#
|
22
|
-
def self.parse(path, skip_unsupported_modules: false)
|
23
|
-
require 'puppetfile-resolver'
|
24
|
-
require 'puppetfile-resolver/puppetfile/parser/r10k_eval'
|
25
|
-
|
26
|
-
begin
|
27
|
-
parsed = ::PuppetfileResolver::Puppetfile::Parser::R10KEval.parse(File.read(path))
|
28
|
-
rescue StandardError => e
|
29
|
-
raise Bolt::Error.new(
|
30
|
-
"Unable to parse Puppetfile #{path}: #{e.message}",
|
31
|
-
'bolt/puppetfile-parsing'
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
unless parsed.valid?
|
36
|
-
# valid? Just checks if validation_errors is empty, so if we get here we know it's not.
|
37
|
-
raise Bolt::ValidationError, <<~MSG
|
38
|
-
Unable to parse Puppetfile #{path}:
|
39
|
-
#{parsed.validation_errors.join("\n\n")}.
|
40
|
-
This may not be a Puppetfile managed by Bolt.
|
41
|
-
MSG
|
42
|
-
end
|
43
|
-
|
44
|
-
modules = parsed.modules.each_with_object([]) do |mod, acc|
|
45
|
-
unless mod.instance_of? PuppetfileResolver::Puppetfile::ForgeModule
|
46
|
-
next if skip_unsupported_modules
|
47
|
-
|
48
|
-
raise Bolt::ValidationError,
|
49
|
-
"Module '#{mod.title}' is not a Puppet Forge module. Unable to "\
|
50
|
-
"parse Puppetfile #{path}."
|
51
|
-
end
|
52
|
-
|
53
|
-
acc << Bolt::Puppetfile::Module.new(mod.owner, mod.name, mod.version)
|
54
|
-
end
|
55
|
-
|
56
|
-
new(modules)
|
57
|
-
end
|
58
|
-
|
59
|
-
# Writes a Puppetfile that includes specifications for each of the
|
60
|
-
# modules.
|
61
|
-
#
|
62
|
-
def write(path, moduledir = nil)
|
63
|
-
File.open(path, 'w') do |file|
|
64
|
-
if moduledir
|
65
|
-
file.puts "# This Puppetfile is managed by Bolt. Do not edit."
|
66
|
-
file.puts "# For more information, see https://pup.pt/bolt-modules"
|
67
|
-
file.puts
|
68
|
-
file.puts "# The following directive installs modules to the managed moduledir."
|
69
|
-
file.puts "moduledir '#{moduledir.basename}'"
|
70
|
-
file.puts
|
71
|
-
end
|
72
|
-
|
73
|
-
modules.each { |mod| file.puts mod.to_spec }
|
74
|
-
end
|
75
|
-
rescue SystemCallError => e
|
76
|
-
raise Bolt::FileError.new(
|
77
|
-
"#{e.message}: unable to write Puppetfile.",
|
78
|
-
path
|
79
|
-
)
|
80
|
-
end
|
81
|
-
|
82
|
-
# Resolves module dependencies using the puppetfile-resolver library. The
|
83
|
-
# resolver will return a document model including all module dependencies
|
84
|
-
# and the latest version that can be installed for each. The document model
|
85
|
-
# is parsed and turned into a Set of Bolt::Puppetfile::Module objects.
|
86
|
-
#
|
87
|
-
def resolve
|
88
|
-
require 'puppetfile-resolver'
|
89
|
-
|
90
|
-
# Build the document model from the modules.
|
91
|
-
model = PuppetfileResolver::Puppetfile::Document.new('')
|
92
|
-
|
93
|
-
@modules.each do |mod|
|
94
|
-
model.add_module(
|
95
|
-
PuppetfileResolver::Puppetfile::ForgeModule.new(mod.title).tap do |tap|
|
96
|
-
tap.version = mod.version || :latest
|
97
|
-
end
|
98
|
-
)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Make sure the Puppetfile model is valid.
|
102
|
-
unless model.valid?
|
103
|
-
raise Bolt::ValidationError,
|
104
|
-
"Unable to resolve dependencies for modules: #{@modules.map(&:title).join(', ')}"
|
105
|
-
end
|
106
|
-
|
107
|
-
# Create the resolver using the Puppetfile model. nil disables Puppet
|
108
|
-
# version restrictions.
|
109
|
-
resolver = PuppetfileResolver::Resolver.new(model, nil)
|
110
|
-
|
111
|
-
# Configure and resolve the dependency graph, catching any errors
|
112
|
-
# raised by puppetfile-resolver and re-raising them as Bolt errors.
|
113
|
-
begin
|
114
|
-
result = resolver.resolve(
|
115
|
-
cache: nil,
|
116
|
-
ui: nil,
|
117
|
-
module_paths: [],
|
118
|
-
allow_missing_modules: false
|
119
|
-
)
|
120
|
-
rescue StandardError => e
|
121
|
-
raise Bolt::Error.new(e.message, 'bolt/puppetfile-resolver-error')
|
122
|
-
end
|
123
|
-
|
124
|
-
# Turn specifications into module objects. This will skip over anything that is not
|
125
|
-
# a module specification (i.e. a Puppet version specification).
|
126
|
-
@modules = result.specifications.each_with_object(Set.new) do |(_name, spec), acc|
|
127
|
-
next unless spec.instance_of? PuppetfileResolver::Models::ModuleSpecification
|
128
|
-
acc << Bolt::Puppetfile::Module.new(spec.owner, spec.name, spec.version.to_s)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# Adds to the set of modules.
|
133
|
-
#
|
134
|
-
def add_modules(modules)
|
135
|
-
Array(modules).each do |mod|
|
136
|
-
case mod
|
137
|
-
when Bolt::Puppetfile::Module
|
138
|
-
@modules << mod
|
139
|
-
when Hash
|
140
|
-
@modules << Bolt::Puppetfile::Module.from_hash(mod)
|
141
|
-
else
|
142
|
-
raise Bolt::ValidationError, "Module must be a Bolt::Puppetfile::Module or Hash."
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
@modules
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
@@ -1,93 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bolt/error'
|
4
|
-
|
5
|
-
# This class represents a module specification. It used by the Bolt::Puppetfile
|
6
|
-
# class to have a consistent API for accessing a module's attributes.
|
7
|
-
#
|
8
|
-
module Bolt
|
9
|
-
class Puppetfile
|
10
|
-
class Module
|
11
|
-
attr_reader :owner, :name, :version
|
12
|
-
|
13
|
-
def initialize(owner, name, version = nil)
|
14
|
-
@owner = owner
|
15
|
-
@name = name
|
16
|
-
|
17
|
-
if version.is_a?(String)
|
18
|
-
@version = version[0] == '=' ? version[1..-1] : version
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Creates a new module from a hash.
|
23
|
-
#
|
24
|
-
def self.from_hash(mod)
|
25
|
-
unless mod['name'].is_a?(String)
|
26
|
-
raise Bolt::ValidationError,
|
27
|
-
"Module name must be a String, not #{mod['name'].inspect}"
|
28
|
-
end
|
29
|
-
|
30
|
-
owner, name = mod['name'].tr('/', '-').split('-', 2)
|
31
|
-
|
32
|
-
unless owner && name
|
33
|
-
raise Bolt::ValidationError, "Module name #{mod['name']} must include both the owner and module name."
|
34
|
-
end
|
35
|
-
|
36
|
-
new(owner, name, mod['version_requirement'])
|
37
|
-
end
|
38
|
-
|
39
|
-
# Returns the module's title.
|
40
|
-
#
|
41
|
-
def title
|
42
|
-
"#{@owner}-#{@name}"
|
43
|
-
end
|
44
|
-
alias to_s title
|
45
|
-
|
46
|
-
# Checks two modules for equality.
|
47
|
-
#
|
48
|
-
def eql?(other)
|
49
|
-
self.class == other.class &&
|
50
|
-
@owner == other.owner &&
|
51
|
-
@name == other.name &&
|
52
|
-
versions_intersect?(other)
|
53
|
-
end
|
54
|
-
alias == eql?
|
55
|
-
|
56
|
-
# Returns true if the versions of two modules intersect. Used to determine
|
57
|
-
# if an installed module satisfies the version requirement of another.
|
58
|
-
#
|
59
|
-
def versions_intersect?(other)
|
60
|
-
range = ::SemanticPuppet::VersionRange.parse(@version || '')
|
61
|
-
other_range = ::SemanticPuppet::VersionRange.parse(other.version || '')
|
62
|
-
|
63
|
-
range.intersection(other_range) != ::SemanticPuppet::VersionRange::EMPTY_RANGE
|
64
|
-
end
|
65
|
-
|
66
|
-
# Hashes the module.
|
67
|
-
#
|
68
|
-
def hash
|
69
|
-
[@owner, @name].hash
|
70
|
-
end
|
71
|
-
|
72
|
-
# Returns a hash representation similar to the module
|
73
|
-
# declaration.
|
74
|
-
#
|
75
|
-
def to_hash
|
76
|
-
{
|
77
|
-
'name' => title,
|
78
|
-
'version_requirement' => version
|
79
|
-
}.compact
|
80
|
-
end
|
81
|
-
|
82
|
-
# Returns the Puppetfile specification for the module.
|
83
|
-
#
|
84
|
-
def to_spec
|
85
|
-
if @version
|
86
|
-
"mod #{title.inspect}, #{@version.inspect}"
|
87
|
-
else
|
88
|
-
"mod #{title.inspect}"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|