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
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ repos:
verbose: true
files: ^db\.py|README\.md$

- rev: v0.3.5
- rev: v0.5.4
repo: https://github.com/astral-sh/ruff-pre-commit
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format

- repo: https://github.com/pdm-project/pdm
rev: 2.13.2
rev: 2.17.1
hooks:
- id: pdm-lock-check
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pdm 2.13.2
python 3.12.2 3.11.8 3.10.13 3.9.18
pdm 2.17.1
python 3.12.4 3.11.9 3.10.14 3.9.19
1,035 changes: 529 additions & 506 deletions pdm.lock

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/sync_pre_commit_lock/actions/install_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ def execute(self) -> None:
def _install_pre_commit_hooks(self) -> None:
try:
self.printer.info("Installing pre-commit hooks...")
return_code = subprocess.check_call(
self.install_pre_commit_hooks_command, # noqa: S603
return_code = subprocess.check_call( # noqa: S603
self.install_pre_commit_hooks_command,
# XXX We probably want to see the output, at least in verbose mode or if it fails
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
Expand All @@ -61,8 +61,8 @@ def _install_pre_commit_hooks(self) -> None:
def _is_pre_commit_package_installed(self) -> bool:
try:
# Try is `pre-commit --version` works
output = subprocess.check_output(
self.check_pre_commit_version_command, # noqa: S603
output = subprocess.check_output( # noqa: S603
self.check_pre_commit_version_command,
).decode()
except (subprocess.CalledProcessError, FileNotFoundError):
return False
Expand All @@ -75,8 +75,8 @@ def _are_pre_commit_hooks_installed(git_root: Path) -> bool:

def _get_git_directory_path(self) -> Path | None:
try:
result = subprocess.check_output(
["git", "rev-parse", "--show-toplevel"], # noqa: S603, S607
result = subprocess.check_output( # noqa: S603
["git", "rev-parse", "--show-toplevel"], # noqa: S607
stderr=subprocess.PIPE,
)
return Path(result.decode().strip()) / ".git"
Expand Down
19 changes: 16 additions & 3 deletions src/sync_pre_commit_lock/pdm_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, ClassVar
from collections.abc import Iterable
from typing import TYPE_CHECKING, Any, ClassVar, Union

from pdm import termui
from pdm.cli.commands.base import BaseCommand
Expand Down Expand Up @@ -117,17 +118,29 @@ def on_pdm_install_setup_pre_commit(
action.execute()


if TYPE_CHECKING:
Resolution = Union[dict[str, list[Candidate]], dict[str, Candidate]]


def select_candidate(candidate: Union[Candidate, list[Candidate]]) -> Candidate | None:
if isinstance(candidate, Iterable):
return next(iter(candidate), None)
return candidate


@post_lock.connect
def on_pdm_lock_check_pre_commit(
project: Project, *, resolution: dict[str, Candidate], dry_run: bool, with_prefix: bool = True, **kwargs: Any
project: Project, *, resolution: Resolution, dry_run: bool, with_prefix: bool = True, **kwargs: Any
) -> None:
project_root: Path = project.root
plugin_config: SyncPreCommitLockConfig = load_config(project_root / project.PYPROJECT_FILENAME)
printer = PDMPrinter(project.core.ui, with_prefix=with_prefix)

file_path = project_root / plugin_config.pre_commit_config_file
resolved_packages: dict[str, GenericLockedPackage] = {
k: GenericLockedPackage(v.name, v.version) for k, v in resolution.items() if v.name and v.version
k: GenericLockedPackage(c.name, c.version)
for k, v in resolution.items()
if (c := select_candidate(v)) and c.name and c.version
}
action = SyncPreCommitHooksVersion(
printer=printer,
Expand Down
22 changes: 18 additions & 4 deletions tests/test_pdm/test_pdm_sync_pre_commit_hook.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING
from unittest.mock import MagicMock, patch

import pytest
from packaging.version import Version

pdm_module = pytest.importorskip("pdm")
# ruff: noqa: E402
from pdm.__version__ import __version__ as pdm_version
from pdm.core import Core
from pdm.models.candidates import Candidate
from pdm.models.requirements import NamedRequirement
Expand All @@ -16,6 +21,9 @@
from sync_pre_commit_lock.config import SyncPreCommitLockConfig
from sync_pre_commit_lock.pdm_plugin import on_pdm_lock_check_pre_commit, register_pdm_plugin

if TYPE_CHECKING:
from sync_pre_commit_lock.pdm_plugin import Resolution


@pytest.fixture()
def project() -> Project:
Expand All @@ -36,6 +44,15 @@ def printer() -> Printer:
return x


@pytest.fixture
def resolution() -> Resolution:
"""
Mock resolution depending on pdm version
"""
candidate = Candidate(NamedRequirement("some-library"), "1.0.0", "https://example.com/some-library")
return {"some-library": [candidate] if Version(pdm_version) >= Version("2.17") else candidate}


def test_register_pdm_plugin(project: Project) -> None:
core = project.core
register_pdm_plugin(core)
Expand All @@ -44,10 +61,7 @@ def test_register_pdm_plugin(project: Project) -> None:


@patch("sync_pre_commit_lock.pdm_plugin.load_config")
def test_on_pdm_lock_check_pre_commit(mock_load_config: MagicMock, project: MagicMock) -> None:
def test_on_pdm_lock_check_pre_commit(mock_load_config: MagicMock, project: MagicMock, resolution: Resolution) -> None:
mock_load_config.return_value = SyncPreCommitLockConfig(disable_sync_from_lock=True)
resolution = {
"some-library": Candidate(NamedRequirement("some-library"), "1.0.0", "https://example.com/some-library")
}
on_pdm_lock_check_pre_commit(project, dry_run=False, resolution=resolution)
mock_load_config.assert_called_once()
24 changes: 14 additions & 10 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ requires =
env_list =
clean
report
py{312, 311, 310, 39}-pdm{213, 212, 211, 210, 29, 28, 27}
py{312, 311, 310, 39}-pdm{217, 216, 215, 214, 213, 212, 211, 210, 29, 28, 27}
py{312, 311, 310, 39}-poetry{18, 17, 16}

[testenv]
set_env =
py{39,310,311,312}-pdm{27,28,29,210,211,212,213}: COVERAGE_FILE = .coverage.{envname}
py{39,310,311,312}-pdm{27,28,29,210,211,212,213,214,215,216,217}: COVERAGE_FILE = .coverage.{envname}
py{39,310,311,312}-poetry{16, 17, 18}: COVERAGE_FILE = .coverage.{envname}
commands =
pytest --cov --cov-append --cov-report=term-missing {posargs:-vv} --cov-config=pyproject.toml
Expand All @@ -18,16 +18,16 @@ allowlist_externals =
pdm
pytest
depends =
report: py{312, 311, 310, 39}-pdm{213, 212, 211, 210, 29, 28, 27}
report: py{312, 311, 310, 39}-pdm{217, 216, 215, 214, 213, 212, 211, 210, 29, 28, 27}
report: py{312, 311, 310, 39}-poetry{17, 16}
py{312, 311, 310, 39}-pdm{213, 212, 211, 210, 29, 28, 27}: clean
py{312, 311, 310, 39}-pdm{217, 216, 215, 214, 213, 212, 211, 210, 29, 28, 27}: clean
py{312, 311, 310, 39}-poetry{18, 17, 16}: clean

[testenv:clean]
skip_install = true
commands =
coverage erase
pdm export --dev --group testtox -o requirements-tox.txt
pdm export --dev --group testtox -o requirements-tox.txt --no-hashes
groups =
testtox

Expand All @@ -41,14 +41,18 @@ commands =
coverage html
coverage xml

[testenv:py{39,310,311,312}-pdm{27,28,29,210,211,212,213}]
[testenv:py{39,310,311,312}-pdm{27,28,29,210,211,212,213,214,215,216,217}]
package = editable
deps =
-r requirements-tox.txt
pdm210: pdm<2.11,>=2.10
pdm211: pdm<2.12,>=2.11
pdm212: pdm<2.13,>=2.12
pdm213: pdm<2.14,>=2.13.2
pdm214: pdm<2.15,>=2.14
pdm215: pdm<2.16,>=2.15
pdm216: pdm<2.17,>=2.16
pdm217: pdm<2.18,>=2.17
pdm27: pdm<2.8,>=2.7
pdm28: pdm<2.9,>=2.8
pdm29: pdm<2.10,>=2.9
Expand All @@ -63,8 +67,8 @@ deps =

[gh]
python =
3.9= py39-pdm{27,28,29,210,211,212,213},py39-poetry{16, 17, 18}, report, clean
3.10= py310-pdm{27,28,29,210,211,212,213}, py310-poetry{16, 17, 18}, report, clean
3.11= py311-pdm{27,28,29,210,211,212,213}, py311-poetry{16, 17, 18}, report, clean
3.12= py312-pdm{27,28,29,210,211,212,213}, py312-poetry{16, 17, 18}, report, clean
3.9= py39-pdm{27,28,29,210,211,212,213,214,215,216,217},py39-poetry{16, 17, 18}, report, clean
3.10= py310-pdm{27,28,29,210,211,212,213,214,215,216,217}, py310-poetry{16, 17, 18}, report, clean
3.11= py311-pdm{27,28,29,210,211,212,213,214,215,216,217}, py311-poetry{16, 17, 18}, report, clean
3.12= py312-pdm{27,28,29,210,211,212,213,214,215,216,217}, py312-poetry{16, 17, 18}, report, clean
fail_on_no_env = True