@@ -158,7 +158,7 @@ impl Shuttle {
158158
159159 self . output_mode = args. output_mode ;
160160
161- // All commands that call the API
161+ // Set up the API client for all commands that call the API
162162 if matches ! (
163163 args. cmd,
164164 Command :: Init ( ..)
@@ -171,10 +171,6 @@ impl Shuttle {
171171 | Command :: Resource ( ..)
172172 | Command :: Certificate ( ..)
173173 | Command :: Project ( ..)
174- ) || (
175- // project linking on beta requires api client
176- // TODO: refactor so that beta local run does not need to know project id / always uses crate name ???
177- matches ! ( args. cmd, Command :: Run ( ..) )
178174 ) {
179175 let api_url = args
180176 . api_url
@@ -210,7 +206,7 @@ impl Shuttle {
210206 self . client = Some ( client) ;
211207 }
212208
213- // All commands that need to know which project is being handled
209+ // Load project context for all commands that need to know which project is being targetted
214210 if matches ! (
215211 args. cmd,
216212 Command :: Deploy ( ..)
@@ -227,12 +223,12 @@ impl Shuttle {
227223 )
228224 | Command :: Logs { .. }
229225 ) {
230- // Command::Run only uses load_local_config (below) instead of load_project since it does not target a project in the API
226+ // Command::Run only uses ` load_local_config` (below) instead of ` load_project` since it does not target a project in the API
231227 self . load_project (
232228 & args. project_args ,
233229 matches ! ( args. cmd, Command :: Project ( ProjectCommand :: Link ) ) ,
234- // only the deploy command should create a project if the provided name is not found in the project list.
235- // (project start should always make the POST call, it's an upsert operation)
230+ // Only the deploy command should create a project if the provided name is not found in the project list.
231+ // (ProjectCommand::Create should always make the POST call since it's an upsert operation)
236232 matches ! ( args. cmd, Command :: Deploy ( ..) ) ,
237233 )
238234 . await ?;
@@ -255,7 +251,7 @@ impl Shuttle {
255251 }
256252 } ,
257253 Command :: Account => self . account ( ) . await ,
258- Command :: Login ( login_args) => self . login ( login_args, args. offline ) . await ,
254+ Command :: Login ( login_args) => self . login ( login_args, args. offline , true ) . await ,
259255 Command :: Logout ( logout_args) => self . logout ( logout_args) . await ,
260256 Command :: Feedback => open_gh_issue ( ) ,
261257 Command :: Run ( run_args) => {
@@ -301,7 +297,7 @@ impl Shuttle {
301297 ProjectCommand :: Status => self . project_status ( ) . await ,
302298 ProjectCommand :: List { table, .. } => self . projects_list ( table) . await ,
303299 ProjectCommand :: Delete ( ConfirmationArgs { yes } ) => self . project_delete ( yes) . await ,
304- ProjectCommand :: Link => Ok ( ( ) ) , // logic is done in `load_local`
300+ ProjectCommand :: Link => Ok ( ( ) ) , // logic is done in `load_project` in previous step
305301 } ,
306302 Command :: Upgrade { preview } => update_cargo_shuttle ( preview) . await ,
307303 }
@@ -334,10 +330,10 @@ impl Shuttle {
334330 // 1. Log in (if not logged in yet)
335331 if needs_login {
336332 eprintln ! ( "First, let's log in to your Shuttle account." ) ;
337- self . login ( args. login_args . clone ( ) , offline) . await ?;
333+ self . login ( args. login_args . clone ( ) , offline, false ) . await ?;
338334 eprintln ! ( ) ;
339335 } else if args. login_args . api_key . is_some ( ) {
340- self . login ( args. login_args . clone ( ) , offline) . await ?;
336+ self . login ( args. login_args . clone ( ) , offline, false ) . await ?;
341337 }
342338
343339 // 2. Ask for project name or validate the given one
@@ -690,6 +686,7 @@ impl Shuttle {
690686 trace ! ( "did not find project by name" ) ;
691687 if create_missing_project {
692688 trace ! ( "creating project since it was not found" ) ;
689+ // This is a side effect (non-primary output), so OutputMode::Json is not considered
693690 let proj = client. create_project ( name) . await ?. into_inner ( ) ;
694691 eprintln ! ( "Created project '{}' with id {}" , proj. name, proj. id) ;
695692 self . ctx . set_project_id ( proj. id ) ;
@@ -754,19 +751,11 @@ impl Shuttle {
754751 . with_prompt ( "Project name" )
755752 . interact ( ) ?;
756753
757- let r = client. create_project ( & name) . await ?;
754+ // This is a side effect (non-primary output), so OutputMode::Json is not considered
755+ let proj = client. create_project ( & name) . await ?. into_inner ( ) ;
756+ eprintln ! ( "Created project '{}' with id {}" , proj. name, proj. id) ;
758757
759- match self . output_mode {
760- OutputMode :: Normal => {
761- let proj = r. into_inner ( ) ;
762- eprintln ! ( "Created project '{}' with id {}" , proj. name, proj. id) ;
763- proj
764- }
765- OutputMode :: Json => {
766- println ! ( "{}" , r. raw_json) ;
767- r. into_inner ( )
768- }
769- }
758+ proj
770759 }
771760 } ;
772761
@@ -793,7 +782,7 @@ impl Shuttle {
793782 }
794783
795784 /// Log in with the given API key or after prompting the user for one.
796- async fn login ( & mut self , login_args : LoginArgs , offline : bool ) -> Result < ( ) > {
785+ async fn login ( & mut self , login_args : LoginArgs , offline : bool , login_cmd : bool ) -> Result < ( ) > {
797786 let api_key = match login_args. api_key {
798787 Some ( api_key) => api_key,
799788 None => {
@@ -822,12 +811,23 @@ impl Shuttle {
822811 if offline {
823812 eprintln ! ( "INFO: Skipping API key verification" ) ;
824813 } else {
825- let u = client
814+ let ( user , raw_json ) = client
826815 . get_current_user ( )
827816 . await
828817 . context ( "failed to check API key validity" ) ?
829- . into_inner ( ) ;
830- println ! ( "Logged in as {}" , u. id. bold( ) ) ;
818+ . into_parts ( ) ;
819+ if login_cmd {
820+ match self . output_mode {
821+ OutputMode :: Normal => {
822+ println ! ( "Logged in as {}" , user. id. bold( ) ) ;
823+ }
824+ OutputMode :: Json => {
825+ println ! ( "{}" , raw_json) ;
826+ }
827+ }
828+ } else {
829+ eprintln ! ( "Logged in as {}" , user. id. bold( ) ) ;
830+ }
831831 }
832832 }
833833
@@ -914,12 +914,19 @@ impl Shuttle {
914914 }
915915
916916 wait_with_spinner ( 2000 , |_, pb| async move {
917- let deployment = client. get_current_deployment ( pid) . await ?. into_inner ( ) ;
917+ let ( deployment, raw_json ) = client. get_current_deployment ( pid) . await ?. into_parts ( ) ;
918918
919919 let get_cleanup = |d : Option < DeploymentResponse > | {
920920 move || {
921921 if let Some ( d) = d {
922- eprintln ! ( "{}" , d. to_string_colored( ) ) ;
922+ match self . output_mode {
923+ OutputMode :: Normal => {
924+ eprintln ! ( "{}" , d. to_string_colored( ) ) ;
925+ }
926+ OutputMode :: Json => {
927+ // last deployment response already printed
928+ }
929+ }
923930 }
924931 }
925932 } ;
@@ -928,18 +935,25 @@ impl Shuttle {
928935 } ;
929936
930937 let state = deployment. state . clone ( ) ;
931- pb. set_message ( deployment. to_string_summary_colored ( ) ) ;
938+ match self . output_mode {
939+ OutputMode :: Normal => {
940+ pb. set_message ( deployment. to_string_summary_colored ( ) ) ;
941+ }
942+ OutputMode :: Json => {
943+ println ! ( "{}" , raw_json) ;
944+ }
945+ }
932946 let cleanup = get_cleanup ( Some ( deployment) ) ;
933947 match state {
934- DeploymentState :: Pending
935- | DeploymentState :: Stopping
936- | DeploymentState :: InProgress
937- | DeploymentState :: Running => Ok ( None ) ,
938- DeploymentState :: Building // a building deployment should take it back to InProgress then Running, so don't follow that sequence
939- | DeploymentState :: Failed
940- | DeploymentState :: Stopped
941- | DeploymentState :: Unknown ( _) => Ok ( Some ( cleanup) ) ,
942- }
948+ DeploymentState :: Pending
949+ | DeploymentState :: Stopping
950+ | DeploymentState :: InProgress
951+ | DeploymentState :: Running => Ok ( None ) ,
952+ DeploymentState :: Building // a building deployment should take it back to InProgress then Running, so don't follow that sequence
953+ | DeploymentState :: Failed
954+ | DeploymentState :: Stopped
955+ | DeploymentState :: Unknown ( _) => Ok ( Some ( cleanup) ) ,
956+ }
943957 } )
944958 . await ?;
945959
@@ -1713,19 +1727,35 @@ impl Shuttle {
17131727 async fn track_deployment_status ( & self , pid : & str , id : & str ) -> Result < bool > {
17141728 let client = self . client . as_ref ( ) . unwrap ( ) ;
17151729 let failed = wait_with_spinner ( 2000 , |_, pb| async move {
1716- let deployment = client. get_deployment ( pid, id) . await ?. into_inner ( ) ;
1730+ let ( deployment, raw_json ) = client. get_deployment ( pid, id) . await ?. into_parts ( ) ;
17171731
17181732 let state = deployment. state . clone ( ) ;
1719- pb. set_message ( deployment. to_string_summary_colored ( ) ) ;
1733+ match self . output_mode {
1734+ OutputMode :: Normal => {
1735+ pb. set_message ( deployment. to_string_summary_colored ( ) ) ;
1736+ }
1737+ OutputMode :: Json => {
1738+ println ! ( "{}" , raw_json) ;
1739+ }
1740+ }
17201741 let failed = state == DeploymentState :: Failed ;
17211742 let cleanup = move || {
1722- eprintln ! ( "{}" , deployment. to_string_colored( ) ) ;
1743+ match self . output_mode {
1744+ OutputMode :: Normal => {
1745+ eprintln ! ( "{}" , deployment. to_string_colored( ) ) ;
1746+ }
1747+ OutputMode :: Json => {
1748+ // last deployment response already printed
1749+ }
1750+ }
17231751 failed
17241752 } ;
17251753 match state {
1754+ // non-end states
17261755 DeploymentState :: Pending
17271756 | DeploymentState :: Building
17281757 | DeploymentState :: InProgress => Ok ( None ) ,
1758+ // end states
17291759 DeploymentState :: Running
17301760 | DeploymentState :: Stopped
17311761 | DeploymentState :: Stopping
@@ -1747,16 +1777,20 @@ impl Shuttle {
17471777 let client = self . client . as_ref ( ) . unwrap ( ) ;
17481778 let failed = self . track_deployment_status ( proj_id, depl_id) . await ?;
17491779 if failed {
1750- for log in client
1751- . get_deployment_logs ( proj_id, depl_id)
1752- . await ?
1753- . into_inner ( )
1754- . logs
1755- {
1756- if raw {
1757- println ! ( "{}" , log. line) ;
1758- } else {
1759- println ! ( "{log}" ) ;
1780+ let r = client. get_deployment_logs ( proj_id, depl_id) . await ?;
1781+ match self . output_mode {
1782+ OutputMode :: Normal => {
1783+ let logs = r. into_inner ( ) . logs ;
1784+ for log in logs {
1785+ if raw {
1786+ println ! ( "{}" , log. line) ;
1787+ } else {
1788+ println ! ( "{log}" ) ;
1789+ }
1790+ }
1791+ }
1792+ OutputMode :: Json => {
1793+ println ! ( "{}" , r. raw_json) ;
17601794 }
17611795 }
17621796 return Err ( anyhow ! ( "Deployment failed" ) ) ;
0 commit comments