Skip to content

Commit

Permalink
Allow selection of additional dependency groups - fix #44 (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
kurthaegeman authored Aug 2, 2023
1 parent 5d9dc6c commit 953c7b7
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 16 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
max-parallel: 5
matrix:
python-version: [3.7, 3.8, 3.9, '3.10', '3.11']
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
steps:
- name: Checkout 🛎️
uses: actions/checkout@v3
Expand All @@ -26,10 +26,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install --upgrade . -r dev-requirements.txt
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | python
- name: Execute all pre-commit hooks on all files ☑
if: matrix.python-version != '3.11'
# cf. https://github.com/PyCQA/pylint/issues/7972#issuecomment-1370602977
run: pre-commit run --all-files
- name: Running tests ☑
run: pytest
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
*.pyc
/pre_commit_hooks_safety.egg-info
/.cache/
/.coverage
**/.coverage
/venv/
/.idea/
build/
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Note that **telemetry data will be sent with every Safety call**. These data are
```
## How to Use Arguments
There are a few different arguements that this hook will accept.
There are a few different arguments that this hook will accept.
The first is the `files` arguement. Simply put which file your dependancies are listed in.
The first is the `files` argument. Simply put which file your dependencies are listed in.
```yaml
- repo: https://github.com/Lucas-C/pre-commit-hooks-safety
rev: v1.3.1
Expand All @@ -35,7 +35,15 @@ The next is the `--ignore` flag. This will ignore a comma seperated list of know
- id: python-safety-dependencies-check
args: ["--ignore=39153,39652"]
```
You can also select between `--full-report` and `--short-report`. By default safety will use the `--full-report` flag so you can omit it for cleaner code.
The `--groups` flag will allow you to select additional dependency groups, other than the implicit main group. An example:
```yaml
- repo: https://github.com/Lucas-C/pre-commit-hooks-safety
rev: v1.3.1
hooks:
- id: python-safety-dependencies-check
args: ["--groups=dev,test"]
```
You can also select between `--full-report` and `--short-report`. By default, safety will use the `--full-report` flag so you can omit it for cleaner code.
```yaml
- repo: https://github.com/Lucas-C/pre-commit-hooks-safety
rev: v1.3.1
Expand Down
3 changes: 2 additions & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pre-commit
pylint
pytest
pytest-cov
pytest-cov
poetry
16 changes: 13 additions & 3 deletions pre_commit_hooks/safety_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

def build_parser():
parser = argparse.ArgumentParser()

class AppendStringAction(argparse.Action): # pylint: disable=too-few-public-methods
def __call__(self, _, namespace, values, option_string=None):
setattr(namespace, self.dest, values.split(','))

parser.add_argument(
"--full-report",
dest="report_arg",
Expand All @@ -28,6 +33,7 @@ def build_parser():
const="--short-report",
)
parser.add_argument("--ignore", "-i", action="append")
parser.add_argument("--groups", "-g", default=[], action=AppendStringAction)
parser.add_argument("files", nargs="+")
return parser

Expand All @@ -43,7 +49,7 @@ def main(argv=None): # pylint: disable=inconsistent-return-statements
with pyproject_toml_filepath.open() as pyproject_file:
lines = [line.strip() for line in pyproject_file.readlines()]
if any(line.startswith("[tool.poetry]") for line in lines):
with convert_poetry_to_requirements(pyproject_toml_filepath) as tmp_requirements:
with convert_poetry_to_requirements(pyproject_toml_filepath, groups=parsed_args.groups) as tmp_requirements:
return call_safety_check([tmp_requirements.name], parsed_args.ignore, parsed_args.report_arg, args_rest)
parser.error("Unsupported build tool: this pre-commit hook currently only handles pyproject.toml with Poetry"
" ([tool.poetry] must be present in pyproject.toml)")
Expand All @@ -70,7 +76,7 @@ def call_safety_check(requirements_file_paths, ignore_args, report_arg, args_res


@contextmanager
def convert_poetry_to_requirements(pyproject_toml_filepath): # Sad function name :(
def convert_poetry_to_requirements(pyproject_toml_filepath, groups): # Sad function name :(
poetry_cmd_path = which("poetry")
if not poetry_cmd_path: # Using install-poetry.py installation $PATH:
poetry_cmd_path = os.path.join(os.environ.get("HOME", ""), ".local", "bin", "poetry")
Expand All @@ -82,7 +88,11 @@ def convert_poetry_to_requirements(pyproject_toml_filepath): # Sad function nam
with ntf:
# Placing ourselves in the pyproject.toml parent directory:
with chdir(pyproject_toml_filepath.parent):
check_call([poetry_cmd_path, "export", "--with", "dev", "--format", "requirements.txt", "--output", ntf.name])
cmd = [poetry_cmd_path, "export", "--format", "requirements.txt", "--output", ntf.name]
# Add groups to include in the export command
for group in groups:
cmd.extend(["--with", group])
check_call(cmd)
yield ntf
finally: # Manually deleting temporary file:
os.remove(ntf.name)
Expand Down
37 changes: 33 additions & 4 deletions tests/safety_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ def test_poetry_requirements(tmpdir): # cf. https://github.com/Lucas-C/pre-comm
colored-traceback==0.3.0 \
--hash=sha256:6da7ce2b1da869f6bb54c927b415b95727c4bb6d9a84c4615ea77d9872911b05 \
--hash=sha256:f76c21a4b4c72e9e09763d4d1b234afc469c88693152a763ad6786467ef9e79f
configobj==5.0.6
future==0.18.3
six==1.13.0 \
--hash=sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd \
Expand All @@ -90,7 +89,8 @@ def test_pyproject_toml_without_deps(tmpdir):
name = 'Thing'
version = '1.2.3'
description = 'Dummy'
authors = ['Lucas Cimon']""")
authors = ['Lucas Cimon']
""")
assert safety([str(pyproject_file)]) == 0

def test_pyproject_toml_with_ko_deps(tmpdir):
Expand All @@ -103,7 +103,8 @@ def test_pyproject_toml_with_ko_deps(tmpdir):
[tool.poetry.dependencies]
python = "^3.7"
jsonpickle = '1.4.1'""")
jsonpickle = '1.4.1'
""")
assert safety([str(pyproject_file)]) == EXIT_CODE_VULNERABILITIES_FOUND

def test_pyproject_toml_with_ko_dev_deps(tmpdir):
Expand All @@ -117,6 +118,34 @@ def test_pyproject_toml_with_ko_dev_deps(tmpdir):
[tool.poetry.dependencies]
python = "^3.7"
# Poetry pre-1.2.x style
[tool.poetry.dev-dependencies]
jsonpickle = '1.4.1'""")
assert safety([str(pyproject_file)]) == EXIT_CODE_VULNERABILITIES_FOUND
assert safety([str(pyproject_file), "--groups=dev"]) == EXIT_CODE_VULNERABILITIES_FOUND

@pytest.mark.parametrize(
"group_arg,status",
[
("--groups=dev", 0),
("--groups=dev,test", EXIT_CODE_VULNERABILITIES_FOUND),
("--groups=test", EXIT_CODE_VULNERABILITIES_FOUND),
]
)
def test_pyproject_toml_with_groups(tmpdir, group_arg, status):
pyproject_file = tmpdir.join('pyproject.toml')
pyproject_file.write("""[tool.poetry]
name = 'Thing'
version = '1.2.3'
description = 'Dummy'
authors = ['Lucas Cimon']
[tool.poetry.dependencies]
python = "^3.7"
# Poetry 1.2.0 style
[tool.poetry.group.dev.dependencies]
colored = "1.4.2"
[tool.poetry.group.test.dependencies]
insecure-package = '0.1.0'""")
assert safety([str(pyproject_file), group_arg]) == status

0 comments on commit 953c7b7

Please sign in to comment.