[MNG-7338] Automatically activate batch-mode and make output quiet when running in CI. (#869)

This commit is contained in:
Martin Kanters 2023-06-08 15:44:17 +02:00 committed by GitHub
parent 8b652a8b3e
commit ac0bc5541e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 148 additions and 16 deletions

View File

@ -146,6 +146,11 @@ under the License.
<groupId>commons-cli</groupId> <groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId> <artifactId>commons-cli</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>

View File

@ -38,6 +38,10 @@ public class CLIManager {
public static final char BATCH_MODE = 'B'; public static final char BATCH_MODE = 'B';
public static final String NON_INTERACTIVE = "non-interactive";
public static final String FORCE_INTERACTIVE = "force-interactive";
public static final char SET_USER_PROPERTY = 'D'; public static final char SET_USER_PROPERTY = 'D';
/** /**
@ -173,7 +177,16 @@ public class CLIManager {
.build()); .build());
options.addOption(Option.builder(Character.toString(BATCH_MODE)) options.addOption(Option.builder(Character.toString(BATCH_MODE))
.longOpt("batch-mode") .longOpt("batch-mode")
.desc("Run in non-interactive (batch) mode (disables output color)") .desc("Run in non-interactive mode. Alias for --non-interactive (kept for backwards compatability)")
.build());
options.addOption(Option.builder()
.longOpt(NON_INTERACTIVE)
.desc("Run in non-interactive mode. Alias for --batch-mode")
.build());
options.addOption(Option.builder()
.longOpt(FORCE_INTERACTIVE)
.desc(
"Run in interactive mode. Overrides, if applicable, the CI environment variable and --non-interactive/--batch-mode options")
.build()); .build());
options.addOption(Option.builder(SUPPRESS_SNAPSHOT_UPDATES) options.addOption(Option.builder(SUPPRESS_SNAPSHOT_UPDATES)
.longOpt("no-snapshot-updates") .longOpt("no-snapshot-updates")

View File

@ -119,7 +119,10 @@ import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity; import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
import static java.util.Comparator.comparing; 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.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.cli.ResolveFile.resolveFile;
import static org.apache.maven.shared.utils.logging.MessageUtils.buffer; import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
@ -486,10 +489,10 @@ public class MavenCli {
*/ */
void logging(CliRequest cliRequest) { void logging(CliRequest cliRequest) {
// LOG LEVEL // LOG LEVEL
cliRequest.verbose = cliRequest.commandLine.hasOption(CLIManager.VERBOSE) CommandLine commandLine = cliRequest.commandLine;
|| cliRequest.commandLine.hasOption(CLIManager.DEBUG); cliRequest.verbose = commandLine.hasOption(CLIManager.VERBOSE) || commandLine.hasOption(CLIManager.DEBUG);
cliRequest.quiet = !cliRequest.verbose && cliRequest.commandLine.hasOption(CLIManager.QUIET); cliRequest.quiet = !cliRequest.verbose && commandLine.hasOption(CLIManager.QUIET);
cliRequest.showErrors = cliRequest.verbose || cliRequest.commandLine.hasOption(CLIManager.ERRORS); cliRequest.showErrors = cliRequest.verbose || commandLine.hasOption(CLIManager.ERRORS);
slf4jLoggerFactory = LoggerFactory.getILoggerFactory(); slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory); Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory);
@ -506,7 +509,7 @@ public class MavenCli {
// LOG COLOR // LOG COLOR
String styleColor = cliRequest.getUserProperties().getProperty(STYLE_COLOR_PROPERTY, "auto"); 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)) { if ("always".equals(styleColor) || "yes".equals(styleColor) || "force".equals(styleColor)) {
MessageUtils.setColorEnabled(true); MessageUtils.setColorEnabled(true);
} else if ("never".equals(styleColor) || "no".equals(styleColor) || "none".equals(styleColor)) { } else if ("never".equals(styleColor) || "no".equals(styleColor) || "none".equals(styleColor)) {
@ -514,14 +517,17 @@ public class MavenCli {
} else if (!"auto".equals(styleColor) && !"tty".equals(styleColor) && !"if-tty".equals(styleColor)) { } else if (!"auto".equals(styleColor) && !"tty".equals(styleColor) && !"if-tty".equals(styleColor)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Invalid color configuration value '" + styleColor + "'. Supported are 'auto', 'always', 'never'."); "Invalid color configuration value '" + styleColor + "'. Supported are 'auto', 'always', 'never'.");
} else if (cliRequest.commandLine.hasOption(CLIManager.BATCH_MODE) } else {
|| cliRequest.commandLine.hasOption(CLIManager.LOG_FILE)) { boolean isBatchMode = !commandLine.hasOption(FORCE_INTERACTIVE)
MessageUtils.setColorEnabled(false); && (commandLine.hasOption(BATCH_MODE) || commandLine.hasOption(NON_INTERACTIVE));
if (isBatchMode || commandLine.hasOption(CLIManager.LOG_FILE)) {
MessageUtils.setColorEnabled(false);
}
} }
// LOG STREAMS // 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); logFile = resolveFile(logFile, cliRequest.workingDirectory);
// redirect stdout and stderr to file // redirect stdout and stderr to file
@ -541,8 +547,8 @@ public class MavenCli {
plexusLoggerManager = new Slf4jLoggerManager(); plexusLoggerManager = new Slf4jLoggerManager();
slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName()); 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) { if (slf4jLoggerFactory instanceof MavenSlf4jWrapperFactory) {
LogLevelRecorder logLevelRecorder = new LogLevelRecorder(logLevelThreshold); LogLevelRecorder logLevelRecorder = new LogLevelRecorder(logLevelThreshold);
@ -557,7 +563,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" slf4jLogger.warn("The option '--debug' is deprecated and may be repurposed as Java debug"
+ " in a future version. Use -X/--verbose instead."); + " in a future version. Use -X/--verbose instead.");
} }
@ -1242,7 +1248,7 @@ public class MavenCli {
request.setShowErrors(cliRequest.showErrors); // default: false request.setShowErrors(cliRequest.showErrors); // default: false
File baseDirectory = new File(workingDirectory, "").getAbsoluteFile(); File baseDirectory = new File(workingDirectory, "").getAbsoluteFile();
disableOnPresentOption(commandLine, CLIManager.BATCH_MODE, request::setInteractiveMode); disableInteractiveModeIfNeeded(cliRequest, request);
enableOnPresentOption(commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates); enableOnPresentOption(commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates);
request.setGoals(commandLine.getArgList()); request.setGoals(commandLine.getArgList());
request.setReactorFailureBehavior(determineReactorFailureBehaviour(commandLine)); request.setReactorFailureBehavior(determineReactorFailureBehaviour(commandLine));
@ -1304,6 +1310,27 @@ public class MavenCli {
return request; return request;
} }
private void disableInteractiveModeIfNeeded(final CliRequest cliRequest, final MavenExecutionRequest request) {
CommandLine commandLine = cliRequest.getCommandLine();
if (commandLine.hasOption(FORCE_INTERACTIVE)) {
return;
}
boolean runningOnCI = isRunningOnCI(cliRequest.getSystemProperties());
if (runningOnCI) {
slf4jLogger.info("Making this build non-interactive, 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 static boolean isRunningOnCI(Properties systemProperties) {
String ciEnv = systemProperties.getProperty("env.CI");
return ciEnv != null && !"false".equals(ciEnv);
}
private String determineLocalRepositoryPath(final MavenExecutionRequest request) { private String determineLocalRepositoryPath(final MavenExecutionRequest request) {
String userDefinedLocalRepo = request.getUserProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY); String userDefinedLocalRepo = request.getUserProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY);
if (userDefinedLocalRepo != null) { if (userDefinedLocalRepo != null) {
@ -1424,7 +1451,10 @@ public class MavenCli {
final boolean verbose, final boolean verbose,
final CommandLine commandLine, final CommandLine commandLine,
final MavenExecutionRequest request) { final MavenExecutionRequest request) {
if (quiet || commandLine.hasOption(CLIManager.NO_TRANSFER_PROGRESS)) { boolean runningOnCI = isRunningOnCI(request.getSystemProperties());
boolean quietCI = runningOnCI && !commandLine.hasOption(FORCE_INTERACTIVE);
if (quiet || commandLine.hasOption(CLIManager.NO_TRANSFER_PROGRESS) || quietCI) {
return new QuietMavenTransferListener(); return new QuietMavenTransferListener();
} else if (request.isInteractiveMode() && !commandLine.hasOption(CLIManager.LOG_FILE)) { } else if (request.isInteractiveMode() && !commandLine.hasOption(CLIManager.LOG_FILE)) {
// //

View File

@ -26,6 +26,7 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
@ -34,6 +35,9 @@ import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.maven.Maven; 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.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.ProfileActivation; import org.apache.maven.execution.ProfileActivation;
@ -45,9 +49,13 @@ import org.apache.maven.toolchain.building.ToolchainsBuildingRequest;
import org.apache.maven.toolchain.building.ToolchainsBuildingResult; import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
import org.codehaus.plexus.DefaultPlexusContainer; import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainer;
import org.eclipse.aether.transfer.TransferListener;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; 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; import org.mockito.InOrder;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@ -333,6 +341,20 @@ class MavenCliTest {
cli.logging(request); cli.logging(request);
assertFalse(MessageUtils.isColorEnabled()); 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); MessageUtils.setColorEnabled(true);
request = new CliRequest(new String[] {"-l", "target/temp/mvn.log"}, null); request = new CliRequest(new String[] {"-l", "target/temp/mvn.log"}, null);
request.workingDirectory = "target/temp"; request.workingDirectory = "target/temp";
@ -585,6 +607,68 @@ class MavenCliTest {
assertThat(request.getCommandLine().getArgs(), equalTo(new String[] {"prefix:3.0.0:bar", "validate"})); assertThat(request.getCommandLine().getArgs(), equalTo(new String[] {"prefix:3.0.0:bar", "validate"}));
} }
@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) { private MavenProject createMavenProject(String groupId, String artifactId) {
MavenProject project = new MavenProject(); MavenProject project = new MavenProject();
project.setGroupId(groupId); project.setGroupId(groupId);