@@ -17,6 +17,8 @@ use url::Url;
17
17
18
18
use crate :: { opts:: * , parse_buildinfo, sloth:: warn_if_slow_response} ;
19
19
20
+ const SPIN_DEPLOY_CHANNEL_NAME : & str = "spin-deploy" ;
21
+
20
22
/// Package and upload Spin artifacts, notifying Hippo
21
23
#[ derive( Parser , Debug ) ]
22
24
#[ clap( about = "Deploy a Spin application" ) ]
@@ -161,36 +163,56 @@ impl DeployCommand {
161
163
} ) ;
162
164
163
165
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
+ } ;
175
202
176
203
let channel_id = Client :: add_channel (
177
204
& hippo_client,
178
205
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 ) ,
183
207
None ,
208
+ revision_selection_strategy,
209
+ range_rule,
210
+ active_revision_id,
184
211
None ,
185
212
)
186
213
. await
187
214
. context ( "Problem creating a channel in Hippo" ) ?;
188
215
189
- println ! (
190
- "Deployed {} version {}" ,
191
- name. clone( ) ,
192
- bindle_id. version_string( )
193
- ) ;
194
216
let channel = Client :: get_channel_by_id ( & hippo_client, & channel_id)
195
217
. await
196
218
. context ( "Problem getting channel by id" ) ?;
@@ -260,6 +282,34 @@ impl DeployCommand {
260
282
}
261
283
}
262
284
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
+
263
313
async fn create_and_push_bindle ( & self , buildinfo : Option < BuildMetadata > ) -> Result < Id > {
264
314
let source_dir = crate :: app_dir ( & self . app ) ?;
265
315
let bindle_connection_info = spin_publish:: BindleConnectionInfo :: new (
0 commit comments