Skip to content

Commit db193fe

Browse files
Implement supergraph config schema command (#2418)
This takes Dylan's work from #2139 and makes it work with the latest work in Rover Essentially this allows us to take the work done in `apollo-federation-types` and expose it for others to consume in other IDEs etc.
1 parent 484d54f commit db193fe

File tree

10 files changed

+378
-149
lines changed

10 files changed

+378
-149
lines changed

Cargo.lock

+221-113
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+11-8
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ apollo-parser = "0.8"
6969
apollo-encoder = "0.8"
7070

7171
# https://github.com/apollographql/federation-rs
72-
apollo-federation-types = "0.15.2"
72+
apollo-federation-types = { version = "0.15.2", features = ["json_schema"] }
7373

7474
apollo-language-server = { version = "0.4.0", default-features = false, features = ["tokio"] }
7575

@@ -86,7 +86,7 @@ base64 = "0.22"
8686
billboard = "0.2"
8787
buildstructor = "0.6.0"
8888
bytes = "1.8.0"
89-
cargo_metadata = "0.19"
89+
cargo_metadata = "0.18"
9090
calm_io = "0.1"
9191
camino = { version = "1", features = ["serde1"] }
9292
clap = "4"
@@ -100,7 +100,7 @@ directories-next = "2.0"
100100
flate2 = "1"
101101
futures = "0.3"
102102
git-url-parse = "0.4.5"
103-
git2 = { version = "0.20", default-features = false }
103+
git2 = { version = "0.19", default-features = false }
104104
graphql_client = "0.14"
105105
heck = "0.5"
106106
humantime = "2.1.0"
@@ -110,7 +110,7 @@ http-body-util = "0.1.2"
110110
httpmock = "0.7"
111111
hyper = "1.0"
112112
indoc = "2"
113-
itertools = "0.14.0"
113+
itertools = "0.13.0"
114114
lazycell = "1"
115115
lazy_static = "1.4"
116116
notify = { version = "8" }
@@ -122,6 +122,7 @@ pretty_assertions = "1"
122122
regex = "1"
123123
reqwest = { version = "0.12", default-features = false }
124124
rstest = "0.24.0"
125+
schemars = "0.8.21"
125126
semver = "1"
126127
serial_test = "3"
127128
serde = "1.0"
@@ -132,8 +133,8 @@ shell-candy = "0.4"
132133
speculoos = "0.11.0"
133134
strip-ansi-escapes = "0.2"
134135
strsim = "0.11"
135-
strum = "0.27"
136-
strum_macros = "0.27"
136+
strum = "0.26"
137+
strum_macros = "0.26"
137138
sha2 = "0.10"
138139
shellexpand = "3.1"
139140
termcolor = "1.3"
@@ -197,6 +198,7 @@ rover-graphql = { workspace = true }
197198
rover-http = { workspace = true }
198199
rover-std = { workspace = true }
199200
rover-studio = { workspace = true }
201+
schemars = { workspace = true }
200202
semver = { workspace = true }
201203
serde = { workspace = true }
202204
serde_json = { workspace = true }
@@ -233,12 +235,13 @@ git2 = { workspace = true, features = ["https"] }
233235
graphql-schema-diff = "=0.2.0"
234236
httpmock = { workspace = true }
235237
indoc = { workspace = true }
238+
jsonschema = "0.29.0"
236239
mime = "=0.3.17"
237240
mockall = "=0.13.1"
238241
portpicker = "=0.1.1"
239242
predicates = { workspace = true }
240-
rand = "=0.9.0"
241-
rand_regex = "=0.18.0"
243+
rand = "=0.8.5"
244+
rand_regex = "=0.17.0"
242245
reqwest = { workspace = true, features = ["native-tls-vendored"] }
243246
rstest = { workspace = true }
244247
serial_test = { workspace = true }

docs/source/commands/supergraphs.mdx

+20
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,23 @@ We recommend updating to the latest version of Rover as soon as possible. If you
229229
|---|---|
230230
|<= v0.2.x|<= v0.38.x|
231231
|>= v0.3.x|>= v0.39.x|
232+
233+
## Configuration awareness in your text editor
234+
235+
### `supergraph config schema`
236+
237+
You can use Rover to generate a JSON schema for config validation in your text editor. This schema helps you format the YAML file correctly and also provides content assist.
238+
239+
Generate the schema with the following command:
240+
241+
```bash
242+
rover supergraph config schema
243+
```
244+
245+
After you generate the schema, configure your text editor. Here are the instructions for some commonly used editors:
246+
247+
- [Visual Studio Code](https://code.visualstudio.com/docs/languages/json#_json-schemas-and-settings)
248+
- [Emacs](https://emacs-lsp.github.io/lsp-mode/page/lsp-yaml)
249+
- [IntelliJ](https://www.jetbrains.com/help/idea/json.html#ws_json_using_schemas)
250+
- [Sublime](https://github.com/sublimelsp/LSP-yaml)
251+
- [Vim](https://github.com/Quramy/vison)

src/command/output.rs

+20-28
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
use std::{
2-
collections::BTreeMap,
3-
fmt::Write,
4-
io::{self, IsTerminal},
5-
};
1+
use std::collections::BTreeMap;
2+
use std::fmt::Write;
3+
use std::io::{self, IsTerminal};
64

75
use calm_io::{stderr, stderrln};
86
use camino::Utf8PathBuf;
97
use comfy_table::Attribute::Bold;
108
use comfy_table::Cell;
119
use comfy_table::CellAlignment::Center;
12-
use serde_json::{json, Value};
13-
use termimad::{crossterm::style::Attribute::Underlined, MadSkin};
14-
1510
use rover_client::operations::contract::describe::ContractDescribeResponse;
1611
use rover_client::operations::contract::publish::ContractPublishResponse;
1712
use rover_client::operations::graph::publish::GraphPublishResponse;
@@ -25,11 +20,13 @@ use rover_client::shared::{
2520
};
2621
use rover_client::RoverClientError;
2722
use rover_std::Style;
23+
use serde_json::{json, Value};
24+
use termimad::crossterm::style::Attribute::Underlined;
25+
use termimad::MadSkin;
2826

2927
use crate::command::supergraph::compose::CompositionOutput;
3028
use crate::command::template::queries::list_templates_for_language::ListTemplatesForLanguageTemplates;
31-
use crate::options::JsonVersion;
32-
use crate::options::ProjectLanguage;
29+
use crate::options::{JsonVersion, ProjectLanguage};
3330
use crate::utils::table;
3431
use crate::RoverError;
3532

@@ -56,6 +53,7 @@ pub enum RoverOutput {
5653
DocsList(BTreeMap<&'static str, &'static str>),
5754
FetchResponse(FetchResponse),
5855
SupergraphSchema(String),
56+
JsonSchema(String),
5957
CompositionResult(CompositionOutput),
6058
SubgraphList(SubgraphListResponse),
6159
CheckWorkflowResponse(CheckWorkflowResponse),
@@ -284,6 +282,7 @@ impl RoverOutput {
284282
}
285283
}
286284
RoverOutput::SupergraphSchema(csdl) => Some((csdl).to_string()),
285+
RoverOutput::JsonSchema(schema) => Some(schema.clone()),
287286
RoverOutput::CompositionResult(composition_output) => {
288287
let warn_prefix = Style::HintPrefix.paint("HINT:");
289288

@@ -498,6 +497,7 @@ impl RoverOutput {
498497
}
499498
RoverOutput::FetchResponse(fetch_response) => json!(fetch_response),
500499
RoverOutput::SupergraphSchema(csdl) => json!({ "core_schema": csdl }),
500+
RoverOutput::JsonSchema(schema) => Value::String(schema.clone()),
501501
RoverOutput::CompositionResult(composition_output) => {
502502
if let Some(federation_version) = &composition_output.federation_version {
503503
json!({
@@ -681,28 +681,20 @@ mod tests {
681681
use apollo_federation_types::rover::{BuildError, BuildErrors};
682682
use assert_json_diff::assert_json_eq;
683683
use chrono::{DateTime, Local, Utc};
684-
685684
use console::strip_ansi_codes;
686-
use rover_client::{
687-
operations::{
688-
graph::publish::{ChangeSummary, FieldChanges, TypeChanges},
689-
persisted_queries::publish::PersistedQueriesOperationCounts,
690-
subgraph::{
691-
delete::SubgraphDeleteResponse,
692-
list::{SubgraphInfo, SubgraphUpdatedAt},
693-
},
694-
},
695-
shared::{
696-
ChangeSeverity, CheckTaskStatus, CheckWorkflowResponse, CustomCheckResponse,
697-
Diagnostic, LintCheckResponse, OperationCheckResponse, ProposalsCheckResponse,
698-
ProposalsCheckSeverityLevel, ProposalsCoverage, RelatedProposal, SchemaChange, Sdl,
699-
SdlType, Violation,
700-
},
685+
use rover_client::operations::graph::publish::{ChangeSummary, FieldChanges, TypeChanges};
686+
use rover_client::operations::persisted_queries::publish::PersistedQueriesOperationCounts;
687+
use rover_client::operations::subgraph::delete::SubgraphDeleteResponse;
688+
use rover_client::operations::subgraph::list::{SubgraphInfo, SubgraphUpdatedAt};
689+
use rover_client::shared::{
690+
ChangeSeverity, CheckTaskStatus, CheckWorkflowResponse, CustomCheckResponse, Diagnostic,
691+
LintCheckResponse, OperationCheckResponse, ProposalsCheckResponse,
692+
ProposalsCheckSeverityLevel, ProposalsCoverage, RelatedProposal, SchemaChange, Sdl,
693+
SdlType, Violation,
701694
};
702695

703-
use crate::options::JsonOutput;
704-
705696
use super::*;
697+
use crate::options::JsonOutput;
706698

707699
#[test]
708700
fn docs_list_json() {

src/command/supergraph/config/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
mod schema;
2+
3+
use clap::Parser;
4+
use serde::Serialize;
5+
6+
use crate::{RoverOutput, RoverResult};
7+
8+
#[derive(Debug, Serialize, Parser)]
9+
pub struct Config {
10+
#[clap(subcommand)]
11+
command: Command,
12+
}
13+
14+
#[derive(Debug, Serialize, Parser)]
15+
pub enum Command {
16+
/// Print the Schema associated with the `supergraph.yaml` file for use in editors
17+
Schema(schema::Schema),
18+
}
19+
20+
impl Config {
21+
pub fn run(&self) -> RoverResult<RoverOutput> {
22+
match &self.command {
23+
Command::Schema(command) => command.run(),
24+
}
25+
}
26+
}
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use apollo_federation_types::config::SupergraphConfig;
2+
use clap::Parser;
3+
use schemars::schema_for;
4+
use serde::Serialize;
5+
6+
use crate::{RoverOutput, RoverResult};
7+
8+
#[derive(Debug, Serialize, Parser)]
9+
pub struct Schema {}
10+
11+
impl Schema {
12+
pub fn run(&self) -> RoverResult<RoverOutput> {
13+
let schema = schema_for!(SupergraphConfig);
14+
Ok(RoverOutput::JsonSchema(
15+
serde_json::to_string_pretty(&schema).unwrap(),
16+
))
17+
}
18+
}

src/command/supergraph/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::utils::client::StudioClientConfig;
66
use crate::{RoverOutput, RoverResult};
77

88
pub(crate) mod compose;
9+
mod config;
910
mod fetch;
1011

1112
#[derive(Debug, Serialize, Parser)]
@@ -19,6 +20,9 @@ pub enum Command {
1920
/// Locally compose supergraph SDL from a set of subgraph schemas
2021
Compose(compose::Compose),
2122

23+
/// Supergraph Config Schema commands
24+
Config(config::Config),
25+
2226
/// Fetch supergraph SDL from the graph registry
2327
Fetch(fetch::Fetch),
2428
}
@@ -37,6 +41,7 @@ impl Supergraph {
3741
.run(override_install_path, client_config, output_file)
3842
.await
3943
}
44+
Command::Config(command) => command.run(),
4045
}
4146
}
4247
}

tests/e2e/supergraph/config.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::process::Command;
2+
3+
use assert_cmd::cargo::CommandCargoExt;
4+
use rstest::rstest;
5+
use tracing::error;
6+
use tracing_test::traced_test;
7+
8+
#[rstest]
9+
#[ignore]
10+
#[tokio::test(flavor = "multi_thread")]
11+
#[traced_test]
12+
async fn e2e_test_rover_supergraph_config_schema() {
13+
let mut cmd = Command::cargo_bin("rover").expect("Could not find necessary binary");
14+
cmd.args(["supergraph", "config", "schema"]);
15+
16+
let output = cmd.output().expect("Could not run command");
17+
if !output.status.success() {
18+
error!("{}", String::from_utf8(output.stderr).unwrap());
19+
panic!("Command did not complete successfully");
20+
}
21+
22+
let output = String::from_utf8(output.stdout).unwrap();
23+
let json_schema = serde_json::from_str(&output).unwrap();
24+
if !jsonschema::meta::is_valid(&json_schema) {
25+
error!("{}", output);
26+
panic!("Could not validate JSON Schema, incorrect schema printed above");
27+
}
28+
}

tests/e2e/supergraph/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
mod compose;
2+
mod config;
23
mod fetch;
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::process::Command;
2+
3+
use assert_cmd::cargo::CommandCargoExt;
4+
use rstest::rstest;
5+
use tracing::error;
6+
use tracing_test::traced_test;
7+
8+
#[rstest]
9+
#[ignore]
10+
#[tokio::test(flavor = "multi_thread")]
11+
#[traced_test]
12+
async fn e2e_test_rover_supergraph_print_json_schema() {
13+
let mut cmd = Command::cargo_bin("rover").expect("Could not find necessary binary");
14+
cmd.args(["supergraph", "print-json-schema"]);
15+
16+
let output = cmd.output().expect("Could not run command");
17+
if !output.status.success() {
18+
error!("{}", String::from_utf8(output.stderr).unwrap());
19+
panic!("Command did not complete successfully");
20+
}
21+
22+
let output = String::from_utf8(output.stdout).unwrap();
23+
let json_schema = serde_json::from_str(&output).unwrap();
24+
if !jsonschema::meta::is_valid(&json_schema) {
25+
error!("{}", output);
26+
panic!("Could not validate JSON Schema, incorrect schema printed above");
27+
}
28+
}

0 commit comments

Comments
 (0)