@@ -79,6 +79,46 @@ def _print_step(step_num: int, total: int, description: str) -> None:
7979 print ("-" * 80 )
8080
8181
82+ def _run_command (
83+ cmd : list [str ],
84+ description : str ,
85+ error_message : str ,
86+ success_message : Optional [str ] = None ,
87+ capture_output : bool = True ,
88+ ** kwargs ,
89+ ) -> subprocess .CompletedProcess :
90+ """Run a subprocess command with consistent error handling and output.
91+
92+ Args:
93+ cmd: Command and arguments as list
94+ description: What we're doing (printed before running)
95+ error_message: Error message prefix if command fails
96+ success_message: Optional success message (printed after if provided)
97+ capture_output: Whether to capture stdout/stderr (default True)
98+ **kwargs: Additional arguments to pass to subprocess.run
99+
100+ Returns:
101+ CompletedProcess instance
102+ """
103+ if description :
104+ print (f" { description } " )
105+
106+ try :
107+ result = subprocess .run (
108+ cmd ,
109+ check = True ,
110+ capture_output = capture_output ,
111+ text = True ,
112+ ** kwargs ,
113+ )
114+ if success_message :
115+ print (f" ✓ { success_message } " )
116+ return result
117+ except subprocess .CalledProcessError as e :
118+ error_detail = f": { e .stderr } " if capture_output and e .stderr else ""
119+ _fail (f"{ error_message } { error_detail } " )
120+
121+
82122# ============================================================================
83123# Environment Validation
84124# ============================================================================
@@ -200,14 +240,13 @@ def _sign_artifact(artifact_path: str) -> tuple[str, str]:
200240 checksum_path = f"{ artifact_path } .sha512"
201241
202242 # GPG signature
203- try :
204- subprocess .run (
205- ["gpg" , "--armor" , "--output" , signature_path , "--detach-sig" , artifact_path ],
206- check = True ,
207- )
208- print (f" ✓ Created GPG signature: { signature_path } " )
209- except subprocess .CalledProcessError as e :
210- _fail (f"Error signing artifact: { e } " )
243+ _run_command (
244+ ["gpg" , "--armor" , "--output" , signature_path , "--detach-sig" , artifact_path ],
245+ description = "" ,
246+ error_message = "Error signing artifact" ,
247+ capture_output = False ,
248+ )
249+ print (f" ✓ Created GPG signature: { signature_path } " )
211250
212251 # SHA512 checksum
213252 sha512_hash = hashlib .sha512 ()
@@ -306,22 +345,21 @@ def _create_git_archive(version: str, rc_num: str, output_dir: str = "dist") ->
306345 archive_path = os .path .join (output_dir , archive_name )
307346 prefix = f"apache-burr-{ version } -incubating/"
308347
309- try :
310- subprocess .run (
311- [
312- "git" ,
313- "archive" ,
314- "HEAD" ,
315- f"--prefix={ prefix } " ,
316- "--format=tar.gz" ,
317- "--output" ,
318- archive_path ,
319- ],
320- check = True ,
321- )
322- print (f" ✓ Created git archive: { archive_path } " )
323- except subprocess .CalledProcessError as e :
324- _fail (f"Error creating git archive: { e } " )
348+ _run_command (
349+ [
350+ "git" ,
351+ "archive" ,
352+ "HEAD" ,
353+ f"--prefix={ prefix } " ,
354+ "--format=tar.gz" ,
355+ "--output" ,
356+ archive_path ,
357+ ],
358+ description = "" ,
359+ error_message = "Error creating git archive" ,
360+ capture_output = False ,
361+ )
362+ print (f" ✓ Created git archive: { archive_path } " )
325363
326364 file_size = os .path .getsize (archive_path )
327365 print (f" ✓ Archive size: { file_size :,} bytes" )
@@ -359,20 +397,15 @@ def _build_sdist_from_git(version: str, output_dir: str = "dist") -> str:
359397 _remove_ui_build_artifacts ()
360398 _check_git_working_tree ()
361399
362- print (" Running flit build --format sdist..." )
363- try :
364- env = os .environ .copy ()
365- env ["FLIT_USE_VCS" ] = "0"
366- subprocess .run (
367- ["flit" , "build" , "--format" , "sdist" ],
368- env = env ,
369- capture_output = True ,
370- text = True ,
371- check = True ,
372- )
373- print (" ✓ flit sdist created successfully" )
374- except subprocess .CalledProcessError as e :
375- _fail (f"Failed to build sdist: { e .stderr } " )
400+ env = os .environ .copy ()
401+ env ["FLIT_USE_VCS" ] = "0"
402+ _run_command (
403+ ["flit" , "build" , "--format" , "sdist" ],
404+ description = "Running flit build --format sdist..." ,
405+ error_message = "Failed to build sdist" ,
406+ success_message = "flit sdist created successfully" ,
407+ env = env ,
408+ )
376409
377410 # Find and rename sdist
378411 expected_pattern = f"dist/apache_burr-{ version .lower ()} .tar.gz"
@@ -401,28 +434,46 @@ def _build_sdist_from_git(version: str, output_dir: str = "dist") -> str:
401434
402435
403436def _build_ui_artifacts () -> None :
404- """Build UI artifacts using burr-admin-build-ui."""
437+ """Build UI artifacts (npm build + copy to burr/tracking/server/build).
438+
439+ This replicates the logic from burr.cli.__main__.run_build_ui_bash_commands()
440+ without requiring burr to be installed.
441+ """
405442 print ("Building UI artifacts..." )
406443
444+ ui_source_dir = "telemetry/ui"
407445 ui_build_dir = "burr/tracking/server/build"
408446
409447 # Clean existing UI build
410448 if os .path .exists (ui_build_dir ):
411449 shutil .rmtree (ui_build_dir )
412450
413- # Check for burr-admin-build-ui
414- if shutil .which ("burr-admin-build-ui" ) is None :
415- _fail ("burr-admin-build-ui not found. Install with: pip install -e .[cli]" )
451+ # Install npm dependencies
452+ _run_command (
453+ ["npm" , "install" , "--prefix" , ui_source_dir ],
454+ description = "Installing npm dependencies..." ,
455+ error_message = "npm install failed" ,
456+ success_message = "npm dependencies installed" ,
457+ )
458+
459+ # Build UI with npm
460+ _run_command (
461+ ["npm" , "run" , "build" , "--prefix" , ui_source_dir ],
462+ description = "Building UI with npm..." ,
463+ error_message = "npm build failed" ,
464+ success_message = "npm build completed" ,
465+ )
416466
417- # Build UI
418- env = os .environ .copy ()
419- env ["BURR_PROJECT_ROOT" ] = os .getcwd ()
467+ # Copy build artifacts
468+ print (" Copying build artifacts..." )
469+ os .makedirs (ui_build_dir , exist_ok = True )
470+ ui_output = os .path .join (ui_source_dir , "build" )
420471
421472 try :
422- subprocess . run ([ "burr-admin-build-ui" ], check = True , env = env , capture_output = True )
423- print (" ✓ UI artifacts built successfully " )
424- except subprocess . CalledProcessError as e :
425- _fail (f"Error building UI : { e } " )
473+ shutil . copytree ( ui_output , ui_build_dir , dirs_exist_ok = True )
474+ print (" ✓ Build artifacts copied " )
475+ except Exception as e :
476+ _fail (f"Failed to copy build artifacts : { e } " )
426477
427478 # Verify
428479 if not os .path .exists (ui_build_dir ) or not os .listdir (ui_build_dir ):
@@ -505,13 +556,13 @@ def _build_wheel_from_current_dir(version: str, output_dir: str = "dist") -> str
505556 env = os .environ .copy ()
506557 env ["FLIT_USE_VCS" ] = "0"
507558
508- subprocess . run (
559+ _run_command (
509560 ["flit" , "build" , "--format" , "wheel" ],
561+ description = "" ,
562+ error_message = "Wheel build failed" ,
563+ success_message = "Wheel built successfully" ,
510564 env = env ,
511- check = True ,
512- capture_output = True ,
513565 )
514- print (" ✓ Wheel built successfully" )
515566
516567 # Find the wheel
517568 wheel_pattern = f"dist/apache_burr-{ version } *.whl"
@@ -525,8 +576,6 @@ def _build_wheel_from_current_dir(version: str, output_dir: str = "dist") -> str
525576
526577 return wheel_path
527578
528- except subprocess .CalledProcessError as e :
529- _fail (f"Wheel build failed: { e } " )
530579 finally :
531580 # Always restore symlinks
532581 if copied :
@@ -662,18 +711,14 @@ def _generate_vote_email(version: str, rc_num: str, svn_url: str) -> str:
662711The Git tag to be voted upon is:
663712{ tag }
664713
665- Release artifacts are signed with your GPG key. The KEYS file is available at:
714+ Release artifacts are signed with the release manager's GPG key. The KEYS file is available at:
666715https://downloads.apache.org/incubator/{ PROJECT_SHORT_NAME } /KEYS
667716
668717Please download, verify, and test the release candidate.
669718
670- Some ideas to verify the release:
671- 1. Build from source - see README in scripts/ directory for instructions
672- 2. Install the wheel using pip to test functionality
673- 3. Run license verification using the verify_apache_artifacts.py script or manually check
674- - Verify checksums and signatures match
675- - Check LICENSE/NOTICE files are present
676- - Ensure all source files have Apache headers
719+ For detailed step-by-step instructions on how to verify this release, please see the
720+ "For Voters: Verifying a Release" section in the scripts/README.md file within the
721+ source archive.
677722
678723The vote will run for a minimum of 72 hours.
679724Please vote:
0 commit comments