diff --git a/CHANGELOG.md b/CHANGELOG.md index 95f3e5e1e..3904404fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,16 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm [pull/484]: https://github.com/apollographql/rover/pull/484 [issue/169]: https://github.com/apollographql/rover/issues/169 +- **`rover explain` command added - [JakeDawkins], [pull/457]** + + When encountering most errors in Rover, there will be an error code in the format + `E###` printed along with the error description. Running `rover explain CODE` + will now print a more detailed description of the error along with any + resolution steps and relevant docs links. + + [JakeDawkins]: https://github.com/JakeDawkins + [pull/457]: https://github.com/apollographql/rover/pull/457 + - **Better error messages for HTTP errors - [EverlastingBugstopper], [issue/489] [pull/518]** Previously, Rover obfuscated the information about HTTP errors that occurred. Now, if something goes wrong between your machine and any HTTP server, you'll get some more information about what exactly went wrong. diff --git a/Cargo.lock b/Cargo.lock index f0819dc2c..6717d263d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,6 +362,64 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +[[package]] +name = "crossbeam" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd01a6eb3daaafa260f6fc94c3a6c36390abc2080e38e3e34ced87393fb77d80" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.3" @@ -373,6 +431,31 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossterm" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c36c10130df424b2f3552fcc2ddcd9b28a27b1e54b358b45874f88d1ca6888c" +dependencies = [ + "bitflags", + "crossterm_winapi", + "lazy_static", + "libc", + "mio", + "parking_lot", + "signal-hook", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da8964ace4d3e4a044fd027919b2237000b24315a37c916f61809f1ff2140b9" +dependencies = [ + "winapi", +] + [[package]] name = "csv" version = "1.1.6" @@ -1184,12 +1267,30 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +[[package]] +name = "memoffset" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "minimad" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f608f20e91ebfa44263b3b5eee1f6cea8e67a8dfd0ad037a5b56f1f3fa071dd" +dependencies = [ + "lazy_static", +] + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -1760,6 +1861,7 @@ dependencies = [ "camino", "chrono", "console 0.14.1", + "crossterm", "git-url-parse", "git2", "harmonizer", @@ -1784,6 +1886,9 @@ dependencies = [ "sputnik", "strsim 0.10.0", "structopt", + "strum", + "strum_macros", + "termimad", "timber", "toml", "tracing", @@ -2033,6 +2138,26 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signal-hook" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729" +dependencies = [ + "libc", + "mio", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + [[package]] name = "simple-error" version = "0.2.3" @@ -2202,6 +2327,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termimad" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d26fdb7dae513c61d25496c42fc586511419e41696ce019ef4cb672e6f70e8f" +dependencies = [ + "crossbeam", + "crossterm", + "lazy_static", + "minimad", + "thiserror", + "unicode-width", +] + [[package]] name = "terminal_size" version = "0.1.16" diff --git a/Cargo.toml b/Cargo.toml index 2256b25a7..d6bfc96a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,10 @@ structopt = "0.3.21" toml = "0.5" tracing = "0.1.26" url = "2.2.0" +termimad = "0.10.1" +crossterm = "0.19.0" +strum = "0.20.0" +strum_macros = "0.20.1" [dev-dependencies] assert_cmd = "1.0.1" diff --git a/build.rs b/build.rs index b47bbda3c..167fabb9d 100644 --- a/build.rs +++ b/build.rs @@ -24,6 +24,9 @@ fn main() -> Result<()> { cargo_warn("updating npm package."); prep_npm(is_release_build)?; + cargo_warn("updating error reference docs"); + build_error_code_reference()?; + cargo_warn("exiting build.rs"); Ok(()) @@ -266,3 +269,57 @@ fn process_command_output(output: &Output) -> Result<()> { Ok(()) } } + +fn build_error_code_reference() -> Result<()> { + let docs_path = Utf8PathBuf::from("./docs/source/errors.md"); + let codes_dir = Utf8PathBuf::from("./src/error/metadata/codes"); + let codes = fs::read_dir(codes_dir)?; + + let mut all_descriptions = String::new(); + + // filter out Errs and non-file entries in the `/codes` dir + let code_files = codes + .into_iter() + .filter_map(Result::ok) + .filter(|e| !e.file_type().unwrap().is_dir()); + + // sort the list of files alphabetically + let mut code_files: Vec<_> = code_files.collect(); + code_files.sort_by_key(|f| f.path()); + + // for each code description, get the name of the code from the filename, + // and add it as a header. Then push the header and description to the + // all_descriptions string + for code in code_files { + let path = code.path(); + + let contents = fs::read_to_string(&path)?; + let code_name = path + .file_name() + .unwrap() + .to_string_lossy() + .replace(".md", ""); + + let description = format!("### {}\n\n{}\n\n", code_name, contents); + + all_descriptions.push_str(&description); + } + + let docs_content = fs::read_to_string(&docs_path)?; + + // build up a new docs page with existing content line-by-line + // and then concat the loaded code descriptions after + let mut new_content = String::new(); + for line in docs_content.lines() { + new_content.push_str(line); + new_content.push('\n'); + if line.contains("") { + break; + } + } + new_content.push_str(&all_descriptions); + + fs::write(&docs_path, new_content)?; + + Ok(()) +} diff --git a/docs/gatsby-config.js b/docs/gatsby-config.js index a4e9574d7..864404b52 100644 --- a/docs/gatsby-config.js +++ b/docs/gatsby-config.js @@ -25,6 +25,7 @@ module.exports = { ], 'Base Commands': ['graphs'], 'Federation Commands': ['subgraphs', 'supergraphs'], + Reference: ['errors'], }, }, }, diff --git a/docs/source/errors.md b/docs/source/errors.md new file mode 100644 index 000000000..706363955 --- /dev/null +++ b/docs/source/errors.md @@ -0,0 +1,229 @@ +--- +title: "Index of Errors" +sidebar_title: "Index of Errors" +--- + +Rover has a number of predefined error codes that you may run into. You can see descriptions and potential solutions directly in Rover by running `rover explain `. + +This page acts as an index of all of these codes and their descriptions for quick reference. + +## Codes + + + +### E001 + +This error occurs when the expected JSON response from a GraphQL endpoint can't be deserialized. + +This is most likely caused by an invalid endpoint or headers, causing the server to return something that is not JSON (like an HTML error page). + +Try running the command again with `--log trace` to see what the GraphQL endpoint is responding with. + +If this error occurs on a command interacting with the Apollo Registry, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E001%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! + +### E002 + +This error occurs when trying to build headers for requests, and a header name is invalid. + +Examples of an invalid header name include header names with included spaces and non-ascii characters in the name. + +To resolve, check your headings for any unusual characters. + +If this error occurs on a command where you aren't providing headers, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E002%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! + +### E003 + +This error occurs when trying to build headers for requests, and a header's value is invalid. + +To resolve, check your headings for any unusual characters. + +If this error occurs on a command where you aren't providing headers, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E003%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! + +### E004 + +This error can occur in a number of places. It indicates an error occurring when actually executing a request. + +This error commonly occurs when the server can't be reached, or network connection is lost. + +To debug, use the `--log trace` flag to expose more detailed logs of the specific error that's being encountered. + +### E005 + +This error is unexpected behavior, and likely the result of a programming mistake made in the graph registry. + + +This error shouldn't be reachable under normal circumstances, but if it does occur, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E005%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. + +### E006 + +This error is unexpected behavior, and likely the result of a programming mistake made in the graph registry. + +This error shouldn't be reachable under normal circumstances, but if it does occur, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E006%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. + +### E007 + +This error occurs when using a `subgraph` command on a non-federated graph. + +Either the graph you're trying to run this operation on isn't federated or the specified variant isn't. Double check the specified `graph@variant` combination is valid and federated. + +### E008 + +This error occurs when an invalid variant is specified for a command. + +Double check your spelling or open the graph in [Apollo Studio](https://studio.apollographql.com) to verify that the variant you're trying to use is valid. + +If you didn't pass a variant in the format `graph@variant`, then the default variant, `current` is used. If you encounter this error without providing a variant, it likely means the `current` variant does not exist. + +### E009 + +This error occurs when working with federated graphs and the subgraph `--name` provided doesn't exist as a valid subgraph. + +To find a list of subgraphs already published to a graph, open the graph in [Apollo Studio](https://studio.apollographql.com) or run `rover subgraph list @`. + +### E010 + +This error can occur because of graph lookup issues or authentication failures. + +Graphs you don't have permission to will always error as unavailable for security purposes. Check your API keys with `rover config whoami` and make sure your graph IDs are properly spelled. + +If applicable, check with your graph admin to make sure permissions and keys haven't changed. + + +### E011 + +This error occurs when an introspection response from a GraphQL endpoint can't be parsed properly. + +Verify your endpoint is correct, and use `--log trace` to make sure the response from the server is the expected JSON response. If you're still seeing this error with the correct introspection response from the server, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E012%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! + + +### E012 + +This error occurs when an endpoint returns an HTTP status between 400-599. + +These errors are most common with a misuse of an endpoint. If you are running `introspection` commands or fetching from an endpoint for composition, it's likely you misused headers or specified the wrong url. + +Check your urls, headers, and if needed, run the command again with `--log trace` to see specific details about the request/response. + +### E013 + +This error occurs when an API key isn't recognized by the graph registry. Your key may have been disabled, changed, or saved improperly. + +Try running `rover config whoami` to debug API key issues. + +Check the length of the key shown in the response of this command and make sure it's what you expect. Sometimes double-pasting the key when running `auth` can happen. + +### E014 + +This occurs when an API key is not in the format expected. + +Registry API keys are in one of the following formats: + +`user:my-username:secretkey` +`service:graph-id:secretkey` + +If you're getting this error, it's because the key couldn't be parsed properly based on these formats. Run `rover config whoami` to make sure your key looks like you expect it to. + +The middle of the key is masked for security, but you should be able to see the `user` or `serv` at the beginning of the key, and the last few characters of the key, along with its length. + +### E015 + +This error occurs when Rover's update checking fails because of release versions not being in the correct format. + +If you encounter this issue, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E016%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! + +### E016 + +This error occurs when trying to setup a configuration profile, and Rover is unable to create the directory to store this information in. + +This is usually a permissions issue. If your system's default configuration directory is inaccessible, you can use the `APOLLO_CONFIG_HOME` environment variable to choose a different directory. See Rover's [configuring docs](https://go.apollo.dev/r/configuring) for more info. + + +### E017 + +This error occurs when trying to setup a configuration profile, and Rover is unable to determine your system's defauly configuration directory. + +You can use the `APOLLO_CONFIG_HOME` environment variable to tell Rover where to save and find configuration info. See Rover's [configuring docs](https://go.apollo.dev/r/configuring) for more info. + + +### E018 + +This error occurs when using the `APOLLO_CONFIG_HOME` environment variable improperly. + +This variable should reference a directory to store configuration info in, but the current value is likely pointing to a file rather than a directory. + +Check your `APOLLO_CONFIG_HOME` variable and the intended destination. + +### E019 + +This error occurs when trying to clear all of Rover's local config, but none is found. + +This may be the result of running the `rover config clear` command multiple times, or an update to your `APOLLO_CONFIG_HOME` variable. + +See Rover's [configuration docs](https://go.apollo.dev/r/configuring) for more on how to manage Rover's configuration. + +### E020 + +This error occurs when trying to run a command that needs to use a configuration profile or an API key, but none are found. + +This is likely because you haven't set up a configuration profile yet or your `APOLLO_KEY` has been removed. + +Run `apollo config auth` to set up a new configuration profile or check out Rover's [configuration docs](https://go.apollo.dev/r/configuring) for more on how to set up and use Rover. + +### E021 + +This error occurs when trying to use a configuration profile that can't be found. + +This is most likely the result of a typo when running a command with the `--profile` option or saving a new profile. + +Run `apollo config list` to see a full list of available configuration profiles or `apollo config auth` to set up a new one. + +Check out Rover's [configuration docs](https://go.apollo.dev/r/configuring) for more on how to set up and use Rover. + +### E022 + +This error occurs when trying to load the contents of a configuration profile, and there is nothing available to load that isn't sensitive. + +This likely occured because configuration profiles were cleared. Try running `rover config auth` and setting up a new configuration profile. + + +### E023 + +This error occurs when trying to save or load a configuration profile using a file path that is not valid UTF-8. + +This is likely due to an invalid path in your `APOLLO_CONFIG_HOME` environment variable. + +Check your environment variable or use `--log trace` for more information about the path that Rover is trying to use. + +### E024 + +This error occurs when Rover tries to load a configuration profile that has been modified with invalid TOML. + +If you modified a configuration file by hand, double check to make sure your formatting is appropriate. + +If you did not intentionally modify a configuration profile, you may need to delete the profile and re-create it with `rover config delete --profile ` and `rover config auth --profile `. + +If this error persists, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E025%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. + +### E025 + +This error occurs when trying to save a configuration profile, and Rover can't serialize it appropriately to TOML. + +If this error occurs, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E026%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. + +### E026 + +This error occurs when Rover runs into an issue loading or saving a configuration profile. + +This may happen as a result of a typo in a profile name, or a profile name being incorrect. + +Double check your command usage, and list available profiles with `rover config list`. + +If this error persists, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E027%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. + +### E027 + +This error occurs when working with a federated graph and its subgraphs. When graphs can't be composed due to errors, no final supergraph schema can be built. + +To resolve this error, inspect the printed errors and correct the subgraph schemas. + + diff --git a/installers/npm/package-lock.json b/installers/npm/package-lock.json index 515ab8573..92759a651 100644 --- a/installers/npm/package-lock.json +++ b/installers/npm/package-lock.json @@ -106,9 +106,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.0.tgz", - "integrity": "sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", "funding": [ { "type": "individual", @@ -141,9 +141,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -235,9 +235,9 @@ } }, "node_modules/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -371,9 +371,9 @@ } }, "follow-redirects": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.0.tgz", - "integrity": "sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg==" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" }, "fs-minipass": { "version": "2.1.0", @@ -389,9 +389,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -459,9 +459,9 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz", + "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==", "dev": true }, "rimraf": { diff --git a/src/cli.rs b/src/cli.rs index 42e98acc8..6f761362f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -120,6 +120,9 @@ pub enum Command { /// Get system information #[structopt(setting(structopt::clap::AppSettings::Hidden))] Info(command::Info), + + /// Explain error codes + Explain(command::Explain), } impl Rover { @@ -146,6 +149,7 @@ impl Rover { Command::Update(command) => command.run(self.get_rover_config()?), Command::Install(command) => command.run(self.get_install_override_path()?), Command::Info(command) => command.run(), + Command::Explain(command) => command.run(), } } } diff --git a/src/command/explain.rs b/src/command/explain.rs new file mode 100644 index 000000000..4c2d3a5ad --- /dev/null +++ b/src/command/explain.rs @@ -0,0 +1,19 @@ +use crate::command::RoverStdout; +use crate::error::metadata::code::Code; +use crate::Result; +use serde::Serialize; +use structopt::StructOpt; + +#[derive(Debug, Serialize, StructOpt)] +pub struct Explain { + /// The full error code. For example, E020 + #[structopt(name = "CODE")] + code: Code, +} + +impl Explain { + pub fn run(&self) -> Result { + let explanation = &self.code.explain(); + Ok(RoverStdout::Markdown(explanation.clone())) + } +} diff --git a/src/command/mod.rs b/src/command/mod.rs index 68476358c..dfc4d344b 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,5 +1,6 @@ mod config; mod docs; +mod explain; mod graph; mod info; mod install; @@ -10,6 +11,7 @@ mod update; pub use config::Config; pub use docs::Docs; +pub use explain::Explain; pub use graph::Graph; pub use info::Info; pub use install::Install; diff --git a/src/command/output.rs b/src/command/output.rs index b1d7aba49..e4b8112dc 100644 --- a/src/command/output.rs +++ b/src/command/output.rs @@ -1,11 +1,12 @@ use std::fmt::Debug; use std::{collections::HashMap, fmt::Display}; +use crate::utils::table::{self, cell, row}; use ansi_term::Colour::Yellow; use atty::Stream; +use crossterm::style::Attribute::Underlined; use rover_client::query::subgraph::list::ListDetails; - -use crate::utils::table::{self, cell, row}; +use termimad::MadSkin; /// RoverStdout defines all of the different types of data that are printed /// to `stdout`. Every one of Rover's commands should return `anyhow::Result` @@ -26,6 +27,8 @@ pub enum RoverStdout { VariantList(Vec), Profiles(Vec), Introspection(String), + Markdown(String), + PlainText(String), None, } @@ -115,6 +118,16 @@ impl RoverStdout { print_descriptor("Introspection Response"); print_content(&introspection_response); } + RoverStdout::Markdown(markdown_string) => { + // underline bolded md + let mut skin = MadSkin::default(); + skin.bold.add_attr(Underlined); + + println!("{}", skin.inline(&markdown_string)); + } + RoverStdout::PlainText(text) => { + println!("{}", text); + } RoverStdout::None => (), } } diff --git a/src/error/metadata/code.rs b/src/error/metadata/code.rs index 2547e294d..07e09efb7 100644 --- a/src/error/metadata/code.rs +++ b/src/error/metadata/code.rs @@ -1,11 +1,93 @@ +use serde::Serialize; +use std::collections::HashMap; use std::fmt::{self, Display}; +use strum_macros::EnumString; /// `Code` contains the error codes associated with specific errors. -#[derive(Debug)] -pub enum Code {} +#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, EnumString)] +pub enum Code { + E001, + E002, + E003, + E004, + E005, + E006, + E007, + E008, + E009, + E010, + E011, + E012, + E013, + E014, + E015, + E016, + E017, + E018, + E019, + E020, + E021, + E022, + E023, + E024, + E025, + E026, + E027, + E028, +} impl Display for Code { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "{:?}", &self) } } + +impl Code { + // builds a Map of every possible code and its explanation, so we can + // access from the `explain` function + fn explanations() -> HashMap { + let contents = vec![ + (Code::E001, include_str!("./codes/E001.md").to_string()), + (Code::E002, include_str!("./codes/E002.md").to_string()), + (Code::E003, include_str!("./codes/E003.md").to_string()), + (Code::E004, include_str!("./codes/E004.md").to_string()), + (Code::E005, include_str!("./codes/E005.md").to_string()), + (Code::E006, include_str!("./codes/E006.md").to_string()), + (Code::E007, include_str!("./codes/E007.md").to_string()), + (Code::E008, include_str!("./codes/E008.md").to_string()), + (Code::E009, include_str!("./codes/E009.md").to_string()), + (Code::E010, include_str!("./codes/E010.md").to_string()), + (Code::E011, include_str!("./codes/E011.md").to_string()), + (Code::E012, include_str!("./codes/E012.md").to_string()), + (Code::E013, include_str!("./codes/E013.md").to_string()), + (Code::E014, include_str!("./codes/E014.md").to_string()), + (Code::E015, include_str!("./codes/E015.md").to_string()), + (Code::E016, include_str!("./codes/E016.md").to_string()), + (Code::E017, include_str!("./codes/E017.md").to_string()), + (Code::E018, include_str!("./codes/E018.md").to_string()), + (Code::E019, include_str!("./codes/E019.md").to_string()), + (Code::E020, include_str!("./codes/E020.md").to_string()), + (Code::E021, include_str!("./codes/E021.md").to_string()), + (Code::E022, include_str!("./codes/E022.md").to_string()), + (Code::E023, include_str!("./codes/E023.md").to_string()), + (Code::E024, include_str!("./codes/E024.md").to_string()), + (Code::E025, include_str!("./codes/E025.md").to_string()), + (Code::E026, include_str!("./codes/E026.md").to_string()), + (Code::E027, include_str!("./codes/E027.md").to_string()), + (Code::E028, include_str!("./codes/E028.md").to_string()), + ]; + contents.into_iter().collect() + } + + /// For a given error code, returns a markdown string with a given error's + /// explanation. Explanations are in ./codes + pub fn explain(&self) -> String { + let all_explanations = Code::explanations(); + let explanation = all_explanations.get(self); + if let Some(expl) = explanation { + format!("**{}**\n\n{}\n\n", self.to_string(), expl.clone()) + } else { + "Explanation not available".to_string() + } + } +} diff --git a/src/error/metadata/codes/E001.md b/src/error/metadata/codes/E001.md new file mode 100644 index 000000000..28edab491 --- /dev/null +++ b/src/error/metadata/codes/E001.md @@ -0,0 +1,7 @@ +This error occurs when the expected JSON response from a GraphQL endpoint can't be deserialized. + +This is most likely caused by an invalid endpoint or headers, causing the server to return something that is not JSON (like an HTML error page). + +Try running the command again with `--log trace` to see what the GraphQL endpoint is responding with. + +If this error occurs on a command interacting with the Apollo Registry, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E001%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! \ No newline at end of file diff --git a/src/error/metadata/codes/E002.md b/src/error/metadata/codes/E002.md new file mode 100644 index 000000000..b402e92d5 --- /dev/null +++ b/src/error/metadata/codes/E002.md @@ -0,0 +1,7 @@ +This error occurs when trying to build headers for requests, and a header name is invalid. + +Examples of an invalid header name include header names with included spaces and non-ascii characters in the name. + +To resolve, check your headings for any unusual characters. + +If this error occurs on a command where you aren't providing headers, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E002%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! \ No newline at end of file diff --git a/src/error/metadata/codes/E003.md b/src/error/metadata/codes/E003.md new file mode 100644 index 000000000..691fe442e --- /dev/null +++ b/src/error/metadata/codes/E003.md @@ -0,0 +1,5 @@ +This error occurs when trying to build headers for requests, and a header's value is invalid. + +To resolve, check your headings for any unusual characters. + +If this error occurs on a command where you aren't providing headers, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E003%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! \ No newline at end of file diff --git a/src/error/metadata/codes/E004.md b/src/error/metadata/codes/E004.md new file mode 100644 index 000000000..5ca19ce52 --- /dev/null +++ b/src/error/metadata/codes/E004.md @@ -0,0 +1,5 @@ +This error can occur in a number of places. It indicates an error occurring when actually executing a request. + +This error commonly occurs when the server can't be reached, or network connection is lost. + +To debug, use the `--log trace` flag to expose more detailed logs of the specific error that's being encountered. \ No newline at end of file diff --git a/src/error/metadata/codes/E005.md b/src/error/metadata/codes/E005.md new file mode 100644 index 000000000..4d356cafd --- /dev/null +++ b/src/error/metadata/codes/E005.md @@ -0,0 +1,4 @@ +This error is unexpected behavior, and likely the result of a programming mistake made in the graph registry. + + +This error shouldn't be reachable under normal circumstances, but if it does occur, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E005%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. \ No newline at end of file diff --git a/src/error/metadata/codes/E006.md b/src/error/metadata/codes/E006.md new file mode 100644 index 000000000..20ba57a52 --- /dev/null +++ b/src/error/metadata/codes/E006.md @@ -0,0 +1,3 @@ +This error is unexpected behavior, and likely the result of a programming mistake made in the graph registry. + +This error shouldn't be reachable under normal circumstances, but if it does occur, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E006%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. \ No newline at end of file diff --git a/src/error/metadata/codes/E007.md b/src/error/metadata/codes/E007.md new file mode 100644 index 000000000..74912127f --- /dev/null +++ b/src/error/metadata/codes/E007.md @@ -0,0 +1,3 @@ +This error occurs when using a `subgraph` command on a non-federated graph. + +Either the graph you're trying to run this operation on isn't federated or the specified variant isn't. Double check the specified `graph@variant` combination is valid and federated. \ No newline at end of file diff --git a/src/error/metadata/codes/E008.md b/src/error/metadata/codes/E008.md new file mode 100644 index 000000000..27ee399b9 --- /dev/null +++ b/src/error/metadata/codes/E008.md @@ -0,0 +1,5 @@ +This error occurs when an invalid variant is specified for a command. + +Double check your spelling or open the graph in [Apollo Studio](https://studio.apollographql.com) to verify that the variant you're trying to use is valid. + +If you didn't pass a variant in the format `graph@variant`, then the default variant, `current` is used. If you encounter this error without providing a variant, it likely means the `current` variant does not exist. \ No newline at end of file diff --git a/src/error/metadata/codes/E009.md b/src/error/metadata/codes/E009.md new file mode 100644 index 000000000..16711631e --- /dev/null +++ b/src/error/metadata/codes/E009.md @@ -0,0 +1,3 @@ +This error occurs when working with federated graphs and the subgraph `--name` provided doesn't exist as a valid subgraph. + +To find a list of subgraphs already published to a graph, open the graph in [Apollo Studio](https://studio.apollographql.com) or run `rover subgraph list @`. \ No newline at end of file diff --git a/src/error/metadata/codes/E010.md b/src/error/metadata/codes/E010.md new file mode 100644 index 000000000..fe351a628 --- /dev/null +++ b/src/error/metadata/codes/E010.md @@ -0,0 +1,5 @@ +This error can occur because of graph lookup issues or authentication failures. + +Graphs you don't have permission to will always error as unavailable for security purposes. Check your API keys with `rover config whoami` and make sure your graph IDs are properly spelled. + +If applicable, check with your graph admin to make sure permissions and keys haven't changed. diff --git a/src/error/metadata/codes/E011.md b/src/error/metadata/codes/E011.md new file mode 100644 index 000000000..e291a02f5 --- /dev/null +++ b/src/error/metadata/codes/E011.md @@ -0,0 +1,3 @@ +This error occurs when an introspection response from a GraphQL endpoint can't be parsed properly. + +Verify your endpoint is correct, and use `--log trace` to make sure the response from the server is the expected JSON response. If you're still seeing this error with the correct introspection response from the server, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E012%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! diff --git a/src/error/metadata/codes/E012.md b/src/error/metadata/codes/E012.md new file mode 100644 index 000000000..e06fe63b4 --- /dev/null +++ b/src/error/metadata/codes/E012.md @@ -0,0 +1,5 @@ +This error occurs when an endpoint returns an HTTP status between 400-599. + +These errors are most common with a misuse of an endpoint. If you are running `introspection` commands or fetching from an endpoint for composition, it's likely you misused headers or specified the wrong url. + +Check your urls, headers, and if needed, run the command again with `--log trace` to see specific details about the request/response. \ No newline at end of file diff --git a/src/error/metadata/codes/E013.md b/src/error/metadata/codes/E013.md new file mode 100644 index 000000000..ba460d7a8 --- /dev/null +++ b/src/error/metadata/codes/E013.md @@ -0,0 +1,5 @@ +This error occurs when an API key isn't recognized by the graph registry. Your key may have been disabled, changed, or saved improperly. + +Try running `rover config whoami` to debug API key issues. + +Check the length of the key shown in the response of this command and make sure it's what you expect. Sometimes double-pasting the key when running `auth` can happen. \ No newline at end of file diff --git a/src/error/metadata/codes/E014.md b/src/error/metadata/codes/E014.md new file mode 100644 index 000000000..2ea21c970 --- /dev/null +++ b/src/error/metadata/codes/E014.md @@ -0,0 +1,10 @@ +This occurs when an API key is not in the format expected. + +Registry API keys are in one of the following formats: + +`user:my-username:secretkey` +`service:graph-id:secretkey` + +If you're getting this error, it's because the key couldn't be parsed properly based on these formats. Run `rover config whoami` to make sure your key looks like you expect it to. + +The middle of the key is masked for security, but you should be able to see the `user` or `serv` at the beginning of the key, and the last few characters of the key, along with its length. \ No newline at end of file diff --git a/src/error/metadata/codes/E015.md b/src/error/metadata/codes/E015.md new file mode 100644 index 000000000..b429acf39 --- /dev/null +++ b/src/error/metadata/codes/E015.md @@ -0,0 +1,3 @@ +This error occurs when Rover's update checking fails because of release versions not being in the correct format. + +If you encounter this issue, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E016%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know! \ No newline at end of file diff --git a/src/error/metadata/codes/E016.md b/src/error/metadata/codes/E016.md new file mode 100644 index 000000000..50c23b16b --- /dev/null +++ b/src/error/metadata/codes/E016.md @@ -0,0 +1,3 @@ +This error occurs when trying to setup a configuration profile, and Rover is unable to create the directory to store this information in. + +This is usually a permissions issue. If your system's default configuration directory is inaccessible, you can use the `APOLLO_CONFIG_HOME` environment variable to choose a different directory. See Rover's [configuring docs](https://go.apollo.dev/r/configuring) for more info. diff --git a/src/error/metadata/codes/E017.md b/src/error/metadata/codes/E017.md new file mode 100644 index 000000000..82d721f76 --- /dev/null +++ b/src/error/metadata/codes/E017.md @@ -0,0 +1,3 @@ +This error occurs when trying to setup a configuration profile, and Rover is unable to determine your system's defauly configuration directory. + +You can use the `APOLLO_CONFIG_HOME` environment variable to tell Rover where to save and find configuration info. See Rover's [configuring docs](https://go.apollo.dev/r/configuring) for more info. diff --git a/src/error/metadata/codes/E018.md b/src/error/metadata/codes/E018.md new file mode 100644 index 000000000..0cc9af937 --- /dev/null +++ b/src/error/metadata/codes/E018.md @@ -0,0 +1,5 @@ +This error occurs when using the `APOLLO_CONFIG_HOME` environment variable improperly. + +This variable should reference a directory to store configuration info in, but the current value is likely pointing to a file rather than a directory. + +Check your `APOLLO_CONFIG_HOME` variable and the intended destination. \ No newline at end of file diff --git a/src/error/metadata/codes/E019.md b/src/error/metadata/codes/E019.md new file mode 100644 index 000000000..94c8a4183 --- /dev/null +++ b/src/error/metadata/codes/E019.md @@ -0,0 +1,5 @@ +This error occurs when trying to clear all of Rover's local config, but none is found. + +This may be the result of running the `rover config clear` command multiple times, or an update to your `APOLLO_CONFIG_HOME` variable. + +See Rover's [configuration docs](https://go.apollo.dev/r/configuring) for more on how to manage Rover's configuration. \ No newline at end of file diff --git a/src/error/metadata/codes/E020.md b/src/error/metadata/codes/E020.md new file mode 100644 index 000000000..aa8d4aee5 --- /dev/null +++ b/src/error/metadata/codes/E020.md @@ -0,0 +1,5 @@ +This error occurs when trying to run a command that needs to use a configuration profile or an API key, but none are found. + +This is likely because you haven't set up a configuration profile yet or your `APOLLO_KEY` has been removed. + +Run `apollo config auth` to set up a new configuration profile or check out Rover's [configuration docs](https://go.apollo.dev/r/configuring) for more on how to set up and use Rover. \ No newline at end of file diff --git a/src/error/metadata/codes/E021.md b/src/error/metadata/codes/E021.md new file mode 100644 index 000000000..cce0aeaed --- /dev/null +++ b/src/error/metadata/codes/E021.md @@ -0,0 +1,7 @@ +This error occurs when trying to use a configuration profile that can't be found. + +This is most likely the result of a typo when running a command with the `--profile` option or saving a new profile. + +Run `apollo config list` to see a full list of available configuration profiles or `apollo config auth` to set up a new one. + +Check out Rover's [configuration docs](https://go.apollo.dev/r/configuring) for more on how to set up and use Rover. \ No newline at end of file diff --git a/src/error/metadata/codes/E022.md b/src/error/metadata/codes/E022.md new file mode 100644 index 000000000..d048924c7 --- /dev/null +++ b/src/error/metadata/codes/E022.md @@ -0,0 +1,3 @@ +This error occurs when trying to load the contents of a configuration profile, and there is nothing available to load that isn't sensitive. + +This likely occured because configuration profiles were cleared. Try running `rover config auth` and setting up a new configuration profile. diff --git a/src/error/metadata/codes/E023.md b/src/error/metadata/codes/E023.md new file mode 100644 index 000000000..c97b6552f --- /dev/null +++ b/src/error/metadata/codes/E023.md @@ -0,0 +1,5 @@ +This error occurs when trying to save or load a configuration profile using a file path that is not valid UTF-8. + +This is likely due to an invalid path in your `APOLLO_CONFIG_HOME` environment variable. + +Check your environment variable or use `--log trace` for more information about the path that Rover is trying to use. \ No newline at end of file diff --git a/src/error/metadata/codes/E024.md b/src/error/metadata/codes/E024.md new file mode 100644 index 000000000..47a80c6ca --- /dev/null +++ b/src/error/metadata/codes/E024.md @@ -0,0 +1,7 @@ +This error occurs when Rover tries to load a configuration profile that has been modified with invalid TOML. + +If you modified a configuration file by hand, double check to make sure your formatting is appropriate. + +If you did not intentionally modify a configuration profile, you may need to delete the profile and re-create it with `rover config delete --profile ` and `rover config auth --profile `. + +If this error persists, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E025%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. \ No newline at end of file diff --git a/src/error/metadata/codes/E025.md b/src/error/metadata/codes/E025.md new file mode 100644 index 000000000..df5835560 --- /dev/null +++ b/src/error/metadata/codes/E025.md @@ -0,0 +1,3 @@ +This error occurs when trying to save a configuration profile, and Rover can't serialize it appropriately to TOML. + +If this error occurs, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E026%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. \ No newline at end of file diff --git a/src/error/metadata/codes/E026.md b/src/error/metadata/codes/E026.md new file mode 100644 index 000000000..2beac7c9f --- /dev/null +++ b/src/error/metadata/codes/E026.md @@ -0,0 +1,7 @@ +This error occurs when Rover runs into an issue loading or saving a configuration profile. + +This may happen as a result of a typo in a profile name, or a profile name being incorrect. + +Double check your command usage, and list available profiles with `rover config list`. + +If this error persists, please [open an issue](https://github.com/apollographql/rover/issues/new?body=Error%20E027%0A%0ADescribe%20your%20issue%20or%20question%20here&labels=triage) and let us know. \ No newline at end of file diff --git a/src/error/metadata/codes/E027.md b/src/error/metadata/codes/E027.md new file mode 100644 index 000000000..46d4c00a8 --- /dev/null +++ b/src/error/metadata/codes/E027.md @@ -0,0 +1,3 @@ +This error occurs when working with a federated graph and its subgraphs. When graphs can't be composed due to errors, no final supergraph schema can be built. + +To resolve this error, inspect the printed errors and correct the subgraph schemas. diff --git a/src/error/metadata/codes/E028.md b/src/error/metadata/codes/E028.md new file mode 100644 index 000000000..b5ba2644a --- /dev/null +++ b/src/error/metadata/codes/E028.md @@ -0,0 +1,3 @@ +This error occurs when a connection could not be established with to an introspection endpoint. + +To resolve this problem, make sure the endpoint URL is correct. You may wish to run the command again with `--log=debug`. diff --git a/src/error/metadata/mod.rs b/src/error/metadata/mod.rs index 3d980539f..fbe9cf1f7 100644 --- a/src/error/metadata/mod.rs +++ b/src/error/metadata/mod.rs @@ -1,4 +1,4 @@ -mod code; +pub(crate) mod code; mod suggestion; pub(crate) use code::Code; @@ -40,26 +40,26 @@ impl From<&mut anyhow::Error> for Metadata { fn from(error: &mut anyhow::Error) -> Self { if let Some(rover_client_error) = error.downcast_ref::() { let (suggestion, code) = match rover_client_error { - RoverClientError::InvalidJson(_) - | RoverClientError::InvalidHeaderName(_) - | RoverClientError::InvalidHeaderValue(_) - | RoverClientError::MalformedResponse { null_field: _ } - | RoverClientError::InvalidSeverity => (Some(Suggestion::SubmitIssue), None), - RoverClientError::SendRequest(_) => (None, None), - RoverClientError::CouldNotConnect { .. } => { - (Some(Suggestion::CheckServerConnection), None) + RoverClientError::InvalidJson(_) => { + (Some(Suggestion::SubmitIssue), Some(Code::E001)) } - RoverClientError::NoCompositionPublishes { - graph: _, - composition_errors, - } => { - for composition_error in composition_errors { - eprintln!("{} {}", Red.bold().paint("error:"), composition_error); - } - (Some(Suggestion::RunComposition), None) + RoverClientError::InvalidHeaderName(_) => { + (Some(Suggestion::SubmitIssue), Some(Code::E002)) + } + RoverClientError::InvalidHeaderValue(_) => { + (Some(Suggestion::SubmitIssue), Some(Code::E003)) + } + RoverClientError::SendRequest(_) => { + (Some(Suggestion::SubmitIssue), Some(Code::E004)) + } + RoverClientError::MalformedResponse { null_field: _ } => { + (Some(Suggestion::SubmitIssue), Some(Code::E005)) + } + RoverClientError::InvalidSeverity => { + (Some(Suggestion::SubmitIssue), Some(Code::E006)) } RoverClientError::ExpectedFederatedGraph { graph: _ } => { - (Some(Suggestion::UseFederatedGraph), None) + (Some(Suggestion::UseFederatedGraph), Some(Code::E007)) } RoverClientError::NoSchemaForVariant { graph, @@ -73,26 +73,38 @@ impl From<&mut anyhow::Error> for Metadata { valid_variants: valid_variants.clone(), frontend_url_root: frontend_url_root.clone(), }), - None, + Some(Code::E008), ), RoverClientError::NoSubgraphInGraph { invalid_subgraph: _, valid_subgraphs, } => ( Some(Suggestion::ProvideValidSubgraph(valid_subgraphs.clone())), - None, + Some(Code::E009), ), RoverClientError::NoService { graph: _ } => { - (Some(Suggestion::CheckGraphNameAndAuth), None) - } - RoverClientError::AdhocError { msg: _ } - | RoverClientError::GraphQl { msg: _ } - | RoverClientError::IntrospectionError { msg: _ } - | RoverClientError::ClientError { msg: _ } => (None, None), - RoverClientError::InvalidKey => (Some(Suggestion::CheckKey), None), - RoverClientError::MalformedKey => (Some(Suggestion::ProperKey), None), + (Some(Suggestion::CheckGraphNameAndAuth), Some(Code::E010)) + } + RoverClientError::GraphQl { msg: _ } => (None, None), + RoverClientError::IntrospectionError { msg: _ } => (None, Some(Code::E011)), + RoverClientError::ClientError { msg: _ } => (None, Some(Code::E012)), + RoverClientError::InvalidKey => (Some(Suggestion::CheckKey), Some(Code::E013)), + RoverClientError::MalformedKey => (Some(Suggestion::ProperKey), Some(Code::E014)), RoverClientError::UnparseableReleaseVersion => { - (Some(Suggestion::SubmitIssue), None) + (Some(Suggestion::SubmitIssue), Some(Code::E015)) + } + RoverClientError::NoCompositionPublishes { + graph: _, + composition_errors, + } => { + for composition_error in composition_errors { + eprintln!("{} {}", Red.bold().paint("error:"), composition_error); + } + (Some(Suggestion::RunComposition), Some(Code::E027)) + } + RoverClientError::AdhocError { msg: _ } => (None, None), + RoverClientError::CouldNotConnect { .. } => { + (Some(Suggestion::CheckServerConnection), Some(Code::E028)) } }; return Metadata { @@ -104,13 +116,17 @@ impl From<&mut anyhow::Error> for Metadata { if let Some(houston_problem) = error.downcast_ref::() { let (suggestion, code) = match houston_problem { - HoustonProblem::CouldNotCreateConfigHome(_) - | HoustonProblem::DefaultConfigDirNotFound - | HoustonProblem::InvalidOverrideConfigDir(_) => { - (Some(Suggestion::SetConfigHome), None) + HoustonProblem::CouldNotCreateConfigHome(_) => { + (Some(Suggestion::SetConfigHome), Some(Code::E016)) + } + HoustonProblem::DefaultConfigDirNotFound => { + (Some(Suggestion::SetConfigHome), Some(Code::E017)) + } + HoustonProblem::InvalidOverrideConfigDir(_) => { + (Some(Suggestion::SetConfigHome), Some(Code::E018)) } HoustonProblem::NoConfigFound(_) => { - let code = None; + let code = Some(Code::E019); let suggestion = if env::var_os(RoverEnvKey::ConfigHome.to_string()).is_some() { Some(Suggestion::MigrateConfigHomeOrCreateConfig) } else { @@ -118,13 +134,23 @@ impl From<&mut anyhow::Error> for Metadata { }; (suggestion, code) } - HoustonProblem::NoConfigProfiles => (Some(Suggestion::NewUserNoProfiles), None), - HoustonProblem::ProfileNotFound(_) => (Some(Suggestion::ListProfiles), None), - HoustonProblem::NoNonSensitiveConfigFound(_) - | HoustonProblem::PathNotUtf8(_) - | HoustonProblem::TomlDeserialization(_) - | HoustonProblem::TomlSerialization(_) - | HoustonProblem::IoError(_) => (Some(Suggestion::SubmitIssue), None), + HoustonProblem::NoConfigProfiles => { + (Some(Suggestion::NewUserNoProfiles), Some(Code::E020)) + } + HoustonProblem::ProfileNotFound(_) => { + (Some(Suggestion::ListProfiles), Some(Code::E021)) + } + HoustonProblem::NoNonSensitiveConfigFound(_) => { + (Some(Suggestion::SubmitIssue), Some(Code::E022)) + } + HoustonProblem::PathNotUtf8(_) => (Some(Suggestion::SubmitIssue), Some(Code::E023)), + HoustonProblem::TomlDeserialization(_) => { + (Some(Suggestion::SubmitIssue), Some(Code::E024)) + } + HoustonProblem::TomlSerialization(_) => { + (Some(Suggestion::SubmitIssue), Some(Code::E025)) + } + HoustonProblem::IoError(_) => (Some(Suggestion::SubmitIssue), Some(Code::E026)), }; return Metadata { suggestion, diff --git a/src/error/mod.rs b/src/error/mod.rs index 12a4aaee7..25704f5d4 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -1,4 +1,4 @@ -mod metadata; +pub(crate) mod metadata; pub use anyhow::{anyhow, Context}; pub(crate) use metadata::Metadata;