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

fix(config): unrecognized config properties don't cause config error #4547

Merged
merged 4 commits into from Nov 20, 2022
Merged

fix(config): unrecognized config properties don't cause config error #4547

merged 4 commits into from Nov 20, 2022

Conversation

brahmlower
Copy link
Contributor

@brahmlower brahmlower commented Oct 30, 2022

Fixes an issue where the config was not being loaded when ignored properties are present. This still prints a warning log indicating a possible misconfiguration.

Description

The deserializer wrapper has been updated such that deserialization of ignored properties does not return an error, and instead returns the visitor.visit_none(). This function now includes a warning log statement since the log statement for reporting the error as shown in the bug ticket is no longer reached. (this described the initial implementation before PR review)

The ValueDeserializer wrapper has been updated so that warnings can be either ignored or cause an Err result. At this time, the only warning that gets emitted is the warning from ignored properties during deserialization. This can be used via the new with_allow_unknown_keys function.

The configurable warning behavior is used within the generic from_config implementation of ModuleConfig, wherein the deserializer wrapper is used to load the config. If it reports an "Unknown key" error, then the config is loaded again and deserialized without reporting warnings. This results in the warning be reported without preventing the otherwise valid config being loaded and returned.

Motivation and Context

Closes #4481

Screenshots (if appropriate):

In this screenshot, I'm showing that as I initialize starship with these changes, we can see I have not set a custom format (the line in the config is commented out), and the unexpected property "go" is detected and a warning is printed. After updating the config to enable the format using sed, the shell format is updated with the new prompt without resolving the unexpected config field.

image

How Has This Been Tested?

  • I have tested using MacOS
  • I have tested using Linux
  • I have tested using Windows
  1. set ~/.config/starship.toml with an unexpected key like the following:
format = 'Hello! $character'

# This should be "golang".
[go]
disabled = true

[shell]
disabled = false
  1. re-initialize starship using the build with eval "$(cargo run init zsh)" (I'm using zsh, but the shell type doesn't matter in this case)
  2. Expect to see the prompt "Hello!" rather than the default shell name (in my case zsh ❯

Checklist:

  • I have updated the documentation accordingly. (n/a)
  • I have updated the tests accordingly.

@brahmlower brahmlower changed the title Fix #4481, config does not error when unrecognized properties are present fix(config) Resolve #4481, unrecognized config properties don't cause config error Oct 30, 2022
@davidkna
Copy link
Member

davidkna commented Oct 30, 2022

I don't think we currently use Either<A, B> or any enums like that, but I did it like that on purpose. For instance, if a config item has multiple variants, and if one of them fails to parse, this could print warnings; even if one of the other variants ends up being successful and doesn't have any extra keys.

@brahmlower
Copy link
Contributor Author

Ah okay, that's good foresight. Unless I've misunderstood though, I believe a scenario using Either<A, B> without my changes in this PR would still result in deserialize_ignored_any returning an Err if B was provided and A was checked first, meaning deserialization would still fail? I'm not sure how to rectify this. As I see it, we have a couple core facts:

  • We shouldn't emit logs during deserialization
  • We can't return warnings without using Err
  • Warnings shouldn't cause deserialization to fail

So it would seem like we can't support the "Unknown key{did_you_mean}" feature without logging during serialization and without causing deserialization to fail.

One thought was we could give ValueDeserializer an extra config such that warnings do cause deserialization failures so that we could log them, and then we could just run it again without warnings as errors. That wouldn't solve the case you brought up though, because it would still potentially cause a warning to be emitted for an Either typed config.

Do you have any preferences or direction for this?

@davidkna
Copy link
Member

Ah okay, that's good foresight. Unless I've misunderstood though, I believe a scenario using Either<A, B> without my changes in this PR would still result in deserialize_ignored_any returning an Err if B was provided and A was checked first, meaning deserialization would still fail? I

If I remember correctly, serde(untagged) works by trying each variant in turn, until the first deserialization succeeds (does not return an error).

One thought was we could give ValueDeserializer an extra config such that warnings do cause deserialization failures so that we could log them, and then we could just run it again without warnings as errors. That wouldn't solve the case you brought up though, because it would still potentially cause a warning to be emitted for an Either typed config.

I guess that would be okay if it's simple to implement.

@brahmlower
Copy link
Contributor Author

brahmlower commented Oct 30, 2022

I guess that would be okay if it's simple to implement

Yeah I def agree on the "if it's simple" part. The existing interface is really nice, and I don't want to undermine that 😅

I don't think I'll have a chance to get back to the computer this this evening, so I won't have any code updates for another 12 hours or so

Edit: oh, I'll also brush up on the serde untagged behavior, because I wasn't aware that's how it handled parse errors 👍

@brahmlower
Copy link
Contributor Author

Alrighty! I've got the deserialization retry behavior implemented, so now we'll only print the warning when intended 👍

@brahmlower
Copy link
Contributor Author

Hey @davidkna, sorry to bother you with this but would you be comfortable adding the "hacktoberfest-accepted" label to this PR today? I don't at all want to rush review of these changes and I definitely intend to see this through to a state you're comfortable with, but this is my 4th and final PR for the event 🙏 Adding the label will give me credit without you having to approve or merge the changes in their current form

@davidkna
Copy link
Member

Sure.

@brahmlower
Copy link
Contributor Author

Awesome, thank you! I realized I still need to update the description to reflect the revised approach we came up with yesterday. I can take care of that this evening 👍

Copy link
Member

@davidkna davidkna left a comment

Choose a reason for hiding this comment

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

I have made two suggestions, but apart from that this looks good to me.

src/serde_utils.rs Outdated Show resolved Hide resolved
}
}

pub fn with_no_ignored_error(self) -> Self {
Copy link
Member

Choose a reason for hiding this comment

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

Please find a better name for this function, the current name sounds a bit like it would make the deserializer not ignore errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I definitely struggled to find a good name for this- iirc I flip flopped between a few names while working on it 😅

How does without_warnings sound?

Copy link
Member

Choose a reason for hiding this comment

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

How about with_allow_ignored_keys(), with_allow_unknown_keys() or with_ignored_noerror()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah yeah these are much better suggestions than mine 😅 Lets go with with_allow_unknown_keys()- I feel like that works best as part of the public interface for the struct whereas the other two lean more heavily on verbiage from the internal implementation 🤔

I'll make these changes and get them pushed in a minute

@brahmlower
Copy link
Contributor Author

Looks like that lint error is due to some clippy changes for rust 1.65.0, since that job is targeting stable

@brahmlower
Copy link
Contributor Author

Hmm, I tried fixing the lint errors but it turned into a bit of a slippery slope that seemed a little out of scope for this PR, so I've just rebased those commits out. 😬 I still have them locally if you'd like me to open a separate PR fixing the lint issues

@andytom
Copy link
Member

andytom commented Nov 5, 2022

Hmm, I tried fixing the lint errors but it turned into a bit of a slippery slope that seemed a little out of scope for this PR, so I've just rebased those commits out. grimacing I still have them locally if you'd like me to open a separate PR fixing the lint issues

I've merged the latest clippy fixes so if you rebase your branch that should (hopefully) fix them.

@brahmlower
Copy link
Contributor Author

Thanks for fixing those lint errors Thomas! With this branch rebased, we're all set for final review 👍

Comment on lines +55 to +57
log::warn!("{}", err);
let deserializer2 = ValueDeserializer::new(config).with_allow_unknown_keys();
T::deserialize(deserializer2)
Copy link
Member

Choose a reason for hiding this comment

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

Didn't you add or edit and existing test? Did it get lost during rebasing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just dug through my reflog to confirm, and it looks like I had only updated the test in serde_utils.rs. I thought the coverage reports showed this code branch was covered by that test change, but maybe I'm misremembering 🤔 I'll do some further testing/experimenting locally in the morning to see what's up

Copy link
Member

Choose a reason for hiding this comment

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

In that case, would you mind adding a test that uses this path?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey! Sorry for the crazy delay here- I caught the flu a couple weeks ago and it ended up wiping me out pretty bad. I'm slowly getting back in the saddle here though 😅 I just wrapped up work today and will get this last test added this evening

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Had to step away for a while while CI was running, but looks like that test has properly covered that block now 👍

@andytom andytom changed the title fix(config) Resolve #4481, unrecognized config properties don't cause config error fix(config): unrecognized config properties don't cause config error Nov 6, 2022
@andytom andytom merged commit 1b03ef2 into starship:master Nov 20, 2022
@andytom
Copy link
Member

andytom commented Nov 20, 2022

Thank you for your contribution @brahmlower and thanks for reviewing @davidkna.

@brahmlower brahmlower deleted the fix-4481-ignore-unrecognized-config-fields branch November 20, 2022 20:58
Indyandie pushed a commit to Indyandie/starship that referenced this pull request Jul 26, 2023
…tarship#4547)

* Fix starship#4481, config does not error when unrecognized properties are present

* cleanup: use stuct update syntax to improve readability

from review feedback

Co-authored-by: David Knaack <davidkna@users.noreply.github.com>

* cleanup: renamed ValueDeserializer func w/ better name

* cleanup: added test to cover unknown key retry condition

Co-authored-by: David Knaack <davidkna@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unrecognized sections in starship.toml prevent top-level format from being recognized
3 participants