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

Fix: Update the scaffold template so it works with streams. #1248

Merged
merged 18 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 30 additions & 10 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
default-members = ["apollo-router"]
default-members = ["apollo-router", "apollo-router-scaffold"]
members = [
"apollo-spaceport",
"apollo-router",
Expand Down
9 changes: 9 additions & 0 deletions NEXT_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ By [@bnjjj](https://github.com/bnjjj) in https://github.com/apollographql/router

### Support introspection object types ([PR #1240](https://github.com/apollographql/router/pull/1240))


### Update the scaffold template so it works with streams ([#1247](https://github.com/apollographql/router/issues/1247))

Release v0.9.4 changed the way we deal with Response objects, which can now be streams.
This Pull request updates the scaffold template so it generates plugins that are compatible with the new Plugin API.

By [@o0Ignition0o](https://github.com/o0Ignition0o) in https://github.com/apollographql/router/pull/1248


Introspection queries can use a set of object types defined in the specification. The query parsing code was not recognizing them,
resulting in some introspection queries not working.

Expand Down
5 changes: 3 additions & 2 deletions apollo-router-scaffold/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ license = "Elastic-2.0"
publish = false

[dependencies]
anyhow = "1.0.56"
anyhow = "1.0.57"
clap = { version = "=3.1.18", features = ["derive"] }
cargo-scaffold = { version = "0.8.3", default-features = false }
cargo-scaffold = { version = "0.8.4", default-features = false }
regex = "1"
str_inflector = "0.12.0"
toml = "0.5.8"
[dev-dependencies]
tempfile = "3.3.0"
copy_dir = "0.1.2"
102 changes: 72 additions & 30 deletions apollo-router-scaffold/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,59 +23,77 @@ impl RouterAction {

#[cfg(test)]
mod test {
use anyhow::Result;
use anyhow::{bail, Result};
use cargo_scaffold::{Opts, ScaffoldDescription};
use inflector::Inflector;
use std::collections::BTreeMap;
use std::env;
use std::path::Path;
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process::Command;
use tempfile::TempDir;

#[test]
fn test_scaffold() -> Result<()> {
fn the_next_test_takes_a_while_to_pass_do_not_worry() {}

#[test]
// this test takes a while, I hope the above test name
// let users know they should not worry and wait a bit.
// Hang in there!
fn test_scaffold() {
let temp_dir = tempfile::Builder::new()
.prefix("router_scaffold")
.tempdir()?;
let current_dir = env::current_dir()?;
.tempdir()
.unwrap();

let current_dir = env::current_dir().unwrap();
// Scaffold the main project
let opts = Opts::builder()
.project_name("temp")
.target_dir(temp_dir.path())
.template_path("templates/base")
.template_path(PathBuf::from("templates").join("base"))
.force(true)
.build();
ScaffoldDescription::new(opts)?.scaffold_with_parameters(BTreeMap::from([(
"integration_test".to_string(),
toml::Value::String(
current_dir
.to_str()
.expect("current dir must be convertable to string")
.to_string(),
),
)]))?;
test_build(&temp_dir)?;
ScaffoldDescription::new(opts)
.unwrap()
.scaffold_with_parameters(BTreeMap::from([(
"integration_test".to_string(),
toml::Value::String(
format!(
"{}{}",
current_dir
.parent()
.expect("current dir cannot be the root")
.to_str()
.expect("current dir must be convertable to string"),
// add / or \ depending on windows or unix
MAIN_SEPARATOR,
)
// we need to double \ so they don't get interpreted as escape characters in TOML
.replace('\\', "\\\\"),
),
)]))
.unwrap();
let _ = test_build_with_backup_folder(&temp_dir);

// Scaffold one of each type of plugin
scaffold_plugin(&current_dir, &temp_dir, "basic")?;
scaffold_plugin(&current_dir, &temp_dir, "auth")?;
scaffold_plugin(&current_dir, &temp_dir, "tracing")?;
scaffold_plugin(&current_dir, &temp_dir, "basic").unwrap();
scaffold_plugin(&current_dir, &temp_dir, "auth").unwrap();
scaffold_plugin(&current_dir, &temp_dir, "tracing").unwrap();
std::fs::write(
temp_dir.path().join("src/plugins/mod.rs"),
temp_dir.path().join("src").join("plugins").join("mod.rs"),
"mod auth;\nmod basic;\nmod tracing;\n",
)?;
test_build(&temp_dir)?;
)
.unwrap();

drop(temp_dir);
Ok(())
test_build_with_backup_folder(&temp_dir).unwrap()
}

fn scaffold_plugin(current_dir: &Path, dir: &TempDir, plugin_type: &str) -> Result<()> {
let opts = Opts::builder()
.project_name(plugin_type)
.target_dir(dir.path())
.append(true)
.template_path("templates/plugin")
.template_path(PathBuf::from("templates").join("plugin"))
.build();
ScaffoldDescription::new(opts)?.scaffold_with_parameters(BTreeMap::from([
(
Expand All @@ -97,16 +115,40 @@ mod test {
(
"integration_test".to_string(),
toml::Value::String(
current_dir
.to_str()
.expect("current dir must be convertable to string")
.to_string(),
format!(
"{}{}",
current_dir
.parent()
.expect("current dir cannot be the root")
.to_str()
.expect("current dir must be convertable to string"),
// add / or \ depending on windows or unix
MAIN_SEPARATOR,
)
// we need to double \ so they don't get interpreted as escape characters in TOML
.replace('\\', "\\\\"),
),
),
]))?;
Ok(())
}

fn test_build_with_backup_folder(temp_dir: &TempDir) -> Result<()> {
test_build(temp_dir).map_err(|e| {
let mut output_dir = std::env::temp_dir();
output_dir.push("test_scaffold_output");

// best effort to prepare the output directory
let _ = std::fs::remove_dir_all(&output_dir);
copy_dir::copy_dir(&temp_dir, &output_dir)
.expect("couldn't copy test_scaffold_output directory");
anyhow::anyhow!(
"scaffold test failed: {e}\nYou can find the scaffolded project at '{}'",
output_dir.display()
)
})
}

fn test_build(dir: &TempDir) -> Result<()> {
let output = Command::new("cargo")
.args(["test"])
Expand All @@ -116,7 +158,7 @@ mod test {
eprintln!("failed to build scaffolded project");
eprintln!("{}", String::from_utf8(output.stdout)?);
eprintln!("{}", String::from_utf8(output.stderr)?);
panic!(
bail!(
"build failed with exit code {}",
output.status.code().unwrap_or_default()
);
Expand Down
21 changes: 14 additions & 7 deletions apollo-router-scaffold/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ fn create_plugin(name: &str, template_path: &Option<PathBuf>) -> Result<()> {
"https://github.com/apollographql/router.git",
)))
.git_ref(version)
.repository_template_path("apollo-router-scaffold/templates/plugin")
.repository_template_path(
PathBuf::from("apollo-router-scaffold")
.join("templates")
.join("plugin"),
)
.target_dir(".")
.project_name(name)
.parameter(format!("name={}", name))
Expand Down Expand Up @@ -92,11 +96,12 @@ fn create_plugin(name: &str, template_path: &Option<PathBuf>) -> Result<()> {
Value::Boolean(true),
);

dbg!(&params);
desc.scaffold_with_parameters(params)?;

let mod_path = mod_path();
let mut mod_rs = if mod_path.exists() {
std::fs::read_to_string(mod_path)?
std::fs::read_to_string(&mod_path)?
} else {
"".to_string()
};
Expand Down Expand Up @@ -147,8 +152,8 @@ fn remove_plugin(name: &str) -> Result<()> {

// Remove the mod;
let mod_path = mod_path();
if Path::new(mod_path).exists() {
let mut mod_rs = std::fs::read_to_string(mod_path)?;
if Path::new(&mod_path).exists() {
let mut mod_rs = std::fs::read_to_string(&mod_path)?;
let re = Regex::new(&format!(r"(?m)^mod {};$", snake_name)).unwrap();
mod_rs = re.replace(&mod_rs, "").to_string();

Expand All @@ -162,10 +167,12 @@ fn remove_plugin(name: &str) -> Result<()> {
Ok(())
}

fn mod_path() -> &'static Path {
Path::new("src/plugins/mod.rs")
fn mod_path() -> PathBuf {
PathBuf::from("src").join("plugins").join("mod.rs")
}

fn plugin_path(name: &str) -> PathBuf {
format!("src/plugins/{}.rs", name.to_snake_case()).into()
PathBuf::from("src")
.join("plugins")
.join(format!("{}.rs", name.to_snake_case()))
}
5 changes: 3 additions & 2 deletions apollo-router-scaffold/templates/base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ name = "router"
path = "src/main.rs"

[dependencies]
anyhow = "1.0.55"
anyhow = "1.0.57"
{{#if integration_test}}
apollo-router = {path ="{{integration_test}}/../apollo-router" }
apollo-router = { path ="{{integration_test}}apollo-router" }
{{else}}
{{#if branch}}
apollo-router = { git="https://github.com/apollographql/router.git", branch="{{branch}}" }
Expand All @@ -26,6 +26,7 @@ apollo-router = { git="https://github.com/apollographql/router.git", tag="v0.9.4
{{/if}}
{{/if}}
async-trait = "0.1.52"
futures = "0.3.21"
schemars = "0.8.10"
serde = "1.0.136"
serde_json = "1.0.79"
Expand Down
Loading