diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..489b5cb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: +# raise PRs for gem updates +- package-ecosystem: bundler + directory: "/" + schedule: + interval: daily + time: "13:00" + open-pull-requests-limit: 10 + +# Maintain dependencies for GitHub Actions +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + time: "13:00" + open-pull-requests-limit: 10 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a392f30..5565bcc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,14 +10,16 @@ jobs: runs-on: ubuntu-latest if: github.repository_owner == 'voxpupuli' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Ruby 3.0 uses: ruby/setup-ruby@v1 with: ruby-version: '3.0' bundler: 'none' + env: + BUNDLE_WITHOUT: release:development:rubocop - name: Build gem - run: gem build *.gemspec + run: gem build --strict --verbose *.gemspec - name: Publish gem to rubygems.org run: gem push *.gem env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b760780..273150c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,31 +1,43 @@ name: Test on: - - pull_request - - push + pull_request: {} + push: + branches: + - master + - main env: BUNDLE_WITHOUT: release jobs: + rubocop: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.0' + bundler-cache: true + - name: Run rake rubocop + run: bundle exec rake rubocop test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - - ruby: "2.4" - - ruby: "2.5" - - ruby: "2.6" - ruby: "2.7" - ruby: "3.0" - ruby: "3.1" coverage: "yes" + - ruby: "3.2" env: COVERAGE: ${{ matrix.coverage }} name: Ruby ${{ matrix.ruby }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Ruby ${{ matrix.ruby }} uses: ruby/setup-ruby@v1 with: @@ -34,4 +46,12 @@ jobs: - name: Run tests run: bundle exec rake spec - name: Verify gem builds - run: gem build *.gemspec + run: gem build --strict --verbose *.gemspec + tests: + needs: + - rubocop + - test + runs-on: ubuntu-latest + name: Test suite + steps: + - run: echo Test suite completed diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..4304779 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,12 @@ +--- +inherit_from: .rubocop_todo.yml + +# Managed by modulesync - DO NOT EDIT +# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/ + +inherit_gem: + voxpupuli-rubocop: rubocop.yml + +Naming/FileName: + Exclude: + - "*.gemspec" diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 0000000..539224b --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,80 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2023-04-21 12:21:18 UTC using RuboCop version 1.50.2. +# 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: 11 +# Configuration parameters: ForbiddenDelimiters. +# ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$)) +Naming/HeredocDelimiterNaming: + Exclude: + - 'puppet-lint-trailing_comma-check.gemspec' + - 'spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.rb' + +# Offense count: 2 +# Configuration parameters: MinSize. +Performance/CollectionLiteralInLoop: + Exclude: + - 'lib/puppet-lint/plugins/check_trailing_comma.rb' + +# Offense count: 4 +# Configuration parameters: Prefixes, AllowedPatterns. +# Prefixes: when, with, without +RSpec/ContextWording: + Exclude: + - 'spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.rb' + +# Offense count: 1 +# Configuration parameters: IgnoredMetadata. +RSpec/DescribeClass: + Exclude: + - '**/spec/features/**/*' + - '**/spec/requests/**/*' + - '**/spec/routing/**/*' + - '**/spec/system/**/*' + - '**/spec/views/**/*' + - 'spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.rb' + +# Offense count: 4 +# Configuration parameters: CountAsOne. +RSpec/ExampleLength: + Max: 53 + +# Offense count: 4 +RSpec/MultipleExpectations: + Max: 7 + +# Offense count: 4 +# Configuration parameters: AllowedGroups. +RSpec/NestedGroups: + Max: 4 + +# Offense count: 5 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Exclude: + - 'Gemfile' + - 'Rakefile' + - 'lib/puppet-lint/plugins/check_trailing_comma.rb' + - 'puppet-lint-trailing_comma-check.gemspec' + - 'spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.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-lint/plugins/check_trailing_comma.rb' + +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/SlicingWithRange: + Exclude: + - 'lib/puppet-lint/plugins/check_trailing_comma.rb' diff --git a/Gemfile b/Gemfile index 20e2ce6..d24cd36 100644 --- a/Gemfile +++ b/Gemfile @@ -3,10 +3,19 @@ source ENV['GEM_SOURCE'] || 'https://rubygems.org' gemspec group :release do - gem 'github_changelog_generator', require: false + gem 'faraday-retry', '~> 2.1', require: false + gem 'github_changelog_generator', '~> 1.16.4', require: false end -group :coverage, optional: ENV['COVERAGE']!='yes' do - gem 'simplecov-console', :require => false - gem 'codecov', :require => false +group :coverage, optional: ENV['COVERAGE'] != 'yes' do + gem 'codecov', require: false + gem 'simplecov-console', require: false +end + +group :development do + gem 'rake', '~> 13.0', '>= 13.0.6' + gem 'rspec', '~> 3.12' + gem 'rspec-collection_matchers', '~> 1.2' + gem 'rspec-its', '~> 1.3' + gem 'voxpupuli-rubocop', '~> 1.1' end diff --git a/Rakefile b/Rakefile index 302c1cb..e359ecb 100644 --- a/Rakefile +++ b/Rakefile @@ -7,13 +7,28 @@ task default: :spec begin require 'rubygems' require 'github_changelog_generator/task' - +rescue LoadError + # github-changelog-generator is an optional group +else GitHubChangelogGenerator::RakeTask.new :changelog do |config| config.header = "# Changelog\n\nAll notable changes to this project will be documented in this file." - config.exclude_labels = %w{duplicate question invalid wontfix wont-fix skip-changelog modulesync} + config.exclude_labels = %w[duplicate question invalid wontfix wont-fix skip-changelog modulesync] config.user = 'voxpupuli' config.project = 'puppet-lint-trailing_comma-check' config.future_release = Gem::Specification.load("#{config.project}.gemspec").version end +end + +begin + require 'rubocop/rake_task' rescue LoadError + # RuboCop is an optional group +else + RuboCop::RakeTask.new(:rubocop) do |task| + # These make the rubocop experience maybe slightly less terrible + task.options = ['--display-cop-names', '--display-style-guide', '--extra-details'] + + # Use Rubocop's Github Actions formatter if possible + task.formatters << 'github' if ENV['GITHUB_ACTIONS'] == 'true' + end end diff --git a/lib/puppet-lint/plugins/check_trailing_comma.rb b/lib/puppet-lint/plugins/check_trailing_comma.rb index 48fc215..abe30c1 100644 --- a/lib/puppet-lint/plugins/check_trailing_comma.rb +++ b/lib/puppet-lint/plugins/check_trailing_comma.rb @@ -1,86 +1,87 @@ PuppetLint.new_check(:trailing_comma) do def array_indexes - @array_indexes ||= Proc.new do + @array_indexes ||= proc do arrays = [] tokens.each_with_index do |token, token_idx| - if token.type == :LBRACK - real_idx = 0 - tokens[token_idx+1..-1].each_with_index do |cur_token, cur_token_idx| - real_idx = token_idx + 1 + cur_token_idx - break if cur_token.type == :RBRACK - end - - # Ignore resource references - next if token.prev_code_token && \ - token.prev_code_token.type == :CLASSREF - - # Ignore data types - next if token.prev_code_token && \ - token.prev_code_token.type == :TYPE - - arrays << { - :start => token_idx, - :end => real_idx, - :tokens => tokens[token_idx..real_idx], - } + next unless token.type == :LBRACK + + real_idx = 0 + tokens[token_idx + 1..-1].each_with_index do |cur_token, cur_token_idx| + real_idx = token_idx + 1 + cur_token_idx + break if cur_token.type == :RBRACK end + + # Ignore resource references + next if token.prev_code_token && + token.prev_code_token.type == :CLASSREF + + # Ignore data types + next if token.prev_code_token && + token.prev_code_token.type == :TYPE + + arrays << { + start: token_idx, + end: real_idx, + tokens: tokens[token_idx..real_idx], + } end arrays end.call end def hash_indexes - @hash_indexes ||= Proc.new do + @hash_indexes ||= proc do hashes = [] tokens.each_with_index do |token, token_idx| next unless token.prev_code_token - next unless [:EQUALS, :ISEQUAL, :FARROW, :LPAREN].include? token.prev_code_token.type - if token.type == :LBRACE - level = 0 - real_idx = 0 - tokens[token_idx+1..-1].each_with_index do |cur_token, cur_token_idx| - real_idx = token_idx + 1 + cur_token_idx - - level += 1 if cur_token.type == :LBRACE - level -= 1 if cur_token.type == :RBRACE - break if level < 0 - end - - hashes << { - :start => token_idx, - :end => real_idx, - :tokens => tokens[token_idx..real_idx], - } + next unless %i[EQUALS ISEQUAL FARROW LPAREN].include? token.prev_code_token.type + + next unless token.type == :LBRACE + + level = 0 + real_idx = 0 + tokens[token_idx + 1..-1].each_with_index do |cur_token, cur_token_idx| + real_idx = token_idx + 1 + cur_token_idx + + level += 1 if cur_token.type == :LBRACE + level -= 1 if cur_token.type == :RBRACE + break if level < 0 end + + hashes << { + start: token_idx, + end: real_idx, + tokens: tokens[token_idx..real_idx], + } end hashes end.call end def defaults_indexes - @defaults_indexes ||= Proc.new do + @defaults_indexes ||= proc do defaults = [] tokens.each_with_index do |token, token_idx| - if token.type == :CLASSREF && token.next_code_token && \ - token.next_code_token.type == :LBRACE && \ - token.prev_code_token && \ - # Ensure that we aren't matching a function return type: - token.prev_code_token.type != :RSHIFT && \ - # Or a conditional matching a type: - ! [:MATCH, :NOMATCH].include?(token.prev_code_token.type) - real_idx = 0 - - tokens[token_idx+1..-1].each_with_index do |cur_token, cur_token_idx| - real_idx = token_idx + 1 + cur_token_idx - break if cur_token.type == :RBRACE - end - - defaults << { - :start => token_idx, - :end => real_idx, - :tokens => tokens[token_idx..real_idx], - } + next unless token.type == :CLASSREF && token.next_code_token && + token.next_code_token.type == :LBRACE && + token.prev_code_token && + # Ensure that we aren't matching a function return type: + token.prev_code_token.type != :RSHIFT && + # Or a conditional matching a type: + !%i[MATCH NOMATCH].include?(token.prev_code_token.type) + + real_idx = 0 + + tokens[token_idx + 1..-1].each_with_index do |cur_token, cur_token_idx| + real_idx = token_idx + 1 + cur_token_idx + break if cur_token.type == :RBRACE end + + defaults << { + start: token_idx, + end: real_idx, + tokens: tokens[token_idx..real_idx], + } end defaults end.call @@ -92,21 +93,19 @@ def check_elem(elem, except_type) # If we get a token indicating the end of a HEREDOC, backtrack # until we find HEREDOC_OPEN. That is the line which should # be examined for the comma. - if lbo_token && [:HEREDOC, :HEREDOC_POST].include?(lbo_token.type) - while lbo_token && lbo_token.type != :HEREDOC_OPEN do - lbo_token = lbo_token.prev_code_token - end + if lbo_token && %i[HEREDOC HEREDOC_POST].include?(lbo_token.type) + lbo_token = lbo_token.prev_code_token while lbo_token && lbo_token.type != :HEREDOC_OPEN end - if lbo_token && lbo_token.type != except_type && \ - elem[:tokens][-1].type != :SEMIC && \ - lbo_token.type != :COMMA && \ - lbo_token.next_token.type == :NEWLINE + if lbo_token && lbo_token.type != except_type && + elem[:tokens][-1].type != :SEMIC && + lbo_token.type != :COMMA && + lbo_token.next_token.type == :NEWLINE notify :warning, { - :message => 'missing trailing comma after last element', - :line => lbo_token.next_token.line, - :column => lbo_token.next_token.column, - :token => lbo_token.next_token, + message: 'missing trailing comma after last element', + line: lbo_token.next_token.line, + column: lbo_token.next_token.column, + token: lbo_token.next_token, } end end @@ -138,7 +137,7 @@ def fix(problem) :COMMA, ',', problem[:token].line, - problem[:token].column + problem[:token].column, ) idx = tokens.index(problem[:token]) diff --git a/puppet-lint-trailing_comma-check.gemspec b/puppet-lint-trailing_comma-check.gemspec index 8d3ee21..3d3fa6a 100644 --- a/puppet-lint-trailing_comma-check.gemspec +++ b/puppet-lint-trailing_comma-check.gemspec @@ -12,18 +12,12 @@ Gem::Specification.new do |spec| 'spec/**/*', 'CHANGELOG.md', ] - spec.test_files = Dir['spec/**/*'] spec.summary = 'A puppet-lint plugin to check for missing trailing commas.' spec.description = <<-EOF A puppet-lint plugin to check for missing trailing commas. EOF - spec.required_ruby_version = Gem::Requirement.new(">= 2.0".freeze) + spec.required_ruby_version = '>= 2.7.0' - spec.add_dependency 'puppet-lint', '>= 1.0', '< 4' - spec.add_development_dependency 'rspec', '~> 3.0' - spec.add_development_dependency 'rspec-its', '~> 1.0' - spec.add_development_dependency 'rspec-collection_matchers', '~> 1.0' - spec.add_development_dependency 'simplecov' - spec.add_development_dependency 'rake' + spec.add_dependency 'puppet-lint', '>= 3', '< 5' end diff --git a/spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.rb b/spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.rb index 92d381a..785b681 100644 --- a/spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.rb +++ b/spec/puppet-lint/plugins/check_trailing_comma/check_trailing_comma_spec.rb @@ -1,11 +1,11 @@ require 'spec_helper' describe 'trailing_comma' do - let (:msg) { 'missing trailing comma after last element' } + let(:msg) { 'missing trailing comma after last element' } context 'with fix disabled' do context 'trailing comma present' do - let (:code) { + let(:code) do <<-EOS class { '::apache': timeout => '100', @@ -82,15 +82,15 @@ class { '::apache': 'c', ], EOS - } + end - it 'should not detect any problems' do + it 'does not detect any problems' do expect(problems).to have(0).problems end end context 'trailing comma absent' do - let (:code) { + let(:code) do <<-EOS class { '::apache': timeout => '100', @@ -152,13 +152,13 @@ class { '::apache': 'c' ] EOS - } + end - it 'should detect 7 problems' do + it 'detects 7 problems' do expect(problems).to have(7).problems end - it 'should create warnings' do + it 'creates warnings' do expect(problems).to contain_warning(msg).on_line(8).in_column(24) expect(problems).to contain_warning(msg).on_line(15).in_column(27) expect(problems).to contain_warning(msg).on_line(29).in_column(18) @@ -171,7 +171,7 @@ class { '::apache': context 'with heredoc' do context 'with trailing comma' do - let(:code) { + let(:code) do <<-EOS file { '/tmp/test.txt': ensure => 'file', @@ -190,15 +190,15 @@ class { '::apache': | FRAGMENT } EOS - } + end - it 'should not detect any problems' do + it 'does not detect any problems' do expect(problems).to have(0).problems end end context 'without trailing comma' do - let(:code) { + let(:code) do <<-EOS file { '/tmp/test.txt': ensure => 'file', @@ -217,13 +217,13 @@ class { '::apache': | FRAGMENT } EOS - } + end - it 'should detect a problem' do + it 'detects a problem' do expect(problems).to have(2).problems end - it 'should create a warning' do + it 'creates a warning' do expect(problems).to contain_warning(msg).on_line(3).in_column(30) expect(problems).to contain_warning(msg).on_line(11).in_column(37) end @@ -241,7 +241,7 @@ class { '::apache': end context 'trailing comma present' do - let (:code) { + let(:code) do <<-EOS class { '::apache': timeout => '100', @@ -303,19 +303,19 @@ class { '::apache': 'c', ], EOS - } + end - it 'should not detect any problems' do + it 'does not detect any problems' do expect(problems).to have(0).problems end - it 'should not modify the manifest' do + it 'does not modify the manifest' do expect(manifest).to eq(code) end end context 'trailing comma absent' do - let (:code) { + let(:code) do <<-EOS class { '::apache': timeout => '100', @@ -377,13 +377,13 @@ class { '::apache': 'c' ] EOS - } + end - it 'should detect 7 problems' do + it 'detects 7 problems' do expect(problems).to have(7).problems end - it 'should create a warning' do + it 'creates a warning' do expect(problems).to contain_fixed(msg).on_line(8).in_column(24) expect(problems).to contain_fixed(msg).on_line(15).in_column(27) expect(problems).to contain_fixed(msg).on_line(29).in_column(18) @@ -393,9 +393,9 @@ class { '::apache': expect(problems).to contain_fixed(msg).on_line(58).in_column(14) end - it 'should add trailing commas' do + it 'adds trailing commas' do expect(manifest).to eq( - <<-EOS + <<-EOS, class { '::apache': timeout => '100', docroot => '/var/www', @@ -462,7 +462,7 @@ class { '::apache': context 'with heredoc' do context 'with trailing comma' do - let(:code) { + let(:code) do <<-EOS file { '/tmp/test.txt': ensure => 'file', @@ -481,19 +481,19 @@ class { '::apache': | FRAGMENT } EOS - } + end - it 'should not detect any problems' do + it 'does not detect any problems' do expect(problems).to have(0).problems end - it 'should not modify the manifest' do + it 'does not modify the manifest' do expect(manifest).to eq(code) end end context 'without trailing comma' do - let(:code) { + let(:code) do <<-EOS file { '/tmp/test.txt': ensure => 'file', @@ -512,20 +512,20 @@ class { '::apache': | FRAGMENT } EOS - } + end - it 'should detect a problem' do + it 'detects a problem' do expect(problems).to have(2).problems end - it 'should create a warning' do + it 'creates a warning' do expect(problems).to contain_fixed(msg).on_line(3).in_column(30) expect(problems).to contain_fixed(msg).on_line(11).in_column(37) end - it 'should add trailing commas' do + it 'adds trailing commas' do expect(manifest).to eq( - <<-EOS + <<-EOS, file { '/tmp/test.txt': ensure => 'file', content => @(EOT),