Создать собственный плагин для платформы 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 не так сложно, как кажется на первый взгляд. Это может быть очень интересно и полезно. К этому сообщению я приложил весь проект, чтобы вы могли скачать его и попробовать, если хотите. Надеюсь, вам понравился мой пост, и спасибо, что прочитали это краткое описание.