-
Notifications
You must be signed in to change notification settings - Fork 80
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 whoami command #252
add whoami command #252
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/// runner for rover config whoami | ||
pub mod whoami; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
query WhoAmIQuery { | ||
me { | ||
__typename | ||
name | ||
id | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I think it's reasonable to display IDs for debugging, I'll note that we don't actually show the user ID to users on the Studio UI. For first-party users, this is just |
||
asActor { | ||
type | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
use crate::blocking::StudioClient; | ||
use crate::RoverClientError; | ||
use graphql_client::*; | ||
|
||
#[derive(GraphQLQuery)] | ||
// The paths are relative to the directory where your `Cargo.toml` is located. | ||
// Both json and the GraphQL schema language are supported as sources for the schema | ||
#[graphql( | ||
query_path = "src/query/config/whoami.graphql", | ||
schema_path = ".schema/schema.graphql", | ||
response_derives = "PartialEq, Debug, Serialize, Deserialize", | ||
deprecated = "warn" | ||
)] | ||
/// This struct is used to generate the module containing `Variables` and | ||
/// `ResponseData` structs. | ||
/// Snake case of this name is the mod name. i.e. who_am_i_query | ||
pub struct WhoAmIQuery; | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub struct RegistryIdentity { | ||
pub name: String, | ||
pub id: String, | ||
pub key_actor_type: Actor, | ||
} | ||
|
||
#[derive(Debug, PartialEq)] | ||
pub enum Actor { | ||
GRAPH, | ||
USER, | ||
OTHER, | ||
} | ||
|
||
/// Get info from the registry about an API key, i.e. the name/id of the | ||
/// user/graph and what kind of key it is (GRAPH/USER/Other) | ||
pub fn run( | ||
variables: who_am_i_query::Variables, | ||
client: &StudioClient, | ||
) -> Result<RegistryIdentity, RoverClientError> { | ||
let response_data = client.post::<WhoAmIQuery>(variables)?; | ||
get_identity_from_response_data(response_data) | ||
} | ||
|
||
fn get_identity_from_response_data( | ||
response_data: who_am_i_query::ResponseData, | ||
) -> Result<RegistryIdentity, RoverClientError> { | ||
if let Some(me) = response_data.me { | ||
// I believe for the purposes of the CLI, we only care about users and | ||
// graphs as api key actors, since that's all we _should_ get. | ||
// I think it's safe to only include those two kinds of actors in the enum | ||
// more here: https://studio-staging.apollographql.com/graph/engine/schema/reference/enums/ActorType?variant=prod | ||
let key_actor_type = match me.as_actor.type_ { | ||
who_am_i_query::ActorType::GRAPH => Actor::GRAPH, | ||
who_am_i_query::ActorType::USER => Actor::USER, | ||
_ => Actor::OTHER, | ||
}; | ||
Ok(RegistryIdentity { | ||
id: me.id, | ||
name: me.name, | ||
key_actor_type, | ||
}) | ||
} else { | ||
Err(RoverClientError::InvalidKey) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use serde_json::json; | ||
#[test] | ||
fn get_identity_from_response_data_works_for_users() { | ||
let json_response = json!({ | ||
"me": { | ||
"__typename": "User", | ||
"name": "Yaboi", | ||
"id": "gh.nobodydefinitelyhasthisusernamelol", | ||
"asActor": { | ||
"type": "USER" | ||
}, | ||
} | ||
}); | ||
let data: who_am_i_query::ResponseData = serde_json::from_value(json_response).unwrap(); | ||
let output = get_identity_from_response_data(data); | ||
|
||
let expected_identity = RegistryIdentity { | ||
name: "Yaboi".to_string(), | ||
id: "gh.nobodydefinitelyhasthisusernamelol".to_string(), | ||
key_actor_type: Actor::USER, | ||
}; | ||
assert!(output.is_ok()); | ||
assert_eq!(output.unwrap(), expected_identity); | ||
} | ||
|
||
#[test] | ||
fn get_identity_from_response_data_works_for_services() { | ||
let json_response = json!({ | ||
"me": { | ||
"__typename": "Service", | ||
"name": "big-ol-graph", | ||
"id": "big-ol-graph-key-lolol", | ||
"asActor": { | ||
"type": "GRAPH" | ||
}, | ||
} | ||
}); | ||
let data: who_am_i_query::ResponseData = serde_json::from_value(json_response).unwrap(); | ||
let output = get_identity_from_response_data(data); | ||
|
||
let expected_identity = RegistryIdentity { | ||
name: "big-ol-graph".to_string(), | ||
id: "big-ol-graph-key-lolol".to_string(), | ||
key_actor_type: Actor::GRAPH, | ||
}; | ||
assert!(output.is_ok()); | ||
assert_eq!(output.unwrap(), expected_identity); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would not recommend reading this field and displaying it to the user as "name". This isn't well documented (our schema isn't too documented, sorry) but this interface field has two real implementations: Service.name and User.name.
Service.name is actually a deprecated field: the value in it is referred to as "title" these days in our UI and has a non-deprecated Service.title field. (We thought it was confusing to have the name and ID be distinct things — people generally referred to the the ID as the name. So we changed it so the things are "title" and "ID", and often use name to mean the latter. So Rover shouldn't use name to mean the former.)
User.name is literally just User.id without the first few characters (
gh.
etc).I would recommend not querying
Identity.name
or displaying aName:
line, but instead doing a... on Service { title }
and showing that field as "title" for graphs specifically. See next comment for more on the User case.