diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index c29d9a858..906168834 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -13,6 +13,10 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co == Unreleased +Improvement:: + +* Add command line option --failure-level to force non-zero exit code from AsciidoctorJ CLI if specified logging level is reached. (#1115) (@pasieronen) + Bug Fixes:: * Avoid throwing an exception when using AsciidoctorJ CLI and reading input from stdin (#1105) (@AlexCzar) diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorCliOptions.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorCliOptions.java index 8b694278e..724a6539c 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorCliOptions.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorCliOptions.java @@ -2,6 +2,7 @@ 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 require; @@ -111,6 +115,8 @@ public boolean isQuiet() { return quiet; } + public Severity getFailureLevel() { return failureLevel; } + public boolean isRequire() { return this.require != null && this.require.size() > 0; } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorInvoker.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorInvoker.java index 86adfd09a..ec5fc4629 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/AsciidoctorInvoker.java +++ b/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 void invoke(String... parameters) { 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 inputFiles = getInputFiles(asciidoctorCliOptions); @@ -72,12 +72,17 @@ public void invoke(String... parameters) { convertInput(asciidoctor, options, inputFiles); + if (asciidoctorCliOptions.getFailureLevel().compareTo(asciidoctor.getMaxSeverity()) <= 0) { + return 1; + } + if (asciidoctorCliOptions.isTimings()) { Map 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 static void main(String args[]) { // Process .jrubyrc file Main.processDotfile(); - new AsciidoctorInvoker().invoke(args); + int status = new AsciidoctorInvoker().invoke(args); + if (status != 0) { + System.exit(status); + } } } diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/SeverityConverter.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/SeverityConverter.java new file mode 100644 index 000000000..b0fc987fa --- /dev/null +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/cli/SeverityConverter.java @@ -0,0 +1,12 @@ +package org.asciidoctor.jruby.cli; + +import com.beust.jcommander.IStringConverter; +import org.asciidoctor.SafeMode; +import org.asciidoctor.log.Severity; + +public class SeverityConverter implements IStringConverter { + + @Override + public Severity convert(String argument) { return Severity.valueOf(argument.toUpperCase()); } + +} diff --git a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java index ff85e1e2b..4d561d171 100644 --- a/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java +++ b/asciidoctorj-core/src/main/java/org/asciidoctor/jruby/internal/JRubyAsciidoctor.java @@ -22,6 +22,7 @@ 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 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 @@ private RubyClass getExtensionGroupClass() { @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; + } } diff --git a/asciidoctorj-core/src/test/java/org/asciidoctor/jruby/cli/WhenAsciidoctorIsCalledUsingCli.java b/asciidoctorj-core/src/test/java/org/asciidoctor/jruby/cli/WhenAsciidoctorIsCalledUsingCli.java index f3f9d3d00..464aab346 100644 --- a/asciidoctorj-core/src/test/java/org/asciidoctor/jruby/cli/WhenAsciidoctorIsCalledUsingCli.java +++ b/asciidoctorj-core/src/test/java/org/asciidoctor/jruby/cli/WhenAsciidoctorIsCalledUsingCli.java @@ -249,6 +249,22 @@ public void quiet_option_should_not_write_to_console() { } + @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() {