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