From 1ebbe0c59219a324abf64e3a2d6a7e2793b4dc0a Mon Sep 17 00:00:00 2001 From: Andres Almiray Date: Mon, 31 May 2021 00:33:11 +0200 Subject: [PATCH] [core] Validate YAML config files. Resolves #184 --- .../json/JsonJReleaserConfigParser.java | 5 +++ .../toml/TomlJReleaserConfigParser.java | 5 +++ .../jreleaser-config-yaml.gradle | 4 +++ .../yaml/YamlJReleaserConfigParser.java | 36 +++++++++++++++++++ .../config/JReleaserConfigLoader.java | 5 +++ .../config/JReleaserConfigParser.java | 7 ++++ gradle.properties | 1 + 7 files changed, 63 insertions(+) diff --git a/core/jreleaser-config-json/src/main/java/org/jreleaser/config/json/JsonJReleaserConfigParser.java b/core/jreleaser-config-json/src/main/java/org/jreleaser/config/json/JsonJReleaserConfigParser.java index 54547064..434bcde7 100644 --- a/core/jreleaser-config-json/src/main/java/org/jreleaser/config/json/JsonJReleaserConfigParser.java +++ b/core/jreleaser-config-json/src/main/java/org/jreleaser/config/json/JsonJReleaserConfigParser.java @@ -43,6 +43,11 @@ public class JsonJReleaserConfigParser implements JReleaserConfigParser { return configFile.getFileName().toString().endsWith(".json"); } + @Override + public void validate(Path configFile) throws IOException { + // noop + } + @Override public JReleaserModel parse(InputStream inputStream) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/core/jreleaser-config-toml/src/main/java/org/jreleaser/config/toml/TomlJReleaserConfigParser.java b/core/jreleaser-config-toml/src/main/java/org/jreleaser/config/toml/TomlJReleaserConfigParser.java index 26da9a26..7518a92f 100644 --- a/core/jreleaser-config-toml/src/main/java/org/jreleaser/config/toml/TomlJReleaserConfigParser.java +++ b/core/jreleaser-config-toml/src/main/java/org/jreleaser/config/toml/TomlJReleaserConfigParser.java @@ -43,6 +43,11 @@ public class TomlJReleaserConfigParser implements JReleaserConfigParser { return configFile.getFileName().toString().endsWith(".toml"); } + @Override + public void validate(Path configFile) throws IOException { + // noop + } + @Override public JReleaserModel parse(InputStream inputStream) throws IOException { TomlMapper mapper = TomlMapper.builder().build(); diff --git a/core/jreleaser-config-yaml/jreleaser-config-yaml.gradle b/core/jreleaser-config-yaml/jreleaser-config-yaml.gradle index c9625d83..915e0c08 100644 --- a/core/jreleaser-config-yaml/jreleaser-config-yaml.gradle +++ b/core/jreleaser-config-yaml/jreleaser-config-yaml.gradle @@ -20,6 +20,10 @@ dependencies { api "com.fasterxml.jackson.core:jackson-core:$jacksonVersion" api "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" api "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jacksonVersion" + api("com.github.sbaudoin:yamllint:1.3.1") { + exclude group: 'commons-cli', module: 'commons-cli' + exclude group: 'com.google.code.findbugs', module: 'jsr305' + } compileOnly "org.kordamp.jipsy:jipsy-annotations:${jipsyVersion}" annotationProcessor "org.kordamp.jipsy:jipsy-processor:${jipsyVersion}" diff --git a/core/jreleaser-config-yaml/src/main/java/org/jreleaser/config/yaml/YamlJReleaserConfigParser.java b/core/jreleaser-config-yaml/src/main/java/org/jreleaser/config/yaml/YamlJReleaserConfigParser.java index 08c44db9..6dce6d52 100644 --- a/core/jreleaser-config-yaml/src/main/java/org/jreleaser/config/yaml/YamlJReleaserConfigParser.java +++ b/core/jreleaser-config-yaml/src/main/java/org/jreleaser/config/yaml/YamlJReleaserConfigParser.java @@ -18,6 +18,11 @@ package org.jreleaser.config.yaml; import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import com.github.sbaudoin.yamllint.Format; +import com.github.sbaudoin.yamllint.LintProblem; +import com.github.sbaudoin.yamllint.Linter; +import com.github.sbaudoin.yamllint.YamlLintConfig; +import com.github.sbaudoin.yamllint.YamlLintConfigException; import org.jreleaser.config.JReleaserConfigParser; import org.jreleaser.model.JReleaserModel; import org.kordamp.jipsy.annotations.ServiceProviderFor; @@ -25,14 +30,27 @@ import org.kordamp.jipsy.annotations.ServiceProviderFor; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; +import java.util.List; import java.util.Map; +import static java.lang.System.lineSeparator; +import static java.util.Arrays.asList; + /** * @author Andres Almiray * @since 0.1.0 */ @ServiceProviderFor(JReleaserConfigParser.class) public class YamlJReleaserConfigParser implements JReleaserConfigParser { + private static final String YAML_LINT_CONFIG = String.join(lineSeparator(), asList( + "---", + "rules:", + " indentation:", + " spaces: consistent", + " check-multi-line-strings: true", + " indent-sequences: true", + " comments-indentation: {}")) + lineSeparator(); + @Override public String getPreferredFileExtension() { return "yml"; @@ -44,6 +62,24 @@ public class YamlJReleaserConfigParser implements JReleaserConfigParser { return fileName.endsWith(".yml") || fileName.endsWith(".yaml"); } + @Override + public void validate(Path configFile) throws IOException { + YamlLintConfig config = null; + try { + config = new YamlLintConfig(YAML_LINT_CONFIG); + } catch (YamlLintConfigException e) { + return; + } + + List problems = Linter.run(config, configFile.toFile()); + + if (!problems.isEmpty()) { + throw new IOException(Format.format(configFile.toAbsolutePath().toString(), + problems, + Format.OutputFormat.AUTO)); + } + } + @Override public JReleaserModel parse(InputStream inputStream) throws IOException { YAMLMapper mapper = YAMLMapper.builder().build(); diff --git a/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigLoader.java b/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigLoader.java index f3a3b3ff..39a50e29 100644 --- a/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigLoader.java +++ b/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigLoader.java @@ -36,6 +36,11 @@ public class JReleaserConfigLoader { for (JReleaserConfigParser parser : parsers) { if (parser.supports(configFile)) { + try { + parser.validate(configFile); + } catch (IOException e) { + throw new JReleaserException("Invalid config file. " + configFile, e); + } try (InputStream inputStream = configFile.toUri().toURL().openStream()) { return parser.parse(inputStream); } catch (IOException e) { diff --git a/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigParser.java b/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigParser.java index 23eb199b..0853d303 100644 --- a/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigParser.java +++ b/core/jreleaser-model/src/main/java/org/jreleaser/config/JReleaserConfigParser.java @@ -47,6 +47,13 @@ public interface JReleaserConfigParser { */ boolean supports(Path configFile); + /** + * Checks the contents of the config file for syntax compliance. + * + * @param configFile the configuration file to inspect + */ + void validate(Path configFile) throws IOException; + /** * Reads and parses external configuration into a {@code JReleaserModel} instance. * diff --git a/gradle.properties b/gradle.properties index 8d3b889e..3d5f528c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -52,6 +52,7 @@ wiremockVersion = 2.28.0 slf4jVersion = 1.7.30 snakeYamlVersion = 1.27 twitter4jVersion = 4.0.7 +yamllintVersion = 1.3.1 ztexecVersion = 1.12 org.gradle.daemon = true