@@ -55,12 +55,13 @@ mod tests {
5555 artifact_requires_component_extract_command, resolve_preflight_artifact_path,
5656 validate_predeploy_artifact_version,
5757 } ;
58- use super :: prepare:: failed_component_deploy_result;
58+ use super :: prepare:: { failed_component_deploy_result, prepare_component_deploy } ;
5959 use super :: release_plan:: { release_artifact_plan, should_try_download_release_artifact} ;
6060 use super :: strategies:: cleanup_deploy_build_artifact;
6161 use super :: { bound_captured_read, ReleaseArtifactPlan , ARTIFACT_VERSION_READ_LIMIT_BYTES } ;
62- use crate :: core:: component:: { ArtifactInput , Component , VersionTarget } ;
63- use crate :: core:: deploy:: types:: DeployConfig ;
62+ use crate :: core:: component:: { ArtifactInput , Component , ComponentScriptsConfig , VersionTarget } ;
63+ use crate :: core:: deploy:: types:: { DeployConfig , PreparedDeployArtifact } ;
64+ use crate :: core:: project:: Project ;
6465 use std:: io:: Write ;
6566 use std:: process:: Command ;
6667
@@ -116,6 +117,70 @@ mod tests {
116117 assert_eq ! ( result. error. as_deref( ) , Some ( "deploy failed" ) ) ;
117118 }
118119
120+ #[ test]
121+ fn prepared_artifact_skips_local_build_invocation ( ) {
122+ let temp = tempfile:: tempdir ( ) . expect ( "tempdir" ) ;
123+ let durable_artifact = temp. path ( ) . join ( "release.tar.gz" ) ;
124+ let build_counter = temp. path ( ) . join ( "build-count" ) ;
125+ std:: fs:: write ( & durable_artifact, "release payload" ) . expect ( "artifact" ) ;
126+ let mut component = Component {
127+ id : "fixture" . to_string ( ) ,
128+ local_path : temp. path ( ) . display ( ) . to_string ( ) ,
129+ remote_path : "plugins/fixture" . to_string ( ) ,
130+ build_artifact : Some ( "build/fixture.tar.gz" . to_string ( ) ) ,
131+ extract_command : Some ( "tar -xzf {{artifact}}" . to_string ( ) ) ,
132+ ..Component :: default ( )
133+ } ;
134+ component. scripts = Some ( ComponentScriptsConfig {
135+ build : vec ! [ format!( "printf build >> {}" , build_counter. display( ) ) ] ,
136+ ..ComponentScriptsConfig :: default ( )
137+ } ) ;
138+ let config = DeployConfig {
139+ component_ids : vec ! [ component. id. clone( ) ] ,
140+ all : false ,
141+ outdated : false ,
142+ behind_upstream : false ,
143+ dry_run : false ,
144+ check : false ,
145+ force : true ,
146+ skip_build : true ,
147+ keep_deps : false ,
148+ skip_deps_hydration : false ,
149+ expected_version : Some ( "1.2.3" . to_string ( ) ) ,
150+ no_pull : true ,
151+ head : false ,
152+ requested_ref : None ,
153+ tagged : false ,
154+ prepared_artifact : Some ( PreparedDeployArtifact {
155+ component_id : component. id . clone ( ) ,
156+ path : "build/fixture.tar.gz" . to_string ( ) ,
157+ durable_path : durable_artifact. display ( ) . to_string ( ) ,
158+ size_bytes : 15 ,
159+ sha256 : crate :: core:: deploy:: sha256_file ( & durable_artifact) . expect ( "sha" ) ,
160+ version : "1.2.3" . to_string ( ) ,
161+ tag : "v1.2.3" . to_string ( ) ,
162+ source_commit : "0123456789abcdef" . to_string ( ) ,
163+ } ) ,
164+ } ;
165+
166+ let prepared = prepare_component_deploy (
167+ & component,
168+ & config,
169+ "/srv/site" ,
170+ & Project :: default ( ) ,
171+ Some ( "1.2.3" . to_string ( ) ) ,
172+ None ,
173+ None ,
174+ )
175+ . expect ( "prepared artifact should pass local preflight" ) ;
176+
177+ assert_eq ! ( prepared. artifact_path, Some ( durable_artifact) ) ;
178+ assert ! (
179+ !build_counter. exists( ) ,
180+ "prepared deployment must not build"
181+ ) ;
182+ }
183+
119184 #[ test]
120185 fn archive_artifact_without_component_extract_is_allowed_by_deploy_override ( ) {
121186 assert ! ( !artifact_requires_component_extract_command(
@@ -165,6 +230,7 @@ mod tests {
165230 head : false ,
166231 requested_ref : None ,
167232 tagged : false ,
233+ prepared_artifact : None ,
168234 } ;
169235
170236 let result = resolve_preflight_artifact_path (
@@ -225,6 +291,7 @@ mod tests {
225291 head : true ,
226292 requested_ref : None ,
227293 tagged : false ,
294+ prepared_artifact : None ,
228295 } ;
229296
230297 assert ! ( !should_try_download_release_artifact(
@@ -258,6 +325,7 @@ mod tests {
258325 head : false ,
259326 requested_ref : None ,
260327 tagged : true ,
328+ prepared_artifact : None ,
261329 } ;
262330
263331 assert ! ( !should_try_download_release_artifact(
@@ -302,6 +370,7 @@ mod tests {
302370 head : false ,
303371 requested_ref : None ,
304372 tagged : false ,
373+ prepared_artifact : None ,
305374 } ;
306375
307376 assert ! ( should_try_download_release_artifact(
@@ -346,6 +415,7 @@ mod tests {
346415 head : false ,
347416 requested_ref : None ,
348417 tagged : false ,
418+ prepared_artifact : None ,
349419 } ;
350420
351421 assert ! ( should_try_download_release_artifact(
@@ -381,6 +451,7 @@ mod tests {
381451 head : false ,
382452 requested_ref : None ,
383453 tagged : false ,
454+ prepared_artifact : None ,
384455 } ;
385456
386457 match release_artifact_plan ( & component, & config, false , false ) {
@@ -429,6 +500,7 @@ mod tests {
429500 head : false ,
430501 requested_ref : None ,
431502 tagged : false ,
503+ prepared_artifact : None ,
432504 } ;
433505
434506 assert ! ( should_try_download_release_artifact(
@@ -502,6 +574,7 @@ mod tests {
502574 head : true ,
503575 requested_ref : None ,
504576 tagged : false ,
577+ prepared_artifact : None ,
505578 } ;
506579
507580 let artifact = resolve_preflight_artifact_path (
0 commit comments