需求
sonar-pmd 插件只有添加了 pmd 的 java 规则, 现在需要添加 pmd 的 xml 规则, 更准确是添加自定义的 xml 规则.
步骤:
为了更好集成和示范, 选择前人已集成 p3c 的 sonar-pmd 插件.
url: https://github.com/mrprince/sonar-p3c-pmd
Git clone 到本地
集成分为两个环节:
1. 规则配置
2. 源码修改
规则配置
该插件首先依赖 PmdRulesDefinition 对仓库 repository 进行定义, 从
extractRulesData(repository, "/org/sonar/plugins/pmd/rules.xml", "/org/sonar/l10n/pmd/rules/pmd");
方法内部, 可以得知其是读取外部配置来初始化 pmd 的 rules.
一共有四处需要配置:
- /org/sonar/plugins/pmd/rules.xml
- /org/sonar/l10n/pmd/rules/pmd
- /com/sonar/sqale/pmd-model.xml
- /org/sonar/l10n/pmd.properties
对于配置, 没有什么多说的, 原则就是模仿!
l10n 下的 html 是需要和 rule 的 key 一致. 作用是 sonar 的 rule 页面展示.
pmd.properties 的 rule.pmd-xml.MistypedCDATASection.name 中, rule.pmd-xml 代表 repository 名字, 需要一致.
源码修改
在 PmdRulesDefinition 类的 define(Context context) 里可以看到 extractRulesData 是读取配置信息, 如果想分别管理不同类型的规则, 例如 pmd 原生和 p3c 规则, 就可以分别配置, 另外读取.
NewRepository 类是和 sonar 的规则语言绑定的, 所以另外增加一个新的 repository 对象, 添加 xml.Key
pom.xml 新增依赖:
- <dependency>
- <groupId>org.sonarsource.sonar-xml-plugin</groupId>
- <artifactId>sonar-xml-plugin</artifactId>
- <version>1.3</version>
- <scope>provided</scope>
- </dependency>
- NewRepository xmlRepository = context
- .createRepository(PmdConstants.XML_REPOSITORY_KEY, xml.KEY)
- .setName(PmdConstants.XML_REPOSITORY_NAME);
模仿之前的 repository 设置, 将一些常量写在 PmdConstants 类里, 后续还会经常用到这个 string 值.
入口: PmdSensor
真正的入口是 PmdSensor, 重写父类 Sensor 的 analyse 方法, 定位到这个方法, 继续开始修改.
因为添加了一个新的仓库, 而且从源码得知, 一开始代码只是支持 java 的规则, 全部都是写死的, 现在需要新增 xml. 修改该类的 shouldExecuteOnProject 和 hasFilesToCheck, 这里显然也是和 sonar 接口对接的方法, 用于判断是否执行的.
- @Override
- public boolean shouldExecuteOnProject(Project project) {
- return (hasFilesToCheck(Type.MAIN, PmdConstants.REPOSITORY_KEY))
- || (hasFilesToCheck(Type.TEST, PmdConstants.TEST_REPOSITORY_KEY))
- || (hasFilesToCheck(Type.MAIN, PmdConstants.XML_REPOSITORY_KEY)) ;
- }
- private boolean hasFilesToCheck(Type type, String repositoryKey) {
- FilePredicates predicates = fs.predicates();
- Iterable<File> files = fs.files(predicates.or(
- predicates.and(predicates.hasLanguage(xml.KEY),predicates.hasType(type)),
- predicates.and(predicates.hasLanguage(Java.KEY),
- predicates.hasType(type))));
- return !Iterables.isEmpty(files) && !profile.getActiveRulesByRepository(repositoryKey).isEmpty();
- }
新增了 xml 的判断, Type.MAIN 是代表扫描的 source 是在 src/main 下, 和 src/test 对应. FilePredicates 很像之前接触的 FileFilter 类, 使用方式也很像, 为了有 xml 或 java 时都返回 true, 就在外面写一个 predicates.or, 这种类的设计感觉除了写着麻烦, 实际上很好理解.
接下来从 analyse 方法一步步进去, 遇到有硬编码和判断语言类型的地方就着手修改.
PmdExecutor 执行 pmd 的地方.
- private Report executePmd(URLClassLoader classLoader) {
- ...
- PmdTemplate pmdFactory = createPmdTemplate(classLoader);
- executeRules(pmdFactory, context, javaFiles(Type.MAIN), PmdConstants.REPOSITORY_KEY);
- ...
- return report;
- }
可以看到, 是通过 PmdTemplate 来执行 rules, 模仿它新增一句:
executeRules(pmdFactory, context, xmlFiles(Type.MAIN), PmdConstants.XML_REPOSITORY_KEY);
并且提供自己的 xmlFiles 方法, 基于语言过滤.
为了一探究竟, 顺便看看 PmdTemplate 类
从代码看是通过 create 方法初始化 PMDConfiguration 和 SourceCodeProcessor 两个对象. SourceCodeProcessor 是传入 InputStream 和 rulesets 来分析每个文件的 PMD 核心分析类.
通过 languageVersions 来控制可使用何种语言的 rule.
原先是只添加了 java 的 LanguageModule, 现在需要增加 xml 部分. 对 pmd 源码进行分析, 即可知道 new XmlLanguageModule().getVersion("") 可获得 xml 的 languageVersion.
PmdViolationRecorder 输出
最后输出的地方仍旧需要修改.
- private Rule findRuleFor(RuleViolation violation) {
- String ruleKey = violation.getRule().getName();
- Rule xmlRule = ruleFinder.findByKey(PmdConstants.XML_REPOSITORY_KEY, ruleKey);
- if (xmlRule != null) {
- return xmlRule;
- }
- Rule rule = ruleFinder.findByKey(PmdConstants.REPOSITORY_KEY, ruleKey);
- if (rule != null) {
- return rule;
- }
- return ruleFinder.findByKey(PmdConstants.TEST_REPOSITORY_KEY, ruleKey);
- }
这里需要添加 xmlRule, 否则是找一个普通 javaRule, 没有则返回 java 的 testRule
源码改的差不多了. 但 test 里的类还需要修改, 如果直接执行, 会有部分类报错, 因为它 test 里也是硬编码了 java 的. 当然也可以选择 - Dmaven.test.skip=true.
本文对应 GitHub 地址:
https://github.com/phinehasz/sonar-pmd-xml-plugin
最快捷的办法, 下载我的代码, 在其基础上新增配置.
- Git clone https://github.com/phinehasz/sonar-pmd-xml-plugin
- mvn package
放到 sonar{version}\extensions\plugins
restart sonar 即可
来源: https://www.cnblogs.com/zhhiyp/p/9839132.html