Bugzilla – Attachment 190711 Details for
Bug 6473
Test bug for Git-bz ✔ ❤ ★
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
[#36] Add iterative error handling for invalid QA contacts
b73d66d.patch (text/plain), 13.68 KB, created by
Tomás Cohen Arazi (tcohen)
on 2025-12-24 13:50:27 UTC
(
hide
)
Description:
[#36] Add iterative error handling for invalid QA contacts
Filename:
MIME Type:
Creator:
Tomás Cohen Arazi (tcohen)
Created:
2025-12-24 13:50:27 UTC
Size:
13.68 KB
patch
obsolete
>From b73d66d2a4a57e669d302bf8cd05961b38ac7246 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@openfifth.co.uk> >Date: Wed, 24 Dec 2025 10:34:16 +0000 >Subject: [PATCH] [#36] Add iterative error handling for invalid QA contacts >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >When a user enters an invalid QA contact email (e.g., a typo or >non-existent user), the bug update would fail with a 404 error and >the spinner would hang indefinitely. This commit adds comprehensive >error handling with user search and iterative retry logic. > >Changes: >- Added search_users() method to RestClient.pm to query Bugzilla's > user API endpoint with authentication token >- Added select_qa_contact() method to Edit.pm and Attach.pm that: > * Extracts the local part of the invalid email (before @) > * Searches for similar users whose emails begin with that pattern > * Presents a numbered list of matching users for selection > * Allows manual entry if no matches found >- Implemented iterative retry loop in both Edit and Attach commands: > * On 404 error, searches for similar users > * User can select from results or enter a different email > * If manually entered email also fails, searches again > * Continues until successful update or user cancels > * Properly stops spinner on each error before continuing > >Example flow: >1. User enters "martinrenvoize@theke.io" â 404 >2. Searches for "martinrenvoize" â no results >3. User enters "martin.renvoize@theke.io" â 404 >4. Searches for "martin.renvoize" â finds matches >5. User selects "martin.renvoize@openfifth.co.uk" â success > >This provides a much better user experience than the previous behavior >of hanging indefinitely with no feedback. >--- > lib/GitBz/Commands/Attach.pm | 131 +++++++++++++++++++++++++++++++++- > lib/GitBz/Commands/Edit.pm | 134 ++++++++++++++++++++++++++++++++++- > lib/GitBz/RestClient.pm | 41 ++++++++++- > 3 files changed, 300 insertions(+), 6 deletions(-) > >diff --git a/lib/GitBz/Commands/Attach.pm b/lib/GitBz/Commands/Attach.pm >index 4c29e7d..a9df70b 100644 >--- a/lib/GitBz/Commands/Attach.pm >+++ b/lib/GitBz/Commands/Attach.pm >@@ -406,8 +406,68 @@ sub attach_patches { > # Apply updates with spinner > if (%bug_updates) { > my $spinner = GitBz::Progress::start_spinner("Updating bug fields"); >- $bug->apply_updates(); >- GitBz::Progress::stop_spinner( $spinner, 'success', "Bug fields updated" ); >+ >+ my $update_success = eval { >+ $bug->apply_updates(); >+ 1; >+ }; >+ >+ if ($@) { >+ my $error = $@; >+ GitBz::Progress::stop_spinner( $spinner, 'error' ); >+ >+ # Check if it's a 404 error related to QA contact >+ if ( exists $bug_updates{qa_contact} && $error =~ /404|not found/i ) { >+ print "\n"; >+ GitBz::Progress::print_error("QA contact '$bug_updates{qa_contact}' not found"); >+ >+ # Iteratively search and retry until success or user cancels >+ my $attempted_email = $bug_updates{qa_contact}; >+ my $retry_success = 0; >+ >+ while ( !$retry_success ) { >+ # Offer to search for similar users >+ my $selected_email = $self->select_qa_contact( $client, $attempted_email ); >+ >+ if ( !$selected_email ) { >+ die "Update cancelled by user\n"; >+ } >+ >+ # Retry with the selected user >+ $bug->set_field( 'qa_contact', $selected_email ); >+ print "\nRetrying with QA contact: $selected_email\n"; >+ $spinner = GitBz::Progress::start_spinner("Updating bug fields"); >+ >+ my $retry_eval = eval { >+ $bug->apply_updates(); >+ 1; >+ }; >+ >+ if ($@) { >+ my $retry_error = $@; >+ GitBz::Progress::stop_spinner( $spinner, 'error' ); >+ >+ # Check if it's another 404 error >+ if ( $retry_error =~ /404|not found/i ) { >+ GitBz::Progress::print_error("QA contact '$selected_email' not found"); >+ $attempted_email = $selected_email; # Use this as the next search term >+ # Loop continues >+ } else { >+ # Different error, rethrow >+ die $retry_error; >+ } >+ } else { >+ # Success! >+ GitBz::Progress::stop_spinner( $spinner, 'success', "Bug fields updated" ); >+ $retry_success = 1; >+ } >+ } >+ } else { >+ die $error; >+ } >+ } else { >+ GitBz::Progress::stop_spinner( $spinner, 'success', "Bug fields updated" ); >+ } > } > > # Perform obsoletes with real-time feedback >@@ -659,4 +719,71 @@ sub parse_bug_updates { > return ( $bug_comment, \@obsoletes, $bug_updates ); > } > >+=head2 select_qa_contact >+ >+ my $email = $attach->select_qa_contact($client, $invalid_email); >+ >+Searches for users matching the invalid email and presents a selection menu. >+Returns the selected email, or undef if cancelled. >+ >+=cut >+ >+sub select_qa_contact { >+ my ( $self, $client, $invalid_email ) = @_; >+ >+ # Extract the local part (before @) from the invalid email >+ my $search_term; >+ if ( $invalid_email =~ /^([^@]+)@/ ) { >+ $search_term = $1; >+ } else { >+ $search_term = $invalid_email; >+ } >+ >+ # Search for users whose email begins with the local part >+ print "\nSearching for similar users (begins with '$search_term')...\n"; >+ my $users = GitBz::Progress::with_spinner( >+ "Searching users", >+ sub { >+ return $client->search_users($search_term); >+ }, >+ 1 >+ ); >+ >+ if ( !@$users ) { >+ print "No similar users found.\n"; >+ print "Would you like to enter a different QA contact? [y/N]: "; >+ my $response = <STDIN>; >+ chomp $response; >+ >+ if ( $response =~ /^[yY]/ ) { >+ print "Enter QA contact email: "; >+ my $new_email = <STDIN>; >+ chomp $new_email; >+ $new_email =~ s/^\s+|\s+$//g; >+ return $new_email if $new_email; >+ } >+ >+ return; >+ } >+ >+ # Present users for selection >+ print "\nFound " . scalar(@$users) . " similar user(s):\n\n"; >+ >+ for my $i ( 0 .. $#$users ) { >+ my $user = $users->[$i]; >+ my $display_name = $user->{real_name} ? "$user->{real_name} <$user->{email}>" : $user->{email}; >+ print " [$i] $display_name\n"; >+ } >+ >+ print "\nSelect a user by number, or press Enter to cancel: "; >+ my $selection = <STDIN>; >+ chomp $selection; >+ >+ if ( $selection =~ /^\d+$/ && $selection >= 0 && $selection <= $#$users ) { >+ return $users->[$selection]{email}; >+ } >+ >+ return; >+} >+ > 1; >diff --git a/lib/GitBz/Commands/Edit.pm b/lib/GitBz/Commands/Edit.pm >index 6b31028..fbcc103 100644 >--- a/lib/GitBz/Commands/Edit.pm >+++ b/lib/GitBz/Commands/Edit.pm >@@ -393,9 +393,70 @@ sub update_bug { > > $bug->_display_changes(); > my $spinner = GitBz::Progress::start_spinner("Updating bug fields"); >- $bug->apply_updates(); >- GitBz::Progress::stop_spinner( $spinner, 'success', "Bug fields updated" ); >- $changed = 1; >+ >+ my $update_success = eval { >+ $bug->apply_updates(); >+ 1; >+ }; >+ >+ if ($@) { >+ my $error = $@; >+ GitBz::Progress::stop_spinner( $spinner, 'error' ); >+ >+ # Check if it's a 404 error related to QA contact >+ if ( exists $actual_changes{qa_contact} && $error =~ /404|not found/i ) { >+ print "\n"; >+ GitBz::Progress::print_error("QA contact '$actual_changes{qa_contact}' not found"); >+ >+ # Iteratively search and retry until success or user cancels >+ my $attempted_email = $actual_changes{qa_contact}; >+ my $retry_success = 0; >+ >+ while ( !$retry_success ) { >+ # Offer to search for similar users >+ my $selected_email = $self->select_qa_contact( $client, $attempted_email ); >+ >+ if ( !$selected_email ) { >+ die "Update cancelled by user\n"; >+ } >+ >+ # Retry with the selected user >+ $bug->set_field( 'qa_contact', $selected_email ); >+ print "\nRetrying with QA contact: $selected_email\n"; >+ $spinner = GitBz::Progress::start_spinner("Updating bug fields"); >+ >+ my $retry_eval = eval { >+ $bug->apply_updates(); >+ 1; >+ }; >+ >+ if ($@) { >+ my $retry_error = $@; >+ GitBz::Progress::stop_spinner( $spinner, 'error' ); >+ >+ # Check if it's another 404 error >+ if ( $retry_error =~ /404|not found/i ) { >+ GitBz::Progress::print_error("QA contact '$selected_email' not found"); >+ $attempted_email = $selected_email; # Use this as the next search term >+ # Loop continues >+ } else { >+ # Different error, rethrow >+ die $retry_error; >+ } >+ } else { >+ # Success! >+ GitBz::Progress::stop_spinner( $spinner, 'success', "Bug fields updated" ); >+ $changed = 1; >+ $retry_success = 1; >+ } >+ } >+ } else { >+ die $error; >+ } >+ } else { >+ GitBz::Progress::stop_spinner( $spinner, 'success', "Bug fields updated" ); >+ $changed = 1; >+ } > } > > # Handle obsoleting attachments >@@ -445,4 +506,71 @@ sub extract_bug_ref { > return; > } > >+=head2 select_qa_contact >+ >+ my $email = $edit->select_qa_contact($client, $invalid_email); >+ >+Searches for users matching the invalid email and presents a selection menu. >+Returns the selected email, or undef if cancelled. >+ >+=cut >+ >+sub select_qa_contact { >+ my ( $self, $client, $invalid_email ) = @_; >+ >+ # Extract the local part (before @) from the invalid email >+ my $search_term; >+ if ( $invalid_email =~ /^([^@]+)@/ ) { >+ $search_term = $1; >+ } else { >+ $search_term = $invalid_email; >+ } >+ >+ # Search for users whose email begins with the local part >+ print "\nSearching for similar users (begins with '$search_term')...\n"; >+ my $users = GitBz::Progress::with_spinner( >+ "Searching users", >+ sub { >+ return $client->search_users($search_term); >+ }, >+ 1 >+ ); >+ >+ if ( !@$users ) { >+ print "No similar users found.\n"; >+ print "Would you like to enter a different QA contact? [y/N]: "; >+ my $response = <STDIN>; >+ chomp $response; >+ >+ if ( $response =~ /^[yY]/ ) { >+ print "Enter QA contact email: "; >+ my $new_email = <STDIN>; >+ chomp $new_email; >+ $new_email =~ s/^\s+|\s+$//g; >+ return $new_email if $new_email; >+ } >+ >+ return; >+ } >+ >+ # Present users for selection >+ print "\nFound " . scalar(@$users) . " similar user(s):\n\n"; >+ >+ for my $i ( 0 .. $#$users ) { >+ my $user = $users->[$i]; >+ my $display_name = $user->{real_name} ? "$user->{real_name} <$user->{email}>" : $user->{email}; >+ print " [$i] $display_name\n"; >+ } >+ >+ print "\nSelect a user by number, or press Enter to cancel: "; >+ my $selection = <STDIN>; >+ chomp $selection; >+ >+ if ( $selection =~ /^\d+$/ && $selection >= 0 && $selection <= $#$users ) { >+ return $users->[$selection]{email}; >+ } >+ >+ return; >+} >+ > 1; >diff --git a/lib/GitBz/RestClient.pm b/lib/GitBz/RestClient.pm >index ed17db9..492528a 100644 >--- a/lib/GitBz/RestClient.pm >+++ b/lib/GitBz/RestClient.pm >@@ -274,6 +274,45 @@ sub get_field_values { > return []; > } > >+=head2 search_users >+ >+ my $users = $client->search_users($search_term); >+ >+Searches for users matching the given search term. >+Returns arrayref of user hashes with 'email', 'real_name', and 'id' keys. >+ >+=cut >+ >+sub search_users { >+ my ( $self, $search_term ) = @_; >+ >+ return [] unless $search_term; >+ >+ # Get authentication token >+ my $token = $self->get_token(); >+ >+ # Build URL with token for authentication >+ my $url = sprintf( "%s/user?match=%s", $self->{base_url}, $search_term ); >+ $url .= "&token=$token" if $token; >+ >+ my $response = $self->{ua}->get($url); >+ >+ if ( !$response->is_success ) { >+ return []; >+ } >+ >+ my $data = decode_json( $response->content ); >+ >+ # Return users array with relevant fields >+ return [ map { >+ { >+ email => $_->{email}, >+ real_name => $_->{real_name} || '', >+ id => $_->{id} >+ } >+ } @{ $data->{users} || [] } ]; >+} >+ > =head2 obsolete_attachment > > $client->obsolete_attachment($attachment_id); >@@ -353,4 +392,4 @@ sub get_bug_url { > return "$web_url/show_bug.cgi?id=$bug_id"; > } > >-1; >\ No newline at end of file >+1; >-- >2.50.1 (Apple Git-155) >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 6473
:
4386
|
6837
|
6838
|
6839
|
6840
|
6841
|
6842
|
6843
|
7154
|
7155
|
7567
|
7994
|
7995
|
7996
|
7997
|
8018
|
9807
|
9808
|
9813
|
9831
|
9832
|
9836
|
9854
|
10842
|
10843
|
10844
|
10845
|
10846
|
10847
|
10848
|
10849
|
10850
|
10851
|
10852
|
10853
|
10854
|
10855
|
10856
|
10857
|
10858
|
11540
|
11543
|
11544
|
12502
|
12513
|
12514
|
12515
|
12516
|
12517
|
12518
|
12519
|
13473
|
13673
|
14955
|
14969
|
14970
|
14972
|
15201
|
18949
|
18950
|
18951
|
18952
|
18953
|
18954
|
18955
|
18956
|
18957
|
18958
|
18959
|
18960
|
18961
|
18962
|
18963
|
18971
|
18972
|
19518
|
19519
|
19591
|
19592
|
19871
|
19879
|
19880
|
19881
|
19882
|
20011
|
20012
|
20013
|
20014
|
22477
|
22481
|
22482
|
22496
|
22502
|
22503
|
31958
|
32444
|
32445
|
32446
|
32447
|
32448
|
32449
|
32450
|
32451
|
32452
|
34200
|
34201
|
34625
|
34999
|
35130
|
35269
|
35273
|
35274
|
35275
|
35276
|
35277
|
35279
|
35280
|
35303
|
40954
|
40957
|
45345
|
45349
|
45731
|
45732
|
45733
|
45734
|
47283
|
47284
|
47298
|
47299
|
47300
|
47334
|
47336
|
49083
|
56974
|
61059
|
61069
|
62038
|
65313
|
77301
|
78016
|
79959
|
80178
|
80179
|
80180
|
80181
|
80182
|
84400
|
86644
|
86645
|
87152
|
88128
|
95586
|
95716
|
97394
|
99026
|
99027
|
114217
|
114218
|
114219
|
114220
|
114221
|
114222
|
114223
|
114224
|
114225
|
114226
|
119255
|
121181
|
131891
|
131893
|
131894
|
134862
|
144109
|
144144
|
144671
|
144672
|
144673
|
147183
|
149030
|
149031
|
149032
|
149033
|
160566
|
160567
|
160568
|
182093
|
183107
|
183177
|
183178
|
183179
|
183180
|
183182
|
183183
|
183285
|
183286
|
187209
|
187321
|
187322
|
187323
|
187324
|
187325
|
187326
|
187327
|
187328
|
187329
|
187330
|
187331
|
187332
|
187333
|
187334
|
187335
|
187336
|
187337
|
187338
|
187339
|
187340
|
187341
|
187342
|
187343
|
187344
|
187345
|
187346
|
187347
|
187348
|
187349
|
187350
|
187351
|
187352
|
187353
|
187354
|
187355
|
187356
|
187357
|
187358
|
187359
|
187360
|
187361
|
187362
|
187363
|
187364
|
187365
|
187366
|
187367
|
187368
|
187369
|
187370
|
187371
|
187372
|
187545
|
187546
|
188609
|
188610
|
188611
|
188612
|
188613
|
188614
|
188626
|
188627
|
188628
|
188629
|
188630
|
188631
|
188632
|
188633
|
188634
|
188645
|
188647
|
188703
|
188929
|
188937
|
188975
|
190164
|
190165
|
190166
|
190167
|
190168
|
190169
|
190170
|
190171
|
190172
|
190173
|
190174
|
190175
|
190176
|
190177
|
190178
|
190179
|
190180
|
190181
|
190182
|
190183
|
190184
|
190185
|
190186
|
190187
|
190188
|
190240
|
190241
|
190242
|
190243
|
190244
|
190245
|
190246
|
190247
|
190248
|
190249
|
190250
|
190251
|
190252
|
190253
|
190255
|
190256
|
190711
|
190712