Skip to content

Commit

Permalink
bears/general: Add OutdatedDependencyBear
Browse files Browse the repository at this point in the history
Closes coala#2445
  • Loading branch information
bkhanale committed Jun 24, 2019
1 parent fd5a5a7 commit 2e71e49
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
71 changes: 71 additions & 0 deletions bears/general/OutdatedDependencyBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import os

import logging
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 not requirement_type 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,
)
74 changes: 74 additions & 0 deletions tests/general/OutdatedDependencyBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
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')

0 comments on commit 2e71e49

Please sign in to comment.