Skip to content

Commit

Permalink
feat: adds rover docs open and rover docs list (#314)
Browse files Browse the repository at this point in the history
  • Loading branch information
EverlastingBugstopper authored Mar 1, 2021
1 parent 8e382dd commit c6a1f5e
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 10 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ git2 = "0.13.17"
git-url-parse = "0.3.1"
heck = "0.3.2"
humantime = "2.1.0"
opener = "0.4.1"
os_info = "3.0"
prettytable-rs = "0.8.0"
serde = "1.0"
serde_json = "1.0"
structopt = "0.3.21"
tracing = "0.1.22"
regex = "1"
url = "2.2.0"
os_info = "3.0"

[dev-dependencies]
assert_cmd = "1.0.1"
assert_fs = "1.0.0"
reqwest = "0.11.1"
rustversion = "1.0.4"
serial_test = "0.5.0"
predicates = "1.0.5"
Expand Down
14 changes: 12 additions & 2 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ use std::path::PathBuf;
#[derive(Debug, Serialize, StructOpt)]
#[structopt(name = "Rover", global_settings = &[structopt::clap::AppSettings::ColoredHelp], about = "
Rover - Your Graph Companion
Read the getting started guide: https://go.apollo.dev/r/start
Read the getting started guide by running:
$ rover docs open start
To begin working with Rover and to authenticate with Apollo Studio,
run the following command:
Expand All @@ -33,7 +35,9 @@ The most common commands from there are:
- rover graph check: Check for breaking changes in a local graph schema against a graph schema in the Apollo graph registry
- rover graph push: Push an updated graph schema to the Apollo graph registry
You can find full documentation for Rover here: https://go.apollo.dev/r/docs
You can open the full documentation for Rover by running:
$ rover docs open
")]
pub struct Rover {
#[structopt(subcommand)]
Expand Down Expand Up @@ -90,9 +94,14 @@ pub enum Command {
/// Federated schema/graph commands
Subgraph(command::Subgraph),

/// Interact with Rover's documentation
Docs(command::Docs),

/// Installs Rover
#[structopt(setting(structopt::clap::AppSettings::Hidden))]
Install(command::Install),

/// Get system information
#[structopt(setting(structopt::clap::AppSettings::Hidden))]
Info(command::Info),
}
Expand All @@ -103,6 +112,7 @@ impl Rover {
Command::Config(command) => {
command.run(self.get_rover_config()?, self.get_client_config()?)
}
Command::Docs(command) => command.run(),
Command::Graph(command) => {
command.run(self.get_client_config()?, self.get_git_context()?)
}
Expand Down
2 changes: 1 addition & 1 deletion src/command/config/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{anyhow, Result};
/// Running without the --profile flag will set an API key for
/// a profile named "default".
///
/// See https://go.apollo.dev/r/api-keys for more details on Apollo's API keys.
/// Run `rover docs open api-keys` for more details on Apollo's API keys.
pub struct Auth {
#[structopt(long = "profile", default_value = "default")]
#[serde(skip_serializing)]
Expand Down
17 changes: 17 additions & 0 deletions src/command/docs/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::{command::RoverStdout, Result};

use super::shortlinks;

use serde::Serialize;
use structopt::StructOpt;

#[derive(Debug, Serialize, StructOpt)]
pub struct List {}

impl List {
pub fn run(&self) -> Result<RoverStdout> {
Ok(RoverStdout::DocsList(
shortlinks::get_shortlinks_with_description(),
))
}
}
32 changes: 32 additions & 0 deletions src/command/docs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
mod list;
mod open;
pub mod shortlinks;

use serde::Serialize;
use structopt::StructOpt;

use crate::{command::RoverStdout, Result};

#[derive(Debug, Serialize, StructOpt)]
pub struct Docs {
#[structopt(subcommand)]
command: Command,
}

#[derive(Debug, Serialize, StructOpt)]
pub enum Command {
/// List all available docs links
List(list::List),

/// Open a docs link
Open(open::Open),
}

impl Docs {
pub fn run(&self) -> Result<RoverStdout> {
match &self.command {
Command::List(command) => command.run(),
Command::Open(command) => command.run(),
}
}
}
45 changes: 45 additions & 0 deletions src/command/docs/open.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::{anyhow, command::RoverStdout, Result};

use super::shortlinks;

use ansi_term::Colour::{Cyan, Yellow};
use serde::Serialize;
use structopt::StructOpt;

use std::process::Command;

#[derive(Debug, Serialize, StructOpt)]
pub struct Open {
#[structopt(name = "slug", default_value = "docs", possible_values = &shortlinks::possible_shortlinks())]
slug: String,
}

impl Open {
pub fn run(&self) -> Result<RoverStdout> {
let url = shortlinks::get_url_from_slug(&self.slug);
let yellow_browser_var = format!("{}", Yellow.normal().paint("$BROWSER"));
let cyan_url = format!("{}", Cyan.normal().paint(&url));

if let Some(browser_override) = std::env::var_os("BROWSER") {
eprintln!(
"Opening {} with the application specified by {}.",
&cyan_url, &yellow_browser_var
);
if let Err(e) = Command::new(&browser_override).arg(&url).status() {
Err(anyhow!(
"Couldn't open docs with {}: {}",
browser_override.to_string_lossy(),
e
))
} else {
Ok(())
}
} else {
eprintln!("Opening {} with your default browser. This can be overridden by setting the {} environment variable.", &cyan_url, &yellow_browser_var);
opener::open(&url)?;
Ok(())
}?;

Ok(RoverStdout::None)
}
}
50 changes: 50 additions & 0 deletions src/command/docs/shortlinks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
pub const URL_BASE: &str = "https://go.apollo.dev/r";

use std::collections::HashMap;

pub fn get_shortlinks_with_description() -> HashMap<&'static str, &'static str> {
let mut links = HashMap::new();
links.insert("docs", "Rover's Documentation Homepage");
links.insert("api-keys", "Understanding Apollo's API Keys");
links.insert("contributing", "Contributing to Rover");
links.insert("start", "Getting Started with Rover");
links
}

pub fn possible_shortlinks() -> Vec<&'static str> {
let mut res = Vec::new();
for (slug, _) in get_shortlinks_with_description() {
res.push(slug);
}
res
}

pub fn get_url_from_slug(slug: &str) -> String {
format!("{}/{}", URL_BASE, slug)
}

mod tests {
#[test]
fn can_make_shortlink_vec_from_map() {
let shortlinks = super::possible_shortlinks();
assert!(!shortlinks.is_empty())
}

#[test]
fn can_get_url_from_slug() {
let expected_link = "https://go.apollo.dev/r/start";
let actual_link = super::get_url_from_slug("start");
assert_eq!(expected_link, actual_link);
}

#[test]
fn each_url_is_valid() {
for link in super::possible_shortlinks() {
let url = super::get_url_from_slug(link);
assert!(reqwest::blocking::get(&url)
.unwrap()
.error_for_status()
.is_ok());
}
}
}
2 changes: 2 additions & 0 deletions src/command/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod config;
mod docs;
mod graph;
mod info;
mod install;
mod output;
mod subgraph;

pub use config::Config;
pub use docs::Docs;
pub use graph::Graph;
pub use info::Info;
pub use install::Install;
Expand Down
15 changes: 15 additions & 0 deletions src/command/output.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::collections::HashMap;
use std::fmt::Debug;

use ansi_term::Colour::Yellow;
use prettytable::{cell, row, Table};
use rover_client::query::subgraph::list::ListDetails;

Expand All @@ -13,6 +15,7 @@ use rover_client::query::subgraph::list::ListDetails;
/// return something that is not described well in this enum, it should be added.
#[derive(Clone, PartialEq, Debug)]
pub enum RoverStdout {
DocsList(HashMap<&'static str, &'static str>),
SDL(String),
SchemaHash(String),
SubgraphList(ListDetails),
Expand All @@ -23,6 +26,18 @@ pub enum RoverStdout {
impl RoverStdout {
pub fn print(&self) {
match self {
RoverStdout::DocsList(shortlinks) => {
eprintln!(
"You can open any of these documentation pages by running {}.\n",
Yellow.normal().paint("`rover docs open <slug>`")
);
let mut table = Table::new();
table.add_row(row!["Slug", "Description"]);
for (shortlink_slug, shortlink_description) in shortlinks {
table.add_row(row![shortlink_slug, shortlink_description]);
}
println!("{}", table);
}
RoverStdout::SDL(sdl) => {
eprintln!("SDL:");
println!("{}", &sdl);
Expand Down
12 changes: 6 additions & 6 deletions src/error/metadata/suggestion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ impl Display for Suggestion {
Suggestion::RerunWithSensitive => {
format!(
"Try re-running this command with the {} flag",
Yellow.normal().paint("'--sensitive'")
Yellow.normal().paint("`--sensitive`")
)
}
Suggestion::SetConfigHome => {
format!(
"You can override this path by setting the {} environment variable.",
Yellow.normal().paint(RoverEnvKey::ConfigHome.to_string())
Yellow.normal().paint(&format!("${}", RoverEnvKey::ConfigHome))
)
}
Suggestion::MigrateConfigHomeOrCreateConfig => {
format!("If you've recently changed the {} environment variable, you may need to migrate your old configuration directory to the new path. Otherwise, try setting up a new configuration profile by running {}.",
Yellow.normal().paint(RoverEnvKey::ConfigHome.to_string()),
Yellow.normal().paint(&format!("${}", RoverEnvKey::ConfigHome)),
Yellow.normal().paint("`rover config auth`"))
}
Suggestion::CreateConfig => {
Expand All @@ -56,7 +56,7 @@ impl Display for Suggestion {
format!(
"Try running {} to see the possible values for the {} argument.",
Yellow.normal().paint("`rover config list`"),
Yellow.normal().paint("'--profile'")
Yellow.normal().paint("`--profile`")
)
}
Suggestion::UseFederatedGraph => {
Expand All @@ -82,11 +82,11 @@ impl Display for Suggestion {
"Check your API key to make sure it's valid (are you using the right profile?).".to_string()
}
Suggestion::ProperKey => {
format!("Visit {} for more details on Apollo's API keys.", Cyan.normal().paint("https://go.apollo.dev/r/api-keys"))
format!("Try running {} for more details on Apollo's API keys.", Yellow.normal().paint("`rover docs open api-keys`"))
}
Suggestion::NewUserNoProfiles => {
format!("It looks like you may be new here (we couldn't find any existing config profiles). To authenticate with Apollo Studio, run {}",
Cyan.normal().paint("rover config auth")
Yellow.normal().paint("`rover config auth`")
)
}
Suggestion::Adhoc(msg) => msg.to_string()
Expand Down

0 comments on commit c6a1f5e

Please sign in to comment.