mirror of
https://github.com/okhsunrog/vpnhide.git
synced 2026-04-28 06:31:27 +00:00
ci+chore: add ruff (format + lint) for python scripts
Repo had ~1800 lines of Python (kmod/build.py, scripts/*, zygisk/build.py,
portshide/build-zip.py) with no formatter or linter. Long-lived scripts
like scripts/release.py and scripts/codegen-interfaces.py benefit from
catching unused-import / undefined-name / outdated-syntax issues early.
pyproject.toml — ruff config, target-py312, line-length 100,
rules E F W I B UP SIM. Excludes zygisk/third_party,
target/, .claude/.
ci.yml — astral-sh/ruff-action@v4 for `format --check` and `check`,
ahead of the slow Rust/Gradle steps so it fails fast.
docs/development.md — add `uvx ruff …` to the local-lint snippet.
Cleanup applied (`ruff format` + `ruff check --fix`):
- reformat: kmod/build.py, scripts/{changelog_lib,codegen-interfaces,
release,stats}.py, zygisk/build.py
- I001: split multi-name imports onto separate lines after the
sys.path.insert prelude (kmod/build.py, zygisk/build.py)
- E501 manual: wrap one console.print line in scripts/release.py
Stdlib-only invariant from scripts/build_lib.py is preserved — ruff is
a dev/CI tool, not imported at runtime.
This commit is contained in:
parent
9986100a77
commit
91013acb54
9 changed files with 70 additions and 33 deletions
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
|
@ -38,6 +38,17 @@ jobs:
|
|||
- name: Mark workspace safe
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
# Python lint + format (ruff). Fast (~100 ms on 1800 LoC) so it
|
||||
# runs first — fails before the slow Rust/Gradle steps.
|
||||
- name: ruff format
|
||||
uses: astral-sh/ruff-action@v4
|
||||
with:
|
||||
args: format --check
|
||||
- name: ruff check
|
||||
uses: astral-sh/ruff-action@v4
|
||||
with:
|
||||
args: check
|
||||
|
||||
# Cache cargo deps + target dirs for clippy/test. Same key shape as
|
||||
# zygisk + lsposed jobs — when those run on the same Cargo.lock the
|
||||
# restore-keys fallback shares warm artifacts across jobs.
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ CI runs the same checks. See [.github/workflows/ci.yml](../.github/workflows/ci.
|
|||
python3 scripts/codegen-interfaces.py
|
||||
git diff --quiet # must be clean
|
||||
|
||||
# Python (ruff, config in pyproject.toml). uvx runs without installing anything global.
|
||||
uvx ruff format --check
|
||||
uvx ruff check
|
||||
|
||||
# Rust
|
||||
cd zygisk && cargo fmt --check && cargo ndk -t arm64-v8a clippy -- -D warnings
|
||||
cd ../lsposed/native && cargo fmt --check && cargo ndk -t arm64-v8a clippy -- -D warnings
|
||||
|
|
@ -116,8 +120,7 @@ gcc -O2 -Wall -Werror -o /tmp/test_iface_lists kmod/test_iface_lists.c && /tmp/t
|
|||
|
||||
# Kotlin
|
||||
ktlint "lsposed/**/*.kt"
|
||||
cd lsposed && ./gradlew --no-daemon :app:lint
|
||||
cd lsposed && ./gradlew --no-daemon :app:testDebugUnitTest
|
||||
cd lsposed && ./gradlew :app:lint :app:testDebugUnitTest
|
||||
```
|
||||
|
||||
## Build versions
|
||||
|
|
|
|||
|
|
@ -45,8 +45,11 @@ import sys
|
|||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
||||
from build_lib import get_build_version, make_zip, version_sort_key # type: ignore[import-not-found]
|
||||
|
||||
from build_lib import ( # type: ignore[import-not-found]
|
||||
get_build_version,
|
||||
make_zip,
|
||||
version_sort_key,
|
||||
)
|
||||
|
||||
# Module file name on disk after `make`.
|
||||
KMOD_KO = "vpnhide_kmod.ko"
|
||||
|
|
@ -128,13 +131,9 @@ def native_build_one(
|
|||
|
||||
module_prop = staging / "module.prop"
|
||||
content = module_prop.read_text(encoding="utf-8")
|
||||
content = re.sub(
|
||||
r"^version=.*", f"version=v{build_version}", content, flags=re.MULTILINE
|
||||
)
|
||||
content = re.sub(r"^version=.*", f"version=v{build_version}", content, flags=re.MULTILINE)
|
||||
if re.search(r"^gkiVariant=", content, flags=re.MULTILINE):
|
||||
content = re.sub(
|
||||
r"^gkiVariant=.*", f"gkiVariant={kmi}", content, flags=re.MULTILINE
|
||||
)
|
||||
content = re.sub(r"^gkiVariant=.*", f"gkiVariant={kmi}", content, flags=re.MULTILINE)
|
||||
else:
|
||||
content = content.rstrip() + f"\ngkiVariant={kmi}\n"
|
||||
update_json_url = (
|
||||
|
|
@ -219,9 +218,7 @@ def find_runtime() -> tuple[str, bool]:
|
|||
sys.exit(1)
|
||||
|
||||
|
||||
def container_build_one(
|
||||
runtime: str, is_podman: bool, repo_root: Path, kmi: str
|
||||
) -> None:
|
||||
def container_build_one(runtime: str, is_podman: bool, repo_root: Path, kmi: str) -> None:
|
||||
image = f"ghcr.io/ylarod/ddk-min:{kmi}-{DDK_IMAGE_TAG}"
|
||||
mount_spec = f"{repo_root}:/work"
|
||||
cmd = [runtime, "run", "--rm"]
|
||||
|
|
@ -314,10 +311,7 @@ def main() -> int:
|
|||
parser.add_argument(
|
||||
"--kdir",
|
||||
type=str,
|
||||
help=(
|
||||
"Kernel source directory (overrides KDIR/KERNEL_SRC). Implies "
|
||||
"native mode."
|
||||
),
|
||||
help=("Kernel source directory (overrides KDIR/KERNEL_SRC). Implies native mode."),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--clang-dir",
|
||||
|
|
|
|||
21
pyproject.toml
Normal file
21
pyproject.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Ruff config — applies to every .py in the repo.
|
||||
# All our scripts are stdlib-only by policy (see scripts/build_lib.py
|
||||
# header), so ruff is a dev/CI tool here, never a runtime dependency.
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py312" # CI image (Ubuntu 24.04) ships Python 3.12
|
||||
line-length = 100
|
||||
extend-exclude = [
|
||||
# third-party / vendored — not our code, don't lint
|
||||
"zygisk/third_party",
|
||||
# cargo build outputs that may contain stray .py files
|
||||
"**/target",
|
||||
# local-only worktrees / agent state, untracked
|
||||
".claude",
|
||||
]
|
||||
|
||||
[tool.ruff.lint]
|
||||
# Conservative rule set: pycodestyle (E/W) + pyflakes (F) + isort (I)
|
||||
# + bugbear foot-guns (B) + pyupgrade (UP) + simplifications (SIM).
|
||||
# No pylint-style noise, no mypy.
|
||||
select = ["E", "F", "W", "I", "B", "UP", "SIM"]
|
||||
|
|
@ -117,8 +117,8 @@ def parse_fragment(path: Path) -> dict:
|
|||
if date_match.start() > en_match.start():
|
||||
raise ValueError(f"{path.name}: date line must appear before the language sections")
|
||||
|
||||
en_body = text[en_match.end():ru_match.start()].strip()
|
||||
ru_body = text[ru_match.end():].strip()
|
||||
en_body = text[en_match.end() : ru_match.start()].strip()
|
||||
ru_body = text[ru_match.end() :].strip()
|
||||
if not en_body:
|
||||
raise ValueError(f"{path.name}: empty English section")
|
||||
if not ru_body:
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@ def emit_rust(rules: list[Rule], tests: list[TestVector]) -> str:
|
|||
expected = "true" if t.is_vpn else "false"
|
||||
lines.append(
|
||||
f" assert_eq!(matches_vpn({rust_byte_lit(t.name)}), {expected}, "
|
||||
f"\"matches_vpn({t.name!r})\");"
|
||||
f'"matches_vpn({t.name!r})");'
|
||||
)
|
||||
lines.append(" }")
|
||||
lines.append("}")
|
||||
|
|
|
|||
|
|
@ -114,8 +114,7 @@ def main() -> int:
|
|||
for past in data.get("history", []):
|
||||
if past.get("version") == version:
|
||||
console.print(
|
||||
f"[red]error:[/red] v{version} already exists in history[]. "
|
||||
"Pick a new version.",
|
||||
f"[red]error:[/red] v{version} already exists in history[]. Pick a new version.",
|
||||
)
|
||||
return 1
|
||||
|
||||
|
|
@ -169,11 +168,14 @@ def main() -> int:
|
|||
|
||||
console.print()
|
||||
console.print("[bold]Next steps:[/bold]")
|
||||
console.print(f" git commit -am \"chore: release v{version}\"")
|
||||
console.print(f' git commit -am "chore: release v{version}"')
|
||||
console.print(f" git tag v{version} && git push && git push origin v{version}")
|
||||
console.print(" # CI builds artifacts and creates a DRAFT release — review on the Releases page, click Publish")
|
||||
console.print(
|
||||
" # CI builds artifacts and creates a DRAFT release — "
|
||||
"review on the Releases page, click Publish"
|
||||
)
|
||||
console.print(" ./scripts/update-json.sh")
|
||||
console.print(f" git commit -am \"chore: update-json for v{version}\"")
|
||||
console.print(f' git commit -am "chore: update-json for v{version}"')
|
||||
console.print(" git push")
|
||||
return 0
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@ def github_token() -> str | None:
|
|||
if token := os.environ.get("GITHUB_TOKEN"):
|
||||
return token
|
||||
try:
|
||||
out = subprocess.run(
|
||||
["gh", "auth", "token"], capture_output=True, text=True, check=True
|
||||
)
|
||||
out = subprocess.run(["gh", "auth", "token"], capture_output=True, text=True, check=True)
|
||||
return out.stdout.strip() or None
|
||||
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||
return None
|
||||
|
|
@ -34,9 +32,7 @@ headers = {"Accept": "application/vnd.github+json"}
|
|||
if token := github_token():
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
|
||||
resp = httpx.get(
|
||||
"https://api.github.com/repos/okhsunrog/vpnhide/releases", headers=headers
|
||||
)
|
||||
resp = httpx.get("https://api.github.com/repos/okhsunrog/vpnhide/releases", headers=headers)
|
||||
resp.raise_for_status()
|
||||
releases = resp.json()
|
||||
|
||||
|
|
@ -53,7 +49,13 @@ for release in releases:
|
|||
total = sum(a["download_count"] for a in assets)
|
||||
grand_total += total
|
||||
|
||||
table = Table(title=f"{release['tag_name']} ({total} downloads)", title_style="bold", show_header=False, box=None, padding=(0, 1))
|
||||
table = Table(
|
||||
title=f"{release['tag_name']} ({total} downloads)",
|
||||
title_style="bold",
|
||||
show_header=False,
|
||||
box=None,
|
||||
padding=(0, 1),
|
||||
)
|
||||
table.add_column("Asset", style="cyan")
|
||||
table.add_column("Count", justify="right", style="yellow")
|
||||
table.add_column("Bar", style="green", no_wrap=True)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ import sys
|
|||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
|
||||
from build_lib import get_build_version, make_zip, version_sort_key # type: ignore[import-not-found]
|
||||
from build_lib import ( # type: ignore[import-not-found]
|
||||
get_build_version,
|
||||
make_zip,
|
||||
version_sort_key,
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue