mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-18 11:06:19 +00:00
* patch: fix sparkle build * fix: update browseros_server binary path after refactor * fix: sparkle + browseros server build patch * fix: build.py --prep dont apply series patches * fix: build cli -- in prep configure too * fix: cli annotate -- only add description * fix: features.yaml update for new paths * fix: more patch fixes * fix: sparkle pointer exclusion * fix: remove su-updater * fix: sparkle update notification
240 lines
6.9 KiB
Python
Generated
240 lines
6.9 KiB
Python
Generated
"""
|
|
Annotate - Create git commits organized by features from features.yaml
|
|
|
|
For each feature, checks which files have modifications and creates a commit
|
|
with the feature name and description.
|
|
"""
|
|
|
|
import yaml
|
|
from pathlib import Path
|
|
from typing import List, Tuple, Optional, Dict
|
|
|
|
from ..apply.utils import run_git_command
|
|
from ...common.context import Context
|
|
from ...common.module import CommandModule, ValidationError
|
|
from ...common.utils import log_info, log_error, log_success, log_warning
|
|
|
|
|
|
def load_features(features_file: Path) -> Dict:
|
|
"""Load features from YAML file."""
|
|
try:
|
|
with open(features_file, "r") as f:
|
|
data = yaml.safe_load(f)
|
|
return data.get("features", {})
|
|
except Exception as e:
|
|
log_error(f"Failed to load features file: {e}")
|
|
return {}
|
|
|
|
|
|
def get_modified_files(chromium_src: Path, files: List[str]) -> List[str]:
|
|
"""Get list of files that have modifications or are untracked.
|
|
|
|
Args:
|
|
chromium_src: Chromium source directory
|
|
files: List of file paths to check
|
|
|
|
Returns:
|
|
List of file paths that have modifications
|
|
"""
|
|
modified = []
|
|
|
|
for file_path in files:
|
|
full_path = chromium_src / file_path
|
|
|
|
if not full_path.exists():
|
|
continue
|
|
|
|
result = run_git_command(
|
|
["git", "status", "--porcelain", str(file_path)],
|
|
cwd=chromium_src,
|
|
)
|
|
|
|
if result.returncode == 0 and result.stdout.strip():
|
|
modified.append(file_path)
|
|
|
|
return modified
|
|
|
|
|
|
def git_add_and_commit(
|
|
chromium_src: Path, files: List[str], commit_message: str
|
|
) -> bool:
|
|
"""Add files and create commit.
|
|
|
|
Args:
|
|
chromium_src: Chromium source directory
|
|
files: List of file paths to add
|
|
commit_message: Commit message
|
|
|
|
Returns:
|
|
True if commit was created successfully
|
|
"""
|
|
# Add all specified files
|
|
for file_path in files:
|
|
result = run_git_command(
|
|
["git", "add", str(file_path)],
|
|
cwd=chromium_src,
|
|
)
|
|
if result.returncode != 0:
|
|
log_error(f"Failed to add file: {file_path}")
|
|
return False
|
|
|
|
# Create commit
|
|
result = run_git_command(
|
|
["git", "commit", "-m", commit_message],
|
|
cwd=chromium_src,
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
stderr = result.stderr or ""
|
|
if "nothing to commit" in stderr or "nothing added to commit" in stderr:
|
|
return False
|
|
log_error(f"Failed to commit: {stderr}")
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def annotate_features(
|
|
ctx: Context,
|
|
feature_filter: Optional[str] = None,
|
|
) -> Tuple[int, int]:
|
|
"""Create commits for features with modified files.
|
|
|
|
Iterates through features.yaml and creates a commit for each feature
|
|
that has modified files in the working tree.
|
|
|
|
Args:
|
|
ctx: Build context
|
|
feature_filter: If specified, only process this feature
|
|
|
|
Returns:
|
|
Tuple of (commits_created, features_skipped)
|
|
"""
|
|
features_file = ctx.get_features_yaml_path()
|
|
|
|
if not features_file.exists():
|
|
log_error(f"Features file not found: {features_file}")
|
|
return 0, 0
|
|
|
|
features = load_features(features_file)
|
|
if not features:
|
|
log_error("No features found in features.yaml")
|
|
return 0, 0
|
|
|
|
# Filter to specific feature if requested
|
|
if feature_filter:
|
|
if feature_filter not in features:
|
|
log_error(f"Feature '{feature_filter}' not found in features.yaml")
|
|
return 0, 0
|
|
features = {feature_filter: features[feature_filter]}
|
|
|
|
log_info(f"📋 Processing {len(features)} feature(s)")
|
|
log_info("=" * 60)
|
|
|
|
commits_created = 0
|
|
features_skipped = 0
|
|
|
|
for feature_name, feature_data in features.items():
|
|
description = feature_data.get("description", feature_name)
|
|
files = feature_data.get("files", [])
|
|
|
|
log_info(f"\n🔧 {feature_name}")
|
|
log_info(f" {description}")
|
|
|
|
if not files:
|
|
log_warning(" No files specified, skipping")
|
|
features_skipped += 1
|
|
continue
|
|
|
|
# Find files with modifications
|
|
modified_files = get_modified_files(ctx.chromium_src, files)
|
|
|
|
if not modified_files:
|
|
log_warning(f" No modified files ({len(files)} files checked)")
|
|
features_skipped += 1
|
|
continue
|
|
|
|
log_info(f" Found {len(modified_files)} modified file(s)")
|
|
|
|
# Create commit (use description only from features.yaml)
|
|
commit_message = description
|
|
|
|
if git_add_and_commit(ctx.chromium_src, modified_files, commit_message):
|
|
log_success(f" ✓ Committed {len(modified_files)} file(s)")
|
|
commits_created += 1
|
|
else:
|
|
log_warning(" No changes staged, skipping commit")
|
|
features_skipped += 1
|
|
|
|
return commits_created, features_skipped
|
|
|
|
|
|
def annotate_single_feature(
|
|
ctx: Context,
|
|
feature_name: str,
|
|
) -> bool:
|
|
"""Create a commit for a single feature.
|
|
|
|
Args:
|
|
ctx: Build context
|
|
feature_name: Name of the feature to commit
|
|
|
|
Returns:
|
|
True if commit was created successfully
|
|
"""
|
|
commits, _ = annotate_features(ctx, feature_filter=feature_name)
|
|
return commits > 0
|
|
|
|
|
|
class AnnotateModule(CommandModule):
|
|
"""Create git commits organized by features from features.yaml"""
|
|
|
|
produces = []
|
|
requires = []
|
|
description = "Create git commits organized by features"
|
|
|
|
def validate(self, ctx: Context) -> None:
|
|
"""Validate git is available and chromium_src exists."""
|
|
import shutil
|
|
|
|
if not shutil.which("git"):
|
|
raise ValidationError("Git is not available in PATH")
|
|
if not ctx.chromium_src.exists():
|
|
raise ValidationError(f"Chromium source not found: {ctx.chromium_src}")
|
|
|
|
# Check if it's a git repository
|
|
git_dir = ctx.chromium_src / ".git"
|
|
if not git_dir.exists():
|
|
raise ValidationError(f"Not a git repository: {ctx.chromium_src}")
|
|
|
|
def execute(
|
|
self,
|
|
ctx: Context,
|
|
feature_name: Optional[str] = None,
|
|
**kwargs,
|
|
) -> None:
|
|
"""Execute annotate.
|
|
|
|
Args:
|
|
ctx: Build context
|
|
feature_name: If specified, only annotate this feature
|
|
"""
|
|
log_info("🏗️ Annotate Features")
|
|
log_info("=" * 60)
|
|
log_info(f"📁 Chromium source: {ctx.chromium_src}")
|
|
log_info(f"📄 Features file: {ctx.get_features_yaml_path()}")
|
|
|
|
commits_created, features_skipped = annotate_features(
|
|
ctx, feature_filter=feature_name
|
|
)
|
|
|
|
log_info("\n" + "=" * 60)
|
|
if commits_created > 0:
|
|
log_success(f"✓ Created {commits_created} commit(s)")
|
|
else:
|
|
log_info("No commits created (no modified files found)")
|
|
|
|
if features_skipped > 0:
|
|
log_info(f" Skipped {features_skipped} feature(s) with no changes")
|
|
log_info("=" * 60)
|