phetsims/chipper

Precommit checks should run all checks even if some early ones fail

Closed this issue · 7 comments

Currently the precommit hook process short-circuits at the first type of failure. This may be confusing if a developer addresses the reported problems from the precommit hooks and believes all tests to be passing. Instead of short-circuiting and failing early, the precommit checks should run all checks each time.

Here is a patch that implements the proposal, it seems to be working properly in my tests. I'll reach out for a reviewer.

Subject: [PATCH] Precommit check runs all tests even if early ones fail, see https://github.com/phetsims/chipper/issues/1442
---
Index: js/scripts/hook-pre-commit.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/scripts/hook-pre-commit.js b/js/scripts/hook-pre-commit.js
--- a/js/scripts/hook-pre-commit.js	(revision 739e543ddef46bcda67e058ed0e0e2a422142fbd)
+++ b/js/scripts/hook-pre-commit.js	(date 1718115497617)
@@ -26,59 +26,72 @@
 const phetTimingLog = require( '../../../perennial-alias/js/common/phetTimingLog' );
 
 ( async () => {
-
   // Identify the current repo
   const repo = process.cwd().split( path.sep ).pop();
 
   const precommitSuccess = await phetTimingLog.startAsync( `hook-pre-commit repo="${repo}"`, async () => {
-
     // Console logging via --console
     const commandLineArguments = process.argv.slice( 2 );
     const outputToConsole = commandLineArguments.includes( '--console' );
     outputToConsole && console.log( 'repo:', repo );
 
-    const promises = [ 'lint', 'report-media', 'tsc', 'qunit', 'phet-io-api-compare' ].map( task => {
-      return phetTimingLog.startAsync( task, async () => {
-        const results = await execute( 'node', [
-          '../chipper/js/scripts/hook-pre-commit-task.js',
-          `--command=${task}`,
-          `--repo=${repo}`,
-          outputToConsole ? '--console' : '' ], '../chipper', {
-          errors: 'resolve'
-        } );
-        results.stdout && results.stdout.trim().length > 0 && console.log( results.stdout );
-        results.stderr && results.stderr.trim().length > 0 && console.log( results.stderr );
+    const taskResults = await Promise.allSettled(
+      [ 'lint', 'report-media', 'tsc', 'qunit', 'phet-io-api-compare' ].map( task => {
+        return phetTimingLog.startAsync(
+          task,
+          async () => {
+            const results = await execute(
+              'node',
+              [
+                '../chipper/js/scripts/hook-pre-commit-task.js',
+                `--command=${task}`,
+                `--repo=${repo}`,
+                outputToConsole ? '--console' : ''
+              ],
+              '../chipper',
+              {
+                errors: 'resolve'
+              }
+            );
+            results.stdout && results.stdout.trim().length > 0 && console.log( results.stdout );
+            results.stderr && results.stderr.trim().length > 0 && console.log( results.stderr );
 
-        if ( results.code === 0 ) {
-          return 0;
-        }
-        else {
-          let message = 'Task failed: ' + task;
-          if ( results.stdout && results.stdout.trim().length > 0 ) {
-            message = message + ', ' + results.stdout;
-          }
-          if ( results.stderr && results.stderr.trim().length > 0 ) {
-            message = message + ', ' + results.stderr;
-          }
-          throw new Error( message );
-        }
-      }, {
-        depth: 1
-      } );
-    } );
-
-    try {
-      await Promise.all( promises );
-      console.log( 'All tasks succeeded' );
-      return true;
-    }
-    catch( e ) {
+            if ( results.code === 0 ) {
+              return { task: task, success: true };
+            }
+            else {
+              let message = 'Task failed: ' + task;
+              if ( results.stdout && results.stdout.trim().length > 0 ) {
+                message = message + ': ' + results.stdout;
+              }
+              if ( results.stderr && results.stderr.trim().length > 0 ) {
+                message = message + ': ' + results.stderr;
+              }
+              return { task: task, success: false, message: message };
+            }
+          },
+          {
+            depth: 1
+          }
+        );
+      } )
+    );
 
-      // Exit as soon as any one promise fails
-      // Each task is responsible for outputting its error to the console, so the console should already
-      // be showing the error by now
-      return false;
-    }
+    taskResults.forEach( result => {
+      if ( result.status === 'fulfilled' ) {
+        if ( result.value.success ) {
+          console.log( `Task ${result.value.task} succeeded` );
+        }
+        else {
+          console.error( result.value.message );
+        }
+      }
+      else {
+        console.error( `Task ${result.reason.task} encountered an error: ${result.reason.message}` );
+      }
+    } );
+
+    return taskResults.every( result => result.status === 'fulfilled' && result.value.success );
   } );
 
   // generatePhetioMacroAPI is preventing exit for unknown reasons, so manually exit here

This change makes sense, thanks!

I tested by addint a tsc error, lint error, and qunit error to a single repo and expected to see them all print to the console.

I did see the lint and tsc errors. I did not see the qunit error - it reported a success for this task, even though it fails in the browser. I reverted back to main and saw this problem before your patch. EDIT: See #1443

The old code had

// Each task is responsible for outputting its error to the console, so the console should already
// be showing the error by now

Are we going to get duplicate mesages now that we always print task results?

Otherwise, the change looks good.

Regarding the unit tests, I missed this line in hook-pre-commit-task.js

// scenery unit tests take too long, so skip those

So no problem there.

Are we going to get duplicate messages now that we always print task results?

I wondered that too but only saw single messages from the reporting. Thanks for the review, let's close for now.

I don't think the patch was committed, I will apply it.

It has been pushed, closing.