android项目Lint增量扫描(Java开发的CI平台实现)

Java开发实现lint增量扫描

对于不懂安卓应用的Java开发来说,真的是绕了很多圈,查了很多资料,最后写完发现这些忙碌真是不值一提,希望对有需要的人有所帮助。

参考资料

查询了很多网上相关内容帖,都是基于安卓开发的,感谢共享:

  1. Android Lint增量扫描实战纪要
  2. Android自定义Lint增量代码检查工具
  3. Android自定义Lint增量代码检查工具_2
  4. Lint Tool Analysis

1,2,3都是类似的,关键流程都在,第一篇遍地都是,4是关键的源码分析,在后面迷茫的时候很有帮助。

通过jgit工具的git diff获取增量文件/代码

区别于别人的使用git diff xxxxxxx的命令行,我选择的是引入org.eclipse.jgit的maven依赖。直接使用jgit的API基本都可以做命令行能做的事情,是一个非常好的工具。

<dependency>
   <groupId>org.eclipse.jgit</groupId>
   <artifactId>org.eclipse.jgit</artifactId>
   <version>4.8.0.201706111038-r</version>
</dependency>

此处关键是获取到区别对象:List diffs = git.diff().setNewTree(newTreeIter).setOldTree(oldTreeIter).call(),我这里使用的方式是通过两个commitId获取这两次commit之间的增量文件,后面直接扫描这些文件,如果想要针对扫描某一行增量代码,应该也能做到,参考前面的博客,我没做探究此处不讨论。

//.git文件路径
public static final String localProjectGitDir = "D:\\GitHubProject\\android_project_name\\.git";
	
public List<File> getDiffFiles () throws IOException, GitAPIException {
    
    //前提是先把需要扫描的项目pull到本地,获得localProjectGitDir
    Git git = Git.open(new File(localProjectGitDir));
    Repository repository = git.getRepository();
    
	//此处HEAD代表所在分支最新commitId, 需要比较哪两次commit之间的增量,就分别传入commitId
    ObjectId newObjectId = repository.resolve("HEAD"+"^{tree}");
    ObjectId oldObjectId = repository.resolve("xxx8f77d2d5e4xx5fe9b6xxx16xxx500xxx13xxx9"+"^{tree}");
        
    ObjectReader reader = repository.newObjectReader();
    CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
    oldTreeIter.reset(reader, oldObjectId);
    CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
    newTreeIter.reset(reader, newObjectId);

    //测试到这个结论,各位可验证是否属实:
    //相邻两次commit之间的diff只找新的commit修改的文件,非相邻diff包含oldCommit的修改文件
    List<DiffEntry> diffs = git.diff().setNewTree(newTreeIter).setOldTree(oldTreeIter).call();
    
    //将要扫描的文件集合files 
    List<File> files = new ArrayList<>();
    
    for (DiffEntry entry : diffs) {
    
        //entry.getChangeType()可以得到修改的文件是ADD还是MODIFY还是DELETE
        System.out.println(entry.getChangeType());
        
		//entry.getNewPath()是增量文件的相对路径,还有getOldPath不清楚和newPath什么区别
        File file = new File(LOCALPATH + entry.getNewPath());
        
        if (file.isFile() && !"DELETE".equals(entry.getChangeType())) {
			//将非delete类型的文件加入将要扫描的文件中
            files.add(file);
        }
    }
}

重写createLintRequest加入要扫描的文件

在java开发的项目中,想要使用Lint,肯定是找到他的maven依赖,毕竟很多安卓项目也是java开发,终于还是找到了相关API,网上也很少有提及,这个很关键。

<dependency>
   <groupId>com.android.tools.lint</groupId>
   <artifactId>lint-gradle</artifactId>
   <version>26.3.2</version>
</dependency>

首先新建一个LintToolClient 类去继承执行lint扫描的父类,上面实战纪要提到的是使用LintGradleClient, 然后去获取构建所需要的各种参数,我摸索了半天在CI平台-java项目中没找不到org.gradle.api.Project这个类无法import,此路不通(安卓项目开发lint增量扫描可忽略,你们可以使用)

仔细观察LintGradleClient也相当于一个实现类继承的LintCliClient,关键还是LintCliClient去执行run()方法实现扫描。

几个关键点:

  1. 自己建的LintToolClient 要继承LintCliClient
  2. 一定要有有参构造, 因为父类LintCliClient的无参是没有用的
  3. 重写父类 createLintRequest() 方法,将要扫描的文件加入。
  4. 通过 Project.create(lintclient,dir,refrencedir) 获取 project(跟上面参考文章说的一样,重点是project.addFile(file)这一句, 但是这个project的获取也是迷茫了半天)
public class LintToolClient extends LintCliClient {

    public LintToolClient(String clientName) {
        super(clientName);
    }

    @Override
    protected LintRequest createLintRequest(List<File> files) {
    	//此处new File里面的路径是写要扫描的文件所在的项目的根目录,两个一样就可以
        Project project = Project.create(this,new File("D:\\JAVAProject\\WeChatBuChat"),
                new File("D:\\JAVAProject\\WeChatBuChat"));
                
        for (File file : files) {
                project.addFile(file);
            }
        return new LintRequest(this, files);
    }
}

结果输出/报告生成形式

有参构造其实两个选择,如果报告结果只需要输出到控制台的可以选择上面只传clientName的;

要是想要xml报告或者html报告文件的选择LintToolClient(LintCliFlags flags, String clientName),这个flag可定义报告生成的形式。即new一个xxxReporter,里面传的File文件路径是报告生成的路径

//将LintToolClient类中的有参构造改成下面这个有参构造实现报告输出
	public LintToolClient(LintCliFlags flags, String clientName) {
        super(flags, clientName);
        HtmlReporter htmlReporter = null;
        try {
            htmlReporter = new HtmlReporter(this, new File("D:/myreport/lint.html"), flags);
        } catch (IOException e) {
            e.printStackTrace();
        }
        flags.getReporters().add(htmlReporter);
    }

构造执行

在主程序创建扫描任务

public static void main(String[] args){
	LintCliFlags lintCliFlags = new LintCliFlags();
	LintToolClient lintToolClient = new  LintToolClient(lintCliFlags , "gradle")
	//通过刚才写的getDiffFiles方法获取增量文件
	List<File> files = getDiffFiles();
	//run方法需要两个参数,第一个IssueRegistry这里直接使用默认的,有更高需要可自定义
	lintToolClient.run(new BuildInIssueRegistry, files);
}

总结

只要有目标项目在,所有的dir都可以传,中间有遇到一些bug,印象最深的是SDK,扫描时它会自动去找环境变量ANDROID_HOME环境变量,所以必须先在电脑设置环境变量,也要让其生效,我自测时明明新写了环境变量却还是一直报错,然后重启电脑突然发现可以了…真是服气。。如果有bug或者哪里不清楚的可以留言私聊探讨,有错误的地方欢迎指出更正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值