Skip to content

Commit 6812ecf

Browse files
authored
More Sorbet fixes
1 parent 1f5ef87 commit 6812ecf

40 files changed

+1100
-116
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,6 @@ SIMPLE_USER_ACTIVATION=false
8989

9090
# Whether to show units/inspections at all
9191
HAS_ASSESSMENTS=true
92+
93+
# If you're building the Tapioca RBI files, enable this
94+
RUNNING_TAPIOCA=false

.github/workflows/pre-release.yml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,10 @@ jobs:
1818
uses: ./.github/workflows/test-ruby.yml
1919
permissions:
2020
contents: read
21-
22-
typecheck:
23-
name: Type Check
24-
uses: ./.github/workflows/sorbet.yml
25-
permissions:
26-
contents: read
27-
21+
2822
docker-build:
2923
name: Test Docker Build
30-
needs: [test, typecheck]
24+
needs: [test]
3125
uses: ./.github/workflows/docker-build.yml
3226
with:
3327
push: false

.github/workflows/sorbet.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ jobs:
3030
3131
- name: Generate Sorbet RBI files
3232
run: |
33-
bundle exec tapioca gems
34-
bundle exec tapioca dsl
33+
RUNNING_TAPIOCA=true \
34+
bundle exec tapioca annotations && \
35+
bundle exec tapioca gems && \
36+
bundle exec tapioca dsl
3537
3638
- name: Run Sorbet type check
3739
run: |

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151

5252
# Ignore generated Sorbet RBI files (can be regenerated)
5353
.sorbet-results
54+
sorbet/rbi/dsl/*
55+
sorbet/rbi/gems/*
56+
sorbet/rbi/annotations/*
57+
!sorbet/rbi/manual/
5458

5559
# Pinned docker versions
5660
PINNED_VERSION

Gemfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ gem "sqlite3", ">= 1.4"
1414
# Use the Puma web server [https://github.com/puma/puma]
1515
gem "puma", ">= 5.0"
1616
# Using in-memory queue for background processing
17-
gem "solid_queue", "~> 1.0"
18-
gem "mission_control-jobs", "~> 1.0"
17+
gem "solid_queue"
1918

2019
# WebAuthn for passkey support
2120
gem "webauthn", "~> 3.4"
@@ -120,6 +119,12 @@ gem "sentry-rails"
120119
# S3-compatible storage
121120
gem "aws-sdk-s3", require: false
122121

122+
# Production and development gems
123+
group :development, :production do
124+
# Mission Control for managing background jobs
125+
gem "mission_control-jobs", "~> 1.0", require: false
126+
end
127+
123128
# Production-only gems
124129
group :production do
125130
# Cron job management

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ DEPENDENCIES
624624
sentry-ruby
625625
simplecov
626626
simplecov-cobertura
627-
solid_queue (~> 1.0)
627+
solid_queue
628628
sorbet
629629
sorbet-runtime (= 0.5.12016)
630630
sprockets-rails

app/controllers/application_controller.rb

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,23 @@ class ApplicationController < ActionController::Base
4848
raise exception
4949
end
5050

51-
private
52-
5351
sig { returns(T::Boolean) }
5452
def skip_authentication?
5553
false
5654
end
5755

56+
# Class method version for use in rescue_from blocks
5857
sig { params(table: Symbol, key: Symbol, args: T.untyped).returns(String) }
59-
def app_i18n(table, key, **args)
58+
def self.app_i18n(table, key, **args)
6059
I18n.t("application.#{table}.#{key}", **args)
6160
end
6261

62+
# Instance method delegates to class method
63+
sig { params(table: Symbol, key: Symbol, args: T.untyped).returns(String) }
64+
def app_i18n(table, key, **args)
65+
self.class.app_i18n(table, key, **args)
66+
end
67+
6368
sig { params(form: Symbol, key: T.any(Symbol, String), args: T.untyped).returns(String) }
6469
def form_i18n(form, key, **args)
6570
I18n.t("forms.#{form}.#{key}", **args)
@@ -88,9 +93,9 @@ def update_last_active_at
8893
current_user.update(last_active_at: Time.current)
8994

9095
# Update UserSession last_active_at
91-
if session[:session_token]
92-
current_session&.touch_last_active
93-
end
96+
return unless session[:session_token]
97+
98+
current_session&.touch_last_active
9499
end
95100

96101
sig { void }
@@ -195,9 +200,7 @@ def should_notify_error?(exception)
195200
return false if csrf_ignored_actions.include?(action)
196201
end
197202

198-
if exception.is_a?(ActionController::InvalidCrossOriginRequest)
199-
return false unless logged_in?
200-
end
203+
return false if exception.is_a?(ActionController::InvalidCrossOriginRequest) && !logged_in?
201204

202205
true
203206
end

app/controllers/concerns/session_management.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def establish_user_session(user)
1414
)
1515

1616
session[:session_token] = user_session.session_token
17-
create_user_session(user)
17+
create_user_session
1818

1919
user_session
2020
end

app/helpers/concerns/controller_context.rb

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ module ControllerContext
1010

1111
abstract!
1212

13-
# Core Rails controller methods
13+
# These methods are provided by ActionController/ActionView
14+
# We declare them as abstract so Sorbet knows about them
15+
# but doesn't provide implementations that would override Rails
16+
1417
sig { abstract.returns(T.untyped) }
1518
def session
1619
end
@@ -31,15 +34,15 @@ def request
3134
def flash
3235
end
3336

34-
sig { abstract.returns(T.untyped) }
35-
def redirect_to
37+
sig { abstract.params(args: T.untyped).returns(T.untyped) }
38+
def redirect_to(*args)
3639
end
3740

38-
sig { abstract.returns(T.untyped) }
39-
def render
41+
sig { abstract.params(args: T.untyped).returns(T.untyped) }
42+
def render(*args)
4043
end
4144

42-
sig { abstract.returns(T.untyped) }
43-
def respond_to
45+
sig { abstract.params(args: T.untyped, block: T.untyped).returns(T.untyped) }
46+
def respond_to(*args, &block)
4447
end
4548
end

app/helpers/inspections_helper.rb

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ def inspection_result_badge(inspection)
2323
end
2424
end
2525

26-
sig {
26+
sig do
2727
params(inspection: Inspection).returns(
2828
T::Array[T::Hash[Symbol, T.any(String, Symbol, T::Boolean)]]
2929
)
30-
}
30+
end
3131
def inspection_actions(inspection)
3232
actions = T.let([], T::Array[T::Hash[Symbol, T.any(String, Symbol, T::Boolean)]])
3333

@@ -115,18 +115,16 @@ def next_tab_navigation_info(inspection, current_tab)
115115
current_tab_incomplete = !assessment_complete?(inspection, current_tab)
116116

117117
# Find first incomplete tab after current (excluding results for now)
118-
next_incomplete = tabs_after.find { |tab|
118+
next_incomplete = tabs_after.find do |tab|
119119
tab != "results" && !assessment_complete?(inspection, tab)
120-
}
120+
end
121121

122122
# If current tab is incomplete and there's a next tab available
123123
if current_tab_incomplete && tabs_after.any?
124124
incomplete_count = incomplete_fields_count(inspection, current_tab)
125125

126126
# If there's an incomplete tab after, user should skip current incomplete
127-
if next_incomplete
128-
return {tab: next_incomplete, skip_incomplete: true, incomplete_count: incomplete_count}
129-
end
127+
return {tab: next_incomplete, skip_incomplete: true, incomplete_count: incomplete_count} if next_incomplete
130128

131129
# If results tab is incomplete, user should skip to results
132130
if tabs_after.include?("results") && inspection.passed.nil?
@@ -138,14 +136,10 @@ def next_tab_navigation_info(inspection, current_tab)
138136
end
139137

140138
# Current tab is complete, just suggest next incomplete tab
141-
if next_incomplete
142-
return {tab: next_incomplete, skip_incomplete: false}
143-
end
139+
return {tab: next_incomplete, skip_incomplete: false} if next_incomplete
144140

145141
# Check if results tab is incomplete
146-
if tabs_after.include?("results") && inspection.passed.nil?
147-
return {tab: "results", skip_incomplete: false}
148-
end
142+
return {tab: "results", skip_incomplete: false} if tabs_after.include?("results") && inspection.passed.nil?
149143

150144
nil
151145
end

0 commit comments

Comments
 (0)