diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0f15b31..8a2d21e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,7 +4,7 @@ ## Checklist -- [ ] Version bumped in `reyal_core/__init__.py` (if behavior changed) +- [ ] Version bumped in `reyal_core/__init__.py` - [ ] `CHANGELOG.md` updated - [ ] Local bench migration ran successfully (if schema/patch changes) - [ ] No secrets or local-only files included @@ -12,4 +12,7 @@ ## Validation - [ ] Tested manually +- [ ] `ruff check .` passes +- [ ] `ruff format --check .` passes +- [ ] `pytest` passes - [ ] Relevant logs/screenshots attached (if useful) diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000..354f8a5 --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,34 @@ +name: Quality + +on: + pull_request: + push: + branches: [main] + +jobs: + quality: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11"] + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install quality tools + run: python -m pip install pytest ruff + + - name: Run Ruff lint + run: ruff check . + + - name: Check Ruff formatting + run: ruff format --check . + + - name: Run tests + run: python -m pytest diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dd3dba..48a0ad6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on Keep a Changelog. +## [0.0.11] - 2026-08-29 + +### Changed + +- Add automated Ruff linting, formatting, and pytest checks for pull requests +- Document local quality checks for contributors + ## [0.0.10] - 2026-08-10 ### Changed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d75e5bf..05a7bef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,6 +32,18 @@ git commit -m "type: short description" Commit types: `feat`, `fix`, `bump`, `chore`, `refactor`, `docs`. +### Local quality checks + +Run these checks before opening a pull request: + +```bash +uv run --with ruff ruff check . +uv run --with ruff ruff format --check . +uv run --with pytest pytest +``` + +Ruff checks Python lint rules and formatting; pytest runs the automated test suite. + ### Pull requests - Never push directly to `main`. diff --git a/reyal_core/__init__.py b/reyal_core/__init__.py index 9b36b86..b2f0155 100644 --- a/reyal_core/__init__.py +++ b/reyal_core/__init__.py @@ -1 +1 @@ -__version__ = "0.0.10" +__version__ = "0.0.11" diff --git a/reyal_core/overrides.py b/reyal_core/overrides.py index 0b5e8d0..c1fa210 100644 --- a/reyal_core/overrides.py +++ b/reyal_core/overrides.py @@ -10,8 +10,8 @@ def apply_patches(): """Apply all reyal_core patches. Safe to call repeatedly; patches only once.""" - import frappe.utils as fu import frappe.desk.search as fs + import frappe.utils as fu if getattr(fu, "_reyal_core_patched", False): return @@ -29,6 +29,7 @@ def apply_patches(): # Patched implementations: + def _get_fullname(user=None): """Return custom_short_name when set, otherwise fall back to full_name.""" if not user: diff --git a/reyal_core/setup/install.py b/reyal_core/setup/install.py index dfd69cb..69c8496 100644 --- a/reyal_core/setup/install.py +++ b/reyal_core/setup/install.py @@ -1,7 +1,6 @@ import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields - _CUSTOM_FIELDS = { "User": [ { @@ -27,7 +26,11 @@ def _backfill_short_names(): """Compute short_name for all existing users after install.""" from reyal_core.utils import compute_short_name_value - users = frappe.db.get_all("User", filters={"user_type": "System User"}, fields=["name", "first_name", "middle_name", "last_name"]) + users = frappe.db.get_all( + "User", + filters={"user_type": "System User"}, + fields=["name", "first_name", "middle_name", "last_name"], + ) for u in users: short_name = compute_short_name_value(u.first_name, u.last_name, u.get("middle_name")) frappe.db.set_value("User", u.name, "custom_short_name", short_name, update_modified=False) diff --git a/reyal_core/utils.py b/reyal_core/utils.py index 1e4c539..93e22e5 100644 --- a/reyal_core/utils.py +++ b/reyal_core/utils.py @@ -7,7 +7,10 @@ def get_display_name(user: str | None) -> str: return "" u = frappe.db.get_value( - "User", user, ["first_name", "middle_name", "last_name", "full_name", "custom_short_name"], as_dict=True + "User", + user, + ["first_name", "middle_name", "last_name", "full_name", "custom_short_name"], + as_dict=True, ) if not u: return user @@ -36,7 +39,10 @@ def compute_short_name_value( def _get_format() -> str: try: - return frappe.db.get_single_value("Reyal Settings", "user_short_display_name_format") or "First + Last Initial" + return ( + frappe.db.get_single_value("Reyal Settings", "user_short_display_name_format") + or "First + Last Initial" + ) except Exception: return "First + Last Initial" @@ -49,9 +55,7 @@ def _first_last_initial(first_name: str | None, last_name: str | None) -> str: return first or last -def _first_middle_last_initial( - first_name: str | None, middle_name: str | None, last_name: str | None -) -> str: +def _first_middle_last_initial(first_name: str | None, middle_name: str | None, last_name: str | None) -> str: first = (first_name or "").strip() middle = (middle_name or "").strip() last = (last_name or "").strip()