bolt 2.28.0 → 2.29.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03de2a7e4d6fa0b9d4120fff783ccb009665077c7b00e910f5e2de14c03a1767
4
- data.tar.gz: 511e18c31228338f47519ee02a7b248f4d264b93516a58aa1b063a41bb835e80
3
+ metadata.gz: ec167b23fc4ceec9d9b3048ae64582a3fcf2baa1eceb8100fb26cc3c6df95cb6
4
+ data.tar.gz: 4621d274f8c14f4986dae819755c0db162cd056fbd9412275a0bcffc2169edee
5
5
  SHA512:
6
- metadata.gz: 1956edc3051eae34d25957c7827ce1e1f12bfc7e322d9305a79d9a2cb32cf144309413626cfb9db6667193a8853810dabf8d6004924ad3899633a220f34cecb7
7
- data.tar.gz: af2e40875cb54c1e2b4153605ffc6abb6b11a65e2f0abcc30f7eb87701cb3c5c023905dc1709ff0bf7261e856ceaae29fad9df13e4b9b51b9f74a4ef65fb0b74
6
+ metadata.gz: 1af9a8df65a1a95a7404a0b94f74bfeb9086e3a97ba03e1f19a53acbb626757249b69d812f7afe87e2da05a06d698f515b05313018a649621d98269eabfe2f93
7
+ data.tar.gz: 24f0b0f56451570d5e97d74ddb66556b48fd8c14a79fd7a0c09f10a4ef1c8590684ccee1675c4dd4126cdbcbc781bad6bf83ba2aa4d8ada0cd13279c15f53876
@@ -746,7 +746,7 @@ module Bolt
746
746
  'For SSH, port defaults to `22`',
747
747
  'For WinRM, port defaults to `5985` or `5986` based on the --[no-]ssl setting') do |targets|
748
748
  @options[:targets] ||= []
749
- @options[:targets] << get_arg_input(targets)
749
+ @options[:targets] << Bolt::Util.get_arg_input(targets)
750
750
  end
751
751
  define('-q', '--query QUERY', 'Query PuppetDB to determine the targets') do |query|
752
752
  @options[:query] = query
@@ -985,27 +985,10 @@ module Bolt
985
985
  end
986
986
 
987
987
  def parse_params(params)
988
- json = get_arg_input(params)
988
+ json = Bolt::Util.get_arg_input(params)
989
989
  JSON.parse(json)
990
990
  rescue JSON::ParserError => e
991
991
  raise Bolt::CLIError, "Unable to parse --params value as JSON: #{e}"
992
992
  end
993
-
994
- def get_arg_input(value)
995
- if value.start_with?('@')
996
- file = value.sub(/^@/, '')
997
- read_arg_file(file)
998
- elsif value == '-'
999
- $stdin.read
1000
- else
1001
- value
1002
- end
1003
- end
1004
-
1005
- def read_arg_file(file)
1006
- File.read(File.expand_path(file))
1007
- rescue StandardError => e
1008
- raise Bolt::FileError.new("Error attempting to read #{file}: #{e}", file)
1009
- end
1010
993
  end
1011
994
  end
@@ -107,6 +107,11 @@ module Bolt
107
107
 
108
108
  options[:object] = remaining.shift
109
109
 
110
+ # Handle reading a command from a file
111
+ if options[:subcommand] == 'command' && options[:object]
112
+ options[:object] = Bolt::Util.get_arg_input(options[:object])
113
+ end
114
+
110
115
  # Only parse task_options for task or plan
111
116
  if %w[task plan].include?(options[:subcommand])
112
117
  task_options, remaining = remaining.partition { |s| s =~ /.+=/ }
@@ -892,13 +897,17 @@ module Bolt
892
897
  unless existing.modules.superset? puppetfile.modules
893
898
  missing_modules = puppetfile.modules - existing.modules
894
899
 
895
- raise Bolt::Error.new(
896
- "Puppetfile #{puppetfile_path} is missing specifications for modules: "\
897
- "#{missing_modules.map(&:title).join(', ')}. This may not be a Puppetfile "\
898
- "managed by Bolt. To forcibly overwrite the Puppetfile, run with the "\
899
- "'--force' option.",
900
- 'bolt/missing-module-specs'
901
- )
900
+ message = <<~MESSAGE.chomp
901
+ Puppetfile #{puppetfile_path} is missing specifications for the following
902
+ module declarations:
903
+
904
+ #{missing_modules.map(&:to_hash).to_yaml.lines.drop(1).join.chomp}
905
+
906
+ This may not be a Puppetfile managed by Bolt. To forcibly overwrite the
907
+ Puppetfile, run 'bolt module install --force'.
908
+ MESSAGE
909
+
910
+ raise Bolt::Error.new(message, 'bolt/missing-module-specs')
902
911
  end
903
912
  else
904
913
  outputter.print_message "Resolving module dependencies, this may take a moment"
@@ -239,11 +239,21 @@ module Bolt
239
239
  "name" => {
240
240
  description: "The name of the module.",
241
241
  type: String
242
+ },
243
+ "version_requirement" => {
244
+ description: "The version requirement for the module. Accepts a specific version (1.2.3), version "\
245
+ "shorthand (1.2.x), or a version range (>= 1.2.0).",
246
+ type: String
242
247
  }
243
248
  }
244
249
  },
245
250
  _plugin: false,
246
- _example: [{ "name" => "puppetlabs-mysql" }, { "name" => "puppetlabs-apache" }]
251
+ _example: [
252
+ { "name" => "puppetlabs-mysql" },
253
+ { "name" => "puppetlabs-apache", "version_requirement" => "5.5.0" },
254
+ { "name" => "puppetlabs-puppetdb", "version_requirement" => "7.x" },
255
+ { "name" => "puppetlabs-firewall", "version_requirement" => ">= 1.0.0 < 3.0.0" }
256
+ ]
247
257
  },
248
258
  "name" => {
249
259
  description: "The name of the Bolt project. When this option is configured, the project is considered a "\
@@ -4,6 +4,10 @@ require 'logging'
4
4
 
5
5
  module Bolt
6
6
  module Logger
7
+ LEVELS = %w[trace debug info notice warn error fatal].freeze
8
+ @mutex = Mutex.new
9
+ @warnings = Set.new
10
+
7
11
  # This method provides a single point-of-entry to setup logging for both
8
12
  # the CLI and for tests. This is necessary because we define custom log
9
13
  # levels which create corresponding methods on the logger instances;
@@ -11,20 +15,25 @@ module Bolt
11
15
  # will fail.
12
16
  def self.initialize_logging
13
17
  # Initialization isn't idempotent and will result in warnings about const
14
- # redefs, so skip it if it's already been initialized
15
- return if Logging.initialized?
16
-
17
- Logging.init :trace, :debug, :info, :notice, :warn, :error, :fatal, :any
18
- @mutex = Mutex.new
19
-
20
- Logging.color_scheme(
21
- 'bolt',
22
- lines: {
23
- warn: :yellow,
24
- error: :red,
25
- fatal: %i[white on_red]
26
- }
27
- )
18
+ # redefs, so skip it if the log levels we expect are present. If it's
19
+ # already been initialized with an insufficient set of levels, go ahead
20
+ # and call init anyway or we'll have failures when calling log methods
21
+ # for missing levels.
22
+ unless levels & LEVELS == LEVELS
23
+ Logging.init(*LEVELS)
24
+ end
25
+
26
+ # As above, only create the color scheme if we haven't already created it.
27
+ unless Logging.color_scheme('bolt')
28
+ Logging.color_scheme(
29
+ 'bolt',
30
+ lines: {
31
+ warn: :yellow,
32
+ error: :red,
33
+ fatal: %i[white on_red]
34
+ }
35
+ )
36
+ end
28
37
  end
29
38
 
30
39
  def self.configure(destinations, color)
@@ -115,14 +124,12 @@ module Bolt
115
124
  end
116
125
 
117
126
  def self.warn_once(type, msg)
118
- @mutex.synchronize {
119
- @warnings ||= []
127
+ @mutex.synchronize do
120
128
  @logger ||= Bolt::Logger.logger(self)
121
- unless @warnings.include?(type)
129
+ if @warnings.add?(type)
122
130
  @logger.warn(msg)
123
- @warnings << type
124
131
  end
125
- }
132
+ end
126
133
  end
127
134
 
128
135
  def self.deprecation_warning(type, msg)
@@ -199,10 +199,9 @@ module Bolt
199
199
  raise Bolt::ValidationError, "Module declaration #{mod.inspect} must be a hash"
200
200
  end
201
201
 
202
- unknown_keys = data['modules'].flat_map(&:keys).uniq - ['name']
202
+ unknown_keys = data['modules'].flat_map(&:keys).uniq - %w[name version_requirement]
203
203
  if unknown_keys.any?
204
- @logs << { warn: "Module declarations in bolt-project.yaml only support a name key. Ignoring "\
205
- "unsupported keys: #{unknown_keys.join(', ')}." }
204
+ @logs << { warn: "Ignoring unknown keys in module declarations: #{unknown_keys.join(', ')}." }
206
205
  end
207
206
  end
208
207
  end
@@ -82,7 +82,7 @@ module Bolt
82
82
  @modules.each do |mod|
83
83
  model.add_module(
84
84
  PuppetfileResolver::Puppetfile::ForgeModule.new(mod.title).tap do |tap|
85
- tap.version = :latest
85
+ tap.version = mod.version || :latest
86
86
  end
87
87
  )
88
88
  end
@@ -30,7 +30,7 @@ module Bolt
30
30
  raise Bolt::ValidationError, "Module name #{mod['name']} must include both the owner and module name."
31
31
  end
32
32
 
33
- new(owner, name)
33
+ new(owner, name, mod['version_requirement'])
34
34
  end
35
35
 
36
36
  # Returns the module's title.
@@ -42,16 +42,39 @@ module Bolt
42
42
  # Checks two modules for equality.
43
43
  #
44
44
  def eql?(other)
45
- self.class == other.class && @owner == other.owner && @name == other.name
45
+ self.class == other.class &&
46
+ @owner == other.owner &&
47
+ @name == other.name &&
48
+ versions_intersect?(other)
46
49
  end
47
50
  alias == eql?
48
51
 
52
+ # Returns true if the versions of two modules intersect. Used to determine
53
+ # if an installed module satisfies the version requirement of another.
54
+ #
55
+ def versions_intersect?(other)
56
+ range = ::SemanticPuppet::VersionRange.parse(@version || '')
57
+ other_range = ::SemanticPuppet::VersionRange.parse(other.version || '')
58
+
59
+ range.intersection(other_range) != ::SemanticPuppet::VersionRange::EMPTY_RANGE
60
+ end
61
+
49
62
  # Hashes the module.
50
63
  #
51
64
  def hash
52
65
  [@owner, @name].hash
53
66
  end
54
67
 
68
+ # Returns a hash representation similar to the module
69
+ # declaration.
70
+ #
71
+ def to_hash
72
+ {
73
+ 'name' => title,
74
+ 'version_requirement' => version
75
+ }.compact
76
+ end
77
+
55
78
  # Returns the Puppetfile specification for the module.
56
79
  #
57
80
  def to_spec
@@ -3,6 +3,25 @@
3
3
  module Bolt
4
4
  module Util
5
5
  class << self
6
+ # Gets input for an argument.
7
+ def get_arg_input(value)
8
+ if value.start_with?('@')
9
+ file = value.sub(/^@/, '')
10
+ read_arg_file(file)
11
+ elsif value == '-'
12
+ $stdin.read
13
+ else
14
+ value
15
+ end
16
+ end
17
+
18
+ # Reads a file passed as an argument to a command.
19
+ def read_arg_file(file)
20
+ File.read(File.expand_path(file))
21
+ rescue StandardError => e
22
+ raise Bolt::FileError.new("Error attempting to read #{file}: #{e}", file)
23
+ end
24
+
6
25
  def read_yaml_hash(path, file_name)
7
26
  require 'yaml'
8
27
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bolt
4
- VERSION = '2.28.0'
4
+ VERSION = '2.29.0'
5
5
  end
@@ -212,7 +212,7 @@ module BoltServer
212
212
  return [400, "`project_ref`: #{project_dir} does not exist"] unless Dir.exist?(project_dir)
213
213
  @pal_mutex.synchronize do
214
214
  project = Bolt::Project.create_project(project_dir)
215
- bolt_config = Bolt::Config.from_project(project, {})
215
+ bolt_config = Bolt::Config.from_project(project, { log: { 'bolt-debug.log' => 'disable' } })
216
216
  pal = Bolt::PAL.new(bolt_config.modulepath, nil, nil, nil, nil, nil, bolt_config.project)
217
217
  module_path = [
218
218
  BoltServer::PE::PAL::PE_BOLTLIB_PATH,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bolt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.28.0
4
+ version: 2.29.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-16 00:00:00.000000000 Z
11
+ date: 2020-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -198,14 +198,14 @@ dependencies:
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: 0.1.0
201
+ version: '0.4'
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: 0.1.0
208
+ version: '0.4'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: puppet-resource_api
211
211
  requirement: !ruby/object:Gem::Requirement