From 44701757570f96f86da488899d01e984a99f62de Mon Sep 17 00:00:00 2001 From: Tim Meusel Date: Wed, 9 Apr 2025 12:54:01 +0200 Subject: [PATCH] Add Rubocop configuration --- .github/workflows/ruby-rspec.yml | 13 +- .gitignore | 1 + .rubocop.yml | 8 + .rubocop_todo.yml | 409 ++++++++++++++++++ Rakefile | 8 +- lib/puppet_forge/connection.rb | 17 +- .../connection/connection_failure.rb | 9 +- lib/puppet_forge/error.rb | 14 +- lib/puppet_forge/lazy_accessors.rb | 21 +- lib/puppet_forge/lazy_relations.rb | 20 +- lib/puppet_forge/lru_cache.rb | 18 +- lib/puppet_forge/tar.rb | 1 - lib/puppet_forge/tar/mini.rb | 21 +- lib/puppet_forge/unpacker.rb | 20 +- lib/puppet_forge/util.rb | 2 +- lib/puppet_forge/v3.rb | 1 - lib/puppet_forge/v3/base.rb | 38 +- .../v3/base/paginated_collection.rb | 11 +- lib/puppet_forge/v3/metadata.rb | 88 ++-- lib/puppet_forge/v3/module.rb | 1 - lib/puppet_forge/v3/release.rb | 24 +- lib/puppet_forge/v3/user.rb | 4 +- puppet_forge.gemspec | 43 +- spec/spec_helper.rb | 24 +- .../connection/connection_failure_spec.rb | 26 +- spec/unit/forge/connection_spec.rb | 63 +-- spec/unit/forge/lazy_accessors_spec.rb | 50 ++- spec/unit/forge/lazy_relations_spec.rb | 149 +++---- spec/unit/forge/lru_cache_spec.rb | 37 +- spec/unit/forge/tar/mini_spec.rb | 41 +- spec/unit/forge/tar_spec.rb | 6 +- spec/unit/forge/unpacker_spec.rb | 27 +- spec/unit/forge/util_spec.rb | 10 +- .../v3/base/paginated_collection_spec.rb | 62 +-- spec/unit/forge/v3/base_spec.rb | 36 +- spec/unit/forge/v3/metadata_spec.rb | 158 ++++--- spec/unit/forge/v3/module_spec.rb | 19 +- spec/unit/forge/v3/release_spec.rb | 80 ++-- spec/unit/forge/v3/user_spec.rb | 6 +- spec/unit/puppet_forge_spec.rb | 10 +- 40 files changed, 1023 insertions(+), 573 deletions(-) create mode 100644 .rubocop.yml create mode 100644 .rubocop_todo.yml diff --git a/.github/workflows/ruby-rspec.yml b/.github/workflows/ruby-rspec.yml index f133975..2f6953c 100644 --- a/.github/workflows/ruby-rspec.yml +++ b/.github/workflows/ruby-rspec.yml @@ -9,6 +9,18 @@ on: - main jobs: + rubocop: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Ruby ${{ matrix.ruby }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + - name: Run Rubocop + run: bundle exec rake rubocop + test: name: Test with Ruby ${{ matrix.ruby_version }} runs-on: ubuntu-latest @@ -25,6 +37,5 @@ jobs: with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - - name: Build and test with Rspec run: bundle exec rspec diff --git a/.gitignore b/.gitignore index 03407c0..3a50d37 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ _yardoc *.a mkmf.log /vendor/ +/.vendor/ diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..c59548e --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,8 @@ +--- +inherit_from: .rubocop_todo.yml + +inherit_gem: + voxpupuli-rubocop: rubocop.yml + +AllCops: + TargetRubyVersion: '3.1' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..4e13355 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,409 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2025-04-09 10:59:34 UTC using RuboCop version 1.67.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 9 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Exclude: + - 'lib/puppet_forge/connection.rb' + - 'lib/puppet_forge/connection/connection_failure.rb' + - 'lib/puppet_forge/lazy_accessors.rb' + - 'lib/puppet_forge/v3/base/paginated_collection.rb' + - 'lib/puppet_forge/v3/metadata.rb' + +# Offense count: 3 +# Configuration parameters: AllowedMethods. +# AllowedMethods: enums +Lint/ConstantDefinitionInBlock: + Exclude: + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + +# Offense count: 1 +# Configuration parameters: AllowedParentClasses. +Lint/MissingSuper: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, BlockForwardingName. +# SupportedStyles: anonymous, explicit +Naming/BlockForwarding: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + +# Offense count: 1 +# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# ForbiddenPrefixes: is_, has_, have_ +# AllowedMethods: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - 'spec/**/*' + - 'lib/puppet_forge/v3/base.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Performance/BindCall: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Performance/StringInclude: + Exclude: + - 'lib/puppet_forge/v3/metadata.rb' + +# Offense count: 16 +# Configuration parameters: Prefixes, AllowedPatterns. +# Prefixes: when, with, without +RSpec/ContextWording: + Exclude: + - 'spec/unit/forge/v3/base_spec.rb' + - 'spec/unit/forge/v3/metadata_spec.rb' + - 'spec/unit/forge/v3/release_spec.rb' + +# Offense count: 81 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: SkipBlocks, EnforcedStyle, OnlyStaticConstants. +# SupportedStyles: described_class, explicit +RSpec/DescribedClass: + Exclude: + - 'spec/unit/forge/connection_spec.rb' + - 'spec/unit/forge/lru_cache_spec.rb' + - 'spec/unit/forge/unpacker_spec.rb' + - 'spec/unit/forge/v3/base/paginated_collection_spec.rb' + - 'spec/unit/forge/v3/base_spec.rb' + - 'spec/unit/forge/v3/metadata_spec.rb' + - 'spec/unit/forge/v3/module_spec.rb' + - 'spec/unit/forge/v3/release_spec.rb' + - 'spec/unit/forge/v3/user_spec.rb' + - 'spec/unit/puppet_forge_spec.rb' + +# Offense count: 23 +# Configuration parameters: CountAsOne. +RSpec/ExampleLength: + Max: 12 + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: CustomTransform, IgnoredWords, DisallowedExamples. +# DisallowedExamples: works +RSpec/ExampleWording: + Exclude: + - 'spec/unit/forge/v3/base_spec.rb' + +# Offense count: 3 +RSpec/ExpectInHook: + Exclude: + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + +# Offense count: 3 +# Configuration parameters: AssignmentOnly. +RSpec/InstanceVariable: + Exclude: + - 'spec/unit/forge/lru_cache_spec.rb' + - 'spec/unit/forge/v3/base_spec.rb' + +# Offense count: 3 +RSpec/LeakyConstantDeclaration: + Exclude: + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + +# Offense count: 39 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: have_received, receive +RSpec/MessageSpies: + Exclude: + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + - 'spec/unit/forge/tar/mini_spec.rb' + - 'spec/unit/forge/unpacker_spec.rb' + - 'spec/unit/forge/v3/module_spec.rb' + - 'spec/unit/forge/v3/release_spec.rb' + +# Offense count: 40 +RSpec/MultipleExpectations: + Max: 6 + +# Offense count: 2 +# Configuration parameters: AllowSubject. +RSpec/MultipleMemoizedHelpers: + Max: 7 + +# Offense count: 130 +# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. +# SupportedStyles: always, named_only +RSpec/NamedSubject: + Exclude: + - 'spec/unit/forge/connection/connection_failure_spec.rb' + - 'spec/unit/forge/connection_spec.rb' + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + - 'spec/unit/forge/lru_cache_spec.rb' + - 'spec/unit/forge/v3/base/paginated_collection_spec.rb' + - 'spec/unit/forge/v3/metadata_spec.rb' + +# Offense count: 27 +# Configuration parameters: AllowedGroups. +RSpec/NestedGroups: + Max: 5 + +# Offense count: 2 +# Configuration parameters: AllowedPatterns. +# AllowedPatterns: ^expect_, ^assert_ +RSpec/NoExpectationExample: + Exclude: + - 'spec/unit/forge/tar/mini_spec.rb' + - 'spec/unit/forge/v3/metadata_spec.rb' + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: Strict, EnforcedStyle, AllowedExplicitMatchers. +# SupportedStyles: inflected, explicit +RSpec/PredicateMatcher: + Exclude: + - 'spec/unit/forge/lru_cache_spec.rb' + +# Offense count: 4 +# This cop supports unsafe autocorrection (--autocorrect-all). +RSpec/ReceiveMessages: + Exclude: + - 'spec/unit/forge/v3/release_spec.rb' + +# Offense count: 15 +# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata. +# Include: **/*_spec.rb +RSpec/SpecFilePathFormat: + Exclude: + - '**/spec/routing/**/*' + - 'spec/unit/forge/connection/connection_failure_spec.rb' + - 'spec/unit/forge/connection_spec.rb' + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + - 'spec/unit/forge/lru_cache_spec.rb' + - 'spec/unit/forge/tar/mini_spec.rb' + - 'spec/unit/forge/tar_spec.rb' + - 'spec/unit/forge/unpacker_spec.rb' + - 'spec/unit/forge/util_spec.rb' + - 'spec/unit/forge/v3/base/paginated_collection_spec.rb' + - 'spec/unit/forge/v3/base_spec.rb' + - 'spec/unit/forge/v3/metadata_spec.rb' + - 'spec/unit/forge/v3/module_spec.rb' + - 'spec/unit/forge/v3/release_spec.rb' + - 'spec/unit/forge/v3/user_spec.rb' + +# Offense count: 4 +# This cop supports unsafe autocorrection (--autocorrect-all). +RSpec/StringAsInstanceDoubleConstant: + Exclude: + - 'spec/spec_helper.rb' + - 'spec/unit/forge/v3/release_spec.rb' + +# Offense count: 13 +RSpec/StubbedMock: + Exclude: + - 'spec/unit/forge/tar/mini_spec.rb' + - 'spec/unit/forge/unpacker_spec.rb' + - 'spec/unit/forge/v3/release_spec.rb' + +# Offense count: 3 +RSpec/SubjectStub: + Exclude: + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + +# Offense count: 4 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: . +# SupportedStyles: constant, string +RSpec/VerifiedDoubleReference: + EnforcedStyle: string + +# Offense count: 8 +# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. +RSpec/VerifiedDoubles: + Exclude: + - 'spec/unit/forge/tar/mini_spec.rb' + - 'spec/unit/forge/unpacker_spec.rb' + - 'spec/unit/forge/v3/release_spec.rb' + +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: nested, compact +Style/ClassAndModuleChildren: + Exclude: + - 'spec/unit/forge/lazy_accessors_spec.rb' + - 'spec/unit/forge/lazy_relations_spec.rb' + +# Offense count: 8 +# Configuration parameters: AllowedConstants. +Style/Documentation: + Exclude: + - 'spec/**/*' + - 'test/**/*' + - 'lib/puppet_forge.rb' + - 'lib/puppet_forge/error.rb' + - 'lib/puppet_forge/tar.rb' + - 'lib/puppet_forge/tar/mini.rb' + - 'lib/puppet_forge/unpacker.rb' + - 'lib/puppet_forge/util.rb' + +# Offense count: 39 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Enabled: false + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. +Style/GuardClause: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowedReceivers. +# AllowedReceivers: Thread.current +Style/HashEachMethods: + Exclude: + - 'lib/puppet_forge/v3/base.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'lib/puppet_forge/error.rb' + - 'lib/puppet_forge/tar/mini.rb' + +# Offense count: 2 +Style/MissingRespondToMissing: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + - 'lib/puppet_forge/v3/metadata.rb' + +# Offense count: 5 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: literals, strict +Style/MutableConstant: + Exclude: + - 'lib/puppet_forge.rb' + - 'lib/puppet_forge/tar/mini.rb' + - 'lib/puppet_forge/v3/base.rb' + - 'lib/puppet_forge/v3/metadata.rb' + - 'lib/puppet_forge/version.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. +# SupportedStyles: predicate, comparison +Style/NumericPredicate: + Exclude: + - 'spec/**/*' + - 'lib/puppet_forge/lru_cache.rb' + +# Offense count: 6 +# Configuration parameters: AllowedMethods. +# AllowedMethods: respond_to_missing? +Style/OptionalBooleanParameter: + Exclude: + - 'lib/puppet_forge/v3/base.rb' + - 'lib/puppet_forge/v3/metadata.rb' + - 'lib/puppet_forge/v3/release.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: short, verbose +Style/PreferredHashMethods: + Exclude: + - 'lib/puppet_forge/v3/base.rb' + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle, AllowedCompactTypes. +# SupportedStyles: compact, exploded +Style/RaiseArgs: + Exclude: + - 'lib/puppet_forge/v3/release.rb' + +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/RedundantInterpolation: + Exclude: + - 'lib/puppet_forge/lazy_relations.rb' + - 'lib/puppet_forge/v3/base.rb' + +# Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowMultipleReturnValues. +Style/RedundantReturn: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/RedundantSort: + Exclude: + - 'lib/puppet_forge/unpacker.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Style/RescueModifier: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/SlicingWithRange: + Exclude: + - 'lib/puppet_forge/v3/release.rb' + +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: Mode. +Style/StringConcatenation: + Exclude: + - 'lib/puppet_forge/v3/metadata.rb' + - 'spec/unit/forge/unpacker_spec.rb' + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +Style/SuperArguments: + Exclude: + - 'lib/puppet_forge/lazy_accessors.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments. +# AllowedMethods: define_method +Style/SymbolProc: + Exclude: + - 'spec/unit/forge/v3/base/paginated_collection_spec.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/ZeroLengthPredicate: + Exclude: + - 'lib/puppet_forge/v3/release.rb' + +# Offense count: 13 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 255 diff --git a/Rakefile b/Rakefile index 2995527..26b3653 100644 --- a/Rakefile +++ b/Rakefile @@ -1 +1,7 @@ -require "bundler/gem_tasks" +require 'bundler/gem_tasks' + +begin + require 'voxpupuli/rubocop/rake' +rescue LoadError + # the voxpupuli-rubocop gem is optional +end diff --git a/lib/puppet_forge/connection.rb b/lib/puppet_forge/connection.rb index 564749c..454dff8 100644 --- a/lib/puppet_forge/connection.rb +++ b/lib/puppet_forge/connection.rb @@ -20,7 +20,6 @@ module PuppetForge # # @api private module Connection - attr_writer :conn AUTHORIZATION_TOKEN_REGEX = /^[a-f0-9]{64}$/ @@ -32,11 +31,10 @@ def self.authorization=(token) # RK-229 Specific Workaround # Capture instance specific proxy setting if defined. - if defined?(PuppetForge::V3::Base) - if old_conn = PuppetForge::V3::Base.instance_variable_get(:@conn) - self.proxy = old_conn.proxy.uri.to_s if old_conn.proxy - end - end + return unless defined?(PuppetForge::V3::Base) + return unless old_conn = PuppetForge::V3::Base.instance_variable_get(:@conn) + + self.proxy = old_conn.proxy.uri.to_s if old_conn.proxy end def self.authorization @@ -79,7 +77,6 @@ def conn(reset_connection = nil, opts = {}) # @param opts [Hash] Hash of connection options for Faraday def default_connection(opts = {}) - begin # Use Typhoeus if available. Gem::Specification.find_by_name('typhoeus', '~> 1.4') @@ -100,10 +97,10 @@ def default_connection(opts = {}) # @return [Faraday::Connection] def make_connection(url, adapter_args = nil, opts = {}) adapter_args ||= [Faraday.default_adapter] - options = { :headers => { :user_agent => USER_AGENT } }.merge(opts) + options = { headers: { user_agent: USER_AGENT } }.merge(opts) if token = PuppetForge::Connection.authorization - options[:headers][:authorization] = token =~ AUTHORIZATION_TOKEN_REGEX ? "Bearer #{token}" : token + options[:headers][:authorization] = AUTHORIZATION_TOKEN_REGEX.match?(token) ? "Bearer #{token}" : token end if lang = PuppetForge::Connection.accept_language @@ -116,7 +113,7 @@ def make_connection(url, adapter_args = nil, opts = {}) Faraday.new(url, options) do |builder| builder.use Faraday::FollowRedirects::Middleware - builder.response(:json, :content_type => /\bjson$/, :parser_options => { :symbolize_names => true }) + builder.response(:json, content_type: /\bjson$/, parser_options: { symbolize_names: true }) builder.response(:raise_error) builder.use(:connection_failure) diff --git a/lib/puppet_forge/connection/connection_failure.rb b/lib/puppet_forge/connection/connection_failure.rb index 1c2ce7a..b38a346 100644 --- a/lib/puppet_forge/connection/connection_failure.rb +++ b/lib/puppet_forge/connection/connection_failure.rb @@ -9,11 +9,12 @@ def call(env) @app.call(env) rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e baseurl = env[:url].dup - errmsg = "Unable to connect to %{scheme}://%{host}" % { scheme: baseurl.scheme, host: baseurl.host } + errmsg = format('Unable to connect to %s://%s', scheme: baseurl.scheme, host: baseurl.host) if proxy = env[:request][:proxy] - errmsg << " (using proxy %{proxy})" % { proxy: proxy.uri.to_s } + errmsg << (format(' (using proxy %s)', proxy: proxy.uri.to_s)) end - errmsg << " (for request %{path_query}): %{message}" % { message: e.message, path_query: baseurl.request_uri } + errmsg << (format(' (for request %s): %s', message: e.message, + path_query: baseurl.request_uri)) m = Faraday::ConnectionFailed.new(errmsg) m.set_backtrace(e.backtrace) raise m @@ -22,4 +23,4 @@ def call(env) end end -Faraday::Middleware.register_middleware(:connection_failure => PuppetForge::Connection::ConnectionFailure) +Faraday::Middleware.register_middleware(connection_failure: PuppetForge::Connection::ConnectionFailure) diff --git a/lib/puppet_forge/error.rb b/lib/puppet_forge/error.rb index 97f636a..5f8cd07 100644 --- a/lib/puppet_forge/error.rb +++ b/lib/puppet_forge/error.rb @@ -3,7 +3,8 @@ module PuppetForge class Error < RuntimeError attr_accessor :original - def initialize(message, original=nil) + + def initialize(message, original = nil) super(message) @original = original end @@ -16,19 +17,18 @@ class InvalidPathInPackageError < PuppetForge::Error def initialize(options) @entry_path = options[:entry_path] @directory = options[:directory] - super "Attempt to install file into #{@entry_path.inspect} under #{@directory.inspect}" + super("Attempt to install file into #{@entry_path.inspect} under #{@directory.inspect}") end def multiline - <<-MSG.strip -Could not install package - Package attempted to install file into - #{@entry_path.inspect} under #{@directory.inspect}. + <<~MSG.strip + Could not install package + Package attempted to install file into + #{@entry_path.inspect} under #{@directory.inspect}. MSG end end - class ErrorWithDetail < PuppetForge::Error def self.from_response(response) body = JSON.parse(response[:body]) diff --git a/lib/puppet_forge/lazy_accessors.rb b/lib/puppet_forge/lazy_accessors.rb index f066c18..4754f1e 100644 --- a/lib/puppet_forge/lazy_accessors.rb +++ b/lib/puppet_forge/lazy_accessors.rb @@ -1,5 +1,4 @@ module PuppetForge - # When dealing with a remote service, it's reasonably common to receive only # a partial representation of the underlying object, with additional data # available upon request. PuppetForge, by default, provides a convenient interface @@ -8,7 +7,6 @@ module PuppetForge # interface for both local and remote attriibutes, this module replaces the # default behavior with an "updatable" interface. module LazyAccessors - # Callback for module inclusion. # # On each lazy class we'll store a reference to a Module, which will act as @@ -25,7 +23,7 @@ def self.included(base) # Provide class name for object # def class_name - self.class.name.split("::").last.downcase + self.class.name.split('::').last.downcase end # Override the default #inspect behavior. @@ -35,7 +33,7 @@ def class_name # implementation simply reports the contents of the attributes hash. def inspect attrs = attributes.map do |x, y| - [ x, y ].join('=') + [x, y].join('=') end "#<#{self.class}(#{uri}) #{attrs.join(' ')}>" end @@ -82,17 +80,14 @@ def fetch klass = self.class - response = klass.request("#{self.class_name}s/#{self.slug}") - if @_fetch = response.success? - self.send(:initialize, response.body) - end + response = klass.request("#{class_name}s/#{slug}") + send(:initialize, response.body) if @_fetch = response.success? - return self + self end # A Module subclass for attribute accessors. class AccessorContainer < Module - # Creating a new instance of this class will automatically include itself # into the provided class. # @@ -112,17 +107,17 @@ def add_attributes(keys) keys.each do |key| next if methods.include?(name = key) - define_method("#{name}") do + define_method(:"#{name}") do fetch unless has_attribute?(name) attribute(name) end - define_method("#{name}?") do + define_method(:"#{name}?") do fetch unless has_attribute?(name) has_attribute?(name) end - define_method("#{name}=") do |value| + define_method(:"#{name}=") do |value| fetch unless has_attribute?(name) attributes[name] = value end diff --git a/lib/puppet_forge/lazy_relations.rb b/lib/puppet_forge/lazy_relations.rb index fdd9f0e..96743ac 100644 --- a/lib/puppet_forge/lazy_relations.rb +++ b/lib/puppet_forge/lazy_relations.rb @@ -1,12 +1,10 @@ module PuppetForge - # This module provides convenience accessors for related resources. Related # classes will include {LazyAccessors}, allowing them to transparently fetch # fetch more complete representations from the API. # # @see LazyAccessors module LazyRelations - # Mask mistaken `include` calls by transparently extending this class. # @private def self.included(base) @@ -14,21 +12,20 @@ def self.included(base) end def parent - if self.is_a? Class - class_name = self.name - else - class_name = self.class.name - end + class_name = if is_a? Class + name + else + self.class.name + end # Get the name of the version module - version = class_name.split("::")[-2] + version = class_name.split('::')[-2] - if version.nil? - raise RuntimeError, "Unable to determine the parent PuppetForge version module" - end + raise 'Unable to determine the parent PuppetForge version module' if version.nil? PuppetForge.const_get(version) end + # @!macro [attach] lazy # @!method $1 # Returns a lazily-loaded $1 proxy. To eagerly load this $1, call @@ -54,7 +51,6 @@ def lazy(name, class_name = name) @_lazy ||= {} @_lazy[name] ||= begin - klass ||= parent.const_get(class_name) klass.send(:include, PuppetForge::LazyAccessors) diff --git a/lib/puppet_forge/lru_cache.rb b/lib/puppet_forge/lru_cache.rb index 43df516..ff52dc4 100644 --- a/lib/puppet_forge/lru_cache.rb +++ b/lib/puppet_forge/lru_cache.rb @@ -19,7 +19,7 @@ def self.new_key(*string_args) # be overridden by setting the PUPPET_FORGE_MAX_CACHE_SIZE environment # variable. def initialize(max_size = 30) - raise ArgumentError, "max_size must be a positive integer" unless max_size.is_a?(Integer) && max_size > 0 + raise ArgumentError, 'max_size must be a positive integer' unless max_size.is_a?(Integer) && max_size > 0 @max_size = ENV['PUPPET_FORGE_MAX_CACHE_SIZE'] ? ENV['PUPPET_FORGE_MAX_CACHE_SIZE'].to_i : max_size @cache = {} @@ -32,15 +32,15 @@ def initialize(max_size = 30) # @return [Object] the cached value for the given key, or nil if # the key is not present in the cache. def get(key) - if cache.key?(key) - semaphore.synchronize do - # If the key is present, move it to the front of the LRU - # list. - lru.delete(key) - lru.unshift(key) - end - cache[key] + return unless cache.key?(key) + + semaphore.synchronize do + # If the key is present, move it to the front of the LRU + # list. + lru.delete(key) + lru.unshift(key) end + cache[key] end # Adds a value to the cache. diff --git a/lib/puppet_forge/tar.rb b/lib/puppet_forge/tar.rb index 1d743c2..8aac182 100644 --- a/lib/puppet_forge/tar.rb +++ b/lib/puppet_forge/tar.rb @@ -1,4 +1,3 @@ - module PuppetForge class Tar require 'puppet_forge/tar/mini' diff --git a/lib/puppet_forge/tar/mini.rb b/lib/puppet_forge/tar/mini.rb index 18d995b..1a193e1 100644 --- a/lib/puppet_forge/tar/mini.rb +++ b/lib/puppet_forge/tar/mini.rb @@ -4,7 +4,6 @@ module PuppetForge class Tar class Mini - SYMLINK_FLAGS = [2] VALID_TAR_FLAGS = (0..7) @@ -15,7 +14,7 @@ def unpack(sourcefile, destdir) file_lists = {} Zlib::GzipReader.open(sourcefile) do |reader| file_lists = validate_files(reader) - Minitar.unpack(reader, destdir, file_lists[:valid]) do |action, name, stats| + Minitar.unpack(reader, destdir, file_lists[:valid]) do |action, name, _stats| case action when :file_done FileUtils.chmod('u+rw,g+r,a-st', "#{destdir}/#{name}") @@ -27,7 +26,7 @@ def unpack(sourcefile, destdir) end end end - dirlist.each {|d| File.chmod(0755, d)} + dirlist.each { |d| File.chmod(0o755, d) } file_lists end @@ -49,12 +48,12 @@ def pack(sourcedir, destfile) # @param tarfile name of the tarfile # @return [Hash{:symbol => Array}] a hash with file-category keys pointing to lists of filenames. def validate_files(tarfile) - file_lists = {:valid => [], :invalid => [], :symlinks => []} + file_lists = { valid: [], invalid: [], symlinks: [] } Minitar.open(tarfile).each do |entry| flag = entry.typeflag - if flag.nil? || flag =~ /[[:digit:]]/ && SYMLINK_FLAGS.include?(flag.to_i) + if flag.nil? || (flag =~ /[[:digit:]]/ && SYMLINK_FLAGS.include?(flag.to_i)) file_lists[:symlinks] << entry.full_name - elsif flag.nil? || flag =~ /[[:digit:]]/ && VALID_TAR_FLAGS.include?(flag.to_i) + elsif flag.nil? || (flag =~ /[[:digit:]]/ && VALID_TAR_FLAGS.include?(flag.to_i)) file_lists[:valid] << entry.full_name else file_lists[:invalid] << entry.full_name @@ -65,17 +64,15 @@ def validate_files(tarfile) def validate_entry(destdir, path) if Pathname.new(path).absolute? - raise PuppetForge::InvalidPathInPackageError, :entry_path => path, :directory => destdir + raise PuppetForge::InvalidPathInPackageError, entry_path: path, directory: destdir end path = File.expand_path File.join(destdir, path) - if path !~ /\A#{Regexp.escape destdir}/ - raise PuppetForge::InvalidPathInPackageError, :entry_path => path, :directory => destdir - end + return if /\A#{Regexp.escape destdir}/.match?(path) + + raise PuppetForge::InvalidPathInPackageError, entry_path: path, directory: destdir end end end - end - diff --git a/lib/puppet_forge/unpacker.rb b/lib/puppet_forge/unpacker.rb index b27bd5f..43880bb 100644 --- a/lib/puppet_forge/unpacker.rb +++ b/lib/puppet_forge/unpacker.rb @@ -11,7 +11,7 @@ class Unpacker # @return [Hash{:symbol => Array}] a hash with file-category keys pointing to lists of filenames. # The categories are :valid, :invalid and :symlink def self.unpack(filename, target, tmpdir) - inst = self.new(filename, target, tmpdir) + inst = new(filename, target, tmpdir) file_lists = inst.unpack inst.move_into(Pathname.new(target)) file_lists @@ -23,7 +23,7 @@ def self.unpack(filename, target, tmpdir) # @param source [Pathname] source of the permissions # @param target [Pathname] target of the permissions change def self.harmonize_ownership(source, target) - FileUtils.chown_R(source.stat.uid, source.stat.gid, target) + FileUtils.chown_R(source.stat.uid, source.stat.gid, target) end # @param filename [String] the file to unpack @@ -36,11 +36,9 @@ def initialize(filename, target, tmpdir) # @api private def unpack - begin - PuppetForge::Tar.instance.unpack(@filename, @tmpdir) - rescue PuppetForge::ExecutionFailure => e - raise RuntimeError, "Could not extract contents of module archive: #{e.message}" - end + PuppetForge::Tar.instance.unpack(@filename, @tmpdir) + rescue PuppetForge::ExecutionFailure => e + raise "Could not extract contents of module archive: #{e.message}" end # @api private @@ -58,11 +56,9 @@ def root_dir # Grab the first directory containing a metadata.json file metadata_file = Dir["#{@tmpdir}/**/metadata.json"].sort_by(&:length)[0] - if metadata_file - @root_dir = Pathname.new(metadata_file).dirname - else - raise "No valid metadata.json found!" - end + raise 'No valid metadata.json found!' unless metadata_file + + @root_dir = Pathname.new(metadata_file).dirname end end end diff --git a/lib/puppet_forge/util.rb b/lib/puppet_forge/util.rb index 54d819a..86af123 100644 --- a/lib/puppet_forge/util.rb +++ b/lib/puppet_forge/util.rb @@ -3,7 +3,7 @@ module PuppetForge class Util def self.version_valid?(version) - return SemanticPuppet::Version.valid?(version) + SemanticPuppet::Version.valid?(version) end end end diff --git a/lib/puppet_forge/v3.rb b/lib/puppet_forge/v3.rb index b5f192d..2805925 100644 --- a/lib/puppet_forge/v3.rb +++ b/lib/puppet_forge/v3.rb @@ -1,5 +1,4 @@ module PuppetForge - # Models specific to the Puppet Forge's v3 API. module V3 # Normalize a module name to use a hyphen as the separator between the diff --git a/lib/puppet_forge/v3/base.rb b/lib/puppet_forge/v3/base.rb index 12fd8e7..05aefea 100644 --- a/lib/puppet_forge/v3/base.rb +++ b/lib/puppet_forge/v3/base.rb @@ -8,7 +8,6 @@ module PuppetForge module V3 - # Acts as the base class for all PuppetForge::V3::* models. # # @api private @@ -22,10 +21,10 @@ def initialize(json_response) end def orm_resp_item(json_response) - json_response.each do |key, value| + json_response.each do |key, _value| unless respond_to? key - define_singleton_method("#{key}") { @attributes[key] } - define_singleton_method("#{key}=") { |val| @attributes[key] = val } + define_singleton_method(:"#{key}") { @attributes[key] } + define_singleton_method(:"#{key}=") { |val| @attributes[key] = val } end end end @@ -40,15 +39,12 @@ def attribute(name) @attributes[:"#{name}"] end - def attributes - @attributes - end + attr_reader :attributes class << self - include PuppetForge::Connection - API_VERSION = "v3" + API_VERSION = 'v3' def api_version API_VERSION @@ -71,15 +67,13 @@ def request(resource, item = nil, params = {}, reset_connection = false, conn_op return cached unless cached.nil? conn(reset_connection, conn_opts) if reset_connection - unless conn.url_prefix.to_s =~ /^#{PuppetForge.host}/ - conn.url_prefix = "#{PuppetForge.host}" - end + conn.url_prefix = "#{PuppetForge.host}" unless /^#{PuppetForge.host}/.match?(conn.url_prefix.to_s) - if item.nil? - uri_path = "v3/#{resource}" - else - uri_path = "v3/#{resource}/#{item}" - end + uri_path = if item.nil? + "v3/#{resource}" + else + "v3/#{resource}/#{item}" + end # The API expects a space separated string. This allows the user to invoke it with a more natural feeling array. params['endorsements'] = params['endorsements'].join(' ') if params['endorsements'].is_a? Array @@ -93,9 +87,9 @@ def request(resource, item = nil, params = {}, reset_connection = false, conn_op def find_request(slug, reset_connection = false, conn_opts = {}) return nil if slug.nil? - resp = request("#{self.name.split("::").last.downcase}s", slug, {}, reset_connection, conn_opts) + resp = request("#{name.split('::').last.downcase}s", slug, {}, reset_connection, conn_opts) - self.new(resp.body) + new(resp.body) end def find(slug) @@ -108,7 +102,7 @@ def find_stateless(slug, conn_opts = {}) # @private def where_request(params, reset_connection = false, conn_opts = {}) - resp = request("#{self.name.split("::").last.downcase}s", nil, params, reset_connection, conn_opts) + resp = request("#{name.split('::').last.downcase}s", nil, params, reset_connection, conn_opts) new_collection(resp) end @@ -156,11 +150,11 @@ def convert_plus_to_space(str) # @private def split_uri_path(uri_path) - all, resource, params = /(?:\/v3\/)([^\/]+)(?:\?)(.*)/.match(uri_path).to_a + _, resource, params = %r{(?:/v3/)([^/]+)(?:\?)(.*)}.match(uri_path).to_a params = convert_plus_to_space(params).split('&') - param_hash = Hash.new + param_hash = {} params.each do |param| key, val = param.split('=') param_hash[key] = val diff --git a/lib/puppet_forge/v3/base/paginated_collection.rb b/lib/puppet_forge/v3/base/paginated_collection.rb index c7bf0b9..7e92145 100644 --- a/lib/puppet_forge/v3/base/paginated_collection.rb +++ b/lib/puppet_forge/v3/base/paginated_collection.rb @@ -1,10 +1,8 @@ module PuppetForge module V3 class Base - # Enables navigation of the Forge API's paginated datasets. class PaginatedCollection < Array - # Default pagination limit for API request LIMIT = 20 @@ -13,7 +11,7 @@ class PaginatedCollection < Array # @param data [Array] the current data page # @param metadata [Hash<(:limit, :total, :offset)>] page metadata # @param errors [Object] errors for the page request - def initialize(klass, data = [], metadata = {:total => 0, :offset => 0, :limit => LIMIT}, errors = nil) + def initialize(klass, data = [], metadata = { total: 0, offset: 0, limit: LIMIT }, errors = nil) super() @metadata = metadata @errors = errors @@ -50,11 +48,11 @@ def unpaginated # @return [Integer] the maximum size of any page in this dataset # @!method offset # @return [Integer] the offset for the current page - [ :total, :limit, :offset ].each do |info| + %i[total limit offset].each do |info| define_method(info) { @metadata[info] } end - [ :next, :previous ].each do |link| + %i[next previous].each do |link| # @!method next # Returns the next page if a next page exists. # @return [PaginatedCollection, nil] the next page @@ -63,6 +61,7 @@ def unpaginated # @return [PaginatedCollection, nil] the previous page define_method(link) do return unless path = @metadata[link] + @klass.get_collection(path) end @@ -72,7 +71,7 @@ def unpaginated # @!method previous_url # Returns the url of the previous page if a previous page exists. # @return [String, nil] the previous page's url - define_method("#{link}_url") do + define_method(:"#{link}_url") do @metadata[link] end end diff --git a/lib/puppet_forge/v3/metadata.rb b/lib/puppet_forge/v3/metadata.rb index a6e485f..075a8bf 100644 --- a/lib/puppet_forge/v3/metadata.rb +++ b/lib/puppet_forge/v3/metadata.rb @@ -8,18 +8,17 @@ module V3 # This class provides a data structure representing a module's metadata. # @api private class Metadata - attr_accessor :module_name DEFAULTS = { - 'name' => nil, - 'version' => nil, - 'author' => nil, - 'summary' => nil, - 'license' => 'Apache-2.0', - 'source' => '', + 'name' => nil, + 'version' => nil, + 'author' => nil, + 'summary' => nil, + 'license' => 'Apache-2.0', + 'source' => '', 'project_page' => nil, - 'issues_url' => nil, + 'issues_url' => nil, 'dependencies' => Set.new.freeze, } @@ -36,11 +35,12 @@ def dashed_name # Returns a string that uniquely represents this version of this module. def release_name return nil unless @data['name'] && @data['version'] - [ dashed_name, @data['version'] ].join('-') + + [dashed_name, @data['version']].join('-') end - alias :name :module_name - alias :full_module_name :dashed_name + alias name module_name + alias full_module_name dashed_name # Merges the current set of metadata with another metadata hash. This # method also handles the validation of module names and versions, in an @@ -52,18 +52,21 @@ def update(data, with_dependencies = true) merge_dependencies(data) if with_dependencies && data['dependencies'] @data.merge!(data) - return self + self end # Validates the name and version_requirement for a dependency, then creates # the Dependency and adds it. # Returns the Dependency that was added. - def add_dependency(name, version_requirement=nil, repository=nil) + def add_dependency(name, version_requirement = nil, repository = nil) validate_name(name) validate_version_range(version_requirement) if version_requirement - if dup = @data['dependencies'].find { |d| d.full_module_name == name && d.version_requirement != version_requirement } - raise ArgumentError, "Dependency conflict for #{full_module_name}: Dependency #{name} was given conflicting version requirements #{version_requirement} and #{dup.version_requirement}. Verify that there are no duplicates in the metadata.json or the Modulefile." + if dup = @data['dependencies'].find do |d| + d.full_module_name == name && d.version_requirement != version_requirement + end + raise ArgumentError, + "Dependency conflict for #{full_module_name}: Dependency #{name} was given conflicting version requirements #{version_requirement} and #{dup.version_requirement}. Verify that there are no duplicates in the metadata.json or the Modulefile." end dep = Dependency.new(name, version_requirement, repository) @@ -91,13 +94,17 @@ def dependencies def to_hash @data end - alias :to_data_hash :to_hash + alias to_data_hash to_hash - def to_json + def to_json(*_args) data = @data.dup.merge('dependencies' => dependencies) contents = data.keys.map do |k| - value = (JSON.pretty_generate(data[k]) rescue data[k].to_json) + value = begin + JSON.pretty_generate(data[k]) + rescue StandardError + data[k].to_json + end "#{k.to_json}: #{value}" end @@ -107,6 +114,7 @@ def to_json # Expose any metadata keys as callable reader methods. def method_missing(name, *args) return @data[name.to_s] if @data.key? name.to_s + super end @@ -115,7 +123,7 @@ def method_missing(name, *args) # Do basic validation and parsing of the name parameter. def process_name(data) validate_name(data['name']) - author, @module_name = data['name'].split(/[-\/]/, 2) + author, @module_name = data['name'].split(%r{[-/]}, 2) data['author'] ||= author if @data['author'] == DEFAULTS['author'] end @@ -129,21 +137,20 @@ def process_version(data) # GitHub, we can predict sensible defaults for both project_page and # issues_url. def process_source(data) - if data['source'] =~ %r[://] - source_uri = URI.parse(data['source']) - else - source_uri = URI.parse("http://#{data['source']}") - end + source_uri = if %r{://}.match?(data['source']) + URI.parse(data['source']) + else + URI.parse("http://#{data['source']}") + end - if source_uri.host =~ /^(www\.)?github\.com$/ + if /^(www\.)?github\.com$/.match?(source_uri.host) source_uri.scheme = 'https' source_uri.path.sub!(/\.git$/, '') data['project_page'] ||= @data['project_page'] || source_uri.to_s - data['issues_url'] ||= @data['issues_url'] || source_uri.to_s.sub(/\/*$/, '') + '/issues' + data['issues_url'] ||= @data['issues_url'] || (source_uri.to_s.sub(%r{/*$}, '') + '/issues') end - rescue URI::Error - return + nil end # Validates and parses the dependencies. @@ -158,21 +165,21 @@ def merge_dependencies(data) # Validates that the given module name is both namespaced and well-formed. def validate_name(name) - return if name =~ /\A[a-z0-9]+[-\/][a-z][a-z0-9_]*\Z/i + return if %r{\A[a-z0-9]+[-/][a-z][a-z0-9_]*\Z}i.match?(name) - namespace, modname = name.split(/[-\/]/, 2) + namespace, modname = name.split(%r{[-/]}, 2) modname = :namespace_missing if namespace == '' err = case modname - when nil, '', :namespace_missing - "the field must be a namespaced module name" - when /[^a-z0-9_]/i - "the module name contains non-alphanumeric (or underscore) characters" - when /^[^a-z]/i - "the module name must begin with a letter" - else - "the namespace contains non-alphanumeric characters" - end + when nil, '', :namespace_missing + 'the field must be a namespaced module name' + when /[^a-z0-9_]/i + 'the module name contains non-alphanumeric (or underscore) characters' + when /^[^a-z]/i + 'the module name must begin with a letter' + else + 'the namespace contains non-alphanumeric characters' + end raise ArgumentError, "Invalid 'name' field in metadata.json: #{err}" end @@ -181,7 +188,7 @@ def validate_name(name) def validate_version(version) return if SemanticPuppet::Version.valid?(version) - err = "version string cannot be parsed as a valid Semantic Version" + err = 'version string cannot be parsed as a valid Semantic Version' raise ArgumentError, "Invalid 'version' field in metadata.json: #{err}" end @@ -194,4 +201,3 @@ def validate_version_range(version_range) end end end - diff --git a/lib/puppet_forge/v3/module.rb b/lib/puppet_forge/v3/module.rb index b3b6d39..21c38ef 100644 --- a/lib/puppet_forge/v3/module.rb +++ b/lib/puppet_forge/v3/module.rb @@ -4,7 +4,6 @@ module PuppetForge module V3 - # Models a Puppet Module hosted on the Forge. class Module < Base lazy :owner, 'User' diff --git a/lib/puppet_forge/v3/release.rb b/lib/puppet_forge/v3/release.rb index 5a85639..9aaa2f8 100755 --- a/lib/puppet_forge/v3/release.rb +++ b/lib/puppet_forge/v3/release.rb @@ -6,7 +6,6 @@ module PuppetForge module V3 - # Models a specific release version of a Puppet Module on the Forge. class Release < Base lazy :module, 'Module' @@ -30,13 +29,12 @@ def download(path) resp = self.class.conn.get(download_url) path.open('wb') { |fh| fh.write(resp.body) } rescue Faraday::ResourceNotFound => e - raise PuppetForge::ReleaseNotFound, "The module release #{slug} does not exist on #{self.class.conn.url_prefix}.", e.backtrace + raise PuppetForge::ReleaseNotFound, + "The module release #{slug} does not exist on #{self.class.conn.url_prefix}.", e.backtrace rescue Faraday::ClientError => e - if e.response && e.response[:status] == 403 - raise PuppetForge::ReleaseForbidden.from_response(e.response) - else - raise e - end + raise PuppetForge::ReleaseForbidden.from_response(e.response) if e.response && e.response[:status] == 403 + + raise e end # Uploads the tarbarll to the forge @@ -78,20 +76,20 @@ def self.upload(path) # @return [void] def verify(path, allow_md5 = true) checksum = - if self.respond_to?(:file_sha256) && !self.file_sha256.nil? && !self.file_sha256.size.zero? + if respond_to?(:file_sha256) && !file_sha256.nil? && !file_sha256.size.zero? { - type: "SHA-256", - expected: self.file_sha256, + type: 'SHA-256', + expected: file_sha256, actual: Digest::SHA256.file(path).hexdigest, } elsif allow_md5 { - type: "MD5", - expected: self.file_md5, + type: 'MD5', + expected: file_md5, actual: Digest::MD5.file(path).hexdigest, } else - raise PuppetForge::Error.new("Cannot verify module release: SHA-256 checksum is not available in API response and fallback to MD5 has been forbidden.") + raise PuppetForge::Error.new('Cannot verify module release: SHA-256 checksum is not available in API response and fallback to MD5 has been forbidden.') end return if checksum[:expected] == checksum[:actual] diff --git a/lib/puppet_forge/v3/user.rb b/lib/puppet_forge/v3/user.rb index 2b0489a..51d4b1c 100644 --- a/lib/puppet_forge/v3/user.rb +++ b/lib/puppet_forge/v3/user.rb @@ -3,10 +3,8 @@ module PuppetForge module V3 - # Models a Forge user's account. class User < Base - include PuppetForge::LazyAccessors # Returns a collection of Modules owned by the user. @@ -16,7 +14,7 @@ class User < Base # # @return [PaginatedCollection] the modules owned by this user def modules - Module.where(:owner => username) + Module.where(owner: username) end end end diff --git a/puppet_forge.gemspec b/puppet_forge.gemspec index 6f33481..460f564 100644 --- a/puppet_forge.gemspec +++ b/puppet_forge.gemspec @@ -1,35 +1,34 @@ -# coding: utf-8 -lib = File.expand_path('../lib', __FILE__) +lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'puppet_forge/version' Gem::Specification.new do |spec| - spec.name = "puppet_forge" + spec.name = 'puppet_forge' spec.version = PuppetForge::VERSION - spec.authors = ["Puppet Labs"] - spec.email = ["forge-team+api@puppetlabs.com"] - spec.summary = "Access the Puppet Forge API from Ruby for resource information and to download releases." - spec.description = %q{Tools that can be used to access Forge API information on Modules, Users, and Releases. As well as download, unpack, and install Releases to a directory.} - spec.homepage = "https://github.com/puppetlabs/forge-ruby" - spec.license = "Apache-2.0" + spec.authors = ['Puppet Labs'] + spec.email = ['forge-team+api@puppetlabs.com'] + spec.summary = 'Access the Puppet Forge API from Ruby for resource information and to download releases.' + spec.description = 'Tools that can be used to access Forge API information on Modules, Users, and Releases. As well as download, unpack, and install Releases to a directory.' + spec.homepage = 'https://github.com/puppetlabs/forge-ruby' + spec.license = 'Apache-2.0' spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } - spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) - spec.require_paths = ["lib"] + spec.require_paths = ['lib'] spec.required_ruby_version = '>= 3.1.0' - spec.add_runtime_dependency "faraday", "~> 2.0" - spec.add_runtime_dependency "faraday-follow_redirects", "~> 0.3.0" - spec.add_dependency "semantic_puppet", "~> 1.0" - spec.add_dependency "minitar", '~> 1.0', '>= 1.0.2' + spec.add_dependency 'faraday', '~> 2.0' + spec.add_dependency 'faraday-follow_redirects', '~> 0.3.0' + spec.add_dependency 'minitar', '~> 1.0', '>= 1.0.2' + spec.add_dependency 'semantic_puppet', '~> 1.0' - spec.add_development_dependency "rake" - spec.add_development_dependency "rspec", "~> 3.0" - spec.add_development_dependency "simplecov" - spec.add_development_dependency "cane" - spec.add_development_dependency "yard" - spec.add_development_dependency "redcarpet" - spec.add_development_dependency "pry-byebug" + spec.add_development_dependency 'cane' + spec.add_development_dependency 'pry-byebug' + spec.add_development_dependency 'rake' + spec.add_development_dependency 'redcarpet' + spec.add_development_dependency 'rspec', '~> 3.0' + spec.add_development_dependency 'simplecov' + spec.add_development_dependency 'voxpupuli-rubocop', '~> 3.0.0' + spec.add_development_dependency 'yard' end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0b3676a..f61c535 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,7 +3,7 @@ if ENV['COVERAGE'] require 'simplecov' SimpleCov.start do - add_filter "/spec/" + add_filter '/spec/' end end @@ -11,34 +11,34 @@ require 'puppet_forge' module StubbingFaraday - - def stub_api_for(klass, base_url = "http://api.example.com", lru_cache: false) + def stub_api_for(klass, base_url = 'http://api.example.com', lru_cache: false, &block) unless lru_cache # Disable LRU cache by default - allow(klass).to receive(:lru_cache).and_return(instance_double('PuppetForge::LruCache', get: nil, put: nil, clear: nil)) + allow(klass).to receive(:lru_cache).and_return(instance_double('PuppetForge::LruCache', get: nil, put: nil, + clear: nil)) end allow(klass).to receive(:conn) do - Faraday.new :url => base_url do |builder| - builder.response(:json, :content_type => /\bjson$/, :parser_options => { :symbolize_names => true }) + Faraday.new url: base_url do |builder| + builder.response(:json, content_type: /\bjson$/, parser_options: { symbolize_names: true }) builder.response(:raise_error) builder.use(:connection_failure) - builder.adapter(:test) { |s| yield(s) } + builder.adapter(:test, &block) end end - stubs = Faraday::Adapter::Test::Stubs.new + Faraday::Adapter::Test::Stubs.new end def stub_fixture(stubs, method, path) stubs.send(method, path) do |env| - load_fixture([ env[:url].path, env[:url].query ].compact.join('?')) + load_fixture([env[:url].path, env[:url].query].compact.join('?')) end end def load_fixture(path) xplatform_path = path.to_s.gsub('?', '__') - [ 404 ].tap do |response| + [404].tap do |response| local = File.join(PROJECT_ROOT, 'spec', 'fixtures', xplatform_path) if File.exist?("#{local}.headers") && File.exist?("#{local}.json") @@ -68,11 +68,11 @@ def load_fixture(path) # --seed 1234 config.order = 'random' - config.before(:example) do + config.before do @old_host = PuppetForge.host end - config.after(:example) do + config.after do PuppetForge.host = @old_host end end diff --git a/spec/unit/forge/connection/connection_failure_spec.rb b/spec/unit/forge/connection/connection_failure_spec.rb index 028aedb..e4393f5 100644 --- a/spec/unit/forge/connection/connection_failure_spec.rb +++ b/spec/unit/forge/connection/connection_failure_spec.rb @@ -4,39 +4,41 @@ require 'faraday/adapter/net_http' describe PuppetForge::Connection::ConnectionFailure do - subject do Faraday.new('https://my-site.url/some-path') do |builder| builder.use(:connection_failure) builder.adapter :test do |stub| - stub.get('/connectfail') { raise Faraday::ConnectionFailed.new(SocketError.new("getaddrinfo: Name or service not known"), :hi) } - stub.get('/timeout') { raise Faraday::TimeoutError, "request timed out" } + stub.get('/connectfail') do + raise Faraday::ConnectionFailed.new(SocketError.new('getaddrinfo: Name or service not known'), :hi) + end + stub.get('/timeout') { raise Faraday::TimeoutError, 'request timed out' } end end end - it "includes the base URL in the error message" do - expect { + it 'includes the base URL in the error message' do + expect do subject.get('/connectfail') - }.to raise_error(Faraday::ConnectionFailed, /unable to connect to.*\/connectfail.*name or service not known/i) + end.to raise_error(Faraday::ConnectionFailed, %r{unable to connect to.*/connectfail.*name or service not known}i) end - it "logs for timeout errors" do - expect { + it 'logs for timeout errors' do + expect do subject.get('/timeout') - }.to raise_error(Faraday::ConnectionFailed, /unable to connect to.*\/timeout.*request timed out/i) + end.to raise_error(Faraday::ConnectionFailed, %r{unable to connect to.*/timeout.*request timed out}i) end - it "includes the proxy host in the error message when set" do + it 'includes the proxy host in the error message when set' do if subject.respond_to?(:proxy=) subject.proxy = 'https://some-unreachable.proxy:3128' else subject.proxy('https://some-unreachable.proxy:3128') end - expect { + expect do subject.get('/connectfail') - }.to raise_error(Faraday::ConnectionFailed, /unable to connect to.*using proxy.*\/connectfail.*name or service not known/i) + end.to raise_error(Faraday::ConnectionFailed, + %r{unable to connect to.*using proxy.*/connectfail.*name or service not known}i) end end diff --git a/spec/unit/forge/connection_spec.rb b/spec/unit/forge/connection_spec.rb index 76c61b9..1eb479b 100644 --- a/spec/unit/forge/connection_spec.rb +++ b/spec/unit/forge/connection_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe PuppetForge::Connection do - before(:each) do - PuppetForge.host = "https://forgeapi.puppet.com" + before do + PuppetForge.host = 'https://forgeapi.puppet.com' end let(:test_conn) do @@ -13,25 +13,25 @@ subject { described_class } describe '#proxy=' do - after(:each) do + after do subject.proxy = nil end - it "sets @proxy to value when passed non-empty string" do - proxy = "http://proxy.example.com:3128" + it 'sets @proxy to value when passed non-empty string' do + proxy = 'http://proxy.example.com:3128' subject.proxy = proxy expect(subject.instance_variable_get(:@proxy)).to eq proxy end - it "sets @proxy to nil when passed an empty string" do + it 'sets @proxy to nil when passed an empty string' do subject.proxy = '' expect(subject.instance_variable_get(:@proxy)).to be_nil end - it "replaces existing @proxy value with nil when set to empty string" do + it 'replaces existing @proxy value with nil when set to empty string' do subject.instance_variable_set(:@proxy, 'value') subject.proxy = '' @@ -40,25 +40,25 @@ end describe '#accept_language=' do - after(:each) do + after do subject.accept_language = nil end - it "sets @accept_language to value when passed non-empty string" do - lang = "ja-JP" + it 'sets @accept_language to value when passed non-empty string' do + lang = 'ja-JP' subject.accept_language = lang expect(subject.instance_variable_get(:@accept_language)).to eq lang end - it "sets @accept_language to nil when passed an empty string" do + it 'sets @accept_language to nil when passed an empty string' do subject.accept_language = '' expect(subject.instance_variable_get(:@accept_language)).to be_nil end - it "replaces existing @accept_language value with nil when set to empty string" do + it 'replaces existing @accept_language value with nil when set to empty string' do subject.instance_variable_set(:@accept_language, 'value') subject.accept_language = '' @@ -68,75 +68,76 @@ end describe 'creating a new connection' do + subject { test_conn.make_connection('https://some.site/url', [:test, faraday_stubs]) } let(:faraday_stubs) { Faraday::Adapter::Test::Stubs.new } - subject { test_conn.make_connection('https://some.site/url', [:test, faraday_stubs]) } - it 'parses response bodies with a JSON content-type into a hash' do - faraday_stubs.get('/json') { [200, {'Content-Type' => 'application/json'}, '{"hello": "world"}'] } - expect(subject.get('/json').body).to eq(:hello => 'world') + faraday_stubs.get('/json') { [200, { 'Content-Type' => 'application/json' }, '{"hello": "world"}'] } + expect(subject.get('/json').body).to eq(hello: 'world') end it 'returns the response body as-is when the content-type is not JSON' do - faraday_stubs.get('/binary') { [200, {'Content-Type' => 'application/octet-stream'}, 'I am a big bucket of binary data'] } + faraday_stubs.get('/binary') do + [200, { 'Content-Type' => 'application/octet-stream' }, 'I am a big bucket of binary data'] + end expect(subject.get('/binary').body).to eq('I am a big bucket of binary data') end it 'raises errors when the request has an error status code' do - faraday_stubs.get('/error') { [503, {}, "The server caught fire and cannot service your request right now"] } + faraday_stubs.get('/error') { [503, {}, 'The server caught fire and cannot service your request right now'] } - expect { + expect do subject.get('/error') - }.to raise_error(Faraday::ServerError, "the server responded with status 503") + end.to raise_error(Faraday::ServerError, 'the server responded with status 503') end context 'when an authorization value is provided' do - let(:key) { "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" } + let(:key) { 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789' } let(:prepended_key) { "Bearer #{key}" } context 'when the key already includes the Bearer prefix as expected' do - before(:each) do + before do allow(described_class).to receive(:authorization).and_return(prepended_key) end it 'does not prepend it again' do - expect(subject.headers).to include(:authorization => prepended_key) + expect(subject.headers).to include(authorization: prepended_key) end end context 'when the key does not includ the Bearer prefix' do context 'when the value looks like a Forge API key' do - before(:each) do + before do allow(described_class).to receive(:authorization).and_return(key) end it 'prepends "Bearer"' do - expect(subject.headers).to include(:authorization => prepended_key) + expect(subject.headers).to include(authorization: prepended_key) end end context 'when the value does not look like a Forge API key' do - let(:key) { "auth-test value" } + let(:key) { 'auth-test value' } - before(:each) do + before do allow(described_class).to receive(:authorization).and_return(key) end it 'does not alter the value' do - expect(subject.headers).to include(:authorization => key) + expect(subject.headers).to include(authorization: key) end end end end context 'when an accept language value is provided' do - before(:each) do - allow(described_class).to receive(:accept_language).and_return("ja-JP") + before do + allow(described_class).to receive(:accept_language).and_return('ja-JP') end it 'sets accept-language header on requests' do - expect(subject.headers).to include('Accept-Language' => "ja-JP") + expect(subject.headers).to include('Accept-Language' => 'ja-JP') end end end diff --git a/spec/unit/forge/lazy_accessors_spec.rb b/spec/unit/forge/lazy_accessors_spec.rb index 904f573..9643026 100644 --- a/spec/unit/forge/lazy_accessors_spec.rb +++ b/spec/unit/forge/lazy_accessors_spec.rb @@ -1,21 +1,22 @@ require 'spec_helper' describe PuppetForge::LazyAccessors do + subject { klass.new(local_data) } + let(:klass) do class PuppetForge::V3::Thing < PuppetForge::V3::Base - # Needed for #inspect def uri - "/things/1" + '/things/1' end # Needed for fetch def slug - "1" + '1' end def standalone_method - "a/b/c" + 'a/b/c' end def satisified_dependent_method @@ -33,17 +34,14 @@ def shadow def remote_shadow "-#{super}-" end - end PuppetForge::V3::Thing end let(:base_class) { PuppetForge::V3::Base } - let(:local_data) { { :id => 1, :local => 'data', :shadow => 'x' } } - let(:remote_data) { local_data.merge(:remote => 'DATA', :remote_shadow => 'X') } - - subject { klass.new(local_data) } + let(:local_data) { { id: 1, local: 'data', shadow: 'x' } } + let(:remote_data) { local_data.merge(remote: 'DATA', remote_shadow: 'X') } it 'does not call methods to #inspect' do expect(subject).not_to receive(:shadow) @@ -79,9 +77,13 @@ def remote_shadow end example 'do not create accessors on the base class itself' do - expect(klass.instance_methods(false)).to_not include(:local) - subject.local rescue nil - expect(klass.instance_methods(false)).to_not include(:local) + expect(klass.instance_methods(false)).not_to include(:local) + begin + subject.local + rescue StandardError + nil + end + expect(klass.instance_methods(false)).not_to include(:local) end end @@ -89,7 +91,7 @@ def remote_shadow before do stub_api_for(base_class) do |api| api.get('/v3/things/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end end @@ -121,9 +123,13 @@ def remote_shadow end example 'do not create accessors on the base class itself' do - expect(klass.instance_methods(false)).to_not include(:remote) - subject.remote rescue nil - expect(klass.instance_methods(false)).to_not include(:remote) + expect(klass.instance_methods(false)).not_to include(:remote) + begin + subject.remote + rescue StandardError + nil + end + expect(klass.instance_methods(false)).not_to include(:remote) end end @@ -131,7 +137,7 @@ def remote_shadow before do stub_api_for(base_class) do |api| api.get('/v3/things/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end end @@ -141,9 +147,13 @@ def remote_shadow end example 'do not create accessors on the base class itself' do - expect(klass.instance_methods(false)).to_not include(:local) - subject.unknown_attribute rescue nil - expect(klass.instance_methods(false)).to_not include(:local) + expect(klass.instance_methods(false)).not_to include(:local) + begin + subject.unknown_attribute + rescue StandardError + nil + end + expect(klass.instance_methods(false)).not_to include(:local) end end end diff --git a/spec/unit/forge/lazy_relations_spec.rb b/spec/unit/forge/lazy_relations_spec.rb index 5bd974e..35ea3d0 100644 --- a/spec/unit/forge/lazy_relations_spec.rb +++ b/spec/unit/forge/lazy_relations_spec.rb @@ -1,58 +1,55 @@ require 'spec_helper' describe PuppetForge::LazyRelations do - class PuppetForge::V3::Parent < PuppetForge::V3::Base - - lazy :relation, 'Thing' - lazy :chained, 'Parent' - lazy_collection :relations, 'Thing' - lazy_collection :parents, 'Parent' - - def uri - "/parents/#{slug}" - end - - def slug - "1" - end + class PuppetForge::V3::Parent < PuppetForge::V3::Base + lazy :relation, 'Thing' + lazy :chained, 'Parent' + lazy_collection :relations, 'Thing' + lazy_collection :parents, 'Parent' + + def uri + "/parents/#{slug}" end - class PuppetForge::V3::Thing < PuppetForge::V3::Base - - # Needed for #inspect - def uri - "/things/1" - end + def slug + '1' + end + end - # Needed for fetch - def slug - "1" - end + class PuppetForge::V3::Thing < PuppetForge::V3::Base + # Needed for #inspect + def uri + '/things/1' + end - def standalone_method - "a/b/c" - end + # Needed for fetch + def slug + '1' + end - def satisified_dependent_method - "-#{local}-" - end + def standalone_method + 'a/b/c' + end - def unsatisfied_dependent_method - "-#{remote}-" - end + def satisified_dependent_method + "-#{local}-" + end - def shadow - "-#{super}-" - end + def unsatisfied_dependent_method + "-#{remote}-" + end - def remote_shadow - "-#{super}-" - end + def shadow + "-#{super}-" + end + def remote_shadow + "-#{super}-" end + end let(:base_class) { PuppetForge::V3::Base } - let(:klass) do |*args| + let(:klass) do |*_args| PuppetForge::V3::Parent end @@ -60,14 +57,14 @@ def remote_shadow PuppetForge::V3::Thing end - let(:local_data) { { :id => 1, :local => 'data', :shadow => 'x' } } - let(:remote_data) { local_data.merge(:remote => 'DATA', :remote_shadow => 'X') } + let(:local_data) { { id: 1, local: 'data', shadow: 'x' } } + let(:remote_data) { local_data.merge(remote: 'DATA', remote_shadow: 'X') } describe '.lazy' do - subject { klass.new(:relation => local_data).relation } + subject { klass.new(relation: local_data).relation } it do - should be_a(related_class) + expect(subject).to be_a(related_class) end it 'does not call methods to #inspect' do @@ -108,7 +105,7 @@ def remote_shadow before do stub_api_for(base_class) do |stubs| stubs.get('/v3/things/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end end @@ -127,12 +124,12 @@ def remote_shadow end example 'allow multiple instances to access remote attributes' do - expect(related_class).to receive(:request) \ - .exactly(9).times \ - .and_call_original + expect(related_class).to receive(:request) + .exactly(9).times + .and_call_original 9.times do - subject = klass.new(:relation => local_data).relation + subject = klass.new(relation: local_data).relation expect(subject.remote).to eql('DATA') end end @@ -147,46 +144,45 @@ def remote_shadow end describe 'remote relations' do + subject { klass.new(chained: { id: 1 }) } + before do stub_api_for(base_class) do |api| api.get('/v3/parents/1') do - data = { :id => 1, :relation => local_data } - [ 200, { 'Content-Type' => 'json' }, data ] + data = { id: 1, relation: local_data } + [200, { 'Content-Type' => 'json' }, data] end api.get('/v3/things/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end - end - subject { klass.new(:chained => { :id => 1 }) } - example 'allow chained lookups of lazy relations' do expect(subject.chained.relation.remote).to eql('DATA') end end describe 'null relations' do - subject { klass.new(:relation => nil) } + subject { klass.new(relation: nil) } example 'do not return new instances' do - expect(subject.relation).to be nil + expect(subject.relation).to be_nil end end describe 'unsatisfiable attributes' do + subject { klass.new(local_data) } + before do stub_api_for(base_class) do |api| api.get('/v3/parents/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end end - subject { klass.new(local_data) } - example 'raise an exception when accessing an unknown attribute' do expect { subject.unknown_attribute }.to raise_error(NoMethodError) end @@ -194,9 +190,9 @@ def remote_shadow end describe '.lazy_collection' do - subject { klass.new(:relations => [local_data]).relations.first } + subject { klass.new(relations: [local_data]).relations.first } - it { should be_a(related_class) } + it { is_expected.to be_a(related_class) } it 'does not call methods to #inspect' do expect(subject).not_to receive(:shadow) @@ -236,7 +232,7 @@ def remote_shadow before do stub_api_for(base_class) do |api| api.get('/v3/things/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end end @@ -255,12 +251,12 @@ def remote_shadow end example 'allow multiple instances to access remote attributes' do - expect(related_class).to receive(:request) \ - .exactly(9).times \ - .and_call_original + expect(related_class).to receive(:request) + .exactly(9).times + .and_call_original 9.times do - subject = klass.new(:relations => [local_data]).relations.first + subject = klass.new(relations: [local_data]).relations.first expect(subject.remote).to eql('DATA') end end @@ -275,29 +271,28 @@ def remote_shadow end describe 'remote relations' do + subject { klass.new(id: 1) } + before do stub_api_for(base_class) do |api| api.get('/v3/parents/1') do - data = { :id => 1, :parents => [{ :id => 1, :relation => local_data }] } - [ 200, { 'Content-Type' => 'json' }, data ] + data = { id: 1, parents: [{ id: 1, relation: local_data }] } + [200, { 'Content-Type' => 'json' }, data] end api.get('/v3/things/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end - end - subject { klass.new(:id => 1) } - example 'allow chained lookups of lazy relations' do expect(subject.parents[0].relation.remote).to eql('DATA') end end describe 'null relations' do - subject { klass.new(:relations => nil) } + subject { klass.new(relations: nil) } example 'return an empty list' do expect(subject.relations).to be_empty @@ -305,16 +300,16 @@ def remote_shadow end describe 'unsatisfiable attributes' do + subject { klass.new(local_data) } + before do stub_api_for(base_class) do |api| api.get('/v3/parents/1') do - [ 200, { 'Content-Type' => 'json' }, remote_data ] + [200, { 'Content-Type' => 'json' }, remote_data] end end end - subject { klass.new(local_data) } - example 'raise an exception when accessing an unknown attribute' do expect { subject.unknown_attribute }.to raise_error(NoMethodError) end diff --git a/spec/unit/forge/lru_cache_spec.rb b/spec/unit/forge/lru_cache_spec.rb index 380ea05..3d6d7c4 100644 --- a/spec/unit/forge/lru_cache_spec.rb +++ b/spec/unit/forge/lru_cache_spec.rb @@ -2,7 +2,7 @@ describe PuppetForge::LruCache do it 'creates a cache key from a list of strings' do - expect { subject.class.new_key('foo', 'bar', 'baz') }.not_to raise_error + expect { subject.class.new_key('foo', 'bar', 'baz') }.not_to raise_error end it 'creates a new instance' do @@ -36,8 +36,8 @@ end context 'with environment variables' do - around(:each) do |example| - @old_max_size = ENV['PUPPET_FORGE_MAX_CACHE_SIZE'] + around do |example| + @old_max_size = ENV.fetch('PUPPET_FORGE_MAX_CACHE_SIZE', nil) ENV['PUPPET_FORGE_MAX_CACHE_SIZE'] = '42' example.run ENV['PUPPET_FORGE_MAX_CACHE_SIZE'] = @old_max_size @@ -48,7 +48,7 @@ end end - context '#get' do + describe '#get' do it 'returns nil if the key is not present in the cache' do expect(PuppetForge::LruCache.new.get('foo')).to be_nil end @@ -64,32 +64,32 @@ cache.put('foo', 'bar') cache.put('baz', 'qux') cache.get('foo') - expect(cache.send(:lru)).to eq(['foo', 'baz']) + expect(cache.send(:lru)).to eq(%w[foo baz]) end it 'is thread-safe for get calls' do cache = PuppetForge::LruCache.new - + # Populate the cache with initial values cache.put('foo', 'bar') cache.put('baz', 'qux') - + # Create two threads for concurrent cache get operations thread_one = Thread.new do 100.times { expect(cache.get('foo')).to eq('bar') } end - + thread_two = Thread.new do 100.times { expect(cache.get('baz')).to eq('qux') } end - + # Wait for both threads to complete thread_one.join thread_two.join - end + end end - context '#put' do + describe '#put' do it 'adds the key to the front of the LRU list' do cache = PuppetForge::LruCache.new cache.put('foo', 'bar') @@ -107,36 +107,35 @@ cache.put('foo', 'bar') cache.put('baz', 'qux') cache.put('quux', 'corge') - expect(cache.send(:lru)).to eq(['quux', 'baz']) + expect(cache.send(:lru)).to eq(%w[quux baz]) end it 'is thread-safe' do cache = PuppetForge::LruCache.new - + # Create two threads for concurrent cache operations thread_one = Thread.new do 100.times { cache.put('foo', 'bar') } end - + thread_two = Thread.new do 100.times { cache.put('baz', 'qux') } end - + # Wait for both threads to complete thread_one.join thread_two.join - + # At this point, we don't need to compare the LRU list, # because the order may change due to concurrent puts. - + # Instead, we simply expect the code to run without errors. expect { thread_one.value }.not_to raise_error expect { thread_two.value }.not_to raise_error end - end - context '#clear' do + describe '#clear' do it 'clears the cache' do cache = PuppetForge::LruCache.new cache.put('foo', 'bar') diff --git a/spec/unit/forge/tar/mini_spec.rb b/spec/unit/forge/tar/mini_spec.rb index d3f9e3d..b86dc18 100644 --- a/spec/unit/forge/tar/mini_spec.rb +++ b/spec/unit/forge/tar/mini_spec.rb @@ -4,6 +4,7 @@ let(:entry_class) do Class.new do attr_accessor :typeflag, :name, :full_name + def initialize(name, full_name, typeflag) @name = name @full_name = full_name @@ -16,44 +17,46 @@ def initialize(name, full_name, typeflag) let(:sourcedir) { '/the/src/dir' } let(:destfile) { '/the/dest/file.tar.gz' } let(:minitar) { described_class.new } - let(:tarfile_contents) { [entry_class.new('file', 'full_file', '0'), \ - entry_class.new('symlink', 'full_symlink', '2'), \ - entry_class.new('invalid', 'full_invalid', 'F')] } + let(:tarfile_contents) do + [entry_class.new('file', 'full_file', '0'), + entry_class.new('symlink', 'full_symlink', '2'), + entry_class.new('invalid', 'full_invalid', 'F'),] + end - it "unpacks a tar file" do + it 'unpacks a tar file' do unpacks_the_entry(:file_start, 'thefile') minitar.unpack(sourcefile, destdir) end - it "does not allow an absolute path" do + it 'does not allow an absolute path' do unpacks_the_entry(:file_start, '/thefile') - expect { + expect do minitar.unpack(sourcefile, destdir) - }.to raise_error(PuppetForge::InvalidPathInPackageError, - "Attempt to install file into \"/thefile\" under \"#{destdir}\"") + end.to raise_error(PuppetForge::InvalidPathInPackageError, + "Attempt to install file into \"/thefile\" under \"#{destdir}\"") end - it "does not allow a file to be written outside the destination directory" do + it 'does not allow a file to be written outside the destination directory' do unpacks_the_entry(:file_start, '../../thefile') - expect { + expect do minitar.unpack(sourcefile, destdir) - }.to raise_error(PuppetForge::InvalidPathInPackageError, - "Attempt to install file into \"#{File.expand_path('/the/thefile')}\" under \"#{destdir}\"") + end.to raise_error(PuppetForge::InvalidPathInPackageError, + "Attempt to install file into \"#{File.expand_path('/the/thefile')}\" under \"#{destdir}\"") end - it "does not allow a directory to be written outside the destination directory" do + it 'does not allow a directory to be written outside the destination directory' do unpacks_the_entry(:dir, '../../thedir') - expect { + expect do minitar.unpack(sourcefile, destdir) - }.to raise_error(PuppetForge::InvalidPathInPackageError, - "Attempt to install file into \"#{File.expand_path('/the/thedir')}\" under \"#{destdir}\"") + end.to raise_error(PuppetForge::InvalidPathInPackageError, + "Attempt to install file into \"#{File.expand_path('/the/thedir')}\" under \"#{destdir}\"") end - it "packs a tar file" do + it 'packs a tar file' do writer = double('GzipWriter') expect(Zlib::GzipWriter).to receive(:open).with(destfile).and_yield(writer) @@ -62,7 +65,7 @@ def initialize(name, full_name, typeflag) minitar.pack(sourcedir, destfile) end - it "returns filenames in a tar separated into correct categories" do + it 'returns filenames in a tar separated into correct categories' do reader = double('GzipReader') expect(Zlib::GzipReader).to receive(:open).with(sourcefile).and_yield(reader) @@ -80,7 +83,7 @@ def unpacks_the_entry(type, name) reader = double('GzipReader') expect(Zlib::GzipReader).to receive(:open).with(sourcefile).and_yield(reader) - expect(minitar).to receive(:validate_files).with(reader).and_return({:valid => [name]}) + expect(minitar).to receive(:validate_files).with(reader).and_return({ valid: [name] }) expect(Minitar).to receive(:unpack).with(reader, destdir, [name]).and_yield(type, name, nil) end end diff --git a/spec/unit/forge/tar_spec.rb b/spec/unit/forge/tar_spec.rb index 4face2d..60572a5 100644 --- a/spec/unit/forge/tar_spec.rb +++ b/spec/unit/forge/tar_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' describe PuppetForge::Tar do - - it "returns an instance of minitar" do - expect(described_class.instance).to be_a_kind_of PuppetForge::Tar::Mini + it 'returns an instance of minitar' do + expect(described_class.instance).to be_a PuppetForge::Tar::Mini end - end diff --git a/spec/unit/forge/unpacker_spec.rb b/spec/unit/forge/unpacker_spec.rb index 31f25f9..59aad41 100644 --- a/spec/unit/forge/unpacker_spec.rb +++ b/spec/unit/forge/unpacker_spec.rb @@ -2,19 +2,17 @@ require 'spec_helper' describe PuppetForge::Unpacker do - - let(:source) { Dir.mktmpdir("source") } - let(:target) { Dir.mktmpdir("unpacker") } + let(:source) { Dir.mktmpdir('source') } + let(:target) { Dir.mktmpdir('unpacker') } let(:module_name) { 'myusername-mytarball' } - let(:filename) { Dir.mktmpdir("module") + "/module.tar.gz" } - let(:working_dir) { Dir.mktmpdir("working_dir") } - let(:trash_dir) { Dir.mktmpdir("trash_dir") } - - it "attempts to untar file to temporary location" do + let(:filename) { Dir.mktmpdir('module') + '/module.tar.gz' } + let(:working_dir) { Dir.mktmpdir('working_dir') } + let(:trash_dir) { Dir.mktmpdir('trash_dir') } + it 'attempts to untar file to temporary location' do minitar = double('PuppetForge::Tar::Mini') - expect(minitar).to receive(:unpack).with(filename, anything()) do |src, dest| + expect(minitar).to receive(:unpack).with(filename, anything) do |_src, dest| FileUtils.mkdir(File.join(dest, 'extractedmodule')) File.open(File.join(dest, 'extractedmodule', 'metadata.json'), 'w+') do |file| file.puts JSON.generate('name' => module_name, 'version' => '1.0.0') @@ -27,26 +25,24 @@ expect(File).to be_directory(target) end - it "returns the appropriate categories of the contents of the tar file from the tar implementation" do - + it 'returns the appropriate categories of the contents of the tar file from the tar implementation' do minitar = double('PuppetForge::Tar::Mini') - expect(minitar).to receive(:unpack).with(filename, anything()) do |src, dest| + expect(minitar).to receive(:unpack).with(filename, anything) do |_src, dest| FileUtils.mkdir(File.join(dest, 'extractedmodule')) File.open(File.join(dest, 'extractedmodule', 'metadata.json'), 'w+') do |file| file.puts JSON.generate('name' => module_name, 'version' => '1.0.0') end - { :valid => [File.join('extractedmodule', 'metadata.json')], :invalid => [], :symlinks => [] } + { valid: [File.join('extractedmodule', 'metadata.json')], invalid: [], symlinks: [] } end expect(PuppetForge::Tar).to receive(:instance).and_return(minitar) file_lists = PuppetForge::Unpacker.unpack(filename, target, trash_dir) - expect(file_lists).to eq({:valid=>["extractedmodule/metadata.json"], :invalid=>[], :symlinks=>[]}) + expect(file_lists).to eq({ valid: ['extractedmodule/metadata.json'], invalid: [], symlinks: [] }) expect(File).to be_directory(target) end it "attempts to set the ownership of a target dir to a source dir's owner" do - source_path = Pathname.new(source) target_path = Pathname.new(target) @@ -54,5 +50,4 @@ PuppetForge::Unpacker.harmonize_ownership(source_path, target_path) end - end diff --git a/spec/unit/forge/util_spec.rb b/spec/unit/forge/util_spec.rb index 68f8e06..b8724df 100644 --- a/spec/unit/forge/util_spec.rb +++ b/spec/unit/forge/util_spec.rb @@ -1,17 +1,13 @@ require 'puppet_forge/util' describe PuppetForge::Util do - - describe "version_valid?" do - it "returns true for a valid version" do + describe 'version_valid?' do + it 'returns true for a valid version' do expect(described_class.version_valid?('1.0.0')).to equal(true) end - - it "returns false for an invalid version" do + it 'returns false for an invalid version' do expect(described_class.version_valid?('notaversion')).to equal(false) end - end - end diff --git a/spec/unit/forge/v3/base/paginated_collection_spec.rb b/spec/unit/forge/v3/base/paginated_collection_spec.rb index 26309ec..d58c0df 100644 --- a/spec/unit/forge/v3/base/paginated_collection_spec.rb +++ b/spec/unit/forge/v3/base/paginated_collection_spec.rb @@ -1,41 +1,43 @@ require 'spec_helper' describe PuppetForge::V3::Base::PaginatedCollection do + subject { klass.get_collection('/v3/collection') } + let(:klass) do allow(PuppetForge::V3::Base).to receive(:get_collection) do |url| data = { - '/v3/collection' => [ { :data => :A }, { :data => :B }, { :data => :C } ], - '/v3/collection?page=2' => [ { :data => :D }, { :data => :E }, { :data => :F } ], - '/v3/collection?page=3' => [ { :data => :G }, { :data => :H } ], + '/v3/collection' => [{ data: :A }, { data: :B }, { data: :C }], + '/v3/collection?page=2' => [{ data: :D }, { data: :E }, { data: :F }], + '/v3/collection?page=3' => [{ data: :G }, { data: :H }], } meta = { '/v3/collection' => { - :limit => 3, - :offset => 0, - :first => '/v3/collection', - :previous => nil, - :current => '/v3/collection', - :next => '/v3/collection?page=2', - :total => 8, + limit: 3, + offset: 0, + first: '/v3/collection', + previous: nil, + current: '/v3/collection', + next: '/v3/collection?page=2', + total: 8, }, '/v3/collection?page=2' => { - :limit => 3, - :offset => 0, - :first => '/v3/collection', - :previous => '/v3/collection', - :current => '/v3/collection?page=2', - :next => '/v3/collection?page=3', - :total => 8, + limit: 3, + offset: 0, + first: '/v3/collection', + previous: '/v3/collection', + current: '/v3/collection?page=2', + next: '/v3/collection?page=3', + total: 8, }, '/v3/collection?page=3' => { - :limit => 3, - :offset => 0, - :first => '/v3/collection', - :previous => '/v3/collection?page=2', - :current => '/v3/collection?page=3', - :next => nil, - :total => 8, + limit: 3, + offset: 0, + first: '/v3/collection', + previous: '/v3/collection?page=2', + current: '/v3/collection?page=3', + next: nil, + total: 8, }, } @@ -45,8 +47,6 @@ PuppetForge::V3::Base end - subject { klass.get_collection('/v3/collection') } - def collect_data(paginated) paginated.to_a.collect do |x| x.data @@ -60,7 +60,7 @@ def collect_data(paginated) end it 'maps to a single page of the collection' do - expect(collect_data(subject)).to eql([ :A, :B, :C ]) + expect(collect_data(subject)).to eql(%i[A B C]) end it 'knows the size of the entire collection' do @@ -72,8 +72,8 @@ def collect_data(paginated) end it 'enables page navigation' do - expect(subject.next).to_not be_empty - expect(collect_data(subject.next)).to_not eql(collect_data(subject)) + expect(subject.next).not_to be_empty + expect(collect_data(subject.next)).not_to eql(collect_data(subject)) expect(collect_data(subject.next.previous)).to eql(collect_data(subject)) end @@ -88,7 +88,7 @@ def collect_data(paginated) describe '#unpaginated' do it 'provides an iterator over the entire collection' do - expected = [ :A, :B, :C, :D, :E, :F, :G, :H ] + expected = %i[A B C D E F G H] actual = subject.unpaginated.to_a.collect do |x| expect(x).to be_a(klass) x.data @@ -98,7 +98,7 @@ def collect_data(paginated) end it "provides a full iterator regardless of which page it's started on" do - expected = [ :A, :B, :C, :D, :E, :F, :G, :H ] + expected = %i[A B C D E F G H] actual = subject.next.next.unpaginated.to_a.collect do |x| expect(x).to be_a(klass) diff --git a/spec/unit/forge/v3/base_spec.rb b/spec/unit/forge/v3/base_spec.rb index 485dc69..d11cf0a 100644 --- a/spec/unit/forge/v3/base_spec.rb +++ b/spec/unit/forge/v3/base_spec.rb @@ -2,53 +2,53 @@ describe PuppetForge::V3::Base do context 'connection management' do - before(:each) do + before do PuppetForge::Connection.authorization = nil PuppetForge::Connection.proxy = nil described_class.conn = nil end - after(:each) do + after do PuppetForge::Connection.authorization = nil PuppetForge::Connection.proxy = nil described_class.conn = nil end describe 'setting authorization value after a connection is created' do - it 'should reset connection' do + it 'resets connection' do old_conn = described_class.conn PuppetForge::Connection.authorization = 'post-init auth value' new_conn = described_class.conn - expect(new_conn).to_not eq(old_conn) - expect(new_conn.headers).to include(:authorization => 'post-init auth value') + expect(new_conn).not_to eq(old_conn) + expect(new_conn.headers).to include(authorization: 'post-init auth value') end end describe 'setting proxy value after a connection is created' do - it 'should reset connection' do + it 'resets connection' do old_conn = described_class.conn PuppetForge::Connection.proxy = 'http://proxy.example.com:8888' new_conn = described_class.conn - expect(new_conn).to_not eq(old_conn) - expect(new_conn.proxy).to_not be_nil + expect(new_conn).not_to eq(old_conn) + expect(new_conn.proxy).not_to be_nil expect(new_conn.proxy.uri.to_s).to eq('http://proxy.example.com:8888') end end end describe '::new_collection' do - it 'should handle responses with no results' do - response_data = { data: {}, errors: "Something bad happened!" } + it 'handles responses with no results' do + response_data = { data: {}, errors: 'Something bad happened!' } expect(PuppetForge::V3::Base.new_collection(response_data)).to eq([]) end - it 'should handle responses with no pagination info' do - response_data = { data: {}, errors: "Something bad happened!" } + it 'handles responses with no pagination info' do + response_data = { data: {}, errors: 'Something bad happened!' } collection = PuppetForge::V3::Base.new_collection(response_data) @@ -60,7 +60,7 @@ describe 'the host url setting' do context 'without a path prefix' do - before(:each) do + before do PuppetForge::V3::Base.lru_cache.clear # We test the cache later, so clear it now @orig_host = PuppetForge.host PuppetForge.host = 'https://api.example.com' @@ -69,14 +69,14 @@ PuppetForge::V3::Base.conn = PuppetForge::Connection.default_connection end - after(:each) do + after do PuppetForge.host = @orig_host # Trigger connection reset PuppetForge::V3::Base.conn = PuppetForge::Connection.default_connection end - it 'should work' do + it 'works' do stub_api_for(PuppetForge::V3::Base) do |stubs| stub_fixture(stubs, :get, '/v3/bases/puppet') end @@ -101,7 +101,7 @@ end context 'with a path prefix' do - before(:each) do + before do PuppetForge::V3::Base.lru_cache.clear # We test the cache later, so clear it now @orig_host = PuppetForge.host PuppetForge.host = 'https://api.example.com/uri/prefix' @@ -110,14 +110,14 @@ PuppetForge::V3::Base.conn = PuppetForge::Connection.default_connection end - after(:each) do + after do PuppetForge.host = @orig_host # Trigger connection reset PuppetForge::V3::Base.conn = PuppetForge::Connection.default_connection end - it 'should work' do + it 'works' do stub_api_for(PuppetForge::V3::Base, PuppetForge.host) do |stubs| stub_fixture(stubs, :get, '/uri/prefix/v3/bases/puppet') end diff --git a/spec/unit/forge/v3/metadata_spec.rb b/spec/unit/forge/v3/metadata_spec.rb index 02d0215..27c286f 100644 --- a/spec/unit/forge/v3/metadata_spec.rb +++ b/spec/unit/forge/v3/metadata_spec.rb @@ -8,178 +8,197 @@ subject { metadata } %w[ name version author summary license source project_page issues_url - dependencies dashed_name release_name description ].each do |prop| + dependencies dashed_name release_name description ].each do |prop| describe "##{prop}" do - it "responds to the property" do + it 'responds to the property' do subject.send(prop) end end end end - describe "#update" do + describe '#update' do subject { metadata.update(data) } - context "with a valid name" do + context 'with a valid name' do let(:data) { { 'name' => 'billgates-mymodule' } } - it "extracts the author name from the name field" do + it 'extracts the author name from the name field' do expect(subject.to_hash['author']).to eq('billgates') end - it "extracts a module name from the name field" do + it 'extracts a module name from the name field' do expect(subject.module_name).to eq('mymodule') end - context "and existing author" do + context 'and existing author' do before { metadata.update('author' => 'foo') } - it "avoids overwriting the existing author" do + it 'avoids overwriting the existing author' do expect(subject.to_hash['author']).to eq('foo') end end end - context "with a valid name and author" do + context 'with a valid name and author' do let(:data) { { 'name' => 'billgates-mymodule', 'author' => 'foo' } } - it "use the author name from the author field" do + it 'use the author name from the author field' do expect(subject.to_hash['author']).to eq('foo') end - context "and preexisting author" do + context 'and preexisting author' do before { metadata.update('author' => 'bar') } - it "avoids overwriting the existing author" do + it 'avoids overwriting the existing author' do expect(subject.to_hash['author']).to eq('foo') end end end - context "with an invalid name" do - context "(short module name)" do + context 'with an invalid name' do + context '(short module name)' do let(:data) { { 'name' => 'mymodule' } } - it "raises an exception" do - expect { subject }.to raise_error(ArgumentError, "Invalid 'name' field in metadata.json: the field must be a namespaced module name") + it 'raises an exception' do + expect do + subject + end.to raise_error(ArgumentError, + "Invalid 'name' field in metadata.json: the field must be a namespaced module name") end end - context "(missing namespace)" do + context '(missing namespace)' do let(:data) { { 'name' => '/mymodule' } } - it "raises an exception" do - expect { subject }.to raise_error(ArgumentError, "Invalid 'name' field in metadata.json: the field must be a namespaced module name") + it 'raises an exception' do + expect do + subject + end.to raise_error(ArgumentError, + "Invalid 'name' field in metadata.json: the field must be a namespaced module name") end end - context "(missing module name)" do + context '(missing module name)' do let(:data) { { 'name' => 'namespace/' } } - it "raises an exception" do - expect { subject }.to raise_error(ArgumentError, "Invalid 'name' field in metadata.json: the field must be a namespaced module name") + it 'raises an exception' do + expect do + subject + end.to raise_error(ArgumentError, + "Invalid 'name' field in metadata.json: the field must be a namespaced module name") end end - context "(invalid namespace)" do + context '(invalid namespace)' do let(:data) { { 'name' => "dolla'bill$-mymodule" } } - it "raises an exception" do - expect { subject }.to raise_error(ArgumentError, "Invalid 'name' field in metadata.json: the namespace contains non-alphanumeric characters") + it 'raises an exception' do + expect do + subject + end.to raise_error(ArgumentError, + "Invalid 'name' field in metadata.json: the namespace contains non-alphanumeric characters") end end - context "(non-alphanumeric module name)" do + context '(non-alphanumeric module name)' do let(:data) { { 'name' => "dollabils-fivedolla'" } } - it "raises an exception" do - expect { subject }.to raise_error(ArgumentError, "Invalid 'name' field in metadata.json: the module name contains non-alphanumeric (or underscore) characters") + it 'raises an exception' do + expect do + subject + end.to raise_error(ArgumentError, + "Invalid 'name' field in metadata.json: the module name contains non-alphanumeric (or underscore) characters") end end - context "(module name starts with a number)" do - let(:data) { { 'name' => "dollabills-5dollars" } } + context '(module name starts with a number)' do + let(:data) { { 'name' => 'dollabills-5dollars' } } - it "raises an exception" do - expect { subject }.to raise_error(ArgumentError, "Invalid 'name' field in metadata.json: the module name must begin with a letter") + it 'raises an exception' do + expect do + subject + end.to raise_error(ArgumentError, + "Invalid 'name' field in metadata.json: the module name must begin with a letter") end end end - - context "with an invalid version" do + context 'with an invalid version' do let(:data) { { 'version' => '3.0' } } - it "raises an exception" do - expect { subject }.to raise_error(ArgumentError, "Invalid 'version' field in metadata.json: version string cannot be parsed as a valid Semantic Version") + it 'raises an exception' do + expect do + subject + end.to raise_error(ArgumentError, + "Invalid 'version' field in metadata.json: version string cannot be parsed as a valid Semantic Version") end end - context "with a valid source" do - context "which is a GitHub URL" do - context "with a scheme" do + context 'with a valid source' do + context 'which is a GitHub URL' do + context 'with a scheme' do before { metadata.update('source' => 'https://github.com/billgates/amazingness') } - it "predicts a default project_page" do + it 'predicts a default project_page' do expect(subject.to_hash['project_page']).to eq('https://github.com/billgates/amazingness') end - it "predicts a default issues_url" do + it 'predicts a default issues_url' do expect(subject.to_hash['issues_url']).to eq('https://github.com/billgates/amazingness/issues') end end - context "without a scheme" do + context 'without a scheme' do before { metadata.update('source' => 'github.com/billgates/amazingness') } - it "predicts a default project_page" do + it 'predicts a default project_page' do expect(subject.to_hash['project_page']).to eq('https://github.com/billgates/amazingness') end - it "predicts a default issues_url" do + it 'predicts a default issues_url' do expect(subject.to_hash['issues_url']).to eq('https://github.com/billgates/amazingness/issues') end end end - context "which is not a GitHub URL" do + context 'which is not a GitHub URL' do before { metadata.update('source' => 'https://notgithub.com/billgates/amazingness') } - it "does not predict a default project_page" do - expect(subject.to_hash['project_page']).to be nil + it 'does not predict a default project_page' do + expect(subject.to_hash['project_page']).to be_nil end - it "does not predict a default issues_url" do - expect(subject.to_hash['issues_url']).to be nil + it 'does not predict a default issues_url' do + expect(subject.to_hash['issues_url']).to be_nil end end - context "which is not a URL" do + context 'which is not a URL' do before { metadata.update('source' => 'my brain') } - it "does not predict a default project_page" do - expect(subject.to_hash['project_page']).to be nil + it 'does not predict a default project_page' do + expect(subject.to_hash['project_page']).to be_nil end - it "does not predict a default issues_url" do - expect(subject.to_hash['issues_url']).to be nil + it 'does not predict a default issues_url' do + expect(subject.to_hash['issues_url']).to be_nil end end - end - context "with a invalid dependency name" do - let(:data) { {'dependencies' => [{'name' => 'puppetlabsbadmodule'}] }} + context 'with a invalid dependency name' do + let(:data) { { 'dependencies' => [{ 'name' => 'puppetlabsbadmodule' }] } } - it "raises an exception" do + it 'raises an exception' do expect { subject }.to raise_error(ArgumentError) end end - context "with a invalid version range" do - let(:data) { {'dependencies' => [{'name' => 'puppetlabsbadmodule', 'version_requirement' => '>= banana'}] }} + context 'with a invalid version range' do + let(:data) { { 'dependencies' => [{ 'name' => 'puppetlabsbadmodule', 'version_requirement' => '>= banana' }] } } - it "raises an exception" do + it 'raises an exception' do expect { subject }.to raise_error(ArgumentError) end end @@ -226,29 +245,30 @@ end end - describe "#to_hash" do + describe '#to_hash' do subject { metadata.to_hash } - it "contains the default set of keys" do - expect(subject.keys.sort).to eq(%w[ name version author summary license source issues_url project_page dependencies ].sort) + it 'contains the default set of keys' do + expect(subject.keys.sort).to eq(%w[name version author summary license source issues_url project_page + dependencies].sort) end describe "['license']" do - it "defaults to Apache 2" do - expect(subject['license']).to eq("Apache-2.0") + it 'defaults to Apache 2' do + expect(subject['license']).to eq('Apache-2.0') end end describe "['dependencies']" do - it "defaults to an empty set" do + it 'defaults to an empty set' do expect(subject['dependencies']).to eq(Set.new) end end - context "when updated with non-default data" do + context 'when updated with non-default data' do subject { metadata.update('license' => 'MIT', 'non-standard' => 'yup').to_hash } - it "overrides the defaults" do + it 'overrides the defaults' do expect(subject['license']).to eq('MIT') end diff --git a/spec/unit/forge/v3/module_spec.rb b/spec/unit/forge/v3/module_spec.rb index 231e434..a9275c5 100644 --- a/spec/unit/forge/v3/module_spec.rb +++ b/spec/unit/forge/v3/module_spec.rb @@ -37,7 +37,7 @@ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') } it 'exposes the related module as a property' do - expect(mod.owner).to_not be nil + expect(mod.owner).not_to be_nil end it 'grants access to module attributes without an API call' do @@ -47,7 +47,7 @@ it 'transparently makes API calls for other attributes' do expect(PuppetForge::V3::User).to receive(:request).once.and_call_original - expect(mod.owner.created_at).to_not be nil + expect(mod.owner.created_at).not_to be_nil end end @@ -55,14 +55,13 @@ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') } it 'exposes the current_release as a property' do - expect(mod.current_release).to_not be nil + expect(mod.current_release).not_to be_nil end it 'grants access to release attributes without an API call' do expect(PuppetForge::V3::Release).not_to receive(:request) - expect(mod.current_release.version).to_not be nil + expect(mod.current_release.version).not_to be_nil end - end describe '#releases' do @@ -73,21 +72,21 @@ end it 'knows the size of the collection' do - expect(mod.releases).to_not be_empty + expect(mod.releases).not_to be_empty end it 'grants access to release attributes without an API call' do expect(PuppetForge::V3::Release).not_to receive(:request) - expect(mod.releases.map(&:version)).to_not include nil + expect(mod.releases.map(&:version)).not_to include nil end it 'loads releases lazily' do - versions = %w[ 0.0.1 0.0.2 0.0.3 0.0.4 0.1.1 ] + versions = %w[0.0.1 0.0.2 0.0.3 0.0.4 0.1.1] releases = mod.releases.select { |x| versions.include? x.version } expect(PuppetForge::V3::Base).to receive(:request).exactly(5).times.and_call_original - expect(releases.map(&:downloads)).to_not include nil + expect(releases.map(&:downloads)).not_to include nil end end @@ -95,7 +94,7 @@ let(:mod) { PuppetForge::V3::Module.find('puppetlabs-apache') } example 'are easily accessible' do - expect(mod.created_at).to_not be nil + expect(mod.created_at).not_to be_nil end end end diff --git a/spec/unit/forge/v3/release_spec.rb b/spec/unit/forge/v3/release_spec.rb index e47e0a8..b457fc2 100644 --- a/spec/unit/forge/v3/release_spec.rb +++ b/spec/unit/forge/v3/release_spec.rb @@ -3,39 +3,39 @@ describe PuppetForge::V3::Release do context 'connection management' do - before(:each) do + before do PuppetForge::Connection.authorization = nil PuppetForge::Connection.proxy = nil described_class.conn = PuppetForge::V3::Base.conn(true) end - after(:each) do + after do PuppetForge::Connection.authorization = nil PuppetForge::Connection.proxy = nil described_class.conn = nil end describe 'setting authorization value after a connection is created' do - it 'should reset connection' do + it 'resets connection' do old_conn = described_class.conn PuppetForge::Connection.authorization = 'post-init auth value' new_conn = described_class.conn - expect(new_conn).to_not eq(old_conn) - expect(new_conn.headers).to include(:authorization => 'post-init auth value') + expect(new_conn).not_to eq(old_conn) + expect(new_conn.headers).to include(authorization: 'post-init auth value') end end describe 'setting proxy value after a connection is created' do - it 'should reset connection' do + it 'resets connection' do old_conn = described_class.conn PuppetForge::Connection.proxy = 'http://proxy.example.com:8888' new_conn = described_class.conn - expect(new_conn).to_not eq(old_conn) - expect(new_conn.proxy).to_not be_nil + expect(new_conn).not_to eq(old_conn) + expect(new_conn.proxy).not_to be_nil expect(new_conn.proxy.uri.to_s).to eq('http://proxy.example.com:8888') end end @@ -69,7 +69,7 @@ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') } it 'exposes the related module as a property' do - expect(release.module).to_not be nil + expect(release.module).not_to be_nil end it 'grants access to module attributes without an API call' do @@ -79,7 +79,7 @@ it 'transparently makes API calls for other attributes' do expect(PuppetForge::V3::Module).to receive(:request).once.and_call_original - expect(release.module.created_at).to_not be nil + expect(release.module.created_at).not_to be_nil end end @@ -98,7 +98,7 @@ end context 'when PuppetForge.host has a path prefix' do - around(:each) do |spec| + around do |spec| old_host = PuppetForge.host PuppetForge.host = 'http://example.com/forge/api/' @@ -117,8 +117,17 @@ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') } let(:tarball) { "#{PROJECT_ROOT}/spec/tmp/module.tgz" } - before { FileUtils.rm tarball rescue nil } - after { FileUtils.rm tarball rescue nil } + before do + FileUtils.rm tarball + rescue StandardError + nil + end + + after do + FileUtils.rm tarball + rescue StandardError + nil + end it 'downloads the file to the specified location' do expect(File.exist?(tarball)).to be false @@ -127,24 +136,28 @@ end context 'when response is 403' do - it "raises PuppetForge::ReleaseForbidden" do - mock_conn = instance_double("PuppetForge::V3::Connection", :url_prefix => PuppetForge.host) + it 'raises PuppetForge::ReleaseForbidden' do + mock_conn = instance_double('PuppetForge::V3::Connection', url_prefix: PuppetForge.host) allow(described_class).to receive(:conn).and_return(mock_conn) - expect(mock_conn).to receive(:get).and_raise(Faraday::ClientError.new("403", {:status => 403, :body => ({:message => "Forbidden"}.to_json)})) + expect(mock_conn).to receive(:get).and_raise(Faraday::ClientError.new('403', + { status: 403, + body: ({ message: 'Forbidden' }.to_json), })) expect { release.download(Pathname.new(tarball)) }.to raise_error(PuppetForge::ReleaseForbidden) end end context 'when connection fails' do - it "re-raises original error" do - mock_conn = instance_double("PuppetForge::V3::Connection", :url_prefix => PuppetForge.host) + it 're-raises original error' do + mock_conn = instance_double('PuppetForge::V3::Connection', url_prefix: PuppetForge.host) allow(described_class).to receive(:conn).and_return(mock_conn) - expect(mock_conn).to receive(:get).and_raise(Faraday::ConnectionFailed.new("connection failed")) + expect(mock_conn).to receive(:get).and_raise(Faraday::ConnectionFailed.new('connection failed')) - expect { release.download(Pathname.new(tarball)) }.to raise_error(Faraday::ConnectionFailed, /connection failed/) + expect do + release.download(Pathname.new(tarball)) + end.to raise_error(Faraday::ConnectionFailed, /connection failed/) end end end @@ -154,16 +167,24 @@ let(:tarball) { "#{PROJECT_ROOT}/spec/tmp/module.tgz" } let(:allow_md5) { true } - before(:each) do - FileUtils.rm tarball rescue nil + before do + begin + FileUtils.rm tarball + rescue StandardError + nil + end release.download(Pathname.new(tarball)) end - after(:each) { FileUtils.rm tarball rescue nil } + after do + FileUtils.rm tarball + rescue StandardError + nil + end context 'file_sha256 is available' do - before(:each) do - allow(release).to receive(:file_sha256).and_return("810ff2fb242a5dee4220f2cb0e6a519891fb67f2f828a6cab4ef8894633b1f50") + before do + allow(release).to receive(:file_sha256).and_return('810ff2fb242a5dee4220f2cb0e6a519891fb67f2f828a6cab4ef8894633b1f50') end let(:mock_sha256) { double(Digest::SHA256, hexdigest: release.file_sha256) } @@ -195,7 +216,10 @@ expect(Digest::SHA256).not_to receive(:file) expect(Digest::MD5).not_to receive(:file) - expect { release.verify(tarball, allow_md5) }.to raise_error(PuppetForge::Error, /cannot verify module release.*md5.*forbidden/i) + expect do + release.verify(tarball, + allow_md5) + end.to raise_error(PuppetForge::Error, /cannot verify module release.*md5.*forbidden/i) end end end @@ -206,7 +230,7 @@ it 'is lazy and repeatable' do 3.times do - expect(release.module.releases.last.metadata).to_not be_nil + expect(release.module.releases.last.metadata).not_to be_nil end end end @@ -215,7 +239,7 @@ let(:release) { PuppetForge::V3::Release.find('puppetlabs-apache-0.0.1') } example 'are easily accessible' do - expect(release.created_at).to_not be nil + expect(release.created_at).not_to be_nil end end diff --git a/spec/unit/forge/v3/user_spec.rb b/spec/unit/forge/v3/user_spec.rb index 322398a..c164eaa 100644 --- a/spec/unit/forge/v3/user_spec.rb +++ b/spec/unit/forge/v3/user_spec.rb @@ -30,11 +30,11 @@ let(:user) { PuppetForge::V3::User.find('puppetlabs') } - it 'should return a PaginatedCollection' do + it 'returns a PaginatedCollection' do expect(user.modules).to be_a PuppetForge::V3::Base::PaginatedCollection end - it 'should only return modules for the current user' do + it 'onlies return modules for the current user' do module_owners = user.modules.map(&:owner) expect(module_owners.group_by(&:username).keys).to eql(['puppetlabs']) end @@ -44,7 +44,7 @@ let(:user) { PuppetForge::V3::User.find('puppetlabs') } example 'are easily accessible' do - expect(user.created_at).to_not be nil + expect(user.created_at).not_to be_nil end end end diff --git a/spec/unit/puppet_forge_spec.rb b/spec/unit/puppet_forge_spec.rb index 5542c2f..f1af799 100644 --- a/spec/unit/puppet_forge_spec.rb +++ b/spec/unit/puppet_forge_spec.rb @@ -3,21 +3,21 @@ RSpec.describe PuppetForge do describe 'host attribute' do - after(:each) do + after do PuppetForge.host = PuppetForge::DEFAULT_FORGE_HOST end - it 'should add a trailing slash if not present' do + it 'adds a trailing slash if not present' do PuppetForge.host = 'http://example.com' - expect(PuppetForge.host[-1,1]).to eq '/' + expect(PuppetForge.host[-1, 1]).to eq '/' end - it 'should coerce non-String values if possible' do + it 'coerces non-String values if possible' do PuppetForge.host = URI.parse('http://example.com') expect(PuppetForge.host).to be_a String - expect(PuppetForge.host[-1,1]).to eq '/' + expect(PuppetForge.host[-1, 1]).to eq '/' end end end