Upgrade Rails to 6.1.3.1 (#11333)

* Upgrade Rails to 6.1

* Switch to unreleased bullet

* Run rails app:update

* Add deprecation notices after reading changelogs

* Fix app:update error

* Move middleware in the correct place

* Temporarily disable ransack which does not support Rails 6.1

* Remove wrongly merged file

* Re-run spring binstub

* Fix double quotes

* Track ransack branch with Rails 6.1 support

* Fix deprecation

* Switch to Ransack 2.4 which supports Rails 6.1 rc1

* Fix missing default params for the duration substitution

* Fix new behavior of relation.pluck with contradictory queries

* Fix uploaders specs by tracking rspec-rails main repo

* Disable bullet temporarily

* Fix remaining fixture_file_upload usages

* Add default seconds for video article duration

* Trigger Travis CI

* Upgrade Rails to 6.1.0.rc2

* Remove file deleted on master

* Add Rails 6.1 gem to Gemfile

* Trigger Travis CI

* Revert "Disable bullet temporarily"

This reverts commit cee0c2ce61fb72cbc16d52c94b12ee681e873031.

* Fix bullet version

* Upgrade to acts-as-taggable 7 and fix conflict

* Update Gemfile and rspec-* gems

* Fix nokogiri in Gemfile.lock

* Switch to rspec-rails main branch

* Remove leftover vendored cached items

* Fix path for Rails 6.1

* Use latest release of erb_lint

* Re-run rails app:update to incorporate new changes

* Disable erb_lint's ErbSafety checks

* Fix Gemfile.lock and re-add platform specific gems of Nokogiri

* Add mini_portile2 as well

* Fix latest merge conflict by removing now unused faraday_middleware

* Upgrade to Rails 6.1.3.1

* Regenerate Gemfile.lock and vendor/cache

* Add x86_64 linux gem

* Mark spec as flaky

* Revert "Mark spec as flaky"

This reverts commit 3caba94b33645f9b59c84ba78ee8df042fc7aee0.

Co-authored-by: Mac Siri <krairit.siri@gmail.com>
This commit is contained in:
rhymes 2021-04-05 16:39:48 +02:00 committed by GitHub
parent e8098c8e5c
commit b6360fb80c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
198 changed files with 371 additions and 8254 deletions

View file

@ -1,4 +1,8 @@
linters:
ErbSafety:
# TODO: [@rhymes] re-enable this and fix the violations,
# see https://github.com/Shopify/erb-lint#ErbSafety
enabled: false
SelfClosingTag:
enabled: false
ParserErrors:

View file

@ -74,7 +74,7 @@ gem "pusher-push-notifications", "~> 2.0" # Pusher Push Notifications Ruby serve
gem "rack-attack", "~> 6.5.0" # Used to throttle requests to prevent brute force attacks
gem "rack-cors", "~> 1.1" # Middleware that will make Rack-based apps CORS compatible
gem "rack-timeout", "~> 0.6" # Rack middleware which aborts requests that have been running for longer than a specified timeout
gem "rails", "~> 6.0.3" # Ruby on Rails
gem "rails", "~> 6.1" # Ruby on Rails
gem "rails-settings-cached", ">= 2.1.1" # Settings plugin for Rails that makes managing a table of global key, value pairs easy.
gem "ransack", "~> 2.4" # Searching and sorting
gem "recaptcha", "~> 5.7", require: "recaptcha/rails" # Helpers for the reCAPTCHA API
@ -124,10 +124,9 @@ group :development do
gem "brakeman", "~> 5.0", require: false # Brakeman detects security vulnerabilities in Ruby on Rails applications via static analysis
gem "bundler-audit", "~> 0.8" # bundler-audit provides patch-level verification for Bundled apps
gem "derailed_benchmarks", "~> 2.0", require: false # A series of things you can use to benchmark a Rails or Ruby app
gem "erb_lint", github: "thepracticaldev/erb-lint", branch: "jess/remove-version-pinning", require: false # ERB Linter tool
gem "erb_lint", "~> 0.0.37", require: false # ERB Linter tool
gem "guard", "~> 2.16", require: false # Guard is a command line tool to easily handle events on file system modifications
gem "guard-livereload", "~> 2.5", require: false # Guard::LiveReload automatically reloads your browser when 'view' files are modified
gem "guard-rspec", "~> 4.7", require: false # Guard::RSpec automatically run your specs
gem "listen", "~> 3.5", require: false # Helps 'listen' to file system modifications events (also used by other gems like guard)
gem "memory_profiler", "~> 1.0", require: false # Memory profiling routines for Ruby 2.3+
gem "pry", "~> 0.13" # An IRB alternative and runtime developer console

View file

@ -18,85 +18,75 @@ GIT
responders
warden (~> 1.2.3)
GIT
remote: https://github.com/thepracticaldev/erb-lint.git
revision: 05596ea189ee00fb2ad3ea10a41489e2dba345c4
branch: jess/remove-version-pinning
specs:
erb_lint (0.0.35)
activesupport
better_html (~> 1.0.7)
html_tokenizer
parser (>= 2.7.1.4)
rainbow
rubocop
smart_properties
GEM
remote: https://rubygems.org/
specs:
actioncable (6.0.3.5)
actionpack (= 6.0.3.5)
actioncable (6.1.3.1)
actionpack (= 6.1.3.1)
activesupport (= 6.1.3.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.0.3.5)
actionpack (= 6.0.3.5)
activejob (= 6.0.3.5)
activerecord (= 6.0.3.5)
activestorage (= 6.0.3.5)
activesupport (= 6.0.3.5)
actionmailbox (6.1.3.1)
actionpack (= 6.1.3.1)
activejob (= 6.1.3.1)
activerecord (= 6.1.3.1)
activestorage (= 6.1.3.1)
activesupport (= 6.1.3.1)
mail (>= 2.7.1)
actionmailer (6.0.3.5)
actionpack (= 6.0.3.5)
actionview (= 6.0.3.5)
activejob (= 6.0.3.5)
actionmailer (6.1.3.1)
actionpack (= 6.1.3.1)
actionview (= 6.1.3.1)
activejob (= 6.1.3.1)
activesupport (= 6.1.3.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.0.3.5)
actionview (= 6.0.3.5)
activesupport (= 6.0.3.5)
rack (~> 2.0, >= 2.0.8)
actionpack (6.1.3.1)
actionview (= 6.1.3.1)
activesupport (= 6.1.3.1)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.0.3.5)
actionpack (= 6.0.3.5)
activerecord (= 6.0.3.5)
activestorage (= 6.0.3.5)
activesupport (= 6.0.3.5)
actiontext (6.1.3.1)
actionpack (= 6.1.3.1)
activerecord (= 6.1.3.1)
activestorage (= 6.1.3.1)
activesupport (= 6.1.3.1)
nokogiri (>= 1.8.5)
actionview (6.0.3.5)
activesupport (= 6.0.3.5)
actionview (6.1.3.1)
activesupport (= 6.1.3.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_record_union (1.3.0)
activerecord (>= 4.0)
activejob (6.0.3.5)
activesupport (= 6.0.3.5)
activejob (6.1.3.1)
activesupport (= 6.1.3.1)
globalid (>= 0.3.6)
activemodel (6.0.3.5)
activesupport (= 6.0.3.5)
activerecord (6.0.3.5)
activemodel (= 6.0.3.5)
activesupport (= 6.0.3.5)
activestorage (6.0.3.5)
actionpack (= 6.0.3.5)
activejob (= 6.0.3.5)
activerecord (= 6.0.3.5)
marcel (~> 0.3.1)
activesupport (6.0.3.5)
activemodel (6.1.3.1)
activesupport (= 6.1.3.1)
activerecord (6.1.3.1)
activemodel (= 6.1.3.1)
activesupport (= 6.1.3.1)
activestorage (6.1.3.1)
actionpack (= 6.1.3.1)
activejob (= 6.1.3.1)
activerecord (= 6.1.3.1)
activesupport (= 6.1.3.1)
marcel (~> 1.0.0)
mini_mime (~> 1.0.2)
activesupport (6.1.3.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
acts-as-taggable-on (7.0.0)
activerecord (>= 5.0, < 6.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
ahoy_email (1.1.0)
ahoy_email (1.1.1)
actionmailer (>= 5)
addressable (>= 2.3.2)
nokogiri
@ -126,7 +116,7 @@ GEM
coderay (>= 1.0.0)
erubi (>= 1.0.0)
rack (>= 0.9.0)
better_html (1.0.15)
better_html (1.0.16)
actionview (>= 4.0)
activesupport (>= 4.0)
ast (~> 2.0)
@ -145,7 +135,7 @@ GEM
bootsnap (1.7.3)
msgpack (~> 1.0)
brakeman (5.0.0)
browser (5.2.0)
browser (5.3.1)
brpoplpush-redis_script (0.1.2)
concurrent-ruby (~> 1.0, >= 1.0.5)
redis (>= 1.0, <= 5.0)
@ -166,12 +156,12 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
carrierwave (2.2.0)
carrierwave (2.2.1)
activemodel (>= 5.0.0)
activesupport (>= 5.0.0)
addressable (~> 2.6)
image_processing (~> 1.1)
mimemagic (>= 0.3.0)
marcel (~> 1.0.0)
mini_mime (>= 0.1.3)
ssrf_filter (~> 1.0)
carrierwave-bombshelter (0.2.2)
@ -207,8 +197,8 @@ GEM
dante (0.2.0)
ddtrace (0.47.0)
msgpack
dead_end (1.1.4)
debug_inspector (0.0.3)
dead_end (1.1.6)
debug_inspector (1.1.0)
derailed_benchmarks (2.0.1)
benchmark-ips (~> 2)
dead_end
@ -229,8 +219,8 @@ GEM
devise (>= 4.6)
diff-lcs (1.4.4)
distribution (0.8.0)
docile (1.3.4)
dogstatsd-ruby (4.8.3)
docile (1.3.5)
dogstatsd-ruby (4.9.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (5.5.0)
@ -254,6 +244,14 @@ GEM
activemodel
emoji_regex (3.2.2)
equalizer (0.0.11)
erb_lint (0.0.37)
activesupport
better_html (~> 1.0.7)
html_tokenizer
parser (>= 2.7.1.4)
rainbow
rubocop
smart_properties
errbase (0.2.1)
erubi (1.10.0)
et-orbi (1.2.4)
@ -274,7 +272,7 @@ GEM
multipart-post (>= 1.2, < 3)
ruby2_keywords
faraday-net_http (1.0.1)
fastimage (2.2.1)
fastimage (2.2.3)
fastly (3.0.1)
feedjira (3.1.2)
loofah (>= 2.3.1)
@ -315,11 +313,11 @@ GEM
nokogiri (>= 1.5.11, < 2.0.0)
formatador (0.2.5)
front_matter_parser (1.0.0)
fugit (1.4.1)
fugit (1.4.4)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.4)
gemoji (4.0.0.rc2)
geocoder (1.6.5)
geocoder (1.6.6)
get_process_mem (0.2.7)
ffi (~> 1.0)
gibbon (3.4.0)
@ -342,10 +340,6 @@ GEM
guard (~> 2.8)
guard-compat (~> 1.0)
multi_json (~> 1.8)
guard-rspec (4.7.3)
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
hashdiff (1.0.1)
hashie (4.1.0)
heapy (0.2.0)
@ -422,8 +416,9 @@ GEM
rake
launchy (2.5.0)
addressable (~> 2.7)
libhoney (1.17.0)
libhoney (1.18.0)
addressable (~> 2.0)
excon
http (>= 2.0, < 5.0)
liquid (5.0.1)
listen (3.5.1)
@ -435,8 +430,7 @@ GEM
lumberjack (1.2.8)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
marcel (1.0.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
memory_profiler (1.0.0)
@ -444,11 +438,9 @@ GEM
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0225)
mimemagic (0.3.5)
mini_histogram (0.3.1)
mini_magick (4.11.0)
mini_mime (1.0.2)
mini_portile2 (2.5.0)
mini_mime (1.0.3)
minitest (5.14.4)
modis (3.3.0)
activemodel (>= 4.2)
@ -470,9 +462,6 @@ GEM
http-2 (~> 0.11)
netrc (0.11.0)
nio4r (2.5.7)
nokogiri (1.11.2)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
nokogiri (1.11.2-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.11.2-x86_64-linux)
@ -481,7 +470,7 @@ GEM
nenv (~> 0.1)
shellany (~> 0.0)
oauth (0.5.5)
oauth2 (1.4.4)
oauth2 (1.4.7)
faraday (>= 0.8, < 2.0)
jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
@ -563,20 +552,20 @@ GEM
rack-test (1.1.0)
rack (>= 1.0, < 3)
rack-timeout (0.6.0)
rails (6.0.3.5)
actioncable (= 6.0.3.5)
actionmailbox (= 6.0.3.5)
actionmailer (= 6.0.3.5)
actionpack (= 6.0.3.5)
actiontext (= 6.0.3.5)
actionview (= 6.0.3.5)
activejob (= 6.0.3.5)
activemodel (= 6.0.3.5)
activerecord (= 6.0.3.5)
activestorage (= 6.0.3.5)
activesupport (= 6.0.3.5)
bundler (>= 1.3.0)
railties (= 6.0.3.5)
rails (6.1.3.1)
actioncable (= 6.1.3.1)
actionmailbox (= 6.1.3.1)
actionmailer (= 6.1.3.1)
actionpack (= 6.1.3.1)
actiontext (= 6.1.3.1)
actionview (= 6.1.3.1)
activejob (= 6.1.3.1)
activemodel (= 6.1.3.1)
activerecord (= 6.1.3.1)
activestorage (= 6.1.3.1)
activesupport (= 6.1.3.1)
bundler (>= 1.15.0)
railties (= 6.1.3.1)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
@ -585,12 +574,12 @@ GEM
loofah (~> 2.3)
rails-settings-cached (2.5.2)
rails (>= 5.0.0)
railties (6.0.3.5)
actionpack (= 6.0.3.5)
activesupport (= 6.0.3.5)
railties (6.1.3.1)
actionpack (= 6.1.3.1)
activesupport (= 6.1.3.1)
method_source
rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0)
thor (~> 1.0)
rainbow (3.0.0)
rake (13.0.3)
ransack (2.4.2)
@ -648,10 +637,6 @@ GEM
webpush (~> 1.0)
rpush-redis (1.1.0)
modis (~> 3.0)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
@ -696,8 +681,8 @@ GEM
ruby-prof (1.4.3)
ruby-progressbar (1.11.0)
ruby-statistics (2.1.3)
ruby-vips (2.0.17)
ffi (~> 1.9)
ruby-vips (2.1.0)
ffi (~> 1.12)
ruby2_keywords (0.0.4)
rubyzip (2.3.0)
s3_direct_upload (0.1.7)
@ -729,7 +714,7 @@ GEM
selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
semantic_range (2.3.1)
semantic_range (3.0.0)
shellany (0.0.1)
shoulda-matchers (4.5.1)
activesupport (>= 4.2.0)
@ -797,8 +782,8 @@ GEM
multipart-post (~> 2.0)
naught (~> 1.0)
simple_oauth (~> 0.3.0)
tzinfo (1.2.9)
thread_safe (~> 0.1)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
ulid (1.3.0)
@ -806,7 +791,7 @@ GEM
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (2.0.0)
uniform_notifier (1.14.1)
uniform_notifier (1.14.2)
validate_url (1.0.13)
activemodel (>= 3.0.0)
public_suffix
@ -856,9 +841,7 @@ GEM
zonebie (0.6.1)
PLATFORMS
ruby
x86_64-darwin-19
x86_64-darwin-20
x86_64-linux
DEPENDENCIES
@ -893,7 +876,7 @@ DEPENDENCIES
elasticsearch (~> 7.12)
email_validator (~> 2.2)
emoji_regex (~> 3.2)
erb_lint!
erb_lint (~> 0.0.37)
exifr (>= 1.3.6)
factory_bot_rails (~> 6.1)
faker (~> 2.17)
@ -909,7 +892,6 @@ DEPENDENCIES
gibbon (~> 3.4)
guard (~> 2.16)
guard-livereload (~> 2.5)
guard-rspec (~> 4.7)
honeybadger (~> 4.8)
honeycomb-beeline (~> 2.4.0)
html_truncator (~> 0.4)
@ -954,7 +936,7 @@ DEPENDENCIES
rack-cors (~> 1.1)
rack-host-redirect (~> 1.3)
rack-timeout (~> 0.6)
rails (~> 6.0.3)
rails (~> 6.1)
rails-settings-cached (>= 2.1.1)
ransack (~> 2.4)
recaptcha (~> 5.7)
@ -1018,4 +1000,4 @@ RUBY VERSION
ruby 2.7.2p137
BUNDLED WITH
2.2.14
2.2.15

View file

@ -400,6 +400,10 @@ class Article < ApplicationRecord
def video_duration_in_minutes
duration = ActiveSupport::Duration.build(video_duration_in_seconds.to_i).parts
# add default hours and minutes for the substitutions below
duration = duration.reverse_merge(seconds: 0, minutes: 0, hours: 0)
minutes_and_seconds = format("%<minutes>02d:%<seconds>02d", duration)
return minutes_and_seconds if duration[:hours] < 1
@ -468,7 +472,7 @@ class Article < ApplicationRecord
self.description = processed_description if description.blank?
rescue StandardError => e
errors[:base] << ErrorMessages::Clean.call(e.message)
errors.add(:base, ErrorMessages::Clean.call(e.message))
end
def set_tag_list(tags)

View file

@ -1,4 +1,6 @@
class AnalyticsService
DEFAULT_REACTION_TOTALS = { total: 0, like: 0, readinglist: 0, unicorn: 0 }.freeze
def initialize(user_or_org, start_date: "", end_date: "", article_id: nil)
@user_or_org = user_or_org
@article_id = article_id
@ -107,9 +109,13 @@ class AnalyticsService
Arel.sql("COUNT(*) FILTER (WHERE category = 'unicorn')"),
)
# this transforms the counts, eg. [1, 0, 1, 0]
# in a hash, eg. {total: 1, like: 0, readinglist: 1, unicorn: 0}
keys.zip(counts).to_h
if counts
# this transforms the counts, eg. [1, 0, 1, 0]
# in a hash, eg. {total: 1, like: 0, readinglist: 1, unicorn: 0}
keys.zip(counts).to_h
else
DEFAULT_REACTION_TOTALS
end
end
def calculate_page_views_totals

View file

View file

@ -1,4 +1,5 @@
#!/usr/bin/env ruby
load File.expand_path("spring", __dir__)
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
require_relative "../config/boot"
require "rails/commands"

View file

@ -1,4 +1,5 @@
#!/usr/bin/env ruby
require_relative '../config/boot'
require 'rake'
load File.expand_path("spring", __dir__)
require_relative "../config/boot"
require "rake"
Rake.application.run

View file

@ -1,6 +1,5 @@
#!/usr/bin/env ruby
require "fileutils"
include FileUtils
# path to your application root.
APP_ROOT = File.expand_path("..", __dir__)
@ -9,7 +8,7 @@ def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end
chdir APP_ROOT do
FileUtils.chdir APP_ROOT do
# This script is a way to set up or update your development environment automatically.
# This script is idempotent, so that you can run it at anytime and get an expectable outcome.
# Add necessary setup steps to this file.
@ -28,7 +27,7 @@ chdir APP_ROOT do
puts "\n== Copying sample files =="
unless File.exist?("config/database.yml")
cp "config/database.yml.sample", "config/database.yml"
FileUtils.cp "config/database.yml.sample", "config/database.yml"
end
puts "\n== Preparing Test Elasticsearch =="

View file

@ -1,17 +1,14 @@
#!/usr/bin/env ruby
# This file loads spring without using Bundler, in order to be fast.
# It gets overwritten when you run the `spring binstub` command.
unless defined?(Spring)
require "rubygems"
if !defined?(Spring) && [nil, "development", "test"].include?(ENV["RAILS_ENV"])
gem "bundler"
require "bundler"
lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
spring = lockfile.specs.detect { |spec| spec.name == "spring" }
if spring
# Load Spring without loading other gems in the Gemfile, for speed.
Bundler.locked_gems&.specs&.find { |spec| spec.name == "spring" }&.tap do |spring|
Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
gem "spring", spring.version
require "spring/binstub"
rescue Gem::LoadError
# Ignore when Spring is not installed.
end
end

View file

@ -1,9 +1,15 @@
#!/usr/bin/env ruby
APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do
begin
exec "yarnpkg", *ARGV
rescue Errno::ENOENT
yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
select { |dir| File.expand_path(dir) != __dir__ }.
product(["yarn", "yarn.cmd", "yarn.ps1"]).
map { |dir, file| File.expand_path(file, dir) }.
find { |file| File.executable?(file) }
if yarn
exec yarn, *ARGV
else
$stderr.puts "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1

View file

@ -1,4 +1,6 @@
# This file is used by Rack-based servers to start the application.
require ::File.expand_path("config/environment", __dir__)
require_relative "config/environment"
run Rails.application
Rails.application.load_server

View file

@ -8,6 +8,8 @@ require "active_record/railtie"
# require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
# require "action_mailbox/engine"
# require "action_text/engine"
require "action_view/railtie"
# require "action_cable/engine"
require "sprockets/railtie"

View file

@ -1,10 +1,11 @@
require "active_support/core_ext/integer/time"
# rubocop:disable Metrics/BlockLength
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
config.cache_classes = false
# Do not eager load code on boot.
@ -17,6 +18,7 @@ Rails.application.configure do
# Run rails dev:cache to toggle caching.
if Rails.root.join("tmp/caching-dev.txt").exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
DEFAULT_EXPIRATION = 1.hour.to_i.freeze
config.cache_store = :redis_cache_store, { url: ENV["REDIS_URL"], expires_in: DEFAULT_EXPIRATION }
@ -30,9 +32,6 @@ Rails.application.configure do
config.cache_store = :null_store
end
# Store uploaded files on the local file system (see config/storage.yml for options)
# config.active_storage.service = :local
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
@ -41,6 +40,12 @@ Rails.application.configure do
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
@ -64,6 +69,12 @@ Rails.application.configure do
# Suppress logger output for asset requests.
config.assets.quiet = true
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
@ -92,9 +103,6 @@ Rails.application.configure do
config.action_mailer.preview_path = Rails.root.join("spec/mailers/previews")
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
config.public_file_server.enabled = true
# Use an evented file watcher to asynchronously detect changes in source code,
@ -104,6 +112,9 @@ Rails.application.configure do
# Debug is the default log_level, but can be changed per environment.
config.log_level = :debug
# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new($stdout)
logger.formatter = config.log_formatter

View file

@ -1,3 +1,5 @@
require "active_support/core_ext/integer/time"
# rubocop:disable Metrics/BlockLength
Rails.application.configure do
# Allow the app to know when booted up in context where we haven't set ENV vars
@ -57,9 +59,6 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options)
# config.active_storage.service = :local
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = ENV["FORCE_SSL_IN_RAILS"] == "true"
@ -79,7 +78,7 @@ Rails.application.configure do
# Use a real queuing backend for Active Job (and separate queues per environment)
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "practical_developer_#{Rails.env}"
# config.active_job.queue_name_prefix = "practical_developer_production"
config.action_mailer.perform_caching = false
@ -94,6 +93,12 @@ Rails.application.configure do
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Log disallowed deprecations.
config.active_support.disallowed_deprecation = :log
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Filter sensitive information from production logs
config.filter_parameters += %i[
auth_data_dump content email encrypted
@ -138,6 +143,27 @@ Rails.application.configure do
config.middleware.use Rack::HostRedirect,
ENV["HEROKU_APP_URL"] => ENV["APP_DOMAIN"]
end
# Inserts middleware to perform automatic connection switching.
# The `database_selector` hash is used to pass options to the DatabaseSelector
# middleware. The `delay` is used to determine how long to wait after a write
# to send a subsequent read to the primary.
#
# The `database_resolver` class is used by the middleware to determine which
# database is appropriate to use based on the time delay.
#
# The `database_resolver_context` class is used by the middleware to set
# timestamps for the last write to the primary. The resolver uses the context
# class timestamps to determine how long to wait before reading from the
# replica.
#
# By default Rails will store a last write timestamp in the session. The
# DatabaseSelector middleware is designed as such you can define your own
# strategy for connection switching and pass that into the middleware through
# these configuration options.
# config.active_record.database_selector = { delay: 2.seconds }
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end
# rubocop:enable Metrics/BlockLength

View file

@ -1,25 +1,23 @@
require "active_support/core_ext/integer/time"
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
# rubocop:disable Metrics/BlockLength
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
config.cache_classes = true
# Include middleware to ensure timezone for browser requests for Capybara specs
# matches the random zonebie timezone set at the beginning of our spec run
config.middleware.use SetTimeZone
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# See https://github.com/rails/rails/issues/40613#issuecomment-727283155
config.action_view.cache_template_loading = true
# NOTE: [Rails 6] this is the default store in testing,
# as we haven't enabled Rails 6.0 defaults in config/application.rb,
# we need to keep this explicit, for now
config.cache_store = :null_store
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
@ -34,6 +32,7 @@ Rails.application.configure do
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
@ -41,9 +40,6 @@ Rails.application.configure do
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Store uploaded files on the local file system in a temporary directory
# config.active_storage.service = :test
config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
@ -60,14 +56,23 @@ Rails.application.configure do
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
config.active_job.queue_adapter = :test
# Debug is the default log_level, but can be changed per environment.
config.log_level = :debug
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names
# config.action_view.annotate_rendered_view_with_filenames = true
# enable Bullet in testing mode only if requested
config.after_initialize do
Bullet.enable = true

View file

@ -1,7 +1,8 @@
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]

View file

@ -5,29 +5,29 @@
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
Rails.application.config.content_security_policy do |policy|
# if Rails.env.production?
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
# policy.object_src :none
# policy.script_src :self, :https, :unsafe_inline
# policy.style_src :self, :https, :unsafe_inline
# policy.connect_src :self, :https, :unsafe_inline, "*.pusher.com"
# end
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# policy.script_src :self, :https
# policy.style_src :self, :https
# allow webpack-dev-server host as allowed origin for connect-src
# If you are using webpack-dev-server then specify webpack-dev-server host
if Rails.env.development?
webpack_host = "#{ApplicationConfig.app_domain_no_port}:3035"
policy.connect_src :self, :https,
"http://#{webpack_host}", "ws://#{webpack_host}"
policy.connect_src :self, :https, "http://#{webpack_host}", "ws://#{webpack_host}"
end
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Set the nonce only to specific directives
# Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only

View file

@ -1,5 +1,10 @@
# Be sure to restart your server when you modify this file.
# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
# Read more: https://github.com/cyu/rack-cors
# Enable CORS for API v0 (logging is only activated when debug is enabled)
Rails.application.config.middleware.insert_before(
0,

View file

@ -0,0 +1,11 @@
# Define an application-wide HTTP feature policy. For further
# information see https://developers.google.com/web/updates/2018/06/feature-policy
#
# Rails.application.config.feature_policy do |f|
# f.camera :none
# f.gyroscope :none
# f.microphone :none
# f.usb :none
# f.fullscreen :self
# f.payment :self, "https://secure.example.com"
# end

View file

@ -1,4 +1,6 @@
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password]
Rails.application.config.filter_parameters += %i[
password passw secret token _key crypt salt certificate otp ssn
]

View file

@ -36,6 +36,7 @@ Rails.application.config.action_controller.default_protect_from_forgery = true
# see <https://github.com/rails/rails/blob/5-2-stable/actionview/lib/action_view/digestor.rb> and
# <https://github.com/rails/rails/blob/5-2-stable/actionview/lib/action_view/helpers/cache_helper.rb#L227>
# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header.
# NOTE: deprecated in Rails 6.1 in favor of config.active_support.hash_digest_class = ::Digest::SHA1
# Rails.application.config.active_support.use_sha1_digests = true
# Make `form_with` generate id attributes for any generated HTML tags.

View file

@ -16,9 +16,11 @@
# It's best enabled when your entire app is migrated and stable on 6.0.
# Rails.application.config.action_dispatch.use_cookies_with_metadata = true
# NOTE: deprecated in Rails 6.1, see <https://github.com/rails/rails/commit/64efe502f3c7bbf6d17fc1470f4b15d0c9a08b02>
# Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification.
# Rails.application.config.action_dispatch.return_only_media_type_on_content_type = false
# NOTE: deprecated in Rails 6.1, see <https://github.com/rails/rails/commit/fd24cf1c5d02425dbd12179590d9ea225e700b01>
# Return false instead of self when enqueuing is aborted from a callback.
# Rails.application.config.active_job.return_false_on_aborted_enqueue = true

View file

@ -0,0 +1,67 @@
# Be sure to restart your server when you modify this file.
#
# This file contains migration options to ease your Rails 6.1 upgrade.
#
# Once upgraded flip defaults one by one to migrate to the new default.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
# Support for inversing belongs_to -> has_many Active Record associations.
# Rails.application.config.active_record.has_many_inversing = true
# Track Active Storage variants in the database.
# Rails.application.config.active_storage.track_variants = true
# Apply random variation to the delay when retrying failed jobs.
# Rails.application.config.active_job.retry_jitter = 0.15
# Stop executing `after_enqueue`/`after_perform` callbacks if
# `before_enqueue`/`before_perform` respectively halts with `throw :abort`.
# Rails.application.config.active_job.skip_after_callbacks_if_terminated = true
# Specify cookies SameSite protection level: either :none, :lax, or :strict.
#
# This change is not backwards compatible with earlier Rails versions.
# It's best enabled when your entire app is migrated and stable on 6.1.
# Rails.application.config.action_dispatch.cookies_same_site_protection = :lax
# Generate CSRF tokens that are encoded in URL-safe Base64.
#
# This change is not backwards compatible with earlier Rails versions.
# It's best enabled when your entire app is migrated and stable on 6.1.
# Rails.application.config.action_controller.urlsafe_csrf_tokens = true
# Specify whether `ActiveSupport::TimeZone.utc_to_local` returns a time with an
# UTC offset or a UTC time.
# ActiveSupport.utc_to_local_returns_utc_offset_times = true
# Change the default HTTP status code to `308` when redirecting non-GET/HEAD
# requests to HTTPS in `ActionDispatch::SSL` middleware.
# Rails.application.config.action_dispatch.ssl_default_redirect_status = 308
# Use new connection handling API. For most applications this won't have any
# effect. For applications using multiple databases, this new API provides
# support for granular connection swapping.
# Rails.application.config.active_record.legacy_connection_handling = false
# Make `form_with` generate non-remote forms by default.
# Rails.application.config.action_view.form_with_generates_remote_forms = false
# Set the default queue name for the analysis job to the queue adapter default.
# Rails.application.config.active_storage.queues.analysis = nil
# Set the default queue name for the purge job to the queue adapter default.
# Rails.application.config.active_storage.queues.purge = nil
# Set the default queue name for the incineration job to the queue adapter default.
# Rails.application.config.action_mailbox.queues.incineration = nil
# Set the default queue name for the routing job to the queue adapter default.
# Rails.application.config.action_mailbox.queues.routing = nil
# Set the default queue name for the mail deliver job to the queue adapter default.
# Rails.application.config.action_mailer.deliver_later_queue_name = nil
# Generate a `Link` header that gives a hint to modern browsers about
# preloading assets when using `javascript_include_tag` and `stylesheet_link_tag`.
# Rails.application.config.action_view.preload_links_header = true

View file

@ -0,0 +1,11 @@
# Define an application-wide HTTP permissions policy. For further
# information see https://developers.google.com/web/updates/2018/06/feature-policy
#
# Rails.application.config.permissions_policy do |f|
# f.camera :none
# f.gyroscope :none
# f.microphone :none
# f.usb :none
# f.fullscreen :self
# f.payment :self, "https://secure.example.com"
# end

View file

@ -27,7 +27,7 @@
# 'true': 'foo'
#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
# available at https://guides.rubyonrails.org/i18n.html.
en:
hello: "Hello world"

View file

@ -19,7 +19,7 @@ environment ENV.fetch("RAILS_ENV") { "development" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked webserver processes. If using threads and workers together
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).

View file

@ -1,6 +1,6 @@
%w[
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
].each { |path| Spring.watch(path) }
Spring.watch(
".ruby-version",
".rbenv-vars",
"tmp/restart.txt",
"tmp/caching-dev.txt",
)

View file

@ -52,7 +52,10 @@
"app/views/**/*.jbuilder": [
"bundle exec rubocop --require rubocop-rspec --auto-correct"
],
"Gemfile": [
"./Gemfile": [
"bundle exec rubocop --require rubocop-rspec --auto-correct"
],
"docs/Gemfile": [
"bundle exec rubocop --require rubocop-rspec --auto-correct"
],
"*.rake": [

View file

@ -54,9 +54,9 @@ RSpec.describe "/admin/podcasts", type: :request do
soundcloud_url: "https://soundcloud.example.com",
website_url: "https://example.com",
twitter_username: "@ThePracticalDev",
pattern_image: fixture_file_upload("files/800x600.png", "image/png"),
pattern_image: fixture_file_upload("800x600.png", "image/png"),
main_color_hex: "ffffff",
image: fixture_file_upload("files/podcast.png", "image/png"),
image: fixture_file_upload("podcast.png", "image/png"),
slug: "postcast-test-url",
reachable: true,
published: true

View file

@ -33,7 +33,7 @@ RSpec.describe "OrganizationsUpdate", type: :request do
it "updates nav_image" do
put "/organizations/#{org_id}", params: { organization: { id: org_id,
nav_image: fixture_file_upload("files/podcast.png",
nav_image: fixture_file_upload("podcast.png",
"image/png") } }
expect(Organization.find(org_id).nav_image_url).to be_present
end
@ -48,7 +48,7 @@ RSpec.describe "OrganizationsUpdate", type: :request do
it "returns error if profile image file name is too long" do
organization = user.organizations.first
allow(Organization).to receive(:find_by).and_return(organization)
image = fixture_file_upload("files/800x600.png", "image/png")
image = fixture_file_upload("800x600.png", "image/png")
allow(image).to receive(:original_filename).and_return("#{'a_very_long_filename' * 15}.png")
put "/organizations/#{org_id}", params: { organization: { id: org_id, profile_image: image } }

View file

@ -16,7 +16,7 @@ RSpec.describe "Podcast Create", type: :request do
title: Faker::Hipster.words(number: 2).join(", "),
description: Faker::Hipster.paragraph(sentence_count: 1),
twitter_username: "hello-pod",
image: fixture_file_upload("files/podcast.png", "image/png"),
image: fixture_file_upload("podcast.png", "image/png"),
slug: "hello-pod",
main_color_hex: "ffffff",
website_url: Faker::Internet.url,
@ -76,7 +76,7 @@ RSpec.describe "Podcast Create", type: :request do
end
it "returns error if image file name is too long" do
image = fixture_file_upload("files/podcast.png", "image/png")
image = fixture_file_upload("podcast.png", "image/png")
allow(image).to receive(:original_filename).and_return("#{'a_very_long_filename' * 15}.png")
valid_attributes[:image] = image
post podcasts_path, params: { podcast: valid_attributes }
@ -91,7 +91,7 @@ RSpec.describe "Podcast Create", type: :request do
end
it "returns error if pattern_image file name is too long" do
image = fixture_file_upload("files/podcast.png", "image/png")
image = fixture_file_upload("podcast.png", "image/png")
allow(image).to receive(:original_filename).and_return("#{'a_very_long_filename' * 15}.png")
valid_attributes[:pattern_image] = image
post podcasts_path, params: { podcast: valid_attributes }

View file

@ -70,7 +70,7 @@ RSpec.describe "UserOrganization", type: :request do
it "returns error if profile image file name is too long" do
sign_in user
org_params = build(:organization).attributes
image = fixture_file_upload("files/800x600.png", "image/png")
image = fixture_file_upload("800x600.png", "image/png")
allow(image).to receive(:original_filename).and_return("#{'a_very_long_filename' * 15}.png")
org_params["profile_image"] = image
allow(Organization).to receive(:new).and_return(organization)

View file

@ -48,7 +48,7 @@ RSpec.describe Profiles::Update, type: :service do
end
it "returns an error if Profile image is too large" do
profile_image = fixture_file_upload("files/large_profile_img.jpg", "image/jpeg")
profile_image = fixture_file_upload("large_profile_img.jpg", "image/jpeg")
service = described_class.call(user, profile: {}, user: { profile_image: profile_image })
expect(service.success?).to be false
@ -64,7 +64,7 @@ RSpec.describe Profiles::Update, type: :service do
end
it "returns an error if Profile image file name is too long" do
profile_image = fixture_file_upload("files/800x600.png", "image/png")
profile_image = fixture_file_upload("800x600.png", "image/png")
allow(profile_image).to receive(:original_filename).and_return("#{'a_very_long_filename' * 15}.png")
service = described_class.call(user, profile: {}, user: { profile_image: profile_image })
@ -80,7 +80,7 @@ RSpec.describe Profiles::Update, type: :service do
end
it "enqueues resave articles job when changing profile_image" do
profile_image = fixture_file_upload("files/800x600.jpg")
profile_image = fixture_file_upload("800x600.jpg")
sidekiq_assert_resave_article_worker(user) do
described_class.call(user, user: { profile_image: profile_image })

View file

@ -5,11 +5,11 @@ require "exifr/jpeg"
describe ArticleImageUploader, type: :uploader do
include CarrierWave::Test::Matchers
let(:image_jpg) { fixture_file_upload("files/800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("files/800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("files/800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("files/image_gps_data.jpg", "image/jpeg") }
let(:high_frame_count) { fixture_file_upload("files/high_frame_count.gif", "image/gif") }
let(:image_jpg) { fixture_file_upload("800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("image_gps_data.jpg", "image/jpeg") }
let(:high_frame_count) { fixture_file_upload("high_frame_count.gif", "image/gif") }
# we need a new uploader before each test, and since the uploader is not a model
# we can recreate it quickly in memory with `let!`

View file

@ -5,10 +5,10 @@ require "exifr/jpeg"
describe BadgeUploader, type: :uploader do
include CarrierWave::Test::Matchers
let(:image_jpg) { fixture_file_upload("files/800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("files/800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("files/800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("files/image_gps_data.jpg", "image/jpeg") }
let(:image_jpg) { fixture_file_upload("800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("image_gps_data.jpg", "image/jpeg") }
let(:badge) { create(:badge) }

View file

@ -5,10 +5,10 @@ require "exifr/jpeg"
describe CoverImageUploader, type: :uploader do
include CarrierWave::Test::Matchers
let(:image_jpg) { fixture_file_upload("files/800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("files/800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("files/800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("files/image_gps_data.jpg", "image/jpeg") }
let(:image_jpg) { fixture_file_upload("800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("image_gps_data.jpg", "image/jpeg") }
let(:event) { create(:event) }

View file

@ -6,10 +6,10 @@ describe ProfileImageUploader, type: :uploader do
include CarrierWave::Test::Matchers
let(:mounted_as) { :profile_image }
let(:image_jpg) { fixture_file_upload("files/800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("files/800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("files/800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("files/image_gps_data.jpg", "image/jpeg") }
let(:image_jpg) { fixture_file_upload("800x600.jpg", "image/jpeg") }
let(:image_png) { fixture_file_upload("800x600.png", "image/png") }
let(:image_webp) { fixture_file_upload("800x600.webp", "image/webp") }
let(:image_with_gps) { fixture_file_upload("image_gps_data.jpg", "image/jpeg") }
let(:user) { create(:user) }

Binary file not shown.

BIN
vendor/cache/actioncable-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/actionmailbox-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/actionmailer-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/actionpack-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/actiontext-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/actionview-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/activejob-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/activemodel-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/activerecord-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/activestorage-6.1.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/activesupport-6.1.3.1.gem vendored Normal file

Binary file not shown.

View file

@ -8,7 +8,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.require_paths = ["lib".freeze]
s.authors = ["Tom Cocca".freeze]
s.date = "2021-01-02"
s.date = "2021-03-31"
s.description = "acts_as_follower is a Rubygem to allow any model to follow any other model. This is accomplished through a double polymorphic relationship on the Follow model. There is also built in support for blocking/un-blocking follow records. Main uses would be for Users to follow other Users or for Users to follow Books, etc\u2026 (Basically, to develop the type of follow system that GitHub has)".freeze
s.email = ["tom dot cocca at gmail dot com".freeze]
s.files = [".gitignore".freeze, ".travis.yml".freeze, "Gemfile".freeze, "MIT-LICENSE".freeze, "README.rdoc".freeze, "Rakefile".freeze, "acts_as_follower.gemspec".freeze, "init.rb".freeze, "lib/acts_as_follower.rb".freeze, "lib/acts_as_follower/follow_scopes.rb".freeze, "lib/acts_as_follower/followable.rb".freeze, "lib/acts_as_follower/follower.rb".freeze, "lib/acts_as_follower/follower_lib.rb".freeze, "lib/acts_as_follower/railtie.rb".freeze, "lib/acts_as_follower/version.rb".freeze, "lib/generators/USAGE".freeze, "lib/generators/acts_as_follower_generator.rb".freeze, "lib/generators/templates/migration.rb".freeze, "lib/generators/templates/model.rb".freeze, "test/README".freeze, "test/acts_as_followable_test.rb".freeze, "test/acts_as_follower_test.rb".freeze, "test/dummy30/Gemfile".freeze, "test/dummy30/Rakefile".freeze, "test/dummy30/app/models/application_record.rb".freeze, "test/dummy30/app/models/band.rb".freeze, "test/dummy30/app/models/band/punk.rb".freeze, "test/dummy30/app/models/band/punk/pop_punk.rb".freeze, "test/dummy30/app/models/custom_record.rb".freeze, "test/dummy30/app/models/some.rb".freeze, "test/dummy30/app/models/user.rb".freeze, "test/dummy30/config.ru".freeze, "test/dummy30/config/application.rb".freeze, "test/dummy30/config/boot.rb".freeze, "test/dummy30/config/database.yml".freeze, "test/dummy30/config/environment.rb".freeze, "test/dummy30/config/environments/development.rb".freeze, "test/dummy30/config/environments/test.rb".freeze, "test/dummy30/config/initializers/backtrace_silencers.rb".freeze, "test/dummy30/config/initializers/inflections.rb".freeze, "test/dummy30/config/initializers/secret_token.rb".freeze, "test/dummy30/config/initializers/session_store.rb".freeze, "test/dummy30/config/locales/en.yml".freeze, "test/dummy30/config/routes.rb".freeze, "test/factories/bands.rb".freeze, "test/factories/somes.rb".freeze, "test/factories/users.rb".freeze, "test/follow_test.rb".freeze, "test/schema.rb".freeze, "test/test_helper.rb".freeze]

Binary file not shown.

BIN
vendor/cache/ahoy_email-1.1.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/better_html-1.0.16.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/browser-5.3.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/carrierwave-2.2.1.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/dead_end-1.1.6.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/debug_inspector-1.1.0.gem vendored Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

BIN
vendor/cache/docile-1.3.5.gem vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
vendor/cache/dogstatsd-ruby-4.9.0.gem vendored Normal file

Binary file not shown.

View file

@ -1,12 +0,0 @@
# Gem files
*.gem
# DS_Store
.DS_Store
# Bundle configs
.bundle
.rubocop-https---shopify-github-io-ruby-style-guide-rubocop-yml
gemfiles/Gemfile*.lock

View file

@ -1,2 +0,0 @@
--color
--format documentation

View file

@ -1,9 +0,0 @@
inherit_gem:
rubocop-shopify: rubocop.yml
AllCops:
TargetRubyVersion: 2.5
Exclude:
- 'vendor/**/*'
- 'gemfiles/vendor/**/*'
DisplayCopNames: true

View file

@ -1,12 +0,0 @@
language: ruby
cache: bundler
rvm:
- 2.5
- 2.6
- 2.7
gemfile:
- gemfiles/Gemfile.rubocop-old
- gemfiles/Gemfile.rubocop-next
script:
- bundle exec rspec spec
- bundle exec rubocop

View file

@ -1,12 +0,0 @@
# frozen_string_literal: true
source 'https://rubygems.org'
gem 'activesupport', '~> 5.1'
gem 'rake'
group 'test' do
gem 'fakefs'
end
gemspec

View file

@ -1,105 +0,0 @@
PATH
remote: .
specs:
erb_lint (0.0.35)
activesupport
better_html (~> 1.0.7)
html_tokenizer
parser (>= 2.7.1.4)
rainbow
rubocop
smart_properties
GEM
remote: https://rubygems.org/
specs:
actionview (5.2.4.1)
activesupport (= 5.2.4.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activesupport (5.2.4.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
ast (2.4.1)
better_html (1.0.15)
actionview (>= 4.0)
activesupport (>= 4.0)
ast (~> 2.0)
erubi (~> 1.4)
html_tokenizer (~> 0.0.6)
parser (>= 2.4)
smart_properties
builder (3.2.4)
concurrent-ruby (1.1.5)
crass (1.0.6)
diff-lcs (1.3)
erubi (1.10.0)
fakefs (1.0.0)
html_tokenizer (0.0.7)
i18n (1.8.1)
concurrent-ruby (~> 1.0)
jaro_winkler (1.5.4)
loofah (2.7.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mini_portile2 (2.4.0)
minitest (5.13.0)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
parallel (1.19.1)
parser (2.7.1.4)
ast (~> 2.4.1)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
rainbow (3.0.0)
rake (13.0.1)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.9.0)
rspec-core (3.9.1)
rspec-support (~> 3.9.1)
rspec-expectations (3.9.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-mocks (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-support (3.9.2)
rubocop (0.79.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-shopify (1.0.0)
rubocop (>= 0.78.0)
ruby-progressbar (1.10.1)
smart_properties (1.15.0)
thread_safe (0.3.6)
tzinfo (1.2.6)
thread_safe (~> 0.1)
unicode-display_width (1.6.0)
PLATFORMS
ruby
DEPENDENCIES
activesupport (~> 5.1)
erb_lint!
fakefs
rake
rspec
rubocop
rubocop-shopify
BUNDLED WITH
1.17.3

View file

@ -1,8 +0,0 @@
Copyright (c) 2016 Justin Chan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,522 +0,0 @@
# ERB Lint [![Build Status](https://travis-ci.org/Shopify/erb-lint.svg?branch=master)](https://travis-ci.org/Shopify/erb-lint)
`erb-lint` is a tool to help lint your ERB or HTML files using the included linters or by writing your own.
## Requirements
* Ruby 2.3.0+
- This is due to use of the safe navigation operator (`&.`)
- This is also due to the use of the tilde-heredoc `<<~` syntax in some tests.
## Installation
```bash
gem install erb_lint
```
...or add the following to your `Gemfile` and run `bundle install`:
```ruby
gem 'erb_lint', require: false
```
## Configuration
Create a `.erb-lint.yml` file in your project, with the following structure:
```yaml
---
EnableDefaultLinters: true
linters:
ErbSafety:
enabled: true
better_html_config: .better-html.yml
Rubocop:
enabled: true
rubocop_config:
inherit_from:
- .rubocop.yml
```
See below for linter-specific configuration options.
## Usage
This gem provides a command-line interface which can be run like so:
1. Run `erblint [options]` if the gem is installed standalone.
2. Run `bundle exec erblint [options]` if the gem is installed as a Gemfile dependency for your app.
For example, `erblint --lint-all --enable-all-linters` will run all available
linters on all ERB files in the current directory or its descendants (`**/*.html{+*,}.erb`).
If you want to change the glob that is used, you can configure it by adding it to your config file as follows:
```yaml
---
glob: "**/*.{html,text,js}{+*,}.erb"
linters:
ErbSafety:
enabled: true
better_html_config: .better-html.yml
Rubocop:
enabled: true
rubocop_config:
inherit_from:
- .rubocop.yml
```
## Enable or disable default linters
`EnableDefaultLinters`: enables or disables default linters. [Default linters](#Linters) are enabled by default.
## Linters
| Available Linters | Default | Description |
| ------------------------------------------------ |:--------:|-------------|
| [AllowedScriptType](#AllowedScriptType) | Yes | prevents the addition of `<script>` tags that have `type` attributes that are not in a white-list of allowed values |
| ClosingErbTagIndent | Yes | |
| ExtraNewline | Yes | |
| [FinalNewline](#FinalNewline) | Yes | warns about missing newline at the end of a ERB template |
| [NoJavascriptTagHelper](#NoJavascriptTagHelper) | Yes | prevents the usage of Rails' `javascript_tag` |
| ParserErrors | Yes | |
| [RightTrim](#RightTrim) | Yes | enforces trimming at the right of an ERB tag |
| [SelfClosingTag](#SelfClosingTag) | Yes | enforces self closing tag styles for void elements |
| [SpaceAroundErbTag](#SpaceAroundErbTag) | Yes | enforces a single space after `<%` and before `%>`|
| SpaceIndentation | Yes | |
| SpaceInHtmlTag | Yes | |
| TrailingWhitespace | Yes | |
| [DeprecatedClasses](#DeprecatedClasses) | No | warns about deprecated css classes |
| [ErbSafety](#ErbSafety) | No | detects unsafe interpolation of ruby data into various javascript contexts and enforce usage of safe helpers like `.to_json`. |
| [Rubocop](#Rubocop) | No | runs RuboCop rules on ruby statements found in ERB templates |
### DeprecatedClasses
DeprecatedClasses will find all classes used on HTML elements and report any classes that violate the rule set that you provide.
A `rule_set` is specified as a list, each with a set of `deprecated` classes and a corresponding `suggestion` to use as an alternative.
Example configuration:
```yaml
---
linters:
DeprecatedClasses:
enabled: true
exclude:
- 'app/views/shared/deprecated/**'
addendum: "See UX wiki for help."
rule_set:
- deprecated: ['badge[-_\w]*']
suggestion: "Use the ui_badge() component instead."
```
You can specify an `addendum` to be added to the end of each violation.
The error message format is: `"Deprecated class ... #{suggestion}"`
or `"Deprecated class ... #{suggestion} #{addendum}"` if an `addendum` is present.
Linter-Specific Option | Description
-----------------------|-----------------------------------------------------------------------------------
`rule_set` | A list of rules, each with a `deprecated` and `suggestion` option.
`deprecated` | A list of **regular expressions** which specify the classes deprecated by this rule.
`suggestion` | A string to be included in the rule's error message. Make this informative and specific to the rule that it is contained in.
`addendum` | A string to be included at the end of every error message of the rule set. (Optional)
### FinalNewline
Files must have a final newline. This results in better diffs when
adding lines to the file, since SCM systems such as git won't think that you
touched the last line.
You can customize whether or not a final newline exists with the `present`
option.
Example configuration:
```yaml
---
linters:
FinalNewline:
enabled: true
```
Linter-Specific Option | Description
-----------------------|---------------------------------------------------------
`present` | Whether a final newline should be present (default **true**)
### ErbSafety
Runs the checks provided by
[better-html's erb safety test helper](https://github.com/Shopify/better-html#testing-for-valid-html-and-erb).
When using ERB interpolations in javascript contexts, this linter enforces the usage of safe helpers such as `.to_json`.
See [better-html's readme](https://github.com/Shopify/better-html#testing-for-valid-html-and-erb) for more information.
Any ERB statement that does not call a safe helper is deemed unsafe and a violation is shown.
For example:
```erb
Not allowed ❌
<a onclick="alert(<%= some_data %>)">
Allowed ✅
<a onclick="alert(<%= some_data.to_json %>)">
```
```erb
Not allowed ❌
<script>var myData = <%= some_data %>;</script>
Allowed ✅
<script>var myData = <%= some_data.to_json %>;</script>
```
Example configuration:
```yaml
---
linters:
ErbSafety:
enabled: true
better_html_config: .better-html.yml
```
Linter-Specific Option | Description
-----------------------|---------------------------------------------------------
`better_html_config` | Name of the configuration file to use for `better-html`. Optional. Valid options and their defaults are described [in better-html's readme](https://github.com/Shopify/better-html#configuration).
### Rubocop
Runs RuboCop on all ruby statements found in ERB templates. The RuboCop configuration that `erb-lint` uses can inherit from
the configuration that the rest of your application uses. `erb-lint` can be configured independently however, as it will often
be necessary to disable specific RuboCop rules that do not apply to ERB files.
**Note**: Each ruby statement (between ERB tags `<% ... %>`) is parsed and analyzed independently of each other. Any rule that requires a broader context can trigger false positives (e.g. `Lint/UselessAssignment` will complaint for an assignment even if used in a subsequent ERB tag).
Example configuration:
```yaml
---
linters:
Rubocop:
enabled: true
rubocop_config:
inherit_from:
- .rubocop.yml
Layout/InitialIndentation:
Enabled: false
Layout/TrailingEmptyLines:
Enabled: false
Layout/TrailingWhitespace:
Enabled: false
Naming/FileName:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
Metrics/LineLength:
Enabled: false
Lint/UselessAssignment:
Enabled: false
Rails/OutputSafety:
Enabled: false
```
The cops disabled in the example configuration above provide a good starting point.
Linter-Specific Option | Description
-----------------------|---------------------------------------------------------
`rubocop_config` | A valid rubocop configuration hash. Mandatory when this cop is enabled. See [rubocop's manual entry on Configuration](http://rubocop.readthedocs.io/en/latest/configuration/)
`only` | Only run cops listed in this array instead of all cops.
### RightTrim
Trimming at the right of an ERB tag can be done with either `=%>` or `-%>`, this linter enforces one of these two styles.
Example configuration:
```yaml
---
linters:
RightTrim:
enabled: true
enforced_style: '-'
```
Linter-Specific Option | Description
-----------------------|---------------------------------------------------------
`enforced_style` | Which style to enforce, can be either `-` or `=`. Optional. Defaults to `-`.
### SpaceAroundErbTag
Enforce a single space after `<%` and before `%>` in the ERB source.
This linter ignores opening ERB tags (`<%`) that are followed by a newline,
and closing ERB tags (`%>`) that are preceded by a newline.
```erb
Bad ❌
<%foo%>
<%=foo-%>
Good ✅
<% foo %>
<%
foo
%>
```
Example configuration:
```yaml
---
linters:
SpaceAroundErbTag:
enabled: true
```
### NoJavascriptTagHelper
This linter prevents the usage of
Rails' [`javascript_tag`](https://apidock.com/rails/ActionView/Helpers/JavaScriptHelper/javascript_tag)
helper in ERB templates.
The html parser used in this gem knows not to look for html tags within certain other tags
like `script`, `style`, and others. The html parser does this to avoid confusing javascript
expressions like `if (1<a || b>1)` for a malformed html tag. Using the `javascript_tag` in
a ERB template prevents the parser from recognizing the change of parsing context and may
fail or produce erroneous output as a result.
```erb
Bad ❌
<%= javascript_tag(content, defer: true) %>
Good ✅
<script defer="true"><%== content %></script>
Bad ❌
<%= javascript_tag do %>
alert(1)
<% end %>
Good ✅
<script>
alert(1)
</script>
```
The autocorrection rule adds `//<![CDATA[` and `//]]>` markers to the existing script, as this is the default
behavior for `javascript_tag`. This can be disabled by changing the `correction_style` linter option
from `cdata` to `plain`.
Example configuration:
```yaml
---
linters:
NoJavascriptTagHelper:
enabled: true
correction_style: 'plain'
```
Linter-Specific Option | Description
-----------------------|---------------------------------------------------------
`correction_style` | When configured with `cdata`, adds CDATA markers. When configured with `plain`, don't add makers. Defaults to `cdata`.
### SelfClosingTag
This linter enforces self closing tag styles for void elements.
The void elements are `area`, `base`, `br`, `col`, `embed`, `hr`, `img`, `input`, `keygen`, `link`, `menuitem`, `meta`, `param`, `source`, `track`, and `wbr`.
If `enforced_style` is set to `always` (XHTML style):
```erb
Bad ❌
<link rel="stylesheet" type="text/css" href="styles.css">
Good ✅
<img src="someimage.png" alt="Some Image" />
```
If `enforced_style` is set to `never` (HTML5 style):
```erb
Bad ❌
<hr />
Good ✅
<meta charset="UTF-8">
```
Example configuration:
```yaml
---
linters:
SelfClosingTag:
enabled: true
enforced_style: 'always'
```
Linter-Specific Option | Description
-----------------------|---------------------------------------------------------
`enforced_style` | If we should `always` or `never` expect self closing tags for void elements. Defaults to `never`.
### AllowedScriptType
This linter prevent the addition of `<script>` tags that have `type` attributes that are not in a white-list of allowed values.
It is common practice for web developers to use `<script>` tags with non-executable
`type` attributes, such as `application/json` or `text/html` to pass arbitrary data into an html page.
Despite not being executable, these tags are subject to the same parsing quirks as executable script tags, and
it is therefore more difficult to prevent security issues from creeping in. Consider for instance an application
where it is possible to inject the string `</script><script>` unescaped into a `text/html` tag, the application
would be vulnerable to XSS.
This pattern can easily be replaced by `<div>` tags with `data` attributes that can just as easily be read
from javascript, and have the added benefit of being safer. When `content_tag(:div)` or `tag.div()` is used
to pass arbitrary user data into the html document, it becomes much harder to inadvertently introduce a
security issue.
It may also be desirable to avoid typos in `type` attributes.
```html
Bad ❌
<script type="text/javacsrïpt"></script>
Good ✅
<script type="text/javascript"></script>
```
By default, this linter allows the `type` attribute to be omitted, as the behavior in browsers is to
consider `<script>` to be the same as `<script type="text/javascript">`. When the linter is configured with
`allow_blank: false`, instances of `<script>` tags without a type will be auto-corrected
to `<script type="text/javascript">`.
It may also be desirable to disallow `<script>` tags from appearing anywhere in your application.
For instance, Rails applications can benefit from serving static javascript code from the asset
pipeline, as well as other security benefits.
The `disallow_inline_scripts: true` config option may be used for that purpose.
Example configuration:
```yaml
---
linters:
AllowedScriptType:
enabled: true
allowed_types:
- 'application/json'
- 'text/javascript'
- 'text/html'
allow_blank: false
disallow_inline_scripts: false
```
Linter-Specific Option | Description
--------------------------|---------------------------------------------------------
`allowed_types` | An array of allowed types. Defaults to `["text/javascript"]`.
`allow_blank` | True or false, depending on whether or not the `type` attribute may be omitted entirely from a `<script>` tag.
`disallow_inline_scripts` | Do not allow inline `<script>` tags anywhere in ERB templates. Defaults to `false`.
## Custom Linters
`erb-lint` allows you to create custom linters specific to your project. It will load linters from the `.erb-linters` directory in the root of your
repository. See the [linters directory](lib/erb_lint/linters) for examples of how to write linters.
```ruby
# .erb-linters/custom_linter.rb
module ERBLint
module Linters
class CustomLinter < Linter
include LinterRegistry
class ConfigSchema < LinterConfig
property :custom_message, accepts: String
end
self.config_schema = ConfigSchema
def offenses(processed_source)
errors = []
unless processed_source.file_content.include?('this file is fine')
errors << Offense.new(
self,
processed_source.to_source_range(0 ... processed_source.file_content.size),
"This file isn't fine. #{@config.custom_message}"
)
end
errors
end
end
end
end
```
By default, this linter would be disabled. You can enable it by adding an entry to `.erb-lint.yml`:
```yaml
---
linters:
CustomLinter:
enabled: true
custom_message: We suggest you change this file.
```
Test your linter by running `erblint`'s command-line interface:
```bash
bundle exec erblint --enable-linters custom_linter --lint-all
```
Running this on a random project might yield this output:
```
Linting 15 files with 1 linters...
This file isn't fine. We suggest you change this file.
In file: app/views/layouts/application.html.erb:1
Errors were found in ERB files
```
To write a linter that can autocorrect offenses it detects, simply add an
`autocorrect` method that returns a callable. The callable is called with an instance of
[`RuboCop::Cop::Corrector`](http://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Corrector)
as argument, and therefore erb-lint correctors work exactly as RuboCop correctors do.
```ruby
def autocorrect(_processed_source, offense)
lambda do |corrector|
corrector.insert_after(offense.source_range, "this file is fine")
end
end
```
## Output formats
You can change the output format of ERB Lint by specifying formatters with the `-f/--format` option.
### Multiline (default)
```sh
$ erblint
Linting 8 files with 12 linters...
Remove multiple trailing newline at the end of the file.
In file: app/views/users/show.html.erb:95
Remove newline before `%>` to match start of tag.
In file: app/views/subscriptions/index.html.erb:38
2 error(s) were found in ERB files
```
### Compact
```sh
erblint --format compact
Linting 8 files with 12 linters...
app/views/users/show.html.erb:95:0: Remove multiple trailing newline at the end of the file.
app/views/users/_graph.html.erb:27:37: Extra space detected where there should be no space
2 error(s) were found in ERB files
```
## License
This project is released under the [MIT license](LICENSE.txt).

View file

@ -1,29 +0,0 @@
# frozen_string_literal: true
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
require 'rdoc/task'
RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'ErbLint'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.md')
rdoc.rdoc_files.include('lib/**/*.rb')
end
require 'bundler/gem_tasks'
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
end
task(default: :test)

View file

@ -1,12 +0,0 @@
name: erb-lint
up:
- ruby: 2.5.3
- bundler
commands:
test:
syntax:
argument: file
optional: args...
run: bundle exec rspec "$@"

View file

@ -1,53 +0,0 @@
# -*- encoding: utf-8 -*-
# stub: erb_lint 0.0.35 ruby lib
Gem::Specification.new do |s|
s.name = "erb_lint".freeze
s.version = "0.0.35"
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.metadata = { "allowed_push_host" => "https://rubygems.org" } if s.respond_to? :metadata=
s.require_paths = ["lib".freeze]
s.authors = ["Justin Chan".freeze]
s.bindir = "exe".freeze
s.date = "2021-01-02"
s.description = "ERB Linter tool.".freeze
s.email = ["justin.the.c@gmail.com".freeze]
s.executables = ["erblint".freeze]
s.files = ["exe/erblint".freeze, "lib/erb_lint.rb".freeze, "lib/erb_lint/cli.rb".freeze, "lib/erb_lint/corrector.rb".freeze, "lib/erb_lint/file_loader.rb".freeze, "lib/erb_lint/linter.rb".freeze, "lib/erb_lint/linter_config.rb".freeze, "lib/erb_lint/linter_registry.rb".freeze, "lib/erb_lint/linters/allowed_script_type.rb".freeze, "lib/erb_lint/linters/closing_erb_tag_indent.rb".freeze, "lib/erb_lint/linters/deprecated_classes.rb".freeze, "lib/erb_lint/linters/erb_safety.rb".freeze, "lib/erb_lint/linters/extra_newline.rb".freeze, "lib/erb_lint/linters/final_newline.rb".freeze, "lib/erb_lint/linters/hard_coded_string.rb".freeze, "lib/erb_lint/linters/no_javascript_tag_helper.rb".freeze, "lib/erb_lint/linters/parser_errors.rb".freeze, "lib/erb_lint/linters/right_trim.rb".freeze, "lib/erb_lint/linters/rubocop.rb".freeze, "lib/erb_lint/linters/rubocop_text.rb".freeze, "lib/erb_lint/linters/self_closing_tag.rb".freeze, "lib/erb_lint/linters/space_around_erb_tag.rb".freeze, "lib/erb_lint/linters/space_in_html_tag.rb".freeze, "lib/erb_lint/linters/space_indentation.rb".freeze, "lib/erb_lint/linters/trailing_whitespace.rb".freeze, "lib/erb_lint/offense.rb".freeze, "lib/erb_lint/processed_source.rb".freeze, "lib/erb_lint/reporter.rb".freeze, "lib/erb_lint/reporters/compact_reporter.rb".freeze, "lib/erb_lint/reporters/multiline_reporter.rb".freeze, "lib/erb_lint/runner.rb".freeze, "lib/erb_lint/runner_config.rb".freeze, "lib/erb_lint/runner_config_resolver.rb".freeze, "lib/erb_lint/stats.rb".freeze, "lib/erb_lint/utils/block_map.rb".freeze, "lib/erb_lint/utils/offset_corrector.rb".freeze, "lib/erb_lint/utils/ruby_to_erb.rb".freeze, "lib/erb_lint/version.rb".freeze]
s.homepage = "https://github.com/Shopify/erb-lint".freeze
s.licenses = ["MIT".freeze]
s.required_ruby_version = Gem::Requirement.new(">= 2.5.0".freeze)
s.rubygems_version = "3.1.4".freeze
s.summary = "ERB lint tool".freeze
s.installed_by_version = "3.1.4" if s.respond_to? :installed_by_version
if s.respond_to? :specification_version then
s.specification_version = 4
end
if s.respond_to? :add_runtime_dependency then
s.add_runtime_dependency(%q<better_html>.freeze, ["~> 1.0.7"])
s.add_runtime_dependency(%q<html_tokenizer>.freeze, [">= 0"])
s.add_runtime_dependency(%q<rubocop>.freeze, [">= 0"])
s.add_runtime_dependency(%q<parser>.freeze, [">= 2.7.1.4"])
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 0"])
s.add_runtime_dependency(%q<smart_properties>.freeze, [">= 0"])
s.add_runtime_dependency(%q<rainbow>.freeze, [">= 0"])
s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
s.add_development_dependency(%q<rubocop-shopify>.freeze, [">= 0"])
else
s.add_dependency(%q<better_html>.freeze, ["~> 1.0.7"])
s.add_dependency(%q<html_tokenizer>.freeze, [">= 0"])
s.add_dependency(%q<rubocop>.freeze, [">= 0"])
s.add_dependency(%q<parser>.freeze, [">= 2.7.1.4"])
s.add_dependency(%q<activesupport>.freeze, [">= 0"])
s.add_dependency(%q<smart_properties>.freeze, [">= 0"])
s.add_dependency(%q<rainbow>.freeze, [">= 0"])
s.add_dependency(%q<rspec>.freeze, [">= 0"])
s.add_dependency(%q<rubocop>.freeze, [">= 0"])
s.add_dependency(%q<rubocop-shopify>.freeze, [">= 0"])
end
end

View file

@ -1,9 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
$LOAD_PATH.unshift("#{__dir__}/../lib")
require 'erb_lint/cli'
cli = ERBLint::CLI.new
exit(cli.run)

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
eval_gemfile "../Gemfile"
gem "rubocop", ">= 0.87"
gem "rubocop-shopify", ">= 1.0.7"

View file

@ -1,6 +0,0 @@
# frozen_string_literal: true
eval_gemfile "../Gemfile"
gem "rubocop", "< 0.87"
gem "rubocop-ast", "< 0.4.0"

View file

@ -1,26 +0,0 @@
# frozen_string_literal: true
require 'rubocop'
require 'erb_lint/corrector'
require 'erb_lint/file_loader'
require 'erb_lint/linter_config'
require 'erb_lint/linter_registry'
require 'erb_lint/linter'
require 'erb_lint/offense'
require 'erb_lint/processed_source'
require 'erb_lint/runner_config'
require 'erb_lint/runner'
require 'erb_lint/version'
require 'erb_lint/stats'
require 'erb_lint/reporter'
# Load linters
Dir[File.expand_path('erb_lint/linters/**/*.rb', File.dirname(__FILE__))].each do |file|
require file
end
# Load reporters
Dir[File.expand_path('erb_lint/reporters/**/*.rb', File.dirname(__FILE__))].each do |file|
require file
end

View file

@ -1,291 +0,0 @@
# frozen_string_literal: true
require 'erb_lint'
require 'active_support'
require 'active_support/inflector'
require 'optparse'
require 'psych'
require 'yaml'
require 'rainbow'
module ERBLint
class CLI
DEFAULT_CONFIG_FILENAME = '.erb-lint.yml'
DEFAULT_LINT_ALL_GLOB = "**/*.html{+*,}.erb"
class ExitWithFailure < RuntimeError; end
class ExitWithSuccess < RuntimeError; end
def initialize
@options = {}
@config = nil
@files = []
@stats = Stats.new
end
def run(args = ARGV)
dupped_args = args.dup
load_options(dupped_args)
@files = dupped_args
load_config
if !@files.empty? && lint_files.empty?
failure!("no files found...\n")
elsif lint_files.empty?
failure!("no files found or given, specify files or config...\n#{option_parser}")
end
ensure_files_exist(lint_files)
if enabled_linter_classes.empty?
failure!('no linter available with current configuration')
end
@options[:format] ||= :multiline
@stats.files = lint_files.size
@stats.linters = enabled_linter_classes.size
reporter = Reporter.create_reporter(@options[:format], @stats, autocorrect?)
reporter.preview
runner = ERBLint::Runner.new(file_loader, @config)
lint_files.each do |filename|
runner.clear_offenses
begin
run_with_corrections(runner, filename)
rescue => e
@stats.exceptions += 1
puts "Exception occured when processing: #{relative_filename(filename)}"
puts "If this file cannot be processed by erb-lint, "\
"you can exclude it in your configuration file."
puts e.message
puts Rainbow(e.backtrace.join("\n")).red
puts
end
end
reporter.show
@stats.found == 0 && @stats.exceptions == 0
rescue OptionParser::InvalidOption, OptionParser::InvalidArgument, ExitWithFailure => e
warn(Rainbow(e.message).red)
false
rescue ExitWithSuccess => e
puts e.message
true
rescue => e
warn(Rainbow("#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}").red)
false
end
private
def autocorrect?
@options[:autocorrect]
end
def run_with_corrections(runner, filename)
file_content = File.read(filename, encoding: Encoding::UTF_8)
7.times do
processed_source = ERBLint::ProcessedSource.new(filename, file_content)
runner.run(processed_source)
break unless autocorrect? && runner.offenses.any?
corrector = correct(processed_source, runner.offenses)
break if corrector.corrections.empty?
break if processed_source.file_content == corrector.corrected_content
@stats.corrected += corrector.corrections.size
File.open(filename, "wb") do |file|
file.write(corrector.corrected_content)
end
file_content = corrector.corrected_content
runner.clear_offenses
end
offenses_filename = relative_filename(filename)
offenses = runner.offenses || []
@stats.found += offenses.size
@stats.processed_files[offenses_filename] ||= []
@stats.processed_files[offenses_filename] |= offenses
end
def correct(processed_source, offenses)
corrector = ERBLint::Corrector.new(processed_source, offenses)
failure!(corrector.diagnostics.join(', ')) if corrector.diagnostics.any?
corrector
end
def config_filename
@config_filename ||= @options[:config] || DEFAULT_CONFIG_FILENAME
end
def load_config
if File.exist?(config_filename)
config = RunnerConfig.new(file_loader.yaml(config_filename), file_loader)
@config = RunnerConfig.default_for(config)
else
warn(Rainbow("#{config_filename} not found: using default config").yellow)
@config = RunnerConfig.default
end
rescue Psych::SyntaxError => e
failure!("error parsing config: #{e.message}")
ensure
@config.merge!(runner_config_override)
end
def file_loader
@file_loader ||= ERBLint::FileLoader.new(Dir.pwd)
end
def load_options(args)
option_parser.parse!(args)
end
def lint_files
@lint_files ||=
if @options[:lint_all]
pattern = File.expand_path(glob, Dir.pwd)
Dir[pattern].select { |filename| !excluded?(filename) }
else
@files
.map { |f| Dir.exist?(f) ? Dir[File.join(f, glob)] : f }
.map { |f| f.include?('*') ? Dir[f] : f }
.flatten
.map { |f| File.expand_path(f, Dir.pwd) }
.select { |filename| !excluded?(filename) }
end
end
def glob
@config.to_hash["glob"] || DEFAULT_LINT_ALL_GLOB
end
def excluded?(filename)
@config.global_exclude.any? do |path|
File.fnmatch?(path, filename)
end
end
def failure!(msg)
raise ExitWithFailure, msg
end
def success!(msg)
raise ExitWithSuccess, msg
end
def ensure_files_exist(files)
files.each do |filename|
unless File.exist?(filename)
failure!("#{filename}: does not exist")
end
end
end
def known_linter_names
@known_linter_names ||= ERBLint::LinterRegistry.linters
.map(&:simple_name)
.map(&:underscore)
end
def enabled_linter_names
@enabled_linter_names ||=
@options[:enabled_linters] ||
known_linter_names
.select { |name| @config.for_linter(name.camelize).enabled? }
end
def enabled_linter_classes
@enabled_linter_classes ||= ERBLint::LinterRegistry.linters
.select { |klass| linter_can_run?(klass) && enabled_linter_names.include?(klass.simple_name.underscore) }
end
def linter_can_run?(klass)
!autocorrect? || klass.support_autocorrect?
end
def relative_filename(filename)
filename.sub("#{File.expand_path('.', Dir.pwd)}/", '')
end
def runner_config_override
RunnerConfig.new(
linters: {}.tap do |linters|
ERBLint::LinterRegistry.linters.map do |klass|
linters[klass.simple_name] = { 'enabled' => enabled_linter_classes.include?(klass) }
end
end
)
end
def option_parser
OptionParser.new do |opts|
opts.banner = "Usage: erblint [options] [file1, file2, ...]"
opts.on("--config FILENAME", "Config file [default: #{DEFAULT_CONFIG_FILENAME}]") do |config|
if File.exist?(config)
@options[:config] = config
else
failure!("#{config}: does not exist")
end
end
opts.on("--format FORMAT", format_options_help) do |format|
unless Reporter.available_format?(format)
error_message = invalid_format_error_message(format)
failure!(error_message)
end
@options[:format] = format
end
opts.on("--lint-all", "Lint all files matching configured glob [default: #{DEFAULT_LINT_ALL_GLOB}]") do |config|
@options[:lint_all] = config
end
opts.on("--enable-all-linters", "Enable all known linters") do
@options[:enabled_linters] = known_linter_names
end
opts.on("--enable-linters LINTER[,LINTER,...]", Array,
"Only use specified linter", "Known linters are: #{known_linter_names.join(', ')}") do |linters|
linters.each do |linter|
unless known_linter_names.include?(linter)
failure!("#{linter}: not a valid linter name (#{known_linter_names.join(', ')})")
end
end
@options[:enabled_linters] = linters
end
opts.on("-a", "--autocorrect", "Correct offenses automatically if possible (default: false)") do |config|
@options[:autocorrect] = config
end
opts.on_tail("-h", "--help", "Show this message") do
success!(opts)
end
opts.on_tail("--version", "Show version") do
success!(ERBLint::VERSION)
end
end
end
def format_options_help
"Report offenses in the given format: "\
"(#{Reporter.available_formats.join(', ')}) (default: multiline)"
end
def invalid_format_error_message(given_format)
formats = Reporter.available_formats.map { |format| " - #{format}\n" }
"#{given_format}: is not a valid format. Available formats:\n#{formats.join}"
end
end
end

View file

@ -1,38 +0,0 @@
# frozen_string_literal: true
module ERBLint
class Corrector
attr_reader :processed_source, :offenses, :corrected_content
def initialize(processed_source, offenses)
@processed_source = processed_source
@offenses = offenses
@corrected_content = corrector.rewrite
end
def corrections
@corrections ||= @offenses.map do |offense|
offense.linter.autocorrect(@processed_source, offense)
end.compact
end
def corrector
BASE.new(@processed_source.source_buffer, corrections)
end
if ::RuboCop::Version::STRING.to_f >= 0.87
require 'rubocop/cop/legacy/corrector'
BASE = ::RuboCop::Cop::Legacy::Corrector
def diagnostics
[]
end
else
BASE = ::RuboCop::Cop::Corrector
def diagnostics
corrector.diagnostics
end
end
end
end

View file

@ -1,29 +0,0 @@
# frozen_string_literal: true
module ERBLint
# Loads file from disk
class FileLoader
attr_reader :base_path
def initialize(base_path)
@base_path = base_path
end
if RUBY_VERSION >= "2.6"
def yaml(filename)
YAML.safe_load(read_content(filename), permitted_classes: [Regexp, Symbol], filename: filename) || {}
end
else
def yaml(filename)
YAML.safe_load(read_content(filename), [Regexp, Symbol], [], false, filename) || {}
end
end
private
def read_content(filename)
path = File.expand_path(filename, base_path)
File.read(path)
end
end
end

View file

@ -1,64 +0,0 @@
# frozen_string_literal: true
module ERBLint
# Defines common functionality available to all linters.
class Linter
class << self
attr_accessor :simple_name
attr_accessor :config_schema
# When defining a Linter class, define its simple name as well. This
# assumes that the module hierarchy of every linter starts with
# `ERBLint::Linters::`, and removes this part of the class name.
#
# `ERBLint::Linters::Foo.simple_name` #=> "Foo"
# `ERBLint::Linters::Compass::Bar.simple_name` #=> "Compass::Bar"
def inherited(linter)
super
linter.simple_name = if linter.name.start_with?('ERBLint::Linters::')
name_parts = linter.name.split('::')
name_parts[2..-1].join('::')
else
linter.name
end
linter.config_schema = LinterConfig
end
def support_autocorrect?
method_defined?(:autocorrect)
end
end
attr_reader :offenses
# Must be implemented by the concrete inheriting class.
def initialize(file_loader, config)
@file_loader = file_loader
@config = config
raise ArgumentError, "expect `config` to be #{self.class.config_schema} instance, "\
"not #{config.class}" unless config.is_a?(self.class.config_schema)
@offenses = []
end
def enabled?
@config.enabled?
end
def excludes_file?(filename)
@config.excludes_file?(filename)
end
def run(_processed_source)
raise NotImplementedError, "must implement ##{__method__}"
end
def add_offense(source_range, message, context = nil)
@offenses << Offense.new(self, source_range, message, context)
end
def clear_offenses
@offenses = []
end
end
end

View file

@ -1,60 +0,0 @@
# frozen_string_literal: true
require 'active_support'
require 'smart_properties'
module ERBLint
class LinterConfig
include SmartProperties
class Error < StandardError; end
class << self
def array_of?(klass)
lambda { |value| value.is_a?(Array) && value.all? { |s| s.is_a?(klass) } }
end
def to_array_of(klass)
lambda { |entries| entries.map { |entry| klass.new(entry) } }
end
end
property :enabled, accepts: [true, false], default: false, reader: :enabled?
property :exclude, accepts: array_of?(String), default: -> { [] }
def initialize(config = {})
config = config.dup.deep_stringify_keys
allowed_keys = self.class.properties.keys.map(&:to_s)
given_keys = config.keys
if (extra_keys = given_keys - allowed_keys).any?
raise Error, "Given key is not allowed: #{extra_keys.join(', ')}"
end
super(config)
rescue SmartProperties::InitializationError => e
raise Error, "The following properties are required to be set: #{e.properties}"
rescue SmartProperties::InvalidValueError => e
raise Error, e.message
end
def [](name)
unless self.class.properties.key?(name)
raise Error, "No such property: #{name}"
end
super
end
def to_hash
{}.tap do |hash|
self.class.properties.to_hash.each_key do |key|
hash[key.to_s] = self[key]
end
end
end
def excludes_file?(filename)
exclude.any? do |path|
File.fnmatch?(path, filename)
end
end
end
end

View file

@ -1,35 +0,0 @@
# frozen_string_literal: true
module ERBLint
# Stores all linters available to the application.
module LinterRegistry
CUSTOM_LINTERS_DIR = '.erb-linters'
@loaded_linters = []
class << self
def clear
@linters = nil
end
def included(linter_class)
@loaded_linters << linter_class
end
def find_by_name(name)
linters.detect { |linter| linter.simple_name == name }
end
def linters
@linters ||= begin
load_custom_linters
@loaded_linters
end
end
def load_custom_linters(directory = CUSTOM_LINTERS_DIR)
ruby_files = Dir.glob(File.expand_path(File.join(directory, '**', '*.rb')))
ruby_files.each { |file| require file }
end
end
end
end

Some files were not shown because too many files have changed in this diff Show more