diff --git a/.database_consistency.todo.yml b/.database_consistency.todo.yml new file mode 100644 index 00000000..4fcdc664 --- /dev/null +++ b/.database_consistency.todo.yml @@ -0,0 +1,5 @@ +--- +Profile: + self_ref: + MissingIndexChecker: + enabled: false diff --git a/.github/PULL_REQUEST_TEMPLATE/default.md b/.github/PULL_REQUEST_TEMPLATE/default.md new file mode 100644 index 00000000..4cc7a782 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/default.md @@ -0,0 +1,29 @@ +## Description + +Please include a summary of the change. Also, include any additional information that you think is important for reviewers to know. Link to a related issue if applicable. + +## How has this been tested? + +Please mark the tests that you ran to verify your changes. If difficult to test, consider providing instructions so reviewers can test. + +- [ ] Manual testing +- [ ] System tests +- [ ] Unit tests +- [ ] None + +## Checklist + +- [ ] CI pipeline is passing +- [ ] My code follows the conventions of this project +- [ ] I have performed a self-review of my code +- [ ] I have commented on my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation (if applicable) +- [ ] I have added seed data to the database (if applicable) + +## Release tasks + +Add any tasks that need to be done before/after the release of this feature. + +## Screenshots/Loom + +This section is relevant in case we want to share progress with the team, otherwise, it can be omitted. diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml new file mode 100644 index 00000000..4ed4df5d --- /dev/null +++ b/.github/workflows/github-actions.yml @@ -0,0 +1,91 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + branches: + - "**" + +env: + CI: true + RSPEC_RETRY_RETRY_COUNT: 3 + RAILS_ENV: test + RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} + +jobs: + linters: + name: Linters + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Ruby and install gems + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Setup Node + uses: actions/setup-node@v4 + - name: Run RuboCop + run: bundle exec rubocop + - name: Run ERB Lint + run: bundle exec erblint --lint-all + - name: Run StandardJS + run: | + npm install standard --global + standard + - name: Run spell checker + uses: crate-ci/typos@master + + security: + name: Security + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Ruby and install gems + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Run brakeman + run: | + bundle exec brakeman -w3 + - name: Run bundler-audit + run: | + bundle exec bundle-audit check --update + + code_quality: + name: Code quality + runs-on: ubuntu-latest + if: ${{ github.ref_name != 'main' }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Ruby and install gems + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Run rubycritic + run: | + bundle exec rubycritic --mode-ci main --no-browser + - name: Run database consistency + run: | + bundle exec rails db:test:prepare + bundle exec database_consistency -c .database_consistency.todo.yml + + tests: + name: Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Setup DB + run: | + bundle exec rails db:test:prepare + - name: Run tests + run: | + bundle exec rspec diff --git a/.lefthook.yml b/.lefthook.yml new file mode 100644 index 00000000..14f9c505 --- /dev/null +++ b/.lefthook.yml @@ -0,0 +1,18 @@ +pre-commit: + parallel: true + commands: + ruby-linter: + glob: "*.{rb,rake}" + run: bundle exec rubocop -a --force-exclusion {staged_files} + stage_fixed: true + erb-linter: + glob: "*.erb" + run: bundle exec erblint --lint-all {staged_files} + js-linter: + glob: "*.js" + run: standard --fix {staged_files} + stage_fixed: true + fix-typos: + exclude: '\.(pdf|ttf|jpg|png|csv)$' + run: typos --write-changes {staged_files} + stage_fixed: true \ No newline at end of file diff --git a/.reek.yml b/.reek.yml new file mode 100644 index 00000000..4cbdb0d5 --- /dev/null +++ b/.reek.yml @@ -0,0 +1,3 @@ +detectors: + IrresponsibleModule: + enabled: false \ No newline at end of file diff --git a/.rubycritic.yml b/.rubycritic.yml new file mode 100644 index 00000000..64253be9 --- /dev/null +++ b/.rubycritic.yml @@ -0,0 +1,6 @@ +branch: 'main' # default is master +threshold_score: 2 # default is 0 +minimum_score: 95 # default is 0 +paths: + - "app/" + - "config/" \ No newline at end of file diff --git a/Gemfile b/Gemfile index c1840d8c..e2c43009 100644 --- a/Gemfile +++ b/Gemfile @@ -32,10 +32,16 @@ gem "validates_timeliness", "~> 7.0.0.beta1" group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem + gem "better_errors" + gem "binding_of_caller" + gem "brakeman" + gem "bundle-audit" + gem "database_consistency" gem "debug", platforms: %i[mri windows] gem "dotenv" gem "erb_lint", require: false gem "factory_bot_rails" + gem "letter_opener" gem "pry-byebug" gem "rspec-rails" gem "rubocop-capybara", require: false @@ -43,6 +49,7 @@ group :development, :test do gem "rubocop-rails", require: false gem "rubocop-rspec", require: false gem "rubocop-rspec_rails", require: false + gem "rubycritic" gem "standard" end diff --git a/Gemfile.lock b/Gemfile.lock index f48cd04d..d699a233 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -86,7 +86,15 @@ GEM activerecord (>= 3.2, < 8.0) rake (>= 10.4, < 14.0) ast (2.4.2) + axiom-types (0.1.1) + descendants_tracker (~> 0.0.4) + ice_nine (~> 0.11.0) + thread_safe (~> 0.3, >= 0.3.1) base64 (0.2.0) + better_errors (2.10.1) + erubi (>= 1.0.0) + rack (>= 0.9.0) + rouge (>= 1.0.0) better_html (2.1.1) actionview (>= 6.0) activesupport (>= 6.0) @@ -96,9 +104,18 @@ GEM smart_properties bigdecimal (3.1.8) bindex (0.8.1) + binding_of_caller (1.0.1) + debug_inspector (>= 1.2.0) bootsnap (1.18.3) msgpack (~> 1.2) + brakeman (6.1.2) + racc builder (3.3.0) + bundle-audit (0.1.0) + bundler-audit + bundler-audit (0.9.1) + bundler (>= 1.2.0, < 3) + thor (~> 1.0) byebug (11.1.3) capybara (3.40.0) addressable @@ -109,20 +126,56 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) + childprocess (5.0.0) coderay (1.1.3) + coercible (1.0.0) + descendants_tracker (~> 0.0.1) concurrent-ruby (1.3.3) connection_pool (2.4.1) crass (1.0.6) cuprite (0.15.1) capybara (~> 3.0) ferrum (~> 0.15.0) + database_consistency (1.7.23) + activerecord (>= 3.2) date (3.3.4) debug (1.9.2) irb (~> 1.10) reline (>= 0.3.8) + debug_inspector (1.2.0) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.5.1) + docile (1.4.0) dotenv (3.1.2) drb (2.2.1) + dry-configurable (1.2.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.1) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-inflector (1.1.0) + dry-initializer (3.1.1) + dry-logic (1.5.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-schema (1.13.4) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-logic (>= 1.4, < 2) + dry-types (>= 1.7, < 2) + zeitwerk (~> 2.6) + dry-types (1.7.2) + bigdecimal (~> 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) erb_lint (0.5.0) activesupport better_html (>= 2.0.1) @@ -145,6 +198,15 @@ GEM concurrent-ruby (~> 1.1) webrick (~> 1.7) websocket-driver (~> 0.7) + flay (2.13.3) + erubi (~> 1.10) + path_expander (~> 1.0) + ruby_parser (~> 3.0) + sexp_processor (~> 4.0) + flog (4.8.0) + path_expander (~> 1.0) + ruby_parser (~> 3.1, > 3.1.0) + sexp_processor (~> 4.8) fugit (1.11.0) et-orbi (~> 1, >= 1.2.11) raabro (~> 1.4) @@ -155,6 +217,7 @@ GEM activesupport (>= 6.1) i18n (1.14.5) concurrent-ruby (~> 1.0) + ice_nine (0.11.2) importmap-rails (2.0.1) actionpack (>= 6.0.0) activesupport (>= 6.0.0) @@ -165,6 +228,11 @@ GEM reline (>= 0.4.2) json (2.7.2) language_server-protocol (3.17.0.3) + launchy (3.0.1) + addressable (~> 2.8) + childprocess (~> 5.0) + letter_opener (1.10.0) + launchy (>= 2.2, < 4) lint_roller (1.1.0) loofah (2.22.0) crass (~> 1.0.2) @@ -198,10 +266,13 @@ GEM nio4r (2.7.3) nokogiri (1.16.6-arm64-darwin) racc (~> 1.4) + nokogiri (1.16.6-x86_64-linux) + racc (~> 1.4) parallel (1.25.1) parser (3.3.3.0) ast (~> 2.4.1) racc + path_expander (1.1.1) propshaft (0.9.0) actionpack (>= 7.0.0) activesupport (>= 7.0.0) @@ -220,7 +291,7 @@ GEM nio4r (~> 2.0) raabro (1.4.0) racc (1.8.0) - rack (3.1.4) + rack (3.1.6) rack-mini-profiler (3.3.1) rack (>= 1.2.0) rack-session (2.0.0) @@ -263,11 +334,17 @@ GEM rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) + reek (6.3.0) + dry-schema (~> 1.13.0) + parser (~> 3.3.0) + rainbow (>= 2.0, < 4.0) + rexml (~> 3.1) regexp_parser (2.9.2) reline (0.5.9) io-console (~> 0.5) rexml (3.3.1) strscan + rouge (4.3.0) rspec (3.13.0) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) @@ -323,6 +400,28 @@ GEM rubocop-rspec (~> 3, >= 3.0.1) ruby-next-core (1.0.3) ruby-progressbar (1.13.0) + ruby_parser (3.21.0) + racc (~> 1.5) + sexp_processor (~> 4.16) + rubycritic (4.9.0) + flay (~> 2.13) + flog (~> 4.7) + launchy (>= 2.5.2) + parser (>= 3.2.2.1) + rainbow (~> 3.1.1) + reek (~> 6.0, < 7.0) + rexml + ruby_parser (~> 3.20) + simplecov (>= 0.22.0) + tty-which (~> 0.5.0) + virtus (~> 2.0) + sexp_processor (4.17.1) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) smart_properties (1.17.0) solid_queue (0.3.3) activejob (>= 7.1) @@ -331,6 +430,7 @@ GEM fugit (~> 1.11.0) railties (>= 7.1) sqlite3 (1.7.3-arm64-darwin) + sqlite3 (1.7.3-x86_64-linux) standard (1.39.0) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.0) @@ -349,9 +449,13 @@ GEM strscan (3.1.0) tailwindcss-rails (2.6.1-arm64-darwin) railties (>= 7.0.0) + tailwindcss-rails (2.6.1-x86_64-linux) + railties (>= 7.0.0) thor (1.3.1) + thread_safe (0.3.6) timeliness (0.4.5) timeout (0.4.1) + tty-which (0.5.0) turbo-rails (2.0.5) actionpack (>= 6.0.0) activejob (>= 6.0.0) @@ -362,6 +466,10 @@ GEM validates_timeliness (7.0.0.beta2) activemodel (>= 7.0.0, < 8) timeliness (>= 0.3.10, < 1) + virtus (2.0.0) + axiom-types (~> 0.1) + coercible (~> 1.0) + descendants_tracker (~> 0.0, >= 0.0.3) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -378,14 +486,20 @@ GEM PLATFORMS arm64-darwin-21 arm64-darwin-23 + x86_64-linux DEPENDENCIES action_policy (~> 0.7.0) activerecord-enhancedsqlite3-adapter (~> 0.8.0) annotate + better_errors + binding_of_caller bootsnap + brakeman + bundle-audit capybara cuprite + database_consistency debug dotenv erb_lint @@ -393,6 +507,7 @@ DEPENDENCIES faker fuubar importmap-rails + letter_opener mission_control-jobs propshaft pry-byebug @@ -407,6 +522,7 @@ DEPENDENCIES rubocop-rails rubocop-rspec rubocop-rspec_rails + rubycritic solid_queue sqlite3 (~> 1.4) standard diff --git a/README.md b/README.md index 6c325f86..1bdd7018 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,28 @@ We use [Typos](https://github.com/crate-ci/typos) as a spell checker. - Run `typos -w` to auto-correct offenses - For false positives and other configuration, see the `_typos.yml` file +#### Optional - Running linters' auto-fix before a commit + +[Leftook](https://github.com/evilmartians/lefthook) will execute the linters' auto-fix on staged files and abort the commit if there are offenses that can't be auto-fixed. +Run the following commands to enable this flow: + +``` +gem install lefthook +lefthook install +``` + +## Code Quality + +#### Rubycritic + +Besides code reviews, we use [rubycritic](https://github.com/whitesmith/rubycritic) to generate a report of the code quality. Both as a reviewer and as a contributor, you should check the report and address the issues found if the files you are working on have a low score ("D" or "F"). +- You can run it with `bundle exec rubycritic` + +#### Database consistency + +We use [DatabaseConsistency](https://github.com/djezzzl/database_consistency) to check for inconsistencies between the database schema and the application models. +- You can run it with `bundle exec database_consistency`. + ## Testing Run tests by using `bundle exec rspec`. diff --git a/app/models/user.rb b/app/models/user.rb index 86eeec63..6f9f0d0b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -20,4 +20,6 @@ class User < ApplicationRecord has_one :profile, as: :profileable, dependent: :destroy has_and_belongs_to_many :events + + validates :email, presence: true, uniqueness: true end diff --git a/config/environments/development.rb b/config/environments/development.rb index 25334d0b..e01622cf 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -36,6 +36,11 @@ # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local + # Preview email in the default browser instead of sending it. + config.action_mailer.delivery_method = :letter_opener + + config.action_mailer.perform_deliveries = true + # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false