mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 18:51:29 +00:00
presubmit: upload presubmit result as code findings
The recipe will convert presubmit result to finding as long as it has location data. Change-Id: I8e0ce4cf5f66d6236f10c21a6db87d293b3fe379 Bug: 404837554 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/6469944 Commit-Queue: Yiwei Zhang <yiwzhang@google.com> Reviewed-by: Gavin Mak <gavinmak@google.com>
This commit is contained in:
@@ -830,19 +830,22 @@ Raises:
|
||||
— **def [initialize](/recipes/recipe_modules/osx_sdk/api.py#56)(self):**
|
||||
### *recipe_modules* / [presubmit](/recipes/recipe_modules/presubmit)
|
||||
|
||||
[DEPS](/recipes/recipe_modules/presubmit/__init__.py#13): [bot\_update](#recipe_modules-bot_update), [depot\_tools](#recipe_modules-depot_tools), [gclient](#recipe_modules-gclient), [git](#recipe_modules-git), [tryserver](#recipe_modules-tryserver), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/cv][recipe_engine/recipe_modules/cv], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/resultdb][recipe_engine/recipe_modules/resultdb], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||
[DEPS](/recipes/recipe_modules/presubmit/__init__.py#13): [bot\_update](#recipe_modules-bot_update), [depot\_tools](#recipe_modules-depot_tools), [gclient](#recipe_modules-gclient), [git](#recipe_modules-git), [tryserver](#recipe_modules-tryserver), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/cv][recipe_engine/recipe_modules/cv], [recipe\_engine/findings][recipe_engine/recipe_modules/findings], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/resultdb][recipe_engine/recipe_modules/resultdb], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||
|
||||
|
||||
#### **class [PresubmitApi](/recipes/recipe_modules/presubmit/api.py#16)([RecipeApi][recipe_engine/wkt/RecipeApi]):**
|
||||
#### **class [PresubmitApi](/recipes/recipe_modules/presubmit/api.py#17)([RecipeApi][recipe_engine/wkt/RecipeApi]):**
|
||||
|
||||
— **def [\_\_call\_\_](/recipes/recipe_modules/presubmit/api.py#28)(self, \*args, \*\*kwargs):**
|
||||
— **def [\_\_call\_\_](/recipes/recipe_modules/presubmit/api.py#29)(self, \*args, \*\*kwargs):**
|
||||
|
||||
Returns a presubmit step.
|
||||
|
||||
— **def [execute](/recipes/recipe_modules/presubmit/api.py#116)(self, bot_update_step, skip_owners=False, run_all=False):**
|
||||
— **def [execute](/recipes/recipe_modules/presubmit/api.py#117)(self, bot_update_step, skip_owners=False, run_all=False):**
|
||||
|
||||
Runs presubmit and sets summary markdown if applicable.
|
||||
|
||||
Also uploads the presubmit results as findings if the results contain
|
||||
location data.
|
||||
|
||||
Args:
|
||||
* bot_update_step: the StepResult from a previously executed bot_update step.
|
||||
* skip_owners: a boolean indicating whether Owners checks should be skipped.
|
||||
@@ -850,7 +853,7 @@ Args:
|
||||
Returns:
|
||||
a RawResult object, suitable for being returned from RunSteps.
|
||||
|
||||
— **def [prepare](/recipes/recipe_modules/presubmit/api.py#49)(self, root_solution_revision=None):**
|
||||
— **def [prepare](/recipes/recipe_modules/presubmit/api.py#50)(self, root_solution_revision=None):**
|
||||
|
||||
Sets up a presubmit run.
|
||||
|
||||
@@ -867,7 +870,7 @@ Args:
|
||||
Returns:
|
||||
the StepResult from the bot_update step.
|
||||
|
||||
  **@property**<br>— **def [presubmit\_support\_path](/recipes/recipe_modules/presubmit/api.py#24)(self):**
|
||||
  **@property**<br>— **def [presubmit\_support\_path](/recipes/recipe_modules/presubmit/api.py#25)(self):**
|
||||
### *recipe_modules* / [tryserver](/recipes/recipe_modules/tryserver)
|
||||
|
||||
[DEPS](/recipes/recipe_modules/tryserver/__init__.py#7): [gerrit](#recipe_modules-gerrit), [git](#recipe_modules-git), [git\_cl](#recipe_modules-git_cl), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/led][recipe_engine/recipe_modules/led], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/platform][recipe_engine/recipe_modules/platform], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/step][recipe_engine/recipe_modules/step]
|
||||
@@ -1205,10 +1208,10 @@ Move things around in a loop!
|
||||
— **def [RunSteps](/recipes/recipe_modules/presubmit/examples/full.py#13)(api):**
|
||||
### *recipes* / [presubmit:tests/execute](/recipes/recipe_modules/presubmit/tests/execute.py)
|
||||
|
||||
[DEPS](/recipes/recipe_modules/presubmit/tests/execute.py#12): [gclient](#recipe_modules-gclient), [presubmit](#recipe_modules-presubmit), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/cq][recipe_engine/recipe_modules/cq], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime]
|
||||
[DEPS](/recipes/recipe_modules/presubmit/tests/execute.py#13): [gclient](#recipe_modules-gclient), [presubmit](#recipe_modules-presubmit), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/cq][recipe_engine/recipe_modules/cq], [recipe\_engine/json][recipe_engine/recipe_modules/json], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/proto][recipe_engine/recipe_modules/proto], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime]
|
||||
|
||||
|
||||
— **def [RunSteps](/recipes/recipe_modules/presubmit/tests/execute.py#25)(api):**
|
||||
— **def [RunSteps](/recipes/recipe_modules/presubmit/tests/execute.py#27)(api):**
|
||||
### *recipes* / [presubmit:tests/prepare](/recipes/recipe_modules/presubmit/tests/prepare.py)
|
||||
|
||||
[DEPS](/recipes/recipe_modules/presubmit/tests/prepare.py#11): [gclient](#recipe_modules-gclient), [presubmit](#recipe_modules-presubmit), [recipe\_engine/buildbucket][recipe_engine/recipe_modules/buildbucket], [recipe\_engine/context][recipe_engine/recipe_modules/context], [recipe\_engine/path][recipe_engine/recipe_modules/path], [recipe\_engine/properties][recipe_engine/recipe_modules/properties], [recipe\_engine/raw\_io][recipe_engine/recipe_modules/raw_io], [recipe\_engine/runtime][recipe_engine/recipe_modules/runtime]
|
||||
@@ -1279,12 +1282,14 @@ Move things around in a loop!
|
||||
[recipe_engine/recipe_modules/cq]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-cq
|
||||
[recipe_engine/recipe_modules/cv]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-cv
|
||||
[recipe_engine/recipe_modules/file]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-file
|
||||
[recipe_engine/recipe_modules/findings]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-findings
|
||||
[recipe_engine/recipe_modules/json]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-json
|
||||
[recipe_engine/recipe_modules/led]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-led
|
||||
[recipe_engine/recipe_modules/milo]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-milo
|
||||
[recipe_engine/recipe_modules/path]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-path
|
||||
[recipe_engine/recipe_modules/platform]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-platform
|
||||
[recipe_engine/recipe_modules/properties]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-properties
|
||||
[recipe_engine/recipe_modules/proto]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-proto
|
||||
[recipe_engine/recipe_modules/raw_io]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-raw_io
|
||||
[recipe_engine/recipe_modules/resultdb]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-resultdb
|
||||
[recipe_engine/recipe_modules/runtime]: https://chromium.googlesource.com/infra/luci/recipes-py.git/+/c531c52ec17dfef3e6bc77f0eb7493d48e3679ae/README.recipes.md#recipe_modules-runtime
|
||||
|
||||
@@ -18,6 +18,7 @@ DEPS = [
|
||||
'recipe_engine/buildbucket',
|
||||
'recipe_engine/context',
|
||||
'recipe_engine/cv',
|
||||
'recipe_engine/findings',
|
||||
'recipe_engine/json',
|
||||
'recipe_engine/path',
|
||||
'recipe_engine/properties',
|
||||
|
||||
@@ -6,6 +6,7 @@ from recipe_engine import recipe_api
|
||||
|
||||
from PB.recipe_engine import result as result_pb2
|
||||
from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
|
||||
from PB.go.chromium.org.luci.common.proto.findings import findings as findings_pb
|
||||
|
||||
# 8 minutes seems like a reasonable upper bound on presubmit timings.
|
||||
# According to event mon data we have, it seems like anything longer than
|
||||
@@ -116,6 +117,9 @@ class PresubmitApi(recipe_api.RecipeApi):
|
||||
def execute(self, bot_update_step, skip_owners=False, run_all=False):
|
||||
"""Runs presubmit and sets summary markdown if applicable.
|
||||
|
||||
Also uploads the presubmit results as findings if the results contain
|
||||
location data.
|
||||
|
||||
Args:
|
||||
* bot_update_step: the StepResult from a previously executed bot_update step.
|
||||
* skip_owners: a boolean indicating whether Owners checks should be skipped.
|
||||
@@ -210,8 +214,50 @@ class PresubmitApi(recipe_api.RecipeApi):
|
||||
' while running presubmit checks.'
|
||||
' Please [file a bug](https://issues.chromium.org'
|
||||
'/issues/new?component=1456211)')
|
||||
if step_json:
|
||||
self._upload_findings_from_result(step_json)
|
||||
return raw_result
|
||||
|
||||
def _upload_findings_from_result(self, result_json):
|
||||
findings = []
|
||||
base_finding = findings_pb.Finding(
|
||||
category='chromium_presubmit',
|
||||
location=findings_pb.Location(
|
||||
gerrit_change_ref=findings_pb.Location.GerritChangeReference(
|
||||
host=self.m.tryserver.gerrit_change.host,
|
||||
project=self.m.tryserver.gerrit_change.project,
|
||||
change=self.m.tryserver.gerrit_change.change,
|
||||
patchset=self.m.tryserver.gerrit_change.patchset,
|
||||
), ),
|
||||
)
|
||||
for results, level in [
|
||||
(result_json.get('errors',
|
||||
[]), findings_pb.Finding.SEVERITY_LEVEL_ERROR),
|
||||
(result_json.get('warnings',
|
||||
[]), findings_pb.Finding.SEVERITY_LEVEL_WARNING),
|
||||
(result_json.get('notifications',
|
||||
[]), findings_pb.Finding.SEVERITY_LEVEL_INFO)
|
||||
]:
|
||||
for result in results:
|
||||
message = result.get('message', '')
|
||||
if result.get('long_text', None):
|
||||
message += '\n\n' + result['long_text']
|
||||
for loc in result.get('locations', []):
|
||||
f = findings_pb.Finding()
|
||||
f.CopyFrom(base_finding)
|
||||
f.message = message
|
||||
f.severity_level = level
|
||||
f.location.file_path = loc['file_path'].replace(self.m.path.sep, '/')
|
||||
if loc.get('start_line', None):
|
||||
f.location.range.start_line = loc['start_line']
|
||||
f.location.range.end_line = loc['end_line']
|
||||
f.location.range.start_column = loc.get('start_col', 0)
|
||||
f.location.range.end_column = loc.get('end_col', 0)
|
||||
findings.append(f)
|
||||
|
||||
if findings:
|
||||
self.m.findings.upload_findings(
|
||||
findings, step_name='upload presubmit results as findings')
|
||||
|
||||
def _limitSize(message_list, char_limit=450):
|
||||
"""Returns a list of strings within a certain character length.
|
||||
|
||||
@@ -4,21 +4,23 @@
|
||||
|
||||
import textwrap
|
||||
|
||||
from PB.go.chromium.org.luci.common.proto.findings import findings as findings_pb
|
||||
from recipe_engine import post_process
|
||||
from recipe_engine import recipe_api
|
||||
|
||||
|
||||
PYTHON_VERSION_COMPATIBILITY = 'PY3'
|
||||
|
||||
DEPS = [
|
||||
'gclient',
|
||||
'presubmit',
|
||||
'recipe_engine/buildbucket',
|
||||
'recipe_engine/context',
|
||||
'recipe_engine/cq',
|
||||
'recipe_engine/json',
|
||||
'recipe_engine/path',
|
||||
'recipe_engine/properties',
|
||||
'recipe_engine/runtime',
|
||||
'gclient',
|
||||
'presubmit',
|
||||
'recipe_engine/buildbucket',
|
||||
'recipe_engine/context',
|
||||
'recipe_engine/cq',
|
||||
'recipe_engine/json',
|
||||
'recipe_engine/path',
|
||||
'recipe_engine/properties',
|
||||
'recipe_engine/proto',
|
||||
'recipe_engine/runtime',
|
||||
]
|
||||
|
||||
|
||||
@@ -249,3 +251,118 @@ def GenTests(api):
|
||||
api.post_process(post_process.SummaryMarkdown, bug_msg),
|
||||
api.post_process(post_process.DropExpectation),
|
||||
status="INFRA_FAILURE")
|
||||
|
||||
def _has_uploaded_findings(check, steps, expected_findings):
|
||||
step_name = 'upload presubmit results as findings'
|
||||
check(step_name in steps)
|
||||
check('findings.json' in steps[step_name].logs)
|
||||
findings = api.proto.decode(steps[step_name].logs['findings.json'],
|
||||
findings_pb.Findings, 'JSONPB').findings
|
||||
check(len(findings) == len(expected_findings))
|
||||
for (actual, expected) in zip(findings, expected_findings):
|
||||
check(actual == expected)
|
||||
|
||||
gerrit_change_ref = findings_pb.Location.GerritChangeReference(
|
||||
host='chromium-review.googlesource.com',
|
||||
project='infra',
|
||||
change=123456,
|
||||
patchset=7)
|
||||
|
||||
yield api.test(
|
||||
'upload_findings',
|
||||
api.runtime(is_experimental=False),
|
||||
api.buildbucket.try_build(project='infra'),
|
||||
api.step_data(
|
||||
'presubmit',
|
||||
api.json.output(
|
||||
{
|
||||
'errors': [{
|
||||
'message':
|
||||
'bug bug bug',
|
||||
'long_text':
|
||||
'',
|
||||
'items': [],
|
||||
'locations': [{
|
||||
'file_path': 'path/to/file1',
|
||||
}, {
|
||||
'file_path': 'path/to/file2',
|
||||
}],
|
||||
'fatal':
|
||||
True
|
||||
}],
|
||||
'notifications':
|
||||
[{
|
||||
'message': 'cc abc@google.com',
|
||||
'long_text': '',
|
||||
'items': [],
|
||||
'locations': [{
|
||||
'file_path': '/COMMIT_MSG',
|
||||
}],
|
||||
'fatal': False
|
||||
}],
|
||||
'warnings': [{
|
||||
'message':
|
||||
'Change takes 20 min to take effect after landing',
|
||||
'long_text': '',
|
||||
'items': [],
|
||||
'locations': [],
|
||||
'fatal': False
|
||||
}, {
|
||||
'message':
|
||||
'typo!!',
|
||||
'long_text':
|
||||
'replace foo with bar',
|
||||
'items': [],
|
||||
'locations': [{
|
||||
'file_path': 'path/to/file',
|
||||
'start_line': 1,
|
||||
'start_col': 2,
|
||||
'end_line': 1,
|
||||
'end_col': 5,
|
||||
}],
|
||||
'fatal':
|
||||
False
|
||||
}]
|
||||
},
|
||||
retcode=1)),
|
||||
api.post_process(
|
||||
_has_uploaded_findings,
|
||||
[
|
||||
findings_pb.Finding(
|
||||
category='chromium_presubmit',
|
||||
location=findings_pb.Location(
|
||||
gerrit_change_ref=gerrit_change_ref,
|
||||
file_path='path/to/file1'),
|
||||
message='bug bug bug',
|
||||
severity_level=findings_pb.Finding.SEVERITY_LEVEL_ERROR),
|
||||
findings_pb.Finding(
|
||||
category='chromium_presubmit',
|
||||
location=findings_pb.Location(
|
||||
gerrit_change_ref=gerrit_change_ref,
|
||||
file_path='path/to/file2'),
|
||||
message='bug bug bug',
|
||||
severity_level=findings_pb.Finding.SEVERITY_LEVEL_ERROR),
|
||||
findings_pb.Finding(
|
||||
category='chromium_presubmit',
|
||||
location=findings_pb.Location(
|
||||
gerrit_change_ref=gerrit_change_ref,
|
||||
file_path='path/to/file',
|
||||
range=findings_pb.Location.Range(
|
||||
start_line=1,
|
||||
start_column=2,
|
||||
end_line=1,
|
||||
end_column=5,
|
||||
)),
|
||||
message='typo!!\n\nreplace foo with bar',
|
||||
severity_level=findings_pb.Finding.SEVERITY_LEVEL_WARNING),
|
||||
findings_pb.Finding(
|
||||
category='chromium_presubmit',
|
||||
location=findings_pb.Location(
|
||||
gerrit_change_ref=gerrit_change_ref,
|
||||
file_path='/COMMIT_MSG'),
|
||||
message='cc abc@google.com',
|
||||
severity_level=findings_pb.Finding.SEVERITY_LEVEL_INFO),
|
||||
],
|
||||
),
|
||||
api.post_process(post_process.DropExpectation),
|
||||
status="FAILURE")
|
||||
|
||||
Reference in New Issue
Block a user