@@ -591,6 +591,7 @@ public function import( array $bundle, ?string $new_slug = null, int $owner_id =
591591 $ pipeline_id_map = array (); // old_id => new_id.
592592 foreach ( $ bundle ['pipelines ' ] ?? array () as $ pipeline_data ) {
593593 $ old_id = (int ) ( $ pipeline_data ['original_id ' ] ?? 0 );
594+ $ pipeline_config = is_array ( $ pipeline_data ['pipeline_config ' ] ?? null ) ? $ pipeline_data ['pipeline_config ' ] : array ();
594595 $ portable_slug = PortableSlug::normalize (
595596 (string ) ( $ pipeline_data ['portable_slug ' ] ?? ( $ pipeline_data ['pipeline_name ' ] ?? 'pipeline ' ) ),
596597 'pipeline '
@@ -617,25 +618,27 @@ public function import( array $bundle, ?string $new_slug = null, int $owner_id =
617618
618619 if ( $ existing_pipeline ) {
619620 $ new_pipeline_id = (int ) $ existing_pipeline ['pipeline_id ' ];
620- $ this ->pipelines_repo ->update_pipeline (
621- $ new_pipeline_id ,
622- array (
623- 'pipeline_name ' => $ pipeline_data ['pipeline_name ' ],
624- 'pipeline_config ' => $ pipeline_data ['pipeline_config ' ] ?? array (),
625- 'portable_slug ' => $ portable_slug ,
626- )
627- );
628621 } else {
629622 $ new_pipeline_id = $ this ->pipelines_repo ->create_pipeline ( array (
630623 'pipeline_name ' => $ pipeline_data ['pipeline_name ' ],
631- 'pipeline_config ' => $ pipeline_data [ ' pipeline_config ' ] ?? array () ,
624+ 'pipeline_config ' => $ pipeline_config ,
632625 'portable_slug ' => $ portable_slug ,
633626 'agent_id ' => $ agent_id ,
634627 'user_id ' => $ owner_id ,
635628 ) );
636629 }
637630
638631 if ( $ new_pipeline_id ) {
632+ $ pipeline_config = $ this ->remap_pipeline_step_ids ( $ pipeline_config , $ old_id , (int ) $ new_pipeline_id );
633+ $ this ->pipelines_repo ->update_pipeline (
634+ (int ) $ new_pipeline_id ,
635+ array (
636+ 'pipeline_name ' => $ pipeline_data ['pipeline_name ' ],
637+ 'pipeline_config ' => $ pipeline_config ,
638+ 'portable_slug ' => $ portable_slug ,
639+ )
640+ );
641+
639642 $ pipeline_id_map [ $ old_id ] = (int ) $ new_pipeline_id ;
640643 $ artifact_records [ $ artifact_key ] = $ this ->bundle_artifact_record (
641644 $ bundle_metadata ,
@@ -677,12 +680,16 @@ public function import( array $bundle, ?string $new_slug = null, int $owner_id =
677680 $ scheduling ['interval ' ] = 'manual ' ;
678681 }
679682
680- $ flow_config = $ flow_data ['flow_config ' ] ?? array ();
681-
682- // Remap pipeline step IDs inside flow_config.
683- $ flow_config = $ this ->remap_flow_step_ids ( $ flow_config , $ old_pipeline_id , $ new_pipeline_id );
683+ $ flow_config = is_array ( $ flow_data ['flow_config ' ] ?? null ) ? $ flow_data ['flow_config ' ] : array ();
684684 $ existing_flow = $ this ->flows_repo ->get_by_portable_slug ( (int ) $ new_pipeline_id , $ portable_slug );
685- $ flow_payload_source = array_merge ( $ flow_data , array ( 'flow_config ' => $ flow_config ) );
685+ $ flow_payload_source = array_merge (
686+ $ flow_data ,
687+ array (
688+ 'flow_config ' => $ existing_flow
689+ ? $ this ->remap_flow_step_ids ( $ flow_config , $ old_pipeline_id , (int ) $ new_pipeline_id , (int ) $ existing_flow ['flow_id ' ] )
690+ : $ flow_config ,
691+ )
692+ );
686693 $ payload = $ this ->flow_artifact_payload ( $ flow_payload_source , $ portable_slug );
687694
688695 if (
@@ -702,6 +709,7 @@ public function import( array $bundle, ?string $new_slug = null, int $owner_id =
702709
703710 if ( $ existing_flow ) {
704711 $ new_flow_id = (int ) $ existing_flow ['flow_id ' ];
712+ $ flow_config = $ this ->remap_flow_step_ids ( $ flow_config , $ old_pipeline_id , (int ) $ new_pipeline_id , $ new_flow_id );
705713 $ flow_config = $ this ->preserve_runtime_queue_fields ( $ flow_config , $ existing_flow ['flow_config ' ] ?? array () );
706714 $ this ->flows_repo ->update_flow (
707715 $ new_flow_id ,
@@ -715,12 +723,24 @@ public function import( array $bundle, ?string $new_slug = null, int $owner_id =
715723 $ new_flow_id = $ this ->flows_repo ->create_flow ( array (
716724 'pipeline_id ' => $ new_pipeline_id ,
717725 'flow_name ' => $ flow_data ['flow_name ' ],
718- 'flow_config ' => $ flow_config ,
726+ 'flow_config ' => array () ,
719727 'scheduling_config ' => $ scheduling ,
720728 'portable_slug ' => $ portable_slug ,
721729 'agent_id ' => $ agent_id ,
722730 'user_id ' => $ owner_id ,
723731 ) );
732+
733+ if ( $ new_flow_id ) {
734+ $ flow_config = $ this ->remap_flow_step_ids ( $ flow_config , $ old_pipeline_id , (int ) $ new_pipeline_id , (int ) $ new_flow_id );
735+ $ this ->flows_repo ->update_flow (
736+ (int ) $ new_flow_id ,
737+ array (
738+ 'flow_name ' => $ flow_data ['flow_name ' ],
739+ 'flow_config ' => $ flow_config ,
740+ 'portable_slug ' => $ portable_slug ,
741+ )
742+ );
743+ }
724744 }
725745
726746 if ( $ new_flow_id ) {
@@ -1197,38 +1217,82 @@ private function write_flow_memory_files( int $pipeline_id, int $flow_id, array
11971217 }
11981218 }
11991219
1220+ /**
1221+ * Remap pipeline step IDs inside a pipeline config.
1222+ *
1223+ * @param array $pipeline_config Pipeline config.
1224+ * @param int $old_pipeline_id Original pipeline ID.
1225+ * @param int $new_pipeline_id New pipeline ID.
1226+ * @return array Updated pipeline config.
1227+ */
1228+ private function remap_pipeline_step_ids ( array $ pipeline_config , int $ old_pipeline_id , int $ new_pipeline_id ): array {
1229+ $ remapped = array ();
1230+
1231+ foreach ( $ pipeline_config as $ pipeline_step_id => $ step_config ) {
1232+ $ new_pipeline_step_id = $ this ->remap_step_id_prefix ( (string ) $ pipeline_step_id , $ old_pipeline_id , $ new_pipeline_id );
1233+ if ( is_array ( $ step_config ) ) {
1234+ $ step_config ['pipeline_step_id ' ] = $ new_pipeline_step_id ;
1235+ }
1236+
1237+ $ remapped [ $ new_pipeline_step_id ] = $ step_config ;
1238+ }
1239+
1240+ return $ remapped ;
1241+ }
1242+
12001243 /**
12011244 * Remap pipeline step IDs inside a flow config.
12021245 *
1203- * Pipeline step IDs have the format {pipeline_id}_{uuid}. When importing,
1204- * the pipeline ID changes, so we need to rewrite these keys.
1246+ * Pipeline step IDs have the format {pipeline_id}_{uuid}. Flow step IDs add
1247+ * the installed flow ID as the final suffix. Bundle-local IDs must be
1248+ * rewritten after install or runtime lookups resolve the wrong pipeline.
12051249 *
1206- * @param array $flow_config Flow config.
1207- * @param int $old_pipeline_id Original pipeline ID.
1208- * @param int $new_pipeline_id New pipeline ID.
1250+ * @param array $flow_config Flow config.
1251+ * @param int $old_pipeline_id Original pipeline ID.
1252+ * @param int $new_pipeline_id New pipeline ID.
1253+ * @param int $new_flow_id New flow ID.
12091254 * @return array Updated flow config.
12101255 */
1211- private function remap_flow_step_ids ( array $ flow_config , int $ old_pipeline_id , int $ new_pipeline_id ): array {
1212- if ( $ old_pipeline_id === $ new_pipeline_id ) {
1213- return $ flow_config ;
1214- }
1215-
1256+ private function remap_flow_step_ids ( array $ flow_config , int $ old_pipeline_id , int $ new_pipeline_id , int $ new_flow_id ): array {
12161257 $ remapped = array ();
1217- $ prefix = $ old_pipeline_id . '_ ' ;
12181258
1219- foreach ( $ flow_config as $ key => $ value ) {
1220- // Remap step ID keys that start with old pipeline ID.
1221- if ( is_string ( $ key ) && str_starts_with ( $ key , $ prefix ) ) {
1222- $ new_key = $ new_pipeline_id . '_ ' . substr ( $ key , strlen ( $ prefix ) );
1223- $ remapped [ $ new_key ] = $ value ;
1224- } else {
1225- $ remapped [ $ key ] = $ value ;
1259+ foreach ( $ flow_config as $ flow_step_id => $ step_config ) {
1260+ $ pipeline_step_id = is_array ( $ step_config ) && is_string ( $ step_config ['pipeline_step_id ' ] ?? null )
1261+ ? $ step_config ['pipeline_step_id ' ]
1262+ : preg_replace ( '/_\d+$/ ' , '' , (string ) $ flow_step_id );
1263+ $ pipeline_step_id = $ this ->remap_step_id_prefix ( (string ) $ pipeline_step_id , $ old_pipeline_id , $ new_pipeline_id );
1264+ $ new_flow_step_id = $ pipeline_step_id . '_ ' . $ new_flow_id ;
1265+
1266+ if ( is_array ( $ step_config ) ) {
1267+ $ step_config ['pipeline_step_id ' ] = $ pipeline_step_id ;
1268+ $ step_config ['pipeline_id ' ] = $ new_pipeline_id ;
1269+ $ step_config ['flow_id ' ] = $ new_flow_id ;
1270+ $ step_config ['flow_step_id ' ] = $ new_flow_step_id ;
12261271 }
1272+
1273+ $ remapped [ $ new_flow_step_id ] = $ step_config ;
12271274 }
12281275
12291276 return $ remapped ;
12301277 }
12311278
1279+ /**
1280+ * Remap the pipeline ID prefix of a step ID.
1281+ *
1282+ * @param string $step_id Step ID.
1283+ * @param int $old_pipeline_id Original pipeline ID.
1284+ * @param int $new_pipeline_id New pipeline ID.
1285+ * @return string Remapped step ID.
1286+ */
1287+ private function remap_step_id_prefix ( string $ step_id , int $ old_pipeline_id , int $ new_pipeline_id ): string {
1288+ $ prefix = $ old_pipeline_id . '_ ' ;
1289+ if ( $ old_pipeline_id === $ new_pipeline_id || ! str_starts_with ( $ step_id , $ prefix ) ) {
1290+ return $ step_id ;
1291+ }
1292+
1293+ return $ new_pipeline_id . '_ ' . substr ( $ step_id , strlen ( $ prefix ) );
1294+ }
1295+
12321296 /**
12331297 * Serialize a bundle to JSON string.
12341298 *
0 commit comments