Commit 7ecd9f4b authored by paroga@webkit.org's avatar paroga@webkit.org

2011-03-27 Patrick Gansterer <paroga@webkit.org>

        Reviewed by David Levin.

        check-webkit-style should check ChangeLog for a valid bug number
        https://bugs.webkit.org/show_bug.cgi?id=57184

        * Scripts/webkitpy/style/checker.py:
        * Scripts/webkitpy/style/checker_unittest.py:
        * Scripts/webkitpy/style/checkers/changelog.py: Added.
        * Scripts/webkitpy/style/checkers/changelog_unittest.py: Added.

git-svn-id: svn://svn.chromium.org/blink/trunk@82083 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 3ae0ed80
2011-03-27 Patrick Gansterer <paroga@webkit.org>
Reviewed by David Levin.
check-webkit-style should check ChangeLog for a valid bug number
https://bugs.webkit.org/show_bug.cgi?id=57184
* Scripts/webkitpy/style/checker.py:
* Scripts/webkitpy/style/checker_unittest.py:
* Scripts/webkitpy/style/checkers/changelog.py: Added.
* Scripts/webkitpy/style/checkers/changelog_unittest.py: Added.
2011-03-27 Benjamin Poulain <benjamin.poulain@nokia.com> 2011-03-27 Benjamin Poulain <benjamin.poulain@nokia.com>
Reviewed by Andreas Kling. Reviewed by Andreas Kling.
......
...@@ -36,6 +36,7 @@ import sys ...@@ -36,6 +36,7 @@ import sys
from checkers.common import categories as CommonCategories from checkers.common import categories as CommonCategories
from checkers.common import CarriageReturnChecker from checkers.common import CarriageReturnChecker
from checkers.changelog import ChangeLogChecker
from checkers.cpp import CppChecker from checkers.cpp import CppChecker
from checkers.python import PythonChecker from checkers.python import PythonChecker
from checkers.test_expectations import TestExpectationsChecker from checkers.test_expectations import TestExpectationsChecker
...@@ -420,10 +421,11 @@ class FileType: ...@@ -420,10 +421,11 @@ class FileType:
NONE = 0 # FileType.NONE evaluates to False. NONE = 0 # FileType.NONE evaluates to False.
# Alphabetize remaining types # Alphabetize remaining types
CPP = 1 CHANGELOG = 1
PYTHON = 2 CPP = 2
TEXT = 3 PYTHON = 3
XML = 4 TEXT = 4
XML = 5
class CheckerDispatcher(object): class CheckerDispatcher(object):
...@@ -482,8 +484,9 @@ class CheckerDispatcher(object): ...@@ -482,8 +484,9 @@ class CheckerDispatcher(object):
return FileType.PYTHON return FileType.PYTHON
elif file_extension in _XML_FILE_EXTENSIONS: elif file_extension in _XML_FILE_EXTENSIONS:
return FileType.XML return FileType.XML
elif (os.path.basename(file_path).startswith('ChangeLog') or elif os.path.basename(file_path).startswith('ChangeLog'):
(not file_extension and os.path.join("Tools", "Scripts") in file_path) or return FileType.CHANGELOG
elif ((not file_extension and os.path.join("Tools", "Scripts") in file_path) or
file_extension in _TEXT_FILE_EXTENSIONS): file_extension in _TEXT_FILE_EXTENSIONS):
return FileType.TEXT return FileType.TEXT
else: else:
...@@ -494,6 +497,8 @@ class CheckerDispatcher(object): ...@@ -494,6 +497,8 @@ class CheckerDispatcher(object):
"""Instantiate and return a style checker based on file type.""" """Instantiate and return a style checker based on file type."""
if file_type == FileType.NONE: if file_type == FileType.NONE:
checker = None checker = None
elif file_type == FileType.CHANGELOG:
checker = ChangeLogChecker(file_path, handle_style_error)
elif file_type == FileType.CPP: elif file_type == FileType.CPP:
file_extension = self._file_extension(file_path) file_extension = self._file_extension(file_path)
checker = CppChecker(file_path, file_extension, checker = CppChecker(file_path, file_extension,
......
...@@ -52,6 +52,7 @@ from checker import CheckerDispatcher ...@@ -52,6 +52,7 @@ from checker import CheckerDispatcher
from checker import ProcessorBase from checker import ProcessorBase
from checker import StyleProcessor from checker import StyleProcessor
from checker import StyleProcessorConfiguration from checker import StyleProcessorConfiguration
from checkers.changelog import ChangeLogChecker
from checkers.cpp import CppChecker from checkers.cpp import CppChecker
from checkers.python import PythonChecker from checkers.python import PythonChecker
from checkers.text import TextChecker from checkers.text import TextChecker
...@@ -395,6 +396,10 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): ...@@ -395,6 +396,10 @@ class CheckerDispatcherDispatchTest(unittest.TestCase):
"got_class": got_class, "got_class": got_class,
"expected_class": expected_class}) "expected_class": expected_class})
def assert_checker_changelog(self, file_path):
"""Assert that the dispatched checker is a ChangeLogChecker."""
self.assert_checker(file_path, ChangeLogChecker)
def assert_checker_cpp(self, file_path): def assert_checker_cpp(self, file_path):
"""Assert that the dispatched checker is a CppChecker.""" """Assert that the dispatched checker is a CppChecker."""
self.assert_checker(file_path, CppChecker) self.assert_checker(file_path, CppChecker)
...@@ -411,6 +416,25 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): ...@@ -411,6 +416,25 @@ class CheckerDispatcherDispatchTest(unittest.TestCase):
"""Assert that the dispatched checker is a XMLChecker.""" """Assert that the dispatched checker is a XMLChecker."""
self.assert_checker(file_path, XMLChecker) self.assert_checker(file_path, XMLChecker)
def test_changelog_paths(self):
"""Test paths that should be checked as ChangeLog."""
paths = [
"ChangeLog",
"ChangeLog-2009-06-16",
os.path.join("Source", "WebCore", "ChangeLog"),
]
for path in paths:
self.assert_checker_changelog(path)
# Check checker attributes on a typical input.
file_path = "ChangeLog"
self.assert_checker_changelog(file_path)
checker = self.dispatch(file_path)
self.assertEquals(checker.file_path, file_path)
self.assertEquals(checker.handle_style_error,
self.mock_handle_style_error)
def test_cpp_paths(self): def test_cpp_paths(self):
"""Test paths that should be checked as C++.""" """Test paths that should be checked as C++."""
paths = [ paths = [
...@@ -465,8 +489,6 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): ...@@ -465,8 +489,6 @@ class CheckerDispatcherDispatchTest(unittest.TestCase):
def test_text_paths(self): def test_text_paths(self):
"""Test paths that should be checked as text.""" """Test paths that should be checked as text."""
paths = [ paths = [
"ChangeLog",
"ChangeLog-2009-06-16",
"foo.ac", "foo.ac",
"foo.cc", "foo.cc",
"foo.cgi", "foo.cgi",
...@@ -491,7 +513,6 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): ...@@ -491,7 +513,6 @@ class CheckerDispatcherDispatchTest(unittest.TestCase):
"foo.wm", "foo.wm",
"foo.xhtml", "foo.xhtml",
"foo.y", "foo.y",
os.path.join("Source", "WebCore", "ChangeLog"),
os.path.join("Source", "WebCore", "inspector", "front-end", "inspector.js"), os.path.join("Source", "WebCore", "inspector", "front-end", "inspector.js"),
os.path.join("Tools", "Scripts", "check-webkit-style"), os.path.join("Tools", "Scripts", "check-webkit-style"),
] ]
......
#!/usr/bin/env python
#
# Copyright (C) 2011 Patrick Gansterer <paroga@paroga.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Checks WebKit style for ChangeLog files."""
import re
from common import TabChecker
from webkitpy.common.net.bugzilla import parse_bug_id
class ChangeLogChecker(object):
"""Processes text lines for checking style."""
def __init__(self, file_path, handle_style_error):
self.file_path = file_path
self.handle_style_error = handle_style_error
self._tab_checker = TabChecker(file_path, handle_style_error)
def check_entry(self, entry_line_number, entry_lines):
for line in entry_lines:
if parse_bug_id(line):
break
if re.search("Unreviewed", line, re.IGNORECASE):
break
if re.search("build", line, re.IGNORECASE) and re.search("fix", line, re.IGNORECASE):
break
else:
self.handle_style_error(entry_line_number + 1,
"changelog/bugnumber", 5,
"ChangeLog entry has no bug number")
def check(self, lines):
self._tab_checker.check(lines)
entry_line_number = 0
entry_lines = []
started_at_first_line = False
for line_number, line in enumerate(lines):
if re.match("^\d{4}-\d{2}-\d{2}", line):
if line_number:
self.check_entry(entry_line_number, entry_lines)
else:
started_at_first_line = True
entry_line_number = line_number
entry_lines = []
entry_lines.append(line)
if started_at_first_line:
self.check_entry(entry_line_number, entry_lines)
#!/usr/bin/env python
#
# Copyright (C) 2010 Apple Inc. All rights reserved.
# Copyright (C) 2011 Patrick Gansterer <paroga@paroga.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Unit test for changelog.py."""
import changelog
import unittest
class ChangeLogCheckerTest(unittest.TestCase):
"""Tests ChangeLogChecker class."""
def assert_no_error(self, changelog_data):
def handle_style_error(line_number, category, confidence, message):
self.fail('Unexpected error: %d %s %d %s' % (line_number, category, confidence, message))
checker = changelog.ChangeLogChecker('ChangeLog', handle_style_error)
checker.check(changelog_data.split('\n'))
def assert_error(self, expected_line_number, expected_category, changelog_data):
self.had_error = False
def handle_style_error(line_number, category, confidence, message):
self.had_error = True
self.assertEquals(expected_line_number, line_number)
self.assertEquals(expected_category, category)
checker = changelog.ChangeLogChecker('ChangeLog', handle_style_error)
checker.check(changelog_data.split('\n'))
self.assertTrue(self.had_error)
def mock_handle_style_error(self):
pass
def test_init(self):
checker = changelog.ChangeLogChecker('ChangeLog', self.mock_handle_style_error)
self.assertEquals(checker.file_path, 'ChangeLog')
self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
def test_missing_bug_number(self):
entries = [
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug\n http://bugs.webkit.org/show_bug.cgi?id=\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug\n https://bugs.webkit.org/show_bug.cgi?id=\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug\n http://webkit.org/b/\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug\n http://trac.webkit.org/changeset/12345\n',
'Example bug\n https://bugs.webkit.org/show_bug.cgi\n\n2011-01-01 Patrick Gansterer <paroga@paroga.com>\n',
'Example bug\n More text about bug.\n\n2011-01-01 Patrick Gansterer <paroga@paroga.com>\n',
]
for entry in entries:
self.assert_error(1, 'changelog/bugnumber', entry)
def test_no_error(self):
entries = [
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug\n http://bugs.webkit.org/show_bug.cgi?id=12345\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug\n https://bugs.webkit.org/show_bug.cgi?id=12345\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Example bug\n http://webkit.org/b/12345\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Unreview build fix for r12345.\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Fix build after a bad change.\n',
'2011-01-01 Patrick Gansterer <paroga@paroga.com>\n\n Fix example port build.\n',
'Example bug\n https://bugs.webkit.org/show_bug.cgi?id=12345\n\n2011-01-01 Patrick Gansterer <paroga@paroga.com>\n',
]
for entry in entries:
self.assert_no_error(entry)
if __name__ == '__main__':
unittest.main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment