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

feat(azure): add username to azure module config #4323

Merged
merged 4 commits into from Nov 27, 2022

Conversation

rjsab
Copy link
Contributor

@rjsab rjsab commented Aug 29, 2022

Description

Allows a user to show the currently logged in account to azure cli by adding $username as an available variable for the Azure Module configuration.

Motivation and Context

Some companies/users work across many Azure tenants or leverage several accounts for separation of environment access, these changes help provide additional visibility to the context of the user you are currently working as.

How Has This Been Tested?

  • I have tested using MacOS
  • I have tested using Linux
  • I have tested using Windows

Checklist:

  • I have updated the documentation accordingly.
  • I have updated the tests accordingly.

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.

Thanks for the PR! Sorry for only reviewing it now. Please fix the issues I described, so we can merge this.

let user_name: Option<UserName> = get_azure_user_name(context);
if user_name.is_none() {
log::info!("Could not find Azure user name");
return None;
Copy link
Member

Choose a reason for hiding this comment

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

Since this module can replace multiple things now, please handle missing value in map and remove the unwrap calls there. Since there seems to quite a bit of duplication, please also fetch the user name together with the subscription name.

Comment on lines 47 to 49
_ => None,
})
.map(|variable| match variable {
Copy link
Member

Choose a reason for hiding this comment

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

Multiple variables are usually handled with a single closure:

Suggested change
_ => None,
})
.map(|variable| match variable {

@@ -194,6 +227,76 @@ mod tests {
dir.close()
}

#[test]
fn user_name_set_correctly() -> io::Result<()> {
Copy link
Member

Choose a reason for hiding this comment

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

Please also add a test with a missing username, but correctly set-up subscription and the reverse.

@rjsab
Copy link
Contributor Author

rjsab commented Oct 1, 2022

@davidkna Thank you so much for the review! I apologies for the delay and making the changes. I've taken your feedback and made changes after reading up on Rust and soliciting feedback from a friend more versed in the language.

@diskmanti
Copy link

Is this going to be merged?

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.

Please only define keys in the struct definitions that are needed for the program and allow the program to continue if either the user or subscription name or missing by making those parts Option<String>.
As I mentioned in the last review, as part of this, please allow the module to work even if either the subscription name or user are missing.

@rjsab
Copy link
Contributor Author

rjsab commented Oct 12, 2022

Please only define keys in the struct definitions that are needed for the program and allow the program to continue if either the user or subscription name or missing by making those parts Option<String>. As I mentioned in the last review, as part of this, please allow the module to work even if either the subscription name or user are missing.

For a bit of clarity, when you are asking to handle the subscription name or user missing, are you asking for me to handle them missing from the JSON structure entirely, or their values being empty?

@davidkna
Copy link
Member

For a bit of clarity, when you are asking to handle the subscription name or user missing, are you asking for me to handle them missing from the JSON structure entirely, or their values being empty?

I was thinking of them missing entirely, but empty values would likely be handled the same way.

@rjsab
Copy link
Contributor Author

rjsab commented Oct 13, 2022

For a bit of clarity, when you are asking to handle the subscription name or user missing, are you asking for me to handle them missing from the JSON structure entirely, or their values being empty?

I was thinking of them missing entirely, but empty values would likely be handled the same way.

I chose to handle the parse failure on missing keys defined in the struct to allow the program to continue, instead of handling the individual keys as options. I think this would be a more appropriate handling of that situation since a missing name or user key would be more indicative of an issue with the azureProfile config file as a whole, barring any major updates from Microsoft to the format of that file; however, if Microsoft were to change the format of the file, it would likely require updates to this module regardless.

@rjsab
Copy link
Contributor Author

rjsab commented Oct 27, 2022

@davidkna - just nudging to see if you had any further recommendations or changes you would like to see. Thanks!

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 two suggestions to clean up your code.

Given the supposed strong schema on the JSON-file, not being more flexible here is acceptable. Nevertheless, I don't really think there is much of a reason not to be more fault-tolerant, given that it wouldn't have much of an impact on complexity.

Comment on lines 101 to 97
fn load_azure_profile(config_path: &PathBuf) -> Option<AzureProfile> {
let json_data = fs::read_to_string(&config_path).expect("Unable to open azureProfile.json");
let sanitized_json_data = json_data.strip_prefix('\u{feff}').unwrap_or(&json_data);
let azure_profile: Option<AzureProfile> =
if let Ok(azure_profile) = serde_json::from_str::<AzureProfile>(sanitized_json_data) {
Some(azure_profile)
} else {
log::info!("Failed to parse azure profile.");
None
};

azure_profile
}
Copy link
Member

Choose a reason for hiding this comment

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

No need to use expect here

Suggested change
fn load_azure_profile(config_path: &PathBuf) -> Option<AzureProfile> {
let json_data = fs::read_to_string(&config_path).expect("Unable to open azureProfile.json");
let sanitized_json_data = json_data.strip_prefix('\u{feff}').unwrap_or(&json_data);
let azure_profile: Option<AzureProfile> =
if let Ok(azure_profile) = serde_json::from_str::<AzureProfile>(sanitized_json_data) {
Some(azure_profile)
} else {
log::info!("Failed to parse azure profile.");
None
};
azure_profile
}
fn load_azure_profile(config_path: &PathBuf) -> Option<AzureProfile> {
let json_data = fs::read_to_string(&config_path).ok()?;
let sanitized_json_data = json_data.strip_prefix('\u{feff}').unwrap_or(&json_data);
if let Ok(azure_profile) = serde_json::from_str::<AzureProfile>(sanitized_json_data) {
Some(azure_profile)
} else {
log::info!("Failed to parse azure profile.");
None
}
}

Comment on lines 81 to 98
if config_path.exists() {
let azure_profile: Option<AzureProfile> = load_azure_profile(&config_path);

if let Some(azure_profile) = azure_profile {
let subscription = azure_profile.subscriptions.iter().find_map(|s| {
if s.is_default {
Some(s.clone())
} else {
None
}
});
subscription
} else {
None
}
});
if subscription_name.is_some() {
subscription_name
} else {
log::info!("Could not find subscription name");
None
}
Copy link
Member

Choose a reason for hiding this comment

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

Instead of checking for file existence, just try to open it:

    let azure_profile = load_azure_profile(&config_path)?;
    azure_profile
        .subscriptions
        .into_iter()
        .find(|s| s.is_default)

@rjsab
Copy link
Contributor Author

rjsab commented Nov 8, 2022

@davidkna thank you for the recommended changes! I've made those changes, but it appears the builds are failing on a new cargo clippy check for needless borrows. I've corrected those for this module, but build is still failing on the git_commit module.

I wanted to thank you again for your time and patience while working with me on this PR.

@rjsab rjsab force-pushed the azure_module_user_name branch 2 times, most recently from 9a45f78 to 51cf2d4 Compare November 15, 2022 14:14
allow program to procede if unable to parse azure profile due to missing
keys from the JSON structure.
remove unused keys from struct

Code cleanup with suggestions from PR maintainer

Cargo clippy fixes
@andytom andytom merged commit 6e15c00 into starship:master Nov 27, 2022
@andytom
Copy link
Member

andytom commented Nov 27, 2022

Thank you for your contribution @rjsab and thank you for reviewing @davidkna.

Indyandie pushed a commit to Indyandie/starship that referenced this pull request Jul 26, 2023
* add username to azure module config

* add username to azure module config

* formatting with cargo fmt

* Handle parse failure on azureProfile.json

allow program to procede if unable to parse azure profile due to missing
keys from the JSON structure.
remove unused keys from struct

Code cleanup with suggestions from PR maintainer

Cargo clippy fixes
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.

None yet

4 participants