This is an automated email from the ASF dual-hosted git repository. martinkanters pushed a commit to branch feature/MNG-7338-automatic-non-interactive-mode-in-ci in repository https://gitbox.apache.org/repos/asf/maven.git
commit 2a87384e92aed08178aeda45796c72c1ce1d42d6 Author: Martin Kanters <[email protected]> AuthorDate: Thu Nov 10 16:47:16 2022 +0100 [MNG-7338] Automatically activate batch-mode and make output quiet when running in CI. --- maven-embedder/pom.xml | 5 ++ .../main/java/org/apache/maven/cli/CLIManager.java | 8 ++- .../main/java/org/apache/maven/cli/MavenCli.java | 62 +++++++++++++---- .../java/org/apache/maven/cli/MavenCliTest.java | 81 ++++++++++++++++++++++ 4 files changed, 140 insertions(+), 16 deletions(-) diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml index 1e6c98968..892adb1b7 100644 --- a/maven-embedder/pom.xml +++ b/maven-embedder/pom.xml @@ -156,6 +156,11 @@ under the License. <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java index b6005fddf..eaebd5a37 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java @@ -40,6 +40,10 @@ public class CLIManager public static final char BATCH_MODE = 'B'; + public static final String NON_INTERACTIVE = "ni"; + + public static final String FORCE_INTERACTIVE = "fi"; + public static final char SET_USER_PROPERTY = 'D'; /** @@ -138,7 +142,9 @@ public class CLIManager options.addOption( Option.builder( Character.toString( NON_RECURSIVE ) ).longOpt( "non-recursive" ).desc( "Do not recurse into sub-projects. When used together with -pl, do not recurse into sub-projects of selected aggregators" ).build() ); options.addOption( Option.builder( Character.toString( UPDATE_SNAPSHOTS ) ).longOpt( "update-snapshots" ).desc( "Forces a check for missing releases and updated snapshots on remote repositories" ).build() ); options.addOption( Option.builder( Character.toString( ACTIVATE_PROFILES ) ).longOpt( "activate-profiles" ).desc( "Comma-delimited list of profiles to activate. Prefixing a profile with ! excludes it, and ? marks it as optional" ).hasArg().build() ); - options.addOption( Option.builder( Character.toString( BATCH_MODE ) ).longOpt( "batch-mode" ).desc( "Run in non-interactive (batch) mode (disables output color)" ).build() ); + options.addOption( Option.builder( Character.toString( BATCH_MODE ) ).longOpt( "batch-mode" ).desc( "Run in non-interactive (batch) mode (disables output color) - alias for --non-interactive (kept for backwards compatability)" ).build() ); + options.addOption( Option.builder( NON_INTERACTIVE ).longOpt( "non-interactive" ).desc( "Run in non-interactive (batch) mode (disables output color) - alias for --batch-mode" ).build() ); + options.addOption( Option.builder( FORCE_INTERACTIVE ).longOpt( "force-interactive" ).desc( "Run in interactive mode - even when the environment variable CI is set to true and --non-interactive or --batch-mode are set" ).build() ); options.addOption( Option.builder( SUPPRESS_SNAPSHOT_UPDATES ).longOpt( "no-snapshot-updates" ).desc( "Suppress SNAPSHOT updates" ).build() ); options.addOption( Option.builder( Character.toString( CHECKSUM_FAILURE_POLICY ) ).longOpt( "strict-checksums" ).desc( "Fail the build if checksums don't match" ).build() ); options.addOption( Option.builder( Character.toString( CHECKSUM_WARNING_POLICY ) ).longOpt( "lax-checksums" ).desc( "Warn if checksums don't match" ).build() ); diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java index ebfb0830b..2c9ae0ce3 100644 --- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java +++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java @@ -121,7 +121,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import static java.util.Comparator.comparing; +import static org.apache.maven.cli.CLIManager.BATCH_MODE; import static org.apache.maven.cli.CLIManager.COLOR; +import static org.apache.maven.cli.CLIManager.FORCE_INTERACTIVE; +import static org.apache.maven.cli.CLIManager.NON_INTERACTIVE; import static org.apache.maven.cli.ResolveFile.resolveFile; import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; @@ -504,10 +507,11 @@ public class MavenCli void logging( CliRequest cliRequest ) { // LOG LEVEL - cliRequest.verbose = cliRequest.commandLine.hasOption( CLIManager.VERBOSE ) - || cliRequest.commandLine.hasOption( CLIManager.DEBUG ); - cliRequest.quiet = !cliRequest.verbose && cliRequest.commandLine.hasOption( CLIManager.QUIET ); - cliRequest.showErrors = cliRequest.verbose || cliRequest.commandLine.hasOption( CLIManager.ERRORS ); + CommandLine commandLine = cliRequest.commandLine; + cliRequest.verbose = commandLine.hasOption( CLIManager.VERBOSE ) + || commandLine.hasOption( CLIManager.DEBUG ); + cliRequest.quiet = !cliRequest.verbose && commandLine.hasOption( CLIManager.QUIET ); + cliRequest.showErrors = cliRequest.verbose || commandLine.hasOption( CLIManager.ERRORS ); slf4jLoggerFactory = LoggerFactory.getILoggerFactory(); Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory ); @@ -527,7 +531,7 @@ public class MavenCli // LOG COLOR String styleColor = cliRequest.getUserProperties().getProperty( STYLE_COLOR_PROPERTY, "auto" ); - styleColor = cliRequest.commandLine.getOptionValue( COLOR, styleColor ); + styleColor = commandLine.getOptionValue( COLOR, styleColor ); if ( "always".equals( styleColor ) || "yes".equals( styleColor ) || "force".equals( styleColor ) ) { MessageUtils.setColorEnabled( true ); @@ -541,16 +545,20 @@ public class MavenCli throw new IllegalArgumentException( "Invalid color configuration value '" + styleColor + "'. Supported are 'auto', 'always', 'never'." ); } - else if ( cliRequest.commandLine.hasOption( CLIManager.BATCH_MODE ) - || cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) ) + else { - MessageUtils.setColorEnabled( false ); + boolean isBatchMode = !commandLine.hasOption( FORCE_INTERACTIVE ) + && ( commandLine.hasOption( BATCH_MODE ) || commandLine.hasOption( NON_INTERACTIVE ) ); + if ( isBatchMode || commandLine.hasOption( CLIManager.LOG_FILE ) ) + { + MessageUtils.setColorEnabled( false ); + } } // LOG STREAMS - if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) ) + if ( commandLine.hasOption( CLIManager.LOG_FILE ) ) { - File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) ); + File logFile = new File( commandLine.getOptionValue( CLIManager.LOG_FILE ) ); logFile = resolveFile( logFile, cliRequest.workingDirectory ); // redirect stdout and stderr to file @@ -573,9 +581,9 @@ public class MavenCli plexusLoggerManager = new Slf4jLoggerManager(); slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() ); - if ( cliRequest.commandLine.hasOption( CLIManager.FAIL_ON_SEVERITY ) ) + if ( commandLine.hasOption( CLIManager.FAIL_ON_SEVERITY ) ) { - String logLevelThreshold = cliRequest.commandLine.getOptionValue( CLIManager.FAIL_ON_SEVERITY ); + String logLevelThreshold = commandLine.getOptionValue( CLIManager.FAIL_ON_SEVERITY ); if ( slf4jLoggerFactory instanceof MavenSlf4jWrapperFactory ) { @@ -591,7 +599,7 @@ public class MavenCli } } - if ( cliRequest.commandLine.hasOption( CLIManager.DEBUG ) ) + if ( commandLine.hasOption( CLIManager.DEBUG ) ) { slf4jLogger.warn( "The option '--debug' is deprecated and may be repurposed as Java debug" + " in a future version. Use -X/--verbose instead." ); @@ -1374,7 +1382,7 @@ public class MavenCli request.setShowErrors( cliRequest.showErrors ); // default: false File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile(); - disableOnPresentOption( commandLine, CLIManager.BATCH_MODE, request::setInteractiveMode ); + disableInteractiveModeIfNeeded( cliRequest, request ); enableOnPresentOption( commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates ); request.setGoals( commandLine.getArgList() ); request.setReactorFailureBehavior( determineReactorFailureBehaviour ( commandLine ) ); @@ -1438,6 +1446,27 @@ public class MavenCli return request; } + private void disableInteractiveModeIfNeeded( final CliRequest cliRequest, final MavenExecutionRequest request ) + { + CommandLine commandLine = cliRequest.getCommandLine(); + if ( commandLine.hasOption( FORCE_INTERACTIVE ) ) + { + return; + } + + String ciEnv = cliRequest.getSystemProperties().getProperty( "env.CI" ); + if ( "true".equals( ciEnv ) ) + { + slf4jLogger.info( "Detected a CI build, because the environment variable CI equals \"true\". " + + "Disable this detection by removing that variable or adding --force-interactive." ); + request.setInteractiveMode( false ); + } + else if ( commandLine.hasOption( BATCH_MODE ) || commandLine.hasOption( NON_INTERACTIVE ) ) + { + request.setInteractiveMode( false ); + } + } + private String determineLocalRepositoryPath( final MavenExecutionRequest request ) { String userDefinedLocalRepo = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY ); @@ -1593,7 +1622,10 @@ public class MavenCli final CommandLine commandLine, final MavenExecutionRequest request ) { - if ( quiet || commandLine.hasOption( CLIManager.NO_TRANSFER_PROGRESS ) ) + String ciEnv = request.getSystemProperties().getProperty( "env.CI" ); + boolean quietCI = "true".equals( ciEnv ) && !commandLine.hasOption( FORCE_INTERACTIVE ); + + if ( quiet || commandLine.hasOption( CLIManager.NO_TRANSFER_PROGRESS ) || quietCI ) { return new QuietMavenTransferListener(); } diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java index c4fb01a91..54637c3fa 100644 --- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java +++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java @@ -43,6 +43,7 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; @@ -51,6 +52,9 @@ import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.maven.Maven; +import org.apache.maven.cli.transfer.ConsoleMavenTransferListener; +import org.apache.maven.cli.transfer.QuietMavenTransferListener; +import org.apache.maven.cli.transfer.Slf4jMavenTransferListener; import org.apache.maven.eventspy.internal.EventSpyDispatcher; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.ProfileActivation; @@ -61,9 +65,13 @@ import org.apache.maven.toolchain.building.ToolchainsBuildingRequest; import org.apache.maven.toolchain.building.ToolchainsBuildingResult; import org.codehaus.plexus.DefaultPlexusContainer; import org.codehaus.plexus.PlexusContainer; +import org.eclipse.aether.transfer.TransferListener; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.InOrder; public class MavenCliTest @@ -359,6 +367,20 @@ public class MavenCliTest cli.logging( request ); assertFalse( MessageUtils.isColorEnabled() ); + MessageUtils.setColorEnabled( true ); + request = new CliRequest( new String[] { "--non-interactive" }, null ); + cli.cli( request ); + cli.properties( request ); + cli.logging( request ); + assertFalse( MessageUtils.isColorEnabled() ); + + MessageUtils.setColorEnabled( true ); + request = new CliRequest( new String[] { "--force-interactive", "--non-interactive" }, null ); + cli.cli( request ); + cli.properties( request ); + cli.logging( request ); + assertTrue( MessageUtils.isColorEnabled() ); + MessageUtils.setColorEnabled( true ); request = new CliRequest( new String[] { "-l", "target/temp/mvn.log" }, null ); request.workingDirectory = "target/temp"; @@ -588,6 +610,65 @@ public class MavenCliTest assertThat( request.getUserProperties().getProperty( "x" ), is( "false" ) ); } + @ParameterizedTest + @MethodSource("activateBatchModeArguments") + public void activateBatchMode(boolean ciEnv, String[] cliArgs, boolean isBatchMode ) + throws Exception + { + CliRequest request = new CliRequest( cliArgs, null ); + if (ciEnv) request.getSystemProperties().put( "env.CI", "true" ); + cli.cli( request ); + + boolean batchMode = !cli.populateRequest(request).isInteractiveMode(); + + assertThat( batchMode, is( isBatchMode ) ); + } + + public static Stream<Arguments> activateBatchModeArguments() { + return Stream.of( + Arguments.of(false, new String[]{ }, false), + Arguments.of(true, new String[]{ }, true), + Arguments.of(true, new String[]{ "--force-interactive" }, false), + Arguments.of(true, new String[]{ "--force-interactive", "--non-interactive" }, false), + Arguments.of(true, new String[]{ "--force-interactive", "--batch-mode" }, false), + Arguments.of(true, new String[]{ "--force-interactive", "--non-interactive", "--batch-mode" }, false), + Arguments.of(false, new String[]{ "--non-interactive" }, true), + Arguments.of(false, new String[]{ "--batch-mode" }, true), + Arguments.of(false, new String[]{ "--non-interactive", "--batch-mode" }, true) + ); + } + + @ParameterizedTest + @MethodSource("calculateTransferListenerArguments") + public void calculateTransferListener( boolean ciEnv, String[] cliArgs, Class<TransferListener> expectedSubClass) + throws Exception + { + CliRequest request = new CliRequest( cliArgs, null ); + if (ciEnv) request.getSystemProperties().put( "env.CI", "true" ); + cli.cli( request ); + cli.logging( request ); + + TransferListener transferListener = cli.populateRequest(request).getTransferListener(); + + assertThat( transferListener.getClass(), is( expectedSubClass ) ); + } + + public static Stream<Arguments> calculateTransferListenerArguments() { + return Stream.of( + Arguments.of(false, new String[]{ }, ConsoleMavenTransferListener.class), + Arguments.of(true, new String[]{ }, QuietMavenTransferListener.class), + Arguments.of(false, new String[]{ "-ntp" }, QuietMavenTransferListener.class), + Arguments.of(false, new String[]{ "--quiet" }, QuietMavenTransferListener.class), + Arguments.of(true, new String[]{ "--force-interactive" }, ConsoleMavenTransferListener.class), + Arguments.of(true, new String[]{ "--force-interactive", "--non-interactive" }, ConsoleMavenTransferListener.class), + Arguments.of(true, new String[]{ "--force-interactive", "--batch-mode" }, ConsoleMavenTransferListener.class), + Arguments.of(true, new String[]{ "--force-interactive", "--non-interactive", "--batch-mode" }, ConsoleMavenTransferListener.class), + Arguments.of(false, new String[]{ "--non-interactive" }, Slf4jMavenTransferListener.class ), + Arguments.of(false, new String[]{ "--batch-mode" }, Slf4jMavenTransferListener.class ), + Arguments.of(false, new String[]{ "--non-interactive", "--batch-mode" }, Slf4jMavenTransferListener.class ) + ); + } + private MavenProject createMavenProject( String groupId, String artifactId ) { MavenProject project = new MavenProject();
