Files
BrowserOS/packages/browseros/build/cli/release.py
Nikhil 8cbfbf7769 fix: sparkle build flag (#260)
* fix: enable sparkle build flag

* feat: cli new apply changed command for dev cli

* fix: sparkle patch fix

* fix: dev cli changed minor fix

* fix: dev cli - for download add --output support
2025-12-19 10:27:56 -08:00

214 lines
6.7 KiB
Python
Generated

#!/usr/bin/env python3
"""Release CLI - Modular release automation for BrowserOS"""
from pathlib import Path
from typing import Optional
import typer
from ..common.context import Context
from ..common.module import ValidationError
from ..common.utils import log_info, log_error, log_success
from ..modules.release import (
AVAILABLE_MODULES,
ListModule,
AppcastModule,
GithubModule,
PublishModule,
DownloadModule,
)
app = typer.Typer(
help="Release automation commands",
pretty_exceptions_enable=False,
pretty_exceptions_show_locals=False,
)
# GitHub sub-app for complex operations
github_app = typer.Typer(
help="GitHub release operations",
pretty_exceptions_enable=False,
pretty_exceptions_show_locals=False,
)
app.add_typer(github_app, name="github")
def create_release_context(
version: str,
repo: Optional[str] = None,
) -> Context:
"""Create Context for release operations"""
ctx = Context(
root_dir=Path.cwd(),
chromium_src=Path.cwd(), # Not used for release ops
architecture="",
build_type="release",
)
ctx.release_version = version
ctx.github_repo = repo or ""
return ctx
def execute_module(ctx: Context, module) -> None:
"""Execute a single module with validation"""
try:
module.validate(ctx)
module.execute(ctx)
except ValidationError as e:
log_error(f"Validation failed: {e}")
raise typer.Exit(1)
except Exception as e:
log_error(f"Module failed: {e}")
raise typer.Exit(1)
@app.callback(invoke_without_command=True)
def main(
ctx: typer.Context,
version: Optional[str] = typer.Option(
None, "--version", "-v", help="Version to operate on (e.g., 0.31.0)"
),
list_artifacts: bool = typer.Option(
False, "--list", "-l", help="List artifacts for version from R2"
),
appcast: bool = typer.Option(
False, "--appcast", "-a", help="Generate appcast XML snippets"
),
publish: bool = typer.Option(
False, "--publish", "-p", help="Publish to download/ paths (make live)"
),
download: bool = typer.Option(
False, "--download", "-d", help="Download artifacts to temp directory"
),
os_filter: Optional[str] = typer.Option(
None, "--os", help="Filter by OS: macos, windows, linux"
),
output: Optional[Path] = typer.Option(
None, "--output", "-o", help="Output directory for downloads (default: temp dir)"
),
show_modules: bool = typer.Option(
False, "--show-modules", help="Show available modules and exit"
),
):
"""Release automation for BrowserOS
\b
Quick Operations (Flags):
browseros release --list # List all available versions
browseros release --list --version 0.31.0 # List artifacts for version
browseros release --version 0.31.0 --appcast # Generate appcast XML
browseros release --version 0.31.0 --publish # Publish to download/ paths
browseros release --version 0.31.0 --download # Download all artifacts
browseros release --version 0.31.0 --download --os macos # Download macOS only
browseros release --version 0.31.0 --download --output ./downloads # Custom dir
\b
GitHub Release (Sub-command):
browseros release github create --version 0.31.0
browseros release github create --version 0.31.0 --publish
\b
Show Available Modules:
browseros release --show-modules
"""
if show_modules:
log_info("\n📦 Available Release Modules:")
log_info("-" * 50)
for name, module_class in AVAILABLE_MODULES.items():
log_info(f" {name}: {module_class.description}")
log_info("-" * 50)
return
# If subcommand invoked, let it handle things
if ctx.invoked_subcommand is not None:
return
# Check if any flags specified
has_flags = any([list_artifacts, appcast, publish, download])
if not has_flags:
typer.echo(
"Error: Specify a flag (--list, --appcast, --publish, --download) or use a sub-command\n"
)
typer.echo("Use --help for usage information")
typer.echo("Use --show-modules to see available modules")
raise typer.Exit(1)
# Version is required for all flags except --list
requires_version = any([appcast, publish, download])
if requires_version and not version:
log_error("--version is required for this operation")
raise typer.Exit(1)
# Create context
release_ctx = create_release_context(version or "")
# Execute requested modules
if list_artifacts:
if version:
log_info(f"📋 Listing artifacts for v{version}")
else:
log_info("📋 Listing all available releases")
execute_module(release_ctx, ListModule())
if appcast:
log_info(f"📝 Generating appcast for v{version}")
execute_module(release_ctx, AppcastModule())
if publish:
log_info(f"🚀 Publishing v{version} to download/ paths")
execute_module(release_ctx, PublishModule())
if download:
log_info(f"📥 Downloading artifacts for v{version}")
execute_module(release_ctx, DownloadModule(os_filter=os_filter, output_dir=output))
@github_app.command("create")
def github_create(
version: str = typer.Option(
..., "--version", "-v", help="Version to release (e.g., 0.31.0)"
),
draft: bool = typer.Option(
True, "--draft/--publish", help="Create as draft (default: draft)"
),
repo: Optional[str] = typer.Option(
None, "--repo", "-r", help="GitHub repo (owner/name)"
),
skip_upload: bool = typer.Option(
False, "--skip-upload", help="Skip uploading artifacts to GitHub"
),
title: Optional[str] = typer.Option(
None, "--title", "-t", help="Release title (default: v{version})"
),
publish_to_download: bool = typer.Option(
False, "--publish", "-p", help="Also publish to download/ paths after creating release"
),
):
"""Create GitHub release from R2 artifacts
\b
Examples:
browseros release github create --version 0.31.0
browseros release github create --version 0.31.0 --publish # Also publish to download/
browseros release github create --version 0.31.0 --no-draft # Create published release
"""
ctx = create_release_context(version, repo)
log_info(f"🚀 Creating GitHub release for v{version}")
module = GithubModule(
draft=draft,
skip_upload=skip_upload,
title=title,
)
execute_module(ctx, module)
if publish_to_download:
log_info(f"\n🚀 Publishing v{version} to download/ paths")
execute_module(ctx, PublishModule())
if __name__ == "__main__":
app()