001/* 002 * Copyright 2017-2023 original authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.micronaut.maven.enforcer; 017 018import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule; 019import org.apache.maven.enforcer.rule.api.EnforcerRuleException; 020import org.apache.maven.model.Dependency; 021import org.apache.maven.model.Resource; 022import org.apache.maven.project.MavenProject; 023import org.codehaus.plexus.util.xml.XmlUtil; 024import org.eclipse.aether.util.artifact.JavaScopes; 025 026import javax.inject.Inject; 027import javax.inject.Named; 028import java.io.File; 029import java.io.IOException; 030import java.io.StringReader; 031import java.io.StringWriter; 032import java.util.Arrays; 033 034/** 035 * Enforcer rule to check that, when the application has YAML configuration, the SnakeYAML library is present. 036 * 037 * @author Álvaro Sánchez-Mariscal 038 * @since 4.0.0 039 */ 040@Named("checkSnakeYaml") 041public class CheckSnakeYaml extends AbstractEnforcerRule { 042 043 private final MavenProject project; 044 private final Dependency snakeYaml; 045 046 @Inject 047 public CheckSnakeYaml(MavenProject project) { 048 this.project = project; 049 this.snakeYaml = new Dependency(); 050 snakeYaml.setGroupId("org.yaml"); 051 snakeYaml.setArtifactId("snakeyaml"); 052 snakeYaml.setScope(JavaScopes.RUNTIME); 053 } 054 055 @Override 056 public void execute() throws EnforcerRuleException { 057 if (hasYamlConfiguration() && !hasSnakeYaml()) { 058 String message = "YAML configuration file detected, but SnakeYAML is not on the runtime classpath. Make sure to add the following dependency:" + 059 System.lineSeparator(); 060 061 message += toXml(snakeYaml); 062 throw new EnforcerRuleException(message); 063 } 064 } 065 066 private boolean hasYamlConfiguration() { 067 return this.project.getResources().stream().anyMatch(this::hasYamlConfiguration); 068 } 069 070 private boolean hasSnakeYaml() { 071 return project.getDependencies().stream() 072 .anyMatch(d -> d.getGroupId().equals(snakeYaml.getGroupId()) && d.getArtifactId().equals(snakeYaml.getArtifactId())); 073 } 074 075 private boolean hasYamlConfiguration(Resource resource) { 076 File[] files = new File(resource.getDirectory()).listFiles(); 077 if (files != null) { 078 return Arrays.stream(files).anyMatch(this::isYamlConfigurationFile); 079 } else { 080 return false; 081 } 082 } 083 084 private boolean isYamlConfigurationFile(File f) { 085 String name = f.getName().toLowerCase(); 086 return name.startsWith("application") && (name.endsWith(".yml") || name.endsWith(".yaml")); 087 } 088 089 private String toXml(Dependency dependency) { 090 StringReader dependencyXml = new StringReader("<dependency>" + 091 "<groupId>" + dependency.getGroupId() + "</groupId>" + 092 "<artifactId>" + dependency.getArtifactId() + "</artifactId>" + 093 "<scope>" + dependency.getScope() + "</scope>" + 094 "</dependency>"); 095 StringWriter result = new StringWriter(); 096 try { 097 XmlUtil.prettyFormat(dependencyXml, result); 098 return result.toString(); 099 } catch (IOException e) { 100 return dependencyXml.toString(); 101 } 102 } 103 104 @Override 105 public String toString() { 106 return "CheckSnakeYaml"; 107 } 108}