Создать собственный плагин для платформы Sonar очень просто. Если вас не устраивают несколько встроенных плагинов или вам нужно что-то особенное, вы можете легко создать и использовать свой собственный.
В моем текущем проекте мы используем платформу качества кода Sonar уже два года. Это здорово, когда вы хотите обеспечить качество кода вашего проекта. Платформа может визуализировать:
- проблемы, обнаруженные статическими анализаторами кода,
- качества кода,
- покрытие кода и другие умные и полезные вещи.
Если вы не знакомы с ним, продолжайте и попробуйте. Вы можете найти Платформу по адресу: http://www.sonarsource.org/
Как вы, наверное, знаете, платформа Sonar имеет множество встроенных плагинов, а также имеет четко определенный API, если вы хотите написать свой собственный. API хорошо документирован, его можно найти на этом сайте: http://www.sonarsource.org/docs/ . Вы можете получить краткое, но очень полезное описание на этом вики-сайте: http://docs.codehaus.org/display/SONAR/Coding+a+plugin о том, как разработать плагин.
Мой текущий проект очень сильно использует объекты-значения, сгенерированные JAXB, и мы также создали много пользовательских типов исключений . Я не хочу, чтобы эти сгенерированные компоненты и типы исключений влияли, например, на покрытие кода проекта (наша концепция заключалась в том, что мы не пишем модульные тесты для сгенерированных кодов.). Поэтому мне нужен способ исключить эти ресурсы из процедуры анализа.
Sonar поставляется с встроенным в плагин с именем ExcludedResourceFilter , который связан с ресурсами и ресурсами фильтрации на уровне проекта. Я думал, что мог бы использовать это, чтобы исключить упомянутые выше классы, но, к сожалению, у меня есть небольшая проблема с настройкой.
Проблема конфигурации в этом состоит в том, что я не могу установить глобальные — не уровень проекта — шаблоны исключения. Поэтому, если у меня есть два или более проектов Sonar, которые используют один и тот же шаблон исключения, я должен установить эти шаблоны в каждом проекте по одному.
Вдохновленный этим недостатком — и потому что мне лень заполнять эту информацию в каждом проекте ? — я решил создать свой первый плагин Sonar, который фильтрует ресурсы в соответствии с шаблонами, определенными на глобальном уровне и / или уровне проекта. Плагин очень прост, потому что у него есть только одно расширение, которое действительно выполняет фильтрацию ресурсов.
Давайте посмотрим, как это реализовать.
Согласно руководству разработчика плагинов Sonar, первым шагом является создание класса, который реализует интерфейс плагина . В этом интерфейсе метод getExtensions является наиболее важным, поскольку он определяет точки расширения.
Мой класс ResourceFilteringPlugin выглядит следующим образом:
1: package example.sonar.resourcefitering.plugin; 2: 3: import java.util.Arrays; 4: import java.util.List; 5: 6: import org.sonar.api.Plugin; 7: import org.sonar.api.Properties; 8: import org.sonar.api.Property; 9: 10: import example.sonar.resourcefitering.filter.CustomResourceFilter; 11: 12: @Properties({ 13: @Property(key = CustomResourceFilter.PROPERTY_DEFAULT_PATTERNS, name = "Default Patterns", description = "These are the default exclusion patterns.", defaultValue = "**/bean/*.java,**/*Exception.java", module = false, project = false, global = true), 14: @Property(key = CustomResourceFilter.PROPERTY_REPLACE_PROJECT_PATTERNS_WITH_DEFAULT_PATTERNS, name = "Replace project's exclusion patterns with default patterns.", description = "When this is enabled the default patterns are used and the project's patterns are ignored.", defaultValue = "false", module = false, project = false, global = true), 15: @Property(key = CustomResourceFilter.PROPERTY_EXTEND_PROJECT_PATTERNS_WITH_DEFAULT_PATTERNS, name = "Extend project's exclusion patterns with default patterns.", description = "If this property is set to true the project's exclusion patterns are extended with the default patterns.", defaultValue = "true", module = false, project = false, global = true) }) 16: public class ResourceFilteringPlugin implements Plugin 17: { 18: /** 19: * @deprecated this is not used anymore 20: */ 21: @Deprecated 22: public String getKey() 23: { 24: return "resourcefiltering"; 25: } 26: 27: /** 28: * @deprecated this is not used anymore 29: */ 30: @Deprecated 31: public String getName() 32: { 33: return "Resource Filtering"; 34: } 35: 36: /** 37: * @deprecated this is not used anymore 38: */ 39: @Deprecated 40: public String getDescription() 41: { 42: return "Filters resources based on pattenrs."; 43: } 44: 45: // This is where you're going to declare all your Sonar extensions 46: @SuppressWarnings({ "unchecked", "rawtypes" }) 47: public List getExtensions() 48: { 49: return Arrays.asList(CustomResourceFilter.class); 50: } 51: }
Как видите, класс реализует интерфейс Plugin со всеми необходимыми методами. Метод getExtensions возвращает только одну точку расширения, мой класс CustomResourceFilter, который выполняет фильтрацию ресурсов. Еще одна интересная вещь — аннотация Properties в верхней части класса. С помощью этой аннотации вы можете определить параметры конфигурации для вашего плагина. В следующем списке кратко описаны используемые свойства:
- sonar.resourcefiltering.default.patterns: Вы можете определить шаблоны исключений по умолчанию (разделенные комой) на панели глобальной конфигурации плагина.
- sonar.resourcefiltering.replace.project.patterns.with.default.patterns: С помощью этого свойства вы можете указать плагину игнорировать шаблоны исключения проекта и использовать только стандартные (это отключено по умолчанию.),
- sonar.resourcefiltering.extend.project.patterns.with.default.patterns: по крайней мере, этот параметр конфигурации указывает плагину использовать оба шаблона исключения, шаблоны, определенные в глобальном свойстве по умолчанию и на панели конфигурации проекта. (Это включено по умолчанию.)
На следующем шаге мы должны реализовать сам класс расширения, который в моем случае выглядит следующим образом:
1: package example.sonar.resourcefitering.filter; 2: 3: import java.util.ArrayList; 4: import java.util.Arrays; 5: import java.util.List; 6: 7: import org.apache.commons.configuration.Configuration; 8: import org.sonar.api.batch.ResourceFilter; 9: import org.sonar.api.resources.Project; 10: import org.sonar.api.resources.Resource; 11: import org.sonar.api.resources.ResourceUtils; 12: 13: public class CustomResourceFilter implements ResourceFilter 14: { 15: public static final String PROPERTY_DEFAULT_PATTERNS = "sonar.resourcefiltering.default.patterns"; 16: 17: public static final String PROPERTY_REPLACE_PROJECT_PATTERNS_WITH_DEFAULT_PATTERNS = "sonar.resourcefiltering.replace.project.patterns.with.default.patterns"; 18: 19: public static final String PROPERTY_EXTEND_PROJECT_PATTERNS_WITH_DEFAULT_PATTERNS = "sonar.resourcefiltering.extend.project.patterns.with.default.patterns"; 20: 21: protected String[] exclusionPatterns; 22: 23: public CustomResourceFilter(final Project project, final Configuration configuration) 24: { 25: final List<String> exclusionPatterns = new ArrayList<String>(); 26: 27: if (configuration.getBoolean(PROPERTY_REPLACE_PROJECT_PATTERNS_WITH_DEFAULT_PATTERNS, false)) 28: { 29: exclusionPatterns.addAll(Arrays.asList(configuration.getStringArray(PROPERTY_DEFAULT_PATTERNS))); 30: } 31: else 32: { 33: exclusionPatterns.addAll(Arrays.asList(project.getExclusionPatterns())); 34: 35: if (configuration.getBoolean(PROPERTY_EXTEND_PROJECT_PATTERNS_WITH_DEFAULT_PATTERNS, true)) 36: { 37: exclusionPatterns.addAll(Arrays.asList(configuration.getStringArray(PROPERTY_DEFAULT_PATTERNS))); 38: } 39: } 40: 41: this.exclusionPatterns = exclusionPatterns.toArray(new String[exclusionPatterns.size()]); 42: } 43: 44: @SuppressWarnings("rawtypes") 45: public boolean isIgnored(final Resource resource) 46: { 47: if (ResourceUtils.isUnitTestClass(resource)) 48: { 49: return false; 50: } 51: 52: for (final String pattern : this.exclusionPatterns) 53: { 54: if (resource.matchFilePattern(pattern)) 55: { 56: return true; 57: } 58: } 59: return false; 60: } 61: }
Класс реализует интерфейс ResourceFilter, который определяет только один метод isIgnored, в котором выполняется фильтрация ресурсов. Логика очень проста: если данный ресурс не является модульным тестом и не соответствует ни одному шаблону фильтрации, он не фильтруется, что означает, что он будет включен, например, в покрытие кода проекта. Я думаю, что конструктор этого класса более интересен. Как видите, это не конструктор класса по умолчанию, потому что он имеет два параметра. Первый параметр — это объект, представляющий текущий проект сонара., С помощью этого объекта вы можете получить доступ к настройкам конфигурации данного проекта. Второй — объект глобальной конфигурации, который можно использовать для запроса настроек глобальной конфигурации плагина. Эти элементы вводятся автоматически с помощью каркаса сонара . Вам не нужно комментировать или делать что-либо, они просто вводятся автоматически. Тело конструктора создает используемые шаблоны исключений на основе заданных объектов и параметров конфигурации.
Итак, мы закончили с плагином и его расширением. Последний шаг — создать jar-файл, содержащий наш плагин, и развернуть его на сервере Sonar . Чтобы создать правильный файл jar, мы можем использовать плагин Sonar maven, как я это сделал. В следующем фрагменте POM показано, как использовать и настраивать плагин maven:
1: <build> 2: <plugins> 3: <plugin> 4: <groupId>org.codehaus.sonar</groupId> 5: <artifactId>sonar-packaging-maven-plugin</artifactId> 6: <version>1.0</version> 7: <extensions>true</extensions> 8: <configuration> 9: <pluginClass>example.sonar.resourcefitering.plugin.ResourceFilteringPlugin</pluginClass> 10: <pluginKey>resourcefiltering</pluginKey> 11: <pluginName>Resource Filtering</pluginName> 12: <pluginDescription>Filters resources based on patterns.</pluginDescription> 13: </configuration> 14: </plugin> 15: <plugin> 16: <groupId>org.apache.maven.plugins</groupId> 17: <artifactId>maven-compiler-plugin</artifactId> 18: <version>2.0.2</version> 19: <configuration> 20: <source>1.5</source> 21: <target>1.5</target> 22: <encoding>UTF-8</encoding> 23: </configuration> 24: </plugin> 25: </plugins> 26: </build>
Если вы выполните команду mvn package, вы получите файл с именем resourcefilter-1.0.0.jar, который можно развернуть на вашем сервере Sonar .
Резюме
Я думаю, что написание плагина Sonar не так сложно, как кажется на первый взгляд. Это может быть очень интересно и полезно. К этому сообщению я приложил весь проект, чтобы вы могли скачать его и попробовать, если хотите. Надеюсь, вам понравился мой пост, и спасибо, что прочитали это краткое описание.