Skip to content

Commit

Permalink
Merge pull request #108 from apollographql/jake/stdin
Browse files Browse the repository at this point in the history
use stdin as sdl input
  • Loading branch information
JakeDawkins authored Dec 4, 2020
2 parents 036eedd + 631a887 commit e90a8be
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 84 deletions.
54 changes: 11 additions & 43 deletions src/command/graph/push.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use serde::Serialize;
use structopt::StructOpt;
Expand All @@ -8,13 +6,16 @@ use rover_client::query::schema::push;

use crate::client::get_studio_client;
use crate::command::RoverStdout;
use crate::utils::loaders::load_schema_from_flag;
use crate::utils::parsers::{parse_schema_source, SchemaSource};

#[derive(Debug, Serialize, StructOpt)]
pub struct Push {
/// Path of .graphql/.gql schema file to push
#[structopt(name = "SCHEMA_PATH", parse(from_os_str))]
/// The schema file to push
/// Can pass `-` to use stdin instead of a file
#[structopt(long, short = "s", parse(try_from_str = parse_schema_source))]
#[serde(skip_serializing)]
schema_path: PathBuf,
schema: SchemaSource,

/// Name of graph variant in Apollo Studio to push to
#[structopt(long, default_value = "current")]
Expand Down Expand Up @@ -43,8 +44,9 @@ impl Push {
&self.profile_name
);

let schema_document = get_schema_from_file_path(&self.schema_path)
.context("Failed while loading from SDL file")?;
let schema_document = load_schema_from_flag(&self.schema, std::io::stdin())?;

tracing::debug!("Schema Document to push:\n{}", &schema_document);

let push_response = push::run(
push::push_schema_mutation::Variables {
Expand All @@ -54,26 +56,13 @@ impl Push {
},
&client,
)
.context("Failed while pushing to Apollo Studio")?;
.context("Failed while pushing to Apollo Studio. To see a full printout of the schema attempting to push, rerun with `--log debug`")?;

let hash = handle_response(push_response);

Ok(RoverStdout::SchemaHash(hash))
}
}

fn get_schema_from_file_path(path: &PathBuf) -> Result<String> {
if Path::exists(path) {
let contents = std::fs::read_to_string(path)?;
Ok(contents)
} else {
Err(anyhow::anyhow!(
"Invalid path. No file found at {}",
path.display()
))
}
}

/// handle all output logging from operation
fn handle_response(response: push::PushResponse) -> String {
tracing::info!(
Expand All @@ -85,28 +74,7 @@ fn handle_response(response: push::PushResponse) -> String {

#[cfg(test)]
mod tests {
use super::{get_schema_from_file_path, handle_response, push};
use assert_fs::TempDir;
use std::fs::File;
use std::io::Write;

#[test]
fn get_schema_from_file_path_loads() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("schema.graphql");
let mut temp_file = File::create(file_path.clone()).unwrap();
write!(temp_file, "type Query {{ hello: String! }}").unwrap();

let schema = get_schema_from_file_path(&file_path).unwrap();
assert_eq!(schema, "type Query { hello: String! }".to_string());
}

#[test]
fn get_schema_from_file_path_errs_on_bad_path() {
let empty_path = std::path::PathBuf::new().join("wow.graphql");
let schema = get_schema_from_file_path(&empty_path);
assert_eq!(schema.is_err(), true);
}
use super::{handle_response, push};

#[test]
fn handle_response_doesnt_err() {
Expand Down
53 changes: 12 additions & 41 deletions src/command/subgraph/push.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use anyhow::{Context, Result};
use rover_client::query::partial::push::{self, PushPartialSchemaResponse};
use serde::Serialize;
use std::path::{Path, PathBuf};
use structopt::StructOpt;

use crate::client::get_studio_client;
use crate::command::RoverStdout;

use crate::utils::loaders::load_schema_from_flag;
use crate::utils::parsers::{parse_schema_source, SchemaSource};

#[derive(Debug, Serialize, StructOpt)]
pub struct Push {
/// Path of .graphql/.gql schema file to push
#[structopt(name = "SCHEMA_PATH", parse(from_os_str))]
/// The schema file to push
/// Can pass `-` to use stdin instead of a file
#[structopt(long, short = "s", parse(try_from_str = parse_schema_source))]
#[serde(skip_serializing)]
schema_path: PathBuf,
schema: SchemaSource,

/// Name of graph variant in Apollo Studio to push to
#[structopt(long, default_value = "current")]
Expand Down Expand Up @@ -47,8 +50,9 @@ impl Push {
&self.profile_name
);

let schema_document = get_schema_from_file_path(&self.schema_path)
.context("Failed while loading from SDL file")?;
let schema_document = load_schema_from_flag(&self.schema, std::io::stdin())?;

tracing::debug!("Schema Document to push:\n{}", &schema_document);

let push_response = push::run(
push::push_partial_schema_mutation::Variables {
Expand All @@ -64,7 +68,7 @@ impl Push {
},
&client,
)
.context("Failed while pushing to Apollo Studio")?;
.context("Failed while pushing to Apollo Studio. To see a full printout of the schema attempting to push, rerun with `--log debug`")?;

handle_response(push_response, &self.service_name, &self.graph_name);
Ok(RoverStdout::None)
Expand Down Expand Up @@ -103,42 +107,9 @@ fn handle_response(response: PushPartialSchemaResponse, service_name: &str, grap
}
}

fn get_schema_from_file_path(path: &PathBuf) -> Result<String> {
if Path::exists(path) {
let contents = std::fs::read_to_string(path)?;
Ok(contents)
} else {
Err(anyhow::anyhow!(
"Invalid path. No file found at {}",
path.display()
))
}
}

#[cfg(test)]
mod tests {
use super::{get_schema_from_file_path, handle_response, PushPartialSchemaResponse};
use assert_fs::TempDir;
use std::fs::File;
use std::io::Write;

#[test]
fn get_schema_from_file_path_loads() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("schema.graphql");
let mut temp_file = File::create(file_path.clone()).unwrap();
write!(temp_file, "type Query {{ hello: String! }}").unwrap();

let schema = get_schema_from_file_path(&file_path).unwrap();
assert_eq!(schema, "type Query { hello: String! }".to_string());
}

#[test]
fn get_schema_from_file_path_errs_on_bad_path() {
let empty_path = std::path::PathBuf::new().join("wow.graphql");
let schema = get_schema_from_file_path(&empty_path);
assert_eq!(schema.is_err(), true);
}
use super::{handle_response, PushPartialSchemaResponse};

// this test is a bit weird, since we can't test the output. We just verify it
// doesn't error
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub(crate) mod client;
pub mod command;
mod stringify;
mod telemetry;
mod utils;
73 changes: 73 additions & 0 deletions src/utils/loaders.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use crate::utils::parsers::SchemaSource;
use anyhow::{Context, Result};
use std::io::Read;
use std::path::Path;

/// this fn takes 2 args: the first, an enum describing where to look to load
/// a schema - from stdin or a file's PathBuf, and the second, the reference to
/// stdin to load from, should it be needed.
pub fn load_schema_from_flag(loc: &SchemaSource, mut stdin: impl Read) -> Result<String> {
match loc {
SchemaSource::Stdin => {
let mut buffer = String::new();
stdin
.read_to_string(&mut buffer)
.context("Failed while attempting to read SDL from stdin")?;
Ok(buffer)
}
SchemaSource::File(path) => {
if Path::exists(&path) {
let contents = std::fs::read_to_string(path)?;
Ok(contents)
} else {
Err(anyhow::anyhow!(
"Invalid path. No file found at {}",
path.display()
))
}
}
}
}

#[cfg(test)]
mod tests {
use super::{load_schema_from_flag, SchemaSource};
use assert_fs::prelude::*;
use std::path::PathBuf;

#[test]
fn load_schema_from_flag_loads() {
let fixture = assert_fs::TempDir::new().unwrap();

let test_file = fixture.child("schema.graphql");
test_file
.write_str("type Query { hello: String! }")
.unwrap();

let test_path = test_file.path().to_path_buf();
let loc = SchemaSource::File(test_path);

let schema = load_schema_from_flag(&loc, std::io::stdin()).unwrap();
assert_eq!(schema, "type Query { hello: String! }".to_string());
}

#[test]
fn load_schema_from_flag_errs_on_bad_path() {
let empty_path = "./wow.graphql";
let loc = SchemaSource::File(PathBuf::from(empty_path));

let schema = load_schema_from_flag(&loc, std::io::stdin());
assert_eq!(schema.is_err(), true);
}

#[test]
fn load_schema_from_stdin_works() {
// input implements std::io::Read, so it should be a suitable
// replacement for stdin
let input = b"type Query { hello: String! }";
let loc = SchemaSource::Stdin;

let schema = load_schema_from_flag(&loc, &input[..]).unwrap();
assert_eq!(schema, std::str::from_utf8(input).unwrap());
}
}
2 changes: 2 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod loaders;
pub mod parsers;
48 changes: 48 additions & 0 deletions src/utils/parsers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use anyhow::Result;
use std::path::PathBuf;

#[derive(Debug, PartialEq)]
pub enum SchemaSource {
Stdin,
File(PathBuf),
}

pub fn parse_schema_source(loc: &str) -> Result<SchemaSource> {
if loc == "-" {
Ok(SchemaSource::Stdin)
} else if loc.is_empty() {
Err(anyhow::anyhow!(
"The path provided to find a schema is empty"
))
} else {
let path = PathBuf::from(loc);
Ok(SchemaSource::File(path))
}
}

#[cfg(test)]
mod tests {
use super::{parse_schema_source, SchemaSource};

#[test]
fn it_correctly_parses_stdin_flag() {
assert_eq!(parse_schema_source("-").unwrap(), SchemaSource::Stdin);
}

#[test]
fn it_correctly_parses_path_option() {
let loc = parse_schema_source("./schema.graphql").unwrap();
match loc {
SchemaSource::File(buf) => {
assert_eq!(buf.to_str().unwrap(), "./schema.graphql");
}
_ => panic!("parsed incorrectly as stdin"),
}
}

#[test]
fn it_errs_with_empty_path() {
let loc = parse_schema_source("");
assert!(loc.is_err());
}
}

0 comments on commit e90a8be

Please sign in to comment.