Skip to content

Commit 5446cdb

Browse files
elijahbenizzyElijah ben Izzy
andauthored
Script fixes for release (#628)
* Updates to clean up upload file names, upload everything * WIP * WIP * Adds instructions on voter flow * Adds forgotten license * Adds voter flow instructions to README/script --------- Co-authored-by: Elijah ben Izzy <ebenizzy@salesforce.com>
1 parent 21df6e5 commit 5446cdb

File tree

4 files changed

+163
-67
lines changed

4 files changed

+163
-67
lines changed

burr/cli/__main__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ def cli():
132132
pass
133133

134134

135-
def _build_ui():
135+
def run_build_ui_bash_commands():
136+
"""Execute the bash commands to build UI artifacts."""
136137
cmd = "npm install --prefix telemetry/ui"
137138
_command(cmd, capture_output=False)
138139
cmd = "npm run build --prefix telemetry/ui"
@@ -146,12 +147,13 @@ def _build_ui():
146147
_command(cmd, capture_output=False)
147148

148149

149-
@cli.command()
150+
@cli.command(name="build-ui")
150151
def build_ui():
152+
"""Build the UI artifacts from source."""
151153
git_root = _get_git_root()
152154
logger.info("UI build: using project root %s", git_root)
153155
with cd(git_root):
154-
_build_ui()
156+
run_build_ui_bash_commands()
155157

156158

157159
BACKEND_MODULES = {
@@ -246,7 +248,7 @@ def build_and_publish(prod: bool, no_wipe_dist: bool):
246248
git_root = _get_git_root()
247249
with cd(git_root):
248250
logger.info("Building UI -- this may take a bit...")
249-
_build_ui()
251+
build_ui()
250252
logger.info("Built UI!")
251253
if not no_wipe_dist:
252254
logger.info("Wiping dist/ directory for a clean publish.")

docs/_templates/page.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
120
{% extends "!page.html" %}
221

322
{% block extrahead %}

scripts/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,36 @@ python scripts/apache_release.py all 0.41.0 0 your_apache_id --no-upload
9999

100100
Output: `dist/` directory with tar.gz (archive + sdist), whl, plus .asc and .sha512 files. Install from the whl file to test it out after runnig the `wheel` subcommand.
101101

102+
## For Voters: Verifying a Release
103+
104+
If you're voting on a release, follow these steps to verify the release candidate:
105+
106+
### Quick Start
107+
108+
```bash
109+
# 1. Download and extract the source archive
110+
wget https://dist.apache.org/repos/dist/dev/incubator/burr/{VERSION}-incubating-RC{N}/apache-burr-{VERSION}-incubating.tar.gz
111+
tar -xzf apache-burr-{VERSION}-incubating.tar.gz
112+
cd apache-burr-{VERSION}-incubating/
113+
114+
# 2. Verify signatures and checksums
115+
python scripts/verify_apache_artifacts.py signatures
116+
117+
# 3. Install build dependencies
118+
pip install flit
119+
120+
# 4. Build the wheel from source
121+
python scripts/apache_release.py wheel {VERSION} {RC_NUM}
122+
123+
# 5. Install and run the wheel
124+
pip install "dist/apache_burr-{VERSION}-py3-none-any.whl[learn]"
125+
burr
126+
```
127+
128+
You can run tests, etc... from here
129+
130+
See the "Verification" section below for more detailed verification steps.
131+
102132
## Verification
103133

104134
Validate artifacts before uploading or voting. Checks GPG signatures, SHA512 checksums, archive integrity, and license compliance with Apache RAT. The `list-contents` command is useful for inspecting what's actually packaged in each artifact.

scripts/apache_release.py

Lines changed: 108 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -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

403436
def _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:
662711
The 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:
666715
https://downloads.apache.org/incubator/{PROJECT_SHORT_NAME}/KEYS
667716
668717
Please 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
678723
The vote will run for a minimum of 72 hours.
679724
Please vote:

0 commit comments

Comments
 (0)