Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: CI

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
workflow_dispatch:

jobs:
test:
name: Unit Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.12']

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

- name: Install package
run: python -m pip install --upgrade pip && python -m pip install .

- name: Run tests
run: python -m unittest discover -v

- name: Build distributions
run: python -m pip install build && python -m build

- name: Verify built wheel in clean environment
shell: python
run: |
import glob
import os
import pathlib
import subprocess
import venv

env_dir = pathlib.Path(".pkg-test")
venv.EnvBuilder(with_pip=True, clear=True).create(env_dir)

if os.name == "nt":
env_python = env_dir / "Scripts" / "python.exe"
env_cli = env_dir / "Scripts" / "brave-updater.exe"
else:
env_python = env_dir / "bin" / "python"
env_cli = env_dir / "bin" / "brave-updater"

wheel = sorted(glob.glob("dist/*.whl"))
if not wheel:
raise SystemExit("No wheel built in dist/")

subprocess.check_call([str(env_python), "-m", "pip", "install", wheel[-1]])
subprocess.check_call(
[
str(env_python),
"-c",
(
"import importlib.metadata, brave_updater; "
"assert importlib.metadata.version('brave-updater') == brave_updater.__version__"
),
]
)
subprocess.check_call([str(env_cli), "--help"])
51 changes: 51 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Release

on:
push:
tags:
- "v*"

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Validate tag matches package version
shell: python
run: |
import os
import pathlib
import sys

sys.path.insert(0, str(pathlib.Path("src").resolve()))
from brave_updater import __version__

tag = os.environ["GITHUB_REF_NAME"]
expected = tag[1:] if tag.startswith("v") else tag
if __version__ != expected:
raise SystemExit(
"Release tag {} does not match brave_updater.__version__ {}".format(tag, __version__)
)
print("Validated release tag {} against package version {}".format(tag, __version__))

- name: Build distributions
run: |
python -m pip install --upgrade pip
python -m pip install build twine
python -m build
python -m twine check dist/*

- name: Upload release assets
uses: softprops/action-gh-release@v2
with:
files: dist/*
32 changes: 32 additions & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Live Smoke Test

on:
workflow_dispatch:
schedule:
- cron: "0 8 * * 1"

jobs:
smoke:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install package
run: python -m pip install --upgrade pip && python -m pip install .

- name: Legacy URL selection
shell: bash
run: |
URL=$(python braver.py --print-only)
echo "Selected URL: $URL"
[[ "$URL" =~ ^https:// ]] || exit 1

- name: JSON health check
run: brave-updater check --json --source github
139 changes: 0 additions & 139 deletions .github/workflows/test.yml

This file was deleted.

10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
__pycache__/
*.py[cod]
*.egg-info/
.coverage
.DS_Store
.pytest_cache/
.venv/
build/
dist/
test-downloads/
49 changes: 31 additions & 18 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Automatic SHA256 hash verification using asset digest from GitHub API
### Changed
- Updated repository ownership references to `HackEAC/braver-tz`
- Removed Brave-logo-based branding from the documentation and repository root

## [1.1.0] - 2026-03-16

### Improved
- Enhanced installer selection logic with better fallback mechanisms
- Comprehensive error handling with retry logic, timeout handling, and validation
- Windows platform testing completed
### Added
- Packaged Python CLI with `pyproject.toml`, `setup.py`, and `src/brave_updater/`
- `brave-updater` console entrypoint
- Explicit `check`, `download`, `update`, and `install` commands
- Installed-version detection for macOS, Linux, and Windows
- Unit tests for provider logic, version detection, download safety, and CLI compatibility
- Deterministic CI workflow across Linux, macOS, and Windows
- Release workflow for building and publishing wheels/sdists
- Live smoke workflow for read-only endpoint validation
- Homebrew formula starter files and repository transfer checklist docs

### Changed
- Retained `python3 braver.py ...` as a compatibility wrapper instead of the primary implementation
- Reworked download logic to use resumable `.part` files and atomic final replacement
- Added redirect validation against allowed hosts
- Added safer macOS app replacement flow using staged copies
- Updated documentation to describe the new CLI and the `HackEAC` ownership path

### Fixed
- Resume downloads no longer append corrupt data when a server ignores `Range` and returns a full `200`
- Version comparisons now treat `1.2.3` and `1.2.3.0` as equivalent

## [1.0.0] - 2024-12-19

### Added

- Cross-platform Python script to download latest stable Brave Browser from GitHub Releases
- Automatic OS detection (macOS, Windows, Linux)
- Automatic CPU architecture detection (x64, ARM64, x86)
- Linux distribution family detection (Debian-based, RHEL-based, Arch-based)
- Intelligent installer selection:
- `.dmg` / `.pkg` for macOS (prefers universal DMG, falls back to arch-specific)
- `.exe` for Windows (prefers StandaloneSetup offline installer)
- `.dmg` / `.pkg` for macOS
- `.exe` for Windows
- `.deb` for Debian-based Linux distributions
- `.rpm` for RHEL-based Linux distributions
- Download functionality with progress indication
- Optional installation step via `--install` flag
- `--print-only` flag to output download URL for automation
- `--dir` flag to specify custom download directory
- GitHub API token support via `GITHUB_TOKEN` environment variable
- macOS installation support (DMG mounting and app copying to /Applications)
- Windows installation support (launches installer)
- Linux installation support (dpkg for .deb, dnf/yum/rpm for .rpm)
- Interactive prompts before destructive operations
- Error handling for missing assets and unsupported systems
- Uses only Python standard library (no external dependencies)
- Python 3.8+ compatibility

- GitHub API token support via `GITHUB_TOKEN`
- Basic macOS, Windows, and Linux installation support
- Uses only Python standard library
Loading