diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12dbec4..e22ee38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,9 +63,28 @@ jobs: - run: py.test --cov=. - uses: codecov/codecov-action@v4 + + extras: + runs-on: ubuntu-latest + strategy: + matrix: + extras: + - "regex" + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.x" + - run: python -m pip install --upgrade pip setuptools + - run: python -m pip install -e .[test,${{ matrix.extras }}] + - run: relint --version + - run: py.test --cov=. + - uses: codecov/codecov-action@v4 + analyze: name: CodeQL Analyze - needs: [PyTest] + needs: [PyTest,extras] runs-on: ubuntu-latest permissions: actions: read diff --git a/README.md b/README.md index 6bb6eb8..e8ffccf 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ ```shell-session python3 -m pip install relint +# or, if you have super advanced linting expressions +python3 -m pip install relint[regex] ``` ## [Examples & Recipes – The reLint Cookbook](https://github.com/codingjoe/relint/blob/main/COOKBOOK.md) diff --git a/pyproject.toml b/pyproject.toml index d665334..1b4345d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,9 @@ test = [ "pytest-cov", "pytest-mock", ] +regex = [ + "regex" +] [project.scripts] relint = "relint.__main__:main" diff --git a/relint/config.py b/relint/config.py index 38be530..5e9046e 100644 --- a/relint/config.py +++ b/relint/config.py @@ -1,7 +1,11 @@ import collections -import re import warnings +try: + import regex as re +except ImportError: + import re + import yaml from .exceptions import ConfigError @@ -29,7 +33,7 @@ def load_config(path, fail_warnings, ignore_warnings): file_pattern = re.compile(file_pattern) yield Test( name=test["name"], - pattern=re.compile(test["pattern"], re.MULTILINE), + pattern=re.compile(test["pattern"]), hint=test.get("hint"), file_pattern=file_pattern, error=test.get("error", True) or fail_warnings, diff --git a/relint/parse.py b/relint/parse.py index 07138a6..192f3b2 100644 --- a/relint/parse.py +++ b/relint/parse.py @@ -1,7 +1,11 @@ from __future__ import annotations import collections -import re + +try: + import regex as re +except ImportError: + import re from rich import print as rprint from rich.console import Group @@ -65,7 +69,7 @@ def parse_line_numbers(output): def parse_filenames(output): - return re.findall(GIT_DIFF_FILENAME_PATTERN, output) + return GIT_DIFF_FILENAME_PATTERN.findall(output) def split_diff_content_by_filename(output: str) -> {str: str}: @@ -81,7 +85,7 @@ def split_diff_content_by_filename(output: str) -> {str: str}: """ content_by_filename = {} filenames = parse_filenames(output) - split_content = re.split(GIT_DIFF_SPLIT_PATTERN, output) + split_content = GIT_DIFF_SPLIT_PATTERN.split(output) split_content = filter(lambda x: x != "", split_content) for filename, content in zip(filenames, split_content): diff --git a/tests/test_parse.py b/tests/test_parse.py index fb33d95..5777d9b 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -4,8 +4,10 @@ import pytest from relint.__main__ import main +from relint.config import Test from relint.exceptions import ConfigError from relint.parse import ( + lint_file, match_with_diff_changes, parse_diff, parse_filenames, @@ -177,3 +179,40 @@ def test_no_unicode(capsys, tmpdir, fixture_dir): with pytest.raises(SystemExit) as exc_info: main(["test.png"]) assert "0" in str(exc_info.value) + + +def test_cc_linting_rule(tmpdir, fixture_dir): + regex = pytest.importorskip("regex") + cc_file = tmpdir.join("example.cpp") + cc_file.write( + "#include \n" + "/* This is an extremely long COMMENT that has over one hundred and twenty characters to test whether this is recognized by the regex or not. */\n" + "int main() {\n" + ' std::cout << "This is an extremely long CODE that has over one hundred and twenty characters to test whether this is recognized by the regex or not."\n' + " return 0;\n" + "}\n" + ) + + with (fixture_dir / ".relint.yml").open() as fs: + config = fs.read() + tmpdir.join(".relint.yml").write(config) + + # Load the configuration as Test named tuples + + with tmpdir.as_cwd(): + assert list( + lint_file( + str(cc_file), + [ + Test( + name="No line longer than 120 characters", + pattern=regex.compile( + r".{120,}(?