-
Notifications
You must be signed in to change notification settings - Fork 8
fix(cli): refresh setup before hosted updates #533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -413,6 +413,29 @@ mod tests { | |
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn hosted_setup_reconciles_each_packaged_revision_once() { | ||
| for status in ["running", "update-failed", "refresh-failed"] { | ||
| assert!(hosted_setup_reconcile_required( | ||
| status, | ||
| Some("package-b"), | ||
| Some("package-a") | ||
| )); | ||
| assert!(!hosted_setup_reconcile_required( | ||
| status, | ||
| Some("package-b"), | ||
| Some("package-b") | ||
| )); | ||
| } | ||
|
|
||
| assert!(!hosted_setup_reconcile_required( | ||
| "updating", | ||
| Some("package-b"), | ||
| Some("package-a") | ||
| )); | ||
| assert!(!hosted_setup_reconcile_required("running", None, None)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn stable_channel_accepts_exact_semver_tag() { | ||
| assert_eq!( | ||
|
|
@@ -1370,7 +1393,7 @@ pub async fn up_command(args: UpArgs, embedded_config: Option<&DeployCliConfig>) | |
| )?; | ||
|
|
||
| // Check if the deployment is already active — nothing to do. | ||
| let current_deployment = client | ||
| let mut current_deployment = client | ||
| .get_deployment() | ||
| .id(&deployment_id) | ||
| .send() | ||
|
|
@@ -1383,6 +1406,51 @@ pub async fn up_command(args: UpArgs, embedded_config: Option<&DeployCliConfig>) | |
|
|
||
| let hosted_platform = | ||
| manager_url.trim_end_matches('/') != resolved.base_url.trim_end_matches('/'); | ||
| let setup_revision = embedded_config.and_then(|config| config.setup_revision.as_deref()); | ||
| let applied_setup_revision = current_deployment | ||
| .runtime_metadata | ||
| .as_ref() | ||
| .and_then(|metadata| serde_json::to_value(metadata).ok()) | ||
| .and_then(|metadata| { | ||
| metadata | ||
| .get("directSetupRevision") | ||
| .and_then(serde_json::Value::as_str) | ||
| .map(ToString::to_string) | ||
| }); | ||
| if init.deployment_model == DeploymentModel::Push | ||
| && hosted_platform | ||
| && requires_install_context(platform) | ||
| && hosted_setup_reconcile_required( | ||
| ¤t_deployment.status, | ||
| setup_revision, | ||
| applied_setup_revision.as_deref(), | ||
| ) | ||
| { | ||
| output::info("Refreshing setup-owned infrastructure for this CLI revision..."); | ||
| run_push_model( | ||
| &client, | ||
| &deployment_id, | ||
| platform, | ||
| base_platform, | ||
| &manager_url, | ||
| &effective_token, | ||
| install_management_config.clone(), | ||
| &args.network, | ||
| None, | ||
| setup_revision, | ||
| ) | ||
| .await?; | ||
| current_deployment = client | ||
| .get_deployment() | ||
| .id(&deployment_id) | ||
| .send() | ||
| .await | ||
| .into_sdk_error() | ||
| .context(ErrorData::ConfigurationError { | ||
| message: "Failed to refresh deployment after setup reconciliation".to_string(), | ||
| })? | ||
| .into_inner(); | ||
| } | ||
| if supports_hosted_compute_update(¤t_deployment.status) | ||
| && init.deployment_model == DeploymentModel::Push | ||
| && hosted_platform | ||
|
|
@@ -1507,6 +1575,7 @@ pub async fn up_command(args: UpArgs, embedded_config: Option<&DeployCliConfig>) | |
| &effective_token, | ||
| None, | ||
| None, | ||
| setup_revision, | ||
| ) | ||
| .await?; | ||
|
|
||
|
|
@@ -1555,6 +1624,7 @@ pub async fn up_command(args: UpArgs, embedded_config: Option<&DeployCliConfig>) | |
| install_management_config, | ||
| &args.network, | ||
| Some(on_progress), | ||
| setup_revision, | ||
| ) | ||
| .await?; | ||
|
|
||
|
|
@@ -2808,6 +2878,16 @@ fn supports_hosted_compute_update(status: &str) -> bool { | |
| ) | ||
| } | ||
|
|
||
| fn hosted_setup_reconcile_required( | ||
| status: &str, | ||
| packaged_revision: Option<&str>, | ||
| applied_revision: Option<&str>, | ||
| ) -> bool { | ||
| matches!(status, "running" | "update-failed" | "refresh-failed") | ||
| && packaged_revision.is_some() | ||
| && packaged_revision != applied_revision | ||
| } | ||
|
|
||
| /// Whether the hosted platform must receive the requested compute target. | ||
| /// | ||
| /// Platform persists the desired settings before the deployment engine applies | ||
|
|
@@ -3766,6 +3846,7 @@ async fn run_push_model( | |
| management_config: Option<ManagementConfig>, | ||
| network_args: &NetworkArgs, | ||
| on_progress: Option<alien_deployment::runner::ProgressCallback>, | ||
| setup_revision: Option<&str>, | ||
| ) -> Result<()> { | ||
| let credential_platform = base_platform.unwrap_or(platform); | ||
| let client_config = ClientConfig::from_std_env(credential_platform) | ||
|
|
@@ -3788,6 +3869,7 @@ async fn run_push_model( | |
| deployment_token, | ||
| Some(network_args), | ||
| on_progress, | ||
| setup_revision, | ||
| ) | ||
| .await | ||
| } | ||
|
|
@@ -3819,6 +3901,7 @@ pub async fn push_initial_setup( | |
| deployment_token: &str, | ||
| network_args: Option<&NetworkArgs>, | ||
| on_progress: Option<alien_deployment::runner::ProgressCallback>, | ||
| setup_revision: Option<&str>, | ||
| ) -> Result<()> { | ||
| let setup_management_config = management_config.clone(); | ||
|
|
||
|
|
@@ -4065,7 +4148,12 @@ pub async fn push_initial_setup( | |
| message: "Failed to deserialize runtime_metadata from manager".to_string(), | ||
| })?; | ||
|
|
||
| if state.status == DeploymentStatus::Running { | ||
| if matches!( | ||
| state.status, | ||
| DeploymentStatus::Running | ||
| | DeploymentStatus::UpdateFailed | ||
| | DeploymentStatus::RefreshFailed | ||
| ) { | ||
| let stack_state = state.stack_state.as_ref().ok_or_else(|| { | ||
| AlienError::new(ErrorData::ConfigurationError { | ||
| message: "A running deployment has no stack state for setup update".to_string(), | ||
|
|
@@ -4129,6 +4217,16 @@ pub async fn push_initial_setup( | |
| ) | ||
| .await; | ||
|
|
||
| if let Ok(result) = &runner_result { | ||
| if matches!(result.loop_result.outcome, LoopOutcome::Success) { | ||
| if let (Some(revision), Some(metadata)) = | ||
| (setup_revision, state.runtime_metadata.as_mut()) | ||
| { | ||
| metadata.direct_setup_revision = Some(revision.to_string()); | ||
|
Comment on lines
+4220
to
+4225
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When setup reaches its normal Provisioning handoff, the runner returns Knowledge Base Used: Prompt To Fix With AIThis is a comment left during a code review.
Path: crates/alien-deploy-cli/src/commands/up.rs
Line: 4220-4225
Comment:
**Handoff skips revision persistence**
When setup reaches its normal Provisioning handoff, the runner returns `LoopOutcome::Neutral`, but this block records `direct_setup_revision` only for `Success`; the revision therefore remains unset and later invocations rerun setup-owned infrastructure for the same package revision.
**Knowledge Base Used:**
- [CLI and deployment workflows](https://app.greptile.com/alien/-/custom-context/knowledge-base/alienplatform/alien/-/docs/cli-and-deployment.md)
- [Deployment and packaging](https://app.greptile.com/alien/-/custom-context/knowledge-base/alienplatform/alien/-/docs/deployment-and-packaging.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly. |
||
| } | ||
| } | ||
| } | ||
|
|
||
| // Always reconcile + release, even on error. | ||
| final_reconcile(client, deployment_id, &session, &state).await; | ||
| release_deployment(client, deployment_id, &session).await; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a newer generated CLI refreshes a running or refresh-failed hosted deployment,
push_initial_setupreconstructstarget_releaseonly from the cleareddesired_release_id, causing the command to fail with “A setup update requires a desired release” instead of refreshing setup from the current release.Knowledge Base Used:
Prompt To Fix With AI