Add --failure-level command line option to force non-zero exit code from CLI if specified logging level is reached
MODIFY
CHANGELOG.adoc
CHANGELOG.adoc
@@ -17,6 +17,7 @@ Improvement::
* BREAKING: Fix Macro APIs to take StructuralNodes and return Phrase- or StructuralNodes. (#1084)
* BREAKING: Allow Preprocessor extensions to create new Readers and replace the original Reader. (#1081)
+* Add command line option --failure-level to force non-zero exit code from AsciidoctorJ CLI if specified logging level is reached. (#1114)
* Upgrade to asciidoctorj-pdf 2.3.0 (#1109)
* Upgrade to JRuby 9.3.7.0 (#1109)
* Upgrade to tilt 2.0.11 (#1109)

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorCliOptions.java
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorCliOptions.java
@@ -2,6 +2,7 @@ package org.asciidoctor.jruby.cli;
import com.beust.jcommander.Parameter;
import org.asciidoctor.*;
+import org.asciidoctor.log.Severity;
import java.io.File;
import java.util.*;
@@ -95,6 +96,9 @@ public class AsciidoctorCliOptions {
@Parameter(names = {QUIET, "--quiet"}, description = "suppress warnings (default: false)")
private boolean quiet = false;
+ @Parameter(names = {"--failure-level"}, converter = SeverityConverter.class, description = "set minimum log level that yields a non-zero exit code: [info, warning, error, fatal] (default: fatal) ")
+ private Severity failureLevel = Severity.FATAL;
+
@Parameter(names = {REQUIRE, "--require"}, description = "require the specified library before executing the processor (using require)")
private List<String> require;
@@ -111,6 +115,8 @@ public class AsciidoctorCliOptions {
return quiet;
}
+ public Severity getFailureLevel() { return failureLevel; }
+
public boolean isRequire() {
return this.require != null && this.require.size() > 0;
}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorInvoker.java
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorInvoker.java
@@ -26,7 +26,7 @@ public class AsciidoctorInvoker {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
- public void invoke(String... parameters) {
+ public int invoke(String... parameters) {
AsciidoctorCliOptions asciidoctorCliOptions = new AsciidoctorCliOptions();
JCommander jCommander = new JCommander(asciidoctorCliOptions);
@@ -43,7 +43,7 @@ public class AsciidoctorInvoker {
System.out.println("AsciidoctorJ " + getAsciidoctorJVersion() + " (Asciidoctor " + asciidoctor.asciidoctorVersion() + ") [https://asciidoctor.org]");
Object rubyVersionString = JRubyRuntimeContext.get(asciidoctor).evalScriptlet("\"#{JRUBY_VERSION} (#{RUBY_VERSION})\"");
System.out.println("Runtime Environment: jruby " + rubyVersionString);
- return;
+ return 0;
}
List<File> inputFiles = getInputFiles(asciidoctorCliOptions);
@@ -72,12 +72,17 @@ public class AsciidoctorInvoker {
convertInput(asciidoctor, options, inputFiles);
+ if (asciidoctorCliOptions.getFailureLevel().compareTo(asciidoctor.getMaxSeverity()) <= 0) {
+ return 1;
+ }
+
if (asciidoctorCliOptions.isTimings()) {
Map<String, Object> optionsMap = options.map();
IRubyObject timings = (IRubyObject) optionsMap.get(TIMINGS_OPTION_NAME);
timings.callMethod(JRubyRuntimeContext.get(asciidoctor).getCurrentContext(), "print_report");
}
}
+ return 0;
}
private String getAsciidoctorJVersion() {
@@ -196,7 +201,10 @@ public class AsciidoctorInvoker {
// Process .jrubyrc file
Main.processDotfile();
- new AsciidoctorInvoker().invoke(args);
+ int status = new AsciidoctorInvoker().invoke(args);
+ if (status != 0) {
+ System.exit(status);
+ }
}
}

ADD
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/SeverityConverter.java
+package org.asciidoctor.jruby.cli;
+
+import com.beust.jcommander.IStringConverter;
+import org.asciidoctor.SafeMode;
+import org.asciidoctor.log.Severity;
+
+public class SeverityConverter implements IStringConverter<Severity> {
+
+ @Override
+ public Severity convert(String argument) { return Severity.valueOf(argument.toUpperCase()); }
+
+}

MODIFY
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java
asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java
@@ -22,6 +22,7 @@ import org.asciidoctor.jruby.log.internal.LogHandlerRegistryExecutor;
import org.asciidoctor.jruby.syntaxhighlighter.internal.SyntaxHighlighterRegistryExecutor;
import org.asciidoctor.log.LogHandler;
import org.asciidoctor.log.LogRecord;
+import org.asciidoctor.log.Severity;
import org.asciidoctor.syntaxhighlighter.SyntaxHighlighterRegistry;
import org.jruby.*;
import org.jruby.exceptions.RaiseException;
@@ -46,6 +47,8 @@ public class JRubyAsciidoctor implements AsciidoctorJRuby, LogHandler {
private List<LogHandler> logHandlers = new ArrayList<>();
+ private Severity maxSeverity = Severity.DEBUG;
+
public JRubyAsciidoctor() {
this(createRubyRuntime(Collections.singletonMap(GEM_PATH, null), new ArrayList<>(), null));
processRegistrations(this);
@@ -507,8 +510,15 @@ public class JRubyAsciidoctor implements AsciidoctorJRuby, LogHandler {
@Override
public void log(LogRecord logRecord) {
+ if (this.maxSeverity.compareTo(logRecord.getSeverity()) < 0) {
+ this.maxSeverity = logRecord.getSeverity();
+ }
for (LogHandler logHandler : logHandlers) {
logHandler.log(logRecord);
}
}
+
+ public Severity getMaxSeverity() {
+ return this.maxSeverity;
+ }
}

MODIFY
asciidoctorj-core/src/test/java/org/asciidoctor/jruby/cli/WhenAsciidoctorIsCalledUsingCli.java
asciidoctorj-core/src/test/java/org/asciidoctor/jruby/cli/WhenAsciidoctorIsCalledUsingCli.java
@@ -249,6 +249,22 @@ public class WhenAsciidoctorIsCalledUsingCli {
}
+ @Test
+ public void should_exit_with_zero_status_even_if_errors_were_logged() {
+ File inputFile = classpath.getResource("brokeninclude.asciidoc");
+ String inputPath = inputFile.getPath().substring(pwd.length() + 1);
+ int status = new AsciidoctorInvoker().invoke(inputPath);
+ assertThat(status, is(0));
+ }
+
+ @Test
+ public void should_exit_with_nonzero_status_if_logged_severity_was_at_least_failure_level() {
+ File inputFile = classpath.getResource("brokeninclude.asciidoc");
+ String inputPath = inputFile.getPath().substring(pwd.length() + 1);
+ int status = new AsciidoctorInvoker().invoke("--failure-level", "warn", inputPath);
+ assertThat(status, is(1));
+ }
+
@Test
public void with_absolute_path_file_should_be_rendered() {

Add --failure-level command line option to force non-zero exit code from CLI if specified logging level is reached