diff --git a/rust/src/application/client.rs b/rust/src/application/client.rs index 433d957..7179cad 100644 --- a/rust/src/application/client.rs +++ b/rust/src/application/client.rs @@ -128,6 +128,18 @@ impl ApplicationClient { .await } + pub async fn activate_release( + &self, + application_id: &str, + release_id: &str, + ) -> Result { + self.query(json!({ + "query": "mutation ActivateRelease($applicationId: ID!, $releaseId: ID!) { activateRelease(applicationId: $applicationId, releaseId: $releaseId) { id version description status activatedAt createdAt updatedAt } }", + "variables": { "applicationId": application_id, "releaseId": release_id } + })) + .await + } + pub async fn enable_application(&self, input: Value) -> Result { self.query(json!({ "query": "mutation EnableApplication($input: MutationEnableStoreApplicationInput!) { enableStoreApplication(input: $input) { id } }", @@ -243,4 +255,33 @@ mod tests { // may point the default at an http:// local proxy). assert!(url.contains("://"), "{url:?}"); } + + #[tokio::test] + async fn activate_release_sends_ids_and_returns_data() { + use httpmock::prelude::*; + use serde_json::json; + + let server = MockServer::start(); + let mock = server.mock(|when, then| { + when.method(POST) + .path("/v1/apps/app-registry-subgraph") + .body_contains("activateRelease") + .body_contains("app-1") + .body_contains("rel-9"); + then.status(200).header("content-type", "application/json").json_body(json!({ + "data": { "activateRelease": { "id": "rel-9", "version": "1.0.0", "status": "ACTIVE" } } + })); + }); + + let client = super::ApplicationClient::new(server.base_url(), "test-token"); + let data = client + .activate_release("app-1", "rel-9") + .await + .expect("activate_release should succeed"); + + // The mutation was sent with both IDs, and the response data is returned. + mock.assert(); + assert_eq!(data["activateRelease"]["status"], "ACTIVE"); + assert_eq!(data["activateRelease"]["id"], "rel-9"); + } } diff --git a/rust/src/application/commands/mod.rs b/rust/src/application/commands/mod.rs index d558f0e..6c9a3f9 100644 --- a/rust/src/application/commands/mod.rs +++ b/rust/src/application/commands/mod.rs @@ -817,8 +817,34 @@ fn deploy_command() -> RuntimeCommandSpec { .await?; } + // Activate the release, then set the application ACTIVE. This runs + // regardless of extension count — without it the app stays INACTIVE + // and can't be enabled, so a deploy that only uploads artifacts is + // effectively a no-op. (Parity with the TS deploy flow / PR #77.) sender - .send(json!({ "type": "step", "name": "deploy", "status": "completed", "name": name, "extensions": total })) + .send(json!({ "type": "step", "name": "release.activate", "status": "started", "releaseId": release_id })) + .await; + client + .activate_release(&application_id, &release_id) + .await + .map_err(client_err)?; + sender + .send(json!({ "type": "step", "name": "release.activate", "status": "completed", "releaseId": release_id })) + .await; + + sender + .send(json!({ "type": "step", "name": "application.activate", "status": "started", "id": application_id })) + .await; + client + .update_application(&application_id, json!({ "status": "ACTIVE" })) + .await + .map_err(client_err)?; + sender + .send(json!({ "type": "step", "name": "application.activate", "status": "completed", "id": application_id })) + .await; + + sender + .send(json!({ "type": "step", "name": "deploy", "status": "completed", "name": name, "extensions": total, "status_after": "ACTIVE" })) .await; Ok(()) },