Skip to content

(PUP-7738) Ensure that Puppet can be used with semantic_puppet gem.#6030

Merged
joshcooper merged 8 commits intopuppetlabs:5.0.xfrom
thallgren:issue/pup-7738/check-range-parse-arity
Jul 14, 2017
Merged

(PUP-7738) Ensure that Puppet can be used with semantic_puppet gem.#6030
joshcooper merged 8 commits intopuppetlabs:5.0.xfrom
thallgren:issue/pup-7738/check-range-parse-arity

Conversation

@thallgren
Copy link
Contributor

This commit adds an arity check to be able to call the method
SemanticPuppet::VersionRange#parse with one or two arguments from the
Puppet::Module#parse_range method.

When the arity is found to be just 1, a check is made if the gem version
of the semantic_puppet gem is < 1.0.0, in which case it is assumed that
the parse method is incapable of creating a range that adheres to strict
semantics. A warning is logged if a request for a strict range is made.
Conversely, if the gem version is >=1.0.0, it is assumed that strict
semantics will be honored and a warning is issued if a request for a
non-strict range is made.

@thallgren thallgren requested a review from joshcooper June 30, 2017 09:59
@puppetcla
Copy link

CLA signed by all contributors.

# @api private
def self.parse_range(range, strict)
@parse_range_method ||= SemanticPuppet::VersionRange.method(:parse)
if @parse_range_method.arity == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the coolest block of ruby I read this month. I didn't know that ruby is able to tell you the amount of arguments.


Thanks for quickly providing such an awesome fix!

if strict
if @semver_gem_version.major < 1
Puppet.warn_once('strict_version_ranges', 'version_range_cannot_be_strict',
_('VersionRanges will never be strict when using non-vendored SemanticPuppet gem, version %{version}') % { version: @semver_gem_version} )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there are a few places where strict_semver is not getting passed through, so it defaults to true and triggers the warning when --strict_semver is not specified. For example, given a Gemfile:

source "https://rubygems.org"
gem "puppet", :path => '/Users/josh/work/puppet'
gem "semantic_puppet", "~> 0.1.4"

Install gems, including old semantic_puppet:

$ bundle install --path .bundle
Fetching gem metadata from https://rubygems.org/........
Fetching version metadata from https://rubygems.org/.
Resolving dependencies...
Installing CFPropertyList 2.2.8
Installing fast_gettext 1.1.0
Installing locale 2.1.2
Installing text 1.3.1
Installing hiera 3.4.0
Installing hocon 1.2.5
Installing net-ssh 4.1.0
Using bundler 1.14.6
Installing facter 2.4.6 (universal-darwin)
Installing gettext 3.2.3
Installing gettext-setup 0.25
Using puppet 5.0.0 from source at `/Users/josh/work/puppet`
Installing semantic_puppet 0.1.4
Bundle complete! 2 Gemfile dependencies, 13 gems now installed.
Bundled gems are installed into ./.bundle.

This is not expected:

$ rm -rf ~/.puppetlabs/etc/code/modules
$ bundle exec puppet module install puppetlabs-apache
Notice: Preparing to install into /Users/josh/.puppetlabs/etc/code/modules ...
Notice: Created target directory /Users/josh/.puppetlabs/etc/code/modules
Notice: Downloading from https://forgeapi.puppet.com ...
Warning: VersionRanges will never be strict when using non-vendored SemanticPuppet gem, version 0.1.4
   (file & line not available)
Notice: Installing -- do not interrupt ...
/Users/josh/.puppetlabs/etc/code/modules
└─┬ puppetlabs-apache (v1.11.0)
  ├── puppetlabs-concat (v2.2.1)
  └── puppetlabs-stdlib (v4.17.1)

I would only expect the warning when using puppet module install --strict-semver. It looks like Puppet::Forge calls:

        ModuleRelease.new(self, release)

which defaults strict_semver to true triggering the behavior.

Copy link
Contributor

@joshcooper joshcooper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See earlier comments

else
if @semver_gem_version.major >= 1
Puppet.warn_once('strict_version_ranges', 'version_range_always_strict',
_('VersionRanges will always be strict when using non-vendored SemanticPuppet gem, version %{version}') % { version: @semver_gem_version} )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To "resolve" this warning a user would be forced to run with --strict_semver, even though they may not be anything wrong with the versions. That seems overly invasive for little gain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I partly agree. But please consider that:

  • the warning is only output once
  • the warning is only output when they are using the external gem
  • if they indeed do something wrong, and run into problems, there's no way of telling why.

@joshcooper
Copy link
Contributor

@thallgren looks like valid travis/appveyor failures.

thallgren added 4 commits July 6, 2017 12:20
This commit adds the method `Puppet::Module#parse_range` which in turn
calls `SemanticPuppet::VersionRange#parse` and ensures that all calls
from `Puppet::Module` and `Puppet::ModuleTool` uses that method instead
of calling directly.
This commit adds an arity check to be able to call the method
`SemanticPuppet::VersionRange#parse` with one or two arguments from the
`Puppet::Module#parse_range` method.

When the arity is found to be just 1, a check is made if the gem version
of the semantic_puppet gem is < 1.0.0, in which case it is assumed that
the parse method is incapable of creating a range that adheres to strict
semantics. A warning is logged if a request for a strict range is made.
Conversely, if the gem version is >=1.0.0, it is assumed that strict
semantics will be honored and a warning is issued if a request for a
non-strict range is made.
Before this commit, a created `Puppet::Forge` instance would not know
the setting of `strict_semver`. This made parts of the dependency
resolution use strict semantics. This commit ensures that the setting is
known to `Puppet::Forge` and propagated to the created `ModuleRelease`
instances when processing a dependency tree.
It appears that the while the unit test for the `search` face that
tested if the option `:module_repository` was accepted, it did not check
if it was also propagated to the `Puppet::Forge` instance. It wasn't,
and as a consequence, the test failed when the default repository was
propagated in an attempt to simulate the default argument assignment
when passing no arguments to `Puppet::Forge#new`.

This commit therefore fixes two things:
1. It ensures that the `:module_repository` option is propagated when
   the `Puppet::Forge` is instantiated.
2. It updates the test to check that the correct repository is
   propagated when the instance is created.
@thallgren thallgren force-pushed the issue/pup-7738/check-range-parse-arity branch from 690a6c3 to 89c3322 Compare July 6, 2017 10:43
Copy link
Contributor

@joshcooper joshcooper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still isn't working as I would expect. If I'm using semantic_puppet 1.0.1 as an external gem, then I always receive a warning even when using --strict-semver. So I'm getting a warning about something I can't do anything to fix. And I don't think we want to encourage module developers to remove semantic_puppet from their Gemfiles as we want to unvendor from Puppet.

$ rm -rf ~/.puppetlabs/etc/code/modules
$ bx puppet module install puppetlabs-apache
Notice: Preparing to install into /Users/josh/.puppetlabs/etc/code/modules ...
Notice: Created target directory /Users/josh/.puppetlabs/etc/code/modules
Notice: Downloading from https://forgeapi.puppet.com ...
Warning: VersionRanges will always be strict when using non-vendored SemanticPuppet gem, version 1.0.1
   (file & line not available)
Notice: Installing -- do not interrupt ...
/Users/josh/.puppetlabs/etc/code/modules
└─┬ puppetlabs-apache (v1.11.0)
  ├── puppetlabs-concat (v2.2.1)
  └── puppetlabs-stdlib (v4.17.1)
$ rm -rf ~/.puppetlabs/etc/code/modules
$ bx puppet module install puppetlabs-apache --strict-semver
Notice: Preparing to install into /Users/josh/.puppetlabs/etc/code/modules ...
Notice: Created target directory /Users/josh/.puppetlabs/etc/code/modules
Notice: Downloading from https://forgeapi.puppet.com ...
Warning: VersionRanges will always be strict when using non-vendored SemanticPuppet gem, version 1.0.1
   (file & line not available)
Notice: Installing -- do not interrupt ...
/Users/josh/.puppetlabs/etc/code/modules
└─┬ puppetlabs-apache (v1.11.0)
  ├── puppetlabs-concat (v2.2.1)
  └── puppetlabs-stdlib (v4.17.1)

where my Gemfile contains:

source "https://rubygems.org"
gem "puppet", :git => 'https://github.com/thallgren/puppet.git', :branch => 'issue/pup-7738/check-range-parse-arity'
gem "semantic_puppet", "~> 1.0.1"

Prior to this commit, the method `Puppet::ModuleTool#set_default_options`
would set the `:strict_semver` option to `false` even though it had
already been assigned a value. This commit ensures that the given value
is retained and adds tests to assert that.
@joshcooper
Copy link
Contributor

So this seems to be working now, but I still have questions.

If strict-semver is explicitly enabled, then it makes sense to warn if the external semantic_puppet < 1.0.0, since we can't honor that setting.

If strict-semver is disabled (the default), then I don't think we should generate messages when there is nothing wrong with the versions, e.g. in the apache module above. Can we only generate a message if there is a problem (add begin/rescue, and only warn if it raises)?

Also if --no-strict-semver is specified, shouldn't we pass that through to our vendored version, e.g. @parse_range_method.call(range, false)?

@joshcooper
Copy link
Contributor

How about if we drop the warn_once messages for now, and get this change merged for 5.0.1 and file a separate ticket for warning when users specify versions that don't conform to strict semver?

@thallgren
Copy link
Contributor Author

The problem is that we cannot see if there's something wrong with a VersionRange. It's syntax is correct so it will parse OK. The problem arises when the range is used and it includes versions that contain pre-releases. It should't include those versions unless it specifies this. Detecting this isn't trivial since we then must intercept all places where a version range is in use, check how it's constituted, and then check all versions that it accepts. It would be easy to insert such a check into the patched VersionRange but that doesn't help much in this case since the problem arises when the patched semantic_puppet isn't used.

I think the warning should stay in, because the patched semantic_puppet does change how a version range works. We have no other way to signal this to the user. If it's ok to just silently impose strict versioning on the user, then why are we patching the semantic_puppet gem in the first place?

@joshcooper
Copy link
Contributor

In the scenario above, puppet is emitting a warning even though the apache module is using semantically correct version ranges. That makes no sense.

A warning indicates something has gone wrong, but in this case, nothing is wrong. The apache module is correct, and editing metadata.json will not change the outcome.

$ bx puppet module install puppetlabs-apache
Notice: Preparing to install into /Users/josh/.puppetlabs/etc/code/modules ...
Notice: Created target directory /Users/josh/.puppetlabs/etc/code/modules
Notice: Downloading from https://forgeapi.puppet.com ...
Warning: VersionRanges will always be strict when using non-vendored SemanticPuppet gem, version 1.0.1
   (file & line not available)

@thallgren
Copy link
Contributor Author

In your scenario, the resolution above will differ if a pre-release comes into existence for stdlib or concat. If the user uses an external 1.0.1, those pre-releases will not be selected. Perhaps that will never happen for this particular module? In any case, I'm reluctant to create a design that makes that assumption for all modules.

That said, I do understand your objection to using a warning. Perhaps the message should be a Notice (once)?

@joshcooper
Copy link
Contributor

Please change it to a Notice or Info (once).

In some cases, it's desirable to make the user aware of potential
issues that may or may not cause a problem. This commit makes it
possible to use the `warn_once` method to log such problems with a
different log-level than `:warning`.
This commit changes the messages that are logged when the setting of
`strict_semver` cannot be honored by the `semantic_puppet` implementation
so that they are logged using `:notice` instead of `:warning`.
Adds ability to pass `:default` instead of `nil` for the file and line
arguments passed to `#warn_once`. When passing :default for both
arguments, the output "file & line not available" is suppressed.
@joshcooper
Copy link
Contributor

joshcooper commented Jul 14, 2017

From module that depends on semantic_puppet 1.0.1 and puppet:

$ rm -rf ~/.puppetlabs
$ bx puppet module install puppetlabs/apache
Notice: Preparing to install into /Users/josh/.puppetlabs/etc/code/modules ...
Notice: Created target directory /Users/josh/.puppetlabs/etc/code/modules
Notice: Downloading from https://forgeapi.puppet.com ...
Notice: VersionRanges will always be strict when using non-vendored SemanticPuppet gem, version 1.0.1
Notice: Installing -- do not interrupt ...
/Users/josh/.puppetlabs/etc/code/modules
└─┬ puppetlabs-apache (v1.11.0)
  ├── puppetlabs-concat (v2.2.1)
  └── puppetlabs-stdlib (v4.17.1)
$ rm -rf ~/.puppetlabs
$ bx puppet module install puppetlabs/apache --strict-semver
Notice: Preparing to install into /Users/josh/.puppetlabs/etc/code/modules ...
Notice: Created target directory /Users/josh/.puppetlabs/etc/code/modules
Notice: Downloading from https://forgeapi.puppet.com ...
Notice: Installing -- do not interrupt ...
/Users/josh/.puppetlabs/etc/code/modules
└─┬ puppetlabs-apache (v1.11.0)
  ├── puppetlabs-concat (v2.2.1)
  └── puppetlabs-stdlib (v4.17.1)

@joshcooper
Copy link
Contributor

From puppet (so no external semantic_puppet gem):

$ rm -rf ~/.puppetlabs
$ bx puppet module install puppetlabs/apache
Notice: Preparing to install into /Users/josh/.puppetlabs/etc/code/modules ...
Notice: Created target directory /Users/josh/.puppetlabs/etc/code/modules
Notice: Downloading from https://forgeapi.puppet.com ...
Notice: Installing -- do not interrupt ...
/Users/josh/.puppetlabs/etc/code/modules
└─┬ puppetlabs-apache (v1.11.0)
  ├── puppetlabs-concat (v2.2.1)
  └── puppetlabs-stdlib (v4.17.1)

@joshcooper joshcooper merged commit 7f53ea2 into puppetlabs:5.0.x Jul 14, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants