diff --git a/pyproject.toml b/pyproject.toml index 26428660..4a925300 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,7 +84,6 @@ version-file = "src/usethis/_version.py" [tool.ruff] line-length = 88 -src = [ "src" ] lint.select = [ "A", "C4", @@ -178,7 +177,7 @@ type = "layers" layers = [ "bitbucket | github | pre_commit | pytest | ruff", "uv | pydantic | sonarqube", - "pyproject | yaml | python", + "project | pyproject | yaml | python", ] containers = [ "usethis._integrations" ] exhaustive = true diff --git a/src/usethis/_integrations/project/__init__.py b/src/usethis/_integrations/project/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/usethis/_integrations/project/layout.py b/src/usethis/_integrations/project/layout.py new file mode 100644 index 00000000..8eb96c6d --- /dev/null +++ b/src/usethis/_integrations/project/layout.py @@ -0,0 +1,10 @@ +from pathlib import Path +from typing import Literal + + +def get_source_dir_str() -> Literal["src", "."]: + src_dir = Path.cwd() / "src" + + if src_dir.exists() and src_dir.is_dir(): + return "src" + return "." diff --git a/src/usethis/_integrations/sonarqube/config.py b/src/usethis/_integrations/sonarqube/config.py index 760829cb..eddc5b22 100644 --- a/src/usethis/_integrations/sonarqube/config.py +++ b/src/usethis/_integrations/sonarqube/config.py @@ -3,6 +3,7 @@ from pydantic import TypeAdapter +from usethis._integrations.project.layout import get_source_dir_str from usethis._integrations.pyproject.core import get_config_value from usethis._integrations.python.version import get_python_version from usethis._integrations.sonarqube.errors import ( @@ -61,11 +62,17 @@ def get_sonar_project_properties() -> str: raise CoverageReportConfigNotFoundError(msg) # No file, so construct the contents + source_dir_str = get_source_dir_str() + if source_dir_str == ".": + sources = "./" + else: + sources = f"./{source_dir_str}" + text = f"""\ sonar.projectKey={project_key} sonar.language=py sonar.python.version={python_version} -sonar.sources=./src +sonar.sources={sources} sonar.tests=./tests sonar.python.coverage.reportPaths={coverage_output} sonar.verbose={"true" if verbose else "false"} diff --git a/src/usethis/_tool.py b/src/usethis/_tool.py index d94a13eb..add1d888 100644 --- a/src/usethis/_tool.py +++ b/src/usethis/_tool.py @@ -21,6 +21,7 @@ LocalRepo, UriRepo, ) +from usethis._integrations.project.layout import get_source_dir_str from usethis._integrations.pyproject.config import PyProjectConfig from usethis._integrations.pyproject.core import ( PyProjectTOMLValueAlreadySetError, @@ -280,7 +281,7 @@ def get_pyproject_configs(self) -> list[PyProjectConfig]: PyProjectConfig( id_keys=["tool", "coverage", "run"], value={ - "source": ["src"], + "source": [get_source_dir_str()], "omit": ["*/pytest-of-*/*"], }, ), @@ -316,9 +317,11 @@ def dev_deps(self) -> list[Dependency]: return [Dependency(name="deptry")] def print_how_to_use(self) -> None: - box_print("Run 'deptry src' to run deptry.") + _dir = get_source_dir_str() + box_print(f"Run 'deptry {_dir}' to run deptry.") def get_pre_commit_repos(self) -> list[LocalRepo | UriRepo]: + _dir = get_source_dir_str() return [ LocalRepo( repo="local", @@ -326,7 +329,7 @@ def get_pre_commit_repos(self) -> list[LocalRepo | UriRepo]: HookDefinition( id="deptry", name="deptry", - entry="uv run --frozen deptry src", + entry=f"uv run --frozen deptry {_dir}", language=Language("system"), always_run=True, pass_filenames=False, @@ -339,6 +342,7 @@ def get_pyproject_id_keys(self) -> list[list[str]]: return [["tool", "deptry"]] def get_bitbucket_steps(self) -> list[BitbucketStep]: + _dir = get_source_dir_str() return [ BitbucketStep( name="Run Deptry", @@ -346,7 +350,7 @@ def get_bitbucket_steps(self) -> list[BitbucketStep]: script=BitbucketScript( [ BitbucketScriptItemAnchor(name="install-uv"), - "uv run deptry src", + f"uv run deptry {_dir}", ] ), ) @@ -573,7 +577,6 @@ def get_pyproject_configs(self) -> list[PyProjectConfig]: PyProjectConfig( id_keys=["tool", "ruff"], value={ - "src": ["src"], "line-length": 88, "lint": {"select": []}, }, diff --git a/tests/usethis/_integrations/project/test_layout.py b/tests/usethis/_integrations/project/test_layout.py new file mode 100644 index 00000000..32c106f1 --- /dev/null +++ b/tests/usethis/_integrations/project/test_layout.py @@ -0,0 +1,39 @@ +from pathlib import Path + +from usethis._integrations.project.layout import get_source_dir_str +from usethis._test import change_cwd + + +class TestGetSourceDirStr: + def test_has_src(self, tmp_path: Path): + # Arrange + (tmp_path / "src").mkdir() + + # Act + with change_cwd(tmp_path): + result = get_source_dir_str() + + # Assert + assert result == "src" + + def test_no_src(self, tmp_path: Path): + # Arrange + (tmp_path / "foo").mkdir() + + # Act + with change_cwd(tmp_path): + result = get_source_dir_str() + + # Assert + assert result == "." + + def test_src_file_not_dir(self, tmp_path: Path): + # Arrange + (tmp_path / "src").touch() + + # Act + with change_cwd(tmp_path): + result = get_source_dir_str() + + # Assert + assert result == "." diff --git a/tests/usethis/_integrations/sonarqube/test_sonarqube_config.py b/tests/usethis/_integrations/sonarqube/test_sonarqube_config.py index cb9b65a9..61a09f61 100644 --- a/tests/usethis/_integrations/sonarqube/test_sonarqube_config.py +++ b/tests/usethis/_integrations/sonarqube/test_sonarqube_config.py @@ -95,7 +95,7 @@ def test_different_python_version(self, tmp_path: Path): sonar.projectKey=foobar sonar.language=py sonar.python.version=3.10 -sonar.sources=./src +sonar.sources=./ sonar.tests=./tests sonar.python.coverage.reportPaths=coverage.xml sonar.verbose=false @@ -125,7 +125,7 @@ def test_no_pin_python(self, tmp_path: Path): sonar.projectKey=foobar sonar.language=py sonar.python.version={get_python_version()} -sonar.sources=./src +sonar.sources=./ sonar.tests=./tests sonar.python.coverage.reportPaths=coverage.xml sonar.verbose=false @@ -156,7 +156,7 @@ def test_different_project_key(self, tmp_path: Path): sonar.projectKey=different sonar.language=py sonar.python.version=3.12 -sonar.sources=./src +sonar.sources=./ sonar.tests=./tests sonar.python.coverage.reportPaths=coverage.xml sonar.verbose=false @@ -191,7 +191,7 @@ def test_set_verbose_true(self, tmp_path: Path): sonar.projectKey=foobar sonar.language=py sonar.python.version=3.12 -sonar.sources=./src +sonar.sources=./ sonar.tests=./tests sonar.python.coverage.reportPaths=coverage.xml sonar.verbose=true @@ -239,7 +239,7 @@ def test_patch_version_ignored(self, tmp_path: Path): sonar.projectKey=foobar sonar.language=py sonar.python.version=3.12 -sonar.sources=./src +sonar.sources=./ sonar.tests=./tests sonar.python.coverage.reportPaths=coverage.xml sonar.verbose=false @@ -277,7 +277,7 @@ def test_exclusions(self, tmp_path: Path): sonar.projectKey=foobar sonar.language=py sonar.python.version=3.12 -sonar.sources=./src +sonar.sources=./ sonar.tests=./tests sonar.python.coverage.reportPaths=coverage.xml sonar.verbose=false @@ -309,7 +309,7 @@ def test_different_coverage_file_location(self, tmp_path: Path): sonar.projectKey=foobar sonar.language=py sonar.python.version=3.12 -sonar.sources=./src +sonar.sources=./ sonar.tests=./tests sonar.python.coverage.reportPaths=./test-reports/cov.xml sonar.verbose=false