blob: 35c0433e011c9ff8e660f2414c869bc7fb5a6175 [file] [log] [blame]
Mike Frysinger56e8de02019-07-31 14:40:14 -04001# -*- coding: utf-8 -*-
Ryan Cui1562fb82011-05-09 11:01:31 -07002# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Mike Frysingerae409522014-02-01 03:16:11 -05006"""Common errors thrown when repo presubmit checks fail."""
7
Mike Frysinger09d6a3d2013-10-08 22:21:03 -04008from __future__ import print_function
9
Ryan Cui1562fb82011-05-09 11:01:31 -070010import re
11import sys
12
13
14class VerifyException(Exception):
Mike Frysingerae409522014-02-01 03:16:11 -050015 """Basic sanity checks failed."""
Ryan Cui1562fb82011-05-09 11:01:31 -070016
17
18class HookFailure(object):
19 """Contains an error message and a list of error details."""
20 def __init__(self, msg, items=None):
21 self.msg = msg
22 self.items = items
23
Daniel Erat9d203ff2015-02-17 10:12:21 -070024 def __str__(self):
25 return _FormatHookFailure(self)
26
Ryan Cui1562fb82011-05-09 11:01:31 -070027
28_INDENT = ' ' * 4
29_PROJECT_INFO = 'Errors in PROJECT *%s*!'
30
Mike Frysingerae409522014-02-01 03:16:11 -050031
Ryan Cui1562fb82011-05-09 11:01:31 -070032def _PrintWithIndent(msg, indent_level):
33 """Print a block of text with a specified indent level to stderr.
34
35 Args:
36 msg: A string to print (may contain newlines).
37 indent_level: The number of indents to prefix each line with. Each indent
38 is four characters wide.
39 """
40 regex = re.compile(r'^', re.M)
41 msg = regex.sub(_INDENT * indent_level, msg)
Mike Frysinger09d6a3d2013-10-08 22:21:03 -040042 print(msg, file=sys.stderr)
Ryan Cui1562fb82011-05-09 11:01:31 -070043
44
45def _FormatCommitDesc(desc):
46 """Returns the properly prefixed commit description."""
47 regex = re.compile(r'^', re.M)
48 return regex.sub('>', desc)
49
50
51def _FormatHookFailure(hook_failure):
52 """Returns the properly formatted VerifyException as a string."""
53 item_prefix = '\n%s* ' % _INDENT
54 formatted_items = ''
55 if hook_failure.items:
56 formatted_items = item_prefix + item_prefix.join(hook_failure.items)
57 return '* ' + hook_failure.msg + formatted_items
58
59
60def PrintErrorForProject(project, error):
61 """Prints the project and its error.
62
63 Args:
64 project: project name
65 error: An instance of the HookFailure class
66 """
67 _PrintWithIndent(_PROJECT_INFO % project, 0)
68 _PrintWithIndent(_FormatHookFailure(error), 1)
Mike Frysinger09d6a3d2013-10-08 22:21:03 -040069 print('', file=sys.stderr)
Ryan Cui1562fb82011-05-09 11:01:31 -070070
71
72def PrintErrorsForCommit(project, commit, commit_desc, error_list):
73 """Prints the hook error to stderr with project and commit context
74
75 A sample error output for a project would be:
76 ----------------------------------------------------------------------------
77 Errors in PROJECT *chromiumos/repohooks*!
78 COMMIT 10041758:
79 Description:
80 >staged
81 >
82 >TEST=some
83 >Change-Id: I2c4f545a20a659541c02be16aa9dc440c876a604
84 >
85 Errors:
86 * Changelist description needs BUG field (after first line)
87 * Found line ending with white space in:
88 * src/repohooks/pre-upload.py, line 307
89 * Found lines longer than 80 characters (first 5 shown):
90 * src/repohooks/pre-upload.py, line 335, 85 chars
91 ----------------------------------------------------------------------------
92
93 Args:
94 project: project name
95 commit: the commit hash the errors belong to
96 commit_desc: a string containing the commit message
97 error_list: a list of HookFailure instances
98 """
99 _PrintWithIndent(_PROJECT_INFO % project, 0)
100
101 formatted_desc = _FormatCommitDesc(commit_desc)
102 _PrintWithIndent('COMMIT %s:' % commit[:8], 1)
103 _PrintWithIndent('Description:', 2)
104 _PrintWithIndent(formatted_desc, 3)
105 _PrintWithIndent('Errors:', 2)
106
107 for error in error_list:
108 _PrintWithIndent(_FormatHookFailure(error), 3)
109
Mike Frysinger09d6a3d2013-10-08 22:21:03 -0400110 print('', file=sys.stderr)