diff --git a/Cargo.lock b/Cargo.lock index 2a775a0..d472415 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2027,6 +2027,7 @@ dependencies = [ "thiserror", "tokio", "tower-http", + "tracing", "urlencoding", "webbrowser", ] @@ -2486,9 +2487,21 @@ dependencies = [ "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "tracing-core" version = "0.1.31" diff --git a/Cargo.toml b/Cargo.toml index 11337c0..07a1db3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ serde_json = "1" thiserror = "1.0.32" tokio = { version = "1.18.2", features = ["full", "sync"] } tower-http = "0.4" +tracing = "0.1.34" urlencoding = "2" webbrowser = "0.8" starknet = "0.6.0" diff --git a/schema.json b/schema.json index e8d6297..2dcc14e 100644 --- a/schema.json +++ b/schema.json @@ -11568,7 +11568,7 @@ "deprecationReason": null, "description": null, "isDeprecated": false, - "name": "namespace", + "name": "project", "type": { "kind": "NON_NULL", "name": null, @@ -11579,6 +11579,18 @@ } } }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "environment", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, { "args": [], "deprecationReason": null, @@ -11748,9 +11760,13 @@ "isDeprecated": false, "name": "logs", "type": { - "kind": "OBJECT", - "name": "Logs", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Logs", + "ofType": null + } } }, { @@ -11760,9 +11776,13 @@ "isDeprecated": false, "name": "config", "type": { - "kind": "UNION", - "name": "DeploymentConfig", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "UNION", + "name": "DeploymentConfig", + "ofType": null + } } } ], @@ -12153,8 +12173,154 @@ }, { "defaultValue": null, - "description": "namespace field predicates", - "name": "namespace", + "description": "project field predicates", + "name": "project", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectNEQ", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectIn", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectNotIn", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectGT", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectGTE", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectLT", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectLTE", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectContains", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectHasPrefix", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectHasSuffix", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectEqualFold", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "projectContainsFold", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + { + "defaultValue": null, + "description": "environment field predicates", + "name": "environment", "type": { "kind": "SCALAR", "name": "String", @@ -12164,7 +12330,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceNEQ", + "name": "environmentNEQ", "type": { "kind": "SCALAR", "name": "String", @@ -12174,7 +12340,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceIn", + "name": "environmentIn", "type": { "kind": "LIST", "name": null, @@ -12192,7 +12358,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceNotIn", + "name": "environmentNotIn", "type": { "kind": "LIST", "name": null, @@ -12210,7 +12376,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceGT", + "name": "environmentGT", "type": { "kind": "SCALAR", "name": "String", @@ -12220,7 +12386,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceGTE", + "name": "environmentGTE", "type": { "kind": "SCALAR", "name": "String", @@ -12230,7 +12396,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceLT", + "name": "environmentLT", "type": { "kind": "SCALAR", "name": "String", @@ -12240,7 +12406,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceLTE", + "name": "environmentLTE", "type": { "kind": "SCALAR", "name": "String", @@ -12250,7 +12416,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceContains", + "name": "environmentContains", "type": { "kind": "SCALAR", "name": "String", @@ -12260,7 +12426,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceHasPrefix", + "name": "environmentHasPrefix", "type": { "kind": "SCALAR", "name": "String", @@ -12270,7 +12436,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceHasSuffix", + "name": "environmentHasSuffix", "type": { "kind": "SCALAR", "name": "String", @@ -12280,7 +12446,27 @@ { "defaultValue": null, "description": null, - "name": "namespaceEqualFold", + "name": "environmentIsNil", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "environmentNotNil", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + { + "defaultValue": null, + "description": null, + "name": "environmentEqualFold", "type": { "kind": "SCALAR", "name": "String", @@ -12290,7 +12476,7 @@ { "defaultValue": null, "description": null, - "name": "namespaceContainsFold", + "name": "environmentContainsFold", "type": { "kind": "SCALAR", "name": "String", @@ -17908,15 +18094,19 @@ "isDeprecated": false, "name": "entries", "type": { - "kind": "LIST", + "kind": "NON_NULL", "name": null, "ofType": { - "kind": "NON_NULL", + "kind": "LIST", "name": null, "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } } } } @@ -31425,6 +31615,54 @@ "ofType": null } } + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "rpc", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "world", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "startBlock", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Long", + "ofType": null + } + } } ], "inputFields": [], diff --git a/src/command/deployment/create.graphql b/src/command/deployment/create.graphql index 4c5c22e..5284b27 100644 --- a/src/command/deployment/create.graphql +++ b/src/command/deployment/create.graphql @@ -4,12 +4,7 @@ mutation CreateDeployment( $tier: DeploymentTier! $wait: Boolean ) { - createDeployment( - name: $name - service: $service - tier: $tier - wait: $wait - ) { + createDeployment(name: $name, service: $service, tier: $tier, wait: $wait) { __typename ... on KatanaConfig { rpc @@ -17,6 +12,9 @@ mutation CreateDeployment( ... on ToriiConfig { graphql grpc + rpc + world + startBlock } ... on MadaraConfig { rpc diff --git a/src/command/deployment/create.rs b/src/command/deployment/create.rs index 336e6ed..790371c 100644 --- a/src/command/deployment/create.rs +++ b/src/command/deployment/create.rs @@ -4,17 +4,17 @@ use anyhow::Result; use clap::Args; use graphql_client::{GraphQLQuery, Response}; +use self::create_deployment::ServiceInput; use crate::{ api::ApiClient, command::deployment::create::create_deployment::{ + CreateDeploymentCreateDeployment::{KatanaConfig, ToriiConfig}, DeploymentService, DeploymentTier, KatanaConfigInput, ServiceConfigInput, ToriiConfigInput, Variables, }, }; -use self::create_deployment::ServiceInput; - -use super::configs::CreateCommands; +use super::services::CreateCommands; type Long = u64; @@ -106,7 +106,26 @@ impl CreateArgs { } } - println!("{:#?}", res.data); + if let Some(data) = res.data { + println!("Deployment success 🚀"); + match data.create_deployment { + ToriiConfig(config) => { + println!("\nConfiguration:"); + println!(" World: {}", config.world); + println!(" RPC: {}", config.rpc); + println!(" Start Block: {}", config.start_block); + println!("\nEndpoints:"); + println!(" GRAPHQL: {}", config.graphql); + println!(" GRPC: {}", config.grpc); + } + KatanaConfig(config) => { + println!("\nEndpoints:"); + println!(" RPC: {}", config.rpc); + } + _ => {} + } + } + Ok(()) } } diff --git a/src/command/deployment/describe.graphql b/src/command/deployment/describe.graphql new file mode 100644 index 0000000..4d4ceb7 --- /dev/null +++ b/src/command/deployment/describe.graphql @@ -0,0 +1,23 @@ +query DescribeDeployment($name: String!, $service: DeploymentService!) { + deployment(name: $name, service: $service) { + project + environment + tier + config { + __typename + ... on KatanaConfig { + rpc + } + ... on ToriiConfig { + graphql + grpc + rpc + world + startBlock + } + ... on MadaraConfig { + rpc + } + } + } +} diff --git a/src/command/deployment/describe.rs b/src/command/deployment/describe.rs new file mode 100644 index 0000000..bb4d3d3 --- /dev/null +++ b/src/command/deployment/describe.rs @@ -0,0 +1,91 @@ +#![allow(clippy::enum_variant_names)] + +use anyhow::Result; +use clap::Args; +use graphql_client::{GraphQLQuery, Response}; + +use crate::api::ApiClient; + +use self::describe_deployment::{ + DeploymentService, + DescribeDeploymentDeploymentConfig::{KatanaConfig, ToriiConfig}, + ResponseData, Variables, +}; + +use super::services::Service; + +type Long = u64; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schema.json", + query_path = "src/command/deployment/describe.graphql", + response_derives = "Debug" +)] +pub struct DescribeDeployment; + +#[derive(Debug, Args)] +#[command(next_help_heading = "Describe options")] +pub struct DescribeArgs { + #[arg(short, long = "name")] + #[arg(help = "The name of the project.")] + pub name: String, + + #[arg(short, long = "service")] + #[arg(help = "The service of the project.")] + pub service: Service, +} + +impl DescribeArgs { + pub async fn run(&self) -> Result<()> { + let service = match self.service { + Service::Torii => DeploymentService::torii, + Service::Katana => DeploymentService::katana, + }; + + let request_body = DescribeDeployment::build_query(Variables { + name: self.name.clone(), + service, + }); + + let client = ApiClient::new(); + let res: Response = client.post(&request_body).await?; + if let Some(errors) = res.errors.clone() { + for err in errors { + println!("Error: {}", err.message); + } + } + + if let Some(data) = res.data { + if let Some(deployment) = data.deployment { + println!("Project: {}", deployment.project); + println!( + "Environment: {}", + deployment + .environment + .unwrap_or_else(|| String::from("Default")) + ); + println!("Tier: {:?}", deployment.tier); + + match deployment.config { + ToriiConfig(config) => { + println!("\nConfiguration:"); + println!(" World: {}", config.world); + println!(" RPC: {}", config.rpc); + println!(" Start Block: {}", config.start_block); + println!("\nEndpoints:"); + println!(" GraphQL: {}", config.graphql); + println!(" GRPC: {}", config.grpc); + } + KatanaConfig(config) => { + println!("\nEndpoints:"); + println!(" RPC: {}", config.rpc); + } + _ => {} + } + } + } + + Ok(()) + } +} diff --git a/src/command/deployment/list.graphql b/src/command/deployment/list.graphql new file mode 100644 index 0000000..7bfc8a0 --- /dev/null +++ b/src/command/deployment/list.graphql @@ -0,0 +1,19 @@ +query ListDeployments { + me { + id + name + teams { + edges { + node { + deployments { + edges { + node { + project + } + } + } + } + } + } + } +} diff --git a/src/command/deployment/list.rs b/src/command/deployment/list.rs new file mode 100644 index 0000000..ebf5d64 --- /dev/null +++ b/src/command/deployment/list.rs @@ -0,0 +1,59 @@ +#![allow(clippy::enum_variant_names)] + +use anyhow::Result; +use clap::Args; +use graphql_client::{GraphQLQuery, Response}; + +use crate::api::ApiClient; + +use self::list_deployments::{ResponseData, Variables}; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schema.json", + query_path = "src/command/deployment/list.graphql", + response_derives = "Debug" +)] +pub struct ListDeployments; + +#[derive(Debug, Args)] +#[command(next_help_heading = "List options")] +pub struct ListArgs {} + +impl ListArgs { + pub async fn run(&self) -> Result<()> { + let request_body = ListDeployments::build_query(Variables {}); + + let client = ApiClient::new(); + let res: Response = client.post(&request_body).await?; + if let Some(errors) = res.errors.clone() { + for err in errors { + println!("Error: {}", err.message); + } + } + + if let Some(data) = res.data { + if let Some(me) = data.me { + if let Some(teams) = me.teams.edges { + let teams: Vec<_> = teams + .iter() + .filter_map(|team| team.as_ref()) + .filter_map(|team| team.node.as_ref()) + .collect::<_>(); + + let mut all_deployments = Vec::new(); + + for team in teams { + if let Some(deployments) = &team.deployments.edges { + all_deployments.extend(deployments.clone()); + } + } + + println!("{:?}", all_deployments); + } + } + } + + Ok(()) + } +} diff --git a/src/command/deployment/logs.rs b/src/command/deployment/logs.rs index adf4027..2ae0bc6 100644 --- a/src/command/deployment/logs.rs +++ b/src/command/deployment/logs.rs @@ -4,7 +4,7 @@ use graphql_client::{GraphQLQuery, Response}; use crate::api::ApiClient; -use super::configs::Service; +use super::services::Service; #[derive(GraphQLQuery)] #[graphql( @@ -55,9 +55,8 @@ impl LogsArgs { let entries = res .data .and_then(|data| data.deployment) - .and_then(|deployment| deployment.logs) - .and_then(|logs| logs.entries) - .unwrap(); + .and_then(|deployment| Some(deployment.logs.entries)) + .unwrap_or_default(); for e in entries.iter() { if e.trim() == "{}" { diff --git a/src/command/deployment/mod.rs b/src/command/deployment/mod.rs index 2dfc61e..1f8fbd5 100644 --- a/src/command/deployment/mod.rs +++ b/src/command/deployment/mod.rs @@ -1,16 +1,22 @@ use anyhow::Result; use clap::Subcommand; -use self::{create::CreateArgs, logs::LogsArgs}; +use self::{create::CreateArgs, describe::DescribeArgs, list::ListArgs, logs::LogsArgs}; -mod configs; mod create; +mod describe; +mod list; mod logs; +mod services; #[derive(Subcommand, Debug)] pub enum Deployment { #[command(about = "Create a new deployment.")] Create(CreateArgs), + #[command(about = "Describe a deployment's configuration.")] + Describe(DescribeArgs), + #[command(about = "List all deployments.")] + List(ListArgs), #[command(about = "Fetch logs for a deployment.")] Logs(LogsArgs), } @@ -19,6 +25,8 @@ impl Deployment { pub async fn run(&self) -> Result<()> { match &self { Deployment::Create(args) => args.run().await, + Deployment::Describe(args) => args.run().await, + Deployment::List(args) => args.run().await, Deployment::Logs(args) => args.run().await, } } diff --git a/src/command/deployment/configs/katana.rs b/src/command/deployment/services/katana.rs similarity index 96% rename from src/command/deployment/configs/katana.rs rename to src/command/deployment/services/katana.rs index f5d0e7e..2da0b78 100644 --- a/src/command/deployment/configs/katana.rs +++ b/src/command/deployment/services/katana.rs @@ -2,7 +2,7 @@ use clap::Args; #[derive(Debug, Args, serde::Serialize)] #[command(next_help_heading = "Katana options")] -pub struct Katana { +pub struct KatanaArgs { #[arg(long, short, value_name = "block_time")] #[arg(help = "Block time.")] pub block_time: Option, diff --git a/src/command/deployment/configs/madara.rs b/src/command/deployment/services/madara.rs similarity index 81% rename from src/command/deployment/configs/madara.rs rename to src/command/deployment/services/madara.rs index 83dbd7b..9d4b7b1 100644 --- a/src/command/deployment/configs/madara.rs +++ b/src/command/deployment/services/madara.rs @@ -2,4 +2,4 @@ use clap::Args; #[derive(Debug, Args, serde::Serialize)] #[command(next_help_heading = "Madara options")] -pub struct Madara {} +pub struct MadaraArgs {} diff --git a/src/command/deployment/configs/mod.rs b/src/command/deployment/services/mod.rs similarity index 81% rename from src/command/deployment/configs/mod.rs rename to src/command/deployment/services/mod.rs index 2df82ca..1cc7e2a 100644 --- a/src/command/deployment/configs/mod.rs +++ b/src/command/deployment/services/mod.rs @@ -1,6 +1,6 @@ use clap::{Subcommand, ValueEnum}; -use self::{katana::Katana, torii::Torii}; +use self::{katana::KatanaArgs, torii::ToriiArgs}; mod katana; mod madara; @@ -10,11 +10,11 @@ mod torii; #[serde(untagged)] pub enum CreateCommands { #[command(about = "Katana deployment.")] - Katana(Katana), + Katana(KatanaArgs), // #[command(about = "Madara deployment.")] // Madara(Madara), #[command(about = "Torii deployment.")] - Torii(Torii), + Torii(ToriiArgs), } #[derive(Clone, Debug, ValueEnum, serde::Serialize)] diff --git a/src/command/deployment/configs/torii.rs b/src/command/deployment/services/torii.rs similarity index 95% rename from src/command/deployment/configs/torii.rs rename to src/command/deployment/services/torii.rs index 00160bf..d10fa24 100644 --- a/src/command/deployment/configs/torii.rs +++ b/src/command/deployment/services/torii.rs @@ -3,7 +3,7 @@ use starknet::core::types::FieldElement; #[derive(Clone, Debug, Args, serde::Serialize)] #[command(next_help_heading = "Torii options")] -pub struct Torii { +pub struct ToriiArgs { #[arg(long)] #[arg(value_name = "rpc")] #[arg(help = "The Starknet RPC endpoint.")]