diff --git a/.better-html.yml b/.better-html.yml
new file mode 100644
index 000000000..7ef90a3d8
--- /dev/null
+++ b/.better-html.yml
@@ -0,0 +1,3 @@
+# https://github.com/Shopify/better-html#configuration
+
+allow_single_quoted_attributes: false
diff --git a/.erb_lint.yml b/.erb_lint.yml
new file mode 100644
index 000000000..957d6a417
--- /dev/null
+++ b/.erb_lint.yml
@@ -0,0 +1,48 @@
+# configuration reference: https://github.com/Shopify/erb_lint?tab=readme-ov-file#configuration
+
+EnableDefaultLinters: false
+
+exclude:
+ - 'config/**/*'
+ - 'db/**/*'
+ - 'scripts/**/*'
+ - 'bin/**/*'
+ - 'lib/namespaced_env_cache.rb'
+ - 'vendor/bundle/**/*'
+ # TODO: fix clobbering (autocorrect conflics) first:
+ - 'app/views/admin/_error_report.html.erb'
+ - 'app/views/categories/show.html.erb'
+ - 'app/views/micro_auth/authentication/initiate.html.erb'
+ - 'app/views/reactions/_form.html.erb'
+ - 'app/views/reports/reactions.html.erb'
+ - 'app/views/suggested_edit/category_index.html.erb'
+ - 'app/views/questions/_list.html.erb'
+ - 'app/views/tags/category.html.erb'
+ - 'app/views/users/_activity_items.html.erb'
+ # TODO: fix parser errors first:
+ - 'app/views/complaints/training/higher-risk.html.erb'
+ - 'app/views/complaints/training/illegal-content.html.erb'
+
+glob: '**/*.{html,text,js}{+*,}.erb'
+
+linters:
+ ErbSafety:
+ enabled: true
+ better_html_config: .better-html.yml
+ Rubocop:
+ enabled: true
+ rubocop_config:
+ inherit_from:
+ - .rubocop.yml
+ Layout/LeadingEmptyLines:
+ Enabled: false # false positives on embedded Ruby indentation in tags
+ Style/MultilineTernaryOperator:
+ Enabled: false # enable when we settle on how we conditionally access locale strings
+ Layout/InitialIndentation:
+ Enabled: false # false positives on embedded Ruby indentation in tags
+ Layout/TrailingEmptyLines:
+ Enabled: false # enable when we are ready to solve ~3K errors
+ Layout/TrailingWhitespace:
+ Enabled: false # false positives on embedded Ruby indentation in tags
+ Lint/UselessAssignment:
+ Enabled: false # false positives on single-line embedded Ruby assignments
diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml
index d770f1e38..08bb656d2 100644
--- a/.github/workflows/ci-cd.yml
+++ b/.github/workflows/ci-cd.yml
@@ -20,9 +20,8 @@ permissions:
jobs:
rubocop:
- name: Rubocop checking
+ name: Ruby linting (Ruby + Rails + ERB)
runs-on: ubuntu-latest
-
steps:
- name: Checkout repo
uses: actions/checkout@v3
@@ -37,6 +36,23 @@ jobs:
bundler-cache: true
- run: bundle exec rubocop
+ erb-lint:
+ name: ERB linting
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v3
+ - name: Setup dependencies
+ run: |
+ sudo apt-get update -qq
+ sudo apt-get install -yqq libmagickwand-dev
+ - name: Setup Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: ${{ env.RUBY_VERSION }}
+ bundler-cache: true
+ - run: bundle exec erb_lint --lint-all
+
typescript:
name: TypeScript type checking
runs-on: ubuntu-latest
@@ -55,6 +71,10 @@ jobs:
tests:
name: Ruby on Rails tests
runs-on: ubuntu-latest
+ needs:
+ - rubocop
+ - erb-lint
+ - typescript
strategy:
matrix:
@@ -161,6 +181,7 @@ jobs:
if: ${{ github.event_name == 'push' && github.actor != 'dependabot[bot]' }}
needs:
- rubocop
+ - erb-lint
- typescript
- tests
- system-tests
diff --git a/Gemfile b/Gemfile
index 8245fdcee..9645550b2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -57,6 +57,7 @@ gem 'whenever', '~> 1.0', require: false
# Debugging, linting, testing.
gem 'awesome_print', '~> 1.9'
+gem 'erb_lint', '~> 0.9.0'
gem 'rails_performance', '~> 1.6'
gem 'rubocop', '~> 1'
gem 'rubocop-rails', '~> 2.15'
diff --git a/Gemfile.lock b/Gemfile.lock
index 24fe2e0b3..e4600248f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -116,6 +116,13 @@ GEM
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.3.0)
bcrypt (3.1.22)
+ better_html (2.1.1)
+ actionview (>= 6.0)
+ activesupport (>= 6.0)
+ ast (~> 2.0)
+ erubi (~> 1.4)
+ parser (>= 2.4)
+ smart_properties
bigdecimal (4.1.2)
bindex (0.8.1)
browser (6.2.0)
@@ -170,7 +177,14 @@ GEM
docile (1.4.1)
drb (2.2.3)
e2mmap (0.1.0)
- erb (6.0.4)
+ erb (6.0.7)
+ erb_lint (0.9.0)
+ activesupport
+ better_html (>= 2.0.1)
+ parser (>= 2.7.1.4)
+ rainbow
+ rubocop (>= 1)
+ smart_properties
erubi (1.13.1)
execjs (2.10.1)
faraday (2.14.3)
@@ -472,6 +486,7 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.2)
simplecov_json_formatter (0.1.4)
+ smart_properties (1.17.0)
spring (4.7.0)
sprockets (4.1.1)
concurrent-ruby (~> 1.0)
@@ -566,6 +581,7 @@ DEPENDENCIES
devise_saml_authenticatable (~> 1.9)
diffy (~> 3.4)
e2mmap (~> 0.1)
+ erb_lint (~> 0.9.0)
fastimage (~> 2.2)
flamegraph (~> 0.9)
groupdate (~> 6.1)