Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error handling, general refinement to --skip-invitation flag #1006

Merged
merged 30 commits into from
Jun 26, 2023

Conversation

hfishback01
Copy link
Contributor

@hfishback01 hfishback01 commented May 26, 2023

Closes #6913
Closes #6914
Closes #1011

This PR addresses feedback from previous PR, including:

  • Moves csv specification check to validate method in the args file
  • Removes unnecessary comments
  • Updated specific unit tests

It also adds error handling and unit testing for different scenarios as outlined by screenshots below. I've also created an issue to update error message handling here when GH is updated:

--check for duplicate claimant in same issue errror

Updates console color for confirmation request also exits more gracefully on "n":

Screenshot 2023-05-26 at 8 35 30 AM

Errors handled:

Handles duplicates (both to same and different claimants):

Screenshot 2023-05-26 at 8 26 20 AM Screenshot 2023-05-26 at 8 34 22 AM

User not admin to EMU org:

Screenshot 2023-06-22 at 3 33 14 PM

Other errors that were already handled but mentioned in the issue:

Mannequins already claimed:

  • [2023-05-23 17:29:12] [ERROR] brianaj is already claimed. Skipping (use force if you want to reclaim)

Mannequins not part of target org

  • [2023-05-23 17:58:36] [ERROR] Mannequin gargola not found. Skipping.

Claimant not part of target org:

  • [2023-05-23 17:40:08] [ERROR] Failed to reclaim dpmex4527 (M_kgDOCAN3aw) to hfishback01 (MDQ6VXNlcjM4ODQ1Mjcy): Target must be a member of the hfishback01-cli-test3 organization

--no-prompt Used:

Screenshot 2023-06-22 at 3 53 57 PM

Feature Flag not enabled:

Screenshot 2023-06-23 at 7 36 48 PM
  • Did you write/update appropriate tests
  • Release notes updated (if appropriate)
  • Appropriate logging output
  • Issue linked
  • Docs updated (or issue created)
  • New package licenses are added to ThirdPartyNotices.txt (if applicable)

@hfishback01 hfishback01 self-assigned this May 26, 2023
@github-actions
Copy link

github-actions bot commented May 26, 2023

Unit Test Results

785 tests   785 ✔️  23s ⏱️
    1 suites      0 💤
    1 files        0

Results for commit 9a971d1.

♻️ This comment has been updated with latest results.

@hfishback01 hfishback01 marked this pull request as ready for review May 26, 2023 23:15
@brianaj
Copy link
Collaborator

brianaj commented May 26, 2023

Thanks @hfishback01 for getting this out, can you answer if you handled if org is not emu, not sure if this was addressed or not didn't catch it in the description/screenshots. If not can you add a line item to finish as part of this PR as that's a main error scenario we'll want to handle and make sure we don't keep iterating through csv.

@brianaj brianaj requested a review from dylan-smith May 31, 2023 17:22
@brianaj brianaj self-assigned this May 31, 2023
@synthead synthead self-requested a review May 31, 2023 19:46
Copy link
Collaborator

@synthead synthead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! I have a few PR review items to take a look at!

Also, since we're now having interactive prompts, we should probably add a --no-prompt option, too. We promote this tool to be used in scripts (it even creates said scripts!) so we should be ready to handle non-interactive commands.

We could start by going the easy route and abort with an error stating that --no-prompt was used, and there are unresolved mannequins that the user needs to address. This should be enough to have the user read the logs and know exactly what to do 👍

If we aren't implementing the mannequin reclaiming command in any scripts, and we're sure that the scripts generated from the CLI tool won't hang, I'm 100% on making this a tech debt item 👍

src/Octoshift/Services/GithubApi.cs Outdated Show resolved Hide resolved
src/Octoshift/Services/GithubApi.cs Outdated Show resolved Hide resolved
src/Octoshift/Services/ReclaimService.cs Outdated Show resolved Hide resolved
RELEASENOTES.md Outdated Show resolved Hide resolved
src/Octoshift/Services/ConfirmationService.cs Outdated Show resolved Hide resolved
src/Octoshift/Services/ReclaimService.cs Show resolved Hide resolved
Comment on lines +125 to +128
catch (Exception ex)
{
throw new OctoshiftCliException($"Failed to lookup the login for current user", ex);
}

Check notice

Code scanning / CodeQL

Generic catch clause

Generic catch clause.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this CodeQL warning, here. What does a failure look like? Would there be a permission error, for example? Keep in mind that GraphQL will return a 200 on failures related to the response, so we'll want to inspect the GraphQL "errors" key. The errors that come back from GitHub should already be sanitized and helpful, so most of the hard stuff is probably already done for you: see if there's an "errors" key, and if so, append the message to your own exception message! 👌

We're using _retryPolicy here, so it should be robust against network failures, but we should still catch errors related to network issues. If you want to quickly functionally test this, you could redefine url to something you know will not work, like https://my-local-broken-network. The _retryPolicy should kick in and exhaust its retries, then raise an exception related to the network failure.

Additionally, another thing we should be careful of is reporting the correct exceptions to the user. With this block, every exception will turn into a generic OctoshiftCliException error. This means that if a user creates a friction issue with us and mentions the "Failed to lookup the login for current user" error, we will have no information about it by design, and it'd be difficult to help them.

It's probably better to handle most expected cases, like permissions errors being raised via GraphQL and some network-related errors, then go ahead and let the edge cases slip through as unhandled exceptions (in this scope). Then we'll get all the weird stuff displayed in the console and in the logs, even if they aren't following the happiest path of exception handling 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@synthead The OctoshiftCliException is set up so that we can pass the exception ("ex") as an inner exception; which the user can view using the --verbose option. :)

This is the pattern used on a few other functions within this class. If we want to get more specific with errors here, should this and other functions be cleaned up as part of a separate PR? 🤷‍♀️

As for "what does a failure" look like here; honestly, I don't think there really will be anything outside of a network error; I set up the catch to be cautious. Since we're just getting the user's login and that is associated with the PAT they are using, I don't think we should run into a permissions issue or anything else particularly funky.

Copy link
Collaborator

@synthead synthead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! I have a few things for you to 👀 at! Gimme a shout if you'd like to pair!

public ConfirmationService()
{
_writeToConsoleOut = msg => Console.WriteLine(msg);
_writeToConsoleOut = (msg, outputColor) =>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we made outputColor default to ConsoleColor.White? That way, we only need to specify a color if we want to use something other than the default (implied ConsoleColor.White).

Something like:

Suggested change
_writeToConsoleOut = (msg, outputColor) =>
_writeToConsoleOut = (msg, outputColor = ConsoleColor.White) =>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be a c# feature (yet): https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/lambda-method-group-defaults#relevant-background

Unless we want to use preview but I don't think it's worth using an unsupported feature.

response = _readConsoleKey();
if (response != ConsoleKey.Enter)
{
_writeToConsoleOut("");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to write a blank line to the output? If so, perhaps we also want to have msg have an optional parameter that defaults to ""?

_writeToConsoleOut = (msg = "", outputColor = ConsoleColor.White) =>

This way, for empty (white) lines, we can simply do:

_writeToConsoleOut();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the other default value comment... I think it would be a great once this is implemented though!

"This doesn't seem to be a c# feature (yet): https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/lambda-method-group-defaults#relevant-background

Unless we want to use preview but I don't think it's worth using an unsupported feature."

Comment on lines +125 to +128
catch (Exception ex)
{
throw new OctoshiftCliException($"Failed to lookup the login for current user", ex);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this CodeQL warning, here. What does a failure look like? Would there be a permission error, for example? Keep in mind that GraphQL will return a 200 on failures related to the response, so we'll want to inspect the GraphQL "errors" key. The errors that come back from GitHub should already be sanitized and helpful, so most of the hard stuff is probably already done for you: see if there's an "errors" key, and if so, append the message to your own exception message! 👌

We're using _retryPolicy here, so it should be robust against network failures, but we should still catch errors related to network issues. If you want to quickly functionally test this, you could redefine url to something you know will not work, like https://my-local-broken-network. The _retryPolicy should kick in and exhaust its retries, then raise an exception related to the network failure.

Additionally, another thing we should be careful of is reporting the correct exceptions to the user. With this block, every exception will turn into a generic OctoshiftCliException error. This means that if a user creates a friction issue with us and mentions the "Failed to lookup the login for current user" error, we will have no information about it by design, and it'd be difficult to help them.

It's probably better to handle most expected cases, like permissions errors being raised via GraphQL and some network-related errors, then go ahead and let the edge cases slip through as unhandled exceptions (in this scope). Then we'll get all the weird stuff displayed in the console and in the logs, even if they aren't following the happiest path of exception handling 👍

src/Octoshift/Services/ReclaimService.cs Outdated Show resolved Hide resolved
Comment on lines +233 to +241
switch (result.Errors[0].Message)
{
case string a when a.Contains("is not an Enterprise Managed Users (EMU) organization"):
_log.LogError("Failed to reclaim mannequins. The --skip-invitation flag is only available to EMU organizations.");
return false; // Indicates we should stop parsing through the CSV
default:
_log.LogWarning($"Failed to reclaim {mannequinUser} ({mannequin.Id}) to {targetUser} ({targetUserId}): {result.Errors[0].Message}");
return true;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way that we can handle this error without parsing human-readable error messages? Does the GraphQL response happen to include a key or something? If so, we should watch for that 👌

If not (and this is difficult to consume as an API user), we should probably file an issue on our end to make this easier to handle 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@synthead At this point, I don't think so.

This is where the error gets raised: https://github.com/github/github/blob/4ad31aba4642a3776068727dd578ca76e61911df/lib/platform/mutations/reattribute_mannequin_to_user.rb#L33

Is there an example of a key somewhere so I can see what you're envisioning?

Copy link
Collaborator

@brianaj brianaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏾 I think if there are any more non-blocking comments should create a new follow-up issue(s) to address feedback.

synthead and others added 3 commits June 26, 2023 13:46
co-authored-by: Hannah Fishback <38845272+hfishback01@users.noreply.github.com>
co-authored-by: Hannah Fishback <38845272+hfishback01@users.noreply.github.com>
co-authored-by: Hannah Fishback <38845272+hfishback01@users.noreply.github.com>
@synthead synthead requested a review from brianaj June 26, 2023 21:25
@github-actions
Copy link

Code Coverage

Package Line Rate Branch Rate Complexity Health
gei 81% 75% 538
ado2gh 84% 82% 617
bbs2gh 79% 76% 665
Octoshift 86% 76% 1208
Summary 83% (6586 / 7900) 77% (1566 / 2036) 3028

@hfishback01 hfishback01 merged commit b87d7b4 into main Jun 26, 2023
@hfishback01 hfishback01 deleted the reclaimation-error-handling branch June 26, 2023 21:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

reclaim-mannequin --skip-invitation option cannot be used in non-interactive environment
6 participants