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 whoami command #252

Merged
merged 3 commits into from Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/rover-client/src/error.rs
Expand Up @@ -74,4 +74,8 @@ pub enum RoverClientError {
/// The API returned an invalid ChangeSeverity value
#[error("Invalid ChangeSeverity.")]
InvalidSeverity,

/// The registry could not find this key
#[error("The registry did not recognize the provided API key")]
InvalidKey,
}
2 changes: 2 additions & 0 deletions crates/rover-client/src/query/config/mod.rs
@@ -0,0 +1,2 @@
/// runner for rover config whoami
pub mod whoami;
10 changes: 10 additions & 0 deletions crates/rover-client/src/query/config/whoami.graphql
@@ -0,0 +1,10 @@
query WhoAmIQuery {
me {
__typename
name
Copy link
Member

@glasser glasser Feb 9, 2021

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 a Name: 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.

id
Copy link
Member

Choose a reason for hiding this comment

The 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 fp.UUID, and as of recently new GitHub users are also gh.UUID (and for older GitHub users, the ID might not actually match their username if they've changed it on GitHub). So while it's probably reasonable to display the ID, it would be very valuable to also show ... on User { email githubUsername }.

asActor {
type
}
}
}
117 changes: 117 additions & 0 deletions crates/rover-client/src/query/config/whoami.rs
@@ -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);
}
}
3 changes: 3 additions & 0 deletions crates/rover-client/src/query/mod.rs
Expand Up @@ -3,3 +3,6 @@ pub mod graph;

/// all rover-client functionality for the "subgraph" commands in rover
pub mod subgraph;

/// all rover config-related functionality
pub mod config;