Skip to content

Commit 639cb10

Browse files
Merge pull request #694 from kate-goldenring/spin-deploy-add-revision
fix: ensure deterministic behavior of `spin deploy` when redeploying apps
2 parents f57cf9f + b2c9df4 commit 639cb10

File tree

1 file changed

+70
-20
lines changed

1 file changed

+70
-20
lines changed

src/commands/deploy.rs

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use url::Url;
1717

1818
use crate::{opts::*, parse_buildinfo, sloth::warn_if_slow_response};
1919

20+
const SPIN_DEPLOY_CHANNEL_NAME: &str = "spin-deploy";
21+
2022
/// Package and upload Spin artifacts, notifying Hippo
2123
#[derive(Parser, Debug)]
2224
#[clap(about = "Deploy a Spin application")]
@@ -161,36 +163,56 @@ impl DeployCommand {
161163
});
162164

163165
let name = bindle_id.name().to_string();
164-
165-
// delete app if it exists in Hippo already
166-
if let Ok(id) = self.get_app_id(&hippo_client, name.clone()).await {
167-
Client::remove_app(&hippo_client, id)
168-
.await
169-
.context("Problem cleaning up existing Hippo app")?
170-
}
171-
172-
let app_id = Client::add_app(&hippo_client, name.clone(), name.clone())
173-
.await
174-
.context("Unable to create Hippo app")?;
166+
// Values for channel creation are determined by whether the app already exists
167+
let mut active_revision_id = None;
168+
let mut range_rule = None;
169+
let mut revision_selection_strategy = ChannelRevisionSelectionStrategy::UseRangeRule;
170+
171+
// Create or update app
172+
let app_id = match self.get_app_id(&hippo_client, name.clone()).await {
173+
Ok(app_id) => {
174+
Client::add_revision(
175+
&hippo_client,
176+
name.clone(),
177+
bindle_id.version_string().clone(),
178+
)
179+
.await?;
180+
181+
// Remove existing channel to prevent conflict
182+
// TODO: in the future, expand hippo API to update channel rather than delete and recreate
183+
let existing_channel_id = self
184+
.get_channel_id(&hippo_client, SPIN_DEPLOY_CHANNEL_NAME.to_string())
185+
.await?;
186+
Client::remove_channel(&hippo_client, existing_channel_id).await?;
187+
active_revision_id = Some(
188+
self.get_revision_id(&hippo_client, bindle_id.version_string().clone())
189+
.await?,
190+
);
191+
revision_selection_strategy =
192+
ChannelRevisionSelectionStrategy::UseSpecifiedRevision;
193+
app_id
194+
}
195+
Err(_) => {
196+
range_rule = Some(bindle_id.version_string());
197+
Client::add_app(&hippo_client, name.clone(), name.clone())
198+
.await
199+
.context("Unable to create Hippo app")?
200+
}
201+
};
175202

176203
let channel_id = Client::add_channel(
177204
&hippo_client,
178205
app_id,
179-
String::from("spin-deploy"),
180-
None,
181-
ChannelRevisionSelectionStrategy::UseRangeRule,
182-
Some(bindle_id.version_string()),
206+
String::from(SPIN_DEPLOY_CHANNEL_NAME),
183207
None,
208+
revision_selection_strategy,
209+
range_rule,
210+
active_revision_id,
184211
None,
185212
)
186213
.await
187214
.context("Problem creating a channel in Hippo")?;
188215

189-
println!(
190-
"Deployed {} version {}",
191-
name.clone(),
192-
bindle_id.version_string()
193-
);
194216
let channel = Client::get_channel_by_id(&hippo_client, &channel_id)
195217
.await
196218
.context("Problem getting channel by id")?;
@@ -260,6 +282,34 @@ impl DeployCommand {
260282
}
261283
}
262284

285+
async fn get_revision_id(
286+
&self,
287+
hippo_client: &Client,
288+
bindle_version: String,
289+
) -> Result<String> {
290+
let revisions = Client::list_revisions(hippo_client).await?;
291+
let revision = revisions
292+
.revisions
293+
.iter()
294+
.find(|&x| x.revision_number == bindle_version);
295+
Ok(revision
296+
.ok_or_else(|| anyhow::anyhow!("No revision with version {}", bindle_version))?
297+
.id
298+
.clone())
299+
}
300+
301+
async fn get_channel_id(&self, hippo_client: &Client, name: String) -> Result<String> {
302+
let channels_vm = Client::list_channels(hippo_client).await?;
303+
let channel = channels_vm
304+
.channels
305+
.iter()
306+
.find(|&x| x.name == name.clone());
307+
match channel {
308+
Some(c) => Ok(c.id.clone()),
309+
None => anyhow::bail!("No channel with name: {}", name),
310+
}
311+
}
312+
263313
async fn create_and_push_bindle(&self, buildinfo: Option<BuildMetadata>) -> Result<Id> {
264314
let source_dir = crate::app_dir(&self.app)?;
265315
let bindle_connection_info = spin_publish::BindleConnectionInfo::new(

0 commit comments

Comments
 (0)