import { BaseCommand } from "@yarnpkg/cli" ; import { Configuration , MessageName , Project , StreamReport , miscUtils , } from "@yarnpkg/core" ; import { PortablePath } from "@yarnpkg/fslib" ; import { Command , Option , Usage } from "clipanion" ; import path from "path" ; import { EventEmitter } from "events" ; import { GetPluginConfiguration , YarnBuildConfiguration , } from "@ojkelly/yarn-build-shared/src/config" ; import RunSupervisor , { RunSupervisorReporterEvents , } from "@ojkelly/yarn-build-shared/src/supervisor" ; import { addTargets } from "@ojkelly/yarn-build-shared/src/supervisor/workspace" ; import { terminateProcess } from "@ojkelly/yarn-build-shared/src/supervisor/terminate" ; export default class Test extends BaseCommand { static paths = [ [ `test` ] ] ; json = Option . Boolean ( `--json` , false , { description : `flag is set the output will follow a JSON-stream output
      also known as NDJSON (https://github.com/ndjson/ndjson-spec).` , } ) ; verbose = Option . Boolean ( `-v,--verbose` , false , { description : `more information will be logged to stdout than normal.` , } ) ; ignoreTestCache = Option . Boolean ( `--ignore-cache` , false , { description : `every package will be tested, regardless of whether is has changed or not.` , } ) ; maxConcurrency = Option . String ( `-m,--max-concurrency` , { description : `is the maximum number of tests that can run at a time, defaults to the number of logical CPUs on the current machine. Will override the global config option.` , } ) ; shouldBailInstantly = Option . Boolean ( "--bail" , false , { description : `exit immediately upon build failing` , } ) ; public runTarget : string [ ] = Option . Rest ( ) ; static usage : Usage = Command . Usage ( { category : `Test commands` , description : `test a package and all its dependencies` , details : `
    In a monorepo with internal packages that depend on others, this command
    will traverse the dependency graph and efficiently ensure, the packages
    are tested in the right order.
    ` , } ) ; forceQuit = false ; runLog : { [ key ] : { hash : string | undefined ; } ; } = { } ; async execute ( ) { const configuration = await Configuration . find ( this . context . cwd , this . context . plugins ) ; const pluginConfiguration = await GetPluginConfiguration ( configuration ) ; this . shouldBailInstantly = this . shouldBailInstantly ?? pluginConfiguration . bail ; const maxConcurrency = this . maxConcurrency === undefined ? pluginConfiguration . maxConcurrency : parseInt ( this . maxConcurrency ) ; const report = await StreamReport . start ( { configuration , json : this . json , stdout : this . context . stdout , includeLogs : true , } , async ( report ) => { let targetDirectory = this . context . cwd ; if ( typeof this . runTarget [ 0 ] === "string" ) { targetDirectory = `${ configuration . projectCwd }${ path . posix . sep }${ this . runTarget [ 0 ] }` as PortablePath ; } const { project , workspace : cwdWorkspace } = await Project . find ( configuration , targetDirectory ) ; const targetWorkspace = cwdWorkspace || project . topLevelWorkspace ; const runScript = async ( command , cwd , runReporter , prefix ) => { const stdout = new miscUtils . BufferStream ( ) ; stdout . on ( "data" , ( chunk ) => runReporter ?. emit ( RunSupervisorReporterEvents . info , prefix , chunk && chunk . toString ( ) ) ) ; const stderr = new miscUtils . BufferStream ( ) ; stderr . on ( "data" , ( chunk ) => runReporter ?. emit ( RunSupervisorReporterEvents . error , prefix , chunk && chunk . toString ( ) ) ) ; if ( this . forceQuit ) { stdout . destroy ( ) ; stderr . destroy ( ) ; stdout . end ( ) ; stderr . end ( ) ; return 2 ; } try { const exitCode = ( await this . cli . run ( [ "run" , command ] , { cwd , stdout , stderr , } ) ) || 0 ; stdout . end ( ) ; stderr . end ( ) ; return exitCode ; } catch ( err ) { stdout . end ( ) ; stderr . end ( ) ; } return 2 ; } ; const supervisor = new RunSupervisor ( { project , configuration , pluginConfiguration , report , runCommand : "test" , cli : runScript , dryRun : false , ignoreRunCache : this . ignoreTestCache , verbose : this . verbose , concurrency : maxConcurrency , shouldBailInstantly : this . shouldBailInstantly , } ) ; supervisor . runReporter . on ( RunSupervisorReporterEvents . forceQuit , ( ) => { this . forceQuit = true ; } ) ; await supervisor . setup ( ) ; await addTargets ( { targetWorkspace , project , supervisor } ) ; const ranWithoutErrors = await supervisor . run ( ) ; if ( ranWithoutErrors === false ) { report . reportError ( MessageName . BUILD_FAILED , "Test failed" ) ; } } ) ; terminateProcess . hasBeenTerminated = true ; return report . exitCode ( ) ; } }