// Copyright 2022, University of Colorado Boulder
const startTime = Date.now();

const execute = require( '../../../perennial-alias/js/common/execute' );
const fs = require( 'fs' );
const child_process = require( 'child_process' );

// constants
// Don't use getActiveRepos() since it cannot be run from the root
const contents = fs.readFileSync( 'perennial/data/active-repos', 'utf8' ).trim();
const repos = contents.split( '\n' ).map( sim => sim.trim() );

const args = process.argv.slice( 2 );
const all = args.includes( '--all' );

/**
 * Identify all repos with uncommitted changes, and run the precommit hooks on them.
 *
 * USAGE:
 * cd ${root containing all repos}
 * node chipper/js/scripts/precommit-hook-multi.js
 *
 * OPTIONS:
 *
 * --all
 * Runs the precommit hooks on all repos.  Default behavior is to only check the repos with uncommitted changes.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */
( async () => {

  let reposToTest = repos;

  const UPDATE_INDEX = true;

  if ( !all ) {

    const execOnRepo = repo => {
      return new Promise( resolve => {

        // Detect uncommitted changes in each repo:
        // https://stackoverflow.com/questions/3878624/how-do-i-programmatically-determine-if-there-are-uncommitted-changes
        // git diff-index --quiet HEAD --
        // This will error if the diff-index shows any changes in the repo, otherwise error is null.
        // If unexpected changes are showing for a repo, then the index may need to be updated with git update-index --refresh

        const cmd = UPDATE_INDEX ?
                    'git update-index --refresh && git diff-index --quiet HEAD --' :
                    'git diff-index --quiet HEAD --';
        child_process.exec( cmd, { cwd: repo },
          error => resolve( error ) );
      } );
    };

    const results = await Promise.all( repos.map( execOnRepo ) );

    // Find out which repos have uncommitted changes
    const changedRepos = [];
    for ( let i = 0; i < results.length; i++ ) {
      const repo = repos[ i ];
      const result = results[ i ];

      if ( result === null ) {

        // was up-to-date
      }
      else {

        // needs to push
        changedRepos.push( repo );
      }
    }
    console.log( 'detected changed repos: ' + changedRepos.join( ', ' ) );

    reposToTest = changedRepos;
  }

  // This is done sequentially so we don't spawn a bunch of uncached tsc at once, but in the future we may want to optimize
  // to run one sequentially then the rest in parallel
  for ( let i = 0; i < reposToTest.length; i++ ) {

    process.stdout.write( reposToTest[ i ] + ': ' );

    const result = await execute( 'node', [ '../chipper/js/scripts/hook-pre-commit.js' ], `${reposToTest[ i ]}`, {

      // resolve errors so Promise.all doesn't fail on first repo that cannot pull/rebase
      errors: 'resolve'
    } );
    if ( result.code === 0 ) {

      console.log( 'Success' );
    }
    else {
      console.log();
      result.stdout.trim().length > 0 && console.log( result.stdout.trim() );
      result.stderr.trim().length > 0 && console.log( result.stderr.trim() );
    }
  }

  console.log( 'Done in ' + ( Date.now() - startTime ) + 'ms' );
} )();
@@ -915,16 +915,17 @@
 ns)%0A */%0A
+%0A
 ( async 
@@ -965,38 +965,8 @@
 s;%0A%0A
-  const UPDATE_INDEX = true;%0A%0A
   if
@@ -1002,65 +1002,554 @@
 Repo
+s
  = 
-repo
+async ( repoSubset, command )
  =%3E %7B%0A
+%0A
       
-return new Promise( resolve =%3E %7B%0A%0A    
+const promises = repoSubset.map( repo =%3E %7B%0A        return new Promise( resolve =%3E child_process.exec( command, %7B cwd: repo %7D, error =%3E resolve( error ) ) );%0A      %7D );%0A      const results = await Promise.all( promises );%0A%0A      // Find out which repos have uncommitted changes%0A      const changedRepos = %5B%5D;%0A      for ( let i = 0; i %3C results.length; i++ ) %7B%0A        if ( results%5B i %5D !== null ) %7B%0A          changedRepos.push( repoSubset%5B i %5D );%0A        %7D%0A      %7D%0A%0A      return changedRepos;%0A    %7D;%0A%0A
     
@@ -1592,20 +1592,16 @@
 h repo:%0A
-    
     // h
@@ -1712,20 +1712,16 @@
 changes%0A
-    
     // g
@@ -1750,20 +1750,16 @@
 HEAD --%0A
-    
     // T
@@ -1847,20 +1847,16 @@
 s null.%0A
-    
     // I
@@ -1970,21 +1970,16 @@
 refresh%0A
-%0A    
     cons
@@ -1984,693 +1984,391 @@
 nst 
-cmd = UPDATE_INDEX ?%0A                    'git update-index --refresh && git diff-index --quiet HEAD --' :%0A                    'git diff-index --quiet HEAD --';%0A        child_process.exec( cmd, %7B cwd: repo %7D,%0A          error =%3E resolve( error ) );%0A      %7D );%0A    %7D;%0A%0A    const results = await Promise.all( repos.map( execOnRepo ) );%0A%0A    // Find out which
+reposThatindicateChanges = await execOnRepos( repos, 'git diff-index --quiet HEAD --' );%0A    const changedRepos = await execOnRepos(
  repos
- have uncommitted changes%0A    const changedRepos = %5B%5D;%0A    for ( let i = 0; i %3C results.length; i++ ) %7B%0A      const repo = repos%5B i %5D;%0A      const result = results%5B i %5D;%0A%0A      if ( result === null ) %7B%0A%0A        // was up-to-date%0A      %7D%0A      else %7B%0A%0A        // needs to push%0A        changedRepos.push( repo );%0A      %7D
+ThatindicateChanges, 'git update-index --refresh && git diff-index --quiet HEAD --' );%0A    console.log( 'detected changed repos: ' + reposThatindicateChanges.join( ', ' ) );%0A    if ( changedRepos.length !== reposThatindicateChanges.length ) %7B
 %0A  
-  %7D%0A
     
@@ -2381,38 +2381,38 @@
 e.log( '
-detected changed repos
+after refresh, testing
 : ' + ch
@@ -2437,16 +2437,22 @@
 , ' ) );
+%0A    %7D
 %0A%0A    re

Refresh changed repos to avoid false positives, see https://github.com/phetsims/chipper/issues/1301