This commit is contained in:
2026-06-25 02:21:13 +03:00
parent 7963a8d2eb
commit 62ec72ba3d
7 changed files with 196 additions and 9 deletions
+6 -7
View File
@@ -15,8 +15,8 @@ jobs:
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
with: with:
python-version: "3.11" python-version: "3.11"
- run: pip install black>=24.0 - run: pip install -e ".[dev]"
- run: black --check src/ - run: doit format_check
typecheck: typecheck:
name: Type check name: Type check
@@ -27,7 +27,7 @@ jobs:
with: with:
python-version: "3.11" python-version: "3.11"
- run: pip install -e ".[dev]" - run: pip install -e ".[dev]"
- run: mypy src/ - run: doit typecheck
test: test:
name: Tests name: Tests
@@ -38,7 +38,7 @@ jobs:
with: with:
python-version: "3.11" python-version: "3.11"
- run: pip install -e ".[dev]" - run: pip install -e ".[dev]"
- run: pytest - run: doit test
build: build:
name: Build (${{ matrix.os }}) name: Build (${{ matrix.os }})
@@ -53,9 +53,8 @@ jobs:
with: with:
python-version: "3.11" python-version: "3.11"
- run: pip install -e ".[dev]" - run: pip install -e ".[dev]"
- run: pyinstaller --onefile src/nexus_sync/client/__main__.py --name nexus-sync-client - run: doit package
- run: pyinstaller --onefile src/nexus_sync/server/__main__.py --name nexus-sync-server - run: doit pyinstaller
- run: pyinstaller --onefile src/nexus_sync/cli/__main__.py --name nexus-cli
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: nexus-sync-${{ matrix.os }} name: nexus-sync-${{ matrix.os }}
+3 -1
View File
@@ -219,4 +219,6 @@ __marimo__/
.vscode/ .vscode/
*.DS_Store *.DS_Store
.doit.db*
nexus-sync.db
+12
View File
@@ -111,6 +111,18 @@ client on its next heartbeat.
### To build ### To build
Use `doit` for repeatable checks and package builds:
```bash
pip install -e .[dev]
doit list
doit wheel # build dist/nexus_sync-0.1.0-py3-none-any.whl
doit package # build wheel and sdist
doit # run tests, typecheck, format check, and wheel build
```
PyInstaller standalone binaries are still available through Makefile targets:
``` ```
make [client|server|cli] make [client|server|cli]
``` ```
+12
View File
@@ -68,3 +68,15 @@ make cli
``` ```
This creates `dist/nexus-cli` through PyInstaller. This creates `dist/nexus-cli` through PyInstaller.
## Build wheel package
Use `doit` from the development dependencies:
```bash
pip install -e .[dev]
doit wheel
```
The wheel is written to `dist/nexus_sync-0.1.0-py3-none-any.whl` and installs the
`nexus-cli` console script.
+114
View File
@@ -0,0 +1,114 @@
import sys
from pathlib import Path
DOIT_CONFIG = {
"default_tasks": ["test", "typecheck", "format_check", "wheel"],
}
PYTHON = sys.executable
PACKAGE_VERSION = "0.1.0"
WHEEL_TARGET = f"dist/nexus_sync-{PACKAGE_VERSION}-py3-none-any.whl"
SRC_FILES = list(Path("src").rglob("*.py"))
TEST_FILES = list(Path("tests").rglob("*.py"))
DOC_FILES = [Path("README.md"), *Path("docs").glob("*.md")]
BUILD_DEPS = [Path("pyproject.toml"), Path("README.md"), *SRC_FILES]
def task_test():
return {
"actions": [f"{PYTHON} -m pytest -q"],
"file_dep": [str(path) for path in [*SRC_FILES, *TEST_FILES]],
"verbosity": 2,
}
def task_typecheck():
return {
"actions": [f"{PYTHON} -m mypy src"],
"file_dep": [str(path) for path in SRC_FILES],
"verbosity": 2,
}
def task_format_check():
return {
"actions": [f"{PYTHON} -m black --check ."],
"file_dep": [str(path) for path in [*SRC_FILES, *TEST_FILES, Path("dodo.py")]],
"verbosity": 2,
}
def task_wheel():
return {
"actions": [f"{PYTHON} -m build --wheel"],
"file_dep": [str(path) for path in BUILD_DEPS],
"targets": [WHEEL_TARGET],
"clean": True,
"verbosity": 2,
}
def task_sdist():
return {
"actions": [f"{PYTHON} -m build --sdist"],
"file_dep": [str(path) for path in BUILD_DEPS],
"targets": [f"dist/nexus_sync-{PACKAGE_VERSION}.tar.gz"],
"clean": True,
"verbosity": 2,
}
def task_package():
return {
"actions": None,
"task_dep": ["wheel", "sdist"],
"verbosity": 2,
}
def task_pyinstaller_cli():
return {
"actions": [
f"{PYTHON} -m PyInstaller --onefile src/nexus_sync/cli/__main__.py --name nexus-cli"
],
"file_dep": [str(path) for path in BUILD_DEPS],
"clean": True,
"verbosity": 2,
}
def task_pyinstaller_client():
return {
"actions": [
f"{PYTHON} -m PyInstaller --onefile src/nexus_sync/client/__main__.py --name nexus-sync-client"
],
"file_dep": [str(path) for path in BUILD_DEPS],
"clean": True,
"verbosity": 2,
}
def task_pyinstaller_server():
return {
"actions": [
f"{PYTHON} -m PyInstaller --onefile src/nexus_sync/server/__main__.py --name nexus-sync-server"
],
"file_dep": [str(path) for path in BUILD_DEPS],
"clean": True,
"verbosity": 2,
}
def task_pyinstaller():
return {
"actions": None,
"task_dep": ["pyinstaller_client", "pyinstaller_server", "pyinstaller_cli"],
"verbosity": 2,
}
def task_clean_dist():
return {
"actions": ["rm -rf dist build src/*.egg-info *.spec"],
"verbosity": 2,
}
+4 -1
View File
@@ -7,7 +7,8 @@ name = "nexus_sync"
version = "0.1.0" version = "0.1.0"
description = "A utility that allows you to manage your computers from a centralized server." description = "A utility that allows you to manage your computers from a centralized server."
readme = "README.md" readme = "README.md"
license = { file = "LICENSE" } license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = [
"fastapi>=0.115.0", "fastapi>=0.115.0",
@@ -23,6 +24,8 @@ dev = [
"httpx>=0.28.0", "httpx>=0.28.0",
"black>=24.0", "black>=24.0",
"pyinstaller>=6.0", "pyinstaller>=6.0",
"build>=1.2.0",
"doit>=0.36.0",
"mypy>=1.0", "mypy>=1.0",
"types-PyYAML>=6.0.12", "types-PyYAML>=6.0.12",
"pre-commit>=4.0" "pre-commit>=4.0"
+45
View File
@@ -0,0 +1,45 @@
import importlib.util
from pathlib import Path
from typing import Any
PROJECT_ROOT = Path(__file__).resolve().parents[1]
def _load_dodo() -> Any:
spec = importlib.util.spec_from_file_location("dodo", PROJECT_ROOT / "dodo.py")
assert spec is not None
assert spec.loader is not None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _actions(task: dict[str, Any]) -> list[str]:
return [str(action) for action in task["actions"]]
def test_doit_has_wheel_task() -> None:
dodo = _load_dodo()
task = dodo.task_wheel()
assert task["verbosity"] == 2
assert "dist/nexus_sync-0.1.0-py3-none-any.whl" in task["targets"]
assert "pyproject.toml" in task["file_dep"]
assert any("python -m build --wheel" in action for action in _actions(task))
def test_doit_has_clean_dist_task() -> None:
dodo = _load_dodo()
task = dodo.task_clean_dist()
assert any("dist" in action for action in _actions(task))
assert any("build" in action for action in _actions(task))
assert any("*.egg-info" in action for action in _actions(task))
def test_doit_default_tasks_include_checks_and_wheel() -> None:
dodo = _load_dodo()
assert dodo.DOIT_CONFIG["default_tasks"] == ["test", "typecheck", "format_check", "wheel"]