Inner runner that takes the slug-verification step as a parameter. Splitting this out lets tests inject a deterministic verifier (succeed / fail) without making a real network call, so we can assert the load-bearing invariant: **when verification fails, the config file is not modified**.
(&self, verify: F)
| 99 | /// assert the load-bearing invariant: **when verification fails, the |
| 100 | /// config file is not modified**. |
| 101 | fn run_with_verifier<F>(&self, verify: F) -> CliResult<()> |
| 102 | where |
| 103 | F: FnOnce(&str, &str) -> CliResult<()>, |
| 104 | { |
| 105 | if self.slug.is_empty() { |
| 106 | return Err(CliError::InvalidArgument { |
| 107 | message: "Workspace slug cannot be empty.".to_string(), |
| 108 | }); |
| 109 | } |
| 110 | |
| 111 | let mut config = GlobalConfig::load().map_err(|e| { |
| 112 | CliError::Internal(anyhow::anyhow!("Failed to load global config: {e}")) |
| 113 | })?; |
| 114 | |
| 115 | // Determine the target org. Explicit --org wins; otherwise resolve |
| 116 | // the active server profile's default org (falling back to the |
| 117 | // identity's personal org), so this matches what read commands use. |
| 118 | let target_org = match self.org.as_deref() { |
| 119 | Some(o) if !o.is_empty() => o.to_string(), |
| 120 | Some(_) => { |
| 121 | return Err(CliError::InvalidArgument { |
| 122 | message: "Organization slug cannot be empty.".to_string(), |
| 123 | }); |
| 124 | } |
| 125 | None => { |
| 126 | let (server, _name) = config |
| 127 | .resolve_server(None) |
| 128 | .map_err(|e| CliError::Internal(anyhow::anyhow!("{e}")))?; |
| 129 | resolve_org_with_server(None, server)? |
| 130 | } |
| 131 | }; |
| 132 | |
| 133 | // Validate against the server first so a bad slug fails fast |
| 134 | // rather than producing confusing 404s on subsequent commands. |
| 135 | // The `?` here is load-bearing: if it returns Err, the mutation |
| 136 | // and save below never execute. |
| 137 | if !self.no_verify { |
| 138 | verify(&target_org, &self.slug)?; |
| 139 | } |
| 140 | |
| 141 | // Write into the *active* server profile so the default is read back |
| 142 | // by commands that resolve the same profile. |
| 143 | let (server, _profile_name) = config |
| 144 | .resolve_server_mut(None) |
| 145 | .map_err(|e| CliError::Internal(anyhow::anyhow!("{e}")))?; |
| 146 | |
| 147 | let previous = server |
| 148 | .default_workspaces |
| 149 | .insert(target_org.clone(), self.slug.clone()); |
| 150 | let current_org = server.default_org.clone(); |
| 151 | |
| 152 | config.save().map_err(|e| { |
| 153 | CliError::Internal(anyhow::anyhow!("Failed to save global config: {e}")) |
| 154 | })?; |
| 155 | |
| 156 | print_success(&format!( |
| 157 | "Default workspace for '{}' set to: {}", |
| 158 | target_org, self.slug |
no test coverage detected