Ignore the edits unrelated to Android dev in the edit monitor

1) Do not log edit events for files that does not belong to a git
project. 2) Do not log edit events for hidden files or files under a
hidden dir.

Test: atest edit_monitor_test
bug: 365617369
Change-Id: I73a79d9fb2ec3759ff58bded1666d68cff696353
diff --git a/tools/edit_monitor/edit_monitor.py b/tools/edit_monitor/edit_monitor.py
index 386daf7..defc841 100644
--- a/tools/edit_monitor/edit_monitor.py
+++ b/tools/edit_monitor/edit_monitor.py
@@ -17,6 +17,7 @@
 import logging
 import multiprocessing.connection
 import os
+import pathlib
 import platform
 import time
 
@@ -65,10 +66,22 @@
   def _log_edit_event(
       self, event: FileSystemEvent, edit_type: edit_event_pb2.EditEvent.EditType
   ):
-    event_time = time.time()
-
-    logging.info("%s: %s", event.event_type, event.src_path)
     try:
+      event_time = time.time()
+
+      if self._is_hidden_file(pathlib.Path(event.src_path)):
+        logging.debug("ignore hidden file: %s.", event.src_path)
+        return
+
+      if not self._is_under_git_project(pathlib.Path(event.src_path)):
+        logging.debug(
+            "ignore file %s which does not belong to a git project",
+            event.src_path,
+        )
+        return
+
+      logging.info("%s: %s", event.event_type, event.src_path)
+
       event_proto = edit_event_pb2.EditEvent(
           user_name=self.user_name,
           host_name=self.host_name,
@@ -88,6 +101,19 @@
     except Exception:
       logging.exception("Failed to log edit event.")
 
+  def _is_hidden_file(self, file_path: pathlib.Path) -> bool:
+    return any(
+        part.startswith(".")
+        for part in file_path.relative_to(self.root_monitoring_path).parts
+    )
+
+  def _is_under_git_project(self, file_path: pathlib.Path) -> bool:
+    root_path = pathlib.Path(self.root_monitoring_path).resolve()
+    return any(
+        root_path.joinpath(dir).joinpath('.git').exists()
+        for dir in file_path.relative_to(root_path).parents
+    )
+
 
 def start(
     path: str,
diff --git a/tools/edit_monitor/edit_monitor_test.py b/tools/edit_monitor/edit_monitor_test.py
index fdccd44..5bc1b13 100644
--- a/tools/edit_monitor/edit_monitor_test.py
+++ b/tools/edit_monitor/edit_monitor_test.py
@@ -54,6 +54,8 @@
     super().tearDown()
 
   def test_log_edit_event_success(self):
+    # Create the .git file under the monitoring dir.
+    self.root_monitoring_path.joinpath('.git').touch()
     fake_cclient = FakeClearcutClient(
         log_output_file=self.log_event_dir.joinpath('logs.output')
     )
@@ -125,7 +127,72 @@
         ).single_edit_event,
     )
 
+  def test_do_not_log_edit_event_for_directory_change(self):
+    # Create the .git file under the monitoring dir.
+    self.root_monitoring_path.joinpath('.git').touch()
+    fake_cclient = FakeClearcutClient(
+        log_output_file=self.log_event_dir.joinpath('logs.output')
+    )
+    p = self._start_test_edit_monitor_process(fake_cclient)
+
+    # Create a sub directory
+    self.root_monitoring_path.joinpath('test_dir').mkdir()
+    # Give some time for the edit monitor to receive the edit event.
+    time.sleep(1)
+    # Stop the edit monitor and flush all events.
+    os.kill(p.pid, signal.SIGINT)
+    p.join()
+
+    logged_events = self._get_logged_events()
+    self.assertEqual(len(logged_events), 0)
+
+  def test_do_not_log_edit_event_for_hidden_file(self):
+    # Create the .git file under the monitoring dir.
+    self.root_monitoring_path.joinpath('.git').touch()
+    fake_cclient = FakeClearcutClient(
+        log_output_file=self.log_event_dir.joinpath('logs.output')
+    )
+    p = self._start_test_edit_monitor_process(fake_cclient)
+
+    # Create a hidden file.
+    self.root_monitoring_path.joinpath('.test.txt').touch()
+    # Create a hidden dir.
+    hidden_dir = self.root_monitoring_path.joinpath('.test')
+    hidden_dir.mkdir()
+    hidden_dir.joinpath('test.txt').touch()
+    # Give some time for the edit monitor to receive the edit event.
+    time.sleep(1)
+    # Stop the edit monitor and flush all events.
+    os.kill(p.pid, signal.SIGINT)
+    p.join()
+
+    logged_events = self._get_logged_events()
+    self.assertEqual(len(logged_events), 0)
+
+  def test_do_not_log_edit_event_for_non_git_project_file(self):
+    fake_cclient = FakeClearcutClient(
+        log_output_file=self.log_event_dir.joinpath('logs.output')
+    )
+    p = self._start_test_edit_monitor_process(fake_cclient)
+
+    # Create a file.
+    self.root_monitoring_path.joinpath('test.txt').touch()
+    # Create a file under a sub dir.
+    sub_dir = self.root_monitoring_path.joinpath('.test')
+    sub_dir.mkdir()
+    sub_dir.joinpath('test.txt').touch()
+    # Give some time for the edit monitor to receive the edit event.
+    time.sleep(1)
+    # Stop the edit monitor and flush all events.
+    os.kill(p.pid, signal.SIGINT)
+    p.join()
+
+    logged_events = self._get_logged_events()
+    self.assertEqual(len(logged_events), 0)
+
   def test_log_edit_event_fail(self):
+    # Create the .git file under the monitoring dir.
+    self.root_monitoring_path.joinpath('.git').touch()
     fake_cclient = FakeClearcutClient(
         log_output_file=self.log_event_dir.joinpath('logs.output'),
         raise_log_exception=True,