-
Notifications
You must be signed in to change notification settings - Fork 580
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bears/general: Add OutdatedDependencyBear
Closes #2445
- Loading branch information
Showing
2 changed files
with
143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from distutils.version import LooseVersion | ||
from coalib.bears.LocalBear import LocalBear | ||
from coalib.results.Result import Result | ||
from dependency_management.requirements.PipRequirement import ( | ||
parse_requirements_file, get_latest_version | ||
) | ||
from dependency_management.requirements.NpmRequirement import ( | ||
npm_outdated_command | ||
) | ||
|
||
|
||
class OutdatedDependencyBear(LocalBear): | ||
LANGUAGES = {'All'} | ||
AUTHORS = {'The coala developers'} | ||
AUTHORS_EMAILS = {'[email protected]'} | ||
LICENSE = 'AGPL-3.0' | ||
|
||
def run(self, filename, file, requirement_type: str,): | ||
""" | ||
Checks for the outdated dependencies in a project. | ||
:param requirement_type: | ||
One of the requirement types supported by coala's package manager. | ||
:param requirements_file: | ||
Requirements file can be specified to look for the requirements. | ||
""" | ||
requirement_types = ['pip', 'npm'] | ||
|
||
if requirement_type not in requirement_types: | ||
raise ValueError('Currently the bear only supports {} as ' | ||
'requirement_type.' | ||
.format(', '.join( | ||
type for type in requirement_types))) | ||
|
||
message = ('The requirement {} with version {} is not ' | ||
'pinned to its latest version {}.') | ||
|
||
if requirement_type == 'pip': | ||
data = parse_requirements_file(file) | ||
|
||
for req in data: | ||
latest_ver = get_latest_version(req['package_name']) | ||
print(latest_ver) | ||
if LooseVersion(req['version']) < LooseVersion(latest_ver): | ||
yield Result.from_values(origin=self, | ||
message=message.format( | ||
req['package_name'], | ||
req['version'], | ||
latest_ver), | ||
file=filename, | ||
line=req['line_number']+1, | ||
end_line=req['line_number']+1, | ||
) | ||
|
||
elif requirement_type == 'npm': | ||
data = npm_outdated_command() | ||
|
||
for req in data: | ||
latest_ver = data[req]['latest'] | ||
|
||
if LooseVersion(data[req]['wanted']) < LooseVersion(latest_ver): | ||
yield Result.from_values(origin=self, | ||
message=message.format( | ||
req, | ||
data[req]['wanted'], | ||
latest_ver), | ||
file=filename, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import unittest.mock | ||
from queue import Queue | ||
|
||
from bears.general.OutdatedDependencyBear import OutdatedDependencyBear | ||
from coalib.testing.LocalBearTestHelper import LocalBearTestHelper | ||
from coalib.results.Result import Result | ||
from coalib.settings.Section import Section | ||
from coalib.settings.Setting import Setting | ||
|
||
|
||
test_file = """ | ||
foo==1.0 | ||
bar~=2.0 | ||
""" | ||
|
||
|
||
class OutdatedDependencyBearTest(LocalBearTestHelper): | ||
|
||
def setUp(self): | ||
self.section = Section('') | ||
self.uut = OutdatedDependencyBear(self.section, Queue()) | ||
|
||
@unittest.mock.patch('bears.general.OutdatedDependencyBear.' | ||
'get_latest_version') | ||
def test_pip_requirement_type(self, _mock): | ||
self.section.append(Setting('requirement_type', 'pip')) | ||
_mock.return_value = '3.0' | ||
message = ('The requirement {} with version {} is not ' | ||
'pinned to its latest version 3.0.') | ||
self.check_results(self.uut, | ||
test_file.splitlines(True), | ||
[Result.from_values( | ||
origin='OutdatedDependencyBear', | ||
message=message.format('foo', '1.0'), | ||
file='default', | ||
line=2, end_line=2, | ||
), | ||
Result.from_values( | ||
origin='OutdatedDependencyBear', | ||
message=message.format('bar', '2.0'), | ||
file='default', | ||
line=3, end_line=3, | ||
)], | ||
filename='default', | ||
) | ||
|
||
@unittest.mock.patch('bears.general.OutdatedDependencyBear.' | ||
'npm_outdated_command') | ||
def test_npm_requirement_type(self, _mock): | ||
self.section.append(Setting('requirement_type', 'npm')) | ||
_mock.return_value = {'foo': {'wanted': '1.0', 'latest': '3.0'}, | ||
'bar': {'wanted': '2.0', 'latest': '3.0'}} | ||
message = ('The requirement {} with version {} is not ' | ||
'pinned to its latest version 3.0.') | ||
self.check_results(self.uut, | ||
test_file.splitlines(True), | ||
[Result.from_values( | ||
origin='OutdatedDependencyBear', | ||
message=message.format('foo', '1.0'), | ||
file='default', | ||
), | ||
Result.from_values( | ||
origin='OutdatedDependencyBear', | ||
message=message.format('bar', '2.0'), | ||
file='default', | ||
)], | ||
filename='default', | ||
) | ||
|
||
def test_requirement_type_value_error(self): | ||
self.section.append(Setting('requirement_type', 'blabla')) | ||
error = ('ValueError: Currently the bear only supports pip, npm as ' | ||
'requirement_type.') | ||
with self.assertRaisesRegex(AssertionError, error): | ||
self.check_validity(self.uut, [], filename='default') |