@@ -243,6 +243,79 @@ def test_push_pipeline_with_non_existing_code(
243243 self .assertEqual (result .exit_code , 1 )
244244 self .assertIn ("❌ Pipeline with code 'non_existing_code' not found." , result .output )
245245
246+ @patch ("openhexa.cli.api.graphql" )
247+ @patch ("openhexa.cli.cli.get_pipeline" )
248+ @patch ("openhexa.cli.cli.get_pipelines_pages" )
249+ @patch ("openhexa.cli.cli.upload_pipeline" )
250+ @patch ("openhexa.cli.cli.create_pipeline" )
251+ @patch .dict (os .environ , {"HEXA_API_URL" : "https://www.bluesquarehub.com/" , "HEXA_WORKSPACE" : "workspace" })
252+ def test_push_pipeline_creates_new_atomically (
253+ self ,
254+ mock_create_pipeline ,
255+ mock_upload_pipeline ,
256+ mock_get_pipelines_pages ,
257+ mock_get_pipeline ,
258+ mock_graphql ,
259+ ):
260+ """When the user picks 'Create a new pipeline', a single atomic create_pipeline call happens."""
261+ with self .runner .isolated_filesystem () as tmp :
262+ with open (Path (tmp ) / python_file_name , "w" ) as f :
263+ f .write (python_code )
264+ mock_graphql .return_value = setup_graphql_response ()
265+ mock_pipeline = MagicMock (spec = Pipeline )
266+ mock_pipeline .name = pipeline_name
267+ mock_get_pipeline .return_value = mock_pipeline
268+ mock_get_pipelines_pages .return_value = {
269+ "items" : [
270+ {"name" : "Pipeline1" , "code" : "code1" },
271+ {"name" : "Pipeline2" , "code" : "code2" },
272+ ],
273+ "totalPages" : 1 , # single page so no "enter code" option appears
274+ }
275+ mock_create_pipeline .return_value = {
276+ "pipeline" : {
277+ "id" : pipeline_id ,
278+ "code" : "pipeline-1234" ,
279+ "permissions" : {"createTemplateVersion" : {"isAllowed" : False }},
280+ "template" : None ,
281+ },
282+ "pipelineVersion" : {
283+ "id" : pipeline_version_id ,
284+ "versionName" : version ,
285+ "pipeline" : {
286+ "id" : pipeline_id ,
287+ "code" : "pipeline-1234" ,
288+ "permissions" : {"createTemplateVersion" : {"isAllowed" : False }},
289+ "template" : None ,
290+ },
291+ },
292+ }
293+
294+ # choices: [P1, P2, "Create a new ...", "Cancel"] → "3" = create new
295+ # then "Y" to confirm push
296+ result = self .runner .invoke (
297+ pipelines_push ,
298+ [tmp , "--name" , version , "--description" , "first" , "--link" , "https://github.com/" ],
299+ input = "\n " .join (["3" , "Y" ]) + "\n " ,
300+ )
301+
302+ self .assertEqual (result .exit_code , 0 )
303+ self .assertTrue (mock_create_pipeline .called )
304+ self .assertFalse (mock_upload_pipeline .called , "upload_pipeline must not be called on first push" )
305+
306+ call_kwargs = mock_create_pipeline .call_args .kwargs
307+ call_args = mock_create_pipeline .call_args .args
308+ assert call_args [0 ] == pipeline_name # pipeline name (positional)
309+ assert call_kwargs ["version_name" ] == version
310+ assert call_kwargs ["version_description" ] == "first"
311+ assert call_kwargs ["version_external_link" ] == "https://github.com/"
312+
313+ self .assertIn (
314+ f"✅ New version '{ version } ' created! "
315+ "You can view the pipeline in OpenHEXA on https://www.bluesquarehub.com/workspaces/workspace/pipelines/pipeline-1234" ,
316+ result .output ,
317+ )
318+
246319 @patch ("openhexa.cli.api.graphql" )
247320 @patch ("openhexa.cli.cli.get_pipeline" )
248321 @patch ("openhexa.cli.cli.get_pipelines_pages" )
0 commit comments