Lint增量扫描_CI平台
Java开发实现lint增量扫描
对于不懂安卓应用的Java开发来说,真的是绕了很多圈,查了很多资料,最后写完发现这些忙碌真是不值一提,希望对有需要的人有所帮助。
参考资料
查询了很多网上相关内容帖,都是基于安卓开发的,感谢共享:
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()方法实现扫描。
几个关键点:
- 自己建的LintToolClient 要继承LintCliClient
- 一定要有有参构造, 因为父类LintCliClient的无参是没有用的
- 重写父类 createLintRequest() 方法,将要扫描的文件加入。
- 通过 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或者哪里不清楚的可以留言私聊探讨,有错误的地方欢迎指出更正。