pre-upload: check rust formatting with rustfmt
Check all changed files with rustfmt, and block upload if any
errors are found.
BUG=None
TEST=check that hook catches bad commit on 'repo upload'
TEST=check that hook doesn't catch innocuous rust commits
Change-Id: I656e8ea2f8af39d31537aadc510a000bff925ca7
Reviewed-on: https://chromium-review.googlesource.com/1759129
Tested-by: Fletcher Woodruff <fletcherw@chromium.org>
Commit-Ready: Fletcher Woodruff <fletcherw@chromium.org>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/pre-upload.py b/pre-upload.py
index c609530..bb73ee0 100755
--- a/pre-upload.py
+++ b/pre-upload.py
@@ -567,6 +567,23 @@
return HookFailure('Files not formatted with gofmt:', errors)
+def _check_rustfmt(_project, commit):
+ """Checks that Rust files are formatted with rustfmt."""
+ errors = []
+ files = _filter_files(_get_affected_files(commit, relative=True),
+ [r'\.rs$'])
+
+ for rustfile in files:
+ contents = _get_file_content(rustfile, commit)
+ output = _run_command(cmd=['rustfmt'], input=contents,
+ combine_stdout_stderr=True)
+ if output != contents:
+ errors.append(rustfile)
+ if errors:
+ return HookFailure('Files not formatted with rustfmt: '
+ "(run 'cargo fmt' to fix)", errors)
+
+
def _check_change_has_test_field(_project, commit):
"""Check for a non-empty 'TEST=' field in the commit message."""
TEST_RE = r'\nTEST=\S+'
@@ -1714,6 +1731,7 @@
_check_no_stray_whitespace,
_check_no_tabs,
_check_portage_make_use_var,
+ _check_rustfmt,
_check_tabbed_indents,
]
diff --git a/pre-upload_unittest.py b/pre-upload_unittest.py
index 179617d..640aef8 100755
--- a/pre-upload_unittest.py
+++ b/pre-upload_unittest.py
@@ -1623,5 +1623,36 @@
mock.ANY, proj_dir=mock.ANY, commit_list=commits, presubmit=mock.ANY)
+class CheckRustfmtTest(cros_test_lib.MockTestCase):
+ """Tests for _check_rustfmt."""
+
+ def setUp(self):
+ self.content_mock = self.PatchObject(pre_upload, '_get_file_content')
+
+ def testBadRustFile(self):
+ self.PatchObject(pre_upload, '_get_affected_files', return_value=['a.rs'])
+ # Bad because it's missing trailing newline.
+ self.content_mock.return_value = 'fn main() {}'
+ failure = pre_upload._check_rustfmt(ProjectNamed('PROJECT'), 'COMMIT')
+ self.assertIsNotNone(failure)
+ self.assertEquals('Files not formatted with rustfmt: '
+ "(run 'cargo fmt' to fix)",
+ failure.msg)
+ self.assertEquals(['a.rs'], failure.items)
+
+ def testGoodRustFile(self):
+ self.PatchObject(pre_upload, '_get_affected_files', return_value=['a.rs'])
+ self.content_mock.return_value = 'fn main() {}\n'
+ failure = pre_upload._check_rustfmt(ProjectNamed('PROJECT'), 'COMMIT')
+ self.assertIsNone(failure)
+
+ def testFilterNonRustFiles(self):
+ self.PatchObject(pre_upload, '_get_affected_files',
+ return_value=['a.cc', 'a.rsa', 'a.irs', 'rs.cc'])
+ self.content_mock.return_value = 'fn main() {\n}'
+ failure = pre_upload._check_rustfmt(ProjectNamed('PROJECT'), 'COMMIT')
+ self.assertIsNone(failure)
+
+
if __name__ == '__main__':
cros_test_lib.main(module=__name__)