sonar相关插件开发

前言

某天,来一需求,由于业务线使用ThreadLocal后经常忘记remove,导致出现一些故障。为了可以尽早发现这种使用错误的现象,想在公司使用的sonar上新加一个规则用于检查ThreadLocal。

接下来开始了苦逼的扩展sonar插件。。。。。

no文档,no demo,goole搜到的资料也是寥寥数语,怎么办。。。。。

打开sonar的官方文档,虽然介绍不是很清楚,先看看吧,再想想怎么来实现。

注:sonar官方文档

要写代码还得先看看已有的plugin的代码,因为是扩展java的检查规则,还是看java plugin的source code吧

注:sonar-java source code github site

看代码。。。。。。根本看不懂啊,readme也没有,debug吧,最好的方式,那怎么开始远程debug呢。


如何开始远程debug

debug的方式有好多种,本文主要说说mvn debug方式,怎么用mvn来进行debug。

集成开发环境:IDEA

首先,在idea里添加远程debug remote,设置host为localhost,port:8000

其次,在本地启动sonar,在待检查的工程执行命令mvnDebug sonar:sonar

回到idea里开始远程debug

好,如何开始一次debug大约就是这样,那么,问题来了,断点应该加在哪里???不得不说一下sonar的基本流程了,在说sonar的基本流程之前,先说说sonar的domain吧。


sonar domain

从我了解的数据库的表为点来做一个简单的介绍吧:

    • projects:保存所有被sonar分析过的项目的基本信息,需要注意的是,这里存放的不光是工程级别的东西,比如分析一个java代码库,整个代码库就会作为一条记录,每个package也都会作为一条记录,每个类也是一样,换句话说,sonar会对每个级别都做分析;
    • metrics:保存测试指标,比如测试的覆盖率,代码的复杂度等;
    • rules_profiles:保存定制化的测试标准集合,也就是metrics的一个子集;
    • snapshots:有了projects,有了rules_profiles。按照某种rules_profile对某个project进行一次sonar分析,就会产生一些snapshots。但是这里其实并没有存储真正的分析出来的指标值。而是存放在project_measures这个表中。snapshots和project_measures通过外键关联。
接下来说说sonar的基本的流程,直接上源码:

public void execute(Project project) {
	eventBus.fireEvent(new ProjectAnalysisEvent(project, true));
	mavenPluginsConfigurator.execute(project);
	mavenPhaseExecutor.execute(project);
	initializersExecutor.execute();
	persistenceManager.setDelayedMode(true);
	sensorsExecutor.execute(sensorContext);
	decoratorsExecutor.execute();
	persistenceManager.dump();
	persistenceManager.setDelayedMode(false);
	if (project.isRoot()) {
		if (updateStatusJob != null) {
			updateStatusJob.execute();
		}
		postJobsExecutor.execute(sensorContext); 
	}
	cleanMemory();
	eventBus.fireEvent(new ProjectAnalysisEvent(project, false));
}

从源码可以看出:

    • 首先,初始化整个分析过程,包括加载所有的分析任务;
    • 其次,分析这些任务(Sensor和Decorator),并且把结果存储到数据库;
    • 最后,执行postjob,做相关的一些分析。

看到这里,大家应该知道debug开始的断点加在哪里,明显是加在实现Sensor接口的类的analysis方法里。


sonar plugin扩展

从上面的代码可以看出plugin的扩展点应该是:sensor,decorator和postjob

接下来详细说一下如何来扩展写一个自己的plugin吧。

详细的一些内容可以参见:sonar plugin扩展

demo:threadLocal plugin

第一步,扩展SonarPlugin,这是plugin的入口,并指定相关plugin所需要的一些class

public class JavaExtensionRulesPlugin extends SonarPlugin {
	@Override
	public List getExtensions() {
		return Arrays.asList(相关扩展类.class);
	}
}

第二步,定义自己的rule,包括自己rule所在的repostory

public class JavaExtensionRulesDefinition implements RulesDefinition {
    @Override
    public void define(Context context) {
        NewRepository repository = context.createRepository(RulesList.REPOSITORY_KEY, Java.KEY);
        repository.setName(RulesList.REPOSITORY_KEY);
        AnnotationBasedRulesDefinition.load(repository, Java.KEY, RulesList.getChecks());
        repository.done();
    }
}

第三步,扩展CheckRegistrar,创建自己rule以及其所在repository,并将其注册到plugin里

public class JavaExtensionRulesCheckRegistrar implements CheckRegistrar {
    @Override
    public void register(RegistrarContext registrarContext) {
        registrarContext.registerClassesForRepository(RulesList.REPOSITORY_KEY, Arrays.asList(checkClasses()),
                Arrays.asList(testCheckClasses()));
    }

    /**
     * Lists all the checks provided by the plugin
     */
    public static Class[] checkClasses() {
        return new Class[] { ThreadLocalRemoveRule.class };
    }

    /**
     * Lists all the test checks provided by the plugin
     */
    public static Class[] testCheckClasses() {
        return new Class[] {};
    }

}


需要注意的是:自己扩展plugin,需要告诉检查的那些文件(文件名以什么结尾,java是检查以.java和.jav结尾的文件),不然检查文件的时候sonarqube不知道检查什么文件。我踩过这个坑。


第四步,下面该扩展Sensor了,sensor里包含了文件的扫描,各个rule的check,详细的可以参照前文给出的github demo。

到这里还没完,还有很重要的一步没有做呢,自己的规则不要忘了自己来制定哦,具体怎么制定,参照demo里的threadlocal-plugin-checks这个子工程。

做完上面这些,差不多可以结束了,接下来想要你的plugin生效还需要把plugin打成jar包并添加到sonarqube/extensions/plugins下,重启sonar,就可以了。


接下来说说我在扩展plugin的时候遇到的坑:

    • 打jar包需要打成sonar-plugin,需要在pom.xml文件里添加一下内容:

	
		
			org.apache.maven.plugins
			maven-dependency-plugin
			
				
					copy-dependencies
					process-resources
					
						copy-dependencies
					
					
						true
						${project.build.outputDirectory}
						annotations,jsr305,fb-contrib,sonar-threadlocal-plugin
					
				
			
		

		
			org.sonarsource.sonar-packaging-maven-plugin
			sonar-packaging-maven-plugin
			1.15
			true
			
				org.sonarqube.extension.plugin.JavaExtensionRulesPlugin
			
		

		
			org.apache.maven.plugins
			maven-compiler-plugin
			3.3
			
				1.7
				1.7
			
		
	
    • mvn package的时候出现这个错误:
 Failed to execute goal com.mycila.maven-license-plugin:maven-license-plugin:1.10.b1:check (enforce-license-headers) on project threadlocal-plugins: Some files do not have the expected license header -> [H
elp 1]
出现这个错误是因为在打包时会检查每一个类的头部有没有用注释写一段东西,类似于这样:

This bundle contains Java Service Wrapper scripts and binaries version 3.2.3 from Tanukisoftware published
under the following license:

    Copyright (c) 2001 Silver Egg Technology
    
    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without 
    restriction, including without limitation the rights to use, 
    copy, modify, merge, publish, distribute, sub-license, and/or 
    sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following 
    conditions:
    
    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.
    
    http://web.archive.org/web/20070622164715/wrapper.tanukisoftware.org/doc/english/license.html

我比较懒,提供一个跳过license检查的方式吧:在mvn的命令尾部加上:

-Dlicense.skip=true

就可以成功的跳过检查了;

    • 下一个坑也是我踩了好久好久的坑,google了好多都没有找到解决方案,最后看源码才解决的这个问题。打好jar包添加到sonarqube之后,发现在sonarqube ui(localhost:9000)上我的rule已经存在了,但是每次检查的时候我的规则并没有生效。解决这个问题是需要指定profile,profile是对rule的一个配置,sonar通常是通过profile来判断本次检查启用哪些rule。具体这样来操作:先登录,用户名跟密码都是admin,登录之后先去Quality Profiles中看哪一个profile是default profile,找到你的rule,按图操作:

sonar相关插件开发_第1张图片

activate之后,是这样子的:


sonar相关插件开发_第2张图片

再次在待检查工程执行mvn sonar:sonar,你的rule生效了。


后记

到这里基本就结束了,希望对大家的开发有所帮助,有什么问题的也可以留言问我。


你可能感兴趣的:(技术类)