Skip to content

Commit 27e2772

Browse files
Revert "chore: refactor rover-client in pursuit of structured output (#557)"
This reverts commit cdd43c1.
1 parent a78c221 commit 27e2772

File tree

150 files changed

+2488
-10221
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+2488
-10221
lines changed

ARCHITECTURE.md

+35-55
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ A minimal command in Rover would be laid out exactly like this:
116116
pub struct MyNewCommand { }
117117

118118
impl MyNewCommand {
119-
pub fn run(&self) -> Result<RoverOutput> {
120-
Ok(RoverOutput::None)
119+
pub fn run(&self) -> Result<RoverStdout> {
120+
Ok(RoverStdout::None)
121121
}
122122
}
123123
```
@@ -128,16 +128,16 @@ For our `graph hello` command, we'll add a new `hello.rs` file under `src/comman
128128
use serde::Serialize;
129129
use structopt::StructOpt;
130130

131-
use crate::command::RoverOutput;
131+
use crate::command::RoverStdout;
132132
use crate::Result;
133133

134134
#[derive(Debug, Serialize, StructOpt)]
135135
pub struct Hello { }
136136

137137
impl Hello {
138-
pub fn run(&self) -> Result<RoverOutput> {
138+
pub fn run(&self) -> Result<RoverStdout> {
139139
eprintln!("Hello, world!");
140-
Ok(RoverOutput::None)
140+
Ok(RoverStdout::None)
141141
}
142142
}
143143
```
@@ -195,7 +195,7 @@ To add these to our new `graph hello` command, we can copy and paste the field f
195195
pub struct Hello {
196196
/// <NAME>@<VARIANT> of graph in Apollo Studio to publish to.
197197
/// @<VARIANT> may be left off, defaulting to @current
198-
#[structopt(name = "GRAPH_REF"))]
198+
#[structopt(name = "GRAPH_REF", parse(try_from_str = parse_graph_ref))]
199199
#[serde(skip_serializing)]
200200
graph: GraphRef
201201

@@ -206,6 +206,12 @@ pub struct Hello {
206206
}
207207
```
208208

209+
We'll have to also add some import statements at the top of our file to support parsing this new argument:
210+
211+
```rust
212+
use crate::utils::parsers::{parse_graph_ref, GraphRef};
213+
```
214+
209215
Now if we run the command again, it will complain if we don't provide a graph ref:
210216

211217
```console
@@ -222,13 +228,13 @@ For more information try --help
222228

223229
##### Setting up a command to work with `rover-client`
224230

225-
Most of Rover's commands make requests to Apollo Studio's API, or to another GraphQL API. Rather than handling the request logic in the repository's main package, Rover is structured so that this logic lives in `crates/rover-client`. This is helpful for separation of concerns and testing.
231+
Most of Rover's commands make requests to Apollo Studio's API. Rather than handling the request logic in the repository's main package, Rover is structured so that this logic lives in `crates/rover-client`. This is helpful for separation of concerns and testing.
226232

227233
To access functionality from `rover-client` in our `rover graph hello` command, we'll need to pass down a client from the entry to our command in `src/command/graph/mod.rs`.
228234

229235
You can do this by changing the `Command::Hello(command) => command.run(),` line to `Command::Hello(command) => command.run(client_config),`.
230236

231-
Then you'll need to change `Hello::run` to accept a `client_config: StudioClientConfig` parameter in `src/command/graph/hello.rs`, and add a `use crate::utils::client::StudioClientConfig` import statement. Then, at the top of the run function, you can create a `StudioClient` by adding `let client = client_config.get_authenticated_client(&self.profile_name)?;`. You can see examples of this in the other commands.
237+
Then you'll need to change `Hello::run` to accept a `client_config: StudioClientConfig` parameter in `src/command/graph/hello.rs`, and add a `use crate::utils::client::StudioClientConfig` import statement. Then, at the top of the run function, you can create a `StudioClient` by adding `let client = client_config.get_client(&self.profile_name)?;`. You can see examples of this in the other commands.
232238

233239
##### Auto-generated help command
234240

@@ -265,19 +271,19 @@ Whenever you create a new command, make sure to add `#[serde(skip_serializing)]`
265271

266272
##### Adding a query to Apollo Studio
267273

268-
The only piece of the `rover-client` crate that we need to be concerned with for now is the `src/operations` directory. This is where all the queries to Apollo Studio live. This directory is roughly organized by the command names as well, but there might be some queries in these directories that are used by multiple commands.
274+
The only piece of the `rover-client` crate that we need to be concerned with for now is the `src/query` directory. This is where all the queries to Apollo Studio live. This directory is roughly organized by the command names as well, but there might be some queries in these directories that are used by multiple commands.
269275

270-
You can see in the `src/operations/graph` directory a number of `.rs` files paired with `.graphql` files. The `.graphql` files are the files where the GraphQL operations live, and the matching `.rs` files contain the logic needed to execute those operations.
276+
You can see in the `src/query/graph` directory a number of `.rs` files paired with `.graphql` files. The `.graphql` files are the files where the GraphQL operations live, and the matching `.rs` files contain the logic needed to execute those operations.
271277

272278
##### Writing a GraphQL operation
273279

274280
For our basic `graph hello` command, we're going to make a request to Apollo Studio that inquires about the existence of a particular graph, and nothing else. For this, we can use the `Query.service` field.
275281

276-
Create a `hello_query.graphql` file in `crates/rover-client/src/operations/graph` and paste the following into it:
282+
Create a `hello.graphql` file in `crates/rover-client/src/query/graph` and paste the following into it:
277283

278284
```graphql
279-
query GraphHello($graph_id: ID!) {
280-
service(id: $graph_id) {
285+
query GraphHello($graphId: ID!) {
286+
service(id: $graphId) {
281287
deletedAt
282288
}
283289
}
@@ -289,34 +295,32 @@ This basic GraphQL operation uses a graph's unique ID (which we get from the `Gr
289295

290296
This project uses [graphql-client](https://docs.rs/graphql_client/latest/graphql_client/) to generate types for each raw `.graphql` query that we write.
291297

292-
First, create an empty directory at `crates/rover-client/src/operations/graph/hello`, and then in that directory, create a `mod.rs` file to initialize the module.
298+
First, create an empty file at `crates/rover-client/src/query/graph/hello.rs`.
293299

294-
To start compiling this file, we need to export the module in `crates/rover-client/src/operations/graph/mod.rs`:
300+
To start compiling this file, we need to export the module in `crates/rover-client/src/query/graph/mod.rs`:
295301

296302
```rust
297303
...
298-
/// "graph hello" command execution
304+
/// "Graph hello" command execution
299305
pub mod hello;
300306
```
301307

302-
Back in our `hello` module, we'll create a `runner.rs`, and add `mod runner` to our `mod.rs` file.
303-
304-
Then, in `runner.rs`, import the following types:
308+
Back in `hello.rs`, we'll import the following types:
305309

306310
```rust
307311
use crate::blocking::StudioClient;
308312
use crate::RoverClientError;
309313
use graphql_client::*;
310314
```
311315

312-
Then, we'll create a new struct that will have auto-generated types for the `hello_query.graphql` file that we created earlier:
316+
Then, we'll create a new struct that will have auto-generated types for the `hello.graphql` file that we created earlier:
313317

314318
```rust
315319
#[derive(GraphQLQuery)]
316320
// The paths are relative to the directory where your `Cargo.toml` is located.
317321
// Both json and the GraphQL schema language are supported as sources for the schema
318322
#[graphql(
319-
query_path = "src/operations/graph/hello/hello_query.graphql",
323+
query_path = "src/query/graph/hello.graphql",
320324
schema_path = ".schema/schema.graphql",
321325
response_derives = "PartialEq, Debug, Serialize, Deserialize",
322326
deprecated = "warn"
@@ -348,7 +352,7 @@ Before we go any further, lets make sure everything is set up properly. We're go
348352
It should look something like this (you should make sure you are following the style of other commands when creating new ones):
349353

350354
```rust
351-
pub fn run(&self, client_config: StudioClientConfig) -> Result<RoverOutput> {
355+
pub fn run(&self, client_config: StudioClientConfig) -> Result<RoverStdout> {
352356
let client = client_config.get_client(&self.profile_name)?;
353357
let graph_ref = self.graph.to_string();
354358
eprintln!(
@@ -362,10 +366,7 @@ pub fn run(&self, client_config: StudioClientConfig) -> Result<RoverOutput> {
362366
},
363367
&client,
364368
)?;
365-
println!("{:?}", deleted_at);
366-
367-
// TODO: Add a new output type!
368-
Ok(RoverOutput::None)
369+
Ok(RoverStdout::PlainText(deleted_at))
369370
}
370371
```
371372

@@ -394,40 +395,19 @@ fn build_response(
394395
}
395396
```
396397

397-
This should get you to the point where you can run `rover graph hello <GRAPH_REF>` and see if and when the last graph was deleted. From here, you should be able to follow the examples of other commands to write out tests for the `build_response` function.
398-
399-
##### Clean up the API
398+
This should get you to the point where you can run `rover graph hello <GRAPH_REF>` and see if and when the last graph was deleted. From here, you should be able to follow the examples of other commands to write out tests for the `build_response` function. This is left as an exercise for the reader.
400399

401-
Unfortunately this is not the cleanest API and doesn't match the pattern set by the rest of the commands. Each `rover-client` operation has an input type and an output type, along with a `run` function that takes in a `reqwest::blocking::Client`.
400+
##### `RoverStdout`
402401

403-
You'll want to define all of the types scoped to this command in `types.rs`, and re-export them from the top level `hello` module, and nothing else.
402+
Now that you can actually execute the `hello::run` query and return its result, you should create a new variant of `RoverStdout` in `src/command/output.rs` that is not `PlainText`. Your new variant should print the descriptor using the `print_descriptor` function, and print the raw content using `print_content`.
404403

405-
##### `RoverOutput`
406-
407-
Now that you can actually execute the `hello::run` query and return its result, you should create a new variant of `RoverOutput` in `src/command/output.rs` that is not `None`. Your new variant should print the descriptor using the `print_descriptor` function, and print the raw content using `print_content`.
408-
409-
To do so, change the line `Ok(RoverOutput::None)` to `Ok(RoverOutput::DeletedAt(deleted_at))`, add a new `DeletedAt(String)` variant to `RoverOutput`, and then match on it in `pub fn print(&self)` and `pub fn get_json(&self)`:
404+
To do so, change the line `Ok(RoverStdout::PlainText(deleted_at))` to `Ok(RoverStdout::DeletedAt(deleted_at))`, add a new `DeletedAt(String)` variant to `RoverStdout`, and then match on it in `pub fn print(&self)`:
410405

411406
```rust
412-
pub fn print(&self) {
413-
match self {
414-
...
415-
RoverOutput::DeletedAt(timestamp) => {
416-
print_descriptor("Deleted At");
417-
print_content(&timestamp);
418-
}
419-
...
420-
}
421-
}
422-
423-
pub fn get_json(&self) -> Value {
424-
match self {
425-
...
426-
RoverOutput::DeletedAt(timestamp) => {
427-
json!({ "deleted_at": timestamp.to_string() })
428-
}
429-
...
430-
}
407+
...
408+
RoverStdout::DeletedAt(timestamp) => {
409+
print_descriptor("Deleted At");
410+
print_content(&timestamp);
431411
}
432412
```
433413

Cargo.lock

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

Cargo.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,13 @@ git-url-parse = "0.3.1"
5353
git2 = { version = "0.13.20", default-features = false, features = ["vendored-openssl"] }
5454
harmonizer = { version = "0.27.0", optional = true }
5555
heck = "0.3.3"
56+
humantime = "2.1.0"
5657
opener = "0.5.0"
5758
os_info = "3.0"
5859
prettytable-rs = "0.8.0"
59-
reqwest = {version = "0.11.4", default-features = false, features = ["blocking"] }
60+
reqwest = {version = "0.11", default-features = false, features = ["blocking", "brotli", "gzip", "json", "native-tls-vendored"]}
61+
regex = "1"
62+
semver = "1"
6063
serde = "1.0"
6164
serde_json = "1.0"
6265
serde_yaml = "0.8"
@@ -72,7 +75,6 @@ url = { version = "2.2.2", features = ["serde"] }
7275
[dev-dependencies]
7376
assert_cmd = "1.0.7"
7477
assert_fs = "1.0.3"
75-
assert-json-diff = "2.0.1"
7678
predicates = "2.0.0"
7779
reqwest = { version = "0.11.4", default-features = false, features = ["blocking", "native-tls-vendored"] }
7880
serial_test = "0.5.0"

0 commit comments

Comments
 (0)