Repository: oppia/oppia

Issue:
Add typescript checks to pre_push_hook
I've seen typescript_checks is the only way to ensure that correct types are added to the Angular stuff. This is filed to add the typescript checks to the pre_push_hook. 


Add typescript checks to pre_push_hook
I've seen typescript_checks is the only way to ensure that correct types are added to the Angular stuff. This is filed to add the typescript checks to the pre_push_hook. 




Discussion:
cc/ @vojtechjelinek (as primary mentor)
cc/ @vojtechjelinek (as primary mentor)

Resolving patch:
diff --git a/scripts/pre_push_hook.py b/scripts/pre_push_hook.py
--- a/scripts/pre_push_hook.py
+++ b/scripts/pre_push_hook.py
@@ -65,6 +65,7 @@
     PYTHON_CMD, '-m', 'scripts.run_frontend_tests', '--check_coverage']
 TRAVIS_CI_PROTRACTOR_CHECK_CMDS = [
     PYTHON_CMD, '-m', 'scripts.check_e2e_tests_are_captured_in_ci']
+TYPESCRIPT_CHECKS_CMDS = [PYTHON_CMD, '-m', 'scripts.typescript_checks']
 GIT_IS_DIRTY_CMD = 'git status --porcelain --untracked-files=no'
 
 
@@ -328,36 +329,52 @@ def install_hook():
         raise ValueError(err_chmod_cmd)
 
 
-def does_diff_include_js_or_ts_files(files_to_lint):
+def does_diff_include_js_or_ts_files(diff_files):
     """Returns true if diff includes JavaScript or TypeScript files.
 
     Args:
-        files_to_lint: list(str). List of files to be linted.
+        diff_files: list(str). List of files changed.
 
     Returns:
         bool. Whether the diff contains changes in any JavaScript or TypeScript
             files.
     """
 
-    for filename in files_to_lint:
-        if filename.endswith('.ts') or filename.endswith('.js'):
+    for file_path in diff_files:
+        if file_path.endswith('.ts') or file_path.endswith('.js'):
             return True
     return False
 
 
-def does_diff_include_travis_yml_or_js_files(files_to_lint):
+def does_diff_include_ts_files(diff_files):
+    """Returns true if diff includes TypeScript files.
+
+    Args:
+        diff_files: list(str). List of files changed.
+
+    Returns:
+        bool. Whether the diff contains changes in any TypeScript files.
+    """
+
+    for file_path in diff_files:
+        if file_path.endswith('.ts'):
+            return True
+    return False
+
+
+def does_diff_include_travis_yml_or_js_files(diff_files):
     """Returns true if diff includes .travis.yml or Javascript files.
 
     Args:
-        files_to_lint: list(str). List of files to be linted.
+        diff_files: list(str). List of files changed.
 
     Returns:
         bool. Whether the diff contains changes in travis.yml or
         Javascript files.
     """
 
-    for filename in files_to_lint:
-        if filename.endswith('.js') or filename.endswith('.travis.yml'):
+    for file_path in diff_files:
+        if file_path.endswith('.js') or file_path.endswith('.travis.yml'):
             return True
     return False
 
@@ -396,6 +413,16 @@ def main(args=None):
                     python_utils.PRINT(
                         'Push failed, please correct the linting issues above.')
                     sys.exit(1)
+
+            typescript_checks_status = 0
+            if does_diff_include_ts_files(files_to_lint):
+                typescript_checks_status = run_script_and_get_returncode(
+                    TYPESCRIPT_CHECKS_CMDS)
+            if typescript_checks_status != 0:
+                python_utils.PRINT(
+                    'Push aborted due to failing typescript checks.')
+                sys.exit(1)
+
             frontend_status = 0
             travis_ci_check_status = 0
             if does_diff_include_js_or_ts_files(files_to_lint):


Test patch:
diff --git a/scripts/pre_push_hook_test.py b/scripts/pre_push_hook_test.py
--- a/scripts/pre_push_hook_test.py
+++ b/scripts/pre_push_hook_test.py
@@ -64,12 +64,15 @@ def mock_check_output(unused_cmd_tokens):
         def mock_start_linter(unused_files_to_lint):
             return self.linter_code
         self.does_diff_include_js_or_ts_files = False
-        def mock_does_diff_include_js_or_ts_files(unused_files_to_lint):
+        def mock_does_diff_include_js_or_ts_files(unused_diff_files):
             return self.does_diff_include_js_or_ts_files
+        self.does_diff_include_ts_files = False
+        def mock_does_diff_include_ts_files(unused_diff_files):
+            return self.does_diff_include_ts_files
 
         self.does_diff_include_travis_yml_or_js_files = False
         def mock_does_diff_include_travis_yml_or_js_files(
-                unused_files_to_lint):
+                unused_diff_files):
             return self.does_diff_include_travis_yml_or_js_files
 
         self.popen_swap = self.swap(subprocess, 'Popen', mock_popen)
@@ -89,6 +92,9 @@ def mock_does_diff_include_travis_yml_or_js_files(
         self.js_or_ts_swap = self.swap(
             pre_push_hook, 'does_diff_include_js_or_ts_files',
             mock_does_diff_include_js_or_ts_files)
+        self.ts_swap = self.swap(
+            pre_push_hook, 'does_diff_include_ts_files',
+            mock_does_diff_include_ts_files)
         self.travis_yml_or_js_files_swap = self.swap(
             pre_push_hook,
             'does_diff_include_travis_yml_or_js_files',
@@ -446,6 +452,16 @@ def test_does_diff_include_js_or_ts_files_with_no_file(self):
             pre_push_hook.does_diff_include_js_or_ts_files(
                 ['file1.html', 'file2.py']))
 
+    def test_does_diff_include_ts_files(self):
+        self.assertTrue(
+            pre_push_hook.does_diff_include_ts_files(
+                ['file1.ts', 'file2.ts', 'file3.js']))
+
+    def test_does_diff_include_ts_files_fail(self):
+        self.assertFalse(
+            pre_push_hook.does_diff_include_ts_files(
+                ['file1.html', 'file2.yml', 'file3.js']))
+
     def test_does_diff_include_travis_yml_or_js_files(self):
         self.assertTrue(
             pre_push_hook.does_diff_include_travis_yml_or_js_files(
@@ -498,6 +514,22 @@ def test_lint_failure(self):
             'Push failed, please correct the linting issues above.'
             in self.print_arr)
 
+    def test_typescript_check_failiure(self):
+        self.does_diff_include_ts_files = True
+        def mock_run_script_and_get_returncode(unused_script):
+            return 1
+        run_script_and_get_returncode_swap = self.swap(
+            pre_push_hook, 'run_script_and_get_returncode',
+            mock_run_script_and_get_returncode)
+        with self.get_remote_name_swap, self.get_refs_swap, self.print_swap:
+            with self.collect_files_swap, self.uncommitted_files_swap:
+                with self.check_output_swap, self.start_linter_swap:
+                    with self.ts_swap, run_script_and_get_returncode_swap:
+                        with self.assertRaises(SystemExit):
+                            pre_push_hook.main(args=[])
+        self.assertTrue(
+            'Push aborted due to failing typescript checks.' in self.print_arr)
+
     def test_frontend_test_failure(self):
         self.does_diff_include_js_or_ts_files = True
         def mock_run_script_and_get_returncode(unused_script):