Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ public/api/_analytics-events.json: .yardoc .yardoc/objects/root.dat

.yardoc .yardoc/objects/root.dat: app/services/analytics_events.rb
bundle exec yard doc \
--no-progress \
--fail-on-warning \
--type-tag identity.idp.previous_event_name:"Previous Event Name" \
--no-output \
Expand Down
30 changes: 15 additions & 15 deletions app/services/analytics_events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def account_reset_cancel_token_validation(
# @param [String] user_id
# @param [Integer, nil] account_age_in_days number of days since the account was confirmed
# @param [Time] account_confirmed_at date that account creation was confirmed
# (rounded) or nil if the account was not confirmed
# (rounded) or nil if the account was not confirmed
# @param [Hash] mfa_method_counts Hash of MFA method with the number of that method on the account
# @param [Boolean] identity_verified if the deletion occurs on a verified account
# @param [Hash] errors Errors resulting from form validation
Expand Down Expand Up @@ -244,7 +244,7 @@ def account_visit
# @param [Hash] error_details Details for errors that occurred in unsuccessful submission
# @param [String] user_id User the email is linked to
# @param [Boolean] from_select_email_flow Whether email was added as part of partner email
# selection.
# selection.
# A user has clicked the confirmation link in an email
def add_email_confirmation(
user_id:,
Expand All @@ -270,7 +270,7 @@ def add_email_confirmation(
# @param [Hash] error_details Details for errors that occurred in unsuccessful submission
# @param [String] domain_name Domain name of email address submitted
# @param [Boolean] in_select_email_flow Whether email is being added as part of partner email
# selection.
# selection.
# Tracks request for adding new emails to an account
def add_email_request(
success:,
Expand Down Expand Up @@ -513,7 +513,7 @@ def edit_password_visit(required_password_change: false, **extra)
# @param [Boolean] sp_request_url_present if was an SP request URL in the session
# @param [Boolean] remember_device if the remember device cookie was present
# @param [Boolean, nil] new_device Whether the user is authenticating from a new device. Nil if
# the attempt was unsuccessful, since it cannot be known whether it's a new device.
# the attempt was unsuccessful, since it cannot be known whether it's a new device.
# Tracks authentication attempts at the email/password screen
def email_and_password_auth(
success:,
Expand Down Expand Up @@ -1086,7 +1086,7 @@ def idv_camera_info_error(error:, **_extra)

# @param ["hybrid","standard"] flow_path Document capture user flow
# @param [Array] camera_info Information on the users cameras max resolution
# as captured by the browser
# as captured by the browser
def idv_camera_info_logged(flow_path:, camera_info:, **_extra)
track_event(
:idv_camera_info_logged, flow_path: flow_path, camera_info: camera_info
Expand Down Expand Up @@ -1454,7 +1454,7 @@ def idv_doc_auth_exception_visited(step_name:, remaining_submit_attempts:, **ext

# @param [String] side the side of the image submission
# @param [Integer] submit_attempts Times that user has tried submitting (previously called
# "attempts")
# "attempts")
# @param [Integer] remaining_submit_attempts (previously called "remaining_attempts")
# @param ["hybrid","standard"] flow_path Document capture user flow
# @param [String] liveness_checking_required Whether or not the selfie is required
Expand Down Expand Up @@ -2984,7 +2984,7 @@ def idv_in_person_prepare_visited(flow_path:, opted_in_to_in_person_proofing:, *
# @param [String] analytics_id
# @param [Boolean] skip_hybrid_handoff Whether skipped hybrid handoff A/B test is active
# @param [Boolean] opted_in_to_in_person_proofing User opted into in person proofing
# address page visited
# address page visited
def idv_in_person_proofing_address_visited(
flow_path:,
step:,
Expand Down Expand Up @@ -6442,7 +6442,7 @@ def phone_change_viewed

# @param [Boolean] success
# @param [Integer] phone_configuration_id
# tracks a phone number deletion event
# Tracks a phone number deletion event
def phone_deletion(success:, phone_configuration_id:, **extra)
track_event(
'Phone Number Deletion: Submitted',
Expand Down Expand Up @@ -6485,7 +6485,7 @@ def piv_cac_delete_submitted(
# @param [Hash] errors Errors resulting from form validation
# @param [String, nil] key_id PIV/CAC key_id from PKI service
# @param [Boolean] new_device Whether the user is authenticating from a new device
# tracks piv cac login event
# Tracks piv cac login event
def piv_cac_login(success:, errors:, key_id:, new_device:, **extra)
track_event(
:piv_cac_login,
Expand Down Expand Up @@ -7043,17 +7043,17 @@ def security_event_received(
)
end

# tracks if the session is kept alive
# Tracks if the session is kept alive
def session_kept_alive
track_event('Session Kept Alive')
end

# tracks if the session timed out
# Tracks if the session timed out
def session_timed_out
track_event('Session Timed Out')
end

# tracks when a user's session is timed out
# Tracks when a user's session is timed out
def session_total_duration_timeout
track_event('User Maximum Session Length Exceeded')
end
Expand All @@ -7064,7 +7064,7 @@ def sign_in_notification_timeframe_expired_absent
end

# @param [String] flash
# tracks when a user visits the sign in page
# Tracks when a user visits the sign in page
def sign_in_page_visit(flash:, **extra)
track_event('Sign in page visited', flash:, **extra)
end
Expand All @@ -7080,7 +7080,7 @@ def sign_in_security_check_failed_visited
# @param [Boolean] new_user Whether this is an incomplete user (no associated MFA methods)
# @param [Boolean] has_other_auth_methods Whether the user has other authentication methods
# @param [Integer] phone_configuration_id Phone configuration associated with request
# tracks when a user opts into SMS
# Tracks when a user opts into SMS
def sms_opt_in_submitted(
success:,
errors:,
Expand All @@ -7105,7 +7105,7 @@ def sms_opt_in_submitted(
# @param [Boolean] new_user
# @param [Boolean] has_other_auth_methods
# @param [Integer] phone_configuration_id
# tracks when a user visits the sms opt in page
# Tracks when a user visits the sms opt in page
def sms_opt_in_visit(
new_user:,
has_other_auth_methods:,
Expand Down
18 changes: 17 additions & 1 deletion lib/analytics_events_documenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ def missing_documentation
errors << "#{error_prefix} #{tag.name} missing types" if !tag.types
end

description = method_description(method_object)
if description.present? && !method_object.docstring.match?(/\A[A-Z]/)
indented_description = description.lines.map { |line| " #{line.chomp}" }.join("\n")

errors << <<~MSG
#{error_prefix} method description starts with lowercase, check indentation:
#{indented_description}
MSG
end

errors
end
end
Expand Down Expand Up @@ -156,7 +166,7 @@ def as_json
{
event_name: extract_event_name(method_object),
previous_event_names: method_object.tags(PREVIOUS_EVENT_NAME_TAG).map(&:text),
description: method_object.docstring.presence,
description: method_description(method_object),
attributes: attributes,
method_name: method_object.name,
source_line: method_object.line,
Expand All @@ -168,6 +178,12 @@ def as_json
{ events: events_json_summary }
end

# Strips Rubocop directives from description text
# @return [String, nil]
def method_description(method_object)
method_object.docstring.to_s.gsub(/^rubocop.+$/, '').presence&.chomp
end

private

# Naive attempt to pull tracked event string or symbol from source code
Expand Down
43 changes: 41 additions & 2 deletions spec/lib/analytics_events_documenter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,16 +204,55 @@ def some_event(*)
end
end

context 'param description gets munged into method descripion' do
let(:source_code) { <<~RUBY }
class AnalyticsEvents
# @param val [String] some value that
# does things and this should be part of the param
# Some Event
def some_event(val:, **extra)
track_event('Some Event', val:, **extra)
end
end
RUBY

it 'errors' do
expect(documenter.missing_documentation.first)
.to include('method description starts with lowercase, check indentation')
end
end

context 'rubocop comment around params description' do
let(:source_code) { <<~RUBY }
class AnalyticsEvents
# @param val [String] some value that
# does things and this should be part of the param
# Some Event
# rubocop:disable Layout/LineLength
def some_event(val:, **extra)
track_event('Some Event', val:, **extra)
end
# rubocop:enable Layout/LineLength
end
RUBY

it 'ignores rubocop lines' do
expect(documenter.missing_documentation).to be_empty
end
end

describe '#as_json' do
let(:source_code) { <<~RUBY }
class AnalyticsEvents
# @param [Boolean] success
# @param [Integer] count number of attempts
# The event that does something with stuff
# @option extra [String] 'DocumentName' the document name
# rubocop:disable Layout/LineLength
def some_event(success:, count:, **extra)
track_event('Some Event', **extra)
end
# rubocop:enable Layout/LineLength

# @identity.idp.previous_event_name The Old Other Event
# @identity.idp.previous_event_name Even Older Other Event
Expand All @@ -223,7 +262,7 @@ def other_event
end
RUBY

it 'is a JSON representation of params for each event' do
it 'is a JSON representation of params for each event, ignoring rubocop directives' do
expect(documenter.as_json[:events]).to match_array(
[
{
Expand Down Expand Up @@ -277,7 +316,7 @@ def some_event(success:, **extra)
{
event_name: 'some_event',
previous_event_names: [],
description: '',
description: nil,
attributes: [
{ name: 'success', types: ['Boolean'], description: nil },
],
Expand Down